From 9d5d82b4df5b3510177fd31557ac765f46778fe8 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 30 Jul 2006 03:25:38 +0000 Subject: Abstraction cleanups/polish, towards merging with trunk git-svn-id: svn://localhost/ardour2/branches/midi@720 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/audio_regionview.cc | 298 ++------------------ gtk2_ardour/audio_regionview.h | 60 ++-- gtk2_ardour/audio_streamview.cc | 33 +-- gtk2_ardour/audio_streamview.h | 9 +- gtk2_ardour/audio_time_axis.cc | 487 ++------------------------------ gtk2_ardour/audio_time_axis.h | 94 ++----- gtk2_ardour/editor.cc | 12 +- gtk2_ardour/plugin_selector.h | 1 + gtk2_ardour/regionview.cc | 87 +----- gtk2_ardour/regionview.h | 56 ++-- gtk2_ardour/route_time_axis.cc | 506 +++++++++++++++++++++++++++++++++- gtk2_ardour/route_time_axis.h | 164 +++++++---- gtk2_ardour/streamview.cc | 1 - gtk2_ardour/streamview.h | 30 +- gtk2_ardour/taperegionview.cc | 46 +--- libs/ardour/ardour/audio_diskstream.h | 93 ++----- libs/ardour/ardour/diskstream.h | 62 ++--- libs/ardour/ardour/midi_diskstream.h | 22 +- libs/ardour/ardour/playlist.h | 17 +- libs/ardour/ardour/region.h | 2 + libs/ardour/ardour/session.h | 2 +- libs/ardour/audio_diskstream.cc | 197 ++++--------- libs/ardour/diskstream.cc | 112 ++++++-- libs/ardour/midi_diskstream.cc | 4 +- libs/ardour/session.cc | 4 +- libs/ardour/session_butler.cc | 18 +- libs/ardour/session_state.cc | 3 +- 27 files changed, 973 insertions(+), 1447 deletions(-) diff --git a/gtk2_ardour/audio_regionview.cc b/gtk2_ardour/audio_regionview.cc index 125654c35c..f22028f33e 100644 --- a/gtk2_ardour/audio_regionview.cc +++ b/gtk2_ardour/audio_regionview.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2001 Paul Davis + Copyright (C) 2001-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ */ #include +#include #include #include @@ -68,20 +69,18 @@ AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView } void -AudioRegionView::init (Gdk::Color& basic_color, bool wfw) +AudioRegionView::init (Gdk::Color& basic_color, bool wfd) { - ArdourCanvas::Points shape; + // FIXME: Some redundancy here with RegionView::init. Need to figure out + // where order is important and where it isn't... + + RegionView::init(basic_color, wfd); + XMLNode *node; - editor = 0; - valid = true; - in_destructor = false; _amplitude_above_axis = 1.0; - zero_line = 0; - wait_for_waves = wfw; - _height = 0; - - _flags = 0; + zero_line = 0; + _flags = 0; if ((node = _region.extra_xml ("GUI")) != 0) { set_flags (node); @@ -98,23 +97,6 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfw) create_waves (); - name_highlight->set_data ("regionview", this); - name_text->set_data ("regionview", this); - - // shape = new ArdourCanvas::Points (); - - /* an equilateral triangle */ - - shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1)); - shape.push_back (Gnome::Art::Point ((sync_mark_width - 1)/2, 1)); - shape.push_back (Gnome::Art::Point (0, sync_mark_width - 1)); - shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1)); - - sync_mark = new ArdourCanvas::Polygon (*group); - sync_mark->property_points() = shape; - sync_mark->property_fill_color_rgba() = fill_color; - sync_mark->hide(); - fade_in_shape = new ArdourCanvas::Polygon (*group); fade_in_shape->property_fill_color_rgba() = fade_color; fade_in_shape->set_data ("regionview", this); @@ -175,8 +157,6 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfw) _region.StateChanged.connect (mem_fun(*this, &AudioRegionView::region_changed)); - group->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_region_view_event), group, this)); - name_highlight->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_region_view_name_highlight_event), name_highlight, this)); fade_in_shape->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_event), fade_in_shape, this)); fade_in_handle->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_handle_event), fade_in_handle, this)); fade_out_shape->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_event), fade_out_shape, this)); @@ -184,8 +164,6 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfw) set_colors (); - ColorChanged.connect (mem_fun (*this, &AudioRegionView::color_handler)); - /* XXX sync mark drag? */ } @@ -201,14 +179,6 @@ AudioRegionView::~AudioRegionView () /* all waveviews etc will be destroyed when the group is destroyed */ - for (vector::iterator g = ghosts.begin(); g != ghosts.end(); ++g) { - delete *g; - } - - if (editor) { - delete editor; - } - if (gain_line) { delete gain_line; } @@ -217,58 +187,17 @@ AudioRegionView::~AudioRegionView () ARDOUR::AudioRegion& AudioRegionView::audio_region() const { - // Guaranteed to succeed + // "Guaranteed" to succeed... return dynamic_cast(_region); } - -gint -AudioRegionView::_lock_toggle (ArdourCanvas::Item* item, GdkEvent* ev, void* arg) -{ - switch (ev->type) { - case GDK_BUTTON_RELEASE: - static_cast(arg)->lock_toggle (); - return TRUE; - break; - default: - break; - } - return FALSE; -} - -void -AudioRegionView::lock_toggle () -{ - _region.set_locked (!_region.locked()); -} - void AudioRegionView::region_changed (Change what_changed) { ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioRegionView::region_changed), what_changed)); - if (what_changed & BoundsChanged) { - region_resized (what_changed); - region_sync_changed (); - } - if (what_changed & Region::MuteChanged) { - region_muted (); - } - if (what_changed & Region::OpacityChanged) { - region_opacity (); - } - if (what_changed & ARDOUR::NameChanged) { - region_renamed (); - } - if (what_changed & Region::SyncOffsetChanged) { - region_sync_changed (); - } - if (what_changed & Region::LayerChanged) { - region_layered (); - } - if (what_changed & Region::LockChanged) { - region_locked (); - } + RegionView::region_changed(what_changed); + if (what_changed & AudioRegion::ScaleAmplitudeChanged) { region_scale_amplitude_changed (); } @@ -365,38 +294,19 @@ AudioRegionView::region_scale_amplitude_changed () } } -void -AudioRegionView::region_locked () -{ - /* name will show locked status */ - region_renamed (); -} - void AudioRegionView::region_resized (Change what_changed) { - double unit_length; - - if (what_changed & ARDOUR::PositionChanged) { - set_position (_region.position(), 0); - } + RegionView::region_resized(what_changed); if (what_changed & Change (StartChanged|LengthChanged)) { - set_duration (_region.length(), 0); - - unit_length = _region.length() / samples_per_unit; - - reset_width_dependent_items (unit_length); - for (uint32_t n = 0; n < waves.size(); ++n) { waves[n]->property_region_start() = _region.start(); - } + } for (vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { - (*i)->set_duration (unit_length); - for (vector::iterator w = (*i)->waves.begin(); w != (*i)->waves.end(); ++w) { (*w)->property_region_start() = _region.start(); } @@ -407,8 +317,8 @@ AudioRegionView::region_resized (Change what_changed) void AudioRegionView::reset_width_dependent_items (double pixel_width) { - TimeAxisViewItem::reset_width_dependent_items (pixel_width); - _pixel_width = pixel_width; + RegionView::reset_width_dependent_items(pixel_width); + assert(_pixel_width == pixel_width); if (zero_line) { zero_line->property_x2() = pixel_width - 1.0; @@ -432,18 +342,10 @@ AudioRegionView::reset_width_dependent_items (double pixel_width) reset_fade_shapes (); } -void -AudioRegionView::region_layered () -{ - RouteTimeAxisView *atv = dynamic_cast (&get_time_axis_view()); - atv->view()->region_layered (this); -} - void AudioRegionView::region_muted () { - set_frame_color (); - region_renamed (); + RegionView::region_muted(); for (uint32_t n=0; n < waves.size(); ++n) { if (_region.muted()) { @@ -460,6 +362,7 @@ AudioRegionView::set_height (gdouble height) { uint32_t wcnt = waves.size(); + // FIXME: ick TimeAxisViewItem::set_height (height - 2); _height = height; @@ -695,36 +598,16 @@ AudioRegionView::reset_fade_out_shape_width (jack_nframes_t width) void AudioRegionView::set_samples_per_unit (gdouble spu) { - TimeAxisViewItem::set_samples_per_unit (spu); + RegionView::set_samples_per_unit (spu); for (uint32_t n=0; n < waves.size(); ++n) { waves[n]->property_samples_per_unit() = spu; } - for (vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { - (*i)->set_samples_per_unit (spu); - (*i)->set_duration (_region.length() / samples_per_unit); - } - if (gain_line) { gain_line->reset (); } reset_fade_shapes (); - region_sync_changed (); -} - -bool -AudioRegionView::set_duration (jack_nframes_t frames, void *src) -{ - if (!TimeAxisViewItem::set_duration (frames, src)) { - return false; - } - - for (vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { - (*i)->set_duration (_region.length() / samples_per_unit); - } - - return true; } void @@ -738,7 +621,8 @@ AudioRegionView::set_amplitude_above_axis (gdouble spp) void AudioRegionView::compute_colors (Gdk::Color& basic_color) { - TimeAxisViewItem::compute_colors (basic_color); + RegionView::compute_colors(basic_color); + uint32_t r, g, b, a; /* gain color computed in envelope_active_changed() */ @@ -750,16 +634,12 @@ AudioRegionView::compute_colors (Gdk::Color& basic_color) void AudioRegionView::set_colors () { - TimeAxisViewItem::set_colors (); + RegionView::set_colors(); if (gain_line) { gain_line->set_line_color (audio_region().envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]); } - if (sync_mark) { - sync_mark->property_fill_color_rgba() = fill_color; - } - for (uint32_t n=0; n < waves.size(); ++n) { if (_region.muted()) { waves[n]->property_wave_color() = color_map[cMutedWaveForm]; @@ -769,18 +649,6 @@ AudioRegionView::set_colors () } } -void -AudioRegionView::set_frame_color () -{ - if (_region.opaque()) { - fill_opacity = 180; - } else { - fill_opacity = 100; - } - - TimeAxisViewItem::set_frame_color (); -} - void AudioRegionView::show_region_editor () { @@ -795,89 +663,6 @@ AudioRegionView::show_region_editor () editor->get_window()->raise(); } -void -AudioRegionView::hide_region_editor() -{ - if (editor) { - editor->hide_all (); - } -} - -void -AudioRegionView::region_renamed () -{ - string str; - - if (_region.locked()) { - str += '>'; - str += _region.name(); - str += '<'; - } else { - str = _region.name(); - } - - if (audio_region().speed_mismatch (trackview.session().frame_rate())) { - str = string ("*") + str; - } - - if (_region.muted()) { - str = string ("!") + str; - } - - set_item_name (str, this); - set_name_text (str); -} - -void -AudioRegionView::region_sync_changed () -{ - if (sync_mark == 0) { - return; - } - - int sync_dir; - jack_nframes_t sync_offset; - - sync_offset = _region.sync_offset (sync_dir); - - /* this has to handle both a genuine change of position, a change of samples_per_unit, - and a change in the bounds of the _region. - */ - - if (sync_offset == 0) { - - /* no sync mark - its the start of the region */ - - sync_mark->hide(); - - } else { - - if ((sync_dir < 0) || ((sync_dir > 0) && (sync_offset > _region.length()))) { - - /* no sync mark - its out of the bounds of the region */ - - sync_mark->hide(); - - } else { - - /* lets do it */ - - Points points; - - //points = sync_mark->property_points().get_value(); - - double offset = sync_offset / samples_per_unit; - points.push_back (Gnome::Art::Point (offset - ((sync_mark_width-1)/2), 1)); - points.push_back (Gnome::Art::Point (offset + ((sync_mark_width-1)/2), 1)); - points.push_back (Gnome::Art::Point (offset, sync_mark_width - 1)); - points.push_back (Gnome::Art::Point (offset - ((sync_mark_width-1)/2), 1)); - sync_mark->property_points().set_value (points); - sync_mark->show(); - - } - } -} - void AudioRegionView::set_waveform_visible (bool yn) { @@ -954,8 +739,8 @@ AudioRegionView::create_waves () wave_caches.push_back (WaveView::create_cache ()); - if (wait_for_waves) { - if (audio_region().source(n).peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), peaks_ready_connection)) { + if (wait_for_data) { + if (audio_region().source(n).peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), data_ready_connection)) { create_one_wave (n, true); } else { create_zero_line = false; @@ -1056,7 +841,7 @@ AudioRegionView::peaks_ready_handler (uint32_t which) if (!waves.empty()) { /* all waves created, don't hook into peaks ready anymore */ - peaks_ready_connection.disconnect (); + data_ready_connection.disconnect (); } } @@ -1184,22 +969,6 @@ AudioRegionView::set_waveform_shape (WaveformShape shape) } } -void -AudioRegionView::move (double x_delta, double y_delta) -{ - if (_region.locked() || (x_delta == 0 && y_delta == 0)) { - return; - } - - get_canvas_group()->move (x_delta, y_delta); - - /* note: ghosts never leave their tracks so y_delta for them is always zero */ - - for (vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { - (*i)->group->move (x_delta, 0.0); - } -} - GhostRegion* AudioRegionView::add_ghost (AutomationTimeAxisView& atv) { @@ -1243,21 +1012,6 @@ AudioRegionView::add_ghost (AutomationTimeAxisView& atv) return ghost; } -void -AudioRegionView::remove_ghost (GhostRegion* ghost) -{ - if (in_destructor) { - return; - } - - for (vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { - if (*i == ghost) { - ghosts.erase (i); - break; - } - } -} - void AudioRegionView::entered () { diff --git a/gtk2_ardour/audio_regionview.h b/gtk2_ardour/audio_regionview.h index 7889f0c8b5..b59f5f4791 100644 --- a/gtk2_ardour/audio_regionview.h +++ b/gtk2_ardour/audio_regionview.h @@ -57,21 +57,15 @@ class AudioRegionView : public RegionView ~AudioRegionView (); - virtual void init (Gdk::Color& base_color, bool wait_for_waves); + virtual void init (Gdk::Color& base_color, bool wait_for_data = false); ARDOUR::AudioRegion& audio_region() const; - bool is_valid() const { return valid; } - void set_valid (bool yn) { valid = yn; } - void set_height (double); void set_samples_per_unit (double); - bool set_duration (jack_nframes_t, void*); void set_amplitude_above_axis (gdouble spp); - void move (double xdelta, double ydelta); - void temporarily_hide_envelope (); ///< Dangerous! void unhide_envelope (); ///< Dangerous! @@ -80,11 +74,10 @@ class AudioRegionView : public RegionView void set_waveform_shape (WaveformShape); bool waveform_rectified() const { return _flags & WaveformRectified; } - bool waveform_visible() const { return _flags & WaveformVisible; } - bool envelope_visible() const { return _flags & EnvelopeVisible; } + bool waveform_visible() const { return _flags & WaveformVisible; } + bool envelope_visible() const { return _flags & EnvelopeVisible; } void show_region_editor (); - void hide_region_editor(); void add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *event); void remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *event); @@ -95,7 +88,6 @@ class AudioRegionView : public RegionView void envelope_active_changed (); GhostRegion* add_ghost (AutomationTimeAxisView&); - void remove_ghost (GhostRegion*); void reset_fade_in_shape_width (jack_nframes_t); void reset_fade_out_shape_width (jack_nframes_t); @@ -113,11 +105,11 @@ class AudioRegionView : public RegionView */ AudioRegionView (ArdourCanvas::Group *, - RouteTimeAxisView&, - ARDOUR::AudioRegion&, - double initial_samples_per_unit, - Gdk::Color& basic_color, - TimeAxisViewItem::Visibility); + RouteTimeAxisView&, + ARDOUR::AudioRegion&, + double samples_per_unit, + Gdk::Color& basic_color, + TimeAxisViewItem::Visibility); enum Flags { EnvelopeVisible = 0x1, @@ -125,32 +117,22 @@ class AudioRegionView : public RegionView WaveformRectified = 0x8 }; - vector waves; ///< waveviews + vector waves; vector tmp_waves; ///< see ::create_waves() - ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position - ArdourCanvas::Text* no_wave_msg; ///< text - ArdourCanvas::SimpleLine* zero_line; ///< simpleline - ArdourCanvas::Polygon* fade_in_shape; ///< polygon - ArdourCanvas::Polygon* fade_out_shape; ///< polygon - ArdourCanvas::SimpleRect* fade_in_handle; ///< simplerect - ArdourCanvas::SimpleRect* fade_out_handle; ///< simplerect + ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position + ArdourCanvas::SimpleLine* zero_line; + ArdourCanvas::Polygon* fade_in_shape; + ArdourCanvas::Polygon* fade_out_shape; + ArdourCanvas::SimpleRect* fade_in_handle; + ArdourCanvas::SimpleRect* fade_out_handle; AudioRegionGainLine * gain_line; - AudioRegionEditor * editor; - vector control_points; double _amplitude_above_axis; - double current_visible_sync_position; uint32_t _flags; uint32_t fade_color; - bool valid; /* see StreamView::redisplay_diskstream() */ - double _pixel_width; - double _height; - bool in_destructor; - bool wait_for_waves; - sigc::connection peaks_ready_connection; - + void reset_fade_shapes (); void reset_fade_in_shape (); void reset_fade_out_shape (); @@ -162,31 +144,21 @@ class AudioRegionView : public RegionView void region_resized (ARDOUR::Change); void region_moved (void *); void region_muted (); - void region_locked (); - void region_layered (); - void region_renamed (); - void region_sync_changed (); void region_scale_amplitude_changed (); - static gint _lock_toggle (ArdourCanvas::Item*, GdkEvent*, void*); - void lock_toggle (); - void create_waves (); void create_one_wave (uint32_t, bool); void manage_zero_line (); void peaks_ready_handler (uint32_t); - void reset_name (gdouble width); void set_flags (XMLNode *); void store_flags (); void set_colors (); void compute_colors (Gdk::Color&); - virtual void set_frame_color (); void reset_width_dependent_items (double pixel_width); void set_waveview_data_src(); vector wave_caches; - vector ghosts; void color_handler (ColorID, uint32_t); }; diff --git a/gtk2_ardour/audio_streamview.cc b/gtk2_ardour/audio_streamview.cc index 1e43f1dac1..0d0cd7889c 100644 --- a/gtk2_ardour/audio_streamview.cc +++ b/gtk2_ardour/audio_streamview.cc @@ -54,7 +54,6 @@ using namespace Editing; AudioStreamView::AudioStreamView (AudioTimeAxisView& tv) : StreamView (tv) { - region_color = _trackview.color(); crossfades_visible = true; if (tv.is_audio_track()) @@ -62,43 +61,16 @@ AudioStreamView::AudioStreamView (AudioTimeAxisView& tv) else stream_base_color = color_map[cAudioBusBase]; - /* set_position() will position the group */ - - canvas_group = new ArdourCanvas::Group(*_trackview.canvas_display); - - canvas_rect = new ArdourCanvas::SimpleRect (*canvas_group); - canvas_rect->property_x1() = 0.0; - canvas_rect->property_y1() = 0.0; - canvas_rect->property_x2() = 1000000.0; - canvas_rect->property_y2() = (double) tv.height; canvas_rect->property_outline_color_rgba() = color_map[cAudioTrackOutline]; - canvas_rect->property_outline_what() = (guint32) (0x1|0x2|0x8); // outline ends and bottom - canvas_rect->property_fill_color_rgba() = stream_base_color; - - canvas_rect->signal_event().connect (bind (mem_fun (_trackview.editor, &PublicEditor::canvas_stream_view_event), canvas_rect, &_trackview)); - _samples_per_unit = _trackview.editor.get_current_zoom(); _amplitude_above_axis = 1.0; - if (_trackview.is_audio_track()) { - _trackview.audio_track()->DiskstreamChanged.connect (mem_fun (*this, &AudioStreamView::diskstream_changed)); - _trackview.session().TransportStateChange.connect (mem_fun (*this, &AudioStreamView::transport_changed)); - _trackview.get_diskstream()->RecordEnableChanged.connect (mem_fun (*this, &AudioStreamView::rec_enable_changed)); - _trackview.session().RecordStateChanged.connect (mem_fun (*this, &AudioStreamView::sess_rec_enable_changed)); - } - - rec_updating = false; - rec_active = false; use_rec_regions = tv.editor.show_waveforms_recording (); last_rec_peak_frame = 0; - - ColorChanged.connect (mem_fun (*this, &AudioStreamView::color_handler)); } AudioStreamView::~AudioStreamView () { - undisplay_diskstream (); - delete canvas_group; } int @@ -132,7 +104,6 @@ AudioStreamView::set_samples_per_unit (gdouble spp) int AudioStreamView::set_amplitude_above_axis (gdouble app) - { RegionViewList::iterator i; @@ -206,8 +177,6 @@ AudioStreamView::remove_region_view (Region *r) { ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::remove_region_view), r)); - StreamView::remove_region_view(r); - for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end();) { list::iterator tmp; @@ -222,6 +191,8 @@ AudioStreamView::remove_region_view (Region *r) i = tmp; } + + StreamView::remove_region_view(r); } void diff --git a/gtk2_ardour/audio_streamview.h b/gtk2_ardour/audio_streamview.h index d05ecd9307..05ce8125f6 100644 --- a/gtk2_ardour/audio_streamview.h +++ b/gtk2_ardour/audio_streamview.h @@ -59,10 +59,9 @@ class AudioStreamView : public StreamView void set_waveform_shape (WaveformShape); int set_height (gdouble h); - int set_samples_per_unit (gdouble spp); - int set_amplitude_above_axis (gdouble app); + int set_amplitude_above_axis (gdouble app); gdouble get_amplitude_above_axis () { return _amplitude_above_axis; } void set_show_waveforms (bool yn); @@ -90,17 +89,17 @@ class AudioStreamView : public StreamView void playlist_modified (); void playlist_changed (ARDOUR::Diskstream *ds); - bool crossfades_visible; void add_crossfade (ARDOUR::Crossfade*); void remove_crossfade (ARDOUR::Crossfade*); void color_handler (ColorID id, uint32_t val); + double _amplitude_above_axis; + typedef list CrossfadeViewList; CrossfadeViewList crossfade_views; - - double _amplitude_above_axis; + bool crossfades_visible; list peak_ready_connections; jack_nframes_t last_rec_peak_frame; diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc index ea822b97c5..13383fa6a4 100644 --- a/gtk2_ardour/audio_time_axis.cc +++ b/gtk2_ardour/audio_time_axis.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -53,25 +52,18 @@ #include "audio_time_axis.h" #include "automation_gain_line.h" #include "automation_pan_line.h" -#include "automation_time_axis.h" #include "canvas_impl.h" #include "crossfade_view.h" #include "enums.h" #include "gain_automation_time_axis.h" -#include "gui_thread.h" #include "keyboard.h" #include "pan_automation_time_axis.h" #include "playlist_selector.h" #include "plugin_selector.h" #include "plugin_ui.h" -#include "point_selection.h" #include "prompter.h" #include "public_editor.h" -#include "redirect_automation_line.h" -#include "redirect_automation_time_axis.h" #include "audio_regionview.h" -#include "rgb_macros.h" -#include "selection.h" #include "simplerect.h" #include "audio_streamview.h" #include "utils.h" @@ -87,9 +79,12 @@ using namespace Editing; AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr rt, Canvas& canvas) - : AxisView(sess), // FIXME: won't compile without this, why?? - RouteTimeAxisView(ed, sess, rt, canvas) + : AxisView(sess) + , RouteTimeAxisView(ed, sess, rt, canvas) { + // Make sure things are sane... + assert(!is_track() || is_audio_track()); + subplugin_menu.set_name ("ArdourContextMenu"); gain_track = 0; pan_track = 0; @@ -143,11 +138,6 @@ AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::sh AudioTimeAxisView::~AudioTimeAxisView () { - vector_delete (&redirect_automation_curves); - - for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - delete *i; - } } AudioStreamView* @@ -227,56 +217,14 @@ AudioTimeAxisView::set_state (const XMLNode& node) } void -AudioTimeAxisView::reset_redirect_automation_curves () -{ - for (vector::iterator i = redirect_automation_curves.begin(); i != redirect_automation_curves.end(); ++i) { - (*i)->reset(); - } -} - -void -AudioTimeAxisView::build_display_menu () +AudioTimeAxisView::build_automation_action_menu () { using namespace Menu_Helpers; - /* get the size menu ready */ - - build_size_menu (); - - /* prepare it */ - - TimeAxisView::build_display_menu (); - - /* now fill it with our stuff */ - - MenuList& items = display_menu->items(); - display_menu->set_name ("ArdourContextMenu"); - - items.push_back (MenuElem (_("Height"), *size_menu)); - items.push_back (MenuElem (_("Color"), mem_fun(*this, &AudioTimeAxisView::select_track_color))); - - - items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades))); - items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades))); - items.push_back (SeparatorElem()); - - build_remote_control_menu (); - items.push_back (MenuElem (_("Remote Control ID"), *remote_control_menu)); + RouteTimeAxisView::build_automation_action_menu (); - automation_action_menu = manage (new Menu); MenuList& automation_items = automation_action_menu->items(); - automation_action_menu->set_name ("ArdourContextMenu"); - automation_items.push_back (MenuElem (_("Show all automation"), - mem_fun(*this, &AudioTimeAxisView::show_all_automation))); - - automation_items.push_back (MenuElem (_("Show existing automation"), - mem_fun(*this, &AudioTimeAxisView::show_existing_automation))); - - automation_items.push_back (MenuElem (_("Hide all automation"), - mem_fun(*this, &AudioTimeAxisView::hide_all_automation))); - automation_items.push_back (SeparatorElem()); automation_items.push_back (CheckMenuElem (_("Fader"), @@ -288,11 +236,21 @@ AudioTimeAxisView::build_display_menu () mem_fun(*this, &AudioTimeAxisView::toggle_pan_track))); pan_automation_item = static_cast (&automation_items.back()); pan_automation_item->set_active(show_pan_automation); + +} - automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu)); +void +AudioTimeAxisView::append_extra_display_menu_items () +{ + using namespace Menu_Helpers; - items.push_back (MenuElem (_("Automation"), *automation_action_menu)); + MenuList& items = display_menu->items(); + // crossfade stuff + items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades))); + items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades))); + + // waveform menu Menu *waveform_menu = manage(new Menu); MenuList& waveform_items = waveform_menu->items(); waveform_menu->set_name ("ArdourContextMenu"); @@ -312,39 +270,6 @@ AudioTimeAxisView::build_display_menu () rectified_item = static_cast (&waveform_items.back()); items.push_back (MenuElem (_("Waveform"), *waveform_menu)); - - if (is_audio_track()) { - - Menu* alignment_menu = manage (new Menu); - MenuList& alignment_items = alignment_menu->items(); - alignment_menu->set_name ("ArdourContextMenu"); - - RadioMenuItem::Group align_group; - - alignment_items.push_back (RadioMenuElem (align_group, _("Align with existing material"), bind (mem_fun(*this, &AudioTimeAxisView::set_align_style), ExistingMaterial))); - align_existing_item = dynamic_cast(&alignment_items.back()); - if (get_diskstream()->alignment_style() == ExistingMaterial) { - align_existing_item->set_active(); - } - alignment_items.push_back (RadioMenuElem (align_group, _("Align with capture time"), bind (mem_fun(*this, &AudioTimeAxisView::set_align_style), CaptureTime))); - align_capture_item = dynamic_cast(&alignment_items.back()); - if (get_diskstream()->alignment_style() == CaptureTime) { - align_capture_item->set_active(); - } - - items.push_back (MenuElem (_("Alignment"), *alignment_menu)); - - get_diskstream()->AlignmentStyleChanged.connect (mem_fun(*this, &AudioTimeAxisView::align_style_changed)); - } - - items.push_back (SeparatorElem()); - items.push_back (CheckMenuElem (_("Active"), mem_fun(*this, &RouteUI::toggle_route_active))); - route_active_menu_item = dynamic_cast (&items.back()); - route_active_menu_item->set_active (_route->active()); - - items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route))); - } void @@ -393,16 +318,6 @@ AudioTimeAxisView::set_waveform_shape (WaveformShape shape) map_frozen (); } -void -AudioTimeAxisView::set_selected_regionviews (RegionSelection& regions) -{ - AudioStreamView* asv = audio_view(); - - if (asv) { - asv->set_selected_regionviews (regions); - } -} - void AudioTimeAxisView::add_gain_automation_child () { @@ -587,322 +502,6 @@ AudioTimeAxisView::pan_hidden () _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ } -AudioTimeAxisView::RedirectAutomationInfo::~RedirectAutomationInfo () -{ - for (vector::iterator i = lines.begin(); i != lines.end(); ++i) { - delete *i; - } -} - - -AudioTimeAxisView::RedirectAutomationNode::~RedirectAutomationNode () -{ - parent.remove_ran (this); - - if (view) { - delete view; - } -} - -void -AudioTimeAxisView::remove_ran (RedirectAutomationNode* ran) -{ - if (ran->view) { - remove_child (ran->view); - } -} - -AudioTimeAxisView::RedirectAutomationNode* -AudioTimeAxisView::find_redirect_automation_node (boost::shared_ptr redirect, uint32_t what) -{ - for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - - if ((*i)->redirect == redirect) { - - for (vector::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { - if ((*ii)->what == what) { - return *ii; - } - } - } - } - - return 0; -} - -// FIXME: duplicated in midi_time_axis.cc -static string -legalize_for_xml_node (string str) -{ - string::size_type pos; - string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=:"; - string legal; - - legal = str; - pos = 0; - - while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) { - legal.replace (pos, 1, "_"); - pos += 1; - } - - return legal; -} - - -void -AudioTimeAxisView::add_redirect_automation_curve (boost::shared_ptr redirect, uint32_t what) -{ - RedirectAutomationLine* ral; - string name; - RedirectAutomationNode* ran; - - if ((ran = find_redirect_automation_node (redirect, what)) == 0) { - fatal << _("programming error: ") - << string_compose (X_("redirect automation curve for %1:%2 not registered with audio track!"), - redirect->name(), what) - << endmsg; - /*NOTREACHED*/ - return; - } - - if (ran->view) { - return; - } - - name = redirect->describe_parameter (what); - - /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */ - - char state_name[256]; - snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (redirect->name()).c_str(), what); - - ran->view = new RedirectAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, name, what, *redirect, state_name); - - ral = new RedirectAutomationLine (name, - *redirect, what, _session, *ran->view, - *ran->view->canvas_display, redirect->automation_list (what)); - - ral->set_line_color (color_map[cRedirectAutomationLine]); - ral->queue_reset (); - - ran->view->add_line (*ral); - - ran->view->Hiding.connect (bind (mem_fun(*this, &AudioTimeAxisView::redirect_automation_track_hidden), ran, redirect)); - - if (!ran->view->marked_for_display()) { - ran->view->hide (); - } else { - ran->menu_item->set_active (true); - } - - add_child (ran->view); - - audio_view()->foreach_regionview (bind (mem_fun(*this, &AudioTimeAxisView::add_ghost_to_redirect), ran->view)); - - redirect->mark_automation_visible (what, true); -} - -void -AudioTimeAxisView::redirect_automation_track_hidden (AudioTimeAxisView::RedirectAutomationNode* ran, boost::shared_ptr r) -{ - if (!_hidden) { - ran->menu_item->set_active (false); - } - - r->mark_automation_visible (ran->what, false); - - _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ -} - -void -AudioTimeAxisView::add_existing_redirect_automation_curves (boost::shared_ptr redirect) -{ - set s; - RedirectAutomationLine *ral; - - redirect->what_has_visible_automation (s); - - for (set::iterator i = s.begin(); i != s.end(); ++i) { - - if ((ral = find_redirect_automation_curve (redirect, *i)) != 0) { - ral->queue_reset (); - } else { - add_redirect_automation_curve (redirect, (*i)); - } - } -} - -void -AudioTimeAxisView::add_redirect_to_subplugin_menu (boost::shared_ptr r) -{ - using namespace Menu_Helpers; - RedirectAutomationInfo *rai; - list::iterator x; - - const std::set& automatable = r->what_can_be_automated (); - std::set has_visible_automation; - - r->what_has_visible_automation(has_visible_automation); - - if (automatable.empty()) { - return; - } - - for (x = redirect_automation.begin(); x != redirect_automation.end(); ++x) { - if ((*x)->redirect == r) { - break; - } - } - - if (x == redirect_automation.end()) { - - rai = new RedirectAutomationInfo (r); - redirect_automation.push_back (rai); - - } else { - - rai = *x; - - } - - /* any older menu was deleted at the top of redirects_changed() - when we cleared the subplugin menu. - */ - - rai->menu = manage (new Menu); - MenuList& items = rai->menu->items(); - rai->menu->set_name ("ArdourContextMenu"); - - items.clear (); - - for (std::set::const_iterator i = automatable.begin(); i != automatable.end(); ++i) { - - RedirectAutomationNode* ran; - CheckMenuItem* mitem; - - string name = r->describe_parameter (*i); - - items.push_back (CheckMenuElem (name)); - mitem = dynamic_cast (&items.back()); - - if (has_visible_automation.find((*i)) != has_visible_automation.end()) { - mitem->set_active(true); - } - - if ((ran = find_redirect_automation_node (r, *i)) == 0) { - - /* new item */ - - ran = new RedirectAutomationNode (*i, mitem, *this); - - rai->lines.push_back (ran); - - } else { - - ran->menu_item = mitem; - - } - - mitem->signal_toggled().connect (bind (mem_fun(*this, &AudioTimeAxisView::redirect_menu_item_toggled), rai, ran)); - } - - /* add the menu for this redirect, because the subplugin - menu is always cleared at the top of redirects_changed(). - this is the result of some poor design in gtkmm and/or - GTK+. - */ - - subplugin_menu.items().push_back (MenuElem (r->name(), *rai->menu)); - rai->valid = true; -} - -void -AudioTimeAxisView::redirect_menu_item_toggled (AudioTimeAxisView::RedirectAutomationInfo* rai, - AudioTimeAxisView::RedirectAutomationNode* ran) -{ - bool showit = ran->menu_item->get_active(); - bool redraw = false; - - if (ran->view == 0 && showit) { - add_redirect_automation_curve (rai->redirect, ran->what); - redraw = true; - } - - if (showit != ran->view->marked_for_display()) { - - if (showit) { - ran->view->set_marked_for_display (true); - ran->view->canvas_display->show(); - } else { - rai->redirect->mark_automation_visible (ran->what, true); - ran->view->set_marked_for_display (false); - ran->view->hide (); - } - - redraw = true; - - } - - if (redraw && !no_redraw) { - - /* now trigger a redisplay */ - - _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ - - } -} - -void -AudioTimeAxisView::redirects_changed (void *src) -{ - using namespace Menu_Helpers; - - for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - (*i)->valid = false; - } - - subplugin_menu.items().clear (); - - _route->foreach_redirect (this, &AudioTimeAxisView::add_redirect_to_subplugin_menu); - _route->foreach_redirect (this, &AudioTimeAxisView::add_existing_redirect_automation_curves); - - for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ) { - - list::iterator tmp; - - tmp = i; - ++tmp; - - if (!(*i)->valid) { - - delete *i; - redirect_automation.erase (i); - - } - - i = tmp; - } - - /* change in visibility was possible */ - - _route->gui_changed ("track_height", this); -} - -RedirectAutomationLine * -AudioTimeAxisView::find_redirect_automation_curve (boost::shared_ptr redirect, uint32_t what) -{ - RedirectAutomationNode* ran; - - if ((ran = find_redirect_automation_node (redirect, what)) != 0) { - if (ran->view) { - return dynamic_cast (ran->view->lines.front()); - } - } - - return 0; -} - void AudioTimeAxisView::show_all_automation () { @@ -911,15 +510,7 @@ AudioTimeAxisView::show_all_automation () pan_automation_item->set_active (true); gain_automation_item->set_active (true); - for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - for (vector::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { - if ((*ii)->view == 0) { - add_redirect_automation_curve ((*i)->redirect, (*ii)->what); - } - - (*ii)->menu_item->set_active (true); - } - } + RouteTimeAxisView::show_all_automation (); no_redraw = false; @@ -934,13 +525,7 @@ AudioTimeAxisView::show_existing_automation () pan_automation_item->set_active (true); gain_automation_item->set_active (true); - for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - for (vector::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { - if ((*ii)->view != 0) { - (*ii)->menu_item->set_active (true); - } - } - } + RouteTimeAxisView::show_existing_automation (); no_redraw = false; @@ -955,36 +540,12 @@ AudioTimeAxisView::hide_all_automation () pan_automation_item->set_active (false); gain_automation_item->set_active (false); - for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - for (vector::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { - (*ii)->menu_item->set_active (false); - } - } + RouteTimeAxisView::hide_all_automation(); no_redraw = false; _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ } -void -AudioTimeAxisView::region_view_added (RegionView* rv) -{ - assert(dynamic_cast(rv)); - - for (vector::iterator i = children.begin(); i != children.end(); ++i) { - AutomationTimeAxisView* atv; - - if ((atv = dynamic_cast (*i)) != 0) { - rv->add_ghost (*atv); - } - } -} - -void -AudioTimeAxisView::add_ghost_to_redirect (RegionView* rv, AutomationTimeAxisView* atv) -{ - rv->add_ghost (*atv); -} - void AudioTimeAxisView::show_all_xfades () { @@ -1030,7 +591,7 @@ AudioTimeAxisView::reveal_dependent_views (TimeAxisViewItem& tavi) void AudioTimeAxisView::route_active_changed () { - RouteUI::route_active_changed (); + RouteTimeAxisView::route_active_changed (); if (is_audio_track()) { if (_route->active()) { diff --git a/gtk2_ardour/audio_time_axis.h b/gtk2_ardour/audio_time_axis.h index 2a6aa1c4d6..2162771285 100644 --- a/gtk2_ardour/audio_time_axis.h +++ b/gtk2_ardour/audio_time_axis.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,7 +33,6 @@ #include #include -#include #include "ardour_dialog.h" #include "route_ui.h" @@ -62,7 +61,6 @@ class AudioRegionView; class AutomationLine; class AutomationGainLine; class AutomationPanLine; -class RedirectAutomationLine; class TimeSelection; class AutomationTimeAxisView; @@ -78,11 +76,10 @@ class AudioTimeAxisView : public RouteTimeAxisView void set_show_waveforms_recording (bool yn); void show_all_xfades (); void hide_all_xfades (); - void set_selected_regionviews (RegionSelection&); void hide_dependent_views (TimeAxisViewItem&); void reveal_dependent_views (TimeAxisViewItem&); - /* overridden from parent to store display state */ + /* Overridden from parent to store display state */ guint32 show_at (double y, int& nth, Gtk::VBox *parent); void hide (); @@ -95,83 +92,16 @@ class AudioTimeAxisView : public RouteTimeAxisView void route_active_changed (); - AutomationTimeAxisView *gain_track; - AutomationTimeAxisView *pan_track; - - void update_automation_view (ARDOUR::AutomationType); - void reset_redirect_automation_curves (); - - // variables to get the context menu - // automation buttons correctly initialized - bool show_gain_automation; - bool show_pan_automation; - - // FIXME? - void redirects_changed (void *); - - void build_display_menu (); - - Gtk::CheckMenuItem* waveform_item; - Gtk::RadioMenuItem* traditional_item; - Gtk::RadioMenuItem* rectified_item; + void build_automation_action_menu (); + void append_extra_display_menu_items (); void toggle_show_waveforms (); - void set_waveform_shape (WaveformShape); void toggle_waveforms (); - /* automation stuff */ - - Gtk::Menu* automation_action_menu; - Gtk::CheckMenuItem* gain_automation_item; - Gtk::CheckMenuItem* pan_automation_item; - - void automation_click (); - void clear_automation (); - void hide_all_automation (); void show_all_automation (); void show_existing_automation (); - - struct RedirectAutomationNode { - uint32_t what; - Gtk::CheckMenuItem* menu_item; - AutomationTimeAxisView* view; - AudioTimeAxisView& parent; - - RedirectAutomationNode (uint32_t w, Gtk::CheckMenuItem* mitem, AudioTimeAxisView& p) - : what (w), menu_item (mitem), view (0), parent (p) {} - - ~RedirectAutomationNode (); - }; - - struct RedirectAutomationInfo { - boost::shared_ptr redirect; - bool valid; - Gtk::Menu* menu; - vector lines; - - RedirectAutomationInfo (boost::shared_ptr r) - : redirect (r), valid (true) {} - - ~RedirectAutomationInfo (); - }; - - list redirect_automation; - RedirectAutomationNode* find_redirect_automation_node (boost::shared_ptr redirect, uint32_t what); - - Gtk::Menu subplugin_menu; - void add_redirect_to_subplugin_menu (boost::shared_ptr); - - void remove_ran (RedirectAutomationNode* ran); - - void redirect_menu_item_toggled (AudioTimeAxisView::RedirectAutomationInfo*, - AudioTimeAxisView::RedirectAutomationNode*); - void redirect_automation_track_hidden (RedirectAutomationNode*, boost::shared_ptr); - - vector redirect_automation_curves; - RedirectAutomationLine *find_redirect_automation_curve (boost::shared_ptr,uint32_t); - void add_redirect_automation_curve (boost::shared_ptr, uint32_t); - void add_existing_redirect_automation_curves (boost::shared_ptr); + void hide_all_automation (); void add_gain_automation_child (); void add_pan_automation_child (); @@ -185,8 +115,18 @@ class AudioTimeAxisView : public RouteTimeAxisView void update_pans (); - void region_view_added (RegionView*); - void add_ghost_to_redirect (RegionView*, AutomationTimeAxisView*); + AutomationTimeAxisView* gain_track; + AutomationTimeAxisView* pan_track; + + // Set from XML so context menu automation buttons can be correctly initialized + bool show_gain_automation; + bool show_pan_automation; + + Gtk::CheckMenuItem* waveform_item; + Gtk::RadioMenuItem* traditional_item; + Gtk::RadioMenuItem* rectified_item; + Gtk::CheckMenuItem* gain_automation_item; + Gtk::CheckMenuItem* pan_automation_item; }; #endif /* __ardour_audio_time_axis_h__ */ diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 6edc738c41..fcd17cdb4c 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -209,15 +209,6 @@ Editor::Editor (AudioEngine& eng) toolbar_selection_clock_table (2,3), - //mouse_mode_button_table (2, 3), - - /*mouse_select_button (_("range")), - mouse_move_button (_("object")), - mouse_gain_button (_("gain")), - mouse_zoom_button (_("zoom")), - mouse_timefx_button (_("timefx")), - mouse_audition_button (_("listen")),*/ - automation_mode_button (_("mode")), global_automation_button (_("automation")), @@ -2588,9 +2579,8 @@ Editor::setup_toolbar () mouse_mode_button_box.pack_start(mouse_audition_button, true, true); mouse_mode_button_box.set_homogeneous(true); - // This one needs a little more "FUDGE" on my machine at least.. edit_mode_selector.set_name ("EditModeSelector"); - Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "Splice Edit", 3+FUDGE, 10); + Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "Splice Edit", 2+FUDGE, 10); set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings)); edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done)); diff --git a/gtk2_ardour/plugin_selector.h b/gtk2_ardour/plugin_selector.h index 220de74871..bbaf359aa4 100644 --- a/gtk2_ardour/plugin_selector.h +++ b/gtk2_ardour/plugin_selector.h @@ -29,6 +29,7 @@ namespace ARDOUR { class Session; class PluginManager; class Plugin; + class PluginInfo; } class PluginSelector : public ArdourDialog diff --git a/gtk2_ardour/regionview.cc b/gtk2_ardour/regionview.cc index d47b09853c..411117b1af 100644 --- a/gtk2_ardour/regionview.cc +++ b/gtk2_ardour/regionview.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2001 Paul Davis + Copyright (C) 2001-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -82,35 +82,21 @@ RegionView::RegionView (ArdourCanvas::Group* parent, } void -RegionView::init (Gdk::Color& basic_color, bool wfw) +RegionView::init (Gdk::Color& basic_color, bool wfd) { - ArdourCanvas::Points shape; - //XMLNode *node; - - editor = 0; - valid = true; + editor = 0; + valid = true; in_destructor = false; - _height = 0; - - _flags = 0; - - /* - if ((node = _region.extra_xml ("GUI")) != 0) { - set_flags (node); - } else { - //_flags = WaveformVisible; - store_flags (); - }*/ + _height = 0; + wait_for_data = wfd; compute_colors (basic_color); name_highlight->set_data ("regionview", this); name_text->set_data ("regionview", this); - // shape = new ArdourCanvas::Points (); - /* an equilateral triangle */ - + ArdourCanvas::Points shape; shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1)); shape.push_back (Gnome::Art::Point ((sync_mark_width - 1)/2, 1)); shape.push_back (Gnome::Art::Point (0, sync_mark_width - 1)); @@ -234,9 +220,6 @@ RegionView::region_resized (Change what_changed) (*i)->set_duration (unit_length); - /*for (vector::iterator w = (*i)->waves.begin(); w != (*i)->waves.end(); ++w) { - (*w)->property_region_start() = _region.start(); - }*/ } } } @@ -246,27 +229,6 @@ RegionView::reset_width_dependent_items (double pixel_width) { TimeAxisViewItem::reset_width_dependent_items (pixel_width); _pixel_width = pixel_width; -/* - if (zero_line) { - zero_line->property_x2() = pixel_width - 1.0; - } - - if (fade_in_handle) { - if (pixel_width <= 6.0) { - fade_in_handle->hide(); - fade_out_handle->hide(); - } else { - if (_height < 5.0) { - fade_in_handle->hide(); - fade_out_handle->hide(); - } else { - fade_in_handle->show(); - fade_out_handle->show(); - } - } - } - - reset_fade_shapes ();*/ } void @@ -282,14 +244,6 @@ RegionView::region_muted () { set_frame_color (); region_renamed (); - - /*for (uint32_t n=0; n < waves.size(); ++n) { - if (_region.muted()) { - waves[n]->property_wave_color() = color_map[cMutedWaveForm]; - } else { - waves[n]->property_wave_color() = color_map[cWaveForm]; - } - }*/ } void @@ -350,19 +304,11 @@ RegionView::set_samples_per_unit (gdouble spu) { TimeAxisViewItem::set_samples_per_unit (spu); - /*for (uint32_t n=0; n < waves.size(); ++n) { - waves[n]->property_samples_per_unit() = spu; - }*/ - for (vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { (*i)->set_samples_per_unit (spu); (*i)->set_duration (_region.length() / samples_per_unit); } - /*if (gain_line) { - gain_line->reset (); - }*/ - //reset_fade_shapes (); region_sync_changed (); } @@ -384,10 +330,6 @@ void RegionView::compute_colors (Gdk::Color& basic_color) { TimeAxisViewItem::compute_colors (basic_color); - uint32_t r, g, b, a; - - UINT_TO_RGBA (fill_color, &r, &g, &b, &a); - fade_color = RGBA_TO_UINT(r,g,b,120); } void @@ -395,21 +337,9 @@ RegionView::set_colors () { TimeAxisViewItem::set_colors (); - /*if (gain_line) { - gain_line->set_line_color (_region.envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]); - }*/ - if (sync_mark) { sync_mark->property_fill_color_rgba() = fill_color; } - - /*for (uint32_t n=0; n < waves.size(); ++n) { - if (_region.muted()) { - waves[n]->property_wave_color() = color_map[cMutedWaveForm]; - } else { - waves[n]->property_wave_color() = color_map[cWaveForm]; - } - }*/ } void @@ -445,10 +375,9 @@ RegionView::region_renamed () str = _region.name(); } - /* FIXME if (_region.speed_mismatch (trackview.session().frame_rate())) { str = string ("*") + str; - }*/ + } if (_region.muted()) { str = string ("!") + str; diff --git a/gtk2_ardour/regionview.h b/gtk2_ardour/regionview.h index 29c5817a25..d2d2c22760 100644 --- a/gtk2_ardour/regionview.h +++ b/gtk2_ardour/regionview.h @@ -49,7 +49,7 @@ class RegionView : public TimeAxisViewItem ~RegionView (); - virtual void init (Gdk::Color& base_color, bool wait_for_waves); + virtual void init (Gdk::Color& base_color, bool wait_for_data); ARDOUR::Region& region() const { return _region; } @@ -57,8 +57,8 @@ class RegionView : public TimeAxisViewItem void set_valid (bool yn) { valid = yn; } virtual void set_height (double) = 0; - void set_samples_per_unit (double); - bool set_duration (jack_nframes_t, void*); + virtual void set_samples_per_unit (double); + virtual bool set_duration (jack_nframes_t, void*); void move (double xdelta, double ydelta); @@ -70,9 +70,9 @@ class RegionView : public TimeAxisViewItem bool set_position(jack_nframes_t pos, void* src, double* delta = 0); virtual void show_region_editor () = 0; - void hide_region_editor(); + virtual void hide_region_editor(); - void region_changed (ARDOUR::Change); + virtual void region_changed (ARDOUR::Change); virtual GhostRegion* add_ghost (AutomationTimeAxisView&) = 0; void remove_ghost (GhostRegion*); @@ -93,56 +93,44 @@ class RegionView : public TimeAxisViewItem RegionView (ArdourCanvas::Group *, TimeAxisView&, ARDOUR::Region&, - double initial_samples_per_unit, + double samples_per_unit, Gdk::Color& basic_color, TimeAxisViewItem::Visibility); ARDOUR::Region& _region; - enum Flags { - EnvelopeVisible = 0x1, - WaveformVisible = 0x4, - WaveformRectified = 0x8 - }; - ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position - ArdourCanvas::Text* no_wave_msg; ///< text + ArdourCanvas::Text* no_wave_msg; RegionEditor *editor; vector control_points; double current_visible_sync_position; - uint32_t _flags; - uint32_t fade_color; bool valid; ///< see StreamView::redisplay_diskstream() double _pixel_width; double _height; bool in_destructor; - bool wait_for_waves; - - sigc::connection peaks_ready_connection; - - void region_resized (ARDOUR::Change); - void region_moved (void *); - void region_muted (); - void region_locked (); - void region_opacity (); - void region_layered (); - void region_renamed (); - void region_sync_changed (); - void region_scale_amplitude_changed (); + + bool wait_for_data; + sigc::connection data_ready_connection; + + virtual void region_resized (ARDOUR::Change); + void region_moved (void *); + virtual void region_muted (); + void region_locked (); + void region_opacity (); + void region_layered (); + void region_renamed (); + void region_sync_changed (); static gint _lock_toggle (ArdourCanvas::Item*, GdkEvent*, void*); void lock_toggle (); - void peaks_ready_handler (uint32_t); - void reset_name (gdouble width); - - void set_colors (); - void compute_colors (Gdk::Color&); + virtual void set_colors (); + virtual void compute_colors (Gdk::Color&); virtual void set_frame_color (); - void reset_width_dependent_items (double pixel_width); + virtual void reset_width_dependent_items (double pixel_width); vector ghosts; diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index b4f250b5ef..1eba885b44 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,6 +30,8 @@ #include #include +#include +#include #include #include #include @@ -49,6 +51,9 @@ #include "ardour_ui.h" #include "route_time_axis.h" +#include "automation_time_axis.h" +#include "redirect_automation_time_axis.h" +#include "redirect_automation_line.h" #include "canvas_impl.h" #include "crossfade_view.h" #include "enums.h" @@ -217,6 +222,12 @@ RouteTimeAxisView::~RouteTimeAxisView () { GoingAway (); /* EMIT_SIGNAL */ + vector_delete (&redirect_automation_curves); + + for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + delete *i; + } + if (playlist_menu) { delete playlist_menu; playlist_menu = 0; @@ -373,6 +384,97 @@ RouteTimeAxisView::automation_click () automation_action_menu->popup (1, 0); } +void +RouteTimeAxisView::build_automation_action_menu () +{ + using namespace Menu_Helpers; + + automation_action_menu = manage (new Menu); + MenuList& automation_items = automation_action_menu->items(); + automation_action_menu->set_name ("ArdourContextMenu"); + + automation_items.push_back (MenuElem (_("Show all automation"), + mem_fun(*this, &RouteTimeAxisView::show_all_automation))); + + automation_items.push_back (MenuElem (_("Show existing automation"), + mem_fun(*this, &RouteTimeAxisView::show_existing_automation))); + + automation_items.push_back (MenuElem (_("Hide all automation"), + mem_fun(*this, &RouteTimeAxisView::hide_all_automation))); + + automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu)); +} + +void +RouteTimeAxisView::build_display_menu () +{ + using namespace Menu_Helpers; + + /* get the size menu ready */ + + build_size_menu (); + + /* prepare it */ + + TimeAxisView::build_display_menu (); + + /* now fill it with our stuff */ + + MenuList& items = display_menu->items(); + display_menu->set_name ("ArdourContextMenu"); + + items.push_back (MenuElem (_("Height"), *size_menu)); + items.push_back (MenuElem (_("Color"), mem_fun(*this, &RouteTimeAxisView::select_track_color))); + + items.push_back (SeparatorElem()); + + build_remote_control_menu (); + items.push_back (MenuElem (_("Remote Control ID"), *remote_control_menu)); + + build_automation_action_menu (); + items.push_back (MenuElem (_("Automation"), *automation_action_menu)); + + // Hook for derived classes to add type specific stuff + items.push_back (SeparatorElem()); + append_extra_display_menu_items (); + items.push_back (SeparatorElem()); + + if (is_track()) { + + Menu* alignment_menu = manage (new Menu); + MenuList& alignment_items = alignment_menu->items(); + alignment_menu->set_name ("ArdourContextMenu"); + + RadioMenuItem::Group align_group; + + alignment_items.push_back (RadioMenuElem (align_group, _("Align with existing material"), + bind (mem_fun(*this, &RouteTimeAxisView::set_align_style), ExistingMaterial))); + align_existing_item = dynamic_cast(&alignment_items.back()); + if (get_diskstream()->alignment_style() == ExistingMaterial) + align_existing_item->set_active(); + + alignment_items.push_back (RadioMenuElem (align_group, _("Align with capture time"), + bind (mem_fun(*this, &RouteTimeAxisView::set_align_style), CaptureTime))); + align_capture_item = dynamic_cast(&alignment_items.back()); + if (get_diskstream()->alignment_style() == CaptureTime) + align_capture_item->set_active(); + + items.push_back (MenuElem (_("Alignment"), *alignment_menu)); + + get_diskstream()->AlignmentStyleChanged.connect ( + mem_fun(*this, &RouteTimeAxisView::align_style_changed)); + } + + items.push_back (SeparatorElem()); + items.push_back (CheckMenuElem (_("Active"), mem_fun(*this, &RouteUI::toggle_route_active))); + route_active_menu_item = dynamic_cast (&items.back()); + route_active_menu_item->set_active (_route->active()); + + items.push_back (SeparatorElem()); + items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route))); +} + + void RouteTimeAxisView::show_timestretch (jack_nframes_t start, jack_nframes_t end) { @@ -759,6 +861,12 @@ RouteTimeAxisView::set_selected_points (PointSelection& points) } } +void +RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions) +{ + _view->set_selected_regionviews (regions); +} + void RouteTimeAxisView::get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list& results) { @@ -1053,3 +1161,399 @@ RouteTimeAxisView::select_me (GdkEventButton* ev) return false; } +void +RouteTimeAxisView::show_all_automation () +{ + no_redraw = true; + + for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + for (vector::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { + if ((*ii)->view == 0) { + add_redirect_automation_curve ((*i)->redirect, (*ii)->what); + } + + (*ii)->menu_item->set_active (true); + } + } + + no_redraw = false; + + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ +} + +void +RouteTimeAxisView::show_existing_automation () +{ + no_redraw = true; + + for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + for (vector::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { + if ((*ii)->view != 0) { + (*ii)->menu_item->set_active (true); + } + } + } + + no_redraw = false; + + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ +} + +void +RouteTimeAxisView::hide_all_automation () +{ + no_redraw = true; + + for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + for (vector::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { + (*ii)->menu_item->set_active (false); + } + } + + no_redraw = false; + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ +} + + +void +RouteTimeAxisView::region_view_added (RegionView* rv) +{ + for (vector::iterator i = children.begin(); i != children.end(); ++i) { + AutomationTimeAxisView* atv; + + if ((atv = dynamic_cast (*i)) != 0) { + rv->add_ghost (*atv); + } + } +} + +void +RouteTimeAxisView::add_ghost_to_redirect (RegionView* rv, AutomationTimeAxisView* atv) +{ + rv->add_ghost (*atv); +} + +RouteTimeAxisView::RedirectAutomationInfo::~RedirectAutomationInfo () +{ + for (vector::iterator i = lines.begin(); i != lines.end(); ++i) { + delete *i; + } +} + + +RouteTimeAxisView::RedirectAutomationNode::~RedirectAutomationNode () +{ + parent.remove_ran (this); + + if (view) { + delete view; + } +} + +void +RouteTimeAxisView::remove_ran (RedirectAutomationNode* ran) +{ + if (ran->view) { + remove_child (ran->view); + } +} + +RouteTimeAxisView::RedirectAutomationNode* +RouteTimeAxisView::find_redirect_automation_node (boost::shared_ptr redirect, uint32_t what) +{ + for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + + if ((*i)->redirect == redirect) { + + for (vector::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) { + if ((*ii)->what == what) { + return *ii; + } + } + } + } + + return 0; +} + +// FIXME: duplicated in midi_time_axis.cc +static string +legalize_for_xml_node (string str) +{ + string::size_type pos; + string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=:"; + string legal; + + legal = str; + pos = 0; + + while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) { + legal.replace (pos, 1, "_"); + pos += 1; + } + + return legal; +} + + +void +RouteTimeAxisView::add_redirect_automation_curve (boost::shared_ptr redirect, uint32_t what) +{ + RedirectAutomationLine* ral; + string name; + RedirectAutomationNode* ran; + + if ((ran = find_redirect_automation_node (redirect, what)) == 0) { + fatal << _("programming error: ") + << string_compose (X_("redirect automation curve for %1:%2 not registered with audio track!"), + redirect->name(), what) + << endmsg; + /*NOTREACHED*/ + return; + } + + if (ran->view) { + return; + } + + name = redirect->describe_parameter (what); + + /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */ + + char state_name[256]; + snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (redirect->name()).c_str(), what); + + ran->view = new RedirectAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, name, what, *redirect, state_name); + + ral = new RedirectAutomationLine (name, + *redirect, what, _session, *ran->view, + *ran->view->canvas_display, redirect->automation_list (what)); + + ral->set_line_color (color_map[cRedirectAutomationLine]); + ral->queue_reset (); + + ran->view->add_line (*ral); + + ran->view->Hiding.connect (bind (mem_fun(*this, &RouteTimeAxisView::redirect_automation_track_hidden), ran, redirect)); + + if (!ran->view->marked_for_display()) { + ran->view->hide (); + } else { + ran->menu_item->set_active (true); + } + + add_child (ran->view); + + _view->foreach_regionview (bind (mem_fun(*this, &RouteTimeAxisView::add_ghost_to_redirect), ran->view)); + + redirect->mark_automation_visible (what, true); +} + +void +RouteTimeAxisView::redirect_automation_track_hidden (RouteTimeAxisView::RedirectAutomationNode* ran, boost::shared_ptr r) +{ + if (!_hidden) { + ran->menu_item->set_active (false); + } + + r->mark_automation_visible (ran->what, false); + + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ +} + +void +RouteTimeAxisView::add_existing_redirect_automation_curves (boost::shared_ptr redirect) +{ + set s; + RedirectAutomationLine *ral; + + redirect->what_has_visible_automation (s); + + for (set::iterator i = s.begin(); i != s.end(); ++i) { + + if ((ral = find_redirect_automation_curve (redirect, *i)) != 0) { + ral->queue_reset (); + } else { + add_redirect_automation_curve (redirect, (*i)); + } + } +} + +void +RouteTimeAxisView::add_redirect_to_subplugin_menu (boost::shared_ptr r) +{ + using namespace Menu_Helpers; + RedirectAutomationInfo *rai; + list::iterator x; + + const std::set& automatable = r->what_can_be_automated (); + std::set has_visible_automation; + + r->what_has_visible_automation(has_visible_automation); + + if (automatable.empty()) { + return; + } + + for (x = redirect_automation.begin(); x != redirect_automation.end(); ++x) { + if ((*x)->redirect == r) { + break; + } + } + + if (x == redirect_automation.end()) { + + rai = new RedirectAutomationInfo (r); + redirect_automation.push_back (rai); + + } else { + + rai = *x; + + } + + /* any older menu was deleted at the top of redirects_changed() + when we cleared the subplugin menu. + */ + + rai->menu = manage (new Menu); + MenuList& items = rai->menu->items(); + rai->menu->set_name ("ArdourContextMenu"); + + items.clear (); + + for (std::set::const_iterator i = automatable.begin(); i != automatable.end(); ++i) { + + RedirectAutomationNode* ran; + CheckMenuItem* mitem; + + string name = r->describe_parameter (*i); + + items.push_back (CheckMenuElem (name)); + mitem = dynamic_cast (&items.back()); + + if (has_visible_automation.find((*i)) != has_visible_automation.end()) { + mitem->set_active(true); + } + + if ((ran = find_redirect_automation_node (r, *i)) == 0) { + + /* new item */ + + ran = new RedirectAutomationNode (*i, mitem, *this); + + rai->lines.push_back (ran); + + } else { + + ran->menu_item = mitem; + + } + + mitem->signal_toggled().connect (bind (mem_fun(*this, &RouteTimeAxisView::redirect_menu_item_toggled), rai, ran)); + } + + /* add the menu for this redirect, because the subplugin + menu is always cleared at the top of redirects_changed(). + this is the result of some poor design in gtkmm and/or + GTK+. + */ + + subplugin_menu.items().push_back (MenuElem (r->name(), *rai->menu)); + rai->valid = true; +} + +void +RouteTimeAxisView::redirect_menu_item_toggled (RouteTimeAxisView::RedirectAutomationInfo* rai, + RouteTimeAxisView::RedirectAutomationNode* ran) +{ + bool showit = ran->menu_item->get_active(); + bool redraw = false; + + if (ran->view == 0 && showit) { + add_redirect_automation_curve (rai->redirect, ran->what); + redraw = true; + } + + if (showit != ran->view->marked_for_display()) { + + if (showit) { + ran->view->set_marked_for_display (true); + ran->view->canvas_display->show(); + } else { + rai->redirect->mark_automation_visible (ran->what, true); + ran->view->set_marked_for_display (false); + ran->view->hide (); + } + + redraw = true; + + } + + if (redraw && !no_redraw) { + + /* now trigger a redisplay */ + + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + + } +} + +void +RouteTimeAxisView::redirects_changed (void *src) +{ + using namespace Menu_Helpers; + + for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { + (*i)->valid = false; + } + + subplugin_menu.items().clear (); + + _route->foreach_redirect (this, &RouteTimeAxisView::add_redirect_to_subplugin_menu); + _route->foreach_redirect (this, &RouteTimeAxisView::add_existing_redirect_automation_curves); + + for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ) { + + list::iterator tmp; + + tmp = i; + ++tmp; + + if (!(*i)->valid) { + + delete *i; + redirect_automation.erase (i); + + } + + i = tmp; + } + + /* change in visibility was possible */ + + _route->gui_changed ("track_height", this); +} + +RedirectAutomationLine * +RouteTimeAxisView::find_redirect_automation_curve (boost::shared_ptr redirect, uint32_t what) +{ + RedirectAutomationNode* ran; + + if ((ran = find_redirect_automation_node (redirect, what)) != 0) { + if (ran->view) { + return dynamic_cast (ran->view->lines.front()); + } + } + + return 0; +} + +void +RouteTimeAxisView::reset_redirect_automation_curves () +{ + for (vector::iterator i = redirect_automation_curves.begin(); i != redirect_automation_curves.end(); ++i) { + (*i)->reset(); + } +} + diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h index a75851b8a8..476a135c39 100644 --- a/gtk2_ardour/route_time_axis.h +++ b/gtk2_ardour/route_time_axis.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,7 +33,6 @@ #include #include -#include #include "ardour_dialog.h" #include "route_ui.h" @@ -44,6 +43,7 @@ namespace ARDOUR { class Session; + class Region; class Diskstream; class RouteGroup; class Redirect; @@ -57,12 +57,14 @@ class RegionView; class StreamView; class Selection; class Selectable; +class AutomationTimeAxisView; class AutomationLine; +class RedirectAutomationLine; class TimeSelection; class RouteTimeAxisView : public RouteUI, public TimeAxisView { - public: +public: RouteTimeAxisView (PublicEditor&, ARDOUR::Session&, boost::shared_ptr, ArdourCanvas::Canvas& canvas); virtual ~RouteTimeAxisView (); @@ -74,51 +76,57 @@ class RouteTimeAxisView : public RouteUI, public TimeAxisView void hide_timestretch (); void selection_click (GdkEventButton*); void set_selected_points (PointSelection&); + void set_selected_regionviews (RegionSelection&); void get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list&); void get_inverted_selectables (Selection&, list&); ARDOUR::Region* find_next_region (jack_nframes_t pos, ARDOUR::RegionPoint, int32_t dir); - string name() const; - - ARDOUR::RouteGroup* edit_group() const; - - void build_playlist_menu (Gtk::Menu *); - ARDOUR::Playlist* playlist() const; - - StreamView* view() { return _view; } - - /* editing operations */ - + /* Editing operations */ bool cut_copy_clear (Selection&, Editing::CutCopyOp); bool paste (jack_nframes_t, float times, Selection&, size_t nth); list get_child_list(); - /* the editor calls these when mapping an operation across multiple tracks */ - + /* The editor calls these when mapping an operation across multiple tracks */ void use_new_playlist (bool prompt); void use_copy_playlist (bool prompt); void clear_playlist (); + + void build_playlist_menu (Gtk::Menu *); + + string name() const; + StreamView* view() const { return _view; } + ARDOUR::RouteGroup* edit_group() const; + ARDOUR::Playlist* playlist() const; - //private: (FIXME) +protected: friend class StreamView; - StreamView *_view; + struct RedirectAutomationNode { + uint32_t what; + Gtk::CheckMenuItem* menu_item; + AutomationTimeAxisView* view; + RouteTimeAxisView& parent; - ArdourCanvas::Canvas& parent_canvas; + RedirectAutomationNode (uint32_t w, Gtk::CheckMenuItem* mitem, RouteTimeAxisView& p) + : what (w), menu_item (mitem), view (0), parent (p) {} - bool no_redraw; - - Gtk::HBox other_button_hbox; - Gtk::Table button_table; - Gtk::Button redirect_button; - Gtk::Button edit_group_button; - Gtk::Button playlist_button; - Gtk::Button size_button; - Gtk::Button automation_button; - Gtk::Button hide_button; - Gtk::Button visual_button; + ~RedirectAutomationNode (); + }; + + struct RedirectAutomationInfo { + boost::shared_ptr redirect; + bool valid; + Gtk::Menu* menu; + vector lines; + + RedirectAutomationInfo (boost::shared_ptr r) + : redirect (r), valid (true), menu (0) {} + + ~RedirectAutomationInfo (); + }; + void diskstream_changed (void *src); void update_diskstream_display (); @@ -133,11 +141,30 @@ class RouteTimeAxisView : public RouteUI, public TimeAxisView void redirect_relist (); void redirect_row_selected (gint row, gint col, GdkEvent *ev); void add_to_redirect_display (ARDOUR::Redirect *); - //void redirects_changed (void *); + void redirects_changed (void *); + + void add_redirect_to_subplugin_menu (boost::shared_ptr); + void remove_ran (RedirectAutomationNode* ran); - sigc::connection modified_connection; - sigc::connection state_changed_connection; + void redirect_menu_item_toggled (RouteTimeAxisView::RedirectAutomationInfo*, + RouteTimeAxisView::RedirectAutomationNode*); + + void redirect_automation_track_hidden (RedirectAutomationNode*, + boost::shared_ptr); + + RedirectAutomationNode* + find_redirect_automation_node (boost::shared_ptr r, uint32_t); + + RedirectAutomationLine* + find_redirect_automation_curve (boost::shared_ptr r, uint32_t); + void add_redirect_automation_curve (boost::shared_ptr r, uint32_t); + void add_existing_redirect_automation_curves (boost::shared_ptr); + + void reset_redirect_automation_curves (); + + void update_automation_view (ARDOUR::AutomationType); + void take_name_changed (void *); void route_name_changed (void *); void name_entry_changed (); @@ -145,9 +172,7 @@ class RouteTimeAxisView : public RouteUI, public TimeAxisView void on_area_realize (); virtual void label_view (); - - Gtk::Menu edit_group_menu; - + void add_edit_group_menu_item (ARDOUR::RouteGroup *, Gtk::RadioMenuItem::Group*); void set_edit_group_from_menu (ARDOUR::RouteGroup *); @@ -155,35 +180,27 @@ class RouteTimeAxisView : public RouteUI, public TimeAxisView void select_track_color(); - virtual void build_display_menu () = 0; - - Gtk::RadioMenuItem* align_existing_item; - Gtk::RadioMenuItem* align_capture_item; + virtual void build_automation_action_menu (); + virtual void append_extra_display_menu_items () {} + void build_display_menu (); void align_style_changed (); void set_align_style (ARDOUR::AlignStyle); - - Gtk::Menu *playlist_menu; - Gtk::Menu *playlist_action_menu; - Gtk::MenuItem *playlist_item; - /* playlist */ - virtual void set_playlist (ARDOUR::Playlist *); - void playlist_click (); - void show_playlist_selector (); - - void playlist_changed (); - void playlist_state_changed (ARDOUR::Change); - void playlist_modified (); + void playlist_click (); + void show_playlist_selector (); + void playlist_changed (); + void playlist_state_changed (ARDOUR::Change); + void playlist_modified (); void add_playlist_to_playlist_menu (ARDOUR::Playlist*); void rename_current_playlist (); - Gtk::Menu* automation_action_menu; - void automation_click (); - - ArdourCanvas::SimpleRect *timestretch_rect; + void automation_click (); + virtual void show_all_automation (); + virtual void show_existing_automation (); + virtual void hide_all_automation (); void timestretch (jack_nframes_t start, jack_nframes_t end); @@ -198,7 +215,40 @@ class RouteTimeAxisView : public RouteUI, public TimeAxisView void color_handler (ColorID, uint32_t); bool select_me (GdkEventButton*); - virtual void region_view_added (RegionView*) = 0; + void region_view_added (RegionView*); + void add_ghost_to_redirect (RegionView*, AutomationTimeAxisView*); + + + StreamView* _view; + ArdourCanvas::Canvas& parent_canvas; + bool no_redraw; + + Gtk::HBox other_button_hbox; + Gtk::Table button_table; + Gtk::Button redirect_button; + Gtk::Button edit_group_button; + Gtk::Button playlist_button; + Gtk::Button size_button; + Gtk::Button automation_button; + Gtk::Button hide_button; + Gtk::Button visual_button; + + Gtk::Menu subplugin_menu; + Gtk::Menu* automation_action_menu; + Gtk::Menu edit_group_menu; + Gtk::RadioMenuItem* align_existing_item; + Gtk::RadioMenuItem* align_capture_item; + Gtk::Menu* playlist_menu; + Gtk::Menu* playlist_action_menu; + Gtk::MenuItem* playlist_item; + + ArdourCanvas::SimpleRect* timestretch_rect; + + list redirect_automation; + vector redirect_automation_curves; + + sigc::connection modified_connection; + sigc::connection state_changed_connection; }; #endif /* __ardour_route_time_axis_h__ */ diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc index 93d25b6a97..c94184272e 100644 --- a/gtk2_ardour/streamview.cc +++ b/gtk2_ardour/streamview.cc @@ -60,7 +60,6 @@ StreamView::StreamView (RouteTimeAxisView& tv) canvas_rect->property_y1() = 0.0; canvas_rect->property_x2() = 1000000.0; canvas_rect->property_y2() = (double) tv.height; - canvas_rect->property_outline_color_rgba() = color_map[cAudioTrackOutline]; // FIXME canvas_rect->property_outline_what() = (guint32) (0x1|0x2|0x8); // outline ends and bottom canvas_rect->property_fill_color_rgba() = stream_base_color; diff --git a/gtk2_ardour/streamview.h b/gtk2_ardour/streamview.h index f2906d40c4..baa779ba67 100644 --- a/gtk2_ardour/streamview.h +++ b/gtk2_ardour/streamview.h @@ -98,35 +98,37 @@ public: protected: StreamView (RouteTimeAxisView&); -//private: - void update_rec_box (); - void transport_changed(); - void rec_enable_changed(void* src = 0); - void sess_rec_enable_changed(); +//private: (FIXME?) + + void transport_changed(); + void rec_enable_changed(void* src = 0); + void sess_rec_enable_changed(); virtual void setup_rec_box () = 0; - void rec_peak_range_ready (jack_nframes_t start, jack_nframes_t cnt, ARDOUR::Source* src); + void update_rec_box (); virtual void update_rec_regions () = 0; virtual void add_region_view_internal (ARDOUR::Region*, bool wait_for_waves) = 0; virtual void remove_region_view (ARDOUR::Region* ); - void remove_rec_region (ARDOUR::Region*); + void remove_rec_region (ARDOUR::Region*); - void display_diskstream (ARDOUR::Diskstream* ); + void display_diskstream (ARDOUR::Diskstream* ); virtual void undisplay_diskstream (); virtual void redisplay_diskstream () = 0; - void diskstream_changed (void* ); - void playlist_state_changed (ARDOUR::Change); + void diskstream_changed (void* ); + + void playlist_state_changed (ARDOUR::Change); virtual void playlist_changed (ARDOUR::Diskstream* ); virtual void playlist_modified (); + + virtual void color_handler (ColorID, uint32_t) = 0; - RouteTimeAxisView& _trackview; - + RouteTimeAxisView& _trackview; ArdourCanvas::Group* canvas_group; ArdourCanvas::SimpleRect* canvas_rect; /* frame around the whole thing */ typedef list RegionViewList; - RegionViewList region_views; + RegionViewList region_views; double _samples_per_unit; @@ -141,8 +143,6 @@ protected: Gdk::Color region_color; uint32_t stream_base_color; - virtual void color_handler (ColorID, uint32_t) = 0; - vector playlist_connections; sigc::connection playlist_change_connection; }; diff --git a/gtk2_ardour/taperegionview.cc b/gtk2_ardour/taperegionview.cc index 76fd91337e..19e6ba3ad3 100644 --- a/gtk2_ardour/taperegionview.cc +++ b/gtk2_ardour/taperegionview.cc @@ -63,53 +63,9 @@ TapeAudioRegionView::TapeAudioRegionView (ArdourCanvas::Group *parent, RouteTime void TapeAudioRegionView::init (Gdk::Color& basic_color, bool wfw) { - XMLNode *node; - - editor = 0; - valid = true; - in_destructor = false; - _amplitude_above_axis = 1.0; - zero_line = 0; - wait_for_waves = wfw; - _height = 0; - - _flags = 0; - - if ((node = _region.extra_xml ("GUI")) != 0) { - set_flags (node); - } else { - _flags = WaveformVisible; - store_flags (); - } - - fade_in_handle = 0; - fade_out_handle = 0; - gain_line = 0; - sync_mark = 0; - - compute_colors (basic_color); - - create_waves (); - - name_highlight->set_data ("regionview", this); - - reset_width_dependent_items ((double) _region.length() / samples_per_unit); - - set_height (trackview.height); - - region_muted (); - region_resized (BoundsChanged); - set_waveview_data_src(); - region_locked (); - - /* no events, no state changes */ - - set_colors (); - - // ColorChanged.connect (mem_fun (*this, &AudioRegionView::color_handler)); + AudioRegionView::init(basic_color, wfw); /* every time the wave data changes and peaks are ready, redraw */ - for (uint32_t n = 0; n < audio_region().n_channels(); ++n) { audio_region().source(n).PeaksReady.connect (bind (mem_fun(*this, &TapeAudioRegionView::update), n)); diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index c4a942a5d7..ec15cf1caf 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,8 +14,6 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - $Id: diskstream.h 579 2006-06-12 19:56:37Z essej $ */ #ifndef __ardour_audio_diskstream_h__ @@ -62,18 +60,12 @@ class AudioDiskstream : public Diskstream AudioDiskstream (Session &, const string& name, Diskstream::Flag f = Recordable); AudioDiskstream (Session &, const XMLNode&); - void set_io (ARDOUR::IO& io); - + // FIXME AudioDiskstream& ref() { _refcnt++; return *this; } - //void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; } - //uint32_t refcnt() const { return _refcnt; } float playback_buffer_load() const; float capture_buffer_load() const; - //void set_align_style (AlignStyle); - //void set_persistent_align_style (AlignStyle); - string input_source (uint32_t n=0) const { if (n < channels.size()) { return channels[n].source ? channels[n].source->name() : ""; @@ -87,7 +79,6 @@ class AudioDiskstream : public Diskstream } void set_record_enabled (bool yn, void *src); - //void set_speed (double); float peak_power(uint32_t n=0) { float x = channels[n].peak_power; @@ -98,16 +89,13 @@ class AudioDiskstream : public Diskstream return minus_infinity(); } } + + AudioPlaylist* audio_playlist () { return dynamic_cast(_playlist); } int use_playlist (Playlist *); int use_new_playlist (); int use_copy_playlist (); - void start_scrub (jack_nframes_t where) {} // FIXME? - void end_scrub () {} // FIXME? - - Playlist *playlist () { return _playlist; } - Sample *playback_buffer (uint32_t n=0) { if (n < channels.size()) return channels[n].current_playback_buffer; @@ -137,7 +125,6 @@ class AudioDiskstream : public Diskstream void monitor_input (bool); - // FIXME: these don't belong here static void swap_by_ptr (Sample *first, Sample *last) { while (first < last) { Sample tmp = *first; @@ -154,11 +141,6 @@ class AudioDiskstream : public Diskstream } } - //void handle_input_change (IOChange, void *src); - - //static sigc::signal DiskOverrun; - //static sigc::signal DiskUnderrun; - //static sigc::signal AudioDiskstreamCreated; // XXX use a ref with sigc2 static sigc::signal*> DeleteSources; int set_loop (Location *loc); @@ -168,8 +150,6 @@ class AudioDiskstream : public Diskstream return _last_capture_regions; } - void handle_input_change (IOChange, void *src); - const PBD::ID& id() const { return _id; } XMLNode* deprecated_io_node; @@ -184,7 +164,6 @@ class AudioDiskstream : public Diskstream void set_pending_overwrite(bool); int overwrite_existing_buffers (); - void reverse_scrub_buffer (bool to_forward) {} // FIXME? void set_block_size (jack_nframes_t); int internal_playback_seek (jack_nframes_t distance); int can_internal_playback_seek (jack_nframes_t distance); @@ -237,60 +216,30 @@ class AudioDiskstream : public Diskstream jack_nframes_t curr_capture_cnt; }; - typedef vector ChannelList; - - /* the two central butler operations */ - - int do_flush (char * workbuf, bool force = false); - int do_refill (Sample *mixdown_buffer, float *gain_buffer, char *workbuf); + /* The two central butler operations */ + int do_flush (Session::RunContext context, bool force = false); + int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer, _conversion_buffer); } - virtual int non_realtime_do_refill() { return do_refill(0, 0, 0); } + int do_refill_with_alloc(); - int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt, - ChannelInfo& channel_info, int channel, bool reversed); - - /* XXX fix this redundancy ... */ - - //void playlist_changed (Change); - //void playlist_modified (); - void playlist_deleted (Playlist*); - void session_controls_changed (Session::ControlType) {} // FIXME? + int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf, + jack_nframes_t& start, jack_nframes_t cnt, + ChannelInfo& channel_info, int channel, bool reversed); void finish_capture (bool rec_monitors_input); - void clean_up_capture (struct tm&, time_t, bool abort) {} // FIXME? void transport_stopped (struct tm&, time_t, bool abort); - struct CaptureInfo { - uint32_t start; - uint32_t frames; - }; - - vector capture_info; - Glib::Mutex capture_info_lock; - void init (Diskstream::Flag); void init_channel (ChannelInfo &chan); void destroy_channel (ChannelInfo &chan); int use_new_write_source (uint32_t n=0); - int use_new_fade_source (uint32_t n=0) { return 0; } // FIXME? int find_and_use_playlist (const string&); void allocate_temporary_buffers (); - int create_input_port () { return 0; } // FIXME? - int connect_input_port () { return 0; } // FIXME? - int seek_unlocked (jack_nframes_t which_sample) { return 0; } // FIXME? - - int ports_created () { return 0; } // FIXME? - - //bool realtime_set_speed (double, bool global_change); - void non_realtime_set_speed (); - - std::list _last_capture_regions; - std::vector capturing_sources; int use_pending_capture_data (XMLNode& node); void get_input_sources (); @@ -299,10 +248,26 @@ class AudioDiskstream : public Diskstream void setup_destructive_playlist (); void use_destructive_playlist (); - ChannelList channels; - AudioPlaylist* _playlist; void engage_record_enable (void* src); void disengage_record_enable (void* src); + + // Working buffers for do_refill (butler thread) + static void allocate_working_buffers(); + static void free_working_buffers(); + + static size_t _working_buffers_size; + static Sample* _mixdown_buffer; + static gain_t* _gain_buffer; + static char* _conversion_buffer; + + // Uh, /really/ private? (death to friend classes) + int _do_refill (Sample *mixdown_buffer, float *gain_buffer, char *workbuf); + + + std::vector capturing_sources; + + typedef vector ChannelList; + ChannelList channels; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h index b595879264..ff25127ec9 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -52,7 +52,6 @@ class AudioEngine; class Send; class Session; class Playlist; -//class FileSource; class IO; /* FIXME: There are (obviously) far too many virtual functions in this ATM. @@ -71,10 +70,10 @@ class Diskstream : public Stateful, public sigc::trackable virtual int set_name (string str, void* src); ARDOUR::IO* io() const { return _io; } - virtual void set_io (ARDOUR::IO& io) = 0; + void set_io (ARDOUR::IO& io); virtual Diskstream& ref() { _refcnt++; return *this; } - void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; } + void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; } uint32_t refcnt() const { return _refcnt; } virtual float playback_buffer_load() const = 0; @@ -105,17 +104,15 @@ class Diskstream : public Stateful, public sigc::trackable virtual void punch_in() {} virtual void punch_out() {} - virtual void set_speed (double); - virtual void non_realtime_set_speed () = 0; + void set_speed (double); + void non_realtime_set_speed (); - virtual Playlist *playlist () = 0; + Playlist* playlist () { return _playlist; } + + virtual int use_playlist (Playlist *); virtual int use_new_playlist () = 0; - virtual int use_playlist (Playlist *) = 0; virtual int use_copy_playlist () = 0; - virtual void start_scrub (jack_nframes_t where) = 0; - virtual void end_scrub () = 0; - jack_nframes_t current_capture_start() const { return capture_start_frame; } jack_nframes_t current_capture_end() const { return capture_start_frame + capture_captured; } jack_nframes_t get_capture_start_frame (uint32_t n=0); @@ -123,7 +120,7 @@ class Diskstream : public Stateful, public sigc::trackable uint32_t n_channels() { return _n_channels; } - static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; } + static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; } static void set_disk_io_chunk_frames (uint32_t n) { disk_io_chunk_frames = n; } /* Stateful */ @@ -144,7 +141,7 @@ class Diskstream : public Stateful, public sigc::trackable std::list& last_capture_regions () { return _last_capture_regions; } - virtual void handle_input_change (IOChange, void *src); + void handle_input_change (IOChange, void *src); sigc::signal RecordEnableChanged; sigc::signal SpeedChanged; @@ -170,7 +167,6 @@ class Diskstream : public Stateful, public sigc::trackable virtual void set_pending_overwrite (bool) = 0; virtual int overwrite_existing_buffers () = 0; - virtual void reverse_scrub_buffer (bool to_forward) = 0; virtual void set_block_size (jack_nframes_t) = 0; virtual int internal_playback_seek (jack_nframes_t distance) = 0; virtual int can_internal_playback_seek (jack_nframes_t distance) = 0; @@ -209,25 +205,21 @@ class Diskstream : public Stateful, public sigc::trackable jack_nframes_t capture_val; }; - /* the two central butler operations */ - - virtual int do_flush (char * workbuf, bool force = false) = 0; - //int do_refill (Sample *mixdown_buffer, float *gain_buffer, char *workbuf); + /* The two central butler operations */ + virtual int do_flush (Session::RunContext context, bool force = false) = 0; + virtual int do_refill () = 0; - virtual int non_realtime_do_refill() = 0; + /** For non-butler contexts (allocates temporary working buffers) */ + virtual int do_refill_with_alloc() = 0; - //int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt, - // ChannelInfo& channel_info, int channel, bool reversed); /* XXX fix this redundancy ... */ virtual void playlist_changed (Change); virtual void playlist_modified (); - virtual void playlist_deleted (Playlist*) = 0; - virtual void session_controls_changed (Session::ControlType) = 0; + virtual void playlist_deleted (Playlist*); virtual void finish_capture (bool rec_monitors_input) = 0; - virtual void clean_up_capture (struct tm&, time_t, bool abort) = 0; virtual void transport_stopped (struct tm&, time_t, bool abort) = 0; struct CaptureInfo { @@ -237,37 +229,23 @@ class Diskstream : public Stateful, public sigc::trackable virtual void init (Flag); - //void init_channel (ChannelInfo &chan); - //void destroy_channel (ChannelInfo &chan); - virtual int use_new_write_source (uint32_t n=0) = 0; - virtual int use_new_fade_source (uint32_t n=0) = 0; virtual int find_and_use_playlist (const string&) = 0; - //void allocate_temporary_buffers (); - - virtual int create_input_port () = 0; - virtual int connect_input_port () = 0; - virtual int seek_unlocked (jack_nframes_t which_sample) = 0; - - virtual int ports_created () = 0; + virtual void allocate_temporary_buffers () = 0; virtual bool realtime_set_speed (double, bool global_change); - //void non_realtime_set_speed (); std::list _last_capture_regions; - //std::vector capturing_sources; virtual int use_pending_capture_data (XMLNode& node) = 0; virtual void get_input_sources () = 0; virtual void check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record) = 0; - //void set_align_style_from_io(); + virtual void set_align_style_from_io() {} virtual void setup_destructive_playlist () = 0; - //void use_destructive_playlist (); + virtual void use_destructive_playlist () = 0; - // Wouldn't hurt for this thing to do on a diet: - static jack_nframes_t disk_io_chunk_frames; vector capture_info; Glib::Mutex capture_info_lock; @@ -279,6 +257,7 @@ class Diskstream : public Stateful, public sigc::trackable ARDOUR::IO* _io; uint32_t _n_channels; PBD::ID _id; + Playlist* _playlist; mutable gint _record_enabled; double _visible_speed; @@ -338,7 +317,6 @@ class Diskstream : public Stateful, public sigc::trackable sigc::connection plgone_connection; unsigned char _flags; - }; }; /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h index b6121d1176..5998363d69 100644 --- a/libs/ardour/ardour/midi_diskstream.h +++ b/libs/ardour/ardour/midi_diskstream.h @@ -80,9 +80,6 @@ class MidiDiskstream : public Diskstream int use_new_playlist (); int use_copy_playlist (); - void start_scrub (jack_nframes_t where) {} // FIXME? - void end_scrub () {} // FIXME? - Playlist *playlist () { return _playlist; } static sigc::signal*> DeleteSources; @@ -106,7 +103,6 @@ class MidiDiskstream : public Diskstream void set_pending_overwrite(bool); int overwrite_existing_buffers (); - void reverse_scrub_buffer (bool to_forward) {} // FIXME? void set_block_size (jack_nframes_t); int internal_playback_seek (jack_nframes_t distance); int can_internal_playback_seek (jack_nframes_t distance); @@ -134,12 +130,11 @@ class MidiDiskstream : public Diskstream MidiPlaylist* _playlist; - /* the two central butler operations */ - - int do_flush (char * workbuf, bool force = false); - int do_refill (RawMidi *mixdown_buffer, float *gain_buffer, char *workbuf); + /*Tthe two central butler operations */ + int do_flush (Session::RunContext context, bool force = false) { return 0; } + int do_refill () { return 0; } - virtual int non_realtime_do_refill() { return do_refill(0, 0, 0); } + int do_refill_with_alloc() { return 0; } int read (RawMidi* buf, RawMidi* mixdown_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed); @@ -148,10 +143,8 @@ class MidiDiskstream : public Diskstream //void playlist_changed (Change); //void playlist_modified (); void playlist_deleted (Playlist*); - void session_controls_changed (Session::ControlType) {} // FIXME? void finish_capture (bool rec_monitors_input); - void clean_up_capture (struct tm&, time_t, bool abort) {} // FIXME? void transport_stopped (struct tm&, time_t, bool abort); struct CaptureInfo { @@ -162,18 +155,11 @@ class MidiDiskstream : public Diskstream void init (Diskstream::Flag); int use_new_write_source (uint32_t n=0); - int use_new_fade_source (uint32_t n=0) { return 0; } // FIXME? int find_and_use_playlist (const string&); void allocate_temporary_buffers (); - int create_input_port () { return 0; } // FIXME? - int connect_input_port () { return 0; } // FIXME? - int seek_unlocked (jack_nframes_t which_sample) { return 0; } // FIXME? - - int ports_created () { return 0; } // FIXME? - //bool realtime_set_speed (double, bool global_change); void non_realtime_set_speed (); diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index ca760a5ad5..add253982f 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -110,16 +110,15 @@ class Playlist : public Stateful, public StateManager { int set_state (const XMLNode&); XMLNode& get_template (); - sigc::signal RegionAdded; - sigc::signal RegionRemoved; - + sigc::signal RegionAdded; + sigc::signal RegionRemoved; sigc::signal InUse; - sigc::signal Modified; - sigc::signal NameChanged; - sigc::signal LengthChanged; - sigc::signal LayeringChanged; - sigc::signal GoingAway; - sigc::signal StatePushed; + sigc::signal Modified; + sigc::signal NameChanged; + sigc::signal LengthChanged; + sigc::signal LayeringChanged; + sigc::signal GoingAway; + sigc::signal StatePushed; static sigc::signal PlaylistCreated; diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index 68ac55df67..a138f66042 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -145,6 +145,8 @@ class Region : public Stateful, public StateManager bool overlap_equivalent (const Region&) const; bool region_list_equivalent (const Region&) const; virtual bool source_equivalent (const Region&) const = 0; + + virtual bool speed_mismatch (float) const = 0; /*virtual jack_nframes_t read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, char * workbuf, jack_nframes_t position, jack_nframes_t cnt, diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 7bd24b96cc..dd8ec4806a 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -938,7 +938,7 @@ class Session : public sigc::trackable, public Stateful /* buffers for gain and pan */ gain_t* gain_automation_buffer () const { return _gain_automation_buffer; } - pan_t** pan_automation_buffer() const { return _pan_automation_buffer; } + pan_t** pan_automation_buffer () const { return _pan_automation_buffer; } /* buffers for conversion */ enum RunContext { diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index a3345cf15a..5f6ce05016 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2003 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,8 +14,6 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - $Id: diskstream.cc 567 2006-06-07 14:54:12Z trutkin $ */ #include @@ -23,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -57,10 +56,14 @@ using namespace PBD; sigc::signal*> AudioDiskstream::DeleteSources; +size_t AudioDiskstream::_working_buffers_size = 0; +Sample* AudioDiskstream::_mixdown_buffer = 0; +gain_t* AudioDiskstream::_gain_buffer = 0; +char* AudioDiskstream::_conversion_buffer = 0; + AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream::Flag flag) : Diskstream(sess, name, flag) , deprecated_io_node(NULL) - , _playlist(NULL) { /* prevent any write sources from being created */ @@ -77,7 +80,6 @@ AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream: AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node) : Diskstream(sess, node) , deprecated_io_node(NULL) - , _playlist(NULL) { in_set_state = true; init (Recordable); @@ -178,25 +180,33 @@ AudioDiskstream::~AudioDiskstream () { Glib::Mutex::Lock lm (state_lock); - if (_playlist) - _playlist->unref (); - - for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { + for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) destroy_channel((*chan)); - } channels.clear(); } void -AudioDiskstream::handle_input_change (IOChange change, void *src) +AudioDiskstream::allocate_working_buffers() { - Glib::Mutex::Lock lm (state_lock); + assert(disk_io_frames() > 0); - if (!(input_change_pending & change)) { - input_change_pending = IOChange (input_change_pending|change); - _session.request_input_change_handling (); - } + _working_buffers_size = disk_io_frames(); + _mixdown_buffer = new Sample[_working_buffers_size]; + _gain_buffer = new gain_t[_working_buffers_size]; + _conversion_buffer = new char[_working_buffers_size * 4]; +} + +void +AudioDiskstream::free_working_buffers() +{ + delete _mixdown_buffer; + delete _gain_buffer; + delete _conversion_buffer; + _working_buffers_size = 0; + _mixdown_buffer = 0; + _gain_buffer = 0; + _conversion_buffer = 0; } void @@ -312,40 +322,7 @@ AudioDiskstream::use_playlist (Playlist* playlist) { assert(dynamic_cast(playlist)); - { - Glib::Mutex::Lock lm (state_lock); - - if (playlist == _playlist) { - return 0; - } - - plstate_connection.disconnect(); - plmod_connection.disconnect (); - plgone_connection.disconnect (); - - if (_playlist) { - _playlist->unref(); - } - - _playlist = dynamic_cast(playlist); - _playlist->ref(); - - if (!in_set_state && recordable()) { - reset_write_sources (false); - } - - plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &AudioDiskstream::playlist_changed)); - plmod_connection = _playlist->Modified.connect (mem_fun (*this, &AudioDiskstream::playlist_modified)); - plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &AudioDiskstream::playlist_deleted)); - } - - if (!overwrite_queued) { - _session.request_overwrite_buffer (this); - overwrite_queued = true; - } - - PlaylistChanged (); /* EMIT SIGNAL */ - _session.set_dirty (); + Diskstream::use_playlist(playlist); return 0; } @@ -377,6 +354,8 @@ AudioDiskstream::use_new_playlist () int AudioDiskstream::use_copy_playlist () { + assert(audio_playlist()); + if (destructive()) { return 0; } @@ -391,7 +370,7 @@ AudioDiskstream::use_copy_playlist () newname = Playlist::bump_name (_playlist->name(), _session); - if ((playlist = new AudioPlaylist (*_playlist, newname)) != 0) { + if ((playlist = new AudioPlaylist (*audio_playlist(), newname)) != 0) { playlist->set_orig_diskstream_id (id()); return use_playlist (playlist); } else { @@ -399,19 +378,6 @@ AudioDiskstream::use_copy_playlist () } } - -void -AudioDiskstream::playlist_deleted (Playlist* pl) -{ - /* this catches an ordering issue with session destruction. playlists - are destroyed before diskstreams. we have to invalidate any handles - we have to the playlist. - */ - - _playlist = 0; -} - - void AudioDiskstream::setup_destructive_playlist () { @@ -460,36 +426,6 @@ AudioDiskstream::use_destructive_playlist () /* the source list will never be reset for a destructive track */ } -void -AudioDiskstream::set_io (IO& io) -{ - _io = &io; - set_align_style_from_io (); -} - -void -AudioDiskstream::non_realtime_set_speed () -{ - if (_buffer_reallocation_required) - { - Glib::Mutex::Lock lm (state_lock); - allocate_temporary_buffers (); - - _buffer_reallocation_required = false; - } - - if (_seek_required) { - if (speed() != 1.0f || speed() != -1.0f) { - seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true); - } - else { - seek (_session.transport_frame(), true); - } - - _seek_required = false; - } -} - void AudioDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record) { @@ -1054,9 +990,9 @@ AudioDiskstream::seek (jack_nframes_t frame, bool complete_refill) file_frame = frame; if (complete_refill) { - while ((ret = non_realtime_do_refill ()) > 0); + while ((ret = do_refill_with_alloc ()) > 0) ; } else { - ret = non_realtime_do_refill (); + ret = do_refill_with_alloc (); } return ret; @@ -1148,7 +1084,7 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, this_read = min(cnt,this_read); - if (_playlist->read (buf+offset, mixdown_buffer, gain_buffer, workbuf, start, this_read, channel) != this_read) { + if (audio_playlist()->read (buf+offset, mixdown_buffer, gain_buffer, workbuf, start, this_read, channel) != this_read) { error << string_compose(_("AudioDiskstream %1: cannot read %2 from playlist at frame %3"), _id, this_read, start) << endmsg; return -1; @@ -1182,14 +1118,27 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, } int -AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * workbuf) +AudioDiskstream::do_refill_with_alloc() +{ + Sample* mix_buf = new Sample[disk_io_chunk_frames]; + float* gain_buf = new float[disk_io_chunk_frames]; + char* work_buf = new char[disk_io_chunk_frames * 4]; + + int ret = _do_refill(mix_buf, gain_buf, work_buf); + + delete [] mix_buf; + delete [] gain_buf; + delete [] work_buf; + + return ret; +} + +int +AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char * workbuf) { int32_t ret = 0; jack_nframes_t to_read; RingBufferNPT::rw_vector vector; - bool free_mixdown; - bool free_gain; - bool free_workbuf; bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f; jack_nframes_t total_space; jack_nframes_t zero_fill; @@ -1197,6 +1146,10 @@ AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * w ChannelList::iterator i; jack_nframes_t ts; + assert(mixdown_buffer); + assert(gain_buffer); + assert(workbuf); + channels.front().playback_buf->get_write_vector (&vector); if ((total_space = vector.len[0] + vector.len[1]) == 0) { @@ -1303,33 +1256,6 @@ AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * w zero_fill = 0; } } - - /* Please note: the code to allocate buffers isn't run - during normal butler thread operation. Its there - for other times when we need to call do_refill() - from somewhere other than the butler thread. - */ - - if (mixdown_buffer == 0) { - mixdown_buffer = new Sample[disk_io_chunk_frames]; - free_mixdown = true; - } else { - free_mixdown = false; - } - - if (gain_buffer == 0) { - gain_buffer = new float[disk_io_chunk_frames]; - free_gain = true; - } else { - free_gain = false; - } - - if (workbuf == 0) { - workbuf = new char[disk_io_chunk_frames * 4]; - free_workbuf = true; - } else { - free_workbuf = false; - } jack_nframes_t file_frame_tmp = 0; @@ -1398,22 +1324,15 @@ AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * w file_frame = file_frame_tmp; out: - if (free_mixdown) { - delete [] mixdown_buffer; - } - if (free_gain) { - delete [] gain_buffer; - } - if (free_workbuf) { - delete [] workbuf; - } return ret; } int -AudioDiskstream::do_flush (char * workbuf, bool force_flush) +AudioDiskstream::do_flush (Session::RunContext context, bool force_flush) { + char* workbuf = _session.conversion_buffer(context); + uint32_t to_write; int32_t ret = 0; RingBufferNPT::rw_vector vector; @@ -1570,7 +1489,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca */ while (more_work && !err) { - switch (do_flush ( _session.conversion_buffer(Session::TransportContext), true)) { + switch (do_flush (Session::TransportContext, true)) { case 0: more_work = false; break; diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index 4e2bec9850..9fc2ded0ce 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2003 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -55,7 +55,7 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -jack_nframes_t Diskstream::disk_io_chunk_frames; +jack_nframes_t Diskstream::disk_io_chunk_frames = 0; sigc::signal Diskstream::DiskstreamCreated; //sigc::signal*> Diskstream::DeleteSources; @@ -65,13 +65,14 @@ sigc::signal Diskstream::DiskUnderrun; Diskstream::Diskstream (Session &sess, const string &name, Flag flag) : _name (name) , _session (sess) + , _playlist(NULL) { init (flag); } Diskstream::Diskstream (Session& sess, const XMLNode& node) : _session (sess) - + , _playlist(NULL) { init (Recordable); } @@ -113,37 +114,28 @@ Diskstream::init (Flag f) _read_data_count = 0; _write_data_count = 0; - /* there are no channels at this point, so these - two calls just get speed_buffer_size and wrap_buffer - size setup without duplicating their code. - */ - - //set_block_size (_session.get_block_size()); - //allocate_temporary_buffers (); - pending_overwrite = false; overwrite_frame = 0; overwrite_queued = false; input_change_pending = NoChange; - //add_channel (); - _n_channels = 0;//1; + _n_channels = 0; } Diskstream::~Diskstream () { - // Taken by child.. assure lock? + // Taken by derived class destrctors.. assure lock? //Glib::Mutex::Lock lm (state_lock); - //if (_playlist) { - // _playlist->unref (); - //} + if (_playlist) + _playlist->unref (); +} - //for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) { - // destroy_channel((*chan)); - //} - - //channels.clear(); +void +Diskstream::set_io (IO& io) +{ + _io = &io; + set_align_style_from_io (); } void @@ -157,6 +149,29 @@ Diskstream::handle_input_change (IOChange change, void *src) } } +void +Diskstream::non_realtime_set_speed () +{ + if (_buffer_reallocation_required) + { + Glib::Mutex::Lock lm (state_lock); + allocate_temporary_buffers (); + + _buffer_reallocation_required = false; + } + + if (_seek_required) { + if (speed() != 1.0f || speed() != -1.0f) { + seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true); + } + else { + seek (_session.transport_frame(), true); + } + + _seek_required = false; + } +} + bool Diskstream::realtime_set_speed (double sp, bool global) { @@ -223,7 +238,6 @@ Diskstream::set_align_style (AlignStyle a) return; } - if (a != _alignment_style) { _alignment_style = a; AlignmentStyleChanged (); @@ -287,6 +301,47 @@ Diskstream::set_speed (double sp) playlist_modified(); } +int +Diskstream::use_playlist (Playlist* playlist) +{ + { + Glib::Mutex::Lock lm (state_lock); + + if (playlist == _playlist) { + return 0; + } + + plstate_connection.disconnect(); + plmod_connection.disconnect (); + plgone_connection.disconnect (); + + if (_playlist) { + _playlist->unref(); + } + + _playlist = playlist; + _playlist->ref(); + + if (!in_set_state && recordable()) { + reset_write_sources (false); + } + + plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &Diskstream::playlist_changed)); + plmod_connection = _playlist->Modified.connect (mem_fun (*this, &Diskstream::playlist_modified)); + plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &Diskstream::playlist_deleted)); + } + + if (!overwrite_queued) { + _session.request_overwrite_buffer (this); + overwrite_queued = true; + } + + PlaylistChanged (); /* EMIT SIGNAL */ + _session.set_dirty (); + + return 0; +} + void Diskstream::playlist_changed (Change ignored) { @@ -302,6 +357,17 @@ Diskstream::playlist_modified () } } +void +Diskstream::playlist_deleted (Playlist* pl) +{ + /* this catches an ordering issue with session destruction. playlists + are destroyed before diskstreams. we have to invalidate any handles + we have to the playlist. + */ + + _playlist = 0; +} + int Diskstream::set_name (string str, void *src) { diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index a5853136ea..4602fc8f67 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -388,7 +388,7 @@ MidiDiskstream::read (RawMidi* buf, RawMidi* mixdown_buffer, char * workbuf, jac { return 0; } - +/* int MidiDiskstream::do_refill (RawMidi* mixdown_buffer, float* gain_buffer, char * workbuf) { @@ -400,7 +400,7 @@ MidiDiskstream::do_flush (char * workbuf, bool force_flush) { return 0; } - +*/ void MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture) { diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index fec674b671..011d1d6237 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -403,6 +403,8 @@ Session::~Session () for (map::iterator i = _conversion_buffers.begin(); i != _conversion_buffers.end(); ++i) { delete [] (i->second); } + + AudioDiskstream::free_working_buffers(); #undef TRACK_DESTRUCTION #ifdef TRACK_DESTRUCTION @@ -2105,7 +2107,7 @@ void Session::add_diskstream (Diskstream* dstream) { /* need to do this in case we're rolling at the time, to prevent false underruns */ - dstream->non_realtime_do_refill(); + dstream->do_refill_with_alloc(); { Glib::RWLock::WriterLock lm (diskstream_lock); diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc index f0a2af0a83..6509a783bb 100644 --- a/libs/ardour/session_butler.cc +++ b/libs/ardour/session_butler.cc @@ -170,11 +170,6 @@ Session::butler_thread_work () bool disk_work_outstanding = false; DiskstreamList::iterator i; - butler_mixdown_buffer = new Sample[AudioDiskstream::disk_io_frames()]; - butler_gain_buffer = new gain_t[AudioDiskstream::disk_io_frames()]; - // this buffer is used for temp conversion purposes in filesources - char * conv_buffer = conversion_buffer(ButlerContext); - while (true) { pfd[0].fd = butler_request_pipe[0]; pfd[0].events = POLLIN|POLLERR|POLLHUP; @@ -256,16 +251,15 @@ Session::butler_thread_work () Glib::RWLock::ReaderLock dsm (diskstream_lock); for (i = diskstreams.begin(); !transport_work_requested() && butler_should_run && i != diskstreams.end(); ++i) { - // cerr << "rah fondr " << (*i)->io()->name () << endl; - AudioDiskstream* ads = dynamic_cast(*i); - if (!ads) continue; // FIXME - switch (ads->do_refill (butler_mixdown_buffer, butler_gain_buffer, conv_buffer)) { + Diskstream* const ds = *i; + + switch (ds->do_refill ()) { case 0: - bytes += ads->read_data_count(); + bytes += ds->read_data_count(); break; case 1: - bytes += ads->read_data_count(); + bytes += ds->read_data_count(); disk_work_outstanding = true; break; @@ -302,7 +296,7 @@ Session::butler_thread_work () for (i = diskstreams.begin(); !transport_work_requested() && butler_should_run && i != diskstreams.end(); ++i) { // cerr << "write behind for " << (*i)->name () << endl; - switch ((*i)->do_flush (conv_buffer)) { + switch ((*i)->do_flush (Session::ButlerContext)) { case 0: bytes += (*i)->write_data_count(); break; diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 73ba391873..0809aae6eb 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -196,7 +196,8 @@ Session::first_stage_init (string fullpath, string snapshot_name) /* allocate conversion buffers */ _conversion_buffers[ButlerContext] = new char[AudioDiskstream::disk_io_frames() * 4]; _conversion_buffers[TransportContext] = new char[AudioDiskstream::disk_io_frames() * 4]; - + AudioDiskstream::allocate_working_buffers(); + /* default short fade = 15ms */ Crossfade::set_short_xfade_length ((jack_nframes_t) floor ((15.0 * frame_rate()) / 1000.0)); -- cgit v1.2.3