From: David Robillard Date: Tue, 1 Aug 2006 03:23:35 +0000 (+0000) Subject: Heavy-duty abstraction work to split type-specific classes into X-Git-Tag: 2.0beta4~108 X-Git-Url: https://main.carlh.net/gitweb/?p=ardour.git;a=commitdiff_plain;h=6f4a92f740b2fd75794489ce58f9348f8adf6bf4 Heavy-duty abstraction work to split type-specific classes into specializations of (new, for the most part) generic bases. (eg. most everything from the MIDI branch except for actual MIDI things, so merges have a chance of succeeding). Also the new edit toolbar, and various other cleanup things I did along the way. Should be functionally equivalent (except the toolbar), this is just design work. She's a big'un.... git-svn-id: svn://localhost/ardour2/trunk@727 d708f5d6-7413-0410-9779-e7cbd77b26cf --- diff --git a/SConstruct b/SConstruct index 7c441a8d87..90c426300d 100644 --- a/SConstruct +++ b/SConstruct @@ -539,7 +539,7 @@ if env['SYSLIBS']: # libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas') libraries['soundtouch'] = LibraryInfo() - libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs soundtouch-1.0') + libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs libSoundTouch') coredirs = [ 'templates' diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript index c5409d7f8b..43dd09cfb4 100644 --- a/gtk2_ardour/SConscript +++ b/gtk2_ardour/SConscript @@ -75,6 +75,7 @@ ardour_ui_ed.cc ardour_ui_mixer.cc ardour_ui_options.cc audio_clock.cc +route_time_axis.cc audio_time_axis.cc automation_gain_line.cc automation_line.cc @@ -157,10 +158,11 @@ public_editor.cc redirect_automation_line.cc redirect_automation_time_axis.cc redirect_box.cc -region_editor.cc +audio_region_editor.cc region_gain_line.cc region_selection.cc -regionview.cc +region_view.cc +audio_region_view.cc route_params_ui.cc route_redirect_selection.cc route_ui.cc @@ -168,7 +170,8 @@ selection.cc sfdb_ui.cc send_ui.cc streamview.cc -taperegionview.cc +audio_streamview.cc +tape_region_view.cc tempo_dialog.cc time_axis_view.cc time_axis_view_item.cc diff --git a/gtk2_ardour/analysis_window.cc b/gtk2_ardour/analysis_window.cc index 8809c84e7a..f742afd727 100644 --- a/gtk2_ardour/analysis_window.cc +++ b/gtk2_ardour/analysis_window.cc @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include "analysis_window.h" @@ -35,7 +35,7 @@ #include "time_axis_view.h" #include "public_editor.h" #include "selection.h" -#include "regionview.h" +#include "audio_region_view.h" #include "i18n.h" @@ -225,11 +225,16 @@ AnalysisWindow::analyze_data (Gtk::Button *button) Selection s = PublicEditor::instance().get_selection(); TimeSelection ts = s.time; - AudioRegionSelection ars = s.audio_regions; + RegionSelection ars = s.regions; for (TrackSelection::iterator i = s.tracks.begin(); i != s.tracks.end(); ++i) { - ARDOUR::Playlist *pl = (*i)->playlist(); + ARDOUR::AudioPlaylist *pl + = dynamic_cast((*i)->playlist()); + + if (!pl) + continue; + RouteUI *rui = dynamic_cast(*i); // Busses don't have playlists, so we need to check that we actually are working with a playlist @@ -274,24 +279,29 @@ AnalysisWindow::analyze_data (Gtk::Button *button) TimeAxisView *current_axis = (*i); - for (std::set::iterator j = ars.begin(); j != ars.end(); ++j) { + for (std::set::iterator j = ars.begin(); j != ars.end(); ++j) { + // Check that the region is actually audio (so we can analyze it) + AudioRegionView* arv = dynamic_cast(*j); + if (!arv) + continue; + // Check that the region really is selected on _this_ track/solo - if ( &(*j)->get_time_axis_view() != current_axis) + if ( &arv->get_time_axis_view() != current_axis) continue; -// cerr << " - " << (*j)->region.name() << ": " << (*j)->region.length() << " samples starting at " << (*j)->region.position() << endl; +// cerr << " - " << (*j)->region().name() << ": " << (*j)->region().length() << " samples starting at " << (*j)->region().position() << endl; jack_nframes_t i = 0; int n; - while ( i < (*j)->region.length() ) { + while ( i < arv->region().length() ) { // TODO: What about stereo+ channels? composite all to one, I guess n = fft_graph.windowSize(); - if (i + n >= (*j)->region.length() ) { - n = (*j)->region.length() - i; + if (i + n >= arv->region().length() ) { + n = arv->region().length() - i; } - - n = (*j)->region.read_at(buf, mixbuf, gain, work, (*j)->region.position() + i, n); + + n = arv->audio_region().read_at(buf, mixbuf, gain, work, arv->region().position() + i, n); if ( n < fft_graph.windowSize()) { for (int j = n; j < fft_graph.windowSize(); j++) { diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index c9116ac4e9..201fc09880 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -53,7 +54,6 @@ #include #include #include -#include #include #include @@ -186,8 +186,8 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) gettimeofday (&last_shuttle_request, 0); ARDOUR::AudioDiskstream::DeleteSources.connect (mem_fun(*this, &ARDOUR_UI::delete_sources_in_the_right_thread)); - ARDOUR::AudioDiskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler)); - ARDOUR::AudioDiskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler)); + ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler)); + ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler)); /* handle pending state with a dialog */ @@ -543,9 +543,10 @@ ARDOUR_UI::update_buffer_load () } void -ARDOUR_UI::count_recenabled_diskstreams (AudioDiskstream& ds) +ARDOUR_UI::count_recenabled_diskstreams (Route& route) { - if (ds.record_enabled()) { + Track* track = dynamic_cast(&route); + if (track && track->diskstream().record_enabled()) { rec_enabled_diskstreams++; } } @@ -571,7 +572,7 @@ ARDOUR_UI::update_disk_space() if (session->actively_recording()){ rec_enabled_diskstreams = 0; - session->foreach_audio_diskstream (this, &ARDOUR_UI::count_recenabled_diskstreams); + session->foreach_route (this, &ARDOUR_UI::count_recenabled_diskstreams); if (rec_enabled_diskstreams) { frames /= rec_enabled_diskstreams; @@ -918,7 +919,7 @@ restart JACK with more ports.")); } void -ARDOUR_UI::diskstream_added (AudioDiskstream* ds) +ARDOUR_UI::diskstream_added (Diskstream* ds) { } @@ -1169,12 +1170,15 @@ ARDOUR_UI::toggle_record_enable (uint32_t dstream) if ((r = session->route_by_remote_id (dstream)) != 0) { - AudioTrack* at; + Track* t; - if ((at = dynamic_cast(r.get())) != 0) { - at->disk_stream().set_record_enabled (!at->disk_stream().record_enabled(), this); + if ((t = dynamic_cast(r.get())) != 0) { + t->diskstream().set_record_enabled (!t->diskstream().record_enabled()); } } + if (session == 0) { + return; + } } void @@ -2150,11 +2154,11 @@ ARDOUR_UI::halt_on_xrun_message () } void -ARDOUR_UI::delete_sources_in_the_right_thread (list* deletion_list) +ARDOUR_UI::delete_sources_in_the_right_thread (list* deletion_list) { ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::delete_sources_in_the_right_thread), deletion_list)); - for (list::iterator i = deletion_list->begin(); i != deletion_list->end(); ++i) { + for (list::iterator i = deletion_list->begin(); i != deletion_list->end(); ++i) { delete *i; } diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index 5fb9dd95e7..297c9c3c65 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -520,7 +520,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI sigc::connection point_one_second_connection; sigc::connection point_zero_one_second_connection; - void diskstream_added (ARDOUR::AudioDiskstream*); + void diskstream_added (ARDOUR::Diskstream*); gint session_menu (GdkEventButton *); @@ -621,7 +621,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI void toggle_record_enable (uint32_t); uint32_t rec_enabled_diskstreams; - void count_recenabled_diskstreams (ARDOUR::AudioDiskstream&); + void count_recenabled_diskstreams (ARDOUR::Route&); About* about; bool shown_flag; @@ -640,7 +640,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI struct timeval last_peak_grab; struct timeval last_shuttle_request; - void delete_sources_in_the_right_thread (list*); + void delete_sources_in_the_right_thread (list*); void editor_display_control_changed (Editing::DisplayControl c); diff --git a/gtk2_ardour/ardour_ui_dialogs.cc b/gtk2_ardour/ardour_ui_dialogs.cc index 202fa88b59..25f3068a81 100644 --- a/gtk2_ardour/ardour_ui_dialogs.cc +++ b/gtk2_ardour/ardour_ui_dialogs.cc @@ -76,8 +76,8 @@ ARDOUR_UI::connect_to_session (Session *s) rec_button.set_sensitive (true); shuttle_box.set_sensitive (true); - if (session->n_audio_diskstreams() == 0) { - session->AudioDiskstreamAdded.connect (mem_fun(*this, &ARDOUR_UI::diskstream_added)); + if (session->n_diskstreams() == 0) { + session->DiskstreamAdded.connect (mem_fun(*this, &ARDOUR_UI::diskstream_added)); } if (connection_editor) { diff --git a/gtk2_ardour/audio_region_editor.cc b/gtk2_ardour/audio_region_editor.cc new file mode 100644 index 0000000000..194f358b42 --- /dev/null +++ b/gtk2_ardour/audio_region_editor.cc @@ -0,0 +1,731 @@ +/* + Copyright (C) 2001 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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$ +*/ + +#include +#include +#include +#include +#include + +#include "audio_region_editor.h" +#include "audio_region_view.h" +#include "ardour_ui.h" +#include "utils.h" +#include "gui_thread.h" + +#include "i18n.h" + +using namespace ARDOUR; +using namespace PBD; +using namespace sigc; +using namespace std; + +AudioRegionEditor::AudioRegionEditor (Session& s, AudioRegion& r, AudioRegionView& rv) + : RegionEditor (s), + _region (r), + _region_view (rv), + name_label (_("NAME:")), + lock_button (_("lock")), + mute_button (_("mute")), + opaque_button (_("opaque")), + envelope_active_button(_("active")), + envelope_view_button(_("visible")), + raise_arrow (Gtk::ARROW_UP, Gtk::SHADOW_OUT), + lower_arrow (Gtk::ARROW_DOWN, Gtk::SHADOW_OUT), + layer_label (_("Layer")), + audition_button (_("play")), + time_table (3, 2), + start_clock ("AudioRegionEditorClock", true), + end_clock ("AudioRegionEditorClock", true), + length_clock ("AudioRegionEditorClock", true, true), + sync_offset_clock ("AudioRegionEditorClock", true, true), + envelope_loop_table (1, 3), + envelope_label (_("ENVELOPE")), + fade_in_table (4, 3), + fade_in_length_adjustment (5.0, 0.0, 10000, 0.05, 1), + fade_in_length_spinner (fade_in_length_adjustment, 10), + fade_out_table (4, 3), + fade_out_length_adjustment (5.0, 0.0, 10000, 0.05, 1), + fade_out_length_spinner (fade_out_length_adjustment, 10) + +{ + start_clock.set_session (&_session); + end_clock.set_session (&_session); + length_clock.set_session (&_session); + + name_entry.set_name ("AudioRegionEditorEntry"); + name_label.set_name ("AudioRegionEditorLabel"); + + name_hbox.set_spacing (5); + name_hbox.pack_start (name_label, false, false); + name_hbox.pack_start (name_entry, false, false); + + raise_button.add (raise_arrow); + lower_button.add (lower_arrow); + layer_frame.set_name ("BaseFrame"); + layer_frame.set_shadow_type (Gtk::SHADOW_IN); + layer_frame.add (layer_value_label); + layer_label.set_name ("AudioRegionEditorLabel"); + layer_value_label.set_name ("AudioRegionEditorLabel"); + Gtkmm2ext::set_size_request_to_display_given_text (layer_value_label, "99", 5, 2); + + layer_hbox.set_spacing (5); + layer_hbox.pack_start (layer_label, false, false); + layer_hbox.pack_start (layer_frame, false, false); +#if 0 + layer_hbox.pack_start (raise_button, false, false); + layer_hbox.pack_start (lower_button, false, false); +#endif + + mute_button.set_name ("AudioRegionEditorToggleButton"); + opaque_button.set_name ("AudioRegionEditorToggleButton"); + lock_button.set_name ("AudioRegionEditorToggleButton"); + envelope_active_button.set_name ("AudioRegionEditorToggleButton"); + envelope_view_button.set_name ("AudioRegionEditorToggleButton"); + fade_in_active_button.set_name ("AudioRegionEditorToggleButton"); + fade_out_active_button.set_name ("AudioRegionEditorToggleButton"); + audition_button.set_name ("AudioRegionEditorToggleButton"); + + ARDOUR_UI::instance()->tooltips().set_tip (mute_button, _("mute this region")); + ARDOUR_UI::instance()->tooltips().set_tip (opaque_button, _("regions underneath this one cannot be heard")); + ARDOUR_UI::instance()->tooltips().set_tip (lock_button, _("prevent any changes to this region")); + ARDOUR_UI::instance()->tooltips().set_tip (envelope_active_button, _("use the gain envelope during playback")); + ARDOUR_UI::instance()->tooltips().set_tip (envelope_view_button, _("show the gain envelope")); + ARDOUR_UI::instance()->tooltips().set_tip (fade_in_active_button, _("use fade in curve during playback")); + ARDOUR_UI::instance()->tooltips().set_tip (fade_out_active_button, _("use fade out curve during playback")); + ARDOUR_UI::instance()->tooltips().set_tip (audition_button, _("audition this region")); + + mute_button.unset_flags (Gtk::CAN_FOCUS); + opaque_button.unset_flags (Gtk::CAN_FOCUS); + lock_button.unset_flags (Gtk::CAN_FOCUS); + envelope_active_button.unset_flags (Gtk::CAN_FOCUS); + envelope_view_button.unset_flags (Gtk::CAN_FOCUS); + fade_in_active_button.unset_flags (Gtk::CAN_FOCUS); + fade_out_active_button.unset_flags (Gtk::CAN_FOCUS); + audition_button.unset_flags (Gtk::CAN_FOCUS); + + mute_button.set_events (mute_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); + opaque_button.set_events (opaque_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); + lock_button.set_events (lock_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); + envelope_active_button.set_events (envelope_active_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); + envelope_view_button.set_events (envelope_view_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); + fade_in_active_button.set_events (fade_in_active_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); + fade_out_active_button.set_events (fade_out_active_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); + audition_button.set_events (audition_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); + + top_row_button_hbox.set_border_width (5); + top_row_button_hbox.set_spacing (5); + top_row_button_hbox.set_homogeneous (false); + top_row_button_hbox.pack_start (mute_button, false, false); + top_row_button_hbox.pack_start (opaque_button, false, false); + top_row_button_hbox.pack_start (lock_button, false, false); + top_row_button_hbox.pack_start (layer_hbox, false, false, 5); + top_row_button_hbox.pack_end (audition_button, false, false); + + top_row_hbox.pack_start (name_hbox, true, true); + top_row_hbox.pack_end (top_row_button_hbox, true, true); + + start_label.set_name ("AudioRegionEditorLabel"); + start_label.set_text (_("START:")); + end_label.set_name ("AudioRegionEditorLabel"); + end_label.set_text (_("END:")); + length_label.set_name ("AudioRegionEditorLabel"); + length_label.set_text (_("LENGTH:")); + + time_table.set_col_spacings (2); + time_table.set_row_spacings (5); + time_table.set_border_width (5); + + start_alignment.set (1.0, 0.5); + end_alignment.set (1.0, 0.5); + length_alignment.set (1.0, 0.5); + + start_alignment.add (start_label); + end_alignment.add (end_label); + length_alignment.add (length_label); + + time_table.attach (start_alignment, 0, 1, 0, 1, Gtk::FILL, Gtk::FILL); + time_table.attach (start_clock, 1, 2, 0, 1, Gtk::FILL, Gtk::FILL); + + time_table.attach (end_alignment, 0, 1, 1, 2, Gtk::FILL, Gtk::FILL); + time_table.attach (end_clock, 1, 2, 1, 2, Gtk::FILL, Gtk::FILL); + + time_table.attach (length_alignment, 0, 1, 2, 3, Gtk::FILL, Gtk::FILL); + time_table.attach (length_clock, 1, 2, 2, 3, Gtk::FILL, Gtk::FILL); + + envelope_label.set_name ("AudioRegionEditorLabel"); + + envelope_loop_table.set_border_width (5); + envelope_loop_table.set_row_spacings (2); + envelope_loop_table.attach (envelope_label, 0, 1, 0, 1, Gtk::FILL, Gtk::FILL); + envelope_loop_table.attach (envelope_active_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); + envelope_loop_table.attach (envelope_view_button, 0, 1, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); + + /* fade in */ + + fade_in_table.set_border_width (5); + fade_in_table.set_homogeneous (false); + + fade_in_label.set_name ("AudioRegionEditorLabel"); + fade_in_active_button_label.set_name ("AudioRegionEditorSmallLabel"); + fade_in_length_label.set_name ("AudioRegionEditorSmallLabel"); + + fade_in_label.set_text (_("FADE IN")); + fade_in_active_button_label.set_text (_("active")); + fade_in_length_label.set_text (_("msecs")); + + fade_in_active_button.add (fade_in_active_button_label); + + fade_in_length_spinner.set_name("GenericSpinner"); + + fade_in_length_spinner.set_digits (3); + + // fade_in_length_spinner.signal_activate().connect (mem_fun(*this, &AudioRegionEditor::activation)); + + Gtkmm2ext::set_size_request_to_display_given_text (fade_in_length_spinner, "500g", 20, -1); + + fade_in_label_align.add (fade_in_label); + fade_in_label_align.set (0.5); + + + fade_in_table.attach (fade_in_label_align, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); + + fade_in_table.attach (fade_in_length_label, 0, 1, 1, 2, Gtk::EXPAND, Gtk::FILL); + fade_in_table.attach (fade_in_length_spinner, 0, 1, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); + + fade_in_table.attach (fade_in_active_button, 0, 2, 3, 5, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); + + /* fade out */ + + fade_out_table.set_border_width (5); + fade_out_table.set_homogeneous (false); + + fade_out_label.set_name ("AudioRegionEditorLabel"); + fade_out_active_button_label.set_name ("AudioRegionEditorSmallLabel"); + fade_out_length_label.set_name ("AudioRegionEditorSmallLabel"); + + fade_out_label.set_text (_("FADE OUT")); + fade_out_active_button_label.set_text (_("active")); + fade_out_length_label.set_text (_("msecs")); + + fade_out_active_button.add (fade_out_active_button_label); + + fade_out_length_spinner.set_name("GenericSpinner"); + + fade_out_length_spinner.set_digits (3); + + fade_out_length_spinner.signal_activate().connect (mem_fun(*this, &AudioRegionEditor::activation)); + + Gtkmm2ext::set_size_request_to_display_given_text (fade_out_length_spinner, "500g", 20, -1); + + fade_out_label_align.add (fade_out_label); + fade_out_label_align.set (0.5); + + fade_out_table.attach (fade_out_label_align, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); + + fade_out_table.attach (fade_out_length_label, 0, 1, 1, 2, Gtk::EXPAND, Gtk::FILL); + fade_out_table.attach (fade_out_length_spinner, 0, 1, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); + + fade_out_table.attach (fade_out_active_button, 0, 2, 3, 5, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); + + lower_hbox.pack_start (time_table, true, true); + lower_hbox.pack_start (sep1, false, false); + lower_hbox.pack_start (envelope_loop_table, true, true); + lower_hbox.pack_start (sep2, false, false); + lower_hbox.pack_start (fade_in_table, true, true); + lower_hbox.pack_start (fade_out_table, true, true); + + get_vbox()->pack_start (top_row_hbox, true, true); + get_vbox()->pack_start (sep3, false, false); + get_vbox()->pack_start (lower_hbox, true, true); + + set_name ("AudioRegionEditorWindow"); + add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK); + + signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast (this))); + + string title = _("ardour: region "); + title += _region.name(); + set_title (title); + + show_all(); + + name_changed (); + bounds_changed (Change (StartChanged|LengthChanged|PositionChanged)); + envelope_active_changed (); + mute_changed (); + opacity_changed (); + lock_changed (); + layer_changed (); + fade_in_changed (); + fade_out_changed (); + + XMLNode *node = _region.extra_xml ("GUI"); + XMLProperty *prop = 0; + bool showing_envelope = false; + + if (node && (prop = node->property ("envelope-visible")) != 0) { + if (prop->value() == "yes") { + showing_envelope = true; + } + } + + if (showing_envelope) { + envelope_view_button.set_active (true); + } else { + envelope_view_button.set_active (false); + } + + _region.StateChanged.connect (mem_fun(*this, &AudioRegionEditor::region_changed)); + + spin_arrow_grab = false; + + connect_editor_events (); +} + +AudioRegionEditor::~AudioRegionEditor () +{ +} + +void +AudioRegionEditor::region_changed (Change what_changed) +{ + if (what_changed & NameChanged) { + name_changed (); + } + if (what_changed & BoundsChanged) { + bounds_changed (what_changed); + } + + if (what_changed & Region::OpacityChanged) { + opacity_changed (); + } + if (what_changed & Region::MuteChanged) { + mute_changed (); + } + if (what_changed & Region::LockChanged) { + lock_changed (); + } + if (what_changed & Region::LayerChanged) { + layer_changed (); + } + + if (what_changed & AudioRegion::EnvelopeActiveChanged) { + envelope_active_changed (); + } + if (what_changed & AudioRegion::FadeInChanged) { + fade_in_changed (); + } + if (what_changed & AudioRegion::FadeOutChanged) { + fade_out_changed (); + } + if (what_changed & AudioRegion::FadeInActiveChanged) { + fade_in_active_changed (); + } + if (what_changed & AudioRegion::FadeOutActiveChanged) { + fade_out_active_changed (); + } +} + +void +AudioRegionEditor::fade_in_realized () +{ + fade_in_changed (); +} + +void +AudioRegionEditor::fade_out_realized () +{ + fade_out_changed (); +} + +gint +AudioRegionEditor::bpressed (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()) +{ + switch (ev->button) { + case 1: + case 2: + case 3: + if (ev->type == GDK_BUTTON_PRESS) { /* no double clicks here */ + if (!spin_arrow_grab) { + // GTK2FIX probably nuke the region editor + // if ((ev->window == but->gobj()->panel)) { + // spin_arrow_grab = true; + // (this->*pmf)(); + // } + } + } + break; + default: + break; + } + return FALSE; +} + +gint +AudioRegionEditor::breleased (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()) +{ + if (spin_arrow_grab) { + (this->*pmf)(); + spin_arrow_grab = false; + } + return FALSE; +} + +void +AudioRegionEditor::start_editing_fade_in () +{ + _region.freeze (); +} + +void +AudioRegionEditor::stop_editing_fade_in () +{ + _region.thaw (_("fade in edit")); +} + +void +AudioRegionEditor::start_editing_fade_out () +{ + _region.freeze (); +} + +void +AudioRegionEditor::stop_editing_fade_out () +{ + _region.thaw (_("fade out edit")); +} + +void +AudioRegionEditor::connect_editor_events () +{ + name_entry.signal_changed().connect (mem_fun(*this, &AudioRegionEditor::name_entry_changed)); + + start_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::start_clock_changed)); + end_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::end_clock_changed)); + length_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::length_clock_changed)); + + fade_in_length_spinner.signal_button_press_event().connect (bind (mem_fun(*this, &AudioRegionEditor::bpressed), &fade_in_length_spinner, + &AudioRegionEditor::start_editing_fade_in)); + fade_in_length_spinner.signal_button_release_event().connect (bind (mem_fun (*this, &AudioRegionEditor::breleased), &fade_in_length_spinner, + &AudioRegionEditor::stop_editing_fade_in)); + + fade_out_length_spinner.signal_button_press_event().connect (bind (mem_fun(*this, &AudioRegionEditor::bpressed), &fade_out_length_spinner, + &AudioRegionEditor::start_editing_fade_out)); + fade_out_length_spinner.signal_button_release_event().connect (bind (mem_fun (*this, &AudioRegionEditor::breleased), &fade_out_length_spinner, + &AudioRegionEditor::stop_editing_fade_out)); + + fade_in_length_adjustment.signal_value_changed().connect (mem_fun(*this, &AudioRegionEditor::fade_in_length_adjustment_changed)); + fade_out_length_adjustment.signal_value_changed().connect (mem_fun(*this, &AudioRegionEditor::fade_out_length_adjustment_changed)); + + fade_in_active_button.signal_toggled().connect (mem_fun(*this, &AudioRegionEditor::fade_in_active_toggled)); + fade_out_active_button.signal_toggled().connect (mem_fun(*this, &AudioRegionEditor::fade_out_active_toggled)); + + envelope_active_button.signal_button_press_event().connect (mem_fun(*this, &AudioRegionEditor::envelope_active_button_press)); + envelope_active_button.signal_button_release_event().connect (mem_fun(*this, &AudioRegionEditor::envelope_active_button_release)); + audition_button.signal_toggled().connect (mem_fun(*this, &AudioRegionEditor::audition_button_toggled)); + envelope_view_button.signal_toggled().connect (mem_fun(*this, &AudioRegionEditor::envelope_view_button_toggled)); + lock_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::lock_button_clicked)); + mute_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::mute_button_clicked)); + opaque_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::opaque_button_clicked)); + raise_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::raise_button_clicked)); + lower_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::lower_button_clicked)); + _session.AuditionActive.connect (mem_fun(*this, &AudioRegionEditor::audition_state_changed)); +} + +void +AudioRegionEditor::start_clock_changed () +{ + _region.set_position (start_clock.current_time(), this); +} + +void +AudioRegionEditor::end_clock_changed () +{ + _region.trim_end (end_clock.current_time(), this); + + end_clock.set (_region.position() + _region.length(), true); +} + +void +AudioRegionEditor::length_clock_changed () +{ + jack_nframes_t frames = length_clock.current_time(); + _region.trim_end (_region.position() + frames, this); + + length_clock.set (_region.length()); +} + +gint +AudioRegionEditor::envelope_active_button_press(GdkEventButton *ev) +{ + return stop_signal (envelope_active_button, "button_press_event"); +} + +gint +AudioRegionEditor::envelope_active_button_release (GdkEventButton *ev) +{ + _region.set_envelope_active (!_region.envelope_active()); + return stop_signal (envelope_active_button, "button_release_event"); +} + +void +AudioRegionEditor::envelope_view_button_toggled () +{ + bool visible = envelope_view_button.get_active (); + + _region_view.set_envelope_visible (visible); +} + +void +AudioRegionEditor::audition_button_toggled () +{ + if (audition_button.get_active()) { + _session.audition_region (_region); + } else { + _session.cancel_audition (); + } +} + +void +AudioRegionEditor::raise_button_clicked () +{ + _region.raise (); +} + +void +AudioRegionEditor::lower_button_clicked () +{ + _region.lower (); +} + +void +AudioRegionEditor::opaque_button_clicked () +{ + bool ractive = _region.opaque(); + + if (opaque_button.get_active() != ractive) { + _region.set_opaque (!ractive); + } +} + +void +AudioRegionEditor::mute_button_clicked () +{ + bool ractive = _region.muted(); + + if (mute_button.get_active() != ractive) { + _region.set_muted (!ractive); + } +} + +void +AudioRegionEditor::lock_button_clicked () +{ + bool ractive = _region.locked(); + + if (lock_button.get_active() != ractive) { + _region.set_locked (!ractive); + } +} + +void +AudioRegionEditor::layer_changed () +{ + char buf[8]; + snprintf (buf, sizeof(buf), "%d", (int) _region.layer() + 1); + layer_value_label.set_text (buf); +} + +void +AudioRegionEditor::name_changed () +{ + if (name_entry.get_text() != _region.name()) { + name_entry.set_text (_region.name()); + } +} + +void +AudioRegionEditor::lock_changed () +{ + bool yn; + + if ((yn = _region.locked()) != lock_button.get_active()) { + lock_button.set_active (yn); + } + + start_clock.set_sensitive (!yn); + end_clock.set_sensitive (!yn); + length_clock.set_sensitive (!yn); +} + +void +AudioRegionEditor::envelope_active_changed () +{ + bool yn; + + if ((yn = _region.envelope_active()) != envelope_active_button.get_active()) { + envelope_active_button.set_active (yn); + } +} + +void +AudioRegionEditor::opacity_changed () +{ + bool yn; + if ((yn = _region.opaque()) != opaque_button.get_active()) { + opaque_button.set_active (yn); + } +} + +void +AudioRegionEditor::mute_changed () +{ + bool yn; + if ((yn = _region.muted()) != mute_button.get_active()) { + mute_button.set_active (yn); + } +} + +void +AudioRegionEditor::bounds_changed (Change what_changed) +{ + if (what_changed & Change ((PositionChanged|LengthChanged))) { + start_clock.set (_region.position(), true); + end_clock.set (_region.position() + _region.length(), true); + length_clock.set (_region.length(), true); + } +} + +void +AudioRegionEditor::activation () +{ + +} + +void +AudioRegionEditor::name_entry_changed () +{ + if (name_entry.get_text() != _region.name()) { + _region.set_name (name_entry.get_text()); + } +} + +void +AudioRegionEditor::fade_in_changed () +{ + float msecs = fade_in_length_adjustment.get_value(); + jack_nframes_t sr = _session.frame_rate(); + jack_nframes_t adj_frames = (jack_nframes_t) floor (msecs * (sr/1000.0f)); + jack_nframes_t frames; + bool x; + + if (adj_frames != (frames = (jack_nframes_t) _region.fade_in().back()->when)) { + fade_in_length_adjustment.set_value ((frames * 1000.0f) / sr); + } + + if ((x = _region.fade_in_active()) != fade_in_active_button.get_active()) { + fade_in_active_button.set_active (x); + } +} + +void +AudioRegionEditor::fade_out_changed () +{ + float msecs = fade_out_length_adjustment.get_value(); + jack_nframes_t sr = _session.frame_rate(); + jack_nframes_t adj_frames = (jack_nframes_t) floor (msecs * (sr/1000.0f)); + jack_nframes_t frames; + bool x; + if (adj_frames != (frames = (jack_nframes_t) _region.fade_out().back()->when)) { + fade_out_length_adjustment.set_value ((frames * 1000.0f) / sr); + } + + if ((x = _region.fade_out_active()) != fade_out_active_button.get_active()) { + fade_out_active_button.set_active (x); + } +} + +void +AudioRegionEditor::fade_in_length_adjustment_changed () +{ + jack_nframes_t fade_length = (jack_nframes_t) floor (fade_in_length_adjustment.get_value() * _session.frame_rate() * 0.001); + fade_length = max (fade_length, (jack_nframes_t) 64); + fade_length = min (fade_length, _region.length()); + + _region.set_fade_in_length (fade_length); + /* region is frozen, no worries */ + fade_in_changed(); +} + +void +AudioRegionEditor::fade_out_length_adjustment_changed () +{ + jack_nframes_t fade_length = (jack_nframes_t) floor (fade_out_length_adjustment.get_value() * _session.frame_rate() * 0.001); + fade_length = max (fade_length, (jack_nframes_t) 64); + fade_length = min (fade_length, _region.length()); + + _region.set_fade_out_length (fade_length); + /* region is frozen, no worries */ + fade_out_changed(); +} + +void +AudioRegionEditor::fade_in_active_toggled () +{ + _region.set_fade_in_active (fade_in_active_button.get_active()); +} + +void +AudioRegionEditor::fade_out_active_toggled () +{ + _region.set_fade_out_active (fade_out_active_button.get_active()); +} + +void +AudioRegionEditor::fade_out_active_changed () +{ + bool x; + + if ((x = _region.fade_out_active()) != fade_out_active_button.get_active()) { + fade_out_active_button.set_active (x); + } +} + +void +AudioRegionEditor::fade_in_active_changed () +{ + bool x; + + if ((x = _region.fade_in_active()) != fade_in_active_button.get_active()) { + fade_in_active_button.set_active (x); + } +} + +void +AudioRegionEditor::audition_state_changed (bool yn) +{ + ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioRegionEditor::audition_state_changed), yn)); + + if (!yn) { + audition_button.set_active (false); + } +} + diff --git a/gtk2_ardour/audio_region_editor.h b/gtk2_ardour/audio_region_editor.h new file mode 100644 index 0000000000..38cd920e5e --- /dev/null +++ b/gtk2_ardour/audio_region_editor.h @@ -0,0 +1,186 @@ +/* + Copyright (C) 2001 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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$ +*/ + +#ifndef __gtk_ardour_audio_region_edit_h__ +#define __gtk_ardour_audio_region_edit_h__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "audio_clock.h" +#include "ardour_dialog.h" +#include "region_editor.h" + +namespace ARDOUR { + class AudioRegion; + class Session; +} + +class AudioRegionView; + +class AudioRegionEditor : public RegionEditor +{ + public: + AudioRegionEditor (ARDOUR::Session&, ARDOUR::AudioRegion&, AudioRegionView& rv); + ~AudioRegionEditor (); + + private: + ARDOUR::AudioRegion& _region; + AudioRegionView& _region_view; + + void connect_editor_events (); + + Gtk::Label name_label; + Gtk::Entry name_entry; + Gtk::HBox name_hbox; + + Gtk::HBox top_row_hbox; + Gtk::HBox top_row_button_hbox; + + Gtk::ToggleButton lock_button; + Gtk::ToggleButton mute_button; + Gtk::ToggleButton opaque_button; + Gtk::ToggleButton envelope_active_button; + Gtk::ToggleButton envelope_view_button; + + Gtk::Button raise_button; + Gtk::Arrow raise_arrow; + Gtk::Button lower_button; + Gtk::Arrow lower_arrow; + Gtk::Frame layer_frame; + Gtk::Label layer_value_label; + Gtk::Label layer_label; + Gtk::HBox layer_hbox; + + Gtk::ToggleButton audition_button; + + Gtk::HBox lower_hbox; + + Gtk::Table time_table; + + Gtk::Label start_label; + Gtk::Label end_label; + Gtk::Label length_label; + Gtk::Alignment start_alignment; + Gtk::Alignment end_alignment; + Gtk::Alignment length_alignment; + + AudioClock start_clock; + AudioClock end_clock; + AudioClock length_clock; + AudioClock sync_offset_clock; + + Gtk::Table envelope_loop_table; + Gtk::Button loop_button; + Gtk::Label loop_label; + Gtk::Label envelope_label; + + Gtk::Table fade_in_table; + Gtk::Label fade_in_label; + Gtk::Alignment fade_in_label_align; + Gtk::Label fade_in_active_button_label; + Gtk::ToggleButton fade_in_active_button; + Gtk::Label fade_in_length_label; + + Gtk::Adjustment fade_in_length_adjustment; + Gtk::SpinButton fade_in_length_spinner; + + Gtk::Table fade_out_table; + Gtk::Label fade_out_label; + Gtk::Alignment fade_out_label_align; + Gtk::Label fade_out_active_button_label; + Gtk::ToggleButton fade_out_active_button; + Gtk::Label fade_out_length_label; + + Gtk::Adjustment fade_out_length_adjustment; + Gtk::SpinButton fade_out_length_spinner; + + Gtk::HSeparator sep3; + Gtk::VSeparator sep1; + Gtk::VSeparator sep2; + + void region_changed (ARDOUR::Change); + void bounds_changed (ARDOUR::Change); + void name_changed (); + void opacity_changed (); + void mute_changed (); + void envelope_active_changed (); + void lock_changed (); + void layer_changed (); + + void fade_in_length_adjustment_changed (); + void fade_out_length_adjustment_changed (); + void fade_in_changed (); + void fade_out_changed (); + void audition_state_changed (bool); + + void activation (); + + void name_entry_changed (); + void start_clock_changed (); + void end_clock_changed (); + void length_clock_changed (); + + gint envelope_active_button_press (GdkEventButton *); + gint envelope_active_button_release (GdkEventButton *); + + void audition_button_toggled (); + void envelope_view_button_toggled (); + void lock_button_clicked (); + void mute_button_clicked (); + void opaque_button_clicked (); + void raise_button_clicked (); + void lower_button_clicked (); + + void fade_in_active_toggled (); + void fade_out_active_toggled (); + void fade_in_active_changed (); + void fade_out_active_changed (); + + void fade_in_realized (); + void fade_out_realized (); + + void start_editing_fade_in (); + void start_editing_fade_out (); + void stop_editing_fade_in (); + void stop_editing_fade_out (); + + gint bpressed (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()); + gint breleased (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()); + + bool spin_arrow_grab; +}; + +#endif /* __gtk_ardour_audio_region_edit_h__ */ diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc new file mode 100644 index 0000000000..a9a758481f --- /dev/null +++ b/gtk2_ardour/audio_region_view.cc @@ -0,0 +1,1125 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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$ +*/ + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include "streamview.h" +#include "audio_region_view.h" +#include "audio_time_axis.h" +#include "simplerect.h" +#include "simpleline.h" +#include "waveview.h" +#include "public_editor.h" +#include "audio_region_editor.h" +#include "region_gain_line.h" +#include "ghostregion.h" +#include "audio_time_axis.h" +#include "utils.h" +#include "rgb_macros.h" +#include "gui_thread.h" + +#include "i18n.h" + +using namespace sigc; +using namespace ARDOUR; +using namespace PBD; +using namespace Editing; +using namespace ArdourCanvas; + +static const int32_t sync_mark_width = 9; + +AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, AudioRegion& r, double spu, + Gdk::Color& basic_color) + : RegionView (parent, tv, r, spu, basic_color) + , sync_mark(0) + , zero_line(0) + , fade_in_shape(0) + , fade_out_shape(0) + , fade_in_handle(0) + , fade_out_handle(0) + , gain_line(0) + , _amplitude_above_axis(1.0) + , _flags(0) + , fade_color(0) +{ +} + +AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, AudioRegion& r, double spu, + Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility) + : RegionView (parent, tv, r, spu, basic_color, visibility) + , sync_mark(0) + , zero_line(0) + , fade_in_shape(0) + , fade_out_shape(0) + , fade_in_handle(0) + , fade_out_handle(0) + , gain_line(0) + , _amplitude_above_axis(1.0) + , _flags(0) + , fade_color(0) +{ +} + +void +AudioRegionView::init (Gdk::Color& basic_color, bool wfd) +{ + // 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; + + _amplitude_above_axis = 1.0; + zero_line = 0; + _flags = 0; + + if ((node = _region.extra_xml ("GUI")) != 0) { + set_flags (node); + } else { + _flags = WaveformVisible; + store_flags (); + } + + if (trackview.editor.new_regionviews_display_gain()) { + _flags |= EnvelopeVisible; + } + + compute_colors (basic_color); + + create_waves (); + + fade_in_shape = new ArdourCanvas::Polygon (*group); + fade_in_shape->property_fill_color_rgba() = fade_color; + fade_in_shape->set_data ("regionview", this); + + fade_out_shape = new ArdourCanvas::Polygon (*group); + fade_out_shape->property_fill_color_rgba() = fade_color; + fade_out_shape->set_data ("regionview", this); + + + { + uint32_t r,g,b,a; + UINT_TO_RGBA(fill_color,&r,&g,&b,&a); + + + fade_in_handle = new ArdourCanvas::SimpleRect (*group); + fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0); + fade_in_handle->property_outline_pixels() = 0; + fade_in_handle->property_y1() = 2.0; + fade_in_handle->property_y2() = 7.0; + + fade_in_handle->set_data ("regionview", this); + + fade_out_handle = new ArdourCanvas::SimpleRect (*group); + fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0); + fade_out_handle->property_outline_pixels() = 0; + fade_out_handle->property_y1() = 2.0; + fade_out_handle->property_y2() = 7.0; + + fade_out_handle->set_data ("regionview", this); + } + + string foo = _region.name(); + foo += ':'; + foo += "gain"; + + gain_line = new AudioRegionGainLine (foo, trackview.session(), *this, *group, audio_region().envelope()); + + if (!(_flags & EnvelopeVisible)) { + gain_line->hide (); + } else { + gain_line->show (); + } + + reset_width_dependent_items ((double) _region.length() / samples_per_unit); + + gain_line->reset (); + + set_height (trackview.height); + + region_muted (); + region_sync_changed (); + region_resized (BoundsChanged); + set_waveview_data_src(); + region_locked (); + envelope_active_changed (); + fade_in_active_changed (); + fade_out_active_changed (); + + _region.StateChanged.connect (mem_fun(*this, &AudioRegionView::region_changed)); + + 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)); + fade_out_handle->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_handle_event), fade_out_handle, this)); + + set_colors (); + + /* XXX sync mark drag? */ +} + +AudioRegionView::~AudioRegionView () +{ + in_destructor = true; + + RegionViewGoingAway (this); /* EMIT_SIGNAL */ + + for (vector::iterator cache = wave_caches.begin(); cache != wave_caches.end() ; ++cache) { + gnome_canvas_waveview_cache_destroy (*cache); + } + + /* all waveviews etc will be destroyed when the group is destroyed */ + + if (gain_line) { + delete gain_line; + } +} + +ARDOUR::AudioRegion& +AudioRegionView::audio_region() const +{ + // "Guaranteed" to succeed... + return dynamic_cast(_region); +} + +void +AudioRegionView::region_changed (Change what_changed) +{ + ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioRegionView::region_changed), what_changed)); + + RegionView::region_changed(what_changed); + + if (what_changed & AudioRegion::ScaleAmplitudeChanged) { + region_scale_amplitude_changed (); + } + if (what_changed & AudioRegion::FadeInChanged) { + fade_in_changed (); + } + if (what_changed & AudioRegion::FadeOutChanged) { + fade_out_changed (); + } + if (what_changed & AudioRegion::FadeInActiveChanged) { + fade_in_active_changed (); + } + if (what_changed & AudioRegion::FadeOutActiveChanged) { + fade_out_active_changed (); + } + if (what_changed & AudioRegion::EnvelopeActiveChanged) { + envelope_active_changed (); + } +} + +void +AudioRegionView::fade_in_changed () +{ + reset_fade_in_shape (); +} + +void +AudioRegionView::fade_out_changed () +{ + reset_fade_out_shape (); +} + +void +AudioRegionView::set_fade_in_active (bool yn) +{ + audio_region().set_fade_in_active (yn); +} + +void +AudioRegionView::set_fade_out_active (bool yn) +{ + audio_region().set_fade_out_active (yn); +} + +void +AudioRegionView::fade_in_active_changed () +{ + uint32_t r,g,b,a; + uint32_t col; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + + if (audio_region().fade_in_active()) { + col = RGBA_TO_UINT(r,g,b,120); + fade_in_shape->property_fill_color_rgba() = col; + fade_in_shape->property_width_pixels() = 0; + fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,0); + } else { + col = RGBA_TO_UINT(r,g,b,0); + fade_in_shape->property_fill_color_rgba() = col; + fade_in_shape->property_width_pixels() = 1; + fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,255); + } +} + +void +AudioRegionView::fade_out_active_changed () +{ + uint32_t r,g,b,a; + uint32_t col; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + + if (audio_region().fade_out_active()) { + col = RGBA_TO_UINT(r,g,b,120); + fade_out_shape->property_fill_color_rgba() = col; + fade_out_shape->property_width_pixels() = 0; + fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,0); + } else { + col = RGBA_TO_UINT(r,g,b,0); + fade_out_shape->property_fill_color_rgba() = col; + fade_out_shape->property_width_pixels() = 1; + fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,255); + } +} + + +void +AudioRegionView::region_scale_amplitude_changed () +{ + ENSURE_GUI_THREAD (mem_fun(*this, &AudioRegionView::region_scale_amplitude_changed)); + + for (uint32_t n = 0; n < waves.size(); ++n) { + // force a reload of the cache + waves[n]->property_data_src() = &_region; + } +} + +void +AudioRegionView::region_resized (Change what_changed) +{ + RegionView::region_resized(what_changed); + + if (what_changed & Change (StartChanged|LengthChanged)) { + + 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) { + + for (vector::iterator w = (*i)->waves.begin(); w != (*i)->waves.end(); ++w) { + (*w)->property_region_start() = _region.start(); + } + } + } +} + +void +AudioRegionView::reset_width_dependent_items (double 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; + } + + 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 +AudioRegionView::region_muted () +{ + RegionView::region_muted(); + + 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 +AudioRegionView::set_height (gdouble height) +{ + uint32_t wcnt = waves.size(); + + // FIXME: ick + TimeAxisViewItem::set_height (height - 2); + + _height = height; + + for (uint32_t n=0; n < wcnt; ++n) { + gdouble ht; + + if ((height) <= NAME_HIGHLIGHT_THRESH) { + ht = ((height-2*wcnt) / (double) wcnt); + } else { + ht = (((height-2*wcnt) - NAME_HIGHLIGHT_SIZE) / (double) wcnt); + } + + gdouble yoff = n * (ht+1); + + waves[n]->property_height() = ht; + waves[n]->property_y() = yoff + 2; + } + + if (gain_line) { + if ((height/wcnt) < NAME_HIGHLIGHT_SIZE) { + gain_line->hide (); + } else { + if (_flags & EnvelopeVisible) { + gain_line->show (); + } + } + gain_line->set_height ((uint32_t) rint (height - NAME_HIGHLIGHT_SIZE)); + } + + manage_zero_line (); + reset_fade_shapes (); + + if (name_text) { + name_text->raise_to_top(); + } +} + +void +AudioRegionView::manage_zero_line () +{ + if (!zero_line) { + return; + } + + if (_height >= 100) { + gdouble wave_midpoint = (_height - NAME_HIGHLIGHT_SIZE) / 2.0; + zero_line->property_y1() = wave_midpoint; + zero_line->property_y2() = wave_midpoint; + zero_line->show(); + } else { + zero_line->hide(); + } +} + +void +AudioRegionView::reset_fade_shapes () +{ + reset_fade_in_shape (); + reset_fade_out_shape (); +} + +void +AudioRegionView::reset_fade_in_shape () +{ + reset_fade_in_shape_width ((jack_nframes_t) audio_region().fade_in().back()->when); +} + +void +AudioRegionView::reset_fade_in_shape_width (jack_nframes_t width) +{ + if (fade_in_handle == 0) { + return; + } + + /* smallest size for a fade is 64 frames */ + + width = std::max ((jack_nframes_t) 64, width); + + Points* points; + double pwidth = width / samples_per_unit; + uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth); + double h; + + if (_height < 5) { + fade_in_shape->hide(); + fade_in_handle->hide(); + return; + } + + double handle_center; + handle_center = pwidth; + + if (handle_center > 7.0) { + handle_center -= 3.0; + } else { + handle_center = 3.0; + } + + fade_in_handle->property_x1() = handle_center - 3.0; + fade_in_handle->property_x2() = handle_center + 3.0; + + if (pwidth < 5) { + fade_in_shape->hide(); + return; + } + + fade_in_shape->show(); + + float curve[npoints]; + audio_region().fade_in().get_vector (0, audio_region().fade_in().back()->when, curve, npoints); + + points = get_canvas_points ("fade in shape", npoints+3); + + if (_height > NAME_HIGHLIGHT_THRESH) { + h = _height - NAME_HIGHLIGHT_SIZE; + } else { + h = _height; + } + + /* points *MUST* be in anti-clockwise order */ + + uint32_t pi, pc; + double xdelta = pwidth/npoints; + + for (pi = 0, pc = 0; pc < npoints; ++pc) { + (*points)[pi].set_x(1 + (pc * xdelta)); + (*points)[pi++].set_y(2 + (h - (curve[pc] * h))); + } + + /* fold back */ + + (*points)[pi].set_x(pwidth); + (*points)[pi++].set_y(2); + + (*points)[pi].set_x(1); + (*points)[pi++].set_y(2); + + /* connect the dots ... */ + + (*points)[pi] = (*points)[0]; + + fade_in_shape->property_points() = *points; + delete points; +} + +void +AudioRegionView::reset_fade_out_shape () +{ + reset_fade_out_shape_width ((jack_nframes_t) audio_region().fade_out().back()->when); +} + +void +AudioRegionView::reset_fade_out_shape_width (jack_nframes_t width) +{ + if (fade_out_handle == 0) { + return; + } + + /* smallest size for a fade is 64 frames */ + + width = std::max ((jack_nframes_t) 64, width); + + Points* points; + double pwidth = width / samples_per_unit; + uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth); + double h; + + if (_height < 5) { + fade_out_shape->hide(); + fade_out_handle->hide(); + return; + } + + double handle_center; + handle_center = (_region.length() - width) / samples_per_unit; + + if (handle_center > 7.0) { + handle_center -= 3.0; + } else { + handle_center = 3.0; + } + + fade_out_handle->property_x1() = handle_center - 3.0; + fade_out_handle->property_x2() = handle_center + 3.0; + + /* don't show shape if its too small */ + + if (pwidth < 5) { + fade_out_shape->hide(); + return; + } + + fade_out_shape->show(); + + float curve[npoints]; + audio_region().fade_out().get_vector (0, audio_region().fade_out().back()->when, curve, npoints); + + if (_height > NAME_HIGHLIGHT_THRESH) { + h = _height - NAME_HIGHLIGHT_SIZE; + } else { + h = _height; + } + + /* points *MUST* be in anti-clockwise order */ + + points = get_canvas_points ("fade out shape", npoints+3); + + uint32_t pi, pc; + double xdelta = pwidth/npoints; + + for (pi = 0, pc = 0; pc < npoints; ++pc) { + (*points)[pi].set_x(_pixel_width - 1 - pwidth + (pc*xdelta)); + (*points)[pi++].set_y(2 + (h - (curve[pc] * h))); + } + + /* fold back */ + + (*points)[pi].set_x(_pixel_width); + (*points)[pi++].set_y(h); + + (*points)[pi].set_x(_pixel_width); + (*points)[pi++].set_y(2); + + /* connect the dots ... */ + + (*points)[pi] = (*points)[0]; + + fade_out_shape->property_points() = *points; + delete points; +} + +void +AudioRegionView::set_samples_per_unit (gdouble spu) +{ + RegionView::set_samples_per_unit (spu); + + for (uint32_t n=0; n < waves.size(); ++n) { + waves[n]->property_samples_per_unit() = spu; + } + + if (gain_line) { + gain_line->reset (); + } + reset_fade_shapes (); +} + +void +AudioRegionView::set_amplitude_above_axis (gdouble spp) +{ + for (uint32_t n=0; n < waves.size(); ++n) { + waves[n]->property_amplitude_above_axis() = spp; + } +} + +void +AudioRegionView::compute_colors (Gdk::Color& basic_color) +{ + RegionView::compute_colors(basic_color); + + uint32_t r, g, b, a; + + /* gain color computed in envelope_active_changed() */ + + UINT_TO_RGBA (fill_color, &r, &g, &b, &a); + fade_color = RGBA_TO_UINT(r,g,b,120); +} + +void +AudioRegionView::set_colors () +{ + RegionView::set_colors(); + + if (gain_line) { + gain_line->set_line_color (audio_region().envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]); + } + + 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 +AudioRegionView::show_region_editor () +{ + if (editor == 0) { + editor = new AudioRegionEditor (trackview.session(), audio_region(), *this); + // GTK2FIX : how to ensure float without realizing + // editor->realize (); + // trackview.editor.ensure_float (*editor); + } + + editor->show_all (); + editor->get_window()->raise(); +} + +void +AudioRegionView::set_waveform_visible (bool yn) +{ + if (((_flags & WaveformVisible) != yn)) { + if (yn) { + for (uint32_t n=0; n < waves.size(); ++n) { + waves[n]->show(); + } + _flags |= WaveformVisible; + } else { + for (uint32_t n=0; n < waves.size(); ++n) { + waves[n]->hide(); + } + _flags &= ~WaveformVisible; + } + store_flags (); + } +} + +void +AudioRegionView::temporarily_hide_envelope () +{ + if (gain_line) { + gain_line->hide (); + } +} + +void +AudioRegionView::unhide_envelope () +{ + if (gain_line && (_flags & EnvelopeVisible)) { + gain_line->show (); + } +} + +void +AudioRegionView::set_envelope_visible (bool yn) +{ + if (gain_line && ((_flags & EnvelopeVisible) != yn)) { + if (yn) { + gain_line->show (); + _flags |= EnvelopeVisible; + } else { + gain_line->hide (); + _flags &= ~EnvelopeVisible; + } + store_flags (); + } +} + +void +AudioRegionView::create_waves () +{ + bool create_zero_line = true; + + RouteTimeAxisView& atv (*(dynamic_cast(&trackview))); // ick + + if (!atv.get_diskstream()) { + return; + } + + uint32_t nchans = atv.get_diskstream()->n_channels(); + + /* in tmp_waves, set up null pointers for each channel so the vector is allocated */ + for (uint32_t n = 0; n < nchans; ++n) { + tmp_waves.push_back (0); + } + + for (uint32_t n = 0; n < nchans; ++n) { + + if (n >= audio_region().n_channels()) { + break; + } + + wave_caches.push_back (WaveView::create_cache ()); + + 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; + } + } else { + create_one_wave (n, true); + } + } + + if (create_zero_line) { + zero_line = new ArdourCanvas::SimpleLine (*group); + zero_line->property_x1() = (gdouble) 1.0; + zero_line->property_x2() = (gdouble) (_region.length() / samples_per_unit) - 1.0; + zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; + manage_zero_line (); + } +} + +void +AudioRegionView::create_one_wave (uint32_t which, bool direct) +{ + RouteTimeAxisView& atv (*(dynamic_cast(&trackview))); // ick + uint32_t nchans = atv.get_diskstream()->n_channels(); + uint32_t n; + uint32_t nwaves = std::min (nchans, audio_region().n_channels()); + gdouble ht; + + if (trackview.height < NAME_HIGHLIGHT_SIZE) { + ht = ((trackview.height) / (double) nchans); + } else { + ht = ((trackview.height - NAME_HIGHLIGHT_SIZE) / (double) nchans); + } + + gdouble yoff = which * ht; + + WaveView *wave = new WaveView(*group); + + wave->property_data_src() = (gpointer) &_region; + wave->property_cache() = wave_caches[which]; + wave->property_cache_updater() = true; + wave->property_channel() = which; + wave->property_length_function() = (gpointer) region_length_from_c; + wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c; + wave->property_peak_function() = (gpointer) region_read_peaks_from_c; + wave->property_x() = 0.0; + wave->property_y() = yoff; + wave->property_height() = (double) ht; + wave->property_samples_per_unit() = samples_per_unit; + wave->property_amplitude_above_axis() = _amplitude_above_axis; + wave->property_wave_color() = _region.muted() ? color_map[cMutedWaveForm] : color_map[cWaveForm]; + wave->property_region_start() = _region.start(); + + if (!(_flags & WaveformVisible)) { + wave->hide(); + } + + /* note: calling this function is serialized by the lock + held in the peak building thread that signals that + peaks are ready for use *or* by the fact that it is + called one by one from the GUI thread. + */ + + if (which < nchans) { + tmp_waves[which] = wave; + } else { + /* n-channel track, >n-channel source */ + } + + /* see if we're all ready */ + + for (n = 0; n < nchans; ++n) { + if (tmp_waves[n] == 0) { + break; + } + } + + if (n == nwaves && waves.empty()) { + /* all waves are ready */ + tmp_waves.resize(nwaves); + + waves = tmp_waves; + tmp_waves.clear (); + + if (!zero_line) { + zero_line = new ArdourCanvas::SimpleLine (*group); + zero_line->property_x1() = (gdouble) 1.0; + zero_line->property_x2() = (gdouble) (_region.length() / samples_per_unit) - 1.0; + zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; + manage_zero_line (); + } + } +} + +void +AudioRegionView::peaks_ready_handler (uint32_t which) +{ + Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &AudioRegionView::create_one_wave), which, false)); + + if (!waves.empty()) { + /* all waves created, don't hook into peaks ready anymore */ + data_ready_connection.disconnect (); + } +} + +void +AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) +{ + if (gain_line == 0) { + return; + } + + double x, y; + + /* don't create points that can't be seen */ + + set_envelope_visible (true); + + x = ev->button.x; + y = ev->button.y; + + item->w2i (x, y); + + jack_nframes_t fx = trackview.editor.pixel_to_frame (x); + + if (fx > _region.length()) { + return; + } + + /* compute vertical fractional position */ + + y = 1.0 - (y / (trackview.height - NAME_HIGHLIGHT_SIZE)); + + /* map using gain line */ + + gain_line->view_to_model_y (y); + + trackview.session().begin_reversible_command (_("add gain control point")); + trackview.session().add_undo (audio_region().envelope().get_memento()); + + + if (!audio_region().envelope_active()) { + trackview.session().add_undo( bind( mem_fun(audio_region(), &AudioRegion::set_envelope_active), false) ); + audio_region().set_envelope_active(true); + trackview.session().add_redo( bind( mem_fun(audio_region(), &AudioRegion::set_envelope_active), true) ); + } + + audio_region().envelope().add (fx, y); + + trackview.session().add_redo_no_execute (audio_region().envelope().get_memento()); + trackview.session().commit_reversible_command (); +} + +void +AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) +{ + ControlPoint *cp = reinterpret_cast (item->get_data ("control_point")); + audio_region().envelope().erase (cp->model); +} + +void +AudioRegionView::store_flags() +{ + XMLNode *node = new XMLNode ("GUI"); + + node->add_property ("waveform-visible", (_flags & WaveformVisible) ? "yes" : "no"); + node->add_property ("envelope-visible", (_flags & EnvelopeVisible) ? "yes" : "no"); + + _region.add_extra_xml (*node); +} + +void +AudioRegionView::set_flags (XMLNode* node) +{ + XMLProperty *prop; + + if ((prop = node->property ("waveform-visible")) != 0) { + if (prop->value() == "yes") { + _flags |= WaveformVisible; + } + } + + if ((prop = node->property ("envelope-visible")) != 0) { + if (prop->value() == "yes") { + _flags |= EnvelopeVisible; + } + } +} + +void +AudioRegionView::set_waveform_shape (WaveformShape shape) +{ + bool yn; + + /* this slightly odd approach is to leave the door open to + other "shapes" such as spectral displays, etc. + */ + + switch (shape) { + case Rectified: + yn = true; + break; + + default: + yn = false; + break; + } + + if (yn != (bool) (_flags & WaveformRectified)) { + for (vector::iterator wave = waves.begin(); wave != waves.end() ; ++wave) { + (*wave)->property_rectified() = yn; + } + + if (zero_line) { + if (yn) { + zero_line->hide(); + } else { + zero_line->show(); + } + } + + if (yn) { + _flags |= WaveformRectified; + } else { + _flags &= ~WaveformRectified; + } + } +} + +GhostRegion* +AudioRegionView::add_ghost (AutomationTimeAxisView& atv) +{ + RouteTimeAxisView& myatv (*(dynamic_cast(&trackview))); // ick + double unit_position = _region.position () / samples_per_unit; + GhostRegion* ghost = new GhostRegion (atv, unit_position); + uint32_t nchans; + + nchans = myatv.get_diskstream()->n_channels(); + + for (uint32_t n = 0; n < nchans; ++n) { + + if (n >= audio_region().n_channels()) { + break; + } + + WaveView *wave = new WaveView(*ghost->group); + + wave->property_data_src() = &_region; + wave->property_cache() = wave_caches[n]; + wave->property_cache_updater() = false; + wave->property_channel() = n; + wave->property_length_function() = (gpointer)region_length_from_c; + wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c; + wave->property_peak_function() = (gpointer) region_read_peaks_from_c; + wave->property_x() = 0.0; + wave->property_samples_per_unit() = samples_per_unit; + wave->property_amplitude_above_axis() = _amplitude_above_axis; + wave->property_wave_color() = color_map[cGhostTrackWave]; + wave->property_region_start() = _region.start(); + + ghost->waves.push_back(wave); + } + + ghost->set_height (); + ghost->set_duration (_region.length() / samples_per_unit); + ghosts.push_back (ghost); + + ghost->GoingAway.connect (mem_fun(*this, &AudioRegionView::remove_ghost)); + + return ghost; +} + +void +AudioRegionView::entered () +{ + if (gain_line && _flags & EnvelopeVisible) { + gain_line->show_all_control_points (); + } + + uint32_t r,g,b,a; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + a=255; + + if (fade_in_handle) { + fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + } +} + +void +AudioRegionView::exited () +{ + if (gain_line) { + gain_line->hide_all_but_selected_control_points (); + } + + uint32_t r,g,b,a; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + a=0; + + if (fade_in_handle) { + fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + } +} + +void +AudioRegionView::envelope_active_changed () +{ + if (gain_line) { + gain_line->set_line_color (audio_region().envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]); + } +} + +void +AudioRegionView::set_waveview_data_src() +{ + + double unit_length= _region.length() / samples_per_unit; + + for (uint32_t n = 0; n < waves.size(); ++n) { + // TODO: something else to let it know the channel + waves[n]->property_data_src() = &_region; + } + + 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_data_src() = &_region; + } + } + +} + +void +AudioRegionView::color_handler (ColorID id, uint32_t val) +{ + switch (id) { + case cMutedWaveForm: + case cWaveForm: + set_colors (); + break; + + case cGainLineInactive: + case cGainLine: + envelope_active_changed(); + break; + + case cZeroLine: + if (zero_line) { + zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; + } + break; + + case cGhostTrackWave: + break; + + default: + break; + } +} diff --git a/gtk2_ardour/audio_region_view.h b/gtk2_ardour/audio_region_view.h new file mode 100644 index 0000000000..ec3ea6c4c5 --- /dev/null +++ b/gtk2_ardour/audio_region_view.h @@ -0,0 +1,164 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. +*/ + +#ifndef __gtk_ardour_audio_region_view_h__ +#define __gtk_ardour_audio_region_view_h__ + +#include + +#include +#include +#include +#include + +#include "region_view.h" +#include "route_time_axis.h" +#include "time_axis_view_item.h" +#include "automation_line.h" +#include "enums.h" +#include "waveview.h" +#include "canvas.h" +#include "color.h" + +namespace ARDOUR { + class AudioRegion; + class PeakData; +}; + +class AudioTimeAxisView; +class AudioRegionGainLine; +class AudioRegionEditor; +class GhostRegion; +class AutomationTimeAxisView; + +class AudioRegionView : public RegionView +{ + public: + AudioRegionView (ArdourCanvas::Group *, + RouteTimeAxisView&, + ARDOUR::AudioRegion&, + double initial_samples_per_unit, + Gdk::Color& basic_color); + + ~AudioRegionView (); + + virtual void init (Gdk::Color& base_color, bool wait_for_data = false); + + ARDOUR::AudioRegion& audio_region() const; + + void set_height (double); + void set_samples_per_unit (double); + + void set_amplitude_above_axis (gdouble spp); + + void temporarily_hide_envelope (); ///< Dangerous! + void unhide_envelope (); ///< Dangerous! + + void set_envelope_visible (bool); + void set_waveform_visible (bool yn); + 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; } + + void show_region_editor (); + + void add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *event); + void remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *event); + + AudioRegionGainLine* get_gain_line() const { return gain_line; } + + void region_changed (ARDOUR::Change); + void envelope_active_changed (); + + GhostRegion* add_ghost (AutomationTimeAxisView&); + + void reset_fade_in_shape_width (jack_nframes_t); + void reset_fade_out_shape_width (jack_nframes_t); + void set_fade_in_active (bool); + void set_fade_out_active (bool); + + virtual void entered (); + virtual void exited (); + + protected: + + /* this constructor allows derived types + to specify their visibility requirements + to the TimeAxisViewItem parent class + */ + + AudioRegionView (ArdourCanvas::Group *, + RouteTimeAxisView&, + ARDOUR::AudioRegion&, + double samples_per_unit, + Gdk::Color& basic_color, + TimeAxisViewItem::Visibility); + + enum Flags { + EnvelopeVisible = 0x1, + WaveformVisible = 0x4, + WaveformRectified = 0x8 + }; + + void reset_fade_shapes (); + void reset_fade_in_shape (); + void reset_fade_out_shape (); + void fade_in_changed (); + void fade_out_changed (); + void fade_in_active_changed (); + void fade_out_active_changed (); + + void region_resized (ARDOUR::Change); + void region_moved (void *); + void region_muted (); + void region_scale_amplitude_changed (); + + void create_waves (); + void create_one_wave (uint32_t, bool); + void manage_zero_line (); + void peaks_ready_handler (uint32_t); + void set_flags (XMLNode *); + void store_flags (); + + void set_colors (); + void compute_colors (Gdk::Color&); + void reset_width_dependent_items (double pixel_width); + void set_waveview_data_src(); + + void color_handler (ColorID, uint32_t); + + vector wave_caches; + vector waves; + vector tmp_waves; ///< see ::create_waves() + 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; + + double _amplitude_above_axis; + + uint32_t _flags; + uint32_t fade_color; +}; + +#endif /* __gtk_ardour_audio_region_view_h__ */ diff --git a/gtk2_ardour/audio_regionview.cc b/gtk2_ardour/audio_regionview.cc new file mode 100644 index 0000000000..e2d20c0cc0 --- /dev/null +++ b/gtk2_ardour/audio_regionview.cc @@ -0,0 +1,1408 @@ +/* + Copyright (C) 2001 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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: regionview.cc 678 2006-07-11 15:45:19Z paul $ +*/ + +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include "streamview.h" +#include "region_view.h" +#include "audio_time_axis.h" +#include "simplerect.h" +#include "simpleline.h" +#include "waveview.h" +#include "public_editor.h" +#include "region_editor.h" +#include "region_gain_line.h" +#include "ghostregion.h" +#include "audio_time_axis.h" +#include "utils.h" +#include "rgb_macros.h" +#include "gui_thread.h" + +#include "i18n.h" + +using namespace sigc; +using namespace ARDOUR; +using namespace PBD; +using namespace Editing; +using namespace ArdourCanvas; + +static const int32_t sync_mark_width = 9; + +sigc::signal AudioRegionView::AudioRegionViewGoingAway; + +AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, AudioTimeAxisView &tv, AudioRegion& r, double spu, + Gdk::Color& basic_color) + : TimeAxisViewItem (r.name(), *parent, tv, spu, basic_color, r.position(), r.length(), + TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameText| + TimeAxisViewItem::ShowNameHighlight| + TimeAxisViewItem::ShowFrame)), + region (r) +{ +} + +AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, AudioTimeAxisView &tv, AudioRegion& r, double spu, + Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility) + : TimeAxisViewItem (r.name(), *parent, tv, spu, basic_color, r.position(), r.length(), visibility), + region (r) +{ +} + +void +AudioRegionView::init (double amplitude_above_axis, Gdk::Color& basic_color, bool wfw) +{ + ArdourCanvas::Points shape; + XMLNode *node; + + editor = 0; + valid = true; + in_destructor = false; + _amplitude_above_axis = amplitude_above_axis; + 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 (); + } + + if (trackview.editor.new_regionviews_display_gain()) { + _flags |= EnvelopeVisible; + } + + compute_colors (basic_color); + + 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); + + fade_out_shape = new ArdourCanvas::Polygon (*group); + fade_out_shape->property_fill_color_rgba() = fade_color; + fade_out_shape->set_data ("regionview", this); + + + { + uint32_t r,g,b,a; + UINT_TO_RGBA(fill_color,&r,&g,&b,&a); + + + fade_in_handle = new ArdourCanvas::SimpleRect (*group); + fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0); + fade_in_handle->property_outline_pixels() = 0; + fade_in_handle->property_y1() = 2.0; + fade_in_handle->property_y2() = 7.0; + + fade_in_handle->set_data ("regionview", this); + + fade_out_handle = new ArdourCanvas::SimpleRect (*group); + fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0); + fade_out_handle->property_outline_pixels() = 0; + fade_out_handle->property_y1() = 2.0; + fade_out_handle->property_y2() = 7.0; + + fade_out_handle->set_data ("regionview", this); + } + + string foo = region.name(); + foo += ':'; + foo += "gain"; + + gain_line = new AudioRegionGainLine (foo, trackview.session(), *this, *group, region.envelope()); + + if (!(_flags & EnvelopeVisible)) { + gain_line->hide (); + } else { + gain_line->show (); + } + + reset_width_dependent_items ((double) region.length() / samples_per_unit); + + gain_line->reset (); + + set_height (trackview.height); + + region_muted (); + region_sync_changed (); + region_resized (BoundsChanged); + set_waveview_data_src(); + region_locked (); + envelope_active_changed (); + fade_in_active_changed (); + fade_out_active_changed (); + + 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)); + fade_out_handle->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_handle_event), fade_out_handle, this)); + + set_colors (); + + ColorChanged.connect (mem_fun (*this, &AudioRegionView::color_handler)); + + /* XXX sync mark drag? */ +} + +AudioRegionView::~AudioRegionView () +{ + in_destructor = true; + + AudioRegionViewGoingAway (this); /* EMIT_SIGNAL */ + + for (vector::iterator cache = wave_caches.begin(); cache != wave_caches.end() ; ++cache) { + gnome_canvas_waveview_cache_destroy (*cache); + } + + /* 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; + } +} + +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 (); + } + if (what_changed & AudioRegion::ScaleAmplitudeChanged) { + region_scale_amplitude_changed (); + } + if (what_changed & AudioRegion::FadeInChanged) { + fade_in_changed (); + } + if (what_changed & AudioRegion::FadeOutChanged) { + fade_out_changed (); + } + if (what_changed & AudioRegion::FadeInActiveChanged) { + fade_in_active_changed (); + } + if (what_changed & AudioRegion::FadeOutActiveChanged) { + fade_out_active_changed (); + } + if (what_changed & AudioRegion::EnvelopeActiveChanged) { + envelope_active_changed (); + } +} + +void +AudioRegionView::fade_in_changed () +{ + reset_fade_in_shape (); +} + +void +AudioRegionView::fade_out_changed () +{ + reset_fade_out_shape (); +} + +void +AudioRegionView::set_fade_in_active (bool yn) +{ + region.set_fade_in_active (yn); +} + +void +AudioRegionView::set_fade_out_active (bool yn) +{ + region.set_fade_out_active (yn); +} + +void +AudioRegionView::fade_in_active_changed () +{ + uint32_t r,g,b,a; + uint32_t col; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + + if (region.fade_in_active()) { + col = RGBA_TO_UINT(r,g,b,120); + fade_in_shape->property_fill_color_rgba() = col; + fade_in_shape->property_width_pixels() = 0; + fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,0); + } else { + col = RGBA_TO_UINT(r,g,b,0); + fade_in_shape->property_fill_color_rgba() = col; + fade_in_shape->property_width_pixels() = 1; + fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,255); + } +} + +void +AudioRegionView::fade_out_active_changed () +{ + uint32_t r,g,b,a; + uint32_t col; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + + if (region.fade_out_active()) { + col = RGBA_TO_UINT(r,g,b,120); + fade_out_shape->property_fill_color_rgba() = col; + fade_out_shape->property_width_pixels() = 0; + fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,0); + } else { + col = RGBA_TO_UINT(r,g,b,0); + fade_out_shape->property_fill_color_rgba() = col; + fade_out_shape->property_width_pixels() = 1; + fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,255); + } +} + + +void +AudioRegionView::region_scale_amplitude_changed () +{ + ENSURE_GUI_THREAD (mem_fun(*this, &AudioRegionView::region_scale_amplitude_changed)); + + for (uint32_t n = 0; n < waves.size(); ++n) { + // force a reload of the cache + waves[n]->property_data_src() = ®ion; + } +} + +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); + } + + 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(); + } + } + } +} + +void +AudioRegionView::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 +AudioRegionView::region_layered () +{ + AudioTimeAxisView *atv = dynamic_cast (&get_time_axis_view()); + atv->view->region_layered (this); +} + +void +AudioRegionView::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 +AudioRegionView::region_opacity () +{ + set_frame_color (); +} + +void +AudioRegionView::raise () +{ + region.raise (); +} + +void +AudioRegionView::raise_to_top () +{ + region.raise_to_top (); +} + +void +AudioRegionView::lower () +{ + region.lower (); +} + +void +AudioRegionView::lower_to_bottom () +{ + region.lower_to_bottom (); +} + +bool +AudioRegionView::set_position (jack_nframes_t pos, void* src, double* ignored) +{ + double delta; + bool ret; + + if (!(ret = TimeAxisViewItem::set_position (pos, this, &delta))) { + return false; + } + + if (ignored) { + *ignored = delta; + } + + if (delta) { + for (vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { + (*i)->group->move (delta, 0.0); + } + } + + return ret; +} + +void +AudioRegionView::set_height (gdouble height) +{ + uint32_t wcnt = waves.size(); + + TimeAxisViewItem::set_height (height - 2); + + _height = height; + + for (uint32_t n=0; n < wcnt; ++n) { + gdouble ht; + + if ((height) <= NAME_HIGHLIGHT_THRESH) { + ht = ((height-2*wcnt) / (double) wcnt); + } else { + ht = (((height-2*wcnt) - NAME_HIGHLIGHT_SIZE) / (double) wcnt); + } + + gdouble yoff = n * (ht+1); + + waves[n]->property_height() = ht; + waves[n]->property_y() = yoff + 2; + } + + if (gain_line) { + if ((height/wcnt) < NAME_HIGHLIGHT_SIZE) { + gain_line->hide (); + } else { + if (_flags & EnvelopeVisible) { + gain_line->show (); + } + } + gain_line->set_height ((uint32_t) rint (height - NAME_HIGHLIGHT_SIZE)); + } + + manage_zero_line (); + reset_fade_shapes (); + + if (name_text) { + name_text->raise_to_top(); + } +} + +void +AudioRegionView::manage_zero_line () +{ + if (!zero_line) { + return; + } + + if (_height >= 100) { + gdouble wave_midpoint = (_height - NAME_HIGHLIGHT_SIZE) / 2.0; + zero_line->property_y1() = wave_midpoint; + zero_line->property_y2() = wave_midpoint; + zero_line->show(); + } else { + zero_line->hide(); + } +} + +void +AudioRegionView::reset_fade_shapes () +{ + reset_fade_in_shape (); + reset_fade_out_shape (); +} + +void +AudioRegionView::reset_fade_in_shape () +{ + reset_fade_in_shape_width ((jack_nframes_t) region.fade_in().back()->when); +} + +void +AudioRegionView::reset_fade_in_shape_width (jack_nframes_t width) +{ + if (fade_in_handle == 0) { + return; + } + + /* smallest size for a fade is 64 frames */ + + width = std::max ((jack_nframes_t) 64, width); + + Points* points; + double pwidth = width / samples_per_unit; + uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth); + double h; + + if (_height < 5) { + fade_in_shape->hide(); + fade_in_handle->hide(); + return; + } + + double handle_center; + handle_center = pwidth; + + if (handle_center > 7.0) { + handle_center -= 3.0; + } else { + handle_center = 3.0; + } + + fade_in_handle->property_x1() = handle_center - 3.0; + fade_in_handle->property_x2() = handle_center + 3.0; + + if (pwidth < 5) { + fade_in_shape->hide(); + return; + } + + fade_in_shape->show(); + + float curve[npoints]; + region.fade_in().get_vector (0, region.fade_in().back()->when, curve, npoints); + + points = get_canvas_points ("fade in shape", npoints+3); + + if (_height > NAME_HIGHLIGHT_THRESH) { + h = _height - NAME_HIGHLIGHT_SIZE; + } else { + h = _height; + } + + /* points *MUST* be in anti-clockwise order */ + + uint32_t pi, pc; + double xdelta = pwidth/npoints; + + for (pi = 0, pc = 0; pc < npoints; ++pc) { + (*points)[pi].set_x(1 + (pc * xdelta)); + (*points)[pi++].set_y(2 + (h - (curve[pc] * h))); + } + + /* fold back */ + + (*points)[pi].set_x(pwidth); + (*points)[pi++].set_y(2); + + (*points)[pi].set_x(1); + (*points)[pi++].set_y(2); + + /* connect the dots ... */ + + (*points)[pi] = (*points)[0]; + + fade_in_shape->property_points() = *points; + delete points; +} + +void +AudioRegionView::reset_fade_out_shape () +{ + reset_fade_out_shape_width ((jack_nframes_t) region.fade_out().back()->when); +} + +void +AudioRegionView::reset_fade_out_shape_width (jack_nframes_t width) +{ + if (fade_out_handle == 0) { + return; + } + + /* smallest size for a fade is 64 frames */ + + width = std::max ((jack_nframes_t) 64, width); + + Points* points; + double pwidth = width / samples_per_unit; + uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth); + double h; + + if (_height < 5) { + fade_out_shape->hide(); + fade_out_handle->hide(); + return; + } + + double handle_center; + handle_center = (region.length() - width) / samples_per_unit; + + if (handle_center > 7.0) { + handle_center -= 3.0; + } else { + handle_center = 3.0; + } + + fade_out_handle->property_x1() = handle_center - 3.0; + fade_out_handle->property_x2() = handle_center + 3.0; + + /* don't show shape if its too small */ + + if (pwidth < 5) { + fade_out_shape->hide(); + return; + } + + fade_out_shape->show(); + + float curve[npoints]; + region.fade_out().get_vector (0, region.fade_out().back()->when, curve, npoints); + + if (_height > NAME_HIGHLIGHT_THRESH) { + h = _height - NAME_HIGHLIGHT_SIZE; + } else { + h = _height; + } + + /* points *MUST* be in anti-clockwise order */ + + points = get_canvas_points ("fade out shape", npoints+3); + + uint32_t pi, pc; + double xdelta = pwidth/npoints; + + for (pi = 0, pc = 0; pc < npoints; ++pc) { + (*points)[pi].set_x(_pixel_width - 1 - pwidth + (pc*xdelta)); + (*points)[pi++].set_y(2 + (h - (curve[pc] * h))); + } + + /* fold back */ + + (*points)[pi].set_x(_pixel_width); + (*points)[pi++].set_y(h); + + (*points)[pi].set_x(_pixel_width); + (*points)[pi++].set_y(2); + + /* connect the dots ... */ + + (*points)[pi] = (*points)[0]; + + fade_out_shape->property_points() = *points; + delete points; +} + +void +AudioRegionView::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 (); +} + +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 +AudioRegionView::set_amplitude_above_axis (gdouble spp) +{ + for (uint32_t n=0; n < waves.size(); ++n) { + waves[n]->property_amplitude_above_axis() = spp; + } +} + +void +AudioRegionView::compute_colors (Gdk::Color& basic_color) +{ + TimeAxisViewItem::compute_colors (basic_color); + uint32_t r, g, b, a; + + /* gain color computed in envelope_active_changed() */ + + UINT_TO_RGBA (fill_color, &r, &g, &b, &a); + fade_color = RGBA_TO_UINT(r,g,b,120); +} + +void +AudioRegionView::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 +AudioRegionView::set_frame_color () +{ + if (region.opaque()) { + fill_opacity = 180; + } else { + fill_opacity = 100; + } + + TimeAxisViewItem::set_frame_color (); +} + +void +AudioRegionView::show_region_editor () +{ + if (editor == 0) { + editor = new AudioRegionEditor (trackview.session(), region, *this); + // GTK2FIX : how to ensure float without realizing + // editor->realize (); + // trackview.editor.ensure_float (*editor); + } + + editor->show_all (); + 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 (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) +{ + if (((_flags & WaveformVisible) != yn)) { + if (yn) { + for (uint32_t n=0; n < waves.size(); ++n) { + waves[n]->show(); + } + _flags |= WaveformVisible; + } else { + for (uint32_t n=0; n < waves.size(); ++n) { + waves[n]->hide(); + } + _flags &= ~WaveformVisible; + } + store_flags (); + } +} + +void +AudioRegionView::temporarily_hide_envelope () +{ + if (gain_line) { + gain_line->hide (); + } +} + +void +AudioRegionView::unhide_envelope () +{ + if (gain_line && (_flags & EnvelopeVisible)) { + gain_line->show (); + } +} + +void +AudioRegionView::set_envelope_visible (bool yn) +{ + if (gain_line && ((_flags & EnvelopeVisible) != yn)) { + if (yn) { + gain_line->show (); + _flags |= EnvelopeVisible; + } else { + gain_line->hide (); + _flags &= ~EnvelopeVisible; + } + store_flags (); + } +} + +void +AudioRegionView::create_waves () +{ + bool create_zero_line = true; + + AudioTimeAxisView& atv (*(dynamic_cast(&trackview))); // ick + + if (!atv.get_diskstream()) { + return; + } + + uint32_t nchans = atv.get_diskstream()->n_channels(); + + /* in tmp_waves, set up null pointers for each channel so the vector is allocated */ + for (uint32_t n = 0; n < nchans; ++n) { + tmp_waves.push_back (0); + } + + for (uint32_t n = 0; n < nchans; ++n) { + + if (n >= region.n_channels()) { + break; + } + + wave_caches.push_back (WaveView::create_cache ()); + + if (wait_for_waves) { + if (region.source(n).peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), peaks_ready_connection)) { + create_one_wave (n, true); + } else { + create_zero_line = false; + } + } else { + create_one_wave (n, true); + } + } + + if (create_zero_line) { + zero_line = new ArdourCanvas::SimpleLine (*group); + zero_line->property_x1() = (gdouble) 1.0; + zero_line->property_x2() = (gdouble) (region.length() / samples_per_unit) - 1.0; + zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; + manage_zero_line (); + } +} + +void +AudioRegionView::create_one_wave (uint32_t which, bool direct) +{ + AudioTimeAxisView& atv (*(dynamic_cast(&trackview))); // ick + uint32_t nchans = atv.get_diskstream()->n_channels(); + uint32_t n; + uint32_t nwaves = std::min (nchans, region.n_channels()); + gdouble ht; + + if (trackview.height < NAME_HIGHLIGHT_SIZE) { + ht = ((trackview.height) / (double) nchans); + } else { + ht = ((trackview.height - NAME_HIGHLIGHT_SIZE) / (double) nchans); + } + + gdouble yoff = which * ht; + + WaveView *wave = new WaveView(*group); + + wave->property_data_src() = (gpointer) ®ion; + wave->property_cache() = wave_caches[which]; + wave->property_cache_updater() = true; + wave->property_channel() = which; + wave->property_length_function() = (gpointer) region_length_from_c; + wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c; + wave->property_peak_function() = (gpointer) region_read_peaks_from_c; + wave->property_x() = 0.0; + wave->property_y() = yoff; + wave->property_height() = (double) ht; + wave->property_samples_per_unit() = samples_per_unit; + wave->property_amplitude_above_axis() = _amplitude_above_axis; + wave->property_wave_color() = region.muted() ? color_map[cMutedWaveForm] : color_map[cWaveForm]; + wave->property_region_start() = region.start(); + + if (!(_flags & WaveformVisible)) { + wave->hide(); + } + + /* note: calling this function is serialized by the lock + held in the peak building thread that signals that + peaks are ready for use *or* by the fact that it is + called one by one from the GUI thread. + */ + + if (which < nchans) { + tmp_waves[which] = wave; + } else { + /* n-channel track, >n-channel source */ + } + + /* see if we're all ready */ + + for (n = 0; n < nchans; ++n) { + if (tmp_waves[n] == 0) { + break; + } + } + + if (n == nwaves && waves.empty()) { + /* all waves are ready */ + tmp_waves.resize(nwaves); + + waves = tmp_waves; + tmp_waves.clear (); + + if (!zero_line) { + zero_line = new ArdourCanvas::SimpleLine (*group); + zero_line->property_x1() = (gdouble) 1.0; + zero_line->property_x2() = (gdouble) (region.length() / samples_per_unit) - 1.0; + zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; + manage_zero_line (); + } + } +} + +void +AudioRegionView::peaks_ready_handler (uint32_t which) +{ + Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &AudioRegionView::create_one_wave), which, false)); + + if (!waves.empty()) { + /* all waves created, don't hook into peaks ready anymore */ + peaks_ready_connection.disconnect (); + } +} + +void +AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) +{ + if (gain_line == 0) { + return; + } + + double x, y; + + /* don't create points that can't be seen */ + + set_envelope_visible (true); + + x = ev->button.x; + y = ev->button.y; + + item->w2i (x, y); + + jack_nframes_t fx = trackview.editor.pixel_to_frame (x); + + if (fx > region.length()) { + return; + } + + /* compute vertical fractional position */ + + y = 1.0 - (y / (trackview.height - NAME_HIGHLIGHT_SIZE)); + + /* map using gain line */ + + gain_line->view_to_model_y (y); + + trackview.session().begin_reversible_command (_("add gain control point")); + trackview.session().add_undo (region.envelope().get_memento()); + + + if (!region.envelope_active()) { + trackview.session().add_undo( bind( mem_fun(region, &AudioRegion::set_envelope_active), false) ); + region.set_envelope_active(true); + trackview.session().add_redo( bind( mem_fun(region, &AudioRegion::set_envelope_active), true) ); + } + + region.envelope().add (fx, y); + + trackview.session().add_redo_no_execute (region.envelope().get_memento()); + trackview.session().commit_reversible_command (); +} + +void +AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) +{ + ControlPoint *cp = reinterpret_cast (item->get_data ("control_point")); + region.envelope().erase (cp->model); +} + +void +AudioRegionView::store_flags() +{ + XMLNode *node = new XMLNode ("GUI"); + + node->add_property ("waveform-visible", (_flags & WaveformVisible) ? "yes" : "no"); + node->add_property ("envelope-visible", (_flags & EnvelopeVisible) ? "yes" : "no"); + + region.add_extra_xml (*node); +} + +void +AudioRegionView::set_flags (XMLNode* node) +{ + XMLProperty *prop; + + if ((prop = node->property ("waveform-visible")) != 0) { + if (prop->value() == "yes") { + _flags |= WaveformVisible; + } + } + + if ((prop = node->property ("envelope-visible")) != 0) { + if (prop->value() == "yes") { + _flags |= EnvelopeVisible; + } + } +} + +void +AudioRegionView::set_waveform_shape (WaveformShape shape) +{ + bool yn; + + /* this slightly odd approach is to leave the door open to + other "shapes" such as spectral displays, etc. + */ + + switch (shape) { + case Rectified: + yn = true; + break; + + default: + yn = false; + break; + } + + if (yn != (bool) (_flags & WaveformRectified)) { + for (vector::iterator wave = waves.begin(); wave != waves.end() ; ++wave) { + (*wave)->property_rectified() = yn; + } + + if (zero_line) { + if (yn) { + zero_line->hide(); + } else { + zero_line->show(); + } + } + + if (yn) { + _flags |= WaveformRectified; + } else { + _flags &= ~WaveformRectified; + } + } +} + +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) +{ + AudioTimeAxisView& myatv (*(dynamic_cast(&trackview))); // ick + double unit_position = region.position () / samples_per_unit; + GhostRegion* ghost = new GhostRegion (atv, unit_position); + uint32_t nchans; + + nchans = myatv.get_diskstream()->n_channels(); + + for (uint32_t n = 0; n < nchans; ++n) { + + if (n >= region.n_channels()) { + break; + } + + WaveView *wave = new WaveView(*ghost->group); + + wave->property_data_src() = ®ion; + wave->property_cache() = wave_caches[n]; + wave->property_cache_updater() = false; + wave->property_channel() = n; + wave->property_length_function() = (gpointer)region_length_from_c; + wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c; + wave->property_peak_function() = (gpointer) region_read_peaks_from_c; + wave->property_x() = 0.0; + wave->property_samples_per_unit() = samples_per_unit; + wave->property_amplitude_above_axis() = _amplitude_above_axis; + wave->property_wave_color() = color_map[cGhostTrackWave]; + wave->property_region_start() = region.start(); + + ghost->waves.push_back(wave); + } + + ghost->set_height (); + ghost->set_duration (region.length() / samples_per_unit); + ghosts.push_back (ghost); + + ghost->GoingAway.connect (mem_fun(*this, &AudioRegionView::remove_ghost)); + + 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; + } + } +} + +uint32_t +AudioRegionView::get_fill_color () +{ + return fill_color; +} + +void +AudioRegionView::entered () +{ + if (gain_line && _flags & EnvelopeVisible) { + gain_line->show_all_control_points (); + } + + uint32_t r,g,b,a; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + a=255; + + if (fade_in_handle) { + fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + } +} + +void +AudioRegionView::exited () +{ + if (gain_line) { + gain_line->hide_all_but_selected_control_points (); + } + + uint32_t r,g,b,a; + UINT_TO_RGBA(fade_color,&r,&g,&b,&a); + a=0; + + if (fade_in_handle) { + fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); + } +} + +void +AudioRegionView::envelope_active_changed () +{ + if (gain_line) { + gain_line->set_line_color (region.envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]); + } +} + +void +AudioRegionView::set_waveview_data_src() +{ + + double unit_length= region.length() / samples_per_unit; + + for (uint32_t n = 0; n < waves.size(); ++n) { + // TODO: something else to let it know the channel + waves[n]->property_data_src() = ®ion; + } + + 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_data_src() = ®ion; + } + } + +} + +void +AudioRegionView::color_handler (ColorID id, uint32_t val) +{ + switch (id) { + case cMutedWaveForm: + case cWaveForm: + set_colors (); + break; + + case cGainLineInactive: + case cGainLine: + envelope_active_changed(); + break; + + case cZeroLine: + if (zero_line) { + zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; + } + break; + + case cGhostTrackWave: + break; + + default: + break; + } +} diff --git a/gtk2_ardour/audio_streamview.cc b/gtk2_ardour/audio_streamview.cc new file mode 100644 index 0000000000..68df5ffe43 --- /dev/null +++ b/gtk2_ardour/audio_streamview.cc @@ -0,0 +1,698 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. +*/ + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "audio_streamview.h" +#include "audio_region_view.h" +#include "tape_region_view.h" +#include "audio_time_axis.h" +#include "canvas-waveview.h" +#include "canvas-simplerect.h" +#include "region_selection.h" +#include "selection.h" +#include "public_editor.h" +#include "ardour_ui.h" +#include "crossfade_view.h" +#include "rgb_macros.h" +#include "gui_thread.h" +#include "utils.h" +#include "color.h" + +using namespace ARDOUR; +using namespace PBD; +using namespace Editing; + +AudioStreamView::AudioStreamView (AudioTimeAxisView& tv) + : StreamView (tv) +{ + crossfades_visible = true; + + if (tv.is_audio_track()) + stream_base_color = color_map[cAudioTrackBase]; + else + stream_base_color = color_map[cAudioBusBase]; + + canvas_rect->property_outline_color_rgba() = color_map[cAudioTrackOutline]; + + _amplitude_above_axis = 1.0; + + use_rec_regions = tv.editor.show_waveforms_recording (); + last_rec_peak_frame = 0; +} + +AudioStreamView::~AudioStreamView () +{ +} + +int +AudioStreamView::set_height (gdouble h) +{ + /* limit the values to something sane-ish */ + if (h < 10.0 || h > 1000.0) { + return -1; + } + + StreamView::set_height(h); + + for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + (*i)->set_height (h); + } + + return 0; +} + +int +AudioStreamView::set_samples_per_unit (gdouble spp) +{ + StreamView::set_samples_per_unit(spp); + + for (CrossfadeViewList::iterator xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) { + (*xi)->set_samples_per_unit (spp); + } + + return 0; +} + +int +AudioStreamView::set_amplitude_above_axis (gdouble app) +{ + RegionViewList::iterator i; + + if (app < 1.0) { + return -1; + } + + _amplitude_above_axis = app; + + for (i = region_views.begin(); i != region_views.end(); ++i) { + AudioRegionView* const arv = dynamic_cast(*i); + if (arv) + arv->set_amplitude_above_axis (app); + } + + return 0; +} + +void +AudioStreamView::add_region_view_internal (Region *r, bool wait_for_waves) +{ + ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::add_region_view), r)); + + AudioRegion* region = dynamic_cast (r); + + if (region == 0) { + return; + } + + AudioRegionView *region_view; + list::iterator i; + + for (i = region_views.begin(); i != region_views.end(); ++i) { + if (&(*i)->region() == r) { + + /* great. we already have a AudioRegionView for this Region. use it again. */ + + (*i)->set_valid (true); + return; + } + } + + switch (_trackview.audio_track()->mode()) { + case Normal: + region_view = new AudioRegionView (canvas_group, _trackview, *region, + _samples_per_unit, region_color); + break; + case Destructive: + region_view = new TapeAudioRegionView (canvas_group, _trackview, *region, + _samples_per_unit, region_color); + break; + } + + region_view->init (region_color, wait_for_waves); + region_view->set_amplitude_above_axis(_amplitude_above_axis); + region_views.push_front (region_view); + + /* follow global waveform setting */ + + region_view->set_waveform_visible(_trackview.editor.show_waveforms()); + + /* catch regionview going away */ + + region->GoingAway.connect (mem_fun (*this, &AudioStreamView::remove_region_view)); + + RegionViewAdded (region_view); +} + +void +AudioStreamView::remove_region_view (Region *r) +{ + ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::remove_region_view), r)); + + for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end();) { + list::iterator tmp; + + tmp = i; + ++tmp; + + AudioRegion* ar = dynamic_cast(r); + if (ar && (*i)->crossfade.involves (*ar)) { + delete *i; + crossfade_views.erase (i); + } + + i = tmp; + } + + StreamView::remove_region_view(r); +} + +void +AudioStreamView::undisplay_diskstream () +{ + StreamView::undisplay_diskstream(); + + for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + delete *i; + } + + crossfade_views.clear (); +} + +void +AudioStreamView::playlist_modified () +{ + ENSURE_GUI_THREAD (mem_fun (*this, &AudioStreamView::playlist_modified)); + + StreamView::playlist_modified(); + + /* if the playlist is modified, make sure xfades are on top and all the regionviews are stacked + correctly. + */ + + for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + (*i)->get_canvas_group()->raise_to_top(); + } +} + +void +AudioStreamView::playlist_changed (Diskstream *ds) +{ + ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::playlist_changed), ds)); + + StreamView::playlist_changed(ds); + + AudioPlaylist* apl = dynamic_cast(ds->playlist()); + if (apl) + playlist_connections.push_back (apl->NewCrossfade.connect (mem_fun (*this, &AudioStreamView::add_crossfade))); +} + +void +AudioStreamView::add_crossfade (Crossfade *crossfade) +{ + AudioRegionView* lview = 0; + AudioRegionView* rview = 0; + + ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::add_crossfade), crossfade)); + + /* first see if we already have a CrossfadeView for this Crossfade */ + + for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + if (&(*i)->crossfade == crossfade) { + if (!crossfades_visible) { + (*i)->hide(); + } else { + (*i)->show (); + } + (*i)->set_valid (true); + return; + } + } + + /* create a new one */ + + for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { + AudioRegionView* arv = dynamic_cast(*i); + + if (!lview && arv && &(arv->region()) == &crossfade->out()) { + lview = arv; + } + if (!rview && arv && &(arv->region()) == &crossfade->in()) { + rview = arv; + } + } + + CrossfadeView *cv = new CrossfadeView (_trackview.canvas_display, + _trackview, + *crossfade, + _samples_per_unit, + region_color, + *lview, *rview); + + crossfade->Invalidated.connect (mem_fun (*this, &AudioStreamView::remove_crossfade)); + crossfade_views.push_back (cv); + + if (!crossfades_visible) { + cv->hide (); + } +} + +void +AudioStreamView::remove_crossfade (Crossfade *xfade) +{ + ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::remove_crossfade), xfade)); + + for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + if (&(*i)->crossfade == xfade) { + delete *i; + crossfade_views.erase (i); + break; + } + } +} + +void +AudioStreamView::redisplay_diskstream () +{ + list::iterator i, tmp; + list::iterator xi, tmpx; + + + for (i = region_views.begin(); i != region_views.end(); ++i) { + (*i)->set_valid (false); + } + + for (xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) { + (*xi)->set_valid (false); + if ((*xi)->visible()) { + (*xi)->show (); + } + } + + if (_trackview.is_audio_track()) { + _trackview.get_diskstream()->playlist()->foreach_region (static_cast(this), &StreamView::add_region_view); + AudioPlaylist* apl = dynamic_cast(_trackview.get_diskstream()->playlist()); + if (apl) + apl->foreach_crossfade (this, &AudioStreamView::add_crossfade); + } + + for (i = region_views.begin(); i != region_views.end(); ) { + tmp = i; + tmp++; + + if (!(*i)->is_valid()) { + delete *i; + region_views.erase (i); + } + + i = tmp; + } + + for (xi = crossfade_views.begin(); xi != crossfade_views.end();) { + tmpx = xi; + tmpx++; + + if (!(*xi)->valid()) { + delete *xi; + crossfade_views.erase (xi); + } + + xi = tmpx; + } + + /* now fix layering */ + + playlist_modified (); +} + +void +AudioStreamView::set_show_waveforms (bool yn) +{ + for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { + AudioRegionView* const arv = dynamic_cast(*i); + if (arv) + arv->set_waveform_visible (yn); + } +} + +void +AudioStreamView::set_waveform_shape (WaveformShape shape) +{ + for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { + AudioRegionView* const arv = dynamic_cast(*i); + if (arv) + arv->set_waveform_shape (shape); + } +} + +void +AudioStreamView::setup_rec_box () +{ + // cerr << _trackview.name() << " streamview SRB\n"; + + if (_trackview.session().transport_rolling()) { + + // cerr << "\trolling\n"; + + if (!rec_active && + _trackview.session().record_status() == Session::Recording && + _trackview.get_diskstream()->record_enabled()) { + + if (_trackview.audio_track()->mode() == Normal && use_rec_regions && rec_regions.size() == rec_rects.size()) { + + /* add a new region, but don't bother if they set use_rec_regions mid-record */ + + AudioRegion::SourceList sources; + + for (list::iterator prc = peak_ready_connections.begin(); prc != peak_ready_connections.end(); ++prc) { + (*prc).disconnect(); + } + peak_ready_connections.clear(); + + // FIXME + AudioDiskstream* ads = dynamic_cast(_trackview.get_diskstream()); + assert(ads); + + for (uint32_t n=0; n < ads->n_channels(); ++n) { + AudioSource *src = (AudioSource *) ads->write_source (n); + if (src) { + sources.push_back (src); + peak_ready_connections.push_back (src->PeakRangeReady.connect (bind (mem_fun (*this, &AudioStreamView::rec_peak_range_ready), src))); + } + } + + // handle multi + + jack_nframes_t start = 0; + if (rec_regions.size() > 0) { + start = rec_regions.back()->start() + _trackview.get_diskstream()->get_captured_frames(rec_regions.size()-1); + } + + AudioRegion * region = new AudioRegion(sources, start, 1 , "", 0, (Region::Flag)(Region::DefaultFlags | Region::DoNotSaveState), false); + region->set_position (_trackview.session().transport_frame(), this); + rec_regions.push_back (region); + /* catch it if it goes away */ + region->GoingAway.connect (mem_fun (*this, &AudioStreamView::remove_rec_region)); + + /* we add the region later */ + } + + /* start a new rec box */ + + AudioTrack* at; + + at = _trackview.audio_track(); /* we know what it is already */ + AudioDiskstream& ds = at->audio_diskstream(); + jack_nframes_t frame_pos = ds.current_capture_start (); + gdouble xstart = _trackview.editor.frame_to_pixel (frame_pos); + gdouble xend; + uint32_t fill_color; + + switch (_trackview.audio_track()->mode()) { + case Normal: + xend = xstart; + fill_color = color_map[cRecordingRectFill]; + break; + + case Destructive: + xend = xstart + 2; + fill_color = color_map[cRecordingRectFill]; + /* make the recording rect translucent to allow + the user to see the peak data coming in, etc. + */ + fill_color = UINT_RGBA_CHANGE_A (fill_color, 120); + break; + } + + ArdourCanvas::SimpleRect * rec_rect = new Gnome::Canvas::SimpleRect (*canvas_group); + rec_rect->property_x1() = xstart; + rec_rect->property_y1() = 1.0; + rec_rect->property_x2() = xend; + rec_rect->property_y2() = (double) _trackview.height - 1; + rec_rect->property_outline_color_rgba() = color_map[cRecordingRectOutline]; + rec_rect->property_fill_color_rgba() = fill_color; + + RecBoxInfo recbox; + recbox.rectangle = rec_rect; + recbox.start = _trackview.session().transport_frame(); + recbox.length = 0; + + rec_rects.push_back (recbox); + + screen_update_connection.disconnect(); + screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun (*this, &AudioStreamView::update_rec_box)); + rec_updating = true; + rec_active = true; + + } else if (rec_active && + (_trackview.session().record_status() != Session::Recording || + !_trackview.get_diskstream()->record_enabled())) { + + screen_update_connection.disconnect(); + rec_active = false; + rec_updating = false; + + } + + } else { + + // cerr << "\tNOT rolling, rec_rects = " << rec_rects.size() << " rec_regions = " << rec_regions.size() << endl; + + if (!rec_rects.empty() || !rec_regions.empty()) { + + /* disconnect rapid update */ + screen_update_connection.disconnect(); + + for (list::iterator prc = peak_ready_connections.begin(); prc != peak_ready_connections.end(); ++prc) { + (*prc).disconnect(); + } + peak_ready_connections.clear(); + + rec_updating = false; + rec_active = false; + last_rec_peak_frame = 0; + + /* remove temp regions */ + for (list::iterator iter=rec_regions.begin(); iter != rec_regions.end(); ) + { + list::iterator tmp; + + tmp = iter; + ++tmp; + + /* this will trigger the remove_region_view */ + delete *iter; + + iter = tmp; + } + + rec_regions.clear(); + + // cerr << "\tclear " << rec_rects.size() << " rec rects\n"; + + + /* transport stopped, clear boxes */ + for (vector::iterator iter=rec_rects.begin(); iter != rec_rects.end(); ++iter) { + RecBoxInfo &rect = (*iter); + delete rect.rectangle; + } + + rec_rects.clear(); + + } + } +} + +void +AudioStreamView::foreach_crossfadeview (void (CrossfadeView::*pmf)(void)) +{ + for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + ((*i)->*pmf) (); + } +} + +void +AudioStreamView::rec_peak_range_ready (jack_nframes_t start, jack_nframes_t cnt, Source * src) +{ + // this is called from the peak building thread + + ENSURE_GUI_THREAD(bind (mem_fun (*this, &AudioStreamView::rec_peak_range_ready), start, cnt, src)); + + if (rec_peak_ready_map.size() == 0 || start+cnt > last_rec_peak_frame) { + last_rec_peak_frame = start + cnt; + } + + rec_peak_ready_map[src] = true; + + if (rec_peak_ready_map.size() == _trackview.get_diskstream()->n_channels()) { + this->update_rec_regions (); + rec_peak_ready_map.clear(); + } +} + +void +AudioStreamView::update_rec_regions () +{ + if (use_rec_regions) { + + uint32_t n = 0; + + for (list::iterator iter = rec_regions.begin(); iter != rec_regions.end(); n++) { + + list::iterator tmp; + + tmp = iter; + ++tmp; + + if (!canvas_item_visible (rec_rects[n].rectangle)) { + /* rect already hidden, this region is done */ + iter = tmp; + continue; + } + + // FIXME + AudioRegion * region = dynamic_cast(*iter); + assert(region); + + jack_nframes_t origlen = region->length(); + + if (region == rec_regions.back() && rec_active) { + + if (last_rec_peak_frame > region->start()) { + + jack_nframes_t nlen = last_rec_peak_frame - region->start(); + + if (nlen != region->length()) { + + region->freeze (); + region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this); + region->set_length (nlen, this); + region->thaw ("updated"); + + if (origlen == 1) { + /* our special initial length */ + add_region_view_internal (region, false); + } + + /* also update rect */ + ArdourCanvas::SimpleRect * rect = rec_rects[n].rectangle; + gdouble xend = _trackview.editor.frame_to_pixel (region->position() + region->length()); + rect->property_x2() = xend; + } + } + + } else { + + jack_nframes_t nlen = _trackview.get_diskstream()->get_captured_frames(n); + + if (nlen != region->length()) { + + if (region->source(0).length() >= region->start() + nlen) { + + region->freeze (); + region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this); + region->set_length (nlen, this); + region->thaw ("updated"); + + if (origlen == 1) { + /* our special initial length */ + add_region_view_internal (region, false); + } + + /* also hide rect */ + ArdourCanvas::Item * rect = rec_rects[n].rectangle; + rect->hide(); + + } + } + } + + iter = tmp; + } + } +} + +void +AudioStreamView::show_all_xfades () +{ + foreach_crossfadeview (&CrossfadeView::show); + crossfades_visible = true; +} + +void +AudioStreamView::hide_all_xfades () +{ + foreach_crossfadeview (&CrossfadeView::hide); + crossfades_visible = false; +} + +void +AudioStreamView::hide_xfades_involving (AudioRegionView& rv) +{ + for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + if ((*i)->crossfade.involves (rv.audio_region())) { + (*i)->fake_hide (); + } + } +} + +void +AudioStreamView::reveal_xfades_involving (AudioRegionView& rv) +{ + for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + if ((*i)->crossfade.involves (rv.audio_region()) && (*i)->visible()) { + (*i)->show (); + } + } +} + +void +AudioStreamView::color_handler (ColorID id, uint32_t val) +{ + switch (id) { + case cAudioTrackBase: + if (_trackview.is_audio_track()) { + canvas_rect->property_fill_color_rgba() = val; + } + break; + case cAudioBusBase: + if (!_trackview.is_audio_track()) { + canvas_rect->property_fill_color_rgba() = val; + } + break; + case cAudioTrackOutline: + canvas_rect->property_outline_color_rgba() = val; + break; + + default: + break; + } +} diff --git a/gtk2_ardour/audio_streamview.h b/gtk2_ardour/audio_streamview.h new file mode 100644 index 0000000000..05ce8125f6 --- /dev/null +++ b/gtk2_ardour/audio_streamview.h @@ -0,0 +1,110 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. +*/ + +#ifndef __ardour_audio_streamview_h__ +#define __ardour_audio_streamview_h__ + +#include +#include +#include + +#include +#include "enums.h" +#include "simplerect.h" +#include "color.h" +#include "streamview.h" + +namespace Gdk { + class Color; +} + +namespace ARDOUR { + class Route; + class Diskstream; + class Crossfade; + class PeakData; + class AudioRegion; + class Source; +} + +class PublicEditor; +class Selectable; +class AudioTimeAxisView; +class AudioRegionView; +class RegionSelection; +class CrossfadeView; +class Selection; + +class AudioStreamView : public StreamView +{ + public: + AudioStreamView (AudioTimeAxisView&); + ~AudioStreamView (); + + void set_waveform_shape (WaveformShape); + + int set_height (gdouble h); + int set_samples_per_unit (gdouble spp); + + int set_amplitude_above_axis (gdouble app); + gdouble get_amplitude_above_axis () { return _amplitude_above_axis; } + + void set_show_waveforms (bool yn); + void set_show_waveforms_recording (bool yn) { use_rec_regions = yn; } + + void foreach_crossfadeview (void (CrossfadeView::*pmf)(void)); + + void show_all_xfades (); + void hide_all_xfades (); + void hide_xfades_involving (AudioRegionView&); + void reveal_xfades_involving (AudioRegionView&); + + private: + void setup_rec_box (); + void rec_peak_range_ready (jack_nframes_t start, jack_nframes_t cnt, ARDOUR::Source* src); + void update_rec_regions (); + + void add_region_view_internal (ARDOUR::Region*, bool wait_for_waves); + void remove_region_view (ARDOUR::Region* ); + void remove_audio_region_view (ARDOUR::AudioRegion* ); + void remove_audio_rec_region (ARDOUR::AudioRegion*); + + void undisplay_diskstream (); + void redisplay_diskstream (); + void playlist_modified (); + void playlist_changed (ARDOUR::Diskstream *ds); + + 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; + bool crossfades_visible; + + list peak_ready_connections; + jack_nframes_t last_rec_peak_frame; + map rec_peak_ready_map; + +}; + +#endif /* __ardour_audio_streamview_h__ */ diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc index 5f6d29f9ff..376e05aa4c 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 @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -40,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -52,27 +52,20 @@ #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 "regionview.h" -#include "rgb_macros.h" -#include "selection.h" +#include "audio_region_view.h" #include "simplerect.h" -#include "streamview.h" +#include "audio_streamview.h" #include "utils.h" #include @@ -81,39 +74,25 @@ using namespace ARDOUR; using namespace PBD; -using namespace LADSPA; using namespace Gtk; using namespace Editing; AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr rt, Canvas& canvas) - : AxisView(sess), - RouteUI(rt, sess, _("m"), _("s"), _("r")), // mute, solo, and record - TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas), - parent_canvas (canvas), - button_table (3, 3), - edit_group_button (_("g")), // group - playlist_button (_("p")), - size_button (_("h")), // height - automation_button (_("a")), - visual_button (_("v")) - + : AxisView(sess) + , RouteTimeAxisView(ed, sess, rt, canvas) { - _has_state = true; + // Make sure things are sane... + assert(!is_track() || is_audio_track()); + subplugin_menu.set_name ("ArdourContextMenu"); - playlist_menu = 0; - playlist_action_menu = 0; - automation_action_menu = 0; gain_track = 0; pan_track = 0; - view = 0; - timestretch_rect = 0; waveform_item = 0; pan_automation_item = 0; gain_automation_item = 0; - no_redraw = false; - view = new StreamView (*this); + _view = new AudioStreamView (*this); add_gain_automation_child (); add_pan_automation_child (); @@ -123,161 +102,48 @@ AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::sh mute_button->set_active (false); solo_button->set_active (false); - mute_button->set_name ("TrackMuteButton"); - solo_button->set_name ("SoloButton"); - edit_group_button.set_name ("TrackGroupButton"); - playlist_button.set_name ("TrackPlaylistButton"); - automation_button.set_name ("TrackAutomationButton"); - size_button.set_name ("TrackSizeButton"); - visual_button.set_name ("TrackVisualButton"); - hide_button.set_name ("TrackRemoveButton"); - - hide_button.add (*(manage (new Image (get_xpm("small_x.xpm"))))); - - solo_button->signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - mute_button->signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - playlist_button.signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - automation_button.signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - size_button.signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - visual_button.signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - hide_button.signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - - solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false); - solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release), false); - mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false); - mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false); - edit_group_button.signal_button_release_event().connect (mem_fun(*this, &AudioTimeAxisView::edit_click), false); - playlist_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::playlist_click)); - automation_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::automation_click)); - size_button.signal_button_release_event().connect (mem_fun(*this, &AudioTimeAxisView::size_click), false); - visual_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::visual_click)); - hide_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::hide_click)); - - if (is_audio_track()) { - rec_enable_button->set_active (false); - rec_enable_button->set_name ("TrackRecordEnableButton"); - rec_enable_button->signal_button_press_event().connect (mem_fun (*this, &AudioTimeAxisView::select_me), false); - rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press)); - controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); - ARDOUR_UI::instance()->tooltips().set_tip(*rec_enable_button, _("Record")); - } - - controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); - controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::FILL|Gtk::EXPAND, 0, 0); - - controls_table.attach (edit_group_button, 6, 7, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); - - ARDOUR_UI::instance()->tooltips().set_tip(*solo_button,_("Solo")); - ARDOUR_UI::instance()->tooltips().set_tip(*mute_button,_("Mute")); - ARDOUR_UI::instance()->tooltips().set_tip(edit_group_button,_("Edit Group")); - ARDOUR_UI::instance()->tooltips().set_tip(size_button,_("Display Height")); - ARDOUR_UI::instance()->tooltips().set_tip(playlist_button,_("Playlist")); - ARDOUR_UI::instance()->tooltips().set_tip(automation_button, _("Automation")); - ARDOUR_UI::instance()->tooltips().set_tip(visual_button, _("Visual options")); - ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("Hide this track")); - - label_view (); - - controls_table.attach (hide_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.attach (visual_button, 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.attach (size_button, 2, 3, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - controls_table.attach (automation_button, 3, 4, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - - if (is_audio_track() && audio_track()->mode() == ARDOUR::Normal) { - controls_table.attach (playlist_button, 5, 6, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); - } - - /* remove focus from the buttons */ - - automation_button.unset_flags (Gtk::CAN_FOCUS); - solo_button->unset_flags (Gtk::CAN_FOCUS); - mute_button->unset_flags (Gtk::CAN_FOCUS); - edit_group_button.unset_flags (Gtk::CAN_FOCUS); - size_button.unset_flags (Gtk::CAN_FOCUS); - playlist_button.unset_flags (Gtk::CAN_FOCUS); - hide_button.unset_flags (Gtk::CAN_FOCUS); - visual_button.unset_flags (Gtk::CAN_FOCUS); + if (is_audio_track()) + controls_ebox.set_name ("AudioTimeAxisViewControlsBaseUnselected"); + else // bus + controls_ebox.set_name ("AudioBusControlsBaseUnselected"); /* map current state of the route */ - update_diskstream_display (); - solo_changed(0); - mute_changed(0); redirects_changed (0); reset_redirect_automation_curves (); - y_position = -1; ensure_xml_node (); set_state (*xml_node); - _route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)); - _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); - _route->redirects_changed.connect (mem_fun(*this, &AudioTimeAxisView::redirects_changed)); - _route->name_changed.connect (mem_fun(*this, &AudioTimeAxisView::route_name_changed)); - _route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); _route->panner().Changed.connect (mem_fun(*this, &AudioTimeAxisView::update_pans)); if (is_audio_track()) { - /* track */ - - audio_track()->FreezeChange.connect (mem_fun(*this, &AudioTimeAxisView::map_frozen)); - - audio_track()->diskstream_changed.connect (mem_fun(*this, &AudioTimeAxisView::diskstream_changed)); - get_diskstream()->speed_changed.connect (mem_fun(*this, &AudioTimeAxisView::speed_changed)); - controls_ebox.set_name ("AudioTrackControlsBaseUnselected"); controls_base_selected_name = "AudioTrackControlsBaseSelected"; controls_base_unselected_name = "AudioTrackControlsBaseUnselected"; /* ask for notifications of any new RegionViews */ + _view->RegionViewAdded.connect (mem_fun(*this, &AudioTimeAxisView::region_view_added)); + _view->attach (); - view->AudioRegionViewAdded.connect (mem_fun(*this, &AudioTimeAxisView::region_view_added)); - - view->attach (); - - /* pick up the correct freeze state */ - - map_frozen (); - - } else { - - /* bus */ + } else { /* bus */ - controls_ebox.set_name ("BusControlsBaseUnselected"); - controls_base_selected_name = "BusControlsBaseSelected"; - controls_base_unselected_name = "BusControlsBaseUnselected"; + controls_ebox.set_name ("AudioBusControlsBaseUnselected"); + controls_base_selected_name = "AudioBusControlsBaseSelected"; + controls_base_unselected_name = "AudioBusControlsBaseUnselected"; } - - editor.ZoomChanged.connect (mem_fun(*this, &AudioTimeAxisView::reset_samples_per_unit)); - ColorChanged.connect (mem_fun (*this, &AudioTimeAxisView::color_handler)); } AudioTimeAxisView::~AudioTimeAxisView () { - GoingAway (); /* EMIT_SIGNAL */ - - if (playlist_menu) { - delete playlist_menu; - playlist_menu = 0; - } - - if (playlist_action_menu) { - delete playlist_action_menu; - playlist_action_menu = 0; - } - - vector_delete (&redirect_automation_curves); - - for (list::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) { - delete *i; - } +} - if (view) { - delete view; - view = 0; - } +AudioStreamView* +AudioTimeAxisView::audio_view() +{ + return dynamic_cast(_view); } guint32 @@ -298,233 +164,6 @@ AudioTimeAxisView::hide () TimeAxisView::hide (); } -void -AudioTimeAxisView::set_playlist (AudioPlaylist *newplaylist) -{ - AudioPlaylist *pl; - - modified_connection.disconnect (); - state_changed_connection.disconnect (); - - if ((pl = dynamic_cast (playlist())) != 0) { - state_changed_connection = pl->StateChanged.connect (mem_fun(*this, &AudioTimeAxisView::playlist_state_changed)); - modified_connection = pl->Modified.connect (mem_fun(*this, &AudioTimeAxisView::playlist_modified)); - } -} - -void -AudioTimeAxisView::playlist_modified () -{ -} - -gint -AudioTimeAxisView::edit_click (GdkEventButton *ev) -{ - if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { - _route->set_edit_group (0, this); - return FALSE; - } - - using namespace Menu_Helpers; - - MenuList& items = edit_group_menu.items (); - RadioMenuItem::Group group; - - items.clear (); - items.push_back (RadioMenuElem (group, _("No group"), - bind (mem_fun(*this, &AudioTimeAxisView::set_edit_group_from_menu), (RouteGroup *) 0))); - - if (_route->edit_group() == 0) { - static_cast(&items.back())->set_active (); - } - - _session.foreach_edit_group (bind (mem_fun (*this, &AudioTimeAxisView::add_edit_group_menu_item), &group)); - edit_group_menu.popup (ev->button, ev->time); - - return FALSE; -} - -void -AudioTimeAxisView::add_edit_group_menu_item (RouteGroup *eg, RadioMenuItem::Group* group) -{ - using namespace Menu_Helpers; - - MenuList &items = edit_group_menu.items(); - - cerr << "adding edit group called " << eg->name() << endl; - - items.push_back (RadioMenuElem (*group, eg->name(), bind (mem_fun(*this, &AudioTimeAxisView::set_edit_group_from_menu), eg))); - if (_route->edit_group() == eg) { - static_cast(&items.back())->set_active (); - } -} - -void -AudioTimeAxisView::set_edit_group_from_menu (RouteGroup *eg) - -{ - _route->set_edit_group (eg, this); -} - -void -AudioTimeAxisView::playlist_state_changed (Change ignored) -{ - // ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioTimeAxisView::playlist_state_changed), ignored)); - // why are we here ? -} - -void -AudioTimeAxisView::playlist_changed () - -{ - label_view (); - - if (is_audio_track()) { - set_playlist (get_diskstream()->playlist()); - } -} - -void -AudioTimeAxisView::label_view () -{ - string x = _route->name(); - - if (x != name_entry.get_text()) { - name_entry.set_text (x); - } - - ARDOUR_UI::instance()->tooltips().set_tip (name_entry, x); -} - -void -AudioTimeAxisView::route_name_changed (void *src) -{ - editor.route_name_changed (this); - label_view (); -} - -void -AudioTimeAxisView::take_name_changed (void *src) - -{ - if (src != this) { - label_view (); - } -} - -void -AudioTimeAxisView::playlist_click () -{ - // always build a new action menu - - if (playlist_action_menu == 0) { - playlist_action_menu = new Menu; - playlist_action_menu->set_name ("ArdourContextMenu"); - } - - build_playlist_menu(playlist_action_menu); - - playlist_action_menu->popup (1, 0); -} - -void -AudioTimeAxisView::automation_click () -{ - if (automation_action_menu == 0) { - /* this seems odd, but the automation action - menu is built as part of the display menu. - */ - build_display_menu (); - } - automation_action_menu->popup (1, 0); -} - -void -AudioTimeAxisView::show_timestretch (jack_nframes_t start, jack_nframes_t end) -{ - double x1; - double x2; - double y2; - - TimeAxisView::show_timestretch (start, end); - - hide_timestretch (); - -#if 0 - if (ts.empty()) { - return; - } - - - /* check that the time selection was made in our route, or our edit group. - remember that edit_group() == 0 implies the route is *not* in a edit group. - */ - - if (!(ts.track == this || (ts.group != 0 && ts.group == _route->edit_group()))) { - /* this doesn't apply to us */ - return; - } - - /* ignore it if our edit group is not active */ - - if ((ts.track != this) && _route->edit_group() && !_route->edit_group()->is_active()) { - return; - } -#endif - - if (timestretch_rect == 0) { - timestretch_rect = new SimpleRect (*canvas_display); - timestretch_rect->property_x1() = 0.0; - timestretch_rect->property_y1() = 0.0; - timestretch_rect->property_x2() = 0.0; - timestretch_rect->property_y2() = 0.0; - timestretch_rect->property_fill_color_rgba() = color_map[cTimeStretchFill]; - timestretch_rect->property_outline_color_rgba() = color_map[cTimeStretchOutline]; - } - - timestretch_rect->show (); - timestretch_rect->raise_to_top (); - - x1 = start / editor.get_current_zoom(); - x2 = (end - 1) / editor.get_current_zoom(); - y2 = height - 2; - - timestretch_rect->property_x1() = x1; - timestretch_rect->property_y1() = 1.0; - timestretch_rect->property_x2() = x2; - timestretch_rect->property_y2() = y2; -} - -void -AudioTimeAxisView::hide_timestretch () -{ - TimeAxisView::hide_timestretch (); - - if (timestretch_rect) { - timestretch_rect->hide (); - } -} - -void -AudioTimeAxisView::show_selection (TimeSelection& ts) -{ - -#if 0 - /* ignore it if our edit group is not active or if the selection was started - in some other track or edit group (remember that edit_group() == 0 means - that the track is not in an edit group). - */ - - if (((ts.track != this && !is_child (ts.track)) && _route->edit_group() && !_route->edit_group()->is_active()) || - (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->edit_group())))) { - hide_selection (); - return; - } -#endif - - TimeAxisView::show_selection (ts); -} - void AudioTimeAxisView::set_state (const XMLNode& node) { @@ -578,153 +217,14 @@ AudioTimeAxisView::set_state (const XMLNode& node) } void -AudioTimeAxisView::set_height (TrackHeight h) -{ - bool height_changed = (height == 0) || (h != height_style); - - TimeAxisView::set_height (h); - - ensure_xml_node (); - - view->set_height ((double) height); - - switch (height_style) { - case Largest: - xml_node->add_property ("track_height", "largest"); - show_name_entry (); - hide_name_label (); - controls_table.show_all(); - break; - case Large: - xml_node->add_property ("track_height", "large"); - show_name_entry (); - hide_name_label (); - controls_table.show_all(); - break; - case Larger: - xml_node->add_property ("track_height", "larger"); - show_name_entry (); - hide_name_label (); - controls_table.show_all(); - break; - case Normal: - xml_node->add_property ("track_height", "normal"); - show_name_entry (); - hide_name_label (); - controls_table.show_all(); - break; - case Smaller: - xml_node->add_property ("track_height", "smaller"); - controls_table.show_all (); - show_name_entry (); - hide_name_label (); - edit_group_button.hide (); - hide_button.hide (); - visual_button.hide (); - size_button.hide (); - automation_button.hide (); - playlist_button.hide (); - break; - case Small: - xml_node->add_property ("track_height", "small"); - controls_table.hide_all (); - controls_table.show (); - hide_name_entry (); - show_name_label (); - name_label.set_text (_route->name()); - break; - } - - if (height_changed) { - /* only emit the signal if the height really changed */ - _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ - } -} - -void -AudioTimeAxisView::select_track_color () -{ - if (RouteUI::choose_color ()) { - - if (view) { - view->apply_color (_color, StreamView::RegionColor); - } - } -} - -void -AudioTimeAxisView::reset_redirect_automation_curves () -{ - for (vector::iterator i = redirect_automation_curves.begin(); i != redirect_automation_curves.end(); ++i) { - (*i)->reset(); - } -} - -void -AudioTimeAxisView::reset_samples_per_unit () -{ - set_samples_per_unit (editor.get_current_zoom()); -} - -void -AudioTimeAxisView::set_samples_per_unit (double spu) -{ - double speed = 1.0; - - if (get_diskstream() != 0) { - speed = get_diskstream()->speed(); - } - - if (view) { - view->set_samples_per_unit (spu * speed); - } - - TimeAxisView::set_samples_per_unit (spu * speed); -} - -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))); - + RouteTimeAxisView::build_automation_action_menu (); - 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)); - - 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"), @@ -736,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); + +} + +void +AudioTimeAxisView::append_extra_display_menu_items () +{ + using namespace Menu_Helpers; - automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu)); + MenuList& items = display_menu->items(); - items.push_back (MenuElem (_("Automation"), *automation_action_menu)); + // 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"); @@ -760,399 +270,53 @@ 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 -AudioTimeAxisView::align_style_changed () -{ - switch (get_diskstream()->alignment_style()) { - case ExistingMaterial: - if (!align_existing_item->get_active()) { - align_existing_item->set_active(); - } - break; - case CaptureTime: - if (!align_capture_item->get_active()) { - align_capture_item->set_active(); - } - break; - } -} - -void -AudioTimeAxisView::set_align_style (AlignStyle style) -{ - get_diskstream()->set_align_style (style); -} - -void -AudioTimeAxisView::rename_current_playlist () -{ - ArdourPrompter prompter (true); - string name; - - AudioPlaylist *pl; - AudioDiskstream *ds; - - if (((ds = get_diskstream()) == 0) || ds->destructive() || ((pl = ds->playlist()) == 0)) { - return; - } - - prompter.set_prompt (_("Name for playlist")); - prompter.set_initial_text (pl->name()); - prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT); - prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); - - switch (prompter.run ()) { - case Gtk::RESPONSE_ACCEPT: - prompter.get_result (name); - if (name.length()) { - pl->set_name (name); - } - break; - - default: - break; - } -} - -void -AudioTimeAxisView::use_copy_playlist (bool prompt) -{ - AudioPlaylist *pl; - AudioDiskstream *ds; - string name; - - if (((ds = get_diskstream()) == 0) || ds->destructive() || ((pl = ds->playlist()) == 0)) { - return; - } - - name = Playlist::bump_name (pl->name(), _session); - - if (prompt) { - - ArdourPrompter prompter (true); - - prompter.set_prompt (_("Name for Playlist")); - prompter.set_initial_text (name); - prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT); - prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); - prompter.show_all (); - - switch (prompter.run ()) { - case Gtk::RESPONSE_ACCEPT: - prompter.get_result (name); - break; - - default: - return; - } - } - - if (name.length()) { - ds->use_copy_playlist (); - pl = ds->playlist(); - pl->set_name (name); - } -} - -void -AudioTimeAxisView::use_new_playlist (bool prompt) -{ - AudioPlaylist *pl; - AudioDiskstream *ds; - string name; - - if (((ds = get_diskstream()) == 0) || ds->destructive() || ((pl = ds->playlist()) == 0)) { - return; - } - - name = Playlist::bump_name (pl->name(), _session); - - if (prompt) { - - ArdourPrompter prompter (true); - - prompter.set_prompt (_("Name for Playlist")); - prompter.set_initial_text (name); - prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT); - prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); - - switch (prompter.run ()) { - case Gtk::RESPONSE_ACCEPT: - prompter.get_result (name); - break; - - default: - return; - } - } - - if (name.length()) { - ds->use_new_playlist (); - pl = ds->playlist(); - pl->set_name (name); - } -} - -void -AudioTimeAxisView::clear_playlist () -{ - AudioPlaylist *pl; - AudioDiskstream *ds; - - if ((ds = get_diskstream()) != 0) { - if ((pl = ds->playlist()) != 0) { - editor.clear_playlist (*pl); - } - } } void AudioTimeAxisView::toggle_waveforms () { - if (view && waveform_item && !ignore_toggle) { - view->set_show_waveforms (waveform_item->get_active()); + AudioStreamView* asv = audio_view(); + assert(asv); + + if (asv && waveform_item && !ignore_toggle) { + asv->set_show_waveforms (waveform_item->get_active()); } } void AudioTimeAxisView::set_show_waveforms (bool yn) { + AudioStreamView* asv = audio_view(); + assert(asv); + if (waveform_item) { waveform_item->set_active (yn); } else { - view->set_show_waveforms (yn); + asv->set_show_waveforms (yn); } } void AudioTimeAxisView::set_show_waveforms_recording (bool yn) { - if (view) { - view->set_show_waveforms_recording (yn); - } -} - -void -AudioTimeAxisView::set_waveform_shape (WaveformShape shape) -{ - if (view) { - view->set_waveform_shape (shape); - } -} - -void -AudioTimeAxisView::speed_changed () -{ - Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &AudioTimeAxisView::reset_samples_per_unit)); -} - -void -AudioTimeAxisView::diskstream_changed (void *src) -{ - Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &AudioTimeAxisView::update_diskstream_display)); -} - -void -AudioTimeAxisView::update_diskstream_display () -{ - AudioDiskstream *ds; - - if ((ds = get_diskstream()) != 0) { - set_playlist (ds->playlist ()); - } - - map_frozen (); -} - -void -AudioTimeAxisView::selection_click (GdkEventButton* ev) -{ - PublicEditor::TrackViewList* tracks = editor.get_valid_views (this, _route->edit_group()); - - switch (Keyboard::selection_type (ev->state)) { - case Selection::Toggle: - /* XXX this is not right */ - editor.get_selection().add (*tracks); - break; - - case Selection::Set: - editor.get_selection().set (*tracks); - break; - - case Selection::Extend: - /* not defined yet */ - break; - } - - delete tracks; -} - -void -AudioTimeAxisView::set_selected_regionviews (AudioRegionSelection& regions) -{ - if (view) { - view->set_selected_regionviews (regions); - } -} - -void -AudioTimeAxisView::set_selected_points (PointSelection& points) -{ - for (vector::iterator i = children.begin(); i != children.end(); ++i) { - (*i)->set_selected_points (points); - } -} - -void -AudioTimeAxisView::get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list& results) -{ - double speed = 1.0; - - if (get_diskstream() != 0) { - speed = get_diskstream()->speed(); - } - - jack_nframes_t start_adjusted = session_frame_to_track_frame(start, speed); - jack_nframes_t end_adjusted = session_frame_to_track_frame(end, speed); - - if (view && ((top < 0.0 && bot < 0.0)) || touched (top, bot)) { - view->get_selectables (start_adjusted, end_adjusted, results); - } - - /* pick up visible automation tracks */ - - for (vector::iterator i = children.begin(); i != children.end(); ++i) { - if (!(*i)->hidden()) { - (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results); - } - } -} - -void -AudioTimeAxisView::get_inverted_selectables (Selection& sel, list& results) -{ - if (view) { - view->get_inverted_selectables (sel, results); - } - - for (vector::iterator i = children.begin(); i != children.end(); ++i) { - if (!(*i)->hidden()) { - (*i)->get_inverted_selectables (sel, results); - } - } - - return; -} - -RouteGroup* -AudioTimeAxisView::edit_group() const -{ - return _route->edit_group(); -} - -string -AudioTimeAxisView::name() const -{ - return _route->name(); -} - -Playlist * -AudioTimeAxisView::playlist () const -{ - AudioDiskstream *ds; - - if ((ds = get_diskstream()) != 0) { - return ds->playlist(); - } else { - return 0; - } -} - -void -AudioTimeAxisView::name_entry_changed () -{ - string x; - - x = name_entry.get_text (); - - if (x == _route->name()) { - return; - } + AudioStreamView* asv = audio_view(); - if (x.length() == 0) { - name_entry.set_text (_route->name()); - return; - } - - strip_whitespace_edges(x); - - if (_session.route_name_unique (x)) { - _route->set_name (x, this); - } else { - ARDOUR_UI::instance()->popup_error (_("a track already exists with that name")); - name_entry.set_text (_route->name()); + if (asv) { + asv->set_show_waveforms_recording (yn); } } void -AudioTimeAxisView::visual_click () -{ - popup_display_menu (0); -} - -void -AudioTimeAxisView::hide_click () -{ - editor.hide_track_in_display (*this); -} - -Region* -AudioTimeAxisView::find_next_region (jack_nframes_t pos, RegionPoint point, int32_t dir) +AudioTimeAxisView::set_waveform_shape (WaveformShape shape) { - AudioDiskstream *stream; - AudioPlaylist *playlist; + AudioStreamView* asv = audio_view(); - if ((stream = get_diskstream()) != 0 && (playlist = stream->playlist()) != 0) { - return playlist->find_next_region (pos, point, dir); + if (asv) { + asv->set_waveform_shape (shape); } - return 0; -} + map_frozen (); +} void AudioTimeAxisView::add_gain_automation_child () @@ -1338,321 +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; -} - -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); - - 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 () { @@ -1661,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; @@ -1684,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; @@ -1705,230 +540,58 @@ 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 */ } -bool -AudioTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) -{ - Playlist* what_we_got; - AudioDiskstream* ds = get_diskstream(); - Playlist* playlist; - bool ret = false; - - if (ds == 0) { - /* route is a bus, not a track */ - return false; - } - - playlist = ds->playlist(); - - - TimeSelection time (selection.time); - float speed = ds->speed(); - if (speed != 1.0f) { - for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) { - (*i).start = session_frame_to_track_frame((*i).start, speed); - (*i).end = session_frame_to_track_frame((*i).end, speed); - } - } - - switch (op) { - case Cut: - _session.add_undo (playlist->get_memento()); - if ((what_we_got = playlist->cut (time)) != 0) { - editor.get_cut_buffer().add (what_we_got); - _session.add_redo_no_execute (playlist->get_memento()); - ret = true; - } - break; - case Copy: - if ((what_we_got = playlist->copy (time)) != 0) { - editor.get_cut_buffer().add (what_we_got); - } - break; - - case Clear: - _session.add_undo (playlist->get_memento()); - if ((what_we_got = playlist->cut (time)) != 0) { - _session.add_redo_no_execute (playlist->get_memento()); - what_we_got->unref (); - ret = true; - } - break; - } - - return ret; -} - -bool -AudioTimeAxisView::paste (jack_nframes_t pos, float times, Selection& selection, size_t nth) -{ - if (!is_audio_track()) { - return false; - } - - Playlist* playlist = get_diskstream()->playlist(); - PlaylistSelection::iterator p; - - for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth); - - if (p == selection.playlists.end()) { - return false; - } - - if (get_diskstream()->speed() != 1.0f) - pos = session_frame_to_track_frame(pos, get_diskstream()->speed() ); - - _session.add_undo (playlist->get_memento()); - playlist->paste (**p, pos, times); - _session.add_redo_no_execute (playlist->get_memento()); - - return true; -} - -void -AudioTimeAxisView::region_view_added (AudioRegionView* arv) -{ - for (vector::iterator i = children.begin(); i != children.end(); ++i) { - AutomationTimeAxisView* atv; - - if ((atv = dynamic_cast (*i)) != 0) { - arv->add_ghost (*atv); - } - } -} - -void -AudioTimeAxisView::add_ghost_to_redirect (AudioRegionView* arv, AutomationTimeAxisView* atv) -{ - arv->add_ghost (*atv); -} - -list -AudioTimeAxisView::get_child_list() -{ - - listredirect_children; - - for (vector::iterator i = children.begin(); i != children.end(); ++i) { - if (!(*i)->hidden()) { - redirect_children.push_back(*i); - } - } - return redirect_children; -} - - -void -AudioTimeAxisView::build_playlist_menu (Gtk::Menu * menu) -{ - using namespace Menu_Helpers; - - if (!menu || !is_audio_track()) { - return; - } - - MenuList& playlist_items = menu->items(); - menu->set_name ("ArdourContextMenu"); - playlist_items.clear(); - - if (playlist_menu) { - delete playlist_menu; - } - playlist_menu = new Menu; - playlist_menu->set_name ("ArdourContextMenu"); - - playlist_items.push_back (MenuElem (string_compose (_("Current: %1"), get_diskstream()->playlist()->name()))); - playlist_items.push_back (SeparatorElem()); - - playlist_items.push_back (MenuElem (_("Rename"), mem_fun(*this, &AudioTimeAxisView::rename_current_playlist))); - playlist_items.push_back (SeparatorElem()); - - playlist_items.push_back (MenuElem (_("New"), mem_fun(editor, &PublicEditor::new_playlists))); - playlist_items.push_back (MenuElem (_("New Copy"), mem_fun(editor, &PublicEditor::copy_playlists))); - playlist_items.push_back (SeparatorElem()); - playlist_items.push_back (MenuElem (_("Clear Current"), mem_fun(editor, &PublicEditor::clear_playlists))); - playlist_items.push_back (SeparatorElem()); - playlist_items.push_back (MenuElem(_("Select"), mem_fun(*this, &AudioTimeAxisView::show_playlist_selector))); - -} - -void -AudioTimeAxisView::show_playlist_selector () -{ - editor.playlist_selector().show_for (this); -} - - -void -AudioTimeAxisView::map_frozen () -{ - if (!is_audio_track()) { - return; - } - - ENSURE_GUI_THREAD (mem_fun(*this, &AudioTimeAxisView::map_frozen)); - - switch (audio_track()->freeze_state()) { - case AudioTrack::Frozen: - playlist_button.set_sensitive (false); - rec_enable_button->set_sensitive (false); - break; - default: - playlist_button.set_sensitive (true); - rec_enable_button->set_sensitive (true); - break; - } -} - void AudioTimeAxisView::show_all_xfades () { - if (view) { - view->show_all_xfades (); + AudioStreamView* asv = audio_view(); + + if (asv) { + asv->show_all_xfades (); } } void AudioTimeAxisView::hide_all_xfades () { - if (view) { - view->hide_all_xfades (); + AudioStreamView* asv = audio_view(); + + if (asv) { + asv->hide_all_xfades (); } } void AudioTimeAxisView::hide_dependent_views (TimeAxisViewItem& tavi) { + AudioStreamView* asv = audio_view(); AudioRegionView* rv; - if (view && (rv = dynamic_cast(&tavi)) != 0) { - view->hide_xfades_involving (*rv); + if (asv && (rv = dynamic_cast(&tavi)) != 0) { + asv->hide_xfades_involving (*rv); } } void AudioTimeAxisView::reveal_dependent_views (TimeAxisViewItem& tavi) { + AudioStreamView* asv = audio_view(); AudioRegionView* rv; - if (view && (rv = dynamic_cast(&tavi)) != 0) { - view->reveal_xfades_involving (*rv); + if (asv && (rv = dynamic_cast(&tavi)) != 0) { + asv->reveal_xfades_involving (*rv); } } void AudioTimeAxisView::route_active_changed () { - RouteUI::route_active_changed (); + RouteTimeAxisView::route_active_changed (); if (is_audio_track()) { if (_route->active()) { @@ -1959,24 +622,3 @@ AudioTimeAxisView::get_child_xml_node (const string & childname) return RouteUI::get_child_xml_node (childname); } -void -AudioTimeAxisView::color_handler (ColorID id, uint32_t val) -{ - switch (id) { - case cTimeStretchOutline: - timestretch_rect->property_outline_color_rgba() = val; - break; - case cTimeStretchFill: - timestretch_rect->property_fill_color_rgba() = val; - break; - default: - break; - } -} - -bool -AudioTimeAxisView::select_me (GdkEventButton* ev) -{ - editor.get_selection().add (this); - return false; -} diff --git a/gtk2_ardour/audio_time_axis.h b/gtk2_ardour/audio_time_axis.h index 8a7cf4f9a2..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 @@ -18,8 +18,8 @@ $Id$ */ -#ifndef __ardour_trackview_h__ -#define __ardour_trackview_h__ +#ifndef __ardour_audio_time_axis_h__ +#define __ardour_audio_time_axis_h__ #include #include @@ -33,19 +33,14 @@ #include #include -#include #include "ardour_dialog.h" #include "route_ui.h" #include "enums.h" -#include "time_axis_view.h" +#include "route_time_axis.h" #include "canvas.h" #include "color.h" -namespace ALSA { - class MultiChannelDevice; -} - namespace ARDOUR { class Session; class AudioDiskstream; @@ -56,247 +51,58 @@ namespace ARDOUR { class AudioPlaylist; } -namespace LADSPA { - class Manager; - class Plugin; -} - class PublicEditor; class AudioThing; -class StreamView; +class AudioStreamView; class Selection; class Selectable; +class RegionView; class AudioRegionView; class AutomationLine; class AutomationGainLine; class AutomationPanLine; -class RedirectAutomationLine; class TimeSelection; class AutomationTimeAxisView; -class AudioTimeAxisView : public RouteUI, public TimeAxisView +class AudioTimeAxisView : public RouteTimeAxisView { public: AudioTimeAxisView (PublicEditor&, ARDOUR::Session&, boost::shared_ptr, ArdourCanvas::Canvas& canvas); virtual ~AudioTimeAxisView (); + + AudioStreamView* audio_view(); - void show_selection (TimeSelection&); - void automation_control_point_changed (ARDOUR::AutomationType); - - void set_samples_per_unit (double); - void set_height (TimeAxisView::TrackHeight); void set_show_waveforms (bool yn); void set_show_waveforms_recording (bool yn); - void show_timestretch (jack_nframes_t start, jack_nframes_t end); - void hide_timestretch (); - void selection_click (GdkEventButton*); - void set_selected_regionviews (AudioRegionSelection&); - void set_selected_points (PointSelection&); - void get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list&); - void get_inverted_selectables (Selection&, list&); void show_all_xfades (); void hide_all_xfades (); void hide_dependent_views (TimeAxisViewItem&); void reveal_dependent_views (TimeAxisViewItem&); - 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; - - /* 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 (); - /* need accessors/mutators */ - - StreamView *view; - - /* editing operations */ - - bool cut_copy_clear (Selection&, Editing::CutCopyOp); - bool paste (jack_nframes_t, float times, Selection&, size_t nth); - - listget_child_list(); - void set_state (const XMLNode&); XMLNode* get_child_xml_node (const string & childname); - /* 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 (); - private: - friend class StreamView; + friend class AudioStreamView; friend class AudioRegionView; - - ArdourCanvas::Canvas& parent_canvas; - - bool no_redraw; - - AutomationTimeAxisView *gain_track; - AutomationTimeAxisView *pan_track; - - void update_automation_view (ARDOUR::AutomationType); - void reset_redirect_automation_curves (); - - 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; - - void route_active_changed (); - - void diskstream_changed (void *src); - void update_diskstream_display (); - gint edit_click (GdkEventButton *); - - // variables to get the context menu - // automation buttons correctly initialized - bool show_gain_automation; - bool show_pan_automation; - - void build_redirect_window (); - void redirect_click (); - void redirect_add (); - void redirect_remove (); - void redirect_edit (); - void redirect_relist (); - void redirect_row_selected (gint row, gint col, GdkEvent *ev); - void add_to_redirect_display (boost::shared_ptr); - void redirects_changed (void *); - - sigc::connection modified_connection; - sigc::connection state_changed_connection; - - void take_name_changed (void *); - void route_name_changed (void *); - void name_entry_changed (); - - 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 *); - - void reset_samples_per_unit (); + void route_active_changed (); - void select_track_color(); + void build_automation_action_menu (); + void append_extra_display_menu_items (); - virtual void build_display_menu (); - - Gtk::CheckMenuItem* waveform_item; - Gtk::RadioMenuItem* traditional_item; - Gtk::RadioMenuItem* rectified_item; - - Gtk::RadioMenuItem* align_existing_item; - Gtk::RadioMenuItem* align_capture_item; - - void align_style_changed (); - void set_align_style (ARDOUR::AlignStyle); - void toggle_show_waveforms (); - void set_waveform_shape (WaveformShape); void toggle_waveforms (); - Gtk::Menu *playlist_menu; - Gtk::Menu *playlist_action_menu; - Gtk::MenuItem *playlist_item; - - /* playlist */ - - void set_playlist (ARDOUR::AudioPlaylist *); - 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 (); - - /* 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 (); + void hide_all_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); - - ArdourCanvas::SimpleRect *timestretch_rect; - - void timestretch (jack_nframes_t start, jack_nframes_t end); - - void visual_click (); - void hide_click (); - gint when_displayed (GdkEventAny*); - - void speed_changed (); - void add_gain_automation_child (); void add_pan_automation_child (); void add_parameter_automation_child (); @@ -309,14 +115,19 @@ class AudioTimeAxisView : public RouteUI, public TimeAxisView void update_pans (); - void region_view_added (AudioRegionView*); - void add_ghost_to_redirect (AudioRegionView*, AutomationTimeAxisView*); - - void map_frozen (); + AutomationTimeAxisView* gain_track; + AutomationTimeAxisView* pan_track; - void color_handler (ColorID, uint32_t); - bool select_me (GdkEventButton*); + // 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_trackview_h__ */ +#endif /* __ardour_audio_time_axis_h__ */ diff --git a/gtk2_ardour/automation_time_axis.h b/gtk2_ardour/automation_time_axis.h index 0c72ed14f9..6de11a7c6d 100644 --- a/gtk2_ardour/automation_time_axis.h +++ b/gtk2_ardour/automation_time_axis.h @@ -24,7 +24,7 @@ namespace ARDOUR { class PublicEditor; class TimeSelection; -class AudioRegionSelection; +class RegionSelection; class PointSelection; class AutomationLine; class GhostRegion; diff --git a/gtk2_ardour/crossfade_view.cc b/gtk2_ardour/crossfade_view.cc index 350698ec48..087af25e73 100644 --- a/gtk2_ardour/crossfade_view.cc +++ b/gtk2_ardour/crossfade_view.cc @@ -29,7 +29,7 @@ #include "rgb_macros.h" #include "audio_time_axis.h" #include "public_editor.h" -#include "regionview.h" +#include "audio_region_view.h" #include "utils.h" #include "canvas_impl.h" @@ -43,7 +43,7 @@ using namespace Canvas; sigc::signal CrossfadeView::GoingAway; CrossfadeView::CrossfadeView (ArdourCanvas::Group *parent, - AudioTimeAxisView &tv, + RouteTimeAxisView &tv, Crossfade& xf, double spu, Gdk::Color& basic_color, @@ -227,7 +227,7 @@ CrossfadeView::set_valid (bool yn) AudioRegionView& CrossfadeView::upper_regionview () const { - if (left_view.region.layer() > right_view.region.layer()) { + if (left_view.region().layer() > right_view.region().layer()) { return left_view; } else { return right_view; diff --git a/gtk2_ardour/crossfade_view.h b/gtk2_ardour/crossfade_view.h index 403edfe297..adbd74b420 100644 --- a/gtk2_ardour/crossfade_view.h +++ b/gtk2_ardour/crossfade_view.h @@ -28,13 +28,13 @@ #include "time_axis_view_item.h" -class AudioTimeAxisView; +class RouteTimeAxisView; class AudioRegionView; struct CrossfadeView : public TimeAxisViewItem { CrossfadeView (ArdourCanvas::Group*, - AudioTimeAxisView&, + RouteTimeAxisView&, ARDOUR::Crossfade&, double initial_samples_per_unit, Gdk::Color& basic_color, diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 95bcf785f9..518ef7217a 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -56,10 +56,10 @@ #include "keyboard.h" #include "marker.h" #include "playlist_selector.h" -#include "regionview.h" +#include "audio_region_view.h" #include "rgb_macros.h" #include "selection.h" -#include "streamview.h" +#include "audio_streamview.h" #include "time_axis_view.h" #include "utils.h" #include "crossfade_view.h" @@ -101,8 +101,8 @@ static const int32_t slide_index = 0; static const int32_t splice_index = 1; static const gchar *edit_mode_strings[] = { - N_("Slide"), - N_("Splice"), + N_("Slide Edit"), + N_("Splice Edit"), 0 }; @@ -131,17 +131,17 @@ static const gchar *snap_type_strings[] = { }; static const gchar *snap_mode_strings[] = { - N_("Normal"), - N_("Magnetic"), + N_("Normal Snap"), + N_("Magnetic Snap"), 0 }; static const gchar *zoom_focus_strings[] = { - N_("Left"), - N_("Right"), - N_("Center"), - N_("Playhead"), - N_("Edit Cursor"), + N_("Focus Left"), + N_("Focus Right"), + N_("Focus Center"), + N_("Focus Play"), + N_("Focus Edit"), 0 }; @@ -204,37 +204,20 @@ Editor::Editor (AudioEngine& eng) /* tool bar related */ - selection_start_clock (X_("SelectionStartClock"), true), - selection_end_clock (X_("SelectionEndClock"), true), edit_cursor_clock (X_("EditCursorClock"), true), zoom_range_clock (X_("ZoomRangeClock"), true, true), 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")), - edit_mode_label (_("Edit Mode")), - snap_type_label (_("Snap To")), - snap_mode_label(_("Snap Mode")), - zoom_focus_label (_("Zoom Focus")), - /* */ image_socket_listener(0), /* */ /* nudge */ - nudge_label (_("Nudge")), nudge_clock (X_("NudgeClock"), true, true) { @@ -345,6 +328,7 @@ Editor::Editor (AudioEngine& eng) reset_hscrollbar_stepping (); zoom_focus = ZoomFocusLeft; + set_zoom_focus (ZoomFocusLeft); zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed)); initialize_rulers (); @@ -465,36 +449,7 @@ Editor::Editor (AudioEngine& eng) edit_packer.attach (edit_hscrollbar, 2, 3, 2, 3, FILL|EXPAND, FILL, 0, 0); - zoom_in_button.set_name ("EditorTimeButton"); - zoom_out_button.set_name ("EditorTimeButton"); - ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom in")); - ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom out")); - - zoom_out_full_button.set_name ("EditorTimeButton"); - ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to session")); - - zoom_in_button.add (*(manage (new Image (Stock::ZOOM_IN, ICON_SIZE_BUTTON)))); - zoom_out_button.add (*(manage (new Image (Stock::ZOOM_OUT, ICON_SIZE_BUTTON)))); - zoom_out_full_button.add (*(manage (new Image (Stock::ZOOM_FIT, ICON_SIZE_BUTTON)))); - - zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false)); - zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true)); - zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session)); - - zoom_indicator_box.pack_start (zoom_out_button, false, false); - zoom_indicator_box.pack_start (zoom_in_button, false, false); - zoom_indicator_box.pack_start (zoom_range_clock, false, false); - zoom_indicator_box.pack_start (zoom_out_full_button, false, false); - - zoom_indicator_label.set_text (_("Zoom Span")); - zoom_indicator_label.set_name ("ToolBarLabel"); - - zoom_indicator_vbox.set_spacing (3); - zoom_indicator_vbox.set_border_width (3); - zoom_indicator_vbox.pack_start (zoom_indicator_label, false, false); - zoom_indicator_vbox.pack_start (zoom_indicator_box, false, false); - - bottom_hbox.set_border_width (3); + bottom_hbox.set_border_width (2); bottom_hbox.set_spacing (3); route_display_model = ListStore::create(route_display_columns); @@ -717,15 +672,15 @@ Editor::Editor (AudioEngine& eng) _playlist_selector = new PlaylistSelector(); _playlist_selector->signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast (_playlist_selector))); - AudioRegionView::AudioRegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_audio_regionview)); + RegionView::RegionViewGoingAway.connect (mem_fun(*this, &Editor::catch_vanishing_regionview)); /* nudge stuff */ nudge_forward_button.add (*(manage (new Image (get_xpm("right_arrow.xpm"))))); nudge_backward_button.add (*(manage (new Image (get_xpm("left_arrow.xpm"))))); - ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge region/selection forwards")); - ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge region/selection backwards")); + ARDOUR_UI::instance()->tooltips().set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards")); + ARDOUR_UI::instance()->tooltips().set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards")); nudge_forward_button.set_name ("TransportButton"); nudge_backward_button.set_name ("TransportButton"); @@ -775,7 +730,7 @@ Editor::add_toplevel_controls (Container& cont) } void -Editor::catch_vanishing_audio_regionview (AudioRegionView *rv) +Editor::catch_vanishing_regionview (RegionView *rv) { /* note: the selection will take care of the vanishing audioregionview by itself. @@ -791,7 +746,7 @@ Editor::catch_vanishing_audio_regionview (AudioRegionView *rv) } void -Editor::set_entered_regionview (AudioRegionView* rv) +Editor::set_entered_regionview (RegionView* rv) { if (rv == entered_regionview) { return; @@ -1221,7 +1176,7 @@ Editor::connect_to_session (Session *t) session_connections.push_back (session->TransportStateChange.connect (mem_fun(*this, &Editor::map_transport_state))); session_connections.push_back (session->PositionChanged.connect (mem_fun(*this, &Editor::map_position_change))); - session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route_p))); + session_connections.push_back (session->RouteAdded.connect (mem_fun(*this, &Editor::handle_new_route))); session_connections.push_back (session->AudioRegionAdded.connect (mem_fun(*this, &Editor::handle_new_audio_region))); session_connections.push_back (session->AudioRegionRemoved.connect (mem_fun(*this, &Editor::handle_audio_region_removed))); session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration))); @@ -1242,8 +1197,6 @@ Editor::connect_to_session (Session *t) edit_groups_changed (); edit_cursor_clock.set_session (session); - selection_start_clock.set_session (session); - selection_end_clock.set_session (session); zoom_range_clock.set_session (session); _playlist_selector->set_session (session); nudge_clock.set_session (session); @@ -1447,7 +1400,7 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i switch (item_type) { case FadeInItem: case FadeInHandleItem: - if (arv->region.fade_in_active()) { + if (arv->audio_region().fade_in_active()) { items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), false))); } else { items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_in_active), true))); @@ -1455,16 +1408,16 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Linear))); - items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogB))); - items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Fast))); - items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::LogA))); - items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_in_shape), AudioRegion::Slow))); + items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_in_shape), AudioRegion::Linear))); + items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_in_shape), AudioRegion::LogB))); + items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_in_shape), AudioRegion::Fast))); + items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_in_shape), AudioRegion::LogA))); + items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_in_shape), AudioRegion::Slow))); break; case FadeOutItem: case FadeOutHandleItem: - if (arv->region.fade_out_active()) { + if (arv->audio_region().fade_out_active()) { items.push_back (MenuElem (_("Deactivate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), false))); } else { items.push_back (MenuElem (_("Activate"), bind (mem_fun (*arv, &AudioRegionView::set_fade_out_active), true))); @@ -1472,11 +1425,11 @@ Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* i items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Linear))); - items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Fast))); - items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogB))); - items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::LogA))); - items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->region, &AudioRegion::set_fade_out_shape), AudioRegion::Slow))); + items.push_back (MenuElem (_("Linear"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_out_shape), AudioRegion::Linear))); + items.push_back (MenuElem (_("Slowest"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_out_shape), AudioRegion::Fast))); + items.push_back (MenuElem (_("Slow"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_out_shape), AudioRegion::LogB))); + items.push_back (MenuElem (_("Fast"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_out_shape), AudioRegion::LogA))); + items.push_back (MenuElem (_("Fastest"), bind (mem_fun (arv->audio_region(), &AudioRegion::set_fade_out_shape), AudioRegion::Slow))); break; default: @@ -1498,8 +1451,8 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, switch (item_type) { case RegionItem: - case AudioRegionViewName: - case AudioRegionViewNameHighlight: + case RegionViewName: + case RegionViewNameHighlight: if (with_selection) { build_menu_function = &Editor::build_track_selection_context_menu; } else { @@ -1539,25 +1492,26 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, switch (item_type) { case RegionItem: - case AudioRegionViewName: - case AudioRegionViewNameHighlight: + case RegionViewName: + case RegionViewNameHighlight: if (!with_selection) { if (region_edit_menu_split_item) { - if (clicked_regionview && clicked_regionview->region.covers (edit_cursor->current_frame)) { + if (clicked_regionview && clicked_regionview->region().covers (edit_cursor->current_frame)) { ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, true); } else { ActionManager::set_sensitive (ActionManager::edit_cursor_in_region_sensitive_actions, false); } } + /* if (region_edit_menu_split_multichannel_item) { - if (clicked_regionview && clicked_regionview->region.n_channels() > 1) { + if (clicked_regionview && clicked_regionview->region().n_channels() > 1) { // GTK2FIX find the action, change its sensitivity // region_edit_menu_split_multichannel_item->set_sensitive (true); } else { // GTK2FIX see above // region_edit_menu_split_multichannel_item->set_sensitive (false); } - } + }*/ } break; @@ -1637,13 +1591,13 @@ Editor::build_track_region_context_menu (jack_nframes_t frame) AudioTimeAxisView* atv = dynamic_cast (clicked_trackview); if (atv) { - AudioDiskstream* ds; + Diskstream* ds; Playlist* pl; if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) { Playlist::RegionList* regions = pl->regions_at ((jack_nframes_t) floor ( (double)frame * ds->speed())); for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { - add_region_context_items (atv->view, (*i), edit_items); + add_region_context_items (atv->audio_view(), (*i), edit_items); } delete regions; } @@ -1664,7 +1618,7 @@ Editor::build_track_crossfade_context_menu (jack_nframes_t frame) AudioTimeAxisView* atv = dynamic_cast (clicked_trackview); if (atv) { - AudioDiskstream* ds; + Diskstream* ds; Playlist* pl; AudioPlaylist* apl; @@ -1678,11 +1632,11 @@ Editor::build_track_crossfade_context_menu (jack_nframes_t frame) bool many = xfades.size() > 1; for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) { - add_crossfade_context_items (atv->view, (*i), edit_items, many); + add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many); } for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { - add_region_context_items (atv->view, (*i), edit_items); + add_region_context_items (atv->audio_view(), (*i), edit_items); } delete regions; @@ -1748,7 +1702,7 @@ Editor::build_track_selection_context_menu (jack_nframes_t ignored) } void -Editor::add_crossfade_context_items (StreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many) +Editor::add_crossfade_context_items (AudioStreamView* view, Crossfade* xfade, Menu_Helpers::MenuList& edit_items, bool many) { using namespace Menu_Helpers; Menu *xfade_menu = manage (new Menu); @@ -1805,7 +1759,7 @@ Editor::xfade_edit_right_region () } void -Editor::add_region_context_items (StreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items) +Editor::add_region_context_items (AudioStreamView* sv, Region* region, Menu_Helpers::MenuList& edit_items) { using namespace Menu_Helpers; Menu *region_menu = manage (new Menu); @@ -2584,30 +2538,56 @@ void Editor::setup_toolbar () { string pixmap_path; + + const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button + + + /* Mode Buttons (tool selection) */ + vector mouse_mode_buttons; + mouse_move_button.add (*(manage (new Image (get_xpm("tool_object.xpm"))))); + mouse_move_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_move_button); + mouse_select_button.add (*(manage (new Image (get_xpm("tool_range.xpm"))))); + mouse_select_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_select_button); + mouse_gain_button.add (*(manage (new Image (get_xpm("tool_gain.xpm"))))); + mouse_gain_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_gain_button); + mouse_zoom_button.add (*(manage (new Image (get_xpm("tool_zoom.xpm"))))); + mouse_zoom_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_zoom_button); + mouse_timefx_button.add (*(manage (new Image (get_xpm("tool_stretch.xpm"))))); + mouse_timefx_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_timefx_button); + mouse_audition_button.add (*(manage (new Image (get_xpm("tool_audition.xpm"))))); + mouse_audition_button.set_relief(Gtk::RELIEF_NONE); mouse_mode_buttons.push_back (&mouse_audition_button); + mouse_mode_button_set = new GroupedButtons (mouse_mode_buttons); - mouse_mode_button_table.set_homogeneous (true); - mouse_mode_button_table.set_col_spacings (2); - mouse_mode_button_table.set_row_spacings (2); - mouse_mode_button_table.set_border_width (5); + HBox* mode_box = manage(new HBox); + mode_box->set_border_width (2); + mode_box->set_spacing(4); + mouse_mode_button_box.set_spacing(1); + mouse_mode_button_box.pack_start(mouse_move_button, true, true); + mouse_mode_button_box.pack_start(mouse_select_button, true, true); + mouse_mode_button_box.pack_start(mouse_zoom_button, true, true); + mouse_mode_button_box.pack_start(mouse_gain_button, true, true); + mouse_mode_button_box.pack_start(mouse_timefx_button, true, true); + mouse_mode_button_box.pack_start(mouse_audition_button, true, true); + mouse_mode_button_box.set_homogeneous(true); - mouse_mode_button_table.attach (mouse_move_button, 0, 1, 0, 1); - mouse_mode_button_table.attach (mouse_select_button, 1, 2, 0, 1); - mouse_mode_button_table.attach (mouse_zoom_button, 2, 3, 0, 1); - - mouse_mode_button_table.attach (mouse_gain_button, 0, 1, 1, 2); - mouse_mode_button_table.attach (mouse_timefx_button, 1, 2, 1, 2); - mouse_mode_button_table.attach (mouse_audition_button, 2, 3, 1, 2); + edit_mode_selector.set_name ("EditModeSelector"); + 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)); - mouse_mode_tearoff = manage (new TearOff (mouse_mode_button_table)); + mode_box->pack_start(edit_mode_selector); + mode_box->pack_start(mouse_mode_button_box); + + mouse_mode_tearoff = manage (new TearOff (*mode_box)); mouse_mode_tearoff->set_name ("MouseModeBase"); mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast(&toolbar_hbox), @@ -2626,12 +2606,12 @@ Editor::setup_toolbar () mouse_timefx_button.set_name ("MouseModeButton"); mouse_audition_button.set_name ("MouseModeButton"); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("select/move objects")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("select/move ranges")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("draw gain automation")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("select zoom range")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("stretch/shrink regions")); - ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("listen to specific regions")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_move_button, _("Select/Move Objects")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_select_button, _("Select/Move Ranges")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_gain_button, _("Draw Gain Automation")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_zoom_button, _("Select Zoom Range")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_timefx_button, _("Stretch/Shrink Regions")); + ARDOUR_UI::instance()->tooltips().set_tip (mouse_audition_button, _("Listen to Specific Regions")); mouse_move_button.unset_flags (CAN_FOCUS); mouse_select_button.unset_flags (CAN_FOCUS); @@ -2650,160 +2630,82 @@ Editor::setup_toolbar () mouse_audition_button.signal_toggled().connect (bind (mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseAudition)); // mouse_move_button.set_active (true); + - /* automation control */ - - global_automation_button.set_name ("MouseModeButton"); - automation_mode_button.set_name ("MouseModeButton"); - - automation_box.set_spacing (2); - automation_box.set_border_width (2); - automation_box.pack_start (global_automation_button, false, false); - automation_box.pack_start (automation_mode_button, false, false); - - /* Edit mode */ - - edit_mode_label.set_name ("ToolBarLabel"); - - edit_mode_selector.set_name ("EditModeSelector"); + /* Zoom */ + + zoom_box.set_spacing (1); + zoom_box.set_border_width (2); - edit_mode_box.set_spacing (3); - edit_mode_box.set_border_width (3); + zoom_in_button.set_name ("EditorTimeButton"); + zoom_in_button.add (*(manage (new Image (get_xpm("zoom_in.xpm"))))); + zoom_in_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), false)); + ARDOUR_UI::instance()->tooltips().set_tip (zoom_in_button, _("Zoom In")); + + zoom_out_button.set_name ("EditorTimeButton"); + zoom_out_button.add (*(manage (new Image (get_xpm("zoom_out.xpm"))))); + zoom_out_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::temporal_zoom_step), true)); + ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_button, _("Zoom Out")); - /* XXX another disgusting hack because of the way combo boxes size themselves */ + zoom_out_full_button.set_name ("EditorTimeButton"); + zoom_out_full_button.add (*(manage (new Image (get_xpm("zoom_full.xpm"))))); + zoom_out_full_button.signal_clicked().connect (mem_fun(*this, &Editor::temporal_zoom_session)); + ARDOUR_UI::instance()->tooltips().set_tip (zoom_out_full_button, _("Zoom to Session")); + + zoom_box.pack_start (zoom_out_button, false, false); + zoom_box.pack_start (zoom_in_button, false, false); + zoom_box.pack_start (zoom_range_clock, false, false); + zoom_box.pack_start (zoom_out_full_button, false, false); + + ARDOUR_UI::instance()->tooltips().set_tip (zoom_range_clock, _("Current Zoom Range\n(Width of visible area)")); + + zoom_focus_selector.set_name ("ZoomFocusSelector"); + Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Focus Center", 2+FUDGE, 0); + set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings)); + zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done)); - const guint32 FUDGE = 20; // Combo's are stupid - they steal space from the entry for the button - Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "EdgtMode", 2+FUDGE, 10); - set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings)); - edit_mode_box.pack_start (edit_mode_label, false, false); - edit_mode_box.pack_start (edit_mode_selector, false, false); + zoom_box.pack_start (zoom_focus_selector, false, false); - edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done)); - /* Snap Type */ + /* Edit Cursor / Snap */ - snap_type_label.set_name ("ToolBarLabel"); + snap_box.set_spacing (1); + snap_box.set_border_width (2); snap_type_selector.set_name ("SnapTypeSelector"); - - snap_type_box.set_spacing (3); - snap_type_box.set_border_width (3); - - /* XXX another disgusting hack because of the way combo boxes size themselves */ - Gtkmm2ext::set_size_request_to_display_given_text (snap_type_selector, "SMPTE Seconds", 2+FUDGE, 10); set_popdown_strings (snap_type_selector, internationalize (snap_type_strings)); - - snap_type_box.pack_start (snap_type_label, false, false); - snap_type_box.pack_start (snap_type_selector, false, false); - snap_type_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_type_selection_done)); - - /* Snap mode, not snap type */ - - snap_mode_label.set_name ("ToolBarLabel"); + ARDOUR_UI::instance()->tooltips().set_tip (snap_type_selector, _("Unit to snap cursors and ranges to")); snap_mode_selector.set_name ("SnapModeSelector"); - - snap_mode_box.set_spacing (3); - snap_mode_box.set_border_width (3); - - Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "SngpMode", 2+FUDGE, 10); + Gtkmm2ext::set_size_request_to_display_given_text (snap_mode_selector, "Magnetic Snap", 2+FUDGE, 10); set_popdown_strings (snap_mode_selector, internationalize (snap_mode_strings)); - - snap_mode_box.pack_start (snap_mode_label, false, false); - snap_mode_box.pack_start (snap_mode_selector, false, false); - snap_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::snap_mode_selection_done)); - /* Zoom focus mode */ - - zoom_focus_label.set_name ("ToolBarLabel"); - - zoom_focus_selector.set_name ("ZoomFocusSelector"); - - zoom_focus_box.set_spacing (3); - zoom_focus_box.set_border_width (3); - - /* XXX another disgusting hack because of the way combo boxes size themselves */ - - Gtkmm2ext::set_size_request_to_display_given_text (zoom_focus_selector, "Edgt Cursor", 2+FUDGE, 10); - set_popdown_strings (zoom_focus_selector, internationalize (zoom_focus_strings)); - - zoom_focus_box.pack_start (zoom_focus_label, false, false); - zoom_focus_box.pack_start (zoom_focus_selector, false, false); - - zoom_focus_selector.signal_changed().connect (mem_fun(*this, &Editor::zoom_focus_selection_done)); - - /* selection/cursor clocks */ - - toolbar_selection_cursor_label.set_name ("ToolBarLabel"); - selection_start_clock_label.set_name ("ToolBarLabel"); - selection_end_clock_label.set_name ("ToolBarLabel"); - edit_cursor_clock_label.set_name ("ToolBarLabel"); - - selection_start_clock_label.set_text (_("Start:")); - selection_end_clock_label.set_text (_("End:")); - edit_cursor_clock_label.set_text (_("Edit")); - - /* the zoom in/out buttons are generally taller than the clocks, so - put all the toolbar clocks into a size group with one of the - buttons to make them all equal height. + snap_box.pack_start (edit_cursor_clock, false, false); + snap_box.pack_start (snap_mode_selector, false, false); + snap_box.pack_start (snap_type_selector, false, false); - this also applies to the various toolbar combos - */ - - RefPtr toolbar_clock_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL); - toolbar_clock_size_group->add_widget (zoom_out_button); - toolbar_clock_size_group->add_widget (edit_cursor_clock); - toolbar_clock_size_group->add_widget (zoom_range_clock); - toolbar_clock_size_group->add_widget (nudge_clock); - toolbar_clock_size_group->add_widget (edit_mode_selector); - toolbar_clock_size_group->add_widget (snap_type_selector); - toolbar_clock_size_group->add_widget (snap_mode_selector); - toolbar_clock_size_group->add_widget (zoom_focus_selector); - - HBox* edit_clock_hbox = manage (new HBox()); - VBox* edit_clock_vbox = manage (new VBox()); - - edit_clock_hbox->pack_start (edit_cursor_clock, false, false); - - edit_clock_vbox->set_spacing (3); - edit_clock_vbox->set_border_width (3); - edit_clock_vbox->pack_start (edit_cursor_clock_label, false, false); - edit_clock_vbox->pack_start (*edit_clock_hbox, false, false); - - HBox* hbox = new HBox; - hbox->pack_start (*edit_clock_vbox, false, false); - hbox->pack_start (zoom_indicator_vbox, false, false); - hbox->pack_start (zoom_focus_box, false, false); - hbox->pack_start (snap_type_box, false, false); - hbox->pack_start (snap_mode_box, false, false); - hbox->pack_start (edit_mode_box, false, false); + /* Nudge */ - VBox *vbox = manage (new VBox); + HBox *nudge_box = manage (new HBox); + nudge_box->set_spacing(1); + nudge_box->set_border_width (2); - vbox->set_spacing (3); - vbox->set_border_width (3); - - HBox *nbox = manage (new HBox); - nudge_forward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_forward), false)); nudge_backward_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::nudge_backward), false)); - nbox->pack_start (nudge_backward_button, false, false); - nbox->pack_start (nudge_forward_button, false, false); - nbox->pack_start (nudge_clock, false, false, 5); - - nudge_label.set_name ("ToolBarLabel"); + nudge_box->pack_start (nudge_backward_button, false, false); + nudge_box->pack_start (nudge_forward_button, false, false); + nudge_box->pack_start (nudge_clock, false, false); - vbox->pack_start (nudge_label, false, false); - vbox->pack_start (*nbox, false, false); - hbox->pack_start (*vbox, false, false); + /* Pack everything in... */ - hbox->show_all (); + HBox* hbox = new HBox; + hbox->set_spacing(10); tools_tearoff = new TearOff (*hbox); tools_tearoff->set_name ("MouseModeBase"); @@ -2817,11 +2719,18 @@ Editor::setup_toolbar () tools_tearoff->Visible.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast (&toolbar_hbox), &tools_tearoff->tearoff_window(), 0)); - toolbar_hbox.set_spacing (8); - toolbar_hbox.set_border_width (2); + toolbar_hbox.set_spacing (10); + toolbar_hbox.set_border_width (1); - toolbar_hbox.pack_start (*tools_tearoff, false, false); toolbar_hbox.pack_start (*mouse_mode_tearoff, false, false); + toolbar_hbox.pack_start (*tools_tearoff, false, false); + + + hbox->pack_start (snap_box, false, false); + hbox->pack_start (zoom_box, false, false); + hbox->pack_start (*nudge_box, false, false); + + hbox->show_all (); toolbar_base.set_name ("ToolBarBase"); toolbar_base.add (toolbar_hbox); @@ -3101,31 +3010,31 @@ Editor::mapover_audio_tracks (slot sl) } void -Editor::mapped_set_selected_regionview_from_click (AudioTimeAxisView& atv, uint32_t ignored, - AudioRegionView* basis, vector* all_equivs) +Editor::mapped_set_selected_regionview_from_click (RouteTimeAxisView& tv, uint32_t ignored, + RegionView* basis, vector* all_equivs) { - AudioPlaylist* pl; - vector results; - AudioRegionView* marv; - AudioDiskstream* ds; + Playlist* pl; + vector results; + RegionView* marv; + Diskstream* ds; - if ((ds = atv.get_diskstream()) == 0) { + if ((ds = tv.get_diskstream()) == 0) { /* bus */ return; } - if (&atv == &basis->get_time_axis_view()) { + if (&tv == &basis->get_time_axis_view()) { /* looking in same track as the original */ return; } - if ((pl = ds->playlist()) != 0) { - pl->get_equivalent_regions (basis->region, results); + if ((pl = dynamic_cast(ds->playlist())) != 0) { + pl->get_equivalent_regions (basis->region(), results); } - for (vector::iterator ir = results.begin(); ir != results.end(); ++ir) { - if ((marv = atv.view->find_view (**ir)) != 0) { + for (vector::iterator ir = results.begin(); ir != results.end(); ++ir) { + if ((marv = tv.view()->find_view (**ir)) != 0) { all_equivs->push_back (marv); } } @@ -3134,7 +3043,7 @@ Editor::mapped_set_selected_regionview_from_click (AudioTimeAxisView& atv, uint3 bool Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool no_track_remove) { - vector all_equivalent_regions; + vector all_equivalent_regions; bool commit = false; if (!clicked_regionview || !clicked_audio_trackview) { @@ -3189,7 +3098,7 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, commit = true; } - for (vector::iterator i = all_equivalent_regions.begin(); i != all_equivalent_regions.end(); ++i) { + for (vector::iterator i = all_equivalent_regions.begin(); i != all_equivalent_regions.end(); ++i) { selection->add (*i); } } @@ -3222,58 +3131,58 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, last_frame = 0; first_frame = max_frames; - for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ++x) { + for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) { if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) { - if ((*x)->region.last_frame() > last_frame) { - last_frame = (*x)->region.last_frame(); + if ((*x)->region().last_frame() > last_frame) { + last_frame = (*x)->region().last_frame(); } - if ((*x)->region.first_frame() < first_frame) { - first_frame = (*x)->region.first_frame(); + if ((*x)->region().first_frame() < first_frame) { + first_frame = (*x)->region().first_frame(); } } } /* 2. figure out the boundaries for our search for new objects */ - switch (clicked_regionview->region.coverage (first_frame, last_frame)) { + switch (clicked_regionview->region().coverage (first_frame, last_frame)) { case OverlapNone: cerr << "no overlap, first = " << first_frame << " last = " << last_frame << " region = " - << clicked_regionview->region.first_frame() << " .. " << clicked_regionview->region.last_frame() << endl; + << clicked_regionview->region().first_frame() << " .. " << clicked_regionview->region().last_frame() << endl; - if (last_frame < clicked_regionview->region.first_frame()) { + if (last_frame < clicked_regionview->region().first_frame()) { first_frame = last_frame; - last_frame = clicked_regionview->region.last_frame(); + last_frame = clicked_regionview->region().last_frame(); } else { last_frame = first_frame; - first_frame = clicked_regionview->region.first_frame(); + first_frame = clicked_regionview->region().first_frame(); } break; case OverlapExternal: cerr << "external overlap, first = " << first_frame << " last = " << last_frame << " region = " - << clicked_regionview->region.first_frame() << " .. " << clicked_regionview->region.last_frame() << endl; + << clicked_regionview->region().first_frame() << " .. " << clicked_regionview->region().last_frame() << endl; - if (last_frame < clicked_regionview->region.first_frame()) { + if (last_frame < clicked_regionview->region().first_frame()) { first_frame = last_frame; - last_frame = clicked_regionview->region.last_frame(); + last_frame = clicked_regionview->region().last_frame(); } else { last_frame = first_frame; - first_frame = clicked_regionview->region.first_frame(); + first_frame = clicked_regionview->region().first_frame(); } break; case OverlapInternal: cerr << "internal overlap, first = " << first_frame << " last = " << last_frame << " region = " - << clicked_regionview->region.first_frame() << " .. " << clicked_regionview->region.last_frame() << endl; + << clicked_regionview->region().first_frame() << " .. " << clicked_regionview->region().last_frame() << endl; - if (last_frame < clicked_regionview->region.first_frame()) { + if (last_frame < clicked_regionview->region().first_frame()) { first_frame = last_frame; - last_frame = clicked_regionview->region.last_frame(); + last_frame = clicked_regionview->region().last_frame(); } else { last_frame = first_frame; - first_frame = clicked_regionview->region.first_frame(); + first_frame = clicked_regionview->region().first_frame(); } break; @@ -3299,18 +3208,18 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, /* 3. convert to a vector of audio regions */ - vector audio_regions; + vector regions; for (list::iterator x = results.begin(); x != results.end(); ++x) { - AudioRegionView* arv; + RegionView* arv; - if ((arv = dynamic_cast(*x)) != 0) { - audio_regions.push_back (arv); + if ((arv = dynamic_cast(*x)) != 0) { + regions.push_back (arv); } } - if (!audio_regions.empty()) { - selection->add (audio_regions); + if (!regions.empty()) { + selection->add (regions); commit = true; } } @@ -3320,37 +3229,32 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, } void -Editor::set_selected_regionview_from_region_list (Region& r, Selection::Operation op) +Editor::set_selected_regionview_from_region_list (Region& region, Selection::Operation op) { - vector all_equivalent_regions; - AudioRegion* region; - - if ((region = dynamic_cast(&r)) == 0) { - return; - } + vector all_equivalent_regions; for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - AudioTimeAxisView* tatv; + RouteTimeAxisView* tatv; - if ((tatv = dynamic_cast (*i)) != 0) { + if ((tatv = dynamic_cast (*i)) != 0) { - AudioPlaylist* pl; - vector results; - AudioRegionView* marv; - AudioDiskstream* ds; + Playlist* pl; + vector results; + RegionView* marv; + Diskstream* ds; if ((ds = tatv->get_diskstream()) == 0) { /* bus */ continue; } - if ((pl = ds->playlist()) != 0) { - pl->get_region_list_equivalent_regions (*region, results); + if ((pl = dynamic_cast(ds->playlist())) != 0) { + pl->get_region_list_equivalent_regions (region, results); } - for (vector::iterator ir = results.begin(); ir != results.end(); ++ir) { - if ((marv = tatv->view->find_view (**ir)) != 0) { + for (vector::iterator ir = results.begin(); ir != results.end(); ++ir) { + if ((marv = tatv->view()->find_view (**ir)) != 0) { all_equivalent_regions.push_back (marv); } } @@ -3379,10 +3283,10 @@ Editor::set_selected_regionview_from_region_list (Region& r, Selection::Operatio bool Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, Region* r) { - AudioRegionView* rv; - AudioRegion* ar; + RegionView* rv; + Region* ar; - if ((ar = dynamic_cast (r)) == 0) { + if ((ar = dynamic_cast (r)) == 0) { return TRUE; } @@ -3394,7 +3298,7 @@ Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, a single other region. */ - if (selection->audio_regions.size() > 1) { + if (selection->regions.size() > 1) { return TRUE; } @@ -3559,7 +3463,7 @@ Editor::duplicate_dialog (bool dup_region) if (sscanf (text.c_str(), "%f", ×) == 1) { if (dup_region) { - AudioRegionSelection regions; + RegionSelection regions; regions.add (clicked_regionview); duplicate_some_regions (regions, times); } else { @@ -3610,9 +3514,9 @@ Editor::edit_mode_selection_done () string choice = edit_mode_selector.get_active_text(); EditMode mode = Slide; - if (choice == _("Splice")) { + if (choice == _("Splice Edit")) { mode = Splice; - } else if (choice == _("Slide")) { + } else if (choice == _("Slide Edit")) { mode = Slide; } @@ -3628,18 +3532,18 @@ Editor::snap_type_selection_done () string choice = snap_type_selector.get_active_text(); SnapType snaptype = SnapToFrame; - + if (choice == _("Beats/3")) { - snaptype = SnapToAThirdBeat; - } else if (choice == _("Beats/4")) { - snaptype = SnapToAQuarterBeat; - } else if (choice == _("Beats/8")) { - snaptype = SnapToAEighthBeat; - } else if (choice == _("Beats/16")) { - snaptype = SnapToASixteenthBeat; - } else if (choice == _("Beats/32")) { - snaptype = SnapToAThirtysecondBeat; - } else if (choice == _("Beats")) { + snaptype = SnapToAThirdBeat; + } else if (choice == _("Beats/4")) { + snaptype = SnapToAQuarterBeat; + } else if (choice == _("Beats/8")) { + snaptype = SnapToAEighthBeat; + } else if (choice == _("Beats/16")) { + snaptype = SnapToASixteenthBeat; + } else if (choice == _("Beats/32")) { + snaptype = SnapToAThirtysecondBeat; + } else if (choice == _("Beats")) { snaptype = SnapToBeat; } else if (choice == _("Bars")) { snaptype = SnapToBar; @@ -3667,10 +3571,10 @@ Editor::snap_type_selection_done () snaptype = SnapToSeconds; } else if (choice == _("Minutes")) { snaptype = SnapToMinutes; - } else if (choice == _("None")) { + } else if (choice == _("None")) { snaptype = SnapToFrame; } - + set_snap_to (snaptype); } @@ -3684,9 +3588,9 @@ Editor::snap_mode_selection_done () string choice = snap_mode_selector.get_active_text(); SnapMode mode = SnapNormal; - if (choice == _("Normal")) { + if (choice == _("Normal Snap")) { mode = SnapNormal; - } else if (choice == _("Magnetic")) { + } else if (choice == _("Magnetic Snap")) { mode = SnapMagnetic; } @@ -3703,15 +3607,15 @@ Editor::zoom_focus_selection_done () string choice = zoom_focus_selector.get_active_text(); ZoomFocus focus_type = ZoomFocusLeft; - if (choice == _("Left")) { + if (choice == _("Focus Left")) { focus_type = ZoomFocusLeft; - } else if (choice == _("Right")) { + } else if (choice == _("Focus Right")) { focus_type = ZoomFocusRight; - } else if (choice == _("Center")) { + } else if (choice == _("Focus Center")) { focus_type = ZoomFocusCenter; - } else if (choice == _("Playhead")) { + } else if (choice == _("Focus Playhead")) { focus_type = ZoomFocusPlayhead; - } else if (choice == _("Edit Cursor")) { + } else if (choice == _("Focus Edit Cursor")) { focus_type = ZoomFocusEdit; } @@ -3781,7 +3685,7 @@ void Editor::region_selection_changed () { for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - (*i)->set_selected_regionviews (selection->audio_regions); + (*i)->set_selected_regionviews (selection->regions); } } @@ -4051,8 +3955,8 @@ Editor::playlist_deletion_dialog (Playlist* pl) bool Editor::audio_region_selection_covers (jack_nframes_t where) { - for (AudioRegionSelection::iterator a = selection->audio_regions.begin(); a != selection->audio_regions.end(); ++a) { - if ((*a)->region.covers (where)) { + for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) { + if ((*a)->region().covers (where)) { return true; } } @@ -4063,10 +3967,10 @@ Editor::audio_region_selection_covers (jack_nframes_t where) void Editor::prepare_for_cleanup () { - cut_buffer->clear_audio_regions (); + cut_buffer->clear_regions (); cut_buffer->clear_playlists (); - selection->clear_audio_regions (); + selection->clear_regions (); selection->clear_playlists (); } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index bfc49b7d0d..a1e69e2ad1 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -69,6 +69,7 @@ namespace ARDOUR { class AudioDiskstream; class RouteGroup; class Playlist; + class AudioPlaylist; class Region; class Location; class TempoSection; @@ -83,6 +84,7 @@ namespace LADSPA { } class TimeAxisView; +class RouteTimeAxisView; class AudioTimeAxisView; class AutomationTimeAxisView; class AudioRegionView; @@ -100,6 +102,7 @@ class TrackSelection; class AutomationSelection; class MixerStrip; class StreamView; +class AudioStreamView; class ControlPoint; #ifdef FFT_ANALYSIS class AnalysisWindow; @@ -405,8 +408,8 @@ class Editor : public PublicEditor TimeAxisView* clicked_trackview; AudioTimeAxisView* clicked_audio_trackview; - AudioRegionView* clicked_regionview; - AudioRegionView* latest_regionview; + RegionView* clicked_regionview; + RegionView* latest_regionview; uint32_t clicked_selection; CrossfadeView* clicked_crossfadeview; ControlPoint* clicked_control_point; @@ -416,7 +419,7 @@ class Editor : public PublicEditor /* functions to be passed to mapover_audio_tracks(), possibly with sigc::bind()-supplied arguments */ - void mapped_set_selected_regionview_from_click (AudioTimeAxisView&, uint32_t, AudioRegionView*, vector*); + void mapped_set_selected_regionview_from_click (RouteTimeAxisView&, uint32_t, RegionView*, vector*); void mapped_use_new_playlist (AudioTimeAxisView&, uint32_t); void mapped_use_copy_playlist (AudioTimeAxisView&, uint32_t); void mapped_clear_playlist (AudioTimeAxisView&, uint32_t); @@ -426,7 +429,7 @@ class Editor : public PublicEditor void button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type); bool button_release_can_deselect; - void catch_vanishing_audio_regionview (AudioRegionView *); + void catch_vanishing_regionview (RegionView *); bool set_selected_control_point_from_click (bool press, Selection::Operation op = Selection::Set, bool with_undo = true, bool no_remove=false); bool set_selected_track_from_click (bool press, Selection::Operation op = Selection::Set, bool with_undo = true, bool no_remove=false); @@ -434,7 +437,7 @@ class Editor : public PublicEditor void set_selected_regionview_from_region_list (ARDOUR::Region& region, Selection::Operation op = Selection::Set); bool set_selected_regionview_from_map_event (GdkEventAny*, StreamView*, ARDOUR::Region*); - void collect_new_region_view (AudioRegionView *); + void collect_new_region_view (RegionView *); Gtk::Menu track_context_menu; Gtk::Menu track_region_context_menu; @@ -455,12 +458,11 @@ class Editor : public PublicEditor Gtk::Menu* build_track_selection_context_menu (jack_nframes_t); void add_dstream_context_items (Gtk::Menu_Helpers::MenuList&); void add_bus_context_items (Gtk::Menu_Helpers::MenuList&); - void add_region_context_items (StreamView*, ARDOUR::Region*, Gtk::Menu_Helpers::MenuList&); - void add_crossfade_context_items (StreamView*, ARDOUR::Crossfade*, Gtk::Menu_Helpers::MenuList&, bool many); + void add_region_context_items (AudioStreamView*, ARDOUR::Region*, Gtk::Menu_Helpers::MenuList&); + void add_crossfade_context_items (AudioStreamView*, ARDOUR::Crossfade*, Gtk::Menu_Helpers::MenuList&, bool many); void add_selection_context_items (Gtk::Menu_Helpers::MenuList&); void handle_new_route (boost::shared_ptr); - void handle_new_route_p (boost::shared_ptr); void remove_route (TimeAxisView *); bool route_removal; @@ -854,7 +856,7 @@ class Editor : public PublicEditor void lower_region_to_bottom (); void split_region (); void split_region_at (jack_nframes_t); - void split_regions_at (jack_nframes_t, AudioRegionSelection&); + void split_regions_at (jack_nframes_t, RegionSelection&); void crop_region_to_selection (); void set_a_regions_sync_position (ARDOUR::Region&, jack_nframes_t); void set_region_sync_from_edit_cursor (); @@ -867,13 +869,13 @@ class Editor : public PublicEditor void remove_clicked_region (); void destroy_clicked_region (); void edit_region (); - void duplicate_some_regions (AudioRegionSelection&, float times); + void duplicate_some_regions (RegionSelection&, float times); void duplicate_selection (float times); void region_fill_selection (); void region_fill_track (); - void audition_playlist_region_standalone (ARDOUR::AudioRegion&); - void audition_playlist_region_via_route (ARDOUR::AudioRegion&, ARDOUR::Route&); + void audition_playlist_region_standalone (ARDOUR::Region&); + void audition_playlist_region_via_route (ARDOUR::Region&, ARDOUR::Route&); void split_multichannel_region(); void reverse_region (); void normalize_region (); @@ -1020,7 +1022,7 @@ class Editor : public PublicEditor bool have_pending_keyboard_selection; jack_nframes_t pending_keyboard_selection_start; - ARDOUR::AudioRegion* select_region_for_operation (int dir, TimeAxisView **tv); + ARDOUR::Region* select_region_for_operation (int dir, TimeAxisView **tv); void extend_selection_to_end_of_region (bool next); void extend_selection_to_start_of_region (bool previous); @@ -1094,7 +1096,7 @@ class Editor : public PublicEditor void remove_gain_control_point (ArdourCanvas::Item*, GdkEvent*); void remove_control_point (ArdourCanvas::Item*, GdkEvent*); - void mouse_brush_insert_region (AudioRegionView*, jack_nframes_t pos); + void mouse_brush_insert_region (RegionView*, jack_nframes_t pos); void brush (jack_nframes_t); void show_verbose_time_cursor (jack_nframes_t frame, double offset = 0, double xpos=-1, double ypos=-1); @@ -1112,10 +1114,10 @@ class Editor : public PublicEditor bool canvas_fade_in_handle_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); bool canvas_fade_out_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); bool canvas_fade_out_handle_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); - bool canvas_region_view_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); - bool canvas_region_view_name_highlight_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); - bool canvas_region_view_name_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); - bool canvas_stream_view_event (GdkEvent* event,ArdourCanvas::Item*, AudioTimeAxisView*); + bool canvas_region_view_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); + bool canvas_region_view_name_highlight_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); + bool canvas_region_view_name_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); + bool canvas_stream_view_event (GdkEvent* event,ArdourCanvas::Item*, RouteTimeAxisView*); bool canvas_marker_event (GdkEvent* event,ArdourCanvas::Item*, Marker*); bool canvas_zoom_rect_event (GdkEvent* event,ArdourCanvas::Item*); bool canvas_tempo_marker_event (GdkEvent* event,ArdourCanvas::Item*, TempoMarker*); @@ -1263,12 +1265,7 @@ class Editor : public PublicEditor void editor_mixer_button_toggled (); - AudioClock selection_start_clock; - Gtk::Label selection_start_clock_label; - AudioClock selection_end_clock; - Gtk::Label selection_end_clock_label; AudioClock edit_cursor_clock; - Gtk::Label edit_cursor_clock_label; AudioClock zoom_range_clock; Gtk::Button zoom_in_button; Gtk::Button zoom_out_button; @@ -1280,8 +1277,8 @@ class Editor : public PublicEditor Gtk::Table toolbar_selection_clock_table; Gtk::Label toolbar_selection_cursor_label; - Gtk::Table mouse_mode_button_table; - Gtkmm2ext::TearOff* mouse_mode_tearoff; + Gtk::HBox mouse_mode_button_box; + Gtkmm2ext::TearOff* mouse_mode_tearoff; Gtk::ToggleButton mouse_select_button; Gtk::ToggleButton mouse_move_button; Gtk::ToggleButton mouse_gain_button; @@ -1299,32 +1296,23 @@ class Editor : public PublicEditor Gtk::ToggleButton global_automation_button; Gtk::ComboBoxText edit_mode_selector; - Gtk::Label edit_mode_label; - Gtk::VBox edit_mode_box; + Gtk::VBox edit_mode_box; void edit_mode_selection_done (); Gtk::ComboBoxText snap_type_selector; - Gtk::Label snap_type_label; - Gtk::VBox snap_type_box; + Gtk::ComboBoxText snap_mode_selector; + Gtk::HBox snap_box; void snap_type_selection_done (); - - Gtk::ComboBoxText snap_mode_selector; - Gtk::Label snap_mode_label; - Gtk::VBox snap_mode_box; - void snap_mode_selection_done (); Gtk::ComboBoxText zoom_focus_selector; - Gtk::Label zoom_focus_label; Gtk::VBox zoom_focus_box; void zoom_focus_selection_done (); - Gtk::Label zoom_indicator_label; - Gtk::HBox zoom_indicator_box; - Gtk::VBox zoom_indicator_vbox; + Gtk::HBox zoom_box; void update_zoom_indicator (); void zoom_adjustment_changed(); @@ -1533,12 +1521,12 @@ class Editor : public PublicEditor void start_trim (ArdourCanvas::Item*, GdkEvent*); void point_trim (GdkEvent*); void trim_motion_callback (ArdourCanvas::Item*, GdkEvent*); - void single_contents_trim (AudioRegionView&, jack_nframes_t, bool, bool, bool); - void single_start_trim (AudioRegionView&, jack_nframes_t, bool, bool); - void single_end_trim (AudioRegionView&, jack_nframes_t, bool, bool); + void single_contents_trim (RegionView&, jack_nframes_t, bool, bool, bool); + void single_start_trim (RegionView&, jack_nframes_t, bool, bool); + void single_end_trim (RegionView&, jack_nframes_t, bool, bool); void trim_finished_callback (ArdourCanvas::Item*, GdkEvent*); - void thaw_region_after_trim (AudioRegionView& rv); + void thaw_region_after_trim (RegionView& rv); void trim_region_to_edit_cursor (); void trim_region_from_edit_cursor (); @@ -1592,7 +1580,7 @@ class Editor : public PublicEditor void export_range (jack_nframes_t start, jack_nframes_t end); void export_range_markers (); - int write_region_selection(AudioRegionSelection&); + int write_region_selection(RegionSelection&); bool write_region (string path, ARDOUR::AudioRegion&); void export_region (); void bounce_region_selection (); @@ -1600,7 +1588,7 @@ class Editor : public PublicEditor void external_edit_region (); int write_audio_selection (TimeSelection&); - bool write_audio_range (ARDOUR::Playlist&, uint32_t channels, list&); + bool write_audio_range (ARDOUR::AudioPlaylist&, uint32_t channels, list&); void write_selection (); @@ -1670,7 +1658,7 @@ class Editor : public PublicEditor struct TimeStretchDialog : public ArdourDialog { ARDOUR::Session::TimeStretchRequest request; Editor& editor; - AudioRegionSelection regions; + RegionSelection regions; Gtk::ProgressBar progress_bar; Gtk::ToggleButton quick_button; Gtk::ToggleButton antialias_button; @@ -1696,7 +1684,7 @@ class Editor : public PublicEditor TimeStretchDialog* current_timestretch; static void* timestretch_thread (void *arg); - int run_timestretch (AudioRegionSelection&, float fraction); + int run_timestretch (RegionSelection&, float fraction); void do_timestretch (TimeStretchDialog&); /* editor-mixer strip */ @@ -1775,7 +1763,6 @@ class Editor : public PublicEditor Gtk::Button nudge_backward_button; Gtk::HBox nudge_hbox; Gtk::VBox nudge_vbox; - Gtk::Label nudge_label; AudioClock nudge_clock; jack_nframes_t get_nudge_distance (jack_nframes_t pos, jack_nframes_t& next); @@ -1798,11 +1785,11 @@ class Editor : public PublicEditor sigc::connection step_timeout; TimeAxisView* entered_track; - AudioRegionView* entered_regionview; + RegionView* entered_regionview; bool clear_entered_track; gint left_track_canvas (GdkEventCrossing*); void set_entered_track (TimeAxisView*); - void set_entered_regionview (AudioRegionView*); + void set_entered_regionview (RegionView*); gint left_automation_track (); bool _new_regionviews_show_envelope; diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc index 68c481aa01..f8c632f08a 100644 --- a/gtk2_ardour/editor_audio_import.cc +++ b/gtk2_ardour/editor_audio_import.cc @@ -316,7 +316,7 @@ Editor::finish_bringing_in_audio (AudioRegion& region, uint32_t in_chans, uint32 case ImportToTrack: if (track) { - Playlist* playlist = track->disk_stream().playlist(); + Playlist* playlist = track->diskstream().playlist(); AudioRegion* copy = new AudioRegion (region); begin_reversible_command (_("insert sndfile")); @@ -333,7 +333,7 @@ Editor::finish_bringing_in_audio (AudioRegion& region, uint32_t in_chans, uint32 { boost::shared_ptr at (session->new_audio_track (in_chans, out_chans, Normal)); copy = new AudioRegion (region); - at->disk_stream().playlist()->add_region (*copy, pos); + at->diskstream().playlist()->add_region (*copy, pos); break; } @@ -341,7 +341,7 @@ Editor::finish_bringing_in_audio (AudioRegion& region, uint32_t in_chans, uint32 { boost::shared_ptr at (session->new_audio_track (in_chans, out_chans, Destructive)); copy = new AudioRegion (region); - at->disk_stream().playlist()->add_region (*copy, pos); + at->diskstream().playlist()->add_region (*copy, pos); break; } } diff --git a/gtk2_ardour/editor_audiotrack.cc b/gtk2_ardour/editor_audiotrack.cc index acad3371a0..5b575b4814 100644 --- a/gtk2_ardour/editor_audiotrack.cc +++ b/gtk2_ardour/editor_audiotrack.cc @@ -4,7 +4,7 @@ #include "editor.h" #include "editing.h" #include "audio_time_axis.h" -#include "regionview.h" +#include "region_view.h" #include "selection.h" using namespace ARDOUR; diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc index 43114534c5..8e635bbe13 100644 --- a/gtk2_ardour/editor_canvas_events.cc +++ b/gtk2_ardour/editor_canvas_events.cc @@ -26,8 +26,8 @@ #include "editor.h" #include "public_editor.h" -#include "regionview.h" -#include "streamview.h" +#include "audio_region_view.h" +#include "audio_streamview.h" #include "crossfade_view.h" #include "audio_time_axis.h" #include "region_gain_line.h" @@ -212,7 +212,7 @@ Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type) } bool -Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv) +Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv) { gint ret = FALSE; @@ -251,7 +251,7 @@ Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, Aud } bool -Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, AudioTimeAxisView *tv) +Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv) { bool ret = FALSE; @@ -262,7 +262,7 @@ Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, Aud clicked_regionview = 0; clicked_control_point = 0; clicked_trackview = tv; - clicked_audio_trackview = tv; + clicked_audio_trackview = dynamic_cast(tv); ret = button_press_handler (item, event, StreamItem); break; @@ -512,22 +512,25 @@ Editor::canvas_crossfade_view_event (GdkEvent* event, ArdourCanvas::Item* item, if ((atv = dynamic_cast(&tv)) != 0) { if (atv->is_audio_track()) { - - AudioPlaylist* pl = atv->get_diskstream()->playlist(); - Playlist::RegionList* rl = pl->regions_at (event_frame (event)); - if (!rl->empty()) { - DescendingRegionLayerSorter cmp; - rl->sort (cmp); + AudioPlaylist* pl; + if ((pl = dynamic_cast (atv->get_diskstream()->playlist())) != 0) { + + Playlist::RegionList* rl = pl->regions_at (event_frame (event)); + + if (!rl->empty()) { + DescendingRegionLayerSorter cmp; + rl->sort (cmp); - AudioRegionView* arv = atv->view->find_view (*(dynamic_cast (rl->front()))); + RegionView* rv = atv->view()->find_view (*rl->front()); - /* proxy */ - - delete rl; + /* proxy */ - return canvas_region_view_event (event, arv->get_canvas_group(), arv); - } + delete rl; + + return canvas_region_view_event (event, rv->get_canvas_group(), rv); + } + } } } @@ -696,7 +699,7 @@ Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* it bool -Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, AudioRegionView* rv) +Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv) { bool ret = false; @@ -708,20 +711,20 @@ Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas:: clicked_control_point = 0; clicked_trackview = &clicked_regionview->get_time_axis_view(); clicked_audio_trackview = dynamic_cast(clicked_trackview); - ret = button_press_handler (item, event, AudioRegionViewNameHighlight); + ret = button_press_handler (item, event, RegionViewNameHighlight); break; case GDK_BUTTON_RELEASE: - ret = button_release_handler (item, event, AudioRegionViewNameHighlight); + ret = button_release_handler (item, event, RegionViewNameHighlight); break; case GDK_MOTION_NOTIFY: - ret = motion_handler (item, event, AudioRegionViewNameHighlight); + ret = motion_handler (item, event, RegionViewNameHighlight); break; case GDK_ENTER_NOTIFY: - ret = enter_handler (item, event, AudioRegionViewNameHighlight); + ret = enter_handler (item, event, RegionViewNameHighlight); break; case GDK_LEAVE_NOTIFY: - ret = leave_handler (item, event, AudioRegionViewNameHighlight); + ret = leave_handler (item, event, RegionViewNameHighlight); break; default: @@ -732,7 +735,7 @@ Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas:: } bool -Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView* rv) +Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv) { bool ret = false; @@ -744,20 +747,20 @@ Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item clicked_control_point = 0; clicked_trackview = &clicked_regionview->get_time_axis_view(); clicked_audio_trackview = dynamic_cast(clicked_trackview); - ret = button_press_handler (item, event, AudioRegionViewName); + ret = button_press_handler (item, event, RegionViewName); break; case GDK_BUTTON_RELEASE: - ret = button_release_handler (item, event, AudioRegionViewName); + ret = button_release_handler (item, event, RegionViewName); break; case GDK_MOTION_NOTIFY: - ret = motion_handler (item, event, AudioRegionViewName); + ret = motion_handler (item, event, RegionViewName); break; case GDK_ENTER_NOTIFY: - ret = enter_handler (item, event, AudioRegionViewName); + ret = enter_handler (item, event, RegionViewName); break; case GDK_LEAVE_NOTIFY: - ret = leave_handler (item, event, AudioRegionViewName); + ret = leave_handler (item, event, RegionViewName); break; default: diff --git a/gtk2_ardour/editor_export_audio.cc b/gtk2_ardour/editor_export_audio.cc index 0be0a61b23..46a704b435 100644 --- a/gtk2_ardour/editor_export_audio.cc +++ b/gtk2_ardour/editor_export_audio.cc @@ -31,7 +31,7 @@ #include "selection.h" #include "time_axis_view.h" #include "audio_time_axis.h" -#include "regionview.h" +#include "audio_region_view.h" #include #include @@ -92,12 +92,12 @@ Editor::export_region () return; } - ExportDialog* dialog = new ExportRegionDialog (*this, &clicked_regionview->region); + ExportDialog* dialog = new ExportRegionDialog (*this, &clicked_regionview->region()); dialog->connect_to_session (session); dialog->set_range ( - clicked_regionview->region.first_frame(), - clicked_regionview->region.last_frame()); + clicked_regionview->region().first_frame(), + clicked_regionview->region().last_frame()); dialog->start_export(); } @@ -123,24 +123,26 @@ Editor::export_range_markers () } int -Editor::write_region_selection (AudioRegionSelection& regions) +Editor::write_region_selection (RegionSelection& regions) { - for (AudioRegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { - if (write_region ("", (*i)->region) == false) { - return -1; - } + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + AudioRegionView* arv = dynamic_cast(*i); + if (arv) + if (write_region ("", arv->audio_region()) == false) + return -1; } + return 0; } void Editor::bounce_region_selection () { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { - AudioRegion& region ((*i)->region); - AudioTimeAxisView* atv = dynamic_cast(&(*i)->get_time_axis_view()); - AudioTrack* track = dynamic_cast(atv->route().get()); + Region& region ((*i)->region()); + RouteTimeAxisView* rtv = dynamic_cast(&(*i)->get_time_axis_view()); + Track* track = dynamic_cast(rtv->route().get()); InterThreadInfo itt; @@ -287,7 +289,7 @@ Editor::write_audio_selection (TimeSelection& ts) if (atv->is_audio_track()) { - Playlist* playlist = atv->get_diskstream()->playlist(); + AudioPlaylist* playlist = dynamic_cast(atv->get_diskstream()->playlist()); if (playlist && write_audio_range (*playlist, atv->get_diskstream()->n_channels(), ts) == 0) { ret = -1; @@ -300,7 +302,7 @@ Editor::write_audio_selection (TimeSelection& ts) } bool -Editor::write_audio_range (Playlist& playlist, uint32_t channels, list& range) +Editor::write_audio_range (AudioPlaylist& playlist, uint32_t channels, list& range) { AudioFileSource* fs; const jack_nframes_t chunk_size = 4096; @@ -435,7 +437,7 @@ Editor::write_selection () { if (!selection->time.empty()) { write_audio_selection (selection->time); - } else if (!selection->audio_regions.empty()) { - write_region_selection (selection->audio_regions); + } else if (!selection->regions.empty()) { + write_region_selection (selection->regions); } } diff --git a/gtk2_ardour/editor_items.h b/gtk2_ardour/editor_items.h index 4f6010ec2c..7f3a0d3fcc 100644 --- a/gtk2_ardour/editor_items.h +++ b/gtk2_ardour/editor_items.h @@ -23,8 +23,8 @@ enum ItemType { TempoMarkerItem, MeterBarItem, TempoBarItem, - AudioRegionViewNameHighlight, - AudioRegionViewName, + RegionViewNameHighlight, + RegionViewName, StartSelectionTrimItem, EndSelectionTrimItem, AutomationTrackItem, diff --git a/gtk2_ardour/editor_keyboard.cc b/gtk2_ardour/editor_keyboard.cc index 1ffaf2146d..d2b7c1160e 100644 --- a/gtk2_ardour/editor_keyboard.cc +++ b/gtk2_ardour/editor_keyboard.cc @@ -22,7 +22,7 @@ #include #include "editor.h" -#include "regionview.h" +#include "region_view.h" #include "selection.h" #include "i18n.h" @@ -81,10 +81,10 @@ Editor::kbd_do_split (GdkEvent* ev) jack_nframes_t where = event_frame (ev); if (entered_regionview) { - if (selection->audio_regions.find (entered_regionview) != selection->audio_regions.end()) { - split_regions_at (where, selection->audio_regions); + if (selection->regions.find (entered_regionview) != selection->regions.end()) { + split_regions_at (where, selection->regions); } else { - AudioRegionSelection s; + RegionSelection s; s.add (entered_regionview); split_regions_at (where, s); } @@ -102,11 +102,11 @@ Editor::kbd_mute_unmute_region () { if (entered_regionview) { begin_reversible_command (_("mute region")); - session->add_undo (entered_regionview->region.playlist()->get_memento()); + session->add_undo (entered_regionview->region().playlist()->get_memento()); - entered_regionview->region.set_muted (!entered_regionview->region.muted()); + entered_regionview->region().set_muted (!entered_regionview->region().muted()); - session->add_redo_no_execute (entered_regionview->region.playlist()->get_memento()); + session->add_redo_no_execute (entered_regionview->region().playlist()->get_memento()); commit_reversible_command(); } } @@ -124,7 +124,7 @@ Editor::kbd_do_set_sync_position (GdkEvent* ev) snap_to (where); if (entered_regionview) { - set_a_regions_sync_position (entered_regionview->region, where); + set_a_regions_sync_position (entered_regionview->region(), where); } } diff --git a/gtk2_ardour/editor_keys.cc b/gtk2_ardour/editor_keys.cc index baa158cbf8..1bcaafd279 100644 --- a/gtk2_ardour/editor_keys.cc +++ b/gtk2_ardour/editor_keys.cc @@ -30,7 +30,7 @@ #include "ardour_ui.h" #include "editor.h" #include "time_axis_view.h" -#include "regionview.h" +#include "region_view.h" #include "selection.h" #include "i18n.h" @@ -66,7 +66,7 @@ Editor::keyboard_selection_begin () void Editor::keyboard_duplicate_region () { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } @@ -74,9 +74,9 @@ Editor::keyboard_duplicate_region () bool was_floating; if (get_prefix (prefix, was_floating) == 0) { - duplicate_some_regions (selection->audio_regions, prefix); + duplicate_some_regions (selection->regions, prefix); } else { - duplicate_some_regions (selection->audio_regions, 1); + duplicate_some_regions (selection->regions, 1); } } diff --git a/gtk2_ardour/editor_markers.cc b/gtk2_ardour/editor_markers.cc index a584561e42..f34b8590a4 100644 --- a/gtk2_ardour/editor_markers.cc +++ b/gtk2_ardour/editor_markers.cc @@ -714,9 +714,9 @@ Editor::marker_menu_set_from_selection () } } else { - if (!selection->audio_regions.empty()) { - l->set_start (selection->audio_regions.start()); - l->set_end (selection->audio_regions.end_frame()); + if (!selection->regions.empty()) { + l->set_start (selection->regions.start()); + l->set_end (selection->regions.end_frame()); } } } diff --git a/gtk2_ardour/editor_mixer.cc b/gtk2_ardour/editor_mixer.cc index 1418ece574..246dbdc647 100644 --- a/gtk2_ardour/editor_mixer.cc +++ b/gtk2_ardour/editor_mixer.cc @@ -270,8 +270,6 @@ Editor::session_going_away () group_model->clear (); edit_cursor_clock.set_session (0); - selection_start_clock.set_session (0); - selection_end_clock.set_session (0); zoom_range_clock.set_session (0); nudge_clock.set_session (0); diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 8b6729cc4a..7e9af2dcb0 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -18,6 +18,7 @@ $Id$ */ +#include #include #include #include @@ -32,7 +33,7 @@ #include "editor.h" #include "time_axis_view.h" #include "audio_time_axis.h" -#include "regionview.h" +#include "audio_region_view.h" #include "marker.h" #include "streamview.h" #include "region_gain_line.h" @@ -182,7 +183,7 @@ Editor::set_mouse_mode (MouseMode m, bool force) show the object (region) selection. */ - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { (*i)->set_should_show_selection (true); } for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { @@ -319,8 +320,8 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it commit = (c1 || c2); break; - case AudioRegionViewNameHighlight: - case AudioRegionViewName: + case RegionViewNameHighlight: + case RegionViewName: c1 = set_selected_track_from_click (press, op, true, true); c2 = set_selected_regionview_from_click (press, op, true); commit = (c1 || c2); @@ -521,12 +522,12 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp } break; - case AudioRegionViewNameHighlight: + case RegionViewNameHighlight: start_trim (item, event); return true; break; - case AudioRegionViewName: + case RegionViewName: /* rename happens on edit clicks */ start_trim (clicked_regionview->get_name_highlight(), event); return true; @@ -692,12 +693,12 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp switch (item_type) { - case AudioRegionViewNameHighlight: + case RegionViewNameHighlight: start_trim (item, event); return true; break; - case AudioRegionViewName: + case RegionViewName: start_trim (clicked_regionview->get_name_highlight(), event); return true; break; @@ -853,7 +854,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT edit_meter_marker (item); break; - case AudioRegionViewName: + case RegionViewName: if (clicked_regionview->name_active()) { return mouse_rename_region (item, event); } @@ -888,8 +889,8 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case RegionItem: - case AudioRegionViewNameHighlight: - case AudioRegionViewName: + case RegionViewNameHighlight: + case RegionViewName: popup_track_context_menu (1, event->button.time, item_type, false, where); break; @@ -1047,9 +1048,13 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case MouseGain: + // Gain only makes sense for audio regions + if ( ! dynamic_cast(clicked_regionview)) + break; + switch (item_type) { case RegionItem: - clicked_regionview->add_gain_point_event (item, event); + dynamic_cast(clicked_regionview)->add_gain_point_event (item, event); return true; break; @@ -1203,7 +1208,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } break; - case AudioRegionViewNameHighlight: + case RegionViewNameHighlight: if (is_drawable() && mouse_mode == MouseObject) { track_canvas.get_window()->set_cursor (*trimmer_cursor); } @@ -1230,11 +1235,11 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } break; - case AudioRegionViewName: + case RegionViewName: /* when the name is not an active item, the entire name highlight is for trimming */ - if (!reinterpret_cast (item->get_data ("regionview"))->name_active()) { + if (!reinterpret_cast (item->get_data ("regionview"))->name_active()) { if (mouse_mode == MouseObject && is_drawable()) { track_canvas.get_window()->set_cursor (*trimmer_cursor); } @@ -1339,7 +1344,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ ControlPoint* cp; Marker *marker; Location *loc; - AudioRegionView* rv; + RegionView* rv; bool is_start; switch (item_type) { @@ -1361,7 +1366,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ hide_verbose_canvas_cursor (); break; - case AudioRegionViewNameHighlight: + case RegionViewNameHighlight: case StartSelectionTrimItem: case EndSelectionTrimItem: case EditCursorItem: @@ -1392,9 +1397,9 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } break; - case AudioRegionViewName: + case RegionViewName: /* see enter_handler() for notes */ - if (!reinterpret_cast (item->get_data ("regionview"))->name_active()) { + if (!reinterpret_cast (item->get_data ("regionview"))->name_active()) { if (is_drawable() && mouse_mode == MouseObject) { track_canvas.get_window()->set_cursor (*current_canvas_cursor); } @@ -1429,7 +1434,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case FadeInHandleItem: case FadeOutHandleItem: - rv = static_cast(item->get_data ("regionview")); + rv = static_cast(item->get_data ("regionview")); { ArdourCanvas::SimpleRect *rect = dynamic_cast (item); if (rect) { @@ -1524,7 +1529,7 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item case PanAutomationControlPointItem: case TempoMarkerItem: case MeterMarkerItem: - case AudioRegionViewNameHighlight: + case RegionViewNameHighlight: case StartSelectionTrimItem: case EndSelectionTrimItem: case SelectionItem: @@ -1745,7 +1750,7 @@ Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event) AudioRegionView* arv = static_cast(drag_info.data); - drag_info.pointer_frame_offset = drag_info.grab_frame - ((jack_nframes_t) arv->region.fade_in().back()->when + arv->region.position()); + drag_info.pointer_frame_offset = drag_info.grab_frame - ((jack_nframes_t) arv->audio_region().fade_in().back()->when + arv->region().position()); } void @@ -1766,17 +1771,17 @@ Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) snap_to (pos); } - if (pos < (arv->region.position() + 64)) { + if (pos < (arv->region().position() + 64)) { fade_length = 64; // this should be a minimum defined somewhere - } else if (pos > arv->region.last_frame()) { - fade_length = arv->region.length(); + } else if (pos > arv->region().last_frame()) { + fade_length = arv->region().length(); } else { - fade_length = pos - arv->region.position(); + fade_length = pos - arv->region().position(); } arv->reset_fade_in_shape_width (fade_length); - show_verbose_duration_cursor (arv->region.position(), arv->region.position() + fade_length, 10); + show_verbose_duration_cursor (arv->region().position(), arv->region().position() + fade_length, 10); drag_info.first_move = false; } @@ -1801,20 +1806,20 @@ Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* even snap_to (pos); } - if (pos < (arv->region.position() + 64)) { + if (pos < (arv->region().position() + 64)) { fade_length = 64; // this should be a minimum defined somewhere } - else if (pos > arv->region.last_frame()) { - fade_length = arv->region.length(); + else if (pos > arv->region().last_frame()) { + fade_length = arv->region().length(); } else { - fade_length = pos - arv->region.position(); + fade_length = pos - arv->region().position(); } begin_reversible_command (_("change fade in length")); - session->add_undo (arv->region.get_memento()); - arv->region.set_fade_in_length (fade_length); - session->add_redo_no_execute (arv->region.get_memento()); + session->add_undo (arv->region().get_memento()); + arv->audio_region().set_fade_in_length (fade_length); + session->add_redo_no_execute (arv->region().get_memento()); commit_reversible_command (); fade_in_drag_motion_callback (item, event); } @@ -1835,7 +1840,7 @@ Editor::start_fade_out_grab (ArdourCanvas::Item* item, GdkEvent* event) AudioRegionView* arv = static_cast(drag_info.data); - drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region.length() - (jack_nframes_t) arv->region.fade_out().back()->when + arv->region.position()); + drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region().length() - (jack_nframes_t) arv->audio_region().fade_out().back()->when + arv->region().position()); } void @@ -1856,19 +1861,19 @@ Editor::fade_out_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event snap_to (pos); } - if (pos > (arv->region.last_frame() - 64)) { + if (pos > (arv->region().last_frame() - 64)) { fade_length = 64; // this should really be a minimum fade defined somewhere } - else if (pos < arv->region.position()) { - fade_length = arv->region.length(); + else if (pos < arv->region().position()) { + fade_length = arv->region().length(); } else { - fade_length = arv->region.last_frame() - pos; + fade_length = arv->region().last_frame() - pos; } arv->reset_fade_out_shape_width (fade_length); - show_verbose_duration_cursor (arv->region.last_frame() - fade_length, arv->region.last_frame(), 10); + show_verbose_duration_cursor (arv->region().last_frame() - fade_length, arv->region().last_frame(), 10); drag_info.first_move = false; } @@ -1893,20 +1898,20 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve snap_to (pos); } - if (pos > (arv->region.last_frame() - 64)) { + if (pos > (arv->region().last_frame() - 64)) { fade_length = 64; // this should really be a minimum fade defined somewhere } - else if (pos < arv->region.position()) { - fade_length = arv->region.length(); + else if (pos < arv->region().position()) { + fade_length = arv->region().length(); } else { - fade_length = arv->region.last_frame() - pos; + fade_length = arv->region().last_frame() - pos; } begin_reversible_command (_("change fade out length")); - session->add_undo (arv->region.get_memento()); - arv->region.set_fade_out_length (fade_length); - session->add_redo_no_execute (arv->region.get_memento()); + session->add_undo (arv->region().get_memento()); + arv->audio_region().set_fade_out_length (fade_length); + session->add_redo_no_execute (arv->region().get_memento()); commit_reversible_command (); fade_out_drag_motion_callback (item, event); @@ -2551,7 +2556,8 @@ Editor::start_line_grab_from_regionview (ArdourCanvas::Item* item, GdkEvent* eve { switch (mouse_mode) { case MouseGain: - start_line_grab (clicked_regionview->get_gain_line(), event); + assert(dynamic_cast(clicked_regionview)); + start_line_grab (dynamic_cast(clicked_regionview)->get_gain_line(), event); break; default: break; @@ -2645,7 +2651,7 @@ Editor::line_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) void Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event) { - if (selection->audio_regions.empty() || clicked_regionview == 0) { + if (selection->regions.empty() || clicked_regionview == 0) { return; } @@ -2659,13 +2665,13 @@ Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event) double speed = 1.0; TimeAxisView* tvp = clicked_trackview; - AudioTimeAxisView* tv = dynamic_cast(tvp); + RouteTimeAxisView* tv = dynamic_cast(tvp); if (tv && tv->is_audio_track()) { speed = tv->get_diskstream()->speed(); } - drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed); + drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region().position() / speed); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; drag_info.last_trackview = &clicked_regionview->get_time_axis_view(); // we want a move threshold @@ -2679,7 +2685,7 @@ Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event) void Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) { - if (selection->audio_regions.empty() || clicked_regionview == 0) { + if (selection->regions.empty() || clicked_regionview == 0) { return; } @@ -2690,7 +2696,7 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) start_grab(event); TimeAxisView* tv = &clicked_regionview->get_time_axis_view(); - AudioTimeAxisView* atv = dynamic_cast(tv); + RouteTimeAxisView* atv = dynamic_cast(tv); double speed = 1.0; if (atv && atv->is_audio_track()) { @@ -2698,7 +2704,7 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) } drag_info.last_trackview = &clicked_regionview->get_time_axis_view(); - drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed); + drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region().position() / speed); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; // we want a move threshold drag_info.want_move_threshold = true; @@ -2709,7 +2715,7 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) void Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event) { - if (selection->audio_regions.empty() || clicked_regionview == 0) { + if (selection->regions.empty() || clicked_regionview == 0) { return; } @@ -2723,13 +2729,13 @@ Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event) double speed = 1.0; TimeAxisView* tvp = clicked_trackview; - AudioTimeAxisView* tv = dynamic_cast(tvp); + RouteTimeAxisView* tv = dynamic_cast(tvp); if (tv && tv->is_audio_track()) { speed = tv->get_diskstream()->speed(); } - drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region.position() / speed); + drag_info.last_frame_position = (jack_nframes_t) (clicked_regionview->region().position() / speed); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; drag_info.last_trackview = &clicked_regionview->get_time_axis_view(); // we want a move threshold @@ -2744,7 +2750,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) { double x_delta; double y_delta = 0; - AudioRegionView *rv = reinterpret_cast (drag_info.data); + RegionView* rv = reinterpret_cast (drag_info.data); jack_nframes_t pending_region_position = 0; int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order; int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen @@ -2764,18 +2770,18 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) /* duplicate the region(s) */ - vector new_regionviews; + vector new_regionviews; set affected_playlists; pair::iterator,bool> insert_result; - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { - AudioRegionView* rv; + for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { + RegionView* rv; rv = (*i); - Playlist* to_playlist = rv->region.playlist(); - AudioTimeAxisView* atv = dynamic_cast(&rv->get_time_axis_view()); + Playlist* to_playlist = rv->region().playlist(); + RouteTimeAxisView* atv = dynamic_cast(&rv->get_time_axis_view()); insert_result = affected_playlists.insert (to_playlist); if (insert_result.second) { @@ -2784,18 +2790,21 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) latest_regionview = 0; - sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); + sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); - /* create a new region with the same name. - */ - - AudioRegion* newregion = new AudioRegion (rv->region); + /* create a new region with the same name. */ + // FIXME: ew. need a (virtual) Region::duplicate() or something? + Region* newregion = NULL; + if (dynamic_cast(&rv->region())) + newregion = new AudioRegion (dynamic_cast(rv->region())); + assert(newregion); + /* if the original region was locked, we don't care */ newregion->set_locked (false); - to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region.position() * atv->get_diskstream()->speed())); + to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region().position() * atv->get_diskstream()->speed())); c.disconnect (); @@ -2907,16 +2916,15 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) } } - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { - AudioRegionView* rv2; - rv2 = (*i); + for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { + RegionView* rv2 = (*i); double ix1, ix2, iy1, iy2; int32_t n = 0; rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2); rv2->get_canvas_group()->i2w (ix1, iy1); TimeAxisView* tvp2 = trackview_by_y_position (iy1); - AudioTimeAxisView* atv2 = dynamic_cast(tvp2); + RouteTimeAxisView* atv2 = dynamic_cast(tvp2); if (atv2->order != original_pointer_order) { /* this isn't the pointer track */ @@ -3011,8 +3019,8 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset; - sync_offset = rv->region.sync_offset (sync_dir); - sync_frame = rv->region.adjust_to_sync (pending_region_position); + sync_offset = rv->region().sync_offset (sync_dir); + sync_frame = rv->region().adjust_to_sync (pending_region_position); /* we snap if the snap modifier is not enabled. */ @@ -3031,7 +3039,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) pending_region_position = 0; } - if (pending_region_position > max_frames - rv->region.length()) { + if (pending_region_position > max_frames - rv->region().length()) { pending_region_position = drag_info.last_frame_position; } @@ -3073,14 +3081,11 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) } if (x_delta < 0) { - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { + for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { - AudioRegionView* rv2; - rv2 = (*i); + RegionView* rv2 = (*i); - /* if any regionview is at zero, we need to know so we can - stop further leftward motion. - */ + // If any regionview is at zero, we need to know so we can stop further leftward motion. double ix1, ix2, iy1, iy2; rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2); @@ -3098,12 +3103,11 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) ************************************************************/ pair::iterator,bool> insert_result; - const list& layered_regions = selection->audio_regions.by_layer(); + const list& layered_regions = selection->regions.by_layer(); - for (list::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) { + for (list::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) { - AudioRegionView* rv; - rv = (*i); + RegionView* rv = (*i); double ix1, ix2, iy1, iy2; int32_t temp_pointer_y_span = pointer_y_span; @@ -3184,8 +3188,8 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) if (-x_delta > ix1) { x_delta = -ix1; } - } else if ((x_delta > 0) &&(rv->region.last_frame() > max_frames - x_delta)) { - x_delta = max_frames - rv->region.last_frame(); + } else if ((x_delta > 0) &&(rv->region().last_frame() > max_frames - x_delta)) { + x_delta = max_frames - rv->region().last_frame(); } if (drag_info.first_move) { @@ -3210,7 +3214,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) AudioTimeAxisView* atv = dynamic_cast (&rv->get_time_axis_view()); if (atv && atv->is_audio_track()) { - AudioPlaylist* pl = atv->get_diskstream()->playlist(); + AudioPlaylist* pl = dynamic_cast(atv->get_diskstream()->playlist()); if (pl) { /* only freeze and capture state once */ @@ -3246,11 +3250,11 @@ void Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) { jack_nframes_t where; - AudioRegionView* rv = reinterpret_cast (drag_info.data); + RegionView* rv = reinterpret_cast (drag_info.data); pair::iterator,bool> insert_result; bool nocommit = true; double speed; - AudioTimeAxisView* atv; + RouteTimeAxisView* atv; bool regionview_y_movement; bool regionview_x_movement; @@ -3284,7 +3288,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event speed = atv->get_diskstream()->speed(); } - regionview_x_movement = (drag_info.last_frame_position != (jack_nframes_t) (rv->region.position()/speed)); + regionview_x_movement = (drag_info.last_frame_position != (jack_nframes_t) (rv->region().position()/speed)); regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view()); //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed); @@ -3294,13 +3298,13 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event /* motion between tracks */ - list new_selection; + list new_selection; /* moved to a different audio track. */ - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ) { + for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) { - AudioRegionView* rv2 = (*i); + RegionView* rv2 = (*i); /* the region that used to be in the old playlist is not moved to the new one - we make a copy of it. as a result, @@ -3317,7 +3321,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event /* first, freeze the target tracks */ - for (list::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) { + for (list::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) { Playlist* from_playlist; Playlist* to_playlist; @@ -3329,7 +3333,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event TimeAxisView* tvp2 = trackview_by_y_position (iy1); AudioTimeAxisView* atv2 = dynamic_cast(tvp2); - from_playlist = (*i)->region.playlist(); + from_playlist = (*i)->region().playlist(); to_playlist = atv2->playlist(); /* the from_playlist was frozen in the "first_move" case @@ -3352,7 +3356,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event /* now do it again with the actual operations */ - for (list::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) { + for (list::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) { Playlist* from_playlist; Playlist* to_playlist; @@ -3364,17 +3368,17 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event TimeAxisView* tvp2 = trackview_by_y_position (iy1); AudioTimeAxisView* atv2 = dynamic_cast(tvp2); - from_playlist = (*i)->region.playlist(); + from_playlist = (*i)->region().playlist(); to_playlist = atv2->playlist(); latest_regionview = 0; where = (jack_nframes_t) (unit_to_frame (ix1) * speed); - Region* new_region = createRegion ((*i)->region); + Region* new_region = createRegion ((*i)->region()); - from_playlist->remove_region (&((*i)->region)); + from_playlist->remove_region (&((*i)->region())); - sigc::connection c = atv2->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); + sigc::connection c = atv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); to_playlist->add_region (*new_region, where); c.disconnect (); @@ -3387,11 +3391,11 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event /* motion within a single track */ - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { + for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { rv = (*i); - if (rv->region.locked()) { + if (rv->region().locked()) { continue; } @@ -3413,14 +3417,14 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event } else { - where = rv->region.position(); + where = rv->region().position(); } rv->get_time_axis_view().reveal_dependent_views (*rv); /* no need to add an undo here, we did that when we added this playlist to motion_frozen playlists */ - rv->region.set_position (where, (void *) this); + rv->region().set_position (where, (void *) this); } } @@ -3454,15 +3458,15 @@ Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event) if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) { - align_region (rv.region, SyncPoint, (jack_nframes_t) (edit_cursor->current_frame * speed)); + align_region (rv.region(), SyncPoint, (jack_nframes_t) (edit_cursor->current_frame * speed)); } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) { - align_region (rv.region, End, (jack_nframes_t) (edit_cursor->current_frame * speed)); + align_region (rv.region(), End, (jack_nframes_t) (edit_cursor->current_frame * speed)); } else { - align_region (rv.region, Start, (jack_nframes_t) (edit_cursor->current_frame * speed)); + align_region (rv.region(), Start, (jack_nframes_t) (edit_cursor->current_frame * speed)); } } } @@ -3579,7 +3583,7 @@ Editor::show_verbose_duration_cursor (jack_nframes_t start, jack_nframes_t end, } void -Editor::collect_new_region_view (AudioRegionView* rv) +Editor::collect_new_region_view (RegionView* rv) { latest_regionview = rv; } @@ -3612,7 +3616,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event) */ latest_regionview = 0; - sigc::connection c = clicked_audio_trackview->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); + sigc::connection c = clicked_audio_trackview->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); /* A selection grab currently creates two undo/redo operations, one for creating the new region and another for moving it. @@ -3647,7 +3651,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event) start_grab (event); drag_info.last_trackview = clicked_trackview; - drag_info.last_frame_position = latest_regionview->region.position(); + drag_info.last_frame_position = latest_regionview->region().position(); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; show_verbose_time_cursor (drag_info.last_frame_position, 10); @@ -3888,9 +3892,9 @@ Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event) speed = tv->get_diskstream()->speed(); } - jack_nframes_t region_start = (jack_nframes_t) (clicked_regionview->region.position() / speed); - jack_nframes_t region_end = (jack_nframes_t) (clicked_regionview->region.last_frame() / speed); - jack_nframes_t region_length = (jack_nframes_t) (clicked_regionview->region.length() / speed); + jack_nframes_t region_start = (jack_nframes_t) (clicked_regionview->region().position() / speed); + jack_nframes_t region_end = (jack_nframes_t) (clicked_regionview->region().last_frame() / speed); + jack_nframes_t region_length = (jack_nframes_t) (clicked_regionview->region().length() / speed); motion_frozen_playlists.clear(); @@ -3930,7 +3934,7 @@ Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event) void Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) { - AudioRegionView* rv = clicked_regionview; + RegionView* rv = clicked_regionview; jack_nframes_t frame_delta = 0; bool left_direction; bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()); @@ -3942,7 +3946,7 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) double speed = 1.0; TimeAxisView* tvp = clicked_trackview; - AudioTimeAxisView* tv = dynamic_cast(tvp); + RouteTimeAxisView* tv = dynamic_cast(tvp); pair::iterator,bool> insert_result; if (tv && tv->is_audio_track()) { @@ -3981,11 +3985,14 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) begin_reversible_command (trim_type); - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { - (*i)->region.freeze (); - (*i)->temporarily_hide_envelope (); + for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { + (*i)->region().freeze (); + + AudioRegionView* const arv = dynamic_cast(*i); + if (arv) + arv->temporarily_hide_envelope (); - Playlist * pl = (*i)->region.playlist(); + Playlist * pl = (*i)->region().playlist(); insert_result = motion_frozen_playlists.insert (pl); if (insert_result.second) { session->add_undo (pl->get_memento()); @@ -4001,20 +4008,20 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) switch (trim_op) { case StartTrim: - if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region.first_frame()/speed)) { + if ((left_direction == false) && (drag_info.current_pointer_frame <= rv->region().first_frame()/speed)) { break; } else { - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { + for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { single_start_trim (**i, frame_delta, left_direction, obey_snap); } break; } case EndTrim: - if ((left_direction == true) && (drag_info.current_pointer_frame > (jack_nframes_t) (rv->region.last_frame()/speed))) { + if ((left_direction == true) && (drag_info.current_pointer_frame > (jack_nframes_t) (rv->region().last_frame()/speed))) { break; } else { - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) { + for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { single_end_trim (**i, frame_delta, left_direction, obey_snap); } break; @@ -4028,8 +4035,8 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) swap_direction = true; } - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); - i != selection->audio_regions.by_layer().end(); ++i) + for (list::const_iterator i = selection->regions.by_layer().begin(); + i != selection->regions.by_layer().end(); ++i) { single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap); } @@ -4039,10 +4046,10 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) switch (trim_op) { case StartTrim: - show_verbose_time_cursor((jack_nframes_t) (rv->region.position()/speed), 10); + show_verbose_time_cursor((jack_nframes_t) (rv->region().position()/speed), 10); break; case EndTrim: - show_verbose_time_cursor((jack_nframes_t) (rv->region.last_frame()/speed), 10); + show_verbose_time_cursor((jack_nframes_t) (rv->region().last_frame()/speed), 10); break; case ContentsTrim: show_verbose_time_cursor(drag_info.current_pointer_frame, 10); @@ -4054,9 +4061,9 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) } void -Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap) +Editor::single_contents_trim (RegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool swap_direction, bool obey_snap) { - Region& region (rv.region); + Region& region (rv.region()); if (region.locked()) { return; @@ -4066,7 +4073,7 @@ Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, b double speed = 1.0; TimeAxisView* tvp = clicked_trackview; - AudioTimeAxisView* tv = dynamic_cast(tvp); + RouteTimeAxisView* tv = dynamic_cast(tvp); if (tv && tv->is_audio_track()) { speed = tv->get_diskstream()->speed(); @@ -4094,9 +4101,9 @@ Editor::single_contents_trim (AudioRegionView& rv, jack_nframes_t frame_delta, b } void -Editor::single_start_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap) +Editor::single_start_trim (RegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap) { - Region& region (rv.region); + Region& region (rv.region()); if (region.locked()) { return; @@ -4128,9 +4135,9 @@ Editor::single_start_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool } void -Editor::single_end_trim (AudioRegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap) +Editor::single_end_trim (RegionView& rv, jack_nframes_t frame_delta, bool left_direction, bool obey_snap) { - Region& region (rv.region); + Region& region (rv.region()); if (region.locked()) { return; @@ -4169,8 +4176,8 @@ Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) thaw_region_after_trim (*clicked_regionview); } else { - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); - i != selection->audio_regions.by_layer().end(); ++i) + for (list::const_iterator i = selection->regions.by_layer().begin(); + i != selection->regions.by_layer().end(); ++i) { thaw_region_after_trim (**i); } @@ -4193,7 +4200,7 @@ Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) void Editor::point_trim (GdkEvent* event) { - AudioRegionView* rv = clicked_regionview; + RegionView* rv = clicked_regionview; jack_nframes_t new_bound = drag_info.current_pointer_frame; if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { @@ -4208,22 +4215,22 @@ Editor::point_trim (GdkEvent* event) if (rv->get_selected()) { - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); - i != selection->audio_regions.by_layer().end(); ++i) + for (list::const_iterator i = selection->regions.by_layer().begin(); + i != selection->regions.by_layer().end(); ++i) { - if (!(*i)->region.locked()) { - session->add_undo ((*i)->region.playlist()->get_memento()); - (*i)->region.trim_front (new_bound, this); - session->add_redo_no_execute ((*i)->region.playlist()->get_memento()); + if (!(*i)->region().locked()) { + session->add_undo ((*i)->region().playlist()->get_memento()); + (*i)->region().trim_front (new_bound, this); + session->add_redo_no_execute ((*i)->region().playlist()->get_memento()); } } } else { - if (!rv->region.locked()) { - session->add_undo (rv->region.playlist()->get_memento()); - rv->region.trim_front (new_bound, this); - session->add_redo_no_execute (rv->region.playlist()->get_memento()); + if (!rv->region().locked()) { + session->add_undo (rv->region().playlist()->get_memento()); + rv->region().trim_front (new_bound, this); + session->add_redo_no_execute (rv->region().playlist()->get_memento()); } } @@ -4236,21 +4243,21 @@ Editor::point_trim (GdkEvent* event) if (rv->get_selected()) { - for (list::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) + for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { - if (!(*i)->region.locked()) { - session->add_undo ((*i)->region.playlist()->get_memento()); - (*i)->region.trim_end (new_bound, this); - session->add_redo_no_execute ((*i)->region.playlist()->get_memento()); + if (!(*i)->region().locked()) { + session->add_undo ((*i)->region().playlist()->get_memento()); + (*i)->region().trim_end (new_bound, this); + session->add_redo_no_execute ((*i)->region().playlist()->get_memento()); } } } else { - if (!rv->region.locked()) { - session->add_undo (rv->region.playlist()->get_memento()); - rv->region.trim_end (new_bound, this); - session->add_redo_no_execute (rv->region.playlist()->get_memento()); + if (!rv->region().locked()) { + session->add_undo (rv->region().playlist()->get_memento()); + rv->region().trim_end (new_bound, this); + session->add_redo_no_execute (rv->region().playlist()->get_memento()); } } @@ -4263,9 +4270,9 @@ Editor::point_trim (GdkEvent* event) } void -Editor::thaw_region_after_trim (AudioRegionView& rv) +Editor::thaw_region_after_trim (RegionView& rv) { - Region& region (rv.region); + Region& region (rv.region()); if (region.locked()) { return; @@ -4274,7 +4281,9 @@ Editor::thaw_region_after_trim (AudioRegionView& rv) region.thaw (_("trimmed region")); session->add_redo_no_execute (region.playlist()->get_memento()); - rv.unhide_envelope (); + AudioRegionView* arv = dynamic_cast(&rv); + if (arv) + arv->unhide_envelope (); } void @@ -4664,7 +4673,7 @@ Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event) } } else { - selection->clear_audio_regions(); + selection->clear_regions(); selection->clear_points (); selection->clear_lines (); } @@ -4681,7 +4690,7 @@ Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event) ArdourPrompter prompter (false); prompter.set_prompt (_("Name for region:")); - prompter.set_initial_text (clicked_regionview->region.name()); + prompter.set_initial_text (clicked_regionview->region().name()); prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT); prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); prompter.show_all (); @@ -4690,7 +4699,7 @@ Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event) string str; prompter.get_result(str); if (str.length()) { - clicked_regionview->region.set_name (str); + clicked_regionview->region().set_name (str); } break; } @@ -4712,7 +4721,7 @@ Editor::start_time_fx (ArdourCanvas::Item* item, GdkEvent* event) void Editor::time_fx_motion (ArdourCanvas::Item *item, GdkEvent* event) { - AudioRegionView* rv = clicked_regionview; + RegionView* rv = clicked_regionview; if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { snap_to (drag_info.current_pointer_frame); @@ -4722,8 +4731,8 @@ Editor::time_fx_motion (ArdourCanvas::Item *item, GdkEvent* event) return; } - if (drag_info.current_pointer_frame > rv->region.position()) { - rv->get_time_axis_view().show_timestretch (rv->region.position(), drag_info.current_pointer_frame); + if (drag_info.current_pointer_frame > rv->region().position()) { + rv->get_time_axis_view().show_timestretch (rv->region().position(), drag_info.current_pointer_frame); } drag_info.last_pointer_frame = drag_info.current_pointer_frame; @@ -4741,21 +4750,25 @@ Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event) return; } - jack_nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region.position(); - float percentage = (float) ((double) newlen - (double) clicked_regionview->region.length()) / ((double) newlen) * 100.0f; + jack_nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region().position(); + float percentage = (float) ((double) newlen - (double) clicked_regionview->region().length()) / ((double) newlen) * 100.0f; begin_reversible_command (_("timestretch")); - if (run_timestretch (selection->audio_regions, percentage) == 0) { + if (run_timestretch (selection->regions, percentage) == 0) { session->commit_reversible_command (); } } void -Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos) +Editor::mouse_brush_insert_region (RegionView* rv, jack_nframes_t pos) { /* no brushing without a useful snap setting */ + // FIXME + AudioRegionView* arv = dynamic_cast(rv); + assert(arv); + switch (snap_mode) { case SnapMagnetic: return; /* can't work because it allows region to be placed anywhere */ @@ -4775,11 +4788,11 @@ Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos) /* don't brush a copy over the original */ - if (pos == rv->region.position()) { + if (pos == rv->region().position()) { return; } - AudioTimeAxisView* atv = dynamic_cast(&rv->get_time_axis_view()); + RouteTimeAxisView* atv = dynamic_cast(&arv->get_time_axis_view()); if (atv == 0 || !atv->is_audio_track()) { return; @@ -4789,7 +4802,7 @@ Editor::mouse_brush_insert_region (AudioRegionView* rv, jack_nframes_t pos) double speed = atv->get_diskstream()->speed(); session->add_undo (playlist->get_memento()); - playlist->add_region (*(new AudioRegion (rv->region)), (jack_nframes_t) (pos * speed)); + playlist->add_region (*(new AudioRegion (arv->audio_region())), (jack_nframes_t) (pos * speed)); session->add_redo_no_execute (playlist->get_memento()); // playlist is frozen, so we have to update manually diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index d3845dd26b..bdaeb5aa97 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -51,7 +51,7 @@ #include "audio_time_axis.h" #include "automation_time_axis.h" #include "streamview.h" -#include "regionview.h" +#include "audio_region_view.h" #include "rgb_macros.h" #include "selection_templates.h" #include "selection.h" @@ -186,29 +186,31 @@ Editor::split_region () void Editor::split_region_at (jack_nframes_t where) { - split_regions_at (where, selection->audio_regions); + split_regions_at (where, selection->regions); } void -Editor::split_regions_at (jack_nframes_t where, AudioRegionSelection& regions) +Editor::split_regions_at (jack_nframes_t where, RegionSelection& regions) { begin_reversible_command (_("split")); snap_to (where); - for (AudioRegionSelection::iterator a = regions.begin(); a != regions.end(); ) { + for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) { - AudioRegionSelection::iterator tmp; + RegionSelection::iterator tmp; tmp = a; ++tmp; - Playlist* pl = (*a)->region.playlist(); + Playlist* pl = (*a)->region().playlist(); - _new_regionviews_show_envelope = (*a)->envelope_visible(); + AudioRegionView* const arv = dynamic_cast(*a); + if (arv) + _new_regionviews_show_envelope = arv->envelope_visible(); if (pl) { session->add_undo (pl->get_memento()); - pl->split_region ((*a)->region, where); + pl->split_region ((*a)->region(), where); session->add_redo_no_execute (pl->get_memento()); } @@ -230,7 +232,7 @@ Editor::remove_clicked_region () begin_reversible_command (_("remove region")); session->add_undo (playlist->get_memento()); - playlist->remove_region (&clicked_regionview->region); + playlist->remove_region (&clicked_regionview->region()); session->add_redo_no_execute (playlist->get_memento()); commit_reversible_command (); } @@ -238,7 +240,7 @@ Editor::remove_clicked_region () void Editor::destroy_clicked_region () { - int32_t selected = selection->audio_regions.size(); + int32_t selected = selection->regions.size(); if (!session || clicked_regionview == 0 && selected == 0) { return; @@ -270,29 +272,29 @@ Do you really want to destroy %1 ?"), if (selected > 0) { list r; - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - r.push_back (&(*i)->region); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + r.push_back (&(*i)->region()); } session->destroy_regions (r); } else if (clicked_regionview) { - session->destroy_region (&clicked_regionview->region); + session->destroy_region (&clicked_regionview->region()); } } -AudioRegion * +Region * Editor::select_region_for_operation (int dir, TimeAxisView **tv) { - AudioRegionView* rv; - AudioRegion *region; + RegionView* rv; + Region *region; jack_nframes_t start = 0; if (selection->time.start () == selection->time.end_frame ()) { /* no current selection-> is there a selected regionview? */ - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return 0; } @@ -300,26 +302,26 @@ Editor::select_region_for_operation (int dir, TimeAxisView **tv) region = 0; - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { - rv = *(selection->audio_regions.begin()); + rv = *(selection->regions.begin()); (*tv) = &rv->get_time_axis_view(); - region = &rv->region; + region = &rv->region(); } else if (!selection->tracks.empty()) { (*tv) = selection->tracks.front(); - AudioTimeAxisView* atv; + RouteTimeAxisView* rtv; - if ((atv = dynamic_cast (*tv)) != 0) { + if ((rtv = dynamic_cast (*tv)) != 0) { Playlist *pl; - if ((pl = atv->playlist()) == 0) { + if ((pl = rtv->playlist()) == 0) { return 0; } - region = dynamic_cast (pl->top_region_at (start)); + region = pl->top_region_at (start); } } @@ -391,12 +393,12 @@ Editor::nudge_forward (bool next) if (!session) return; - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { begin_reversible_command (_("nudge forward")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - AudioRegion& r ((*i)->region); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + Region& r ((*i)->region()); distance = get_nudge_distance (r.position(), next_distance); @@ -425,12 +427,12 @@ Editor::nudge_backward (bool next) if (!session) return; - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { begin_reversible_command (_("nudge forward")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - AudioRegion& r ((*i)->region); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + Region& r ((*i)->region()); distance = get_nudge_distance (r.position(), next_distance); @@ -469,14 +471,14 @@ Editor::nudge_forward_capture_offset () if (!session) return; - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { begin_reversible_command (_("nudge forward")); distance = session->worst_output_latency(); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - AudioRegion& r ((*i)->region); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + Region& r ((*i)->region()); session->add_undo (r.playlist()->get_memento()); r.set_position (r.position() + distance, this); @@ -495,14 +497,14 @@ Editor::nudge_backward_capture_offset () if (!session) return; - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { begin_reversible_command (_("nudge forward")); distance = session->worst_output_latency(); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - AudioRegion& r ((*i)->region); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + Region& r ((*i)->region()); session->add_undo (r.playlist()->get_memento()); @@ -782,8 +784,8 @@ Editor::cursor_to_selection_start (Cursor *cursor) jack_nframes_t pos = 0; switch (mouse_mode) { case MouseObject: - if (!selection->audio_regions.empty()) { - pos = selection->audio_regions.start(); + if (!selection->regions.empty()) { + pos = selection->regions.start(); } break; @@ -811,8 +813,8 @@ Editor::cursor_to_selection_end (Cursor *cursor) switch (mouse_mode) { case MouseObject: - if (!selection->audio_regions.empty()) { - pos = selection->audio_regions.end_frame(); + if (!selection->regions.empty()) { + pos = selection->regions.end_frame(); } break; @@ -1310,12 +1312,12 @@ Editor::add_location_from_playhead_cursor () void Editor::add_location_from_audio_region () { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } - AudioRegionView* rv = *(selection->audio_regions.begin()); - Region& region = rv->region; + RegionView* rv = *(selection->regions.begin()); + Region& region = rv->region(); Location *location = new Location (region.position(), region.last_frame(), region.name()); session->begin_reversible_command (_("add marker")); @@ -1442,12 +1444,12 @@ Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, void Editor::set_selection_from_audio_region () { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } - AudioRegionView* rv = *(selection->audio_regions.begin()); - Region& region = rv->region; + RegionView* rv = *(selection->regions.begin()); + Region& region = rv->region(); begin_reversible_command (_("set selection from region")); selection->set (0, region.position(), region.last_frame()); @@ -1827,13 +1829,13 @@ Editor::insert_region_list_drag (AudioRegion& region, int x, int y) void Editor::insert_region_list_selection (float times) { - AudioTimeAxisView *tv = 0; + RouteTimeAxisView *tv = 0; Playlist *playlist; if (clicked_audio_trackview != 0) { tv = clicked_audio_trackview; } else if (!selection->tracks.empty()) { - if ((tv = dynamic_cast(selection->tracks.front())) == 0) { + if ((tv = dynamic_cast(selection->tracks.front())) == 0) { return; } } else { @@ -1928,23 +1930,23 @@ Editor::play_selection () void Editor::play_selected_region () { - if (!selection->audio_regions.empty()) { - AudioRegionView *rv = *(selection->audio_regions.begin()); + if (!selection->regions.empty()) { + RegionView *rv = *(selection->regions.begin()); - session->request_bounded_roll (rv->region.position(), rv->region.last_frame()); + session->request_bounded_roll (rv->region().position(), rv->region().last_frame()); } } void Editor::loop_selected_region () { - if (!selection->audio_regions.empty()) { - AudioRegionView *rv = *(selection->audio_regions.begin()); + if (!selection->regions.empty()) { + RegionView *rv = *(selection->regions.begin()); Location* tll; if ((tll = transport_loop_location()) != 0) { - tll->set (rv->region.position(), rv->region.last_frame()); + tll->set (rv->region().position(), rv->region().last_frame()); // enable looping, reposition and start rolling @@ -1987,10 +1989,10 @@ void Editor::toggle_region_mute () { if (clicked_regionview) { - clicked_regionview->region.set_muted (!clicked_regionview->region.muted()); - } else if (!selection->audio_regions.empty()) { - bool yn = ! (*selection->audio_regions.begin())->region.muted(); - selection->foreach_audio_region (&AudioRegion::set_muted, yn); + clicked_regionview->region().set_muted (!clicked_regionview->region().muted()); + } else if (!selection->regions.empty()) { + bool yn = ! (*selection->regions.begin())->region().muted(); + selection->foreach_region (&Region::set_muted, yn); } } @@ -1998,35 +2000,35 @@ void Editor::toggle_region_opaque () { if (clicked_regionview) { - clicked_regionview->region.set_opaque (!clicked_regionview->region.opaque()); - } else if (!selection->audio_regions.empty()) { - bool yn = ! (*selection->audio_regions.begin())->region.opaque(); - selection->foreach_audio_region (&Region::set_opaque, yn); + clicked_regionview->region().set_opaque (!clicked_regionview->region().opaque()); + } else if (!selection->regions.empty()) { + bool yn = ! (*selection->regions.begin())->region().opaque(); + selection->foreach_region (&Region::set_opaque, yn); } } void Editor::raise_region () { - selection->foreach_audio_region (&Region::raise); + selection->foreach_region (&Region::raise); } void Editor::raise_region_to_top () { - selection->foreach_audio_region (&Region::raise_to_top); + selection->foreach_region (&Region::raise_to_top); } void Editor::lower_region () { - selection->foreach_audio_region (&Region::lower); + selection->foreach_region (&Region::lower); } void Editor::lower_region_to_bottom () { - selection->foreach_audio_region (&Region::lower_to_bottom); + selection->foreach_region (&Region::lower_to_bottom); } void @@ -2047,7 +2049,7 @@ Editor::rename_region () Button ok_button (_("OK")); Button cancel_button (_("Cancel")); - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } @@ -2078,7 +2080,7 @@ Editor::rename_region () Main::run (); if (region_renamed) { - (*selection->audio_regions.begin())->region.set_name (entry.get_text()); + (*selection->regions.begin())->region().set_name (entry.get_text()); redisplay_regions (); } } @@ -2092,7 +2094,7 @@ Editor::rename_region_finished (bool status) } void -Editor::audition_playlist_region_via_route (AudioRegion& region, Route& route) +Editor::audition_playlist_region_via_route (Region& region, Route& route) { if (session->is_auditioning()) { session->cancel_audition (); @@ -2113,14 +2115,14 @@ Editor::audition_playlist_region_via_route (AudioRegion& region, Route& route) void Editor::audition_selected_region () { - if (!selection->audio_regions.empty()) { - AudioRegionView* rv = *(selection->audio_regions.begin()); - session->audition_region (rv->region); + if (!selection->regions.empty()) { + RegionView* rv = *(selection->regions.begin()); + session->audition_region (rv->region()); } } void -Editor::audition_playlist_region_standalone (AudioRegion& region) +Editor::audition_playlist_region_standalone (Region& region) { session->audition_region (region); } @@ -2170,7 +2172,6 @@ Editor::region_from_selection () jack_nframes_t selection_cnt = end - start + 1; for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - AudioRegion *region; AudioRegion *current; Region* current_r; @@ -2187,7 +2188,9 @@ Editor::region_from_selection () continue; } - if ((current = dynamic_cast (current_r)) != 0) { + current = dynamic_cast (current_r); + // FIXME: audio only + if (current != 0) { internal_start = start - current->position(); session->region_name (new_name, current->name(), true); region = new AudioRegion (*current, internal_start, selection_cnt, new_name); @@ -2237,11 +2240,13 @@ Editor::split_multichannel_region () { vector v; - if (!clicked_regionview || clicked_regionview->region.n_channels() < 2) { + AudioRegionView* clicked_arv = dynamic_cast(clicked_regionview); + + if (!clicked_arv || clicked_arv->audio_region().n_channels() < 2) { return; } - clicked_regionview->region.separate_by_channel (*session, v); + clicked_arv->audio_region().separate_by_channel (*session, v); /* nothing else to do, really */ } @@ -2419,7 +2424,7 @@ Editor::region_fill_track () { jack_nframes_t end; - if (!session || selection->audio_regions.empty()) { + if (!session || selection->regions.empty()) { return; } @@ -2427,9 +2432,15 @@ Editor::region_fill_track () begin_reversible_command (_("region fill")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + + Region& region ((*i)->region()); + + // FIXME + AudioRegion* const ar = dynamic_cast(®ion); + if (!ar) + continue; - AudioRegion& region ((*i)->region); Playlist* pl = region.playlist(); if (end <= region.last_frame()) { @@ -2443,7 +2454,7 @@ Editor::region_fill_track () } session->add_undo (pl->get_memento()); - pl->add_region (*(new AudioRegion (region)), region.last_frame(), times); + pl->add_region (*(new AudioRegion (*ar)), ar->last_frame(), times); session->add_redo_no_execute (pl->get_memento()); } @@ -2522,12 +2533,12 @@ Editor::set_region_sync_from_edit_cursor () return; } - if (!clicked_regionview->region.covers (edit_cursor->current_frame)) { + if (!clicked_regionview->region().covers (edit_cursor->current_frame)) { error << _("Place the edit cursor at the desired sync point") << endmsg; return; } - Region& region (clicked_regionview->region); + Region& region (clicked_regionview->region()); begin_reversible_command (_("set sync from edit cursor")); session->add_undo (region.playlist()->get_memento()); region.set_sync_position (edit_cursor->current_frame); @@ -2539,7 +2550,7 @@ void Editor::remove_region_sync () { if (clicked_regionview) { - Region& region (clicked_regionview->region); + Region& region (clicked_regionview->region()); begin_reversible_command (_("remove sync")); session->add_undo (region.playlist()->get_memento()); region.clear_sync_position (); @@ -2551,14 +2562,14 @@ Editor::remove_region_sync () void Editor::naturalize () { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } begin_reversible_command (_("naturalize")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - session->add_undo ((*i)->region.get_memento()); - (*i)->region.move_to_natural_position (this); - session->add_redo_no_execute ((*i)->region.get_memento()); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + session->add_undo ((*i)->region().get_memento()); + (*i)->region().move_to_natural_position (this); + session->add_redo_no_execute ((*i)->region().get_memento()); } commit_reversible_command (); } @@ -2577,14 +2588,14 @@ Editor::align_relative (RegionPoint what) struct RegionSortByTime { bool operator() (const AudioRegionView* a, const AudioRegionView* b) { - return a->region.position() < b->region.position(); + return a->region().position() < b->region().position(); } }; void Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } @@ -2592,9 +2603,9 @@ Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) jack_nframes_t pos = 0; int dir; - list sorted; - selection->audio_regions.by_position (sorted); - Region& r ((*sorted.begin())->region); + list sorted; + selection->regions.by_position (sorted); + Region& r ((*sorted.begin())->region()); switch (point) { case Start: @@ -2620,9 +2631,9 @@ Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) begin_reversible_command (_("align selection (relative)")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { - Region& region ((*i)->region); + Region& region ((*i)->region()); session->add_undo (region.playlist()->get_memento()); @@ -2642,14 +2653,14 @@ Editor::align_selection_relative (RegionPoint point, jack_nframes_t position) void Editor::align_selection (RegionPoint point, jack_nframes_t position) { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } begin_reversible_command (_("align selection")); - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - align_region_internal ((*i)->region, point, position); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + align_region_internal ((*i)->region(), point, position); } commit_reversible_command (); @@ -2694,7 +2705,7 @@ Editor::trim_region_to_edit_cursor () return; } - Region& region (clicked_regionview->region); + Region& region (clicked_regionview->region()); float speed = 1.0f; AudioTimeAxisView *atav; @@ -2719,7 +2730,7 @@ Editor::trim_region_from_edit_cursor () return; } - Region& region (clicked_regionview->region); + Region& region (clicked_regionview->region()); float speed = 1.0f; AudioTimeAxisView *atav; @@ -2890,16 +2901,16 @@ Editor::cut_copy (CutCopyOp op) switch (current_mouse_mode()) { case MouseObject: - if (!selection->audio_regions.empty() || !selection->points.empty()) { + if (!selection->regions.empty() || !selection->points.empty()) { begin_reversible_command (opname + _(" objects")); - if (!selection->audio_regions.empty()) { + if (!selection->regions.empty()) { cut_copy_regions (op); if (op == Cut) { - selection->clear_audio_regions (); + selection->clear_regions (); } } @@ -2956,11 +2967,11 @@ Editor::cut_copy_regions (CutCopyOp op) set freezelist; pair::iterator,bool> insert_result; - for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ++x) { - first_position = min ((*x)->region.position(), first_position); + for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) { + first_position = min ((*x)->region().position(), first_position); if (op == Cut || op == Clear) { - AudioPlaylist *pl = dynamic_cast((*x)->region.playlist()); + AudioPlaylist *pl = dynamic_cast((*x)->region().playlist()); if (pl) { insert_result = freezelist.insert (pl); if (insert_result.second) { @@ -2971,11 +2982,11 @@ Editor::cut_copy_regions (CutCopyOp op) } } - for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ) { + for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) { - AudioPlaylist *pl = dynamic_cast((*x)->region.playlist()); + AudioPlaylist *pl = dynamic_cast((*x)->region().playlist()); AudioPlaylist* npl; - AudioRegionSelection::iterator tmp; + RegionSelection::iterator tmp; tmp = x; ++tmp; @@ -2992,18 +3003,24 @@ Editor::cut_copy_regions (CutCopyOp op) npl = pi->second; } + // FIXME + AudioRegion* const ar = dynamic_cast(&(*x)->region()); switch (op) { case Cut: - npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position); - pl->remove_region (&((*x)->region)); + if (!ar) break; + + npl->add_region (*(new AudioRegion (*ar)), (*x)->region().position() - first_position); + pl->remove_region (&((*x)->region())); break; case Copy: - npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position); + if (!ar) break; + + npl->add_region (*(new AudioRegion (*ar)), (*x)->region().position() - first_position); break; case Clear: - pl->remove_region (&((*x)->region)); + pl->remove_region (&((*x)->region())); break; } } @@ -3149,24 +3166,24 @@ Editor::paste_named_selection (float times) } void -Editor::duplicate_some_regions (AudioRegionSelection& regions, float times) +Editor::duplicate_some_regions (RegionSelection& regions, float times) { Playlist *playlist; - AudioRegionSelection sel = regions; // clear (below) will clear the argument list + RegionSelection sel = regions; // clear (below) will clear the argument list begin_reversible_command (_("duplicate region")); - selection->clear_audio_regions (); + selection->clear_regions (); - for (AudioRegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) { + for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) { - Region& r ((*i)->region); + Region& r ((*i)->region()); TimeAxisView& tv = (*i)->get_time_axis_view(); AudioTimeAxisView* atv = dynamic_cast (&tv); - sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); + sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); - playlist = (*i)->region.playlist(); + playlist = (*i)->region().playlist(); session->add_undo (playlist->get_memento()); playlist->duplicate (r, r.last_frame(), times); session->add_redo_no_execute (playlist->get_memento()); @@ -3336,7 +3353,7 @@ Editor::normalize_region () return; } - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } @@ -3345,10 +3362,13 @@ Editor::normalize_region () track_canvas.get_window()->set_cursor (*wait_cursor); gdk_flush (); - for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) { - session->add_undo ((*r)->region.get_memento()); - (*r)->region.normalize_to (0.0f); - session->add_redo_no_execute ((*r)->region.get_memento()); + for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) { + AudioRegionView* const arv = dynamic_cast(*r); + if (!arv) + continue; + session->add_undo (arv->region().get_memento()); + arv->audio_region().normalize_to (0.0f); + session->add_redo_no_execute (arv->region().get_memento()); } commit_reversible_command (); @@ -3363,16 +3383,19 @@ Editor::denormalize_region () return; } - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } begin_reversible_command ("denormalize"); - for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) { - session->add_undo ((*r)->region.get_memento()); - (*r)->region.set_scale_amplitude (1.0f); - session->add_redo_no_execute ((*r)->region.get_memento()); + for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) { + AudioRegionView* const arv = dynamic_cast(*r); + if (!arv) + continue; + session->add_undo (arv->region().get_memento()); + arv->audio_region().set_scale_amplitude (1.0f); + session->add_redo_no_execute (arv->region().get_memento()); } commit_reversible_command (); @@ -3393,7 +3416,7 @@ Editor::reverse_region () void Editor::apply_filter (AudioFilter& filter, string command) { - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { return; } @@ -3402,20 +3425,22 @@ Editor::apply_filter (AudioFilter& filter, string command) track_canvas.get_window()->set_cursor (*wait_cursor); gdk_flush (); - for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ) { + for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) { + AudioRegionView* const arv = dynamic_cast(*r); + if (!arv) + continue; - AudioRegion& region ((*r)->region); - Playlist* playlist = region.playlist(); + Playlist* playlist = arv->region().playlist(); - AudioRegionSelection::iterator tmp; + RegionSelection::iterator tmp; tmp = r; ++tmp; - if (region.apply (filter) == 0) { + if (arv->audio_region().apply (filter) == 0) { session->add_undo (playlist->get_memento()); - playlist->replace_region (region, *(filter.results.front()), region.position()); + playlist->replace_region (arv->region(), *(filter.results.front()), arv->region().position()); session->add_redo_no_execute (playlist->get_memento()); } else { goto out; @@ -3425,7 +3450,7 @@ Editor::apply_filter (AudioFilter& filter, string command) } commit_reversible_command (); - selection->audio_regions.clear (); + selection->regions.clear (); out: track_canvas.get_window()->set_cursor (*current_canvas_cursor); @@ -3434,8 +3459,8 @@ Editor::apply_filter (AudioFilter& filter, string command) void Editor::region_selection_op (void (Region::*pmf)(void)) { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - ((*i)->region.*pmf)(); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + ((*i)->region().*pmf)(); } } @@ -3443,16 +3468,16 @@ Editor::region_selection_op (void (Region::*pmf)(void)) void Editor::region_selection_op (void (Region::*pmf)(void*), void *arg) { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - ((*i)->region.*pmf)(arg); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + ((*i)->region().*pmf)(arg); } } void Editor::region_selection_op (void (Region::*pmf)(bool), bool yn) { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - ((*i)->region.*pmf)(yn); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + ((*i)->region().*pmf)(yn); } } @@ -3469,20 +3494,20 @@ Editor::external_edit_region () void Editor::brush (jack_nframes_t pos) { - AudioRegionSelection sel; + RegionSelection sel; snap_to (pos); - if (selection->audio_regions.empty()) { + if (selection->regions.empty()) { /* XXX get selection from region list */ } else { - sel = selection->audio_regions; + sel = selection->regions; } if (sel.empty()) { return; } - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { mouse_brush_insert_region ((*i), pos); } } @@ -3490,18 +3515,19 @@ Editor::brush (jack_nframes_t pos) void Editor::toggle_gain_envelope_visibility () { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - (*i)->set_envelope_visible (!(*i)->envelope_visible()); + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + AudioRegionView* const arv = dynamic_cast(*i); + if (arv) + arv->set_envelope_visible (!arv->envelope_visible()); } } void Editor::toggle_gain_envelope_active () { - for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) { - AudioRegion* ar = dynamic_cast(&(*i)->region); - if (ar) { - ar->set_envelope_active (true); - } + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { + AudioRegionView* const arv = dynamic_cast(*i); + if (arv) + arv->audio_region().set_envelope_active (true); } } diff --git a/gtk2_ardour/editor_route_list.cc b/gtk2_ardour/editor_route_list.cc index 12240dfb13..c93cf9aba2 100644 --- a/gtk2_ardour/editor_route_list.cc +++ b/gtk2_ardour/editor_route_list.cc @@ -38,16 +38,11 @@ using namespace ARDOUR; using namespace PBD; using namespace Gtk; -void -Editor::handle_new_route_p (boost::shared_ptr route) -{ - ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route_p), route)); - handle_new_route (route); -} - void Editor::handle_new_route (boost::shared_ptr route) { + ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), route)); + TimeAxisView *tv; AudioTimeAxisView *atv; TreeModel::Row parent; diff --git a/gtk2_ardour/editor_timefx.cc b/gtk2_ardour/editor_timefx.cc index 278ab57ebd..79772090f6 100644 --- a/gtk2_ardour/editor_timefx.cc +++ b/gtk2_ardour/editor_timefx.cc @@ -28,7 +28,7 @@ #include "editor.h" #include "audio_time_axis.h" -#include "regionview.h" +#include "audio_region_view.h" #include "region_selection.h" #include @@ -100,7 +100,7 @@ Editor::TimeStretchDialog::delete_timestretch_in_progress (GdkEventAny* ev) } int -Editor::run_timestretch (AudioRegionSelection& regions, float fraction) +Editor::run_timestretch (RegionSelection& regions, float fraction) { pthread_t thread; @@ -157,39 +157,42 @@ Editor::run_timestretch (AudioRegionSelection& regions, float fraction) void Editor::do_timestretch (TimeStretchDialog& dialog) { - AudioTrack* at; + Track* t; Playlist* playlist; - AudioRegion* new_region; + Region* new_region; - for (AudioRegionSelection::iterator i = dialog.regions.begin(); i != dialog.regions.end(); ) { + for (RegionSelection::iterator i = dialog.regions.begin(); i != dialog.regions.end(); ) { + AudioRegionView* arv = dynamic_cast(*i); + if (!arv) + continue; - AudioRegion& aregion ((*i)->region); - TimeAxisView* tv = &(*i)->get_time_axis_view(); - AudioTimeAxisView* atv; - AudioRegionSelection::iterator tmp; + AudioRegion& region (arv->audio_region()); + TimeAxisView* tv = &(arv->get_time_axis_view()); + RouteTimeAxisView* rtv; + RegionSelection::iterator tmp; - cerr << "stretch " << aregion.name() << endl; + cerr << "stretch " << region.name() << endl; tmp = i; ++tmp; - if ((atv = dynamic_cast (tv)) == 0) { + if ((rtv = dynamic_cast (tv)) == 0) { i = tmp; continue; } - if ((at = atv->audio_track()) == 0) { + if ((t = dynamic_cast (rtv->route().get())) == 0) { i = tmp; continue; } - if ((playlist = at->disk_stream().playlist()) == 0) { + if ((playlist = t->diskstream().playlist()) == 0) { i = tmp; continue; } - dialog.request.region = &aregion; + dialog.request.region = ®ion; if (!dialog.request.running) { /* we were cancelled */ @@ -204,7 +207,7 @@ Editor::do_timestretch (TimeStretchDialog& dialog) } session->add_undo (playlist->get_memento()); - playlist->replace_region (aregion, *new_region, aregion.position()); + playlist->replace_region (region, *new_region, region.position()); session->add_redo_no_execute (playlist->get_memento()); i = tmp; diff --git a/gtk2_ardour/export_region_dialog.cc b/gtk2_ardour/export_region_dialog.cc index 97bf7c22b1..1964fabbfe 100644 --- a/gtk2_ardour/export_region_dialog.cc +++ b/gtk2_ardour/export_region_dialog.cc @@ -18,6 +18,8 @@ */ +#include + #include #include @@ -26,11 +28,13 @@ #include "i18n.h" -ExportRegionDialog::ExportRegionDialog (PublicEditor& editor, ARDOUR::AudioRegion* region) +ExportRegionDialog::ExportRegionDialog (PublicEditor& editor, ARDOUR::Region* region) : ExportDialog(editor) { - audio_region = region; - + // FIXME + ARDOUR::AudioRegion* audio_region = dynamic_cast(region); + assert(audio_region); + do_not_allow_track_and_master_selection(); do_not_allow_channel_count_selection(); } diff --git a/gtk2_ardour/export_region_dialog.h b/gtk2_ardour/export_region_dialog.h index 00464eb5b3..e8afe97d6b 100644 --- a/gtk2_ardour/export_region_dialog.h +++ b/gtk2_ardour/export_region_dialog.h @@ -27,7 +27,7 @@ class ExportRegionDialog : public ExportDialog { public: - ExportRegionDialog (PublicEditor&, ARDOUR::AudioRegion*); + ExportRegionDialog (PublicEditor&, ARDOUR::Region*); static void* _export_region_thread (void *); void export_region (); diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 1313fc4082..4f3dc720d9 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -290,8 +290,8 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr rt _route->panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan)); if (is_audio_track()) { - audio_track()->diskstream_changed.connect (mem_fun(*this, &MixerStrip::diskstream_changed)); - get_diskstream()->speed_changed.connect (mem_fun(*this, &MixerStrip::speed_changed)); + audio_track()->DiskstreamChanged.connect (mem_fun(*this, &MixerStrip::diskstream_changed)); + get_diskstream()->SpeedChanged.connect (mem_fun(*this, &MixerStrip::speed_changed)); } _route->name_changed.connect (mem_fun(*this, &RouteUI::name_changed)); @@ -558,11 +558,6 @@ MixerStrip::input_press (GdkEventButton *ev) case 1: -#if ADVANCED_ROUTE_DISKSTREAM_CONNECTIVITY - if (is_audio_track()) { - citems.push_back (MenuElem (_("Track"), mem_fun(*this, &MixerStrip::select_stream_input))); - } -#endif citems.push_back (MenuElem (_("Edit"), mem_fun(*this, &MixerStrip::edit_input_configuration))); citems.push_back (SeparatorElem()); citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast(this)), &RouteUI::disconnect_input))); @@ -659,42 +654,6 @@ MixerStrip::add_connection_to_output_menu (ARDOUR::Connection* c) } } -void -MixerStrip::select_stream_input () -{ - using namespace Menu_Helpers; - - Menu *stream_menu = manage (new Menu); - MenuList& items = stream_menu->items(); - stream_menu->set_name ("ArdourContextMenu"); - - Session::AudioDiskstreamList streams = _session.audio_disk_streams(); - - for (Session::AudioDiskstreamList::iterator i = streams.begin(); i != streams.end(); ++i) { - - if (!(*i)->hidden()) { - - items.push_back (CheckMenuElem ((*i)->name(), bind (mem_fun(*this, &MixerStrip::stream_input_chosen), *i))); - - if (get_diskstream() == *i) { - ignore_toggle = true; - static_cast (&items.back())->set_active (true); - ignore_toggle = false; - } - } - } - - stream_menu->popup (1, 0); -} - -void -MixerStrip::stream_input_chosen (AudioDiskstream *stream) -{ - if (is_audio_track()) { - audio_track()->set_diskstream (*stream, this); - } -} - void MixerStrip::update_diskstream_display () { @@ -785,7 +744,7 @@ MixerStrip::fast_update () } void -MixerStrip::diskstream_changed (void *src) +MixerStrip::diskstream_changed () { Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_diskstream_display)); } @@ -1181,7 +1140,7 @@ MixerStrip::route_active_changed () gpm.set_meter_strip_name ("AudioTrackStripBaseInactive"); } gpm.set_fader_name ("AudioTrackFader"); - } else { + } else { // FIXME: assumed audio bus if (_route->active()) { set_name ("AudioBusStripBase"); gpm.set_meter_strip_name ("AudioBusStripBase"); diff --git a/gtk2_ardour/mixer_strip.h b/gtk2_ardour/mixer_strip.h index e7b68ade48..831b75eeaf 100644 --- a/gtk2_ardour/mixer_strip.h +++ b/gtk2_ardour/mixer_strip.h @@ -179,7 +179,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox void edit_input_configuration (); void edit_output_configuration (); - void diskstream_changed (void *src); + void diskstream_changed (); Gtk::Menu *send_action_menu; void build_send_action_menu (); diff --git a/gtk2_ardour/pixmaps/tool_audition.xpm b/gtk2_ardour/pixmaps/tool_audition.xpm new file mode 100644 index 0000000000..d6f2ccd127 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_audition.xpm @@ -0,0 +1,19 @@ +/* XPM */ +static char * tool_audition_xpm[] = { +"16 12 4 1", +" c None", +". c #000000", +"+ c #ECECEC", +"@ c #FFFFFF", +" .. ", +" .+. . ", +" .++. .@. ", +"....+@+... .@. ", +".+++@@+..@. .@.", +".+@@@@+. .@. .@.", +".+@@@@+. .@. .@.", +".+++@@+..@. .@.", +"....+@+... .@. ", +" .++. .@. ", +" .+. . ", +" .. "}; diff --git a/gtk2_ardour/pixmaps/tool_gain.xpm b/gtk2_ardour/pixmaps/tool_gain.xpm new file mode 100644 index 0000000000..480426fab8 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_gain.xpm @@ -0,0 +1,18 @@ +/* XPM */ +static char * tool_gain_xpm[] = { +"16 12 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"... ", +".++.. ", +"...++. ", +" ..+. ", +" .+. ", +" .+. ", +" .+. ", +" .+. ", +" .+.. ", +" .++.....", +" ..++++.", +" ....."}; diff --git a/gtk2_ardour/pixmaps/tool_object.xpm b/gtk2_ardour/pixmaps/tool_object.xpm new file mode 100644 index 0000000000..3d18ab8af7 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_object.xpm @@ -0,0 +1,18 @@ +/* XPM */ +static char * tool_object_xpm[] = { +"16 12 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +" ... ", +" .+. ", +" .+. ", +" .+. ", +" .+..... ", +" .+.+.+... ", +" ...+.+.+.+. ", +" .+.+++++++. ", +" .+++++++++. ", +" ..+++++++.. ", +" ...+++++. ", +" .+++++. "}; diff --git a/gtk2_ardour/pixmaps/tool_range.xpm b/gtk2_ardour/pixmaps/tool_range.xpm new file mode 100644 index 0000000000..75ee865ca2 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_range.xpm @@ -0,0 +1,18 @@ +/* XPM */ +static char * tool_range_xpm[] = { +"16 12 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"... ...", +".+. .. .. .+.", +".+. .+. .+. .+.", +".+..+. .+..+.", +".+.++......++.+.", +".++++++++++++++.", +".+.++......++.+.", +".+..+. .+..+.", +".+. .+. .+. .+.", +".+. .. .. .+.", +".+. .+.", +"... ..."}; diff --git a/gtk2_ardour/pixmaps/tool_stretch.xpm b/gtk2_ardour/pixmaps/tool_stretch.xpm new file mode 100644 index 0000000000..77943cd7d4 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_stretch.xpm @@ -0,0 +1,18 @@ +/* XPM */ +static char * tool_stretch_xpm[] = { +"16 12 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +" .. .. ", +" .+. .+. ", +".++..........++.", +"++++++++++++++++", +".++..........++.", +" .+. .+. ", +" .. .. ", +" + + + + ", +" ++ +++ + + +++ ", +"++++++++++++++++", +" ++ + ++ + + ", +" + + + + "}; diff --git a/gtk2_ardour/pixmaps/tool_zoom.xpm b/gtk2_ardour/pixmaps/tool_zoom.xpm new file mode 100644 index 0000000000..581363f3f4 --- /dev/null +++ b/gtk2_ardour/pixmaps/tool_zoom.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char * tool_zoom_xpm[] = { +"16 12 14 1", +" c None", +". c #000000", +"+ c #474747", +"@ c #E7E7E7", +"# c #F6F6F6", +"$ c #DCDCDC", +"% c #FFFFFF", +"& c #DFDFDF", +"* c #D7D7D7", +"= c #D6D6D6", +"- c #040404", +"; c #070707", +"> c #060606", +", c #050505", +" ... ", +" +.@#$.+ ", +" .%%%%%. ", +" .&%%%%%*. ", +" .#%%%%%#. ", +" .$%%%%%&. ", +" .%%%%%.+ ", +" +.*#=... ", +" ...+... ", +" -.; ", +" >.- ", +" ,. "}; diff --git a/gtk2_ardour/pixmaps/zoom_full.xpm b/gtk2_ardour/pixmaps/zoom_full.xpm new file mode 100644 index 0000000000..5564074875 --- /dev/null +++ b/gtk2_ardour/pixmaps/zoom_full.xpm @@ -0,0 +1,30 @@ +/* XPM */ +static char * zoom_full_xpm[] = { +"12 12 15 1", +" c None", +". c #000000", +"+ c #474747", +"@ c #E7E7E7", +"# c #F6F6F6", +"$ c #DCDCDC", +"% c #ACACAC", +"& c #FFFFFF", +"* c #DFDFDF", +"= c #D7D7D7", +"- c #D6D6D6", +"; c #040404", +"> c #070707", +", c #060606", +"' c #050505", +" ... ", +" +.@#$.+ ", +" .%&&&%. ", +".*..&..=. ", +".#.&&&.#. ", +".$..&..*. ", +" .%&&&%.+ ", +" +.=#-... ", +" ...+... ", +" ;.> ", +" ,.;", +" '."}; diff --git a/gtk2_ardour/pixmaps/zoom_in.xpm b/gtk2_ardour/pixmaps/zoom_in.xpm new file mode 100644 index 0000000000..1f8d4e8273 --- /dev/null +++ b/gtk2_ardour/pixmaps/zoom_in.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char * zoom_in_xpm[] = { +"12 12 14 1", +" c None", +". c #000000", +"+ c #474747", +"@ c #E7E7E7", +"# c #F6F6F6", +"$ c #DCDCDC", +"% c #FFFFFF", +"& c #DFDFDF", +"* c #D7D7D7", +"= c #D6D6D6", +"- c #040404", +"; c #070707", +"> c #060606", +", c #050505", +" ... ", +" +.@#$.+ ", +" .%%.%%. ", +".&%%.%%*. ", +".#.....#. ", +".$%%.%%&. ", +" .%%.%%.+ ", +" +.*#=... ", +" ...+... ", +" -.; ", +" >.-", +" ,."}; diff --git a/gtk2_ardour/pixmaps/zoom_out.xpm b/gtk2_ardour/pixmaps/zoom_out.xpm new file mode 100644 index 0000000000..ea50d145ad --- /dev/null +++ b/gtk2_ardour/pixmaps/zoom_out.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char * zoom_out_xpm[] = { +"12 12 14 1", +" c None", +". c #000000", +"+ c #474747", +"@ c #E7E7E7", +"# c #F6F6F6", +"$ c #DCDCDC", +"% c #FFFFFF", +"& c #DFDFDF", +"* c #D7D7D7", +"= c #D6D6D6", +"- c #040404", +"; c #070707", +"> c #060606", +", c #050505", +" ... ", +" +.@#$.+ ", +" .%%%%%. ", +".&%%%%%*. ", +".#.....#. ", +".$%%%%%&. ", +" .%%%%%.+ ", +" +.*#=... ", +" ...+... ", +" -.; ", +" >.-", +" ,."}; diff --git a/gtk2_ardour/playlist_selector.cc b/gtk2_ardour/playlist_selector.cc index 5633404094..8eaac7cb9d 100644 --- a/gtk2_ardour/playlist_selector.cc +++ b/gtk2_ardour/playlist_selector.cc @@ -90,7 +90,7 @@ void PlaylistSelector::show_for (RouteUI* ruix) { vector item; - AudioDiskstream* this_ds; + Diskstream* this_ds; string str; rui = ruix; @@ -116,7 +116,7 @@ PlaylistSelector::show_for (RouteUI* ruix) for (DSPL_Map::iterator x = dspl_map.begin(); x != dspl_map.end(); ++x) { - AudioDiskstream* ds = session->diskstream_by_id (x->first); + Diskstream* ds = session->diskstream_by_id (x->first); if (ds == 0) { continue; @@ -243,7 +243,7 @@ PlaylistSelector::selection_changed () return; } - at->disk_stream().use_playlist (apl); + at->diskstream().use_playlist (apl); hide (); } diff --git a/gtk2_ardour/plugin_selector.h b/gtk2_ardour/plugin_selector.h index 25cba998df..18bf06bf04 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/public_editor.h b/gtk2_ardour/public_editor.h index 4c12b99d7c..f70e4c20bd 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -39,7 +39,7 @@ class AutomationLine; class ControlPoint; class SelectionRect; class CrossfadeView; -class AudioTimeAxisView; +class RouteTimeAxisView; class AudioRegionView; class TempoMarker; class MeterMarker; @@ -145,10 +145,10 @@ class PublicEditor : public Gtk::Window, public Stateful { virtual bool canvas_fade_in_handle_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; virtual bool canvas_fade_out_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; virtual bool canvas_fade_out_handle_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; - virtual bool canvas_region_view_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; - virtual bool canvas_region_view_name_highlight_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; - virtual bool canvas_region_view_name_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*) = 0; - virtual bool canvas_stream_view_event (GdkEvent* event,ArdourCanvas::Item*, AudioTimeAxisView*) = 0; + virtual bool canvas_region_view_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*) = 0; + virtual bool canvas_region_view_name_highlight_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*) = 0; + virtual bool canvas_region_view_name_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*) = 0; + virtual bool canvas_stream_view_event (GdkEvent* event,ArdourCanvas::Item*, RouteTimeAxisView*) = 0; virtual bool canvas_marker_event (GdkEvent* event,ArdourCanvas::Item*, Marker*) = 0; virtual bool canvas_zoom_rect_event (GdkEvent* event,ArdourCanvas::Item*) = 0; virtual bool canvas_tempo_marker_event (GdkEvent* event,ArdourCanvas::Item*, TempoMarker*) = 0; diff --git a/gtk2_ardour/region_editor.cc b/gtk2_ardour/region_editor.cc deleted file mode 100644 index 413ff01753..0000000000 --- a/gtk2_ardour/region_editor.cc +++ /dev/null @@ -1,732 +0,0 @@ -/* - Copyright (C) 2001 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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$ -*/ - -#include -#include -#include -#include -#include - -#include "region_editor.h" -#include "regionview.h" -#include "ardour_ui.h" -#include "utils.h" -#include "gui_thread.h" - -#include "i18n.h" - -using namespace ARDOUR; -using namespace PBD; -using namespace sigc; -using namespace std; - -AudioRegionEditor::AudioRegionEditor (Session&s, AudioRegion& r, AudioRegionView& rv) - : ArdourDialog ("audio region editor"), - _session (s), - _region (r), - _region_view (rv), - name_label (_("NAME:")), - lock_button (_("lock")), - mute_button (_("mute")), - opaque_button (_("opaque")), - envelope_active_button(_("active")), - envelope_view_button(_("visible")), - raise_arrow (Gtk::ARROW_UP, Gtk::SHADOW_OUT), - lower_arrow (Gtk::ARROW_DOWN, Gtk::SHADOW_OUT), - layer_label (_("Layer")), - audition_button (_("play")), - time_table (3, 2), - start_clock ("AudioRegionEditorClock", true), - end_clock ("AudioRegionEditorClock", true), - length_clock ("AudioRegionEditorClock", true, true), - sync_offset_clock ("AudioRegionEditorClock", true, true), - envelope_loop_table (1, 3), - envelope_label (_("ENVELOPE")), - fade_in_table (4, 3), - fade_in_length_adjustment (5.0, 0.0, 10000, 0.05, 1), - fade_in_length_spinner (fade_in_length_adjustment, 10), - fade_out_table (4, 3), - fade_out_length_adjustment (5.0, 0.0, 10000, 0.05, 1), - fade_out_length_spinner (fade_out_length_adjustment, 10) - -{ - start_clock.set_session (&_session); - end_clock.set_session (&_session); - length_clock.set_session (&_session); - - name_entry.set_name ("AudioRegionEditorEntry"); - name_label.set_name ("AudioRegionEditorLabel"); - - name_hbox.set_spacing (5); - name_hbox.pack_start (name_label, false, false); - name_hbox.pack_start (name_entry, false, false); - - raise_button.add (raise_arrow); - lower_button.add (lower_arrow); - layer_frame.set_name ("BaseFrame"); - layer_frame.set_shadow_type (Gtk::SHADOW_IN); - layer_frame.add (layer_value_label); - layer_label.set_name ("AudioRegionEditorLabel"); - layer_value_label.set_name ("AudioRegionEditorLabel"); - Gtkmm2ext::set_size_request_to_display_given_text (layer_value_label, "99", 5, 2); - - layer_hbox.set_spacing (5); - layer_hbox.pack_start (layer_label, false, false); - layer_hbox.pack_start (layer_frame, false, false); -#if 0 - layer_hbox.pack_start (raise_button, false, false); - layer_hbox.pack_start (lower_button, false, false); -#endif - - mute_button.set_name ("AudioRegionEditorToggleButton"); - opaque_button.set_name ("AudioRegionEditorToggleButton"); - lock_button.set_name ("AudioRegionEditorToggleButton"); - envelope_active_button.set_name ("AudioRegionEditorToggleButton"); - envelope_view_button.set_name ("AudioRegionEditorToggleButton"); - fade_in_active_button.set_name ("AudioRegionEditorToggleButton"); - fade_out_active_button.set_name ("AudioRegionEditorToggleButton"); - audition_button.set_name ("AudioRegionEditorToggleButton"); - - ARDOUR_UI::instance()->tooltips().set_tip (mute_button, _("mute this region")); - ARDOUR_UI::instance()->tooltips().set_tip (opaque_button, _("regions underneath this one cannot be heard")); - ARDOUR_UI::instance()->tooltips().set_tip (lock_button, _("prevent any changes to this region")); - ARDOUR_UI::instance()->tooltips().set_tip (envelope_active_button, _("use the gain envelope during playback")); - ARDOUR_UI::instance()->tooltips().set_tip (envelope_view_button, _("show the gain envelope")); - ARDOUR_UI::instance()->tooltips().set_tip (fade_in_active_button, _("use fade in curve during playback")); - ARDOUR_UI::instance()->tooltips().set_tip (fade_out_active_button, _("use fade out curve during playback")); - ARDOUR_UI::instance()->tooltips().set_tip (audition_button, _("audition this region")); - - mute_button.unset_flags (Gtk::CAN_FOCUS); - opaque_button.unset_flags (Gtk::CAN_FOCUS); - lock_button.unset_flags (Gtk::CAN_FOCUS); - envelope_active_button.unset_flags (Gtk::CAN_FOCUS); - envelope_view_button.unset_flags (Gtk::CAN_FOCUS); - fade_in_active_button.unset_flags (Gtk::CAN_FOCUS); - fade_out_active_button.unset_flags (Gtk::CAN_FOCUS); - audition_button.unset_flags (Gtk::CAN_FOCUS); - - mute_button.set_events (mute_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); - opaque_button.set_events (opaque_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); - lock_button.set_events (lock_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); - envelope_active_button.set_events (envelope_active_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); - envelope_view_button.set_events (envelope_view_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); - fade_in_active_button.set_events (fade_in_active_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); - fade_out_active_button.set_events (fade_out_active_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); - audition_button.set_events (audition_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK)); - - top_row_button_hbox.set_border_width (5); - top_row_button_hbox.set_spacing (5); - top_row_button_hbox.set_homogeneous (false); - top_row_button_hbox.pack_start (mute_button, false, false); - top_row_button_hbox.pack_start (opaque_button, false, false); - top_row_button_hbox.pack_start (lock_button, false, false); - top_row_button_hbox.pack_start (layer_hbox, false, false, 5); - top_row_button_hbox.pack_end (audition_button, false, false); - - top_row_hbox.pack_start (name_hbox, true, true); - top_row_hbox.pack_end (top_row_button_hbox, true, true); - - start_label.set_name ("AudioRegionEditorLabel"); - start_label.set_text (_("START:")); - end_label.set_name ("AudioRegionEditorLabel"); - end_label.set_text (_("END:")); - length_label.set_name ("AudioRegionEditorLabel"); - length_label.set_text (_("LENGTH:")); - - time_table.set_col_spacings (2); - time_table.set_row_spacings (5); - time_table.set_border_width (5); - - start_alignment.set (1.0, 0.5); - end_alignment.set (1.0, 0.5); - length_alignment.set (1.0, 0.5); - - start_alignment.add (start_label); - end_alignment.add (end_label); - length_alignment.add (length_label); - - time_table.attach (start_alignment, 0, 1, 0, 1, Gtk::FILL, Gtk::FILL); - time_table.attach (start_clock, 1, 2, 0, 1, Gtk::FILL, Gtk::FILL); - - time_table.attach (end_alignment, 0, 1, 1, 2, Gtk::FILL, Gtk::FILL); - time_table.attach (end_clock, 1, 2, 1, 2, Gtk::FILL, Gtk::FILL); - - time_table.attach (length_alignment, 0, 1, 2, 3, Gtk::FILL, Gtk::FILL); - time_table.attach (length_clock, 1, 2, 2, 3, Gtk::FILL, Gtk::FILL); - - envelope_label.set_name ("AudioRegionEditorLabel"); - - envelope_loop_table.set_border_width (5); - envelope_loop_table.set_row_spacings (2); - envelope_loop_table.attach (envelope_label, 0, 1, 0, 1, Gtk::FILL, Gtk::FILL); - envelope_loop_table.attach (envelope_active_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); - envelope_loop_table.attach (envelope_view_button, 0, 1, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); - - /* fade in */ - - fade_in_table.set_border_width (5); - fade_in_table.set_homogeneous (false); - - fade_in_label.set_name ("AudioRegionEditorLabel"); - fade_in_active_button_label.set_name ("AudioRegionEditorSmallLabel"); - fade_in_length_label.set_name ("AudioRegionEditorSmallLabel"); - - fade_in_label.set_text (_("FADE IN")); - fade_in_active_button_label.set_text (_("active")); - fade_in_length_label.set_text (_("msecs")); - - fade_in_active_button.add (fade_in_active_button_label); - - fade_in_length_spinner.set_name("GenericSpinner"); - - fade_in_length_spinner.set_digits (3); - - // fade_in_length_spinner.signal_activate().connect (mem_fun(*this, &AudioRegionEditor::activation)); - - Gtkmm2ext::set_size_request_to_display_given_text (fade_in_length_spinner, "500g", 20, -1); - - fade_in_label_align.add (fade_in_label); - fade_in_label_align.set (0.5); - - - fade_in_table.attach (fade_in_label_align, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); - - fade_in_table.attach (fade_in_length_label, 0, 1, 1, 2, Gtk::EXPAND, Gtk::FILL); - fade_in_table.attach (fade_in_length_spinner, 0, 1, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); - - fade_in_table.attach (fade_in_active_button, 0, 2, 3, 5, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); - - /* fade out */ - - fade_out_table.set_border_width (5); - fade_out_table.set_homogeneous (false); - - fade_out_label.set_name ("AudioRegionEditorLabel"); - fade_out_active_button_label.set_name ("AudioRegionEditorSmallLabel"); - fade_out_length_label.set_name ("AudioRegionEditorSmallLabel"); - - fade_out_label.set_text (_("FADE OUT")); - fade_out_active_button_label.set_text (_("active")); - fade_out_length_label.set_text (_("msecs")); - - fade_out_active_button.add (fade_out_active_button_label); - - fade_out_length_spinner.set_name("GenericSpinner"); - - fade_out_length_spinner.set_digits (3); - - fade_out_length_spinner.signal_activate().connect (mem_fun(*this, &AudioRegionEditor::activation)); - - Gtkmm2ext::set_size_request_to_display_given_text (fade_out_length_spinner, "500g", 20, -1); - - fade_out_label_align.add (fade_out_label); - fade_out_label_align.set (0.5); - - fade_out_table.attach (fade_out_label_align, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); - - fade_out_table.attach (fade_out_length_label, 0, 1, 1, 2, Gtk::EXPAND, Gtk::FILL); - fade_out_table.attach (fade_out_length_spinner, 0, 1, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); - - fade_out_table.attach (fade_out_active_button, 0, 2, 3, 5, Gtk::FILL|Gtk::EXPAND, Gtk::FILL); - - lower_hbox.pack_start (time_table, true, true); - lower_hbox.pack_start (sep1, false, false); - lower_hbox.pack_start (envelope_loop_table, true, true); - lower_hbox.pack_start (sep2, false, false); - lower_hbox.pack_start (fade_in_table, true, true); - lower_hbox.pack_start (fade_out_table, true, true); - - get_vbox()->pack_start (top_row_hbox, true, true); - get_vbox()->pack_start (sep3, false, false); - get_vbox()->pack_start (lower_hbox, true, true); - - set_name ("AudioRegionEditorWindow"); - add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK); - - signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), static_cast (this))); - - string title = _("ardour: region "); - title += _region.name(); - set_title (title); - - show_all(); - - name_changed (); - bounds_changed (Change (StartChanged|LengthChanged|PositionChanged)); - envelope_active_changed (); - mute_changed (); - opacity_changed (); - lock_changed (); - layer_changed (); - fade_in_changed (); - fade_out_changed (); - - XMLNode *node = _region.extra_xml ("GUI"); - XMLProperty *prop = 0; - bool showing_envelope = false; - - if (node && (prop = node->property ("envelope-visible")) != 0) { - if (prop->value() == "yes") { - showing_envelope = true; - } - } - - if (showing_envelope) { - envelope_view_button.set_active (true); - } else { - envelope_view_button.set_active (false); - } - - _region.StateChanged.connect (mem_fun(*this, &AudioRegionEditor::region_changed)); - - spin_arrow_grab = false; - - connect_editor_events (); -} - -AudioRegionEditor::~AudioRegionEditor () -{ -} - -void -AudioRegionEditor::region_changed (Change what_changed) -{ - if (what_changed & NameChanged) { - name_changed (); - } - if (what_changed & BoundsChanged) { - bounds_changed (what_changed); - } - - if (what_changed & Region::OpacityChanged) { - opacity_changed (); - } - if (what_changed & Region::MuteChanged) { - mute_changed (); - } - if (what_changed & Region::LockChanged) { - lock_changed (); - } - if (what_changed & Region::LayerChanged) { - layer_changed (); - } - - if (what_changed & AudioRegion::EnvelopeActiveChanged) { - envelope_active_changed (); - } - if (what_changed & AudioRegion::FadeInChanged) { - fade_in_changed (); - } - if (what_changed & AudioRegion::FadeOutChanged) { - fade_out_changed (); - } - if (what_changed & AudioRegion::FadeInActiveChanged) { - fade_in_active_changed (); - } - if (what_changed & AudioRegion::FadeOutActiveChanged) { - fade_out_active_changed (); - } -} - -void -AudioRegionEditor::fade_in_realized () -{ - fade_in_changed (); -} - -void -AudioRegionEditor::fade_out_realized () -{ - fade_out_changed (); -} - -gint -AudioRegionEditor::bpressed (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()) -{ - switch (ev->button) { - case 1: - case 2: - case 3: - if (ev->type == GDK_BUTTON_PRESS) { /* no double clicks here */ - if (!spin_arrow_grab) { - // GTK2FIX probably nuke the region editor - // if ((ev->window == but->gobj()->panel)) { - // spin_arrow_grab = true; - // (this->*pmf)(); - // } - } - } - break; - default: - break; - } - return FALSE; -} - -gint -AudioRegionEditor::breleased (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()) -{ - if (spin_arrow_grab) { - (this->*pmf)(); - spin_arrow_grab = false; - } - return FALSE; -} - -void -AudioRegionEditor::start_editing_fade_in () -{ - _region.freeze (); -} - -void -AudioRegionEditor::stop_editing_fade_in () -{ - _region.thaw (_("fade in edit")); -} - -void -AudioRegionEditor::start_editing_fade_out () -{ - _region.freeze (); -} - -void -AudioRegionEditor::stop_editing_fade_out () -{ - _region.thaw (_("fade out edit")); -} - -void -AudioRegionEditor::connect_editor_events () -{ - name_entry.signal_changed().connect (mem_fun(*this, &AudioRegionEditor::name_entry_changed)); - - start_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::start_clock_changed)); - end_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::end_clock_changed)); - length_clock.ValueChanged.connect (mem_fun(*this, &AudioRegionEditor::length_clock_changed)); - - fade_in_length_spinner.signal_button_press_event().connect (bind (mem_fun(*this, &AudioRegionEditor::bpressed), &fade_in_length_spinner, - &AudioRegionEditor::start_editing_fade_in)); - fade_in_length_spinner.signal_button_release_event().connect (bind (mem_fun (*this, &AudioRegionEditor::breleased), &fade_in_length_spinner, - &AudioRegionEditor::stop_editing_fade_in)); - - fade_out_length_spinner.signal_button_press_event().connect (bind (mem_fun(*this, &AudioRegionEditor::bpressed), &fade_out_length_spinner, - &AudioRegionEditor::start_editing_fade_out)); - fade_out_length_spinner.signal_button_release_event().connect (bind (mem_fun (*this, &AudioRegionEditor::breleased), &fade_out_length_spinner, - &AudioRegionEditor::stop_editing_fade_out)); - - fade_in_length_adjustment.signal_value_changed().connect (mem_fun(*this, &AudioRegionEditor::fade_in_length_adjustment_changed)); - fade_out_length_adjustment.signal_value_changed().connect (mem_fun(*this, &AudioRegionEditor::fade_out_length_adjustment_changed)); - - fade_in_active_button.signal_toggled().connect (mem_fun(*this, &AudioRegionEditor::fade_in_active_toggled)); - fade_out_active_button.signal_toggled().connect (mem_fun(*this, &AudioRegionEditor::fade_out_active_toggled)); - - envelope_active_button.signal_button_press_event().connect (mem_fun(*this, &AudioRegionEditor::envelope_active_button_press)); - envelope_active_button.signal_button_release_event().connect (mem_fun(*this, &AudioRegionEditor::envelope_active_button_release)); - audition_button.signal_toggled().connect (mem_fun(*this, &AudioRegionEditor::audition_button_toggled)); - envelope_view_button.signal_toggled().connect (mem_fun(*this, &AudioRegionEditor::envelope_view_button_toggled)); - lock_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::lock_button_clicked)); - mute_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::mute_button_clicked)); - opaque_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::opaque_button_clicked)); - raise_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::raise_button_clicked)); - lower_button.signal_clicked().connect (mem_fun(*this, &AudioRegionEditor::lower_button_clicked)); - _session.AuditionActive.connect (mem_fun(*this, &AudioRegionEditor::audition_state_changed)); -} - -void -AudioRegionEditor::start_clock_changed () -{ - _region.set_position (start_clock.current_time(), this); -} - -void -AudioRegionEditor::end_clock_changed () -{ - _region.trim_end (end_clock.current_time(), this); - - end_clock.set (_region.position() + _region.length(), true); -} - -void -AudioRegionEditor::length_clock_changed () -{ - jack_nframes_t frames = length_clock.current_time(); - _region.trim_end (_region.position() + frames, this); - - length_clock.set (_region.length()); -} - -gint -AudioRegionEditor::envelope_active_button_press(GdkEventButton *ev) -{ - return stop_signal (envelope_active_button, "button_press_event"); -} - -gint -AudioRegionEditor::envelope_active_button_release (GdkEventButton *ev) -{ - _region.set_envelope_active (!_region.envelope_active()); - return stop_signal (envelope_active_button, "button_release_event"); -} - -void -AudioRegionEditor::envelope_view_button_toggled () -{ - bool visible = envelope_view_button.get_active (); - - _region_view.set_envelope_visible (visible); -} - -void -AudioRegionEditor::audition_button_toggled () -{ - if (audition_button.get_active()) { - _session.audition_region (_region); - } else { - _session.cancel_audition (); - } -} - -void -AudioRegionEditor::raise_button_clicked () -{ - _region.raise (); -} - -void -AudioRegionEditor::lower_button_clicked () -{ - _region.lower (); -} - -void -AudioRegionEditor::opaque_button_clicked () -{ - bool ractive = _region.opaque(); - - if (opaque_button.get_active() != ractive) { - _region.set_opaque (!ractive); - } -} - -void -AudioRegionEditor::mute_button_clicked () -{ - bool ractive = _region.muted(); - - if (mute_button.get_active() != ractive) { - _region.set_muted (!ractive); - } -} - -void -AudioRegionEditor::lock_button_clicked () -{ - bool ractive = _region.locked(); - - if (lock_button.get_active() != ractive) { - _region.set_locked (!ractive); - } -} - -void -AudioRegionEditor::layer_changed () -{ - char buf[8]; - snprintf (buf, sizeof(buf), "%d", (int) _region.layer() + 1); - layer_value_label.set_text (buf); -} - -void -AudioRegionEditor::name_changed () -{ - if (name_entry.get_text() != _region.name()) { - name_entry.set_text (_region.name()); - } -} - -void -AudioRegionEditor::lock_changed () -{ - bool yn; - - if ((yn = _region.locked()) != lock_button.get_active()) { - lock_button.set_active (yn); - } - - start_clock.set_sensitive (!yn); - end_clock.set_sensitive (!yn); - length_clock.set_sensitive (!yn); -} - -void -AudioRegionEditor::envelope_active_changed () -{ - bool yn; - - if ((yn = _region.envelope_active()) != envelope_active_button.get_active()) { - envelope_active_button.set_active (yn); - } -} - -void -AudioRegionEditor::opacity_changed () -{ - bool yn; - if ((yn = _region.opaque()) != opaque_button.get_active()) { - opaque_button.set_active (yn); - } -} - -void -AudioRegionEditor::mute_changed () -{ - bool yn; - if ((yn = _region.muted()) != mute_button.get_active()) { - mute_button.set_active (yn); - } -} - -void -AudioRegionEditor::bounds_changed (Change what_changed) -{ - if (what_changed & Change ((PositionChanged|LengthChanged))) { - start_clock.set (_region.position(), true); - end_clock.set (_region.position() + _region.length(), true); - length_clock.set (_region.length(), true); - } -} - -void -AudioRegionEditor::activation () -{ - -} - -void -AudioRegionEditor::name_entry_changed () -{ - if (name_entry.get_text() != _region.name()) { - _region.set_name (name_entry.get_text()); - } -} - -void -AudioRegionEditor::fade_in_changed () -{ - float msecs = fade_in_length_adjustment.get_value(); - jack_nframes_t sr = _session.frame_rate(); - jack_nframes_t adj_frames = (jack_nframes_t) floor (msecs * (sr/1000.0f)); - jack_nframes_t frames; - bool x; - - if (adj_frames != (frames = (jack_nframes_t) _region.fade_in().back()->when)) { - fade_in_length_adjustment.set_value ((frames * 1000.0f) / sr); - } - - if ((x = _region.fade_in_active()) != fade_in_active_button.get_active()) { - fade_in_active_button.set_active (x); - } -} - -void -AudioRegionEditor::fade_out_changed () -{ - float msecs = fade_out_length_adjustment.get_value(); - jack_nframes_t sr = _session.frame_rate(); - jack_nframes_t adj_frames = (jack_nframes_t) floor (msecs * (sr/1000.0f)); - jack_nframes_t frames; - bool x; - if (adj_frames != (frames = (jack_nframes_t) _region.fade_out().back()->when)) { - fade_out_length_adjustment.set_value ((frames * 1000.0f) / sr); - } - - if ((x = _region.fade_out_active()) != fade_out_active_button.get_active()) { - fade_out_active_button.set_active (x); - } -} - -void -AudioRegionEditor::fade_in_length_adjustment_changed () -{ - jack_nframes_t fade_length = (jack_nframes_t) floor (fade_in_length_adjustment.get_value() * _session.frame_rate() * 0.001); - fade_length = max (fade_length, (jack_nframes_t) 64); - fade_length = min (fade_length, _region.length()); - - _region.set_fade_in_length (fade_length); - /* region is frozen, no worries */ - fade_in_changed(); -} - -void -AudioRegionEditor::fade_out_length_adjustment_changed () -{ - jack_nframes_t fade_length = (jack_nframes_t) floor (fade_out_length_adjustment.get_value() * _session.frame_rate() * 0.001); - fade_length = max (fade_length, (jack_nframes_t) 64); - fade_length = min (fade_length, _region.length()); - - _region.set_fade_out_length (fade_length); - /* region is frozen, no worries */ - fade_out_changed(); -} - -void -AudioRegionEditor::fade_in_active_toggled () -{ - _region.set_fade_in_active (fade_in_active_button.get_active()); -} - -void -AudioRegionEditor::fade_out_active_toggled () -{ - _region.set_fade_out_active (fade_out_active_button.get_active()); -} - -void -AudioRegionEditor::fade_out_active_changed () -{ - bool x; - - if ((x = _region.fade_out_active()) != fade_out_active_button.get_active()) { - fade_out_active_button.set_active (x); - } -} - -void -AudioRegionEditor::fade_in_active_changed () -{ - bool x; - - if ((x = _region.fade_in_active()) != fade_in_active_button.get_active()) { - fade_in_active_button.set_active (x); - } -} - -void -AudioRegionEditor::audition_state_changed (bool yn) -{ - ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioRegionEditor::audition_state_changed), yn)); - - if (!yn) { - audition_button.set_active (false); - } -} - diff --git a/gtk2_ardour/region_editor.h b/gtk2_ardour/region_editor.h deleted file mode 100644 index 65b0bbaa94..0000000000 --- a/gtk2_ardour/region_editor.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - Copyright (C) 2001 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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$ -*/ - -#ifndef __gtk_ardour_region_edit_h__ -#define __gtk_ardour_region_edit_h__ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "audio_clock.h" -#include "ardour_dialog.h" - -namespace ARDOUR { - class AudioRegion; - class Session; -} - -class AudioRegionView; - -class AudioRegionEditor : public ArdourDialog -{ - public: - AudioRegionEditor (ARDOUR::Session&, ARDOUR::AudioRegion&, AudioRegionView& rv); - ~AudioRegionEditor (); - - private: - ARDOUR::Session& _session; - ARDOUR::AudioRegion& _region; - AudioRegionView& _region_view; - - void connect_editor_events (); - - Gtk::Label name_label; - Gtk::Entry name_entry; - Gtk::HBox name_hbox; - - Gtk::HBox top_row_hbox; - Gtk::HBox top_row_button_hbox; - - Gtk::ToggleButton lock_button; - Gtk::ToggleButton mute_button; - Gtk::ToggleButton opaque_button; - Gtk::ToggleButton envelope_active_button; - Gtk::ToggleButton envelope_view_button; - - Gtk::Button raise_button; - Gtk::Arrow raise_arrow; - Gtk::Button lower_button; - Gtk::Arrow lower_arrow; - Gtk::Frame layer_frame; - Gtk::Label layer_value_label; - Gtk::Label layer_label; - Gtk::HBox layer_hbox; - - Gtk::ToggleButton audition_button; - - Gtk::HBox lower_hbox; - - Gtk::Table time_table; - - Gtk::Label start_label; - Gtk::Label end_label; - Gtk::Label length_label; - Gtk::Alignment start_alignment; - Gtk::Alignment end_alignment; - Gtk::Alignment length_alignment; - - AudioClock start_clock; - AudioClock end_clock; - AudioClock length_clock; - AudioClock sync_offset_clock; - - Gtk::Table envelope_loop_table; - Gtk::Button loop_button; - Gtk::Label loop_label; - Gtk::Label envelope_label; - - Gtk::Table fade_in_table; - Gtk::Label fade_in_label; - Gtk::Alignment fade_in_label_align; - Gtk::Label fade_in_active_button_label; - Gtk::ToggleButton fade_in_active_button; - Gtk::Label fade_in_length_label; - - Gtk::Adjustment fade_in_length_adjustment; - Gtk::SpinButton fade_in_length_spinner; - - Gtk::Table fade_out_table; - Gtk::Label fade_out_label; - Gtk::Alignment fade_out_label_align; - Gtk::Label fade_out_active_button_label; - Gtk::ToggleButton fade_out_active_button; - Gtk::Label fade_out_length_label; - - Gtk::Adjustment fade_out_length_adjustment; - Gtk::SpinButton fade_out_length_spinner; - - Gtk::HSeparator sep3; - Gtk::VSeparator sep1; - Gtk::VSeparator sep2; - - void region_changed (ARDOUR::Change); - void bounds_changed (ARDOUR::Change); - void name_changed (); - void opacity_changed (); - void mute_changed (); - void envelope_active_changed (); - void lock_changed (); - void layer_changed (); - - void fade_in_length_adjustment_changed (); - void fade_out_length_adjustment_changed (); - void fade_in_changed (); - void fade_out_changed (); - void audition_state_changed (bool); - - void activation (); - - void name_entry_changed (); - void start_clock_changed (); - void end_clock_changed (); - void length_clock_changed (); - - gint envelope_active_button_press (GdkEventButton *); - gint envelope_active_button_release (GdkEventButton *); - - void audition_button_toggled (); - void envelope_view_button_toggled (); - void lock_button_clicked (); - void mute_button_clicked (); - void opaque_button_clicked (); - void raise_button_clicked (); - void lower_button_clicked (); - - void fade_in_active_toggled (); - void fade_out_active_toggled (); - void fade_in_active_changed (); - void fade_out_active_changed (); - - void fade_in_realized (); - void fade_out_realized (); - - void start_editing_fade_in (); - void start_editing_fade_out (); - void stop_editing_fade_in (); - void stop_editing_fade_out (); - - gint bpressed (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()); - gint breleased (GdkEventButton* ev, Gtk::SpinButton* but, void (AudioRegionEditor::*pmf)()); - - bool spin_arrow_grab; -}; - -#endif /* __gtk_ardour_region_edit_h__ */ diff --git a/gtk2_ardour/region_gain_line.cc b/gtk2_ardour/region_gain_line.cc index bba9410ffb..a542be054e 100644 --- a/gtk2_ardour/region_gain_line.cc +++ b/gtk2_ardour/region_gain_line.cc @@ -2,7 +2,7 @@ #include #include "region_gain_line.h" -#include "regionview.h" +#include "audio_region_view.h" #include "utils.h" #include "time_axis_view.h" @@ -46,8 +46,8 @@ void AudioRegionGainLine::start_drag (ControlPoint* cp, float fraction) { AutomationLine::start_drag(cp,fraction); - if (!rv.region.envelope_active()) { - trackview.session().add_undo( bind( mem_fun(rv.region, &AudioRegion::set_envelope_active), false) ); + if (!rv.audio_region().envelope_active()) { + trackview.session().add_undo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), false) ); } } @@ -62,10 +62,10 @@ AudioRegionGainLine::remove_point (ControlPoint& cp) trackview.editor.current_session()->begin_reversible_command (_("remove control point")); trackview.editor.current_session()->add_undo (get_memento()); - if (!rv.region.envelope_active()) { - trackview.session().add_undo( bind( mem_fun(rv.region, &AudioRegion::set_envelope_active), false) ); - trackview.session().add_redo( bind( mem_fun(rv.region, &AudioRegion::set_envelope_active), true) ); - rv.region.set_envelope_active(true); + if (!rv.audio_region().envelope_active()) { + trackview.session().add_undo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), false) ); + trackview.session().add_redo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), true) ); + rv.audio_region().set_envelope_active(true); } alist.erase (mr.start, mr.end); @@ -78,9 +78,9 @@ AudioRegionGainLine::remove_point (ControlPoint& cp) void AudioRegionGainLine::end_drag (ControlPoint* cp) { - if (!rv.region.envelope_active()) { - trackview.session().add_redo( bind( mem_fun(rv.region, &AudioRegion::set_envelope_active), true) ); - rv.region.set_envelope_active(true); + if (!rv.audio_region().envelope_active()) { + trackview.session().add_redo( bind( mem_fun(rv.audio_region(), &AudioRegion::set_envelope_active), true) ); + rv.audio_region().set_envelope_active(true); } AutomationLine::end_drag(cp); } diff --git a/gtk2_ardour/region_selection.cc b/gtk2_ardour/region_selection.cc index 751584cab7..f8c9f384a9 100644 --- a/gtk2_ardour/region_selection.cc +++ b/gtk2_ardour/region_selection.cc @@ -1,8 +1,26 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. +*/ + #include -#include +#include -#include "regionview.h" +#include "region_view.h" #include "region_selection.h" using namespace ARDOUR; @@ -11,7 +29,7 @@ using namespace sigc; bool -AudioRegionComparator::operator() (const AudioRegionView* a, const AudioRegionView* b) const +RegionComparator::operator() (const RegionView* a, const RegionView* b) const { if (a == b) { return false; @@ -20,16 +38,16 @@ AudioRegionComparator::operator() (const AudioRegionView* a, const AudioRegionVi } } -AudioRegionSelection::AudioRegionSelection () +RegionSelection::RegionSelection () { _current_start = 0; _current_end = 0; } -AudioRegionSelection::AudioRegionSelection (const AudioRegionSelection& other) +RegionSelection::RegionSelection (const RegionSelection& other) { - for (AudioRegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) { + for (RegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) { add (*i, false); } _current_start = other._current_start; @@ -38,14 +56,14 @@ AudioRegionSelection::AudioRegionSelection (const AudioRegionSelection& other) -AudioRegionSelection& -AudioRegionSelection::operator= (const AudioRegionSelection& other) +RegionSelection& +RegionSelection::operator= (const RegionSelection& other) { if (this != &other) { clear_all(); - for (AudioRegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) { + for (RegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) { add (*i, false); } @@ -57,13 +75,13 @@ AudioRegionSelection::operator= (const AudioRegionSelection& other) } void -AudioRegionSelection::clear_all() +RegionSelection::clear_all() { clear(); _bylayer.clear(); } -bool AudioRegionSelection::contains (AudioRegionView* rv) +bool RegionSelection::contains (RegionView* rv) { if (this->find (rv) != end()) { return true; @@ -75,21 +93,21 @@ bool AudioRegionSelection::contains (AudioRegionView* rv) } void -AudioRegionSelection::add (AudioRegionView* rv, bool dosort) +RegionSelection::add (RegionView* rv, bool dosort) { if (this->find (rv) != end()) { /* we already have it */ return; } - rv->AudioRegionViewGoingAway.connect (mem_fun(*this, &AudioRegionSelection::remove_it)); + rv->RegionViewGoingAway.connect (mem_fun(*this, &RegionSelection::remove_it)); - if (rv->region.first_frame() < _current_start || empty()) { - _current_start = rv->region.first_frame(); + if (rv->region().first_frame() < _current_start || empty()) { + _current_start = rv->region().first_frame(); } - if (rv->region.last_frame() > _current_end || empty()) { - _current_end = rv->region.last_frame(); + if (rv->region().last_frame() > _current_end || empty()) { + _current_end = rv->region().last_frame(); } insert (rv); @@ -100,15 +118,15 @@ AudioRegionSelection::add (AudioRegionView* rv, bool dosort) } void -AudioRegionSelection::remove_it (AudioRegionView *rv) +RegionSelection::remove_it (RegionView *rv) { remove (rv); } bool -AudioRegionSelection::remove (AudioRegionView* rv) +RegionSelection::remove (RegionView* rv) { - AudioRegionSelection::iterator i; + RegionSelection::iterator i; if ((i = this->find (rv)) != end()) { @@ -124,7 +142,7 @@ AudioRegionSelection::remove (AudioRegionView* rv) } else { - AudioRegion& region ((*i)->region); + Region& region ((*i)->region()); if (region.first_frame() == _current_start) { @@ -165,15 +183,15 @@ AudioRegionSelection::remove (AudioRegionView* rv) } void -AudioRegionSelection::add_to_layer (AudioRegionView * rv) +RegionSelection::add_to_layer (RegionView * rv) { // insert it into layer sorted position - list::iterator i; + list::iterator i; for (i = _bylayer.begin(); i != _bylayer.end(); ++i) { - if (rv->region.layer() < (*i)->region.layer()) { + if (rv->region().layer() < (*i)->region().layer()) { _bylayer.insert(i, rv); return; } @@ -184,16 +202,16 @@ AudioRegionSelection::add_to_layer (AudioRegionView * rv) } struct RegionSortByTime { - bool operator() (const AudioRegionView* a, const AudioRegionView* b) { - return a->region.position() < b->region.position(); + bool operator() (const RegionView* a, const RegionView* b) { + return a->region().position() < b->region().position(); } }; void -AudioRegionSelection::by_position (list& foo) const +RegionSelection::by_position (list& foo) const { - list::const_iterator i; + list::const_iterator i; RegionSortByTime sorter; for (i = _bylayer.begin(); i != _bylayer.end(); ++i) { diff --git a/gtk2_ardour/region_selection.h b/gtk2_ardour/region_selection.h index 0c2b7be025..2192442cb0 100644 --- a/gtk2_ardour/region_selection.h +++ b/gtk2_ardour/region_selection.h @@ -1,3 +1,21 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. +*/ + #ifndef __ardour_gtk_region_selection_h__ #define __ardour_gtk_region_selection_h__ @@ -9,23 +27,23 @@ using std::list; using std::set; -class AudioRegionView; +class RegionView; -struct AudioRegionComparator { - bool operator() (const AudioRegionView* a, const AudioRegionView* b) const; +struct RegionComparator { + bool operator() (const RegionView* a, const RegionView* b) const; }; -class AudioRegionSelection : public set, public sigc::trackable +class RegionSelection : public set, public sigc::trackable { public: - AudioRegionSelection(); - AudioRegionSelection (const AudioRegionSelection&); + RegionSelection(); + RegionSelection (const RegionSelection&); - AudioRegionSelection& operator= (const AudioRegionSelection&); + RegionSelection& operator= (const RegionSelection&); - void add (AudioRegionView*, bool dosort = true); - bool remove (AudioRegionView*); - bool contains (AudioRegionView*); + void add (RegionView*, bool dosort = true); + bool remove (RegionView*); + bool contains (RegionView*); void clear_all(); @@ -39,18 +57,18 @@ class AudioRegionSelection : public set return _current_end; } - const list & by_layer() const { return _bylayer; } - void by_position (list&) const; + const list & by_layer() const { return _bylayer; } + void by_position (list&) const; private: - void remove_it (AudioRegionView*); + void remove_it (RegionView*); - void add_to_layer (AudioRegionView *); + void add_to_layer (RegionView *); jack_nframes_t _current_start; jack_nframes_t _current_end; - list _bylayer; + list _bylayer; }; #endif /* __ardour_gtk_region_selection_h__ */ diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc new file mode 100644 index 0000000000..ebec4261ac --- /dev/null +++ b/gtk2_ardour/region_view.cc @@ -0,0 +1,494 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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: regionview.cc 691 2006-07-23 12:03:19Z drobilla $ +*/ + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include "streamview.h" +#include "region_view.h" +#include "route_time_axis.h" +#include "simplerect.h" +#include "simpleline.h" +#include "waveview.h" +#include "public_editor.h" +#include "region_editor.h" +#include "ghostregion.h" +#include "route_time_axis.h" +#include "utils.h" +#include "rgb_macros.h" +#include "gui_thread.h" + +#include "i18n.h" + +using namespace sigc; +using namespace ARDOUR; +using namespace PBD; +using namespace Editing; +using namespace ArdourCanvas; + +static const int32_t sync_mark_width = 9; + +sigc::signal RegionView::RegionViewGoingAway; + +RegionView::RegionView (ArdourCanvas::Group* parent, + TimeAxisView& tv, + ARDOUR::Region& r, + double spu, + Gdk::Color& basic_color) + : TimeAxisViewItem (r.name(), *parent, tv, spu, basic_color, r.position(), r.length(), + TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameText| + TimeAxisViewItem::ShowNameHighlight| + TimeAxisViewItem::ShowFrame)) + , _region (r) + , sync_mark(0) + , no_wave_msg(0) + , editor(0) + , current_visible_sync_position(0.0) + , valid(false) + , _pixel_width(1.0) + , _height(1.0) + , in_destructor(false) + , wait_for_data(false) +{ +} + +RegionView::RegionView (ArdourCanvas::Group* parent, + TimeAxisView& tv, + ARDOUR::Region& r, + double spu, + Gdk::Color& basic_color, + TimeAxisViewItem::Visibility visibility) + : TimeAxisViewItem (r.name(), *parent, tv, spu, basic_color, r.position(), r.length(), visibility) + , _region (r) + , sync_mark(0) + , no_wave_msg(0) + , editor(0) + , current_visible_sync_position(0.0) + , valid(false) + , _pixel_width(1.0) + , _height(1.0) + , in_destructor(false) + , wait_for_data(false) +{ +} + +void +RegionView::init (Gdk::Color& basic_color, bool wfd) +{ + editor = 0; + valid = true; + in_destructor = false; + _height = 0; + wait_for_data = wfd; + + compute_colors (basic_color); + + name_highlight->set_data ("regionview", this); + name_text->set_data ("regionview", this); + + /* 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)); + 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(); + + reset_width_dependent_items ((double) _region.length() / samples_per_unit); + + set_height (trackview.height); + + region_muted (); + region_sync_changed (); + region_resized (BoundsChanged); + region_locked (); + + _region.StateChanged.connect (mem_fun(*this, &RegionView::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)); + + set_colors (); + + ColorChanged.connect (mem_fun (*this, &RegionView::color_handler)); + + /* XXX sync mark drag? */ +} + +RegionView::~RegionView () +{ + in_destructor = true; + + RegionViewGoingAway (this); /* EMIT_SIGNAL */ + + for (vector::iterator g = ghosts.begin(); g != ghosts.end(); ++g) { + delete *g; + } + + if (editor) { + delete editor; + } +} + +gint +RegionView::_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 +RegionView::lock_toggle () +{ + _region.set_locked (!_region.locked()); +} + +void +RegionView::region_changed (Change what_changed) +{ + ENSURE_GUI_THREAD (bind (mem_fun(*this, &RegionView::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 (); + } +} + +void +RegionView::region_locked () +{ + /* name will show locked status */ + region_renamed (); +} + +void +RegionView::region_resized (Change what_changed) +{ + double unit_length; + + if (what_changed & ARDOUR::PositionChanged) { + set_position (_region.position(), 0); + } + + 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 (vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { + + (*i)->set_duration (unit_length); + + } + } +} + +void +RegionView::reset_width_dependent_items (double pixel_width) +{ + TimeAxisViewItem::reset_width_dependent_items (pixel_width); + _pixel_width = pixel_width; +} + +void +RegionView::region_layered () +{ + RouteTimeAxisView *rtv = dynamic_cast(&get_time_axis_view()); + assert(rtv); + rtv->view()->region_layered (this); +} + +void +RegionView::region_muted () +{ + set_frame_color (); + region_renamed (); +} + +void +RegionView::region_opacity () +{ + set_frame_color (); +} + +void +RegionView::raise () +{ + _region.raise (); +} + +void +RegionView::raise_to_top () +{ + _region.raise_to_top (); +} + +void +RegionView::lower () +{ + _region.lower (); +} + +void +RegionView::lower_to_bottom () +{ + _region.lower_to_bottom (); +} + +bool +RegionView::set_position (jack_nframes_t pos, void* src, double* ignored) +{ + double delta; + bool ret; + + if (!(ret = TimeAxisViewItem::set_position (pos, this, &delta))) { + return false; + } + + if (ignored) { + *ignored = delta; + } + + if (delta) { + for (vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { + (*i)->group->move (delta, 0.0); + } + } + + return ret; +} + +void +RegionView::set_samples_per_unit (gdouble spu) +{ + TimeAxisViewItem::set_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); + } + + region_sync_changed (); +} + +bool +RegionView::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 +RegionView::compute_colors (Gdk::Color& basic_color) +{ + TimeAxisViewItem::compute_colors (basic_color); +} + +void +RegionView::set_colors () +{ + TimeAxisViewItem::set_colors (); + + if (sync_mark) { + sync_mark->property_fill_color_rgba() = fill_color; + } +} + +void +RegionView::set_frame_color () +{ + if (_region.opaque()) { + fill_opacity = 180; + } else { + fill_opacity = 100; + } + + TimeAxisViewItem::set_frame_color (); +} + +void +RegionView::hide_region_editor() +{ + if (editor) { + editor->hide_all (); + } +} + +void +RegionView::region_renamed () +{ + string str; + + if (_region.locked()) { + str += '>'; + str += _region.name(); + str += '<'; + } else { + str = _region.name(); + } + + if (_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 +RegionView::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 +RegionView::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); + } +} + +void +RegionView::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; + } + } +} + +uint32_t +RegionView::get_fill_color () +{ + return fill_color; +} + diff --git a/gtk2_ardour/region_view.h b/gtk2_ardour/region_view.h new file mode 100644 index 0000000000..fdc69ea70e --- /dev/null +++ b/gtk2_ardour/region_view.h @@ -0,0 +1,140 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. +*/ + +#ifndef __gtk_ardour_region_view_h__ +#define __gtk_ardour_region_view_h__ + +#include + +#include +#include +#include +#include + +#include "time_axis_view_item.h" +#include "automation_line.h" +#include "enums.h" +#include "waveview.h" +#include "canvas.h" +#include "color.h" + +class TimeAxisView; +class RegionEditor; +class GhostRegion; +class AutomationTimeAxisView; + +class RegionView : public TimeAxisViewItem +{ + public: + RegionView (ArdourCanvas::Group* parent, + TimeAxisView& time_view, + ARDOUR::Region& region, + double samples_per_unit, + Gdk::Color& basic_color); + + ~RegionView (); + + virtual void init (Gdk::Color& base_color, bool wait_for_data); + + ARDOUR::Region& region() const { return _region; } + + bool is_valid() const { return valid; } + void set_valid (bool yn) { valid = yn; } + + virtual void set_height (double) = 0; + virtual void set_samples_per_unit (double); + virtual bool set_duration (jack_nframes_t, void*); + + void move (double xdelta, double ydelta); + + void raise (); + void raise_to_top (); + void lower (); + void lower_to_bottom (); + + bool set_position(jack_nframes_t pos, void* src, double* delta = 0); + + virtual void show_region_editor () = 0; + virtual void hide_region_editor(); + + virtual void region_changed (ARDOUR::Change); + + virtual GhostRegion* add_ghost (AutomationTimeAxisView&) = 0; + void remove_ghost (GhostRegion*); + + uint32_t get_fill_color (); + + virtual void entered () {} + virtual void exited () {} + + static sigc::signal RegionViewGoingAway; + sigc::signal GoingAway; + + protected: + + /** Allows derived types to specify their visibility requirements + * to the TimeAxisViewItem parent class + */ + RegionView (ArdourCanvas::Group *, + TimeAxisView&, + ARDOUR::Region&, + double samples_per_unit, + Gdk::Color& basic_color, + TimeAxisViewItem::Visibility); + + 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 (); + + virtual void set_colors (); + virtual void compute_colors (Gdk::Color&); + virtual void set_frame_color (); + virtual void reset_width_dependent_items (double pixel_width); + + virtual void color_handler (ColorID, uint32_t) {} + + ARDOUR::Region& _region; + + ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position + ArdourCanvas::Text* no_wave_msg; + + RegionEditor* editor; + + vector control_points; + double current_visible_sync_position; + + bool valid; ///< see StreamView::redisplay_diskstream() + double _pixel_width; + double _height; + bool in_destructor; + + bool wait_for_data; + sigc::connection data_ready_connection; + + vector ghosts; +}; + +#endif /* __gtk_ardour_region_view_h__ */ diff --git a/gtk2_ardour/regionview.cc b/gtk2_ardour/regionview.cc deleted file mode 100644 index fa51dd455c..0000000000 --- a/gtk2_ardour/regionview.cc +++ /dev/null @@ -1,1408 +0,0 @@ -/* - Copyright (C) 2001 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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$ -*/ - -#include -#include - -#include - -#include - -#include -#include -#include -#include - -#include "streamview.h" -#include "regionview.h" -#include "audio_time_axis.h" -#include "simplerect.h" -#include "simpleline.h" -#include "waveview.h" -#include "public_editor.h" -#include "region_editor.h" -#include "region_gain_line.h" -#include "ghostregion.h" -#include "audio_time_axis.h" -#include "utils.h" -#include "rgb_macros.h" -#include "gui_thread.h" - -#include "i18n.h" - -using namespace sigc; -using namespace ARDOUR; -using namespace PBD; -using namespace Editing; -using namespace ArdourCanvas; - -static const int32_t sync_mark_width = 9; - -sigc::signal AudioRegionView::AudioRegionViewGoingAway; - -AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, AudioTimeAxisView &tv, AudioRegion& r, double spu, - Gdk::Color& basic_color) - : TimeAxisViewItem (r.name(), *parent, tv, spu, basic_color, r.position(), r.length(), - TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameText| - TimeAxisViewItem::ShowNameHighlight| - TimeAxisViewItem::ShowFrame)), - region (r) -{ -} - -AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, AudioTimeAxisView &tv, AudioRegion& r, double spu, - Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility) - : TimeAxisViewItem (r.name(), *parent, tv, spu, basic_color, r.position(), r.length(), visibility), - region (r) -{ -} - -void -AudioRegionView::init (double amplitude_above_axis, Gdk::Color& basic_color, bool wfw) -{ - ArdourCanvas::Points shape; - XMLNode *node; - - editor = 0; - valid = true; - in_destructor = false; - _amplitude_above_axis = amplitude_above_axis; - 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 (); - } - - if (trackview.editor.new_regionviews_display_gain()) { - _flags |= EnvelopeVisible; - } - - compute_colors (basic_color); - - 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); - - fade_out_shape = new ArdourCanvas::Polygon (*group); - fade_out_shape->property_fill_color_rgba() = fade_color; - fade_out_shape->set_data ("regionview", this); - - - { - uint32_t r,g,b,a; - UINT_TO_RGBA(fill_color,&r,&g,&b,&a); - - - fade_in_handle = new ArdourCanvas::SimpleRect (*group); - fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0); - fade_in_handle->property_outline_pixels() = 0; - fade_in_handle->property_y1() = 2.0; - fade_in_handle->property_y2() = 7.0; - - fade_in_handle->set_data ("regionview", this); - - fade_out_handle = new ArdourCanvas::SimpleRect (*group); - fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0); - fade_out_handle->property_outline_pixels() = 0; - fade_out_handle->property_y1() = 2.0; - fade_out_handle->property_y2() = 7.0; - - fade_out_handle->set_data ("regionview", this); - } - - string foo = region.name(); - foo += ':'; - foo += "gain"; - - gain_line = new AudioRegionGainLine (foo, trackview.session(), *this, *group, region.envelope()); - - if (!(_flags & EnvelopeVisible)) { - gain_line->hide (); - } else { - gain_line->show (); - } - - reset_width_dependent_items ((double) region.length() / samples_per_unit); - - gain_line->reset (); - - set_height (trackview.height); - - region_muted (); - region_sync_changed (); - region_resized (BoundsChanged); - set_waveview_data_src(); - region_locked (); - envelope_active_changed (); - fade_in_active_changed (); - fade_out_active_changed (); - - 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)); - fade_out_handle->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_handle_event), fade_out_handle, this)); - - set_colors (); - - ColorChanged.connect (mem_fun (*this, &AudioRegionView::color_handler)); - - /* XXX sync mark drag? */ -} - -AudioRegionView::~AudioRegionView () -{ - in_destructor = true; - - AudioRegionViewGoingAway (this); /* EMIT_SIGNAL */ - - for (vector::iterator cache = wave_caches.begin(); cache != wave_caches.end() ; ++cache) { - gnome_canvas_waveview_cache_destroy (*cache); - } - - /* 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; - } -} - -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 (); - } - if (what_changed & AudioRegion::ScaleAmplitudeChanged) { - region_scale_amplitude_changed (); - } - if (what_changed & AudioRegion::FadeInChanged) { - fade_in_changed (); - } - if (what_changed & AudioRegion::FadeOutChanged) { - fade_out_changed (); - } - if (what_changed & AudioRegion::FadeInActiveChanged) { - fade_in_active_changed (); - } - if (what_changed & AudioRegion::FadeOutActiveChanged) { - fade_out_active_changed (); - } - if (what_changed & AudioRegion::EnvelopeActiveChanged) { - envelope_active_changed (); - } -} - -void -AudioRegionView::fade_in_changed () -{ - reset_fade_in_shape (); -} - -void -AudioRegionView::fade_out_changed () -{ - reset_fade_out_shape (); -} - -void -AudioRegionView::set_fade_in_active (bool yn) -{ - region.set_fade_in_active (yn); -} - -void -AudioRegionView::set_fade_out_active (bool yn) -{ - region.set_fade_out_active (yn); -} - -void -AudioRegionView::fade_in_active_changed () -{ - uint32_t r,g,b,a; - uint32_t col; - UINT_TO_RGBA(fade_color,&r,&g,&b,&a); - - if (region.fade_in_active()) { - col = RGBA_TO_UINT(r,g,b,120); - fade_in_shape->property_fill_color_rgba() = col; - fade_in_shape->property_width_pixels() = 0; - fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,0); - } else { - col = RGBA_TO_UINT(r,g,b,0); - fade_in_shape->property_fill_color_rgba() = col; - fade_in_shape->property_width_pixels() = 1; - fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,255); - } -} - -void -AudioRegionView::fade_out_active_changed () -{ - uint32_t r,g,b,a; - uint32_t col; - UINT_TO_RGBA(fade_color,&r,&g,&b,&a); - - if (region.fade_out_active()) { - col = RGBA_TO_UINT(r,g,b,120); - fade_out_shape->property_fill_color_rgba() = col; - fade_out_shape->property_width_pixels() = 0; - fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,0); - } else { - col = RGBA_TO_UINT(r,g,b,0); - fade_out_shape->property_fill_color_rgba() = col; - fade_out_shape->property_width_pixels() = 1; - fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,255); - } -} - - -void -AudioRegionView::region_scale_amplitude_changed () -{ - ENSURE_GUI_THREAD (mem_fun(*this, &AudioRegionView::region_scale_amplitude_changed)); - - for (uint32_t n = 0; n < waves.size(); ++n) { - // force a reload of the cache - waves[n]->property_data_src() = ®ion; - } -} - -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); - } - - 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(); - } - } - } -} - -void -AudioRegionView::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 -AudioRegionView::region_layered () -{ - AudioTimeAxisView *atv = dynamic_cast (&get_time_axis_view()); - atv->view->region_layered (this); -} - -void -AudioRegionView::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 -AudioRegionView::region_opacity () -{ - set_frame_color (); -} - -void -AudioRegionView::raise () -{ - region.raise (); -} - -void -AudioRegionView::raise_to_top () -{ - region.raise_to_top (); -} - -void -AudioRegionView::lower () -{ - region.lower (); -} - -void -AudioRegionView::lower_to_bottom () -{ - region.lower_to_bottom (); -} - -bool -AudioRegionView::set_position (jack_nframes_t pos, void* src, double* ignored) -{ - double delta; - bool ret; - - if (!(ret = TimeAxisViewItem::set_position (pos, this, &delta))) { - return false; - } - - if (ignored) { - *ignored = delta; - } - - if (delta) { - for (vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { - (*i)->group->move (delta, 0.0); - } - } - - return ret; -} - -void -AudioRegionView::set_height (gdouble height) -{ - uint32_t wcnt = waves.size(); - - TimeAxisViewItem::set_height (height - 2); - - _height = height; - - for (uint32_t n=0; n < wcnt; ++n) { - gdouble ht; - - if ((height) <= NAME_HIGHLIGHT_THRESH) { - ht = ((height-2*wcnt) / (double) wcnt); - } else { - ht = (((height-2*wcnt) - NAME_HIGHLIGHT_SIZE) / (double) wcnt); - } - - gdouble yoff = n * (ht+1); - - waves[n]->property_height() = ht; - waves[n]->property_y() = yoff + 2; - } - - if (gain_line) { - if ((height/wcnt) < NAME_HIGHLIGHT_SIZE) { - gain_line->hide (); - } else { - if (_flags & EnvelopeVisible) { - gain_line->show (); - } - } - gain_line->set_height ((uint32_t) rint (height - NAME_HIGHLIGHT_SIZE)); - } - - manage_zero_line (); - reset_fade_shapes (); - - if (name_text) { - name_text->raise_to_top(); - } -} - -void -AudioRegionView::manage_zero_line () -{ - if (!zero_line) { - return; - } - - if (_height >= 100) { - gdouble wave_midpoint = (_height - NAME_HIGHLIGHT_SIZE) / 2.0; - zero_line->property_y1() = wave_midpoint; - zero_line->property_y2() = wave_midpoint; - zero_line->show(); - } else { - zero_line->hide(); - } -} - -void -AudioRegionView::reset_fade_shapes () -{ - reset_fade_in_shape (); - reset_fade_out_shape (); -} - -void -AudioRegionView::reset_fade_in_shape () -{ - reset_fade_in_shape_width ((jack_nframes_t) region.fade_in().back()->when); -} - -void -AudioRegionView::reset_fade_in_shape_width (jack_nframes_t width) -{ - if (fade_in_handle == 0) { - return; - } - - /* smallest size for a fade is 64 frames */ - - width = std::max ((jack_nframes_t) 64, width); - - Points* points; - double pwidth = width / samples_per_unit; - uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth); - double h; - - if (_height < 5) { - fade_in_shape->hide(); - fade_in_handle->hide(); - return; - } - - double handle_center; - handle_center = pwidth; - - if (handle_center > 7.0) { - handle_center -= 3.0; - } else { - handle_center = 3.0; - } - - fade_in_handle->property_x1() = handle_center - 3.0; - fade_in_handle->property_x2() = handle_center + 3.0; - - if (pwidth < 5) { - fade_in_shape->hide(); - return; - } - - fade_in_shape->show(); - - float curve[npoints]; - region.fade_in().get_vector (0, region.fade_in().back()->when, curve, npoints); - - points = get_canvas_points ("fade in shape", npoints+3); - - if (_height > NAME_HIGHLIGHT_THRESH) { - h = _height - NAME_HIGHLIGHT_SIZE; - } else { - h = _height; - } - - /* points *MUST* be in anti-clockwise order */ - - uint32_t pi, pc; - double xdelta = pwidth/npoints; - - for (pi = 0, pc = 0; pc < npoints; ++pc) { - (*points)[pi].set_x(1 + (pc * xdelta)); - (*points)[pi++].set_y(2 + (h - (curve[pc] * h))); - } - - /* fold back */ - - (*points)[pi].set_x(pwidth); - (*points)[pi++].set_y(2); - - (*points)[pi].set_x(1); - (*points)[pi++].set_y(2); - - /* connect the dots ... */ - - (*points)[pi] = (*points)[0]; - - fade_in_shape->property_points() = *points; - delete points; -} - -void -AudioRegionView::reset_fade_out_shape () -{ - reset_fade_out_shape_width ((jack_nframes_t) region.fade_out().back()->when); -} - -void -AudioRegionView::reset_fade_out_shape_width (jack_nframes_t width) -{ - if (fade_out_handle == 0) { - return; - } - - /* smallest size for a fade is 64 frames */ - - width = std::max ((jack_nframes_t) 64, width); - - Points* points; - double pwidth = width / samples_per_unit; - uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth); - double h; - - if (_height < 5) { - fade_out_shape->hide(); - fade_out_handle->hide(); - return; - } - - double handle_center; - handle_center = (region.length() - width) / samples_per_unit; - - if (handle_center > 7.0) { - handle_center -= 3.0; - } else { - handle_center = 3.0; - } - - fade_out_handle->property_x1() = handle_center - 3.0; - fade_out_handle->property_x2() = handle_center + 3.0; - - /* don't show shape if its too small */ - - if (pwidth < 5) { - fade_out_shape->hide(); - return; - } - - fade_out_shape->show(); - - float curve[npoints]; - region.fade_out().get_vector (0, region.fade_out().back()->when, curve, npoints); - - if (_height > NAME_HIGHLIGHT_THRESH) { - h = _height - NAME_HIGHLIGHT_SIZE; - } else { - h = _height; - } - - /* points *MUST* be in anti-clockwise order */ - - points = get_canvas_points ("fade out shape", npoints+3); - - uint32_t pi, pc; - double xdelta = pwidth/npoints; - - for (pi = 0, pc = 0; pc < npoints; ++pc) { - (*points)[pi].set_x(_pixel_width - 1 - pwidth + (pc*xdelta)); - (*points)[pi++].set_y(2 + (h - (curve[pc] * h))); - } - - /* fold back */ - - (*points)[pi].set_x(_pixel_width); - (*points)[pi++].set_y(h); - - (*points)[pi].set_x(_pixel_width); - (*points)[pi++].set_y(2); - - /* connect the dots ... */ - - (*points)[pi] = (*points)[0]; - - fade_out_shape->property_points() = *points; - delete points; -} - -void -AudioRegionView::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 (); -} - -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 -AudioRegionView::set_amplitude_above_axis (gdouble spp) -{ - for (uint32_t n=0; n < waves.size(); ++n) { - waves[n]->property_amplitude_above_axis() = spp; - } -} - -void -AudioRegionView::compute_colors (Gdk::Color& basic_color) -{ - TimeAxisViewItem::compute_colors (basic_color); - uint32_t r, g, b, a; - - /* gain color computed in envelope_active_changed() */ - - UINT_TO_RGBA (fill_color, &r, &g, &b, &a); - fade_color = RGBA_TO_UINT(r,g,b,120); -} - -void -AudioRegionView::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 -AudioRegionView::set_frame_color () -{ - if (region.opaque()) { - fill_opacity = 180; - } else { - fill_opacity = 100; - } - - TimeAxisViewItem::set_frame_color (); -} - -void -AudioRegionView::show_region_editor () -{ - if (editor == 0) { - editor = new AudioRegionEditor (trackview.session(), region, *this); - // GTK2FIX : how to ensure float without realizing - // editor->realize (); - // trackview.editor.ensure_float (*editor); - } - - editor->show_all (); - 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 (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) -{ - if (((_flags & WaveformVisible) != yn)) { - if (yn) { - for (uint32_t n=0; n < waves.size(); ++n) { - waves[n]->show(); - } - _flags |= WaveformVisible; - } else { - for (uint32_t n=0; n < waves.size(); ++n) { - waves[n]->hide(); - } - _flags &= ~WaveformVisible; - } - store_flags (); - } -} - -void -AudioRegionView::temporarily_hide_envelope () -{ - if (gain_line) { - gain_line->hide (); - } -} - -void -AudioRegionView::unhide_envelope () -{ - if (gain_line && (_flags & EnvelopeVisible)) { - gain_line->show (); - } -} - -void -AudioRegionView::set_envelope_visible (bool yn) -{ - if (gain_line && ((_flags & EnvelopeVisible) != yn)) { - if (yn) { - gain_line->show (); - _flags |= EnvelopeVisible; - } else { - gain_line->hide (); - _flags &= ~EnvelopeVisible; - } - store_flags (); - } -} - -void -AudioRegionView::create_waves () -{ - bool create_zero_line = true; - - AudioTimeAxisView& atv (*(dynamic_cast(&trackview))); // ick - - if (!atv.get_diskstream()) { - return; - } - - uint32_t nchans = atv.get_diskstream()->n_channels(); - - /* in tmp_waves, set up null pointers for each channel so the vector is allocated */ - for (uint32_t n = 0; n < nchans; ++n) { - tmp_waves.push_back (0); - } - - for (uint32_t n = 0; n < nchans; ++n) { - - if (n >= region.n_channels()) { - break; - } - - wave_caches.push_back (WaveView::create_cache ()); - - if (wait_for_waves) { - if (region.source(n).peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), peaks_ready_connection)) { - create_one_wave (n, true); - } else { - create_zero_line = false; - } - } else { - create_one_wave (n, true); - } - } - - if (create_zero_line) { - zero_line = new ArdourCanvas::SimpleLine (*group); - zero_line->property_x1() = (gdouble) 1.0; - zero_line->property_x2() = (gdouble) (region.length() / samples_per_unit) - 1.0; - zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; - manage_zero_line (); - } -} - -void -AudioRegionView::create_one_wave (uint32_t which, bool direct) -{ - AudioTimeAxisView& atv (*(dynamic_cast(&trackview))); // ick - uint32_t nchans = atv.get_diskstream()->n_channels(); - uint32_t n; - uint32_t nwaves = std::min (nchans, region.n_channels()); - gdouble ht; - - if (trackview.height < NAME_HIGHLIGHT_SIZE) { - ht = ((trackview.height) / (double) nchans); - } else { - ht = ((trackview.height - NAME_HIGHLIGHT_SIZE) / (double) nchans); - } - - gdouble yoff = which * ht; - - WaveView *wave = new WaveView(*group); - - wave->property_data_src() = (gpointer) ®ion; - wave->property_cache() = wave_caches[which]; - wave->property_cache_updater() = true; - wave->property_channel() = which; - wave->property_length_function() = (gpointer) region_length_from_c; - wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c; - wave->property_peak_function() = (gpointer) region_read_peaks_from_c; - wave->property_x() = 0.0; - wave->property_y() = yoff; - wave->property_height() = (double) ht; - wave->property_samples_per_unit() = samples_per_unit; - wave->property_amplitude_above_axis() = _amplitude_above_axis; - wave->property_wave_color() = region.muted() ? color_map[cMutedWaveForm] : color_map[cWaveForm]; - wave->property_region_start() = region.start(); - - if (!(_flags & WaveformVisible)) { - wave->hide(); - } - - /* note: calling this function is serialized by the lock - held in the peak building thread that signals that - peaks are ready for use *or* by the fact that it is - called one by one from the GUI thread. - */ - - if (which < nchans) { - tmp_waves[which] = wave; - } else { - /* n-channel track, >n-channel source */ - } - - /* see if we're all ready */ - - for (n = 0; n < nchans; ++n) { - if (tmp_waves[n] == 0) { - break; - } - } - - if (n == nwaves && waves.empty()) { - /* all waves are ready */ - tmp_waves.resize(nwaves); - - waves = tmp_waves; - tmp_waves.clear (); - - if (!zero_line) { - zero_line = new ArdourCanvas::SimpleLine (*group); - zero_line->property_x1() = (gdouble) 1.0; - zero_line->property_x2() = (gdouble) (region.length() / samples_per_unit) - 1.0; - zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; - manage_zero_line (); - } - } -} - -void -AudioRegionView::peaks_ready_handler (uint32_t which) -{ - Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &AudioRegionView::create_one_wave), which, false)); - - if (!waves.empty()) { - /* all waves created, don't hook into peaks ready anymore */ - peaks_ready_connection.disconnect (); - } -} - -void -AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) -{ - if (gain_line == 0) { - return; - } - - double x, y; - - /* don't create points that can't be seen */ - - set_envelope_visible (true); - - x = ev->button.x; - y = ev->button.y; - - item->w2i (x, y); - - jack_nframes_t fx = trackview.editor.pixel_to_frame (x); - - if (fx > region.length()) { - return; - } - - /* compute vertical fractional position */ - - y = 1.0 - (y / (trackview.height - NAME_HIGHLIGHT_SIZE)); - - /* map using gain line */ - - gain_line->view_to_model_y (y); - - trackview.session().begin_reversible_command (_("add gain control point")); - trackview.session().add_undo (region.envelope().get_memento()); - - - if (!region.envelope_active()) { - trackview.session().add_undo( bind( mem_fun(region, &AudioRegion::set_envelope_active), false) ); - region.set_envelope_active(true); - trackview.session().add_redo( bind( mem_fun(region, &AudioRegion::set_envelope_active), true) ); - } - - region.envelope().add (fx, y); - - trackview.session().add_redo_no_execute (region.envelope().get_memento()); - trackview.session().commit_reversible_command (); -} - -void -AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) -{ - ControlPoint *cp = reinterpret_cast (item->get_data ("control_point")); - region.envelope().erase (cp->model); -} - -void -AudioRegionView::store_flags() -{ - XMLNode *node = new XMLNode ("GUI"); - - node->add_property ("waveform-visible", (_flags & WaveformVisible) ? "yes" : "no"); - node->add_property ("envelope-visible", (_flags & EnvelopeVisible) ? "yes" : "no"); - - region.add_extra_xml (*node); -} - -void -AudioRegionView::set_flags (XMLNode* node) -{ - XMLProperty *prop; - - if ((prop = node->property ("waveform-visible")) != 0) { - if (prop->value() == "yes") { - _flags |= WaveformVisible; - } - } - - if ((prop = node->property ("envelope-visible")) != 0) { - if (prop->value() == "yes") { - _flags |= EnvelopeVisible; - } - } -} - -void -AudioRegionView::set_waveform_shape (WaveformShape shape) -{ - bool yn; - - /* this slightly odd approach is to leave the door open to - other "shapes" such as spectral displays, etc. - */ - - switch (shape) { - case Rectified: - yn = true; - break; - - default: - yn = false; - break; - } - - if (yn != (bool) (_flags & WaveformRectified)) { - for (vector::iterator wave = waves.begin(); wave != waves.end() ; ++wave) { - (*wave)->property_rectified() = yn; - } - - if (zero_line) { - if (yn) { - zero_line->hide(); - } else { - zero_line->show(); - } - } - - if (yn) { - _flags |= WaveformRectified; - } else { - _flags &= ~WaveformRectified; - } - } -} - -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) -{ - AudioTimeAxisView& myatv (*(dynamic_cast(&trackview))); // ick - double unit_position = region.position () / samples_per_unit; - GhostRegion* ghost = new GhostRegion (atv, unit_position); - uint32_t nchans; - - nchans = myatv.get_diskstream()->n_channels(); - - for (uint32_t n = 0; n < nchans; ++n) { - - if (n >= region.n_channels()) { - break; - } - - WaveView *wave = new WaveView(*ghost->group); - - wave->property_data_src() = ®ion; - wave->property_cache() = wave_caches[n]; - wave->property_cache_updater() = false; - wave->property_channel() = n; - wave->property_length_function() = (gpointer)region_length_from_c; - wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c; - wave->property_peak_function() = (gpointer) region_read_peaks_from_c; - wave->property_x() = 0.0; - wave->property_samples_per_unit() = samples_per_unit; - wave->property_amplitude_above_axis() = _amplitude_above_axis; - wave->property_wave_color() = color_map[cGhostTrackWave]; - wave->property_region_start() = region.start(); - - ghost->waves.push_back(wave); - } - - ghost->set_height (); - ghost->set_duration (region.length() / samples_per_unit); - ghosts.push_back (ghost); - - ghost->GoingAway.connect (mem_fun(*this, &AudioRegionView::remove_ghost)); - - 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; - } - } -} - -uint32_t -AudioRegionView::get_fill_color () -{ - return fill_color; -} - -void -AudioRegionView::entered () -{ - if (gain_line && _flags & EnvelopeVisible) { - gain_line->show_all_control_points (); - } - - uint32_t r,g,b,a; - UINT_TO_RGBA(fade_color,&r,&g,&b,&a); - a=255; - - if (fade_in_handle) { - fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); - fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); - } -} - -void -AudioRegionView::exited () -{ - if (gain_line) { - gain_line->hide_all_but_selected_control_points (); - } - - uint32_t r,g,b,a; - UINT_TO_RGBA(fade_color,&r,&g,&b,&a); - a=0; - - if (fade_in_handle) { - fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); - fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a); - } -} - -void -AudioRegionView::envelope_active_changed () -{ - if (gain_line) { - gain_line->set_line_color (region.envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]); - } -} - -void -AudioRegionView::set_waveview_data_src() -{ - - double unit_length= region.length() / samples_per_unit; - - for (uint32_t n = 0; n < waves.size(); ++n) { - // TODO: something else to let it know the channel - waves[n]->property_data_src() = ®ion; - } - - 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_data_src() = ®ion; - } - } - -} - -void -AudioRegionView::color_handler (ColorID id, uint32_t val) -{ - switch (id) { - case cMutedWaveForm: - case cWaveForm: - set_colors (); - break; - - case cGainLineInactive: - case cGainLine: - envelope_active_changed(); - break; - - case cZeroLine: - if (zero_line) { - zero_line->property_color_rgba() = (guint) color_map[cZeroLine]; - } - break; - - case cGhostTrackWave: - break; - - default: - break; - } -} diff --git a/gtk2_ardour/regionview.h b/gtk2_ardour/regionview.h deleted file mode 100644 index f49b46aea4..0000000000 --- a/gtk2_ardour/regionview.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - Copyright (C) 2001-2004 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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$ -*/ - -#ifndef __gtk_ardour_region_view_h__ -#define __gtk_ardour_region_view_h__ - -#include - -#include -#include -#include -#include - -#include "time_axis_view_item.h" -#include "automation_line.h" -#include "enums.h" -#include "waveview.h" -#include "canvas.h" -#include "color.h" - -namespace ARDOUR { - class AudioRegion; - class PeakData; -}; - -class AudioTimeAxisView; -class AudioRegionGainLine; -class AudioRegionEditor; -class GhostRegion; -class AutomationTimeAxisView; - -class AudioRegionView : public TimeAxisViewItem -{ - public: - AudioRegionView (ArdourCanvas::Group *, - AudioTimeAxisView&, - ARDOUR::AudioRegion&, - double initial_samples_per_unit, - Gdk::Color& basic_color); - - ~AudioRegionView (); - - virtual void init (double amplitude_above_axis, Gdk::Color& base_color, bool wait_for_waves); - - ARDOUR::AudioRegion& region; // ok, let 'em have it - 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 raise (); - void raise_to_top (); - void lower (); - void lower_to_bottom (); - - bool set_position(jack_nframes_t pos, void* src, double* delta = 0); - - void temporarily_hide_envelope (); // dangerous - void unhide_envelope (); // dangerous - - void set_envelope_visible (bool); - void set_waveform_visible (bool yn); - 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; } - - 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); - - AudioRegionGainLine* get_gain_line() const { return gain_line; } - - void region_changed (ARDOUR::Change); - void envelope_active_changed (); - - static sigc::signal AudioRegionViewGoingAway; - sigc::signal GoingAway; - - 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); - void set_fade_in_active (bool); - void set_fade_out_active (bool); - - uint32_t get_fill_color (); - - virtual void entered (); - virtual void exited (); - - protected: - - /* this constructor allows derived types - to specify their visibility requirements - to the TimeAxisViewItem parent class - */ - - AudioRegionView (ArdourCanvas::Group *, - AudioTimeAxisView&, - ARDOUR::AudioRegion&, - double initial_samples_per_unit, - Gdk::Color& basic_color, - TimeAxisViewItem::Visibility); - - enum Flags { - EnvelopeVisible = 0x1, - WaveformVisible = 0x4, - WaveformRectified = 0x8 - }; - - vector waves; /* waveviews */ - 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 */ - - 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 (); - void fade_in_changed (); - void fade_out_changed (); - void fade_in_active_changed (); - void fade_out_active_changed (); - - 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 (); - - 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); -}; - -#endif /* __gtk_ardour_region_view_h__ */ diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc new file mode 100644 index 0000000000..cb9883b8e6 --- /dev/null +++ b/gtk2_ardour/route_time_axis.cc @@ -0,0 +1,1559 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. +*/ + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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" +#include "gui_thread.h" +#include "keyboard.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 "region_view.h" +#include "rgb_macros.h" +#include "selection.h" +#include "simplerect.h" +#include "streamview.h" +#include "utils.h" + +#include + +#include "i18n.h" + +using namespace ARDOUR; +using namespace PBD; +using namespace Gtk; +using namespace Editing; + + +RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr rt, Canvas& canvas) + : AxisView(sess), + RouteUI(rt, sess, _("m"), _("s"), _("r")), // mute, solo, and record + TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas), + parent_canvas (canvas), + button_table (3, 3), + edit_group_button (_("g")), // group + playlist_button (_("p")), + size_button (_("h")), // height + automation_button (_("a")), + visual_button (_("v")) + +{ + _has_state = true; + playlist_menu = 0; + playlist_action_menu = 0; + automation_action_menu = 0; + _view = 0; + timestretch_rect = 0; + no_redraw = false; + + ignore_toggle = false; + + mute_button->set_active (false); + solo_button->set_active (false); + + mute_button->set_name ("TrackMuteButton"); + solo_button->set_name ("SoloButton"); + edit_group_button.set_name ("TrackGroupButton"); + playlist_button.set_name ("TrackPlaylistButton"); + automation_button.set_name ("TrackAutomationButton"); + size_button.set_name ("TrackSizeButton"); + visual_button.set_name ("TrackVisualButton"); + hide_button.set_name ("TrackRemoveButton"); + + hide_button.add (*(manage (new Image (get_xpm("small_x.xpm"))))); + + solo_button->signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + mute_button->signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + playlist_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + automation_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + size_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + visual_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + hide_button.signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + + solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false); + solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release), false); + mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false); + mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release), false); + edit_group_button.signal_button_release_event().connect (mem_fun(*this, &RouteTimeAxisView::edit_click), false); + playlist_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::playlist_click)); + automation_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::automation_click)); + size_button.signal_button_release_event().connect (mem_fun(*this, &RouteTimeAxisView::size_click), false); + visual_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::visual_click)); + hide_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::hide_click)); + + if (is_track()) { + rec_enable_button->set_active (false); + rec_enable_button->set_name ("TrackRecordEnableButton"); + rec_enable_button->signal_button_press_event().connect (mem_fun (*this, &RouteTimeAxisView::select_me), false); + rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press)); + controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); + ARDOUR_UI::instance()->tooltips().set_tip(*rec_enable_button, _("Record")); + } + + controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); + controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::FILL|Gtk::EXPAND, 0, 0); + + controls_table.attach (edit_group_button, 6, 7, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); + + ARDOUR_UI::instance()->tooltips().set_tip(*solo_button,_("Solo")); + ARDOUR_UI::instance()->tooltips().set_tip(*mute_button,_("Mute")); + ARDOUR_UI::instance()->tooltips().set_tip(edit_group_button,_("Edit Group")); + ARDOUR_UI::instance()->tooltips().set_tip(size_button,_("Display Height")); + ARDOUR_UI::instance()->tooltips().set_tip(playlist_button,_("Playlist")); + ARDOUR_UI::instance()->tooltips().set_tip(automation_button, _("Automation")); + ARDOUR_UI::instance()->tooltips().set_tip(visual_button, _("Visual options")); + ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("Hide this track")); + + label_view (); + + controls_table.attach (hide_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.attach (visual_button, 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.attach (size_button, 2, 3, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + controls_table.attach (automation_button, 3, 4, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + + if (is_track() && track()->mode() == ARDOUR::Normal) { + controls_table.attach (playlist_button, 5, 6, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND); + } + + /* remove focus from the buttons */ + + automation_button.unset_flags (Gtk::CAN_FOCUS); + solo_button->unset_flags (Gtk::CAN_FOCUS); + mute_button->unset_flags (Gtk::CAN_FOCUS); + edit_group_button.unset_flags (Gtk::CAN_FOCUS); + size_button.unset_flags (Gtk::CAN_FOCUS); + playlist_button.unset_flags (Gtk::CAN_FOCUS); + hide_button.unset_flags (Gtk::CAN_FOCUS); + visual_button.unset_flags (Gtk::CAN_FOCUS); + + /* map current state of the route */ + + update_diskstream_display (); + solo_changed(0); + mute_changed(0); + //redirects_changed (0); + //reset_redirect_automation_curves (); + y_position = -1; + + _route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)); + _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); + _route->redirects_changed.connect (mem_fun(*this, &RouteTimeAxisView::redirects_changed)); + _route->name_changed.connect (mem_fun(*this, &RouteTimeAxisView::route_name_changed)); + _route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); + + if (is_track()) { + + track()->FreezeChange.connect (mem_fun(*this, &RouteTimeAxisView::map_frozen)); + track()->DiskstreamChanged.connect (mem_fun(*this, &RouteTimeAxisView::diskstream_changed)); + get_diskstream()->SpeedChanged.connect (mem_fun(*this, &RouteTimeAxisView::speed_changed)); + + /* ask for notifications of any new RegionViews */ + // FIXME: _view is NULL, but it would be nice to attach this here :/ + //_view->RegionViewAdded.connect (mem_fun(*this, &RouteTimeAxisView::region_view_added)); + //_view->attach (); + + /* pick up the correct freeze state */ + map_frozen (); + + } + + editor.ZoomChanged.connect (mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit)); + ColorChanged.connect (mem_fun (*this, &RouteTimeAxisView::color_handler)); +} + +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; + } + + if (playlist_action_menu) { + delete playlist_action_menu; + playlist_action_menu = 0; + } + + if (_view) { + delete _view; + _view = 0; + } +} + +void +RouteTimeAxisView::set_playlist (Playlist *newplaylist) +{ + Playlist *pl = playlist(); + assert(pl); + + modified_connection.disconnect (); + state_changed_connection.disconnect (); + + state_changed_connection = pl->StateChanged.connect (mem_fun(*this, &RouteTimeAxisView::playlist_state_changed)); + modified_connection = pl->Modified.connect (mem_fun(*this, &RouteTimeAxisView::playlist_modified)); +} + +void +RouteTimeAxisView::playlist_modified () +{ +} + +gint +RouteTimeAxisView::edit_click (GdkEventButton *ev) +{ + if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { + _route->set_edit_group (0, this); + return FALSE; + } + + using namespace Menu_Helpers; + + MenuList& items = edit_group_menu.items (); + RadioMenuItem::Group group; + + items.clear (); + items.push_back (RadioMenuElem (group, _("No group"), + bind (mem_fun(*this, &RouteTimeAxisView::set_edit_group_from_menu), (RouteGroup *) 0))); + + if (_route->edit_group() == 0) { + static_cast(&items.back())->set_active (); + } + + _session.foreach_edit_group (bind (mem_fun (*this, &RouteTimeAxisView::add_edit_group_menu_item), &group)); + edit_group_menu.popup (ev->button, ev->time); + + return FALSE; +} + +void +RouteTimeAxisView::add_edit_group_menu_item (RouteGroup *eg, RadioMenuItem::Group* group) +{ + using namespace Menu_Helpers; + + MenuList &items = edit_group_menu.items(); + + cerr << "adding edit group " << eg->name() << endl; + + items.push_back (RadioMenuElem (*group, eg->name(), bind (mem_fun(*this, &RouteTimeAxisView::set_edit_group_from_menu), eg))); + if (_route->edit_group() == eg) { + static_cast(&items.back())->set_active (); + } +} + +void +RouteTimeAxisView::set_edit_group_from_menu (RouteGroup *eg) + +{ + _route->set_edit_group (eg, this); +} + +void +RouteTimeAxisView::playlist_state_changed (Change ignored) +{ + // ENSURE_GUI_THREAD (bind (mem_fun(*this, &RouteTimeAxisView::playlist_state_changed), ignored)); + // why are we here ? +} + +void +RouteTimeAxisView::playlist_changed () + +{ + label_view (); + + if (is_track()) { + set_playlist (dynamic_cast(get_diskstream()->playlist())); + } +} + +void +RouteTimeAxisView::label_view () +{ + string x = _route->name(); + + if (x != name_entry.get_text()) { + name_entry.set_text (x); + } + + ARDOUR_UI::instance()->tooltips().set_tip (name_entry, x); +} + +void +RouteTimeAxisView::route_name_changed (void *src) +{ + editor.route_name_changed (this); + label_view (); +} + +void +RouteTimeAxisView::take_name_changed (void *src) + +{ + if (src != this) { + label_view (); + } +} + +void +RouteTimeAxisView::playlist_click () +{ + // always build a new action menu + + if (playlist_action_menu == 0) { + playlist_action_menu = new Menu; + playlist_action_menu->set_name ("ArdourContextMenu"); + } + + build_playlist_menu(playlist_action_menu); + + playlist_action_menu->popup (1, 0); +} + +void +RouteTimeAxisView::automation_click () +{ + if (automation_action_menu == 0) { + /* this seems odd, but the automation action + menu is built as part of the display menu. + */ + build_display_menu (); + } + 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) +{ + double x1; + double x2; + double y2; + + TimeAxisView::show_timestretch (start, end); + + hide_timestretch (); + +#if 0 + if (ts.empty()) { + return; + } + + + /* check that the time selection was made in our route, or our edit group. + remember that edit_group() == 0 implies the route is *not* in a edit group. + */ + + if (!(ts.track == this || (ts.group != 0 && ts.group == _route->edit_group()))) { + /* this doesn't apply to us */ + return; + } + + /* ignore it if our edit group is not active */ + + if ((ts.track != this) && _route->edit_group() && !_route->edit_group()->is_active()) { + return; + } +#endif + + if (timestretch_rect == 0) { + timestretch_rect = new SimpleRect (*canvas_display); + timestretch_rect->property_x1() = 0.0; + timestretch_rect->property_y1() = 0.0; + timestretch_rect->property_x2() = 0.0; + timestretch_rect->property_y2() = 0.0; + timestretch_rect->property_fill_color_rgba() = color_map[cTimeStretchFill]; + timestretch_rect->property_outline_color_rgba() = color_map[cTimeStretchOutline]; + } + + timestretch_rect->show (); + timestretch_rect->raise_to_top (); + + x1 = start / editor.get_current_zoom(); + x2 = (end - 1) / editor.get_current_zoom(); + y2 = height - 2; + + timestretch_rect->property_x1() = x1; + timestretch_rect->property_y1() = 1.0; + timestretch_rect->property_x2() = x2; + timestretch_rect->property_y2() = y2; +} + +void +RouteTimeAxisView::hide_timestretch () +{ + TimeAxisView::hide_timestretch (); + + if (timestretch_rect) { + timestretch_rect->hide (); + } +} + +void +RouteTimeAxisView::show_selection (TimeSelection& ts) +{ + +#if 0 + /* ignore it if our edit group is not active or if the selection was started + in some other track or edit group (remember that edit_group() == 0 means + that the track is not in an edit group). + */ + + if (((ts.track != this && !is_child (ts.track)) && _route->edit_group() && !_route->edit_group()->is_active()) || + (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->edit_group())))) { + hide_selection (); + return; + } +#endif + + TimeAxisView::show_selection (ts); +} + +void +RouteTimeAxisView::set_height (TrackHeight h) +{ + bool height_changed = (height == 0) || (h != height_style); + + TimeAxisView::set_height (h); + + ensure_xml_node (); + + _view->set_height ((double) height); + + switch (height_style) { + case Largest: + xml_node->add_property ("track_height", "largest"); + show_name_entry (); + hide_name_label (); + controls_table.show_all(); + break; + case Large: + xml_node->add_property ("track_height", "large"); + show_name_entry (); + hide_name_label (); + controls_table.show_all(); + break; + case Larger: + xml_node->add_property ("track_height", "larger"); + show_name_entry (); + hide_name_label (); + controls_table.show_all(); + break; + case Normal: + xml_node->add_property ("track_height", "normal"); + show_name_entry (); + hide_name_label (); + controls_table.show_all(); + break; + case Smaller: + xml_node->add_property ("track_height", "smaller"); + controls_table.show_all (); + show_name_entry (); + hide_name_label (); + edit_group_button.hide (); + hide_button.hide (); + visual_button.hide (); + size_button.hide (); + automation_button.hide (); + playlist_button.hide (); + break; + case Small: + xml_node->add_property ("track_height", "small"); + controls_table.hide_all (); + controls_table.show (); + hide_name_entry (); + show_name_label (); + name_label.set_text (_route->name()); + break; + } + + if (height_changed) { + /* only emit the signal if the height really changed */ + _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */ + } +} + +void +RouteTimeAxisView::select_track_color () +{ + if (RouteUI::choose_color ()) { + + if (_view) { + _view->apply_color (_color, StreamView::RegionColor); + } + } +} + +void +RouteTimeAxisView::reset_samples_per_unit () +{ + set_samples_per_unit (editor.get_current_zoom()); +} + +void +RouteTimeAxisView::set_samples_per_unit (double spu) +{ + double speed = 1.0; + + if (get_diskstream() != 0) { + speed = get_diskstream()->speed(); + } + + if (_view) { + _view->set_samples_per_unit (spu * speed); + } + + TimeAxisView::set_samples_per_unit (spu * speed); +} + +void +RouteTimeAxisView::align_style_changed () +{ + switch (get_diskstream()->alignment_style()) { + case ExistingMaterial: + if (!align_existing_item->get_active()) { + align_existing_item->set_active(); + } + break; + case CaptureTime: + if (!align_capture_item->get_active()) { + align_capture_item->set_active(); + } + break; + } +} + +void +RouteTimeAxisView::set_align_style (AlignStyle style) +{ + get_diskstream()->set_align_style (style); +} + +void +RouteTimeAxisView::rename_current_playlist () +{ + ArdourPrompter prompter (true); + string name; + + Diskstream *const ds = get_diskstream(); + if (!ds || ds->destructive()) + return; + + Playlist *const pl = ds->playlist(); + if (!pl) + return; + + prompter.set_prompt (_("Name for playlist")); + prompter.set_initial_text (pl->name()); + prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT); + prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); + + switch (prompter.run ()) { + case Gtk::RESPONSE_ACCEPT: + prompter.get_result (name); + if (name.length()) { + pl->set_name (name); + } + break; + + default: + break; + } +} + +void +RouteTimeAxisView::use_copy_playlist (bool prompt) +{ + string name; + + Diskstream *const ds = get_diskstream(); + if (!ds || ds->destructive()) + return; + + Playlist *const pl = ds->playlist(); + if (!pl) + return; + + name = Playlist::bump_name (pl->name(), _session); + + if (prompt) { + + ArdourPrompter prompter (true); + + prompter.set_prompt (_("Name for Playlist")); + prompter.set_initial_text (name); + prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT); + prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); + prompter.show_all (); + + switch (prompter.run ()) { + case Gtk::RESPONSE_ACCEPT: + prompter.get_result (name); + break; + + default: + return; + } + } + + if (name.length()) { + ds->use_copy_playlist (); + pl->set_name (name); + } +} + +void +RouteTimeAxisView::use_new_playlist (bool prompt) +{ + string name; + + Diskstream *const ds = get_diskstream(); + if (!ds || ds->destructive()) + return; + + Playlist *const pl = ds->playlist(); + if (!pl) + return; + + name = Playlist::bump_name (pl->name(), _session); + + if (prompt) { + + ArdourPrompter prompter (true); + + prompter.set_prompt (_("Name for Playlist")); + prompter.set_initial_text (name); + prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT); + prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false); + + switch (prompter.run ()) { + case Gtk::RESPONSE_ACCEPT: + prompter.get_result (name); + break; + + default: + return; + } + } + + if (name.length()) { + ds->use_new_playlist (); + pl->set_name (name); + } +} + +void +RouteTimeAxisView::clear_playlist () +{ + Diskstream *const ds = get_diskstream(); + if (!ds || ds->destructive()) + return; + + Playlist *const pl = ds->playlist(); + if (!pl) + return; + + editor.clear_playlist (*pl); +} + +void +RouteTimeAxisView::speed_changed () +{ + Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit)); +} + +void +RouteTimeAxisView::diskstream_changed () +{ + Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &RouteTimeAxisView::update_diskstream_display)); +} + +void +RouteTimeAxisView::update_diskstream_display () +{ + if (!get_diskstream()) // bus + return; + + set_playlist (get_diskstream()->playlist()); + map_frozen (); +} + +void +RouteTimeAxisView::selection_click (GdkEventButton* ev) +{ + PublicEditor::TrackViewList* tracks = editor.get_valid_views (this, _route->edit_group()); + + switch (Keyboard::selection_type (ev->state)) { + case Selection::Toggle: + /* XXX this is not right */ + editor.get_selection().add (*tracks); + break; + + case Selection::Set: + editor.get_selection().set (*tracks); + break; + + case Selection::Extend: + /* not defined yet */ + break; + } + + delete tracks; +} + +void +RouteTimeAxisView::set_selected_points (PointSelection& points) +{ + for (vector::iterator i = children.begin(); i != children.end(); ++i) { + (*i)->set_selected_points (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) +{ + double speed = 1.0; + + if (get_diskstream() != 0) { + speed = get_diskstream()->speed(); + } + + jack_nframes_t start_adjusted = session_frame_to_track_frame(start, speed); + jack_nframes_t end_adjusted = session_frame_to_track_frame(end, speed); + + if (_view && ((top < 0.0 && bot < 0.0)) || touched (top, bot)) { + _view->get_selectables (start_adjusted, end_adjusted, results); + } + + /* pick up visible automation tracks */ + + for (vector::iterator i = children.begin(); i != children.end(); ++i) { + if (!(*i)->hidden()) { + (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results); + } + } +} + +void +RouteTimeAxisView::get_inverted_selectables (Selection& sel, list& results) +{ + if (_view) { + _view->get_inverted_selectables (sel, results); + } + + for (vector::iterator i = children.begin(); i != children.end(); ++i) { + if (!(*i)->hidden()) { + (*i)->get_inverted_selectables (sel, results); + } + } + + return; +} + +RouteGroup* +RouteTimeAxisView::edit_group() const +{ + return _route->edit_group(); +} + +string +RouteTimeAxisView::name() const +{ + return _route->name(); +} + +Playlist * +RouteTimeAxisView::playlist () const +{ + Diskstream *ds; + + if ((ds = get_diskstream()) != 0) { + return ds->playlist(); + } else { + return 0; + } +} + +void +RouteTimeAxisView::name_entry_changed () +{ + string x; + + x = name_entry.get_text (); + + if (x == _route->name()) { + return; + } + + if (x.length() == 0) { + name_entry.set_text (_route->name()); + return; + } + + strip_whitespace_edges(x); + + if (_session.route_name_unique (x)) { + _route->set_name (x, this); + } else { + ARDOUR_UI::instance()->popup_error (_("a track already exists with that name")); + name_entry.set_text (_route->name()); + } +} + +void +RouteTimeAxisView::visual_click () +{ + popup_display_menu (0); +} + +void +RouteTimeAxisView::hide_click () +{ + editor.hide_track_in_display (*this); +} + +Region* +RouteTimeAxisView::find_next_region (jack_nframes_t pos, RegionPoint point, int32_t dir) +{ + Diskstream *stream; + Playlist *playlist; + + if ((stream = get_diskstream()) != 0 && (playlist = stream->playlist()) != 0) { + return playlist->find_next_region (pos, point, dir); + } + + return 0; +} + +bool +RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) +{ + Playlist* what_we_got; + Diskstream* ds = get_diskstream(); + Playlist* playlist; + bool ret = false; + + if (ds == 0) { + /* route is a bus, not a track */ + return false; + } + + playlist = ds->playlist(); + + + TimeSelection time (selection.time); + float speed = ds->speed(); + if (speed != 1.0f) { + for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) { + (*i).start = session_frame_to_track_frame((*i).start, speed); + (*i).end = session_frame_to_track_frame((*i).end, speed); + } + } + + switch (op) { + case Cut: + _session.add_undo (playlist->get_memento()); + if ((what_we_got = playlist->cut (time)) != 0) { + editor.get_cut_buffer().add (what_we_got); + _session.add_redo_no_execute (playlist->get_memento()); + ret = true; + } + break; + case Copy: + if ((what_we_got = playlist->copy (time)) != 0) { + editor.get_cut_buffer().add (what_we_got); + } + break; + + case Clear: + _session.add_undo (playlist->get_memento()); + if ((what_we_got = playlist->cut (time)) != 0) { + _session.add_redo_no_execute (playlist->get_memento()); + what_we_got->unref (); + ret = true; + } + break; + } + + return ret; +} + +bool +RouteTimeAxisView::paste (jack_nframes_t pos, float times, Selection& selection, size_t nth) +{ + if (!is_track()) { + return false; + } + + Playlist* playlist = get_diskstream()->playlist(); + PlaylistSelection::iterator p; + + for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth); + + if (p == selection.playlists.end()) { + return false; + } + + if (get_diskstream()->speed() != 1.0f) + pos = session_frame_to_track_frame(pos, get_diskstream()->speed() ); + + _session.add_undo (playlist->get_memento()); + playlist->paste (**p, pos, times); + _session.add_redo_no_execute (playlist->get_memento()); + + return true; +} + + +list +RouteTimeAxisView::get_child_list() +{ + + listredirect_children; + + for (vector::iterator i = children.begin(); i != children.end(); ++i) { + if (!(*i)->hidden()) { + redirect_children.push_back(*i); + } + } + return redirect_children; +} + + +void +RouteTimeAxisView::build_playlist_menu (Gtk::Menu * menu) +{ + using namespace Menu_Helpers; + + if (!menu || !is_track()) { + return; + } + + MenuList& playlist_items = menu->items(); + menu->set_name ("ArdourContextMenu"); + playlist_items.clear(); + + if (playlist_menu) { + delete playlist_menu; + } + playlist_menu = new Menu; + playlist_menu->set_name ("ArdourContextMenu"); + + playlist_items.push_back (MenuElem (string_compose (_("Current: %1"), get_diskstream()->playlist()->name()))); + playlist_items.push_back (SeparatorElem()); + + playlist_items.push_back (MenuElem (_("Rename"), mem_fun(*this, &RouteTimeAxisView::rename_current_playlist))); + playlist_items.push_back (SeparatorElem()); + + playlist_items.push_back (MenuElem (_("New"), mem_fun(editor, &PublicEditor::new_playlists))); + playlist_items.push_back (MenuElem (_("New Copy"), mem_fun(editor, &PublicEditor::copy_playlists))); + playlist_items.push_back (SeparatorElem()); + playlist_items.push_back (MenuElem (_("Clear Current"), mem_fun(editor, &PublicEditor::clear_playlists))); + playlist_items.push_back (SeparatorElem()); + playlist_items.push_back (MenuElem(_("Select"), mem_fun(*this, &RouteTimeAxisView::show_playlist_selector))); + +} + +void +RouteTimeAxisView::show_playlist_selector () +{ + editor.playlist_selector().show_for (this); +} + +void +RouteTimeAxisView::map_frozen () +{ + if (!is_track()) { + return; + } + + ENSURE_GUI_THREAD (mem_fun(*this, &RouteTimeAxisView::map_frozen)); + + switch (track()->freeze_state()) { + case Track::Frozen: + playlist_button.set_sensitive (false); + rec_enable_button->set_sensitive (false); + break; + default: + playlist_button.set_sensitive (true); + rec_enable_button->set_sensitive (true); + break; + } +} + +void +RouteTimeAxisView::color_handler (ColorID id, uint32_t val) +{ + switch (id) { + case cTimeStretchOutline: + timestretch_rect->property_outline_color_rgba() = val; + break; + case cTimeStretchFill: + timestretch_rect->property_fill_color_rgba() = val; + break; + default: + break; + } +} + +bool +RouteTimeAxisView::select_me (GdkEventButton* ev) +{ + editor.get_selection().add (this); + 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 new file mode 100644 index 0000000000..d305fd390c --- /dev/null +++ b/gtk2_ardour/route_time_axis.h @@ -0,0 +1,256 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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: audio_time_axis.h 664 2006-07-05 19:47:25Z drobilla $ +*/ + +#ifndef __ardour_route_time_axis_h__ +#define __ardour_route_time_axis_h__ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "ardour_dialog.h" +#include "route_ui.h" +#include "enums.h" +#include "time_axis_view.h" +#include "canvas.h" +#include "color.h" + +namespace ARDOUR { + class Session; + class Region; + class Diskstream; + class RouteGroup; + class Redirect; + class Insert; + class Location; + class Playlist; +} + +class PublicEditor; +class RegionView; +class StreamView; +class Selection; +class RegionSelection; +class Selectable; +class AutomationTimeAxisView; +class AutomationLine; +class RedirectAutomationLine; +class TimeSelection; + +class RouteTimeAxisView : public RouteUI, public TimeAxisView +{ +public: + RouteTimeAxisView (PublicEditor&, ARDOUR::Session&, boost::shared_ptr, ArdourCanvas::Canvas& canvas); + virtual ~RouteTimeAxisView (); + + void show_selection (TimeSelection&); + + void set_samples_per_unit (double); + void set_height (TimeAxisView::TrackHeight); + void show_timestretch (jack_nframes_t start, jack_nframes_t end); + 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); + + /* 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 */ + 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; + +protected: + friend class StreamView; + + struct RedirectAutomationNode { + uint32_t what; + Gtk::CheckMenuItem* menu_item; + AutomationTimeAxisView* view; + RouteTimeAxisView& parent; + + RedirectAutomationNode (uint32_t w, Gtk::CheckMenuItem* mitem, RouteTimeAxisView& 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), menu (0) {} + + ~RedirectAutomationInfo (); + }; + + + void diskstream_changed (); + void update_diskstream_display (); + + gint edit_click (GdkEventButton *); + + void build_redirect_window (); + void redirect_click (); + void redirect_add (); + void redirect_remove (); + void redirect_edit (); + 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 add_redirect_to_subplugin_menu (boost::shared_ptr); + void remove_ran (RedirectAutomationNode* ran); + + 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 (); + + void on_area_realize (); + + virtual void label_view (); + + void add_edit_group_menu_item (ARDOUR::RouteGroup *, Gtk::RadioMenuItem::Group*); + void set_edit_group_from_menu (ARDOUR::RouteGroup *); + + void reset_samples_per_unit (); + + void select_track_color(); + + 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); + + 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 add_playlist_to_playlist_menu (ARDOUR::Playlist*); + void rename_current_playlist (); + + 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); + + void visual_click (); + void hide_click (); + gint when_displayed (GdkEventAny*); + + void speed_changed (); + + void map_frozen (); + + void color_handler (ColorID, uint32_t); + bool select_me (GdkEventButton*); + + 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/route_ui.cc b/gtk2_ardour/route_ui.cc index eb20eeac08..eaf28470da 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -70,14 +70,14 @@ RouteUI::RouteUI (boost::shared_ptr rt, ARDOUR::Session& sess, co mute_button = manage (new BindableToggleButton (_route->mute_control(), m_name )); solo_button = manage (new BindableToggleButton (_route->solo_control(), s_name )); - if (is_audio_track()) { - boost::shared_ptr at = boost::dynamic_pointer_cast(_route); + if (is_track()) { + boost::shared_ptr t = boost::dynamic_pointer_cast(_route); - at->disk_stream().record_enable_changed.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)); + t->diskstream().RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)); _session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)); - rec_enable_button = manage (new BindableToggleButton (at->rec_enable_control(), r_name )); + rec_enable_button = manage (new BindableToggleButton (t->rec_enable_control(), r_name )); rec_enable_button->unset_flags (Gtk::CAN_FOCUS); @@ -268,7 +268,7 @@ RouteUI::solo_release(GdkEventButton* ev) gint RouteUI::rec_enable_press(GdkEventButton* ev) { - if (!ignore_toggle && is_audio_track() && rec_enable_button) { + if (!ignore_toggle && is_track() && rec_enable_button) { if (ev->button == 2 && Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) { // do nothing on midi bind event @@ -351,7 +351,7 @@ RouteUI::update_mute_display () } void -RouteUI::route_rec_enable_changed (void *src) +RouteUI::route_rec_enable_changed () { Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display)); } @@ -694,7 +694,7 @@ RouteUI::remove_this_route () vector choices; string prompt; - if (is_audio_track()) { + if (is_track()) { prompt = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n(cannot be undone)"), _route->name()); } else { prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name()); @@ -870,21 +870,21 @@ RouteUI::disconnect_output () } bool -RouteUI::is_audio_track () const +RouteUI::is_track () const { - return dynamic_cast(_route.get()) != 0; + return dynamic_cast(_route.get()) != 0; } -AudioDiskstream* -RouteUI::get_diskstream () const +Track* +RouteUI::track() const { - boost::shared_ptr at; + return dynamic_cast(_route.get()); +} - if ((at = boost::dynamic_pointer_cast(_route)) != 0) { - return &at->disk_stream(); - } else { - return 0; - } +bool +RouteUI::is_audio_track () const +{ + return dynamic_cast(_route.get()) != 0; } AudioTrack* @@ -893,6 +893,18 @@ RouteUI::audio_track() const return dynamic_cast(_route.get()); } +Diskstream* +RouteUI::get_diskstream () const +{ + boost::shared_ptr t; + + if ((t = boost::dynamic_pointer_cast(_route)) != 0) { + return &t->diskstream(); + } else { + return 0; + } +} + string RouteUI::name() const { @@ -917,3 +929,4 @@ RouteUI::map_frozen () } } } + diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h index 48f7d47b97..7415eddad6 100644 --- a/gtk2_ardour/route_ui.h +++ b/gtk2_ardour/route_ui.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "axis_view.h" @@ -47,11 +48,16 @@ class RouteUI : public virtual AxisView RouteUI(boost::shared_ptr, ARDOUR::Session&, const char*, const char*, const char*); virtual ~RouteUI(); + bool is_track() const; bool is_audio_track() const; - ARDOUR::AudioDiskstream* get_diskstream() const; boost::shared_ptr route() const { return _route; } + + // FIXME: make these return shared_ptr + ARDOUR::Track* track() const; ARDOUR::AudioTrack* audio_track() const; + + ARDOUR::Diskstream* get_diskstream() const; string name() const; @@ -89,7 +95,8 @@ class RouteUI : public virtual AxisView void solo_changed(void*); void mute_changed(void*); - void route_rec_enable_changed(void*); + virtual void redirects_changed (void *) {} + void route_rec_enable_changed(); void session_rec_enable_changed(); void build_solo_menu (void); diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc index 6dae5b0bcd..086d878994 100644 --- a/gtk2_ardour/selection.cc +++ b/gtk2_ardour/selection.cc @@ -24,7 +24,7 @@ #include -#include "regionview.h" +#include "region_view.h" #include "selection.h" #include "selection_templates.h" #include "time_axis_view.h" @@ -46,7 +46,7 @@ Selection& Selection::operator= (const Selection& other) { if (&other != this) { - audio_regions = other.audio_regions; + regions = other.regions; tracks = other.tracks; time = other.time; lines = other.lines; @@ -57,7 +57,7 @@ Selection::operator= (const Selection& other) bool operator== (const Selection& a, const Selection& b) { - return a.audio_regions == b.audio_regions && + return a.regions == b.regions && a.tracks == b.tracks && a.time.track == b.time.track && a.time.group == b.time.group && @@ -71,7 +71,7 @@ void Selection::clear () { clear_tracks (); - clear_audio_regions (); + clear_regions (); clear_points (); clear_lines(); clear_time (); @@ -83,8 +83,8 @@ void Selection::dump_region_layers() { cerr << "region selection layer dump" << endl; - for (AudioRegionSelection::iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) { - cerr << "layer: " << (int)(*i)->region.layer() << endl; + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + cerr << "layer: " << (int)(*i)->region().layer() << endl; } } @@ -99,10 +99,10 @@ Selection::clear_redirects () } void -Selection::clear_audio_regions () +Selection::clear_regions () { - if (!audio_regions.empty()) { - audio_regions.clear_all (); + if (!regions.empty()) { + regions.clear_all (); RegionsChanged(); } } @@ -196,29 +196,29 @@ Selection::toggle (TimeAxisView* track) } void -Selection::toggle (AudioRegionView* r) +Selection::toggle (RegionView* r) { - AudioRegionSelection::iterator i; + RegionSelection::iterator i; - if ((i = find (audio_regions.begin(), audio_regions.end(), r)) == audio_regions.end()) { - audio_regions.add (r); + if ((i = find (regions.begin(), regions.end(), r)) == regions.end()) { + regions.add (r); } else { - audio_regions.erase (i); + regions.erase (i); } RegionsChanged (); } void -Selection::toggle (vector& r) +Selection::toggle (vector& r) { - AudioRegionSelection::iterator i; + RegionSelection::iterator i; - for (vector::iterator x = r.begin(); x != r.end(); ++x) { - if ((i = find (audio_regions.begin(), audio_regions.end(), (*x))) == audio_regions.end()) { - audio_regions.add ((*x)); + for (vector::iterator x = r.begin(); x != r.end(); ++x) { + if ((i = find (regions.begin(), regions.end(), (*x))) == regions.end()) { + regions.add ((*x)); } else { - audio_regions.erase (i); + regions.erase (i); } } @@ -310,22 +310,22 @@ Selection::add (TimeAxisView* track) } void -Selection::add (AudioRegionView* r) +Selection::add (RegionView* r) { - if (find (audio_regions.begin(), audio_regions.end(), r) == audio_regions.end()) { - audio_regions.add (r); + if (find (regions.begin(), regions.end(), r) == regions.end()) { + regions.add (r); RegionsChanged (); } } void -Selection::add (vector& v) +Selection::add (vector& v) { bool changed = false; - for (vector::iterator i = v.begin(); i != v.end(); ++i) { - if (find (audio_regions.begin(), audio_regions.end(), (*i)) == audio_regions.end()) { - audio_regions.add ((*i)); + for (vector::iterator i = v.begin(); i != v.end(); ++i) { + if (find (regions.begin(), regions.end(), (*i)) == regions.end()) { + regions.add ((*i)); changed = true; } } @@ -451,9 +451,9 @@ Selection::remove (const list& pllist) } void -Selection::remove (AudioRegionView* r) +Selection::remove (RegionView* r) { - audio_regions.remove (r); + regions.remove (r); RegionsChanged (); } @@ -526,17 +526,16 @@ Selection::set (const list& pllist) } void -Selection::set (AudioRegionView* r) +Selection::set (RegionView* r) { - clear_audio_regions (); + clear_regions (); add (r); } void -Selection::set (vector& v) +Selection::set (vector& v) { - - clear_audio_regions (); + clear_regions (); // make sure to deselect any automation selections clear_points(); add (v); @@ -590,15 +589,15 @@ Selection::selected (TimeAxisView* tv) } bool -Selection::selected (AudioRegionView* arv) +Selection::selected (RegionView* rv) { - return find (audio_regions.begin(), audio_regions.end(), arv) != audio_regions.end(); + return find (regions.begin(), regions.end(), rv) != regions.end(); } bool Selection::empty () { - return audio_regions.empty () && + return regions.empty () && tracks.empty () && points.empty () && playlists.empty () && @@ -612,7 +611,7 @@ Selection::empty () void Selection::set (list& selectables) { - clear_audio_regions(); + clear_regions(); clear_points (); add (selectables); } @@ -620,14 +619,14 @@ Selection::set (list& selectables) void Selection::add (list& selectables) { - AudioRegionView* arv; + RegionView* rv; AutomationSelectable* as; - vector arvs; + vector rvs; vector autos; for (std::list::iterator i = selectables.begin(); i != selectables.end(); ++i) { - if ((arv = dynamic_cast (*i)) != 0) { - arvs.push_back (arv); + if ((rv = dynamic_cast (*i)) != 0) { + rvs.push_back (rv); } else if ((as = dynamic_cast (*i)) != 0) { autos.push_back (as); } else { @@ -638,8 +637,8 @@ Selection::add (list& selectables) } } - if (!arvs.empty()) { - add (arvs); + if (!rvs.empty()) { + add (rvs); } if (!autos.empty()) { diff --git a/gtk2_ardour/selection.h b/gtk2_ardour/selection.h index 102e6e9410..7b503a5e63 100644 --- a/gtk2_ardour/selection.h +++ b/gtk2_ardour/selection.h @@ -35,7 +35,7 @@ #include "point_selection.h" class TimeAxisView; -class AudioRegionView; +class RegionView; class Selectable; namespace ARDOUR { @@ -61,7 +61,7 @@ class Selection : public sigc::trackable }; TrackSelection tracks; - AudioRegionSelection audio_regions; + RegionSelection regions; TimeSelection time; AutomationSelection lines; PlaylistSelection playlists; @@ -89,15 +89,15 @@ class Selection : public sigc::trackable void dump_region_layers(); bool selected (TimeAxisView*); - bool selected (AudioRegionView*); + bool selected (RegionView*); void set (list&); void add (list&); void set (TimeAxisView*); void set (const list&); - void set (AudioRegionView*); - void set (std::vector&); + void set (RegionView*); + void set (std::vector&); long set (TimeAxisView*, jack_nframes_t, jack_nframes_t); void set (ARDOUR::AutomationList*); void set (ARDOUR::Playlist*); @@ -107,8 +107,8 @@ class Selection : public sigc::trackable void toggle (TimeAxisView*); void toggle (const list&); - void toggle (AudioRegionView*); - void toggle (std::vector&); + void toggle (RegionView*); + void toggle (std::vector&); long toggle (jack_nframes_t, jack_nframes_t); void toggle (ARDOUR::AutomationList*); void toggle (ARDOUR::Playlist*); @@ -117,8 +117,8 @@ class Selection : public sigc::trackable void add (TimeAxisView*); void add (const list&); - void add (AudioRegionView*); - void add (std::vector&); + void add (RegionView*); + void add (std::vector&); long add (jack_nframes_t, jack_nframes_t); void add (ARDOUR::AutomationList*); void add (ARDOUR::Playlist*); @@ -127,7 +127,7 @@ class Selection : public sigc::trackable void remove (TimeAxisView*); void remove (const list&); - void remove (AudioRegionView*); + void remove (RegionView*); void remove (uint32_t selection_id); void remove (jack_nframes_t, jack_nframes_t); void remove (ARDOUR::AutomationList*); @@ -137,7 +137,7 @@ class Selection : public sigc::trackable void replace (uint32_t time_index, jack_nframes_t start, jack_nframes_t end); - void clear_audio_regions(); + void clear_regions(); void clear_tracks (); void clear_time(); void clear_lines (); @@ -145,10 +145,8 @@ class Selection : public sigc::trackable void clear_redirects (); void clear_points (); - void foreach_audio_region (void (ARDOUR::AudioRegion::*method)(void)); - void foreach_audio_region (void (ARDOUR::Region::*method)(void)); - template void foreach_audio_region (void (ARDOUR::AudioRegion::*method)(A), A arg); - template void foreach_audio_region (void (ARDOUR::Region::*method)(A), A arg); + void foreach_region (void (ARDOUR::Region::*method)(void)); + template void foreach_region (void (ARDOUR::Region::*method)(A), A arg); private: uint32_t next_time_id; diff --git a/gtk2_ardour/selection_templates.h b/gtk2_ardour/selection_templates.h index c2ca70b526..9511db7d61 100644 --- a/gtk2_ardour/selection_templates.h +++ b/gtk2_ardour/selection_templates.h @@ -27,35 +27,21 @@ */ #include -#include #include "selection.h" +#include "region_view.h" inline void -Selection::foreach_audio_region (void (ARDOUR::AudioRegion::*method)(void)) { - for (AudioRegionSelection::iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) { - ((*i)->region.*(method))(); - } -} - -inline void -Selection::foreach_audio_region (void (ARDOUR::Region::*method)(void)) { - for (AudioRegionSelection::iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) { - ((*i)->region.*(method))(); - } -} - -template inline void -Selection::foreach_audio_region (void (ARDOUR::AudioRegion::*method)(A), A arg) { - for (AudioRegionSelection::iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) { - ((*i)->region.*(method))(arg); +Selection::foreach_region (void (ARDOUR::Region::*method)(void)) { + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + ((*i)->region().*(method))(); } } template inline void -Selection::foreach_audio_region (void (ARDOUR::Region::*method)(A), A arg) { - for (AudioRegionSelection::iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) { - ((*i)->region.*(method))(arg); +Selection::foreach_region (void (ARDOUR::Region::*method)(A), A arg) { + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + ((*i)->region().*(method))(arg); } } @@ -64,14 +50,14 @@ Selection::foreach_audio_region (void (ARDOUR::Region::*method)(A), A arg) { template inline void Selection::foreach_route (void (ARDOUR::Route::*method)(A), A arg) { for (list::iterator i = routes.begin(); i != routes.end(); ++i) { - ((*i)->region.*(method))(arg); + ((*i)->region().*(method))(arg); } } template inline void Selection::foreach_route (void (ARDOUR::Route::*method)(A1,A2), A1 arg1, A2 arg2) { for (list::iterator i = routes.begin(); i != routes.end(); ++i) { - ((*i)->region.*(method))(arg1, arg2); + ((*i)->region().*(method))(arg1, arg2); } } diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc index a60e0d59e7..31452e315b 100644 --- a/gtk2_ardour/streamview.cc +++ b/gtk2_ardour/streamview.cc @@ -1,28 +1,42 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. +*/ + #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include #include +#include +#include #include "streamview.h" -#include "regionview.h" -#include "taperegionview.h" -#include "audio_time_axis.h" +#include "region_view.h" +#include "route_time_axis.h" #include "canvas-waveview.h" #include "canvas-simplerect.h" #include "region_selection.h" #include "selection.h" #include "public_editor.h" #include "ardour_ui.h" -#include "crossfade_view.h" #include "rgb_macros.h" #include "gui_thread.h" #include "utils.h" @@ -32,21 +46,10 @@ using namespace ARDOUR; using namespace PBD; using namespace Editing; -StreamView::StreamView (AudioTimeAxisView& tv) +StreamView::StreamView (RouteTimeAxisView& tv) : _trackview (tv) { region_color = _trackview.color(); - crossfades_visible = true; - - if (tv.is_audio_track()) { - /* TRACK */ - //stream_base_color = RGBA_TO_UINT (222,223,218,255); - stream_base_color = color_map[cAudioTrackBase]; - } else { - /* BUS */ - //stream_base_color = RGBA_TO_UINT (230,226,238,255); - stream_base_color = color_map[cAudioBusBase]; - } /* set_position() will position the group */ @@ -57,26 +60,23 @@ StreamView::StreamView (AudioTimeAxisView& 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]; 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()->diskstream_changed.connect (mem_fun (*this, &StreamView::diskstream_changed)); + if (_trackview.is_track()) { + _trackview.track()->DiskstreamChanged.connect (mem_fun (*this, &StreamView::diskstream_changed)); _trackview.session().TransportStateChange.connect (mem_fun (*this, &StreamView::transport_changed)); - _trackview.get_diskstream()->record_enable_changed.connect (mem_fun (*this, &StreamView::rec_enable_changed)); + _trackview.get_diskstream()->RecordEnableChanged.connect (mem_fun (*this, &StreamView::rec_enable_changed)); _trackview.session().RecordStateChanged.connect (mem_fun (*this, &StreamView::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, &StreamView::color_handler)); } @@ -90,7 +90,7 @@ StreamView::~StreamView () void StreamView::attach () { - if (_trackview.is_audio_track()) { + if (_trackview.is_track()) { display_diskstream (_trackview.get_diskstream()); } } @@ -115,13 +115,13 @@ StreamView::set_height (gdouble h) canvas_rect->property_y2() = h; - for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { + for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { (*i)->set_height (h); } - for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + /*for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { (*i)->set_height (h); - } + }*/ for (vector::iterator i = rec_rects.begin(); i != rec_rects.end(); ++i) { RecBoxInfo &recbox = (*i); @@ -134,7 +134,7 @@ StreamView::set_height (gdouble h) int StreamView::set_samples_per_unit (gdouble spp) { - AudioRegionViewList::iterator i; + RegionViewList::iterator i; if (spp < 1.0) { return -1; @@ -146,10 +146,6 @@ StreamView::set_samples_per_unit (gdouble spp) (*i)->set_samples_per_unit (spp); } - for (CrossfadeViewList::iterator xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) { - (*xi)->set_samples_per_unit (spp); - } - for (vector::iterator xi = rec_rects.begin(); xi != rec_rects.end(); ++xi) { RecBoxInfo &recbox = (*xi); @@ -163,113 +159,24 @@ StreamView::set_samples_per_unit (gdouble spp) return 0; } -int -StreamView::set_amplitude_above_axis (gdouble app) - -{ - AudioRegionViewList::iterator i; - - if (app < 1.0) { - return -1; - } - - _amplitude_above_axis = app; - - for (i = region_views.begin(); i != region_views.end(); ++i) { - (*i)->set_amplitude_above_axis (app); - } - - return 0; -} - void StreamView::add_region_view (Region *r) { add_region_view_internal (r, true); } -void -StreamView::add_region_view_internal (Region *r, bool wait_for_waves) -{ - ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::add_region_view), r)); - - AudioRegion* region = dynamic_cast (r); - - if (region == 0) { - return; - } - - AudioRegionView *region_view; - list::iterator i; - - for (i = region_views.begin(); i != region_views.end(); ++i) { - if (&(*i)->region == region) { - - /* great. we already have a AudioRegionView for this Region. use it again. - */ - - (*i)->set_valid (true); - return; - } - } - - switch (_trackview.audio_track()->mode()) { - case Normal: - region_view = new AudioRegionView (canvas_group, _trackview, *region, - _samples_per_unit, region_color); - break; - case Destructive: - region_view = new TapeAudioRegionView (canvas_group, _trackview, *region, - _samples_per_unit, region_color); - break; - } - - region_view->init (_amplitude_above_axis, region_color, wait_for_waves); - region_views.push_front (region_view); - - /* follow global waveform setting */ - - region_view->set_waveform_visible(_trackview.editor.show_waveforms()); - - /* catch regionview going away */ - - region->GoingAway.connect (mem_fun (*this, &StreamView::remove_region_view)); - - AudioRegionViewAdded (region_view); -} - void StreamView::remove_region_view (Region *r) { ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::remove_region_view), r)); - AudioRegion* ar = dynamic_cast (r); - - if (ar == 0) { - return; - } - - for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { - if (&((*i)->region) == ar) { + for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { + if (&((*i)->region()) == r) { delete *i; region_views.erase (i); break; } } - - for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end();) { - list::iterator tmp; - - tmp = i; - ++tmp; - - if ((*i)->crossfade.involves (*ar)) { - delete *i; - crossfade_views.erase (i); - } - - i = tmp; - } } void @@ -282,14 +189,8 @@ StreamView::remove_rec_region (Region *r) /*NOTREACHED*/ } - AudioRegion* ar = dynamic_cast (r); - - if (ar == 0) { - return; - } - - for (list::iterator i = rec_regions.begin(); i != rec_regions.end(); ++i) { - if (*i == ar) { + for (list::iterator i = rec_regions.begin(); i != rec_regions.end(); ++i) { + if (*i == r) { rec_regions.erase (i); break; } @@ -299,21 +200,15 @@ StreamView::remove_rec_region (Region *r) void StreamView::undisplay_diskstream () { - - for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { - delete *i; - } - - for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { + for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { delete *i; } region_views.clear(); - crossfade_views.clear (); } void -StreamView::display_diskstream (AudioDiskstream *ds) +StreamView::display_diskstream (Diskstream *ds) { playlist_change_connection.disconnect(); playlist_changed (ds); @@ -325,21 +220,13 @@ StreamView::playlist_modified () { ENSURE_GUI_THREAD (mem_fun (*this, &StreamView::playlist_modified)); - /* if the playlist is modified, make sure xfades are on top and all the regionviews are stacked - correctly. - */ - - for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { + for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { region_layered (*i); } - - for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - (*i)->get_canvas_group()->raise_to_top(); - } } void -StreamView::playlist_changed (AudioDiskstream *ds) +StreamView::playlist_changed (Diskstream *ds) { ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_changed), ds)); @@ -362,69 +249,6 @@ StreamView::playlist_changed (AudioDiskstream *ds) playlist_connections.push_back (ds->playlist()->RegionRemoved.connect (mem_fun (*this, &StreamView::remove_region_view))); playlist_connections.push_back (ds->playlist()->StateChanged.connect (mem_fun (*this, &StreamView::playlist_state_changed))); playlist_connections.push_back (ds->playlist()->Modified.connect (mem_fun (*this, &StreamView::playlist_modified))); - playlist_connections.push_back (ds->playlist()->NewCrossfade.connect (mem_fun (*this, &StreamView::add_crossfade))); -} - -void -StreamView::add_crossfade (Crossfade *crossfade) -{ - AudioRegionView* lview = 0; - AudioRegionView* rview = 0; - - ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::add_crossfade), crossfade)); - - /* first see if we already have a CrossfadeView for this Crossfade */ - - for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - if (&(*i)->crossfade == crossfade) { - if (!crossfades_visible) { - (*i)->hide(); - } else { - (*i)->show (); - } - (*i)->set_valid (true); - return; - } - } - - /* create a new one */ - - for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { - if (!lview && &((*i)->region) == &crossfade->out()) { - lview = *i; - } - if (!rview && &((*i)->region) == &crossfade->in()) { - rview = *i; - } - } - - CrossfadeView *cv = new CrossfadeView (_trackview.canvas_display, - _trackview, - *crossfade, - _samples_per_unit, - region_color, - *lview, *rview); - - crossfade->Invalidated.connect (mem_fun (*this, &StreamView::remove_crossfade)); - crossfade_views.push_back (cv); - - if (!crossfades_visible) { - cv->hide (); - } -} - -void -StreamView::remove_crossfade (Crossfade *xfade) -{ - ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::remove_crossfade), xfade)); - - for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - if (&(*i)->crossfade == xfade) { - delete *i; - crossfade_views.erase (i); - break; - } - } } void @@ -436,64 +260,12 @@ StreamView::playlist_state_changed (Change ignored) } void -StreamView::redisplay_diskstream () +StreamView::diskstream_changed () { - list::iterator i, tmp; - list::iterator xi, tmpx; - - - for (i = region_views.begin(); i != region_views.end(); ++i) { - (*i)->set_valid (false); - } + Track *t; - for (xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) { - (*xi)->set_valid (false); - if ((*xi)->visible()) { - (*xi)->show (); - } - } - - if (_trackview.is_audio_track()) { - _trackview.get_diskstream()->playlist()->foreach_region (this, &StreamView::add_region_view); - _trackview.get_diskstream()->playlist()->foreach_crossfade (this, &StreamView::add_crossfade); - } - - for (i = region_views.begin(); i != region_views.end(); ) { - tmp = i; - tmp++; - - if (!(*i)->is_valid()) { - delete *i; - region_views.erase (i); - } - - i = tmp; - } - - for (xi = crossfade_views.begin(); xi != crossfade_views.end();) { - tmpx = xi; - tmpx++; - - if (!(*xi)->valid()) { - delete *xi; - crossfade_views.erase (xi); - } - - xi = tmpx; - } - - /* now fix layering */ - - playlist_modified (); -} - -void -StreamView::diskstream_changed (void *src_ignored) -{ - AudioTrack *at; - - if ((at = _trackview.audio_track()) != 0) { - AudioDiskstream& ds = at->disk_stream(); + if ((t = _trackview.track()) != 0) { + Diskstream& ds = t->diskstream(); /* XXX grrr: when will SigC++ allow me to bind references? */ Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*this, &StreamView::display_diskstream), &ds)); } else { @@ -505,7 +277,7 @@ void StreamView::apply_color (Gdk::Color& color, ColorTarget target) { - list::iterator i; + list::iterator i; switch (target) { case RegionColor: @@ -525,64 +297,7 @@ StreamView::apply_color (Gdk::Color& color, ColorTarget target) } void -StreamView::set_show_waveforms (bool yn) -{ - for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { - (*i)->set_waveform_visible (yn); - } -} - -void -StreamView::set_selected_regionviews (AudioRegionSelection& regions) -{ - bool selected; - - // cerr << _trackview.name() << " (selected = " << regions.size() << ")" << endl; - for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { - - selected = false; - - for (AudioRegionSelection::iterator ii = regions.begin(); ii != regions.end(); ++ii) { - if (*i == *ii) { - selected = true; - } - } - - // cerr << "\tregion " << (*i)->region.name() << " selected = " << selected << endl; - (*i)->set_selected (selected); - } -} - -void -StreamView::get_selectables (jack_nframes_t start, jack_nframes_t end, list& results) -{ - for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { - if ((*i)->region.coverage(start, end) != OverlapNone) { - results.push_back (*i); - } - } -} - -void -StreamView::get_inverted_selectables (Selection& sel, list& results) -{ - for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { - if (!sel.audio_regions.contains (*i)) { - results.push_back (*i); - } - } -} - -void -StreamView::set_waveform_shape (WaveformShape shape) -{ - for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { - (*i)->set_waveform_shape (shape); - } -} - -void -StreamView::region_layered (AudioRegionView* rv) +StreamView::region_layered (RegionView* rv) { rv->get_canvas_group()->lower_to_bottom(); @@ -590,11 +305,11 @@ StreamView::region_layered (AudioRegionView* rv) get events - the parent group does instead ... */ - rv->get_canvas_group()->raise (rv->region.layer() + 1); + rv->get_canvas_group()->raise (rv->region().layer() + 1); } void -StreamView::rec_enable_changed (void *src) +StreamView::rec_enable_changed () { Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box)); } @@ -611,161 +326,6 @@ StreamView::transport_changed() Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box)); } -void -StreamView::setup_rec_box () -{ - // cerr << _trackview.name() << " streamview SRB\n"; - - if (_trackview.session().transport_rolling()) { - - // cerr << "\trolling\n"; - - if (!rec_active && - _trackview.session().record_status() == Session::Recording && - _trackview.get_diskstream()->record_enabled()) { - - if (_trackview.audio_track()->mode() == Normal && use_rec_regions && rec_regions.size() == rec_rects.size()) { - - /* add a new region, but don't bother if they set use_rec_regions mid-record */ - - AudioRegion::SourceList sources; - - for (list::iterator prc = peak_ready_connections.begin(); prc != peak_ready_connections.end(); ++prc) { - (*prc).disconnect(); - } - peak_ready_connections.clear(); - - for (uint32_t n=0; n < _trackview.get_diskstream()->n_channels(); ++n) { - AudioSource *src = (AudioSource *) _trackview.get_diskstream()->write_source (n); - if (src) { - sources.push_back (src); - peak_ready_connections.push_back (src->PeakRangeReady.connect (bind (mem_fun (*this, &StreamView::rec_peak_range_ready), src))); - } - } - - // handle multi - - jack_nframes_t start = 0; - if (rec_regions.size() > 0) { - start = rec_regions.back()->start() + _trackview.get_diskstream()->get_captured_frames(rec_regions.size()-1); - } - - AudioRegion * region = new AudioRegion(sources, start, 1 , "", 0, (Region::Flag)(Region::DefaultFlags | Region::DoNotSaveState), false); - region->set_position (_trackview.session().transport_frame(), this); - rec_regions.push_back (region); - /* catch it if it goes away */ - region->GoingAway.connect (mem_fun (*this, &StreamView::remove_rec_region)); - - /* we add the region later */ - } - - /* start a new rec box */ - - AudioTrack* at; - - at = _trackview.audio_track(); /* we know what it is already */ - AudioDiskstream& ds = at->disk_stream(); - jack_nframes_t frame_pos = ds.current_capture_start (); - gdouble xstart = _trackview.editor.frame_to_pixel (frame_pos); - gdouble xend; - uint32_t fill_color; - - switch (_trackview.audio_track()->mode()) { - case Normal: - xend = xstart; - fill_color = color_map[cRecordingRectFill]; - break; - - case Destructive: - xend = xstart + 2; - fill_color = color_map[cRecordingRectFill]; - /* make the recording rect translucent to allow - the user to see the peak data coming in, etc. - */ - fill_color = UINT_RGBA_CHANGE_A (fill_color, 120); - break; - } - - ArdourCanvas::SimpleRect * rec_rect = new Gnome::Canvas::SimpleRect (*canvas_group); - rec_rect->property_x1() = xstart; - rec_rect->property_y1() = 1.0; - rec_rect->property_x2() = xend; - rec_rect->property_y2() = (double) _trackview.height - 1; - rec_rect->property_outline_color_rgba() = color_map[cRecordingRectOutline]; - rec_rect->property_fill_color_rgba() = fill_color; - - RecBoxInfo recbox; - recbox.rectangle = rec_rect; - recbox.start = _trackview.session().transport_frame(); - recbox.length = 0; - - rec_rects.push_back (recbox); - - screen_update_connection.disconnect(); - screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun (*this, &StreamView::update_rec_box)); - rec_updating = true; - rec_active = true; - - } else if (rec_active && - (_trackview.session().record_status() != Session::Recording || - !_trackview.get_diskstream()->record_enabled())) { - - screen_update_connection.disconnect(); - rec_active = false; - rec_updating = false; - - } - - } else { - - // cerr << "\tNOT rolling, rec_rects = " << rec_rects.size() << " rec_regions = " << rec_regions.size() << endl; - - if (!rec_rects.empty() || !rec_regions.empty()) { - - /* disconnect rapid update */ - screen_update_connection.disconnect(); - - for (list::iterator prc = peak_ready_connections.begin(); prc != peak_ready_connections.end(); ++prc) { - (*prc).disconnect(); - } - peak_ready_connections.clear(); - - rec_updating = false; - rec_active = false; - last_rec_peak_frame = 0; - - /* remove temp regions */ - for (list::iterator iter=rec_regions.begin(); iter != rec_regions.end(); ) - { - list::iterator tmp; - - tmp = iter; - ++tmp; - - /* this will trigger the remove_region_view */ - delete *iter; - - iter = tmp; - } - - rec_regions.clear(); - - // cerr << "\tclear " << rec_rects.size() << " rec rects\n"; - - - /* transport stopped, clear boxes */ - for (vector::iterator iter=rec_rects.begin(); iter != rec_rects.end(); ++iter) { - RecBoxInfo &rect = (*iter); - delete rect.rectangle; - } - - rec_rects.clear(); - - } - } -} - - void StreamView::update_rec_box () { @@ -776,7 +336,7 @@ StreamView::update_rec_box () double xstart; double xend; - switch (_trackview.audio_track()->mode()) { + switch (_trackview.track()->mode()) { case Normal: rect.length = at - rect.start; xstart = _trackview.editor.frame_to_pixel (rect.start); @@ -795,12 +355,12 @@ StreamView::update_rec_box () } } -AudioRegionView* -StreamView::find_view (const AudioRegion& region) +RegionView* +StreamView::find_view (const Region& region) { - for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { + for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { - if (&(*i)->region == ®ion) { + if (&(*i)->region() == ®ion) { return *i; } } @@ -808,172 +368,51 @@ StreamView::find_view (const AudioRegion& region) } void -StreamView::foreach_regionview (sigc::slot slot) +StreamView::foreach_regionview (sigc::slot slot) { - for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { + for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { slot (*i); } } void -StreamView::foreach_crossfadeview (void (CrossfadeView::*pmf)(void)) +StreamView::set_selected_regionviews (RegionSelection& regions) { - for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - ((*i)->*pmf) (); - } -} - -void -StreamView::rec_peak_range_ready (jack_nframes_t start, jack_nframes_t cnt, Source * src) -{ - // this is called from the peak building thread - - ENSURE_GUI_THREAD(bind (mem_fun (*this, &StreamView::rec_peak_range_ready), start, cnt, src)); - - if (rec_peak_ready_map.size() == 0 || start+cnt > last_rec_peak_frame) { - last_rec_peak_frame = start + cnt; - } - - rec_peak_ready_map[src] = true; - - if (rec_peak_ready_map.size() == _trackview.get_diskstream()->n_channels()) { - this->update_rec_regions (); - rec_peak_ready_map.clear(); - } -} - -void -StreamView::update_rec_regions () -{ - if (use_rec_regions) { - - uint32_t n = 0; - - for (list::iterator iter = rec_regions.begin(); iter != rec_regions.end(); n++) { - - list::iterator tmp; - - tmp = iter; - ++tmp; - - if (!canvas_item_visible (rec_rects[n].rectangle)) { - /* rect already hidden, this region is done */ - iter = tmp; - continue; - } - - AudioRegion * region = (*iter); - jack_nframes_t origlen = region->length(); - - if (region == rec_regions.back() && rec_active) { - - if (last_rec_peak_frame > region->start()) { - - jack_nframes_t nlen = last_rec_peak_frame - region->start(); - - if (nlen != region->length()) { - - region->freeze (); - region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this); - region->set_length (nlen, this); - region->thaw ("updated"); - - if (origlen == 1) { - /* our special initial length */ - add_region_view_internal (region, false); - } - - /* also update rect */ - ArdourCanvas::SimpleRect * rect = rec_rects[n].rectangle; - gdouble xend = _trackview.editor.frame_to_pixel (region->position() + region->length()); - rect->property_x2() = xend; - } - } - - } else { - - jack_nframes_t nlen = _trackview.get_diskstream()->get_captured_frames(n); - - if (nlen != region->length()) { - - if (region->source(0).length() >= region->start() + nlen) { - - region->freeze (); - region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this); - region->set_length (nlen, this); - region->thaw ("updated"); - - if (origlen == 1) { - /* our special initial length */ - add_region_view_internal (region, false); - } - - /* also hide rect */ - ArdourCanvas::Item * rect = rec_rects[n].rectangle; - rect->hide(); + bool selected; - } - } + // cerr << _trackview.name() << " (selected = " << regions.size() << ")" << endl; + for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { + + selected = false; + + for (RegionSelection::iterator ii = regions.begin(); ii != regions.end(); ++ii) { + if (*i == *ii) { + selected = true; } - - iter = tmp; } + + // cerr << "\tregion " << (*i)->region().name() << " selected = " << selected << endl; + (*i)->set_selected (selected); } } void -StreamView::show_all_xfades () -{ - foreach_crossfadeview (&CrossfadeView::show); - crossfades_visible = true; -} - -void -StreamView::hide_all_xfades () -{ - foreach_crossfadeview (&CrossfadeView::hide); - crossfades_visible = false; -} - -void -StreamView::hide_xfades_involving (AudioRegionView& rv) +StreamView::get_selectables (jack_nframes_t start, jack_nframes_t end, list& results) { - for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - if ((*i)->crossfade.involves (rv.region)) { - (*i)->fake_hide (); + for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { + if ((*i)->region().coverage(start, end) != OverlapNone) { + results.push_back (*i); } } } void -StreamView::reveal_xfades_involving (AudioRegionView& rv) +StreamView::get_inverted_selectables (Selection& sel, list& results) { - for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { - if ((*i)->crossfade.involves (rv.region) && (*i)->visible()) { - (*i)->show (); + for (list::iterator i = region_views.begin(); i != region_views.end(); ++i) { + if (!sel.regions.contains (*i)) { + results.push_back (*i); } } } -void -StreamView::color_handler (ColorID id, uint32_t val) -{ - switch (id) { - case cAudioTrackBase: - if (_trackview.is_audio_track()) { - canvas_rect->property_fill_color_rgba() = val; - } - break; - case cAudioBusBase: - if (!_trackview.is_audio_track()) { - canvas_rect->property_fill_color_rgba() = val; - } - break; - case cAudioTrackOutline: - canvas_rect->property_outline_color_rgba() = val; - break; - - default: - break; - } -} diff --git a/gtk2_ardour/streamview.h b/gtk2_ardour/streamview.h index 00ec2d93f2..0bec319758 100644 --- a/gtk2_ardour/streamview.h +++ b/gtk2_ardour/streamview.h @@ -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 @@ -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$ */ #ifndef __ardour_streamview_h__ @@ -37,141 +35,117 @@ namespace Gdk { namespace ARDOUR { class Route; - class AudioDiskstream; + class Diskstream; class Crossfade; class PeakData; - class AudioRegion; + class Region; class Source; } struct RecBoxInfo { - ArdourCanvas::SimpleRect* rectangle; - jack_nframes_t start; - jack_nframes_t length; + ArdourCanvas::SimpleRect* rectangle; + jack_nframes_t start; + jack_nframes_t length; }; class PublicEditor; class Selectable; -class AudioTimeAxisView; -class AudioRegionView; -class AudioRegionSelection; +class RouteTimeAxisView; +class RegionView; +class RegionSelection; class CrossfadeView; class Selection; class StreamView : public sigc::trackable { - public: - StreamView (AudioTimeAxisView&); - ~StreamView (); +public: + virtual ~StreamView (); - void set_waveform_shape (WaveformShape); + RouteTimeAxisView& trackview() { return _trackview; } - AudioTimeAxisView& trackview() { return _trackview; } + void attach (); void set_zoom_all(); - int set_height (gdouble); int set_position (gdouble x, gdouble y); + virtual int set_height (gdouble); - int set_samples_per_unit (gdouble spp); - gdouble get_samples_per_unit () { return _samples_per_unit; } - - int set_amplitude_above_axis (gdouble app); - gdouble get_amplitude_above_axis () { return _amplitude_above_axis; } - - void set_show_waveforms (bool yn); - void set_show_waveforms_recording (bool yn) { use_rec_regions = yn; } + virtual int set_samples_per_unit (gdouble spp); + gdouble get_samples_per_unit () { return _samples_per_unit; } ArdourCanvas::Item* canvas_item() { return canvas_group; } - sigc::signal AudioRegionViewAdded; - enum ColorTarget { RegionColor, StreamBaseColor }; - void apply_color (Gdk::Color&, ColorTarget t); - void set_selected_regionviews (AudioRegionSelection&); + Gdk::Color get_region_color () const { return region_color; } + void apply_color (Gdk::Color&, ColorTarget t); + + RegionView* find_view (const ARDOUR::Region&); + void foreach_regionview (sigc::slot slot); + + void set_selected_regionviews (RegionSelection&); void get_selectables (jack_nframes_t start, jack_nframes_t end, list&); void get_inverted_selectables (Selection&, list& results); - Gdk::Color get_region_color () const { return region_color; } - void foreach_regionview (sigc::slot slot); - void foreach_crossfadeview (void (CrossfadeView::*pmf)(void)); + void add_region_view (ARDOUR::Region*); + void region_layered (RegionView*); + + sigc::signal RegionViewAdded; - void attach (); +protected: + StreamView (RouteTimeAxisView&); - void region_layered (AudioRegionView*); +//private: (FIXME?) + + void transport_changed(); + void rec_enable_changed(); + void sess_rec_enable_changed(); + virtual void setup_rec_box () = 0; + void update_rec_box (); + virtual void update_rec_regions () = 0; - AudioRegionView* find_view (const ARDOUR::AudioRegion&); - - void show_all_xfades (); - void hide_all_xfades (); - void hide_xfades_involving (AudioRegionView&); - void reveal_xfades_involving (AudioRegionView&); + 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 display_diskstream (ARDOUR::Diskstream* ); + virtual void undisplay_diskstream (); + virtual void redisplay_diskstream () = 0; + void diskstream_changed (); + + void playlist_state_changed (ARDOUR::Change); + virtual void playlist_changed (ARDOUR::Diskstream* ); + virtual void playlist_modified (); + + virtual void color_handler (ColorID, uint32_t) = 0; - private: - AudioTimeAxisView& _trackview; - ArdourCanvas::Group* canvas_group; + RouteTimeAxisView& _trackview; + ArdourCanvas::Group* canvas_group; ArdourCanvas::SimpleRect* canvas_rect; /* frame around the whole thing */ - typedef list AudioRegionViewList; - AudioRegionViewList region_views; - - typedef list CrossfadeViewList; - CrossfadeViewList crossfade_views; + typedef list RegionViewList; + RegionViewList region_views; double _samples_per_unit; - double _amplitude_above_axis; - - sigc::connection screen_update_connection; - vector rec_rects; - list rec_regions; - bool rec_updating; - bool rec_active; - bool use_rec_regions; - list peak_ready_connections; - jack_nframes_t last_rec_peak_frame; - map rec_peak_ready_map; - - void update_rec_box (); - void transport_changed(); - void rec_enable_changed(void* src = 0); - void sess_rec_enable_changed(); - void setup_rec_box (); - void rec_peak_range_ready (jack_nframes_t start, jack_nframes_t cnt, ARDOUR::Source* src); - void update_rec_regions (); - - void add_region_view (ARDOUR::Region*); - void add_region_view_internal (ARDOUR::Region*, bool wait_for_waves); - void remove_region_view (ARDOUR::Region* ); - void remove_rec_region (ARDOUR::Region*); - void remove_audio_region_view (ARDOUR::AudioRegion* ); - void remove_audio_rec_region (ARDOUR::AudioRegion*); - - void display_diskstream (ARDOUR::AudioDiskstream* ); - void undisplay_diskstream (); - void redisplay_diskstream (); - void diskstream_changed (void* ); - void playlist_state_changed (ARDOUR::Change); - void playlist_changed (ARDOUR::AudioDiskstream* ); - void playlist_modified (); - - bool crossfades_visible; - void add_crossfade (ARDOUR::Crossfade*); - void remove_crossfade (ARDOUR::Crossfade*); - /* XXX why are these different? */ + sigc::connection screen_update_connection; + vector rec_rects; + list rec_regions; + bool rec_updating; + bool rec_active; + bool use_rec_regions; + /* XXX why are these different? */ Gdk::Color region_color; - uint32_t stream_base_color; - - void color_handler (ColorID, uint32_t); + uint32_t stream_base_color; vector playlist_connections; - sigc::connection playlist_change_connection; + sigc::connection playlist_change_connection; }; #endif /* __ardour_streamview_h__ */ + diff --git a/gtk2_ardour/tape_region_view.cc b/gtk2_ardour/tape_region_view.cc new file mode 100644 index 0000000000..bd5ce8af02 --- /dev/null +++ b/gtk2_ardour/tape_region_view.cc @@ -0,0 +1,101 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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$ +*/ + +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include "tape_region_view.h" +#include "audio_time_axis.h" +#include "gui_thread.h" + +#include "i18n.h" + +using namespace sigc; +using namespace ARDOUR; +using namespace PBD; +using namespace Editing; +using namespace ArdourCanvas; + +const TimeAxisViewItem::Visibility TapeAudioRegionView::default_tape_visibility + = TimeAxisViewItem::Visibility ( + TimeAxisViewItem::ShowNameHighlight | + TimeAxisViewItem::ShowFrame | + TimeAxisViewItem::HideFrameRight | + TimeAxisViewItem::FullWidthNameHighlight); + +TapeAudioRegionView::TapeAudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, + AudioRegion& r, + double spu, + Gdk::Color& basic_color) + + : AudioRegionView (parent, tv, r, spu, basic_color, + TimeAxisViewItem::Visibility ((r.position() != 0) ? default_tape_visibility : + TimeAxisViewItem::Visibility (default_tape_visibility|TimeAxisViewItem::HideFrameLeft))) +{ +} + +void +TapeAudioRegionView::init (Gdk::Color& basic_color, bool wfw) +{ + 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)); + } + +} + +TapeAudioRegionView::~TapeAudioRegionView() +{ +} + +void +TapeAudioRegionView::update (uint32_t n) +{ + /* check that all waves are build and ready */ + + if (!tmp_waves.empty()) { + return; + } + + ENSURE_GUI_THREAD (bind (mem_fun(*this, &TapeAudioRegionView::update), n)); + + /* this triggers a cache invalidation and redraw in the waveview */ + + waves[n]->property_data_src() = &_region; +} + +void +TapeAudioRegionView::set_frame_color () +{ + fill_opacity = 255; + TimeAxisViewItem::set_frame_color (); +} diff --git a/gtk2_ardour/tape_region_view.h b/gtk2_ardour/tape_region_view.h new file mode 100644 index 0000000000..ed3852e3a9 --- /dev/null +++ b/gtk2_ardour/tape_region_view.h @@ -0,0 +1,47 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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$ +*/ + +#ifndef __gtk_ardour_tape_audio_region_view_h__ +#define __gtk_ardour_tape_audio_region_view_h__ + +#include + +#include "audio_region_view.h" + +class TapeAudioRegionView : public AudioRegionView +{ + public: + TapeAudioRegionView (ArdourCanvas::Group *, + RouteTimeAxisView&, + ARDOUR::AudioRegion&, + double initial_samples_per_unit, + Gdk::Color& base_color); + ~TapeAudioRegionView (); + + protected: + void init (Gdk::Color& base_color, bool wait_for_waves); + + void set_frame_color (); + void update (uint32_t n); + + static const TimeAxisViewItem::Visibility default_tape_visibility; +}; + +#endif /* __gtk_ardour_tape_audio_region_view_h__ */ diff --git a/gtk2_ardour/taperegionview.cc b/gtk2_ardour/taperegionview.cc deleted file mode 100644 index 228e45a9d5..0000000000 --- a/gtk2_ardour/taperegionview.cc +++ /dev/null @@ -1,143 +0,0 @@ -/* - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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$ -*/ - -#include -#include - -#include - -#include - -#include -#include -#include -#include - -#include "taperegionview.h" -#include "audio_time_axis.h" -#include "gui_thread.h" - -#include "i18n.h" - -using namespace sigc; -using namespace ARDOUR; -using namespace PBD; -using namespace Editing; -using namespace ArdourCanvas; - -const TimeAxisViewItem::Visibility TapeAudioRegionView::default_tape_visibility = TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameHighlight| - TimeAxisViewItem::ShowFrame| - TimeAxisViewItem::HideFrameRight| - TimeAxisViewItem::FullWidthNameHighlight); - -TapeAudioRegionView::TapeAudioRegionView (ArdourCanvas::Group *parent, AudioTimeAxisView &tv, - AudioRegion& r, - double spu, - Gdk::Color& basic_color) - - : AudioRegionView (parent, tv, r, spu, basic_color, - TimeAxisViewItem::Visibility ((r.position() != 0) ? default_tape_visibility : - TimeAxisViewItem::Visibility (default_tape_visibility|TimeAxisViewItem::HideFrameLeft))) -{ -} - -void -TapeAudioRegionView::init (double amplitude_above_axis, Gdk::Color& basic_color, bool wfw) -{ - XMLNode *node; - - editor = 0; - valid = true; - in_destructor = false; - _amplitude_above_axis = amplitude_above_axis; - 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)); - - /* every time the wave data changes and peaks are ready, redraw */ - - - for (uint32_t n = 0; n < region.n_channels(); ++n) { - region.source(n).PeaksReady.connect (bind (mem_fun(*this, &TapeAudioRegionView::update), n)); - } - -} - -TapeAudioRegionView::~TapeAudioRegionView() -{ -} - -void -TapeAudioRegionView::update (uint32_t n) -{ - /* check that all waves are build and ready */ - - if (!tmp_waves.empty()) { - return; - } - - ENSURE_GUI_THREAD (bind (mem_fun(*this, &TapeAudioRegionView::update), n)); - - /* this triggers a cache invalidation and redraw in the waveview */ - - waves[n]->property_data_src() = ®ion; -} - -void -TapeAudioRegionView::set_frame_color () -{ - fill_opacity = 255; - TimeAxisViewItem::set_frame_color (); -} diff --git a/gtk2_ardour/taperegionview.h b/gtk2_ardour/taperegionview.h deleted file mode 100644 index 6b4a57fc97..0000000000 --- a/gtk2_ardour/taperegionview.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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$ -*/ - -#ifndef __gtk_ardour_tape_audio_region_view_h__ -#define __gtk_ardour_tape_audio_region_view_h__ - -#include - -#include "regionview.h" - -class TapeAudioRegionView : public AudioRegionView -{ - public: - TapeAudioRegionView (ArdourCanvas::Group *, - AudioTimeAxisView&, - ARDOUR::AudioRegion&, - double initial_samples_per_unit, - Gdk::Color& base_color); - ~TapeAudioRegionView (); - - protected: - void init (double amplitude_above_axis, Gdk::Color& base_color, bool wait_for_waves); - - void set_frame_color (); - void update (uint32_t n); - - static const TimeAxisViewItem::Visibility default_tape_visibility; -}; - -#endif /* __gtk_ardour_tape_audio_region_view_h__ */ diff --git a/gtk2_ardour/time_axis_view.h b/gtk2_ardour/time_axis_view.h index c607c78166..31ff3d84ee 100644 --- a/gtk2_ardour/time_axis_view.h +++ b/gtk2_ardour/time_axis_view.h @@ -54,7 +54,7 @@ namespace Gtk { } class PublicEditor; -class AudioRegionSelection; +class RegionSelection; class TimeSelection; class PointSelection; class TimeAxisViewItem; @@ -183,7 +183,7 @@ class TimeAxisView : public virtual AxisView virtual bool cut_copy_clear (Selection&, Editing::CutCopyOp) { return false; } virtual bool paste (jack_nframes_t, float times, Selection&, size_t nth) { return false; } - virtual void set_selected_regionviews (AudioRegionSelection&) {} + virtual void set_selected_regionviews (RegionSelection&) {} virtual void set_selected_points (PointSelection&) {} virtual ARDOUR::Region* find_next_region (jack_nframes_t pos, ARDOUR::RegionPoint, int32_t dir) { diff --git a/gtk2_ardour/visual_time_axis.cc b/gtk2_ardour/visual_time_axis.cc index c27ed33089..e44ea4011e 100644 --- a/gtk2_ardour/visual_time_axis.cc +++ b/gtk2_ardour/visual_time_axis.cc @@ -255,7 +255,7 @@ VisualTimeAxis::set_time_axis_color(Gdk::Color c) } void -VisualTimeAxis::set_selected_regionviews (AudioRegionSelection& regions) +VisualTimeAxis::set_selected_regionviews (RegionSelection& regions) { // Not handled by purely visual TimeAxis } diff --git a/gtk2_ardour/visual_time_axis.h b/gtk2_ardour/visual_time_axis.h index 4be2da3b9a..c68ce8da1c 100644 --- a/gtk2_ardour/visual_time_axis.h +++ b/gtk2_ardour/visual_time_axis.h @@ -42,7 +42,7 @@ class ImageFrameView; class ImageFrameTimeAxisView; class MarkersTimeAxisView; class TimeSelection; -class AudioRegionSelection; +class RegionSelection; class MarkerTimeAxis; class TimeAxisViewStrip; @@ -105,7 +105,7 @@ class VisualTimeAxis : public TimeAxisView /** * Not implemented */ - virtual void set_selected_regionviews(AudioRegionSelection&) ; + virtual void set_selected_regionviews(RegionSelection&) ; //---------------------------------------------------------------------------------// diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 1c30921353..303f021f42 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -27,9 +27,11 @@ ardour.Append(POTFILE = domain + '.pot') ardour.Append(CPPPATH = '#libs/surfaces/control_protocol') ardour_files=Split(""" +diskstream.cc audio_diskstream.cc audio_library.cc audio_playlist.cc +track.cc audio_track.cc audioengine.cc audiofilesource.cc diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index 0a0c908d31..e2dfc5fd0c 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,12 +14,10 @@ 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_diskstream_h__ -#define __ardour_diskstream_h__ +#ifndef __ardour_audio_diskstream_h__ +#define __ardour_audio_diskstream_h__ #include @@ -42,6 +40,8 @@ #include #include #include +#include +#include struct tm; @@ -54,53 +54,20 @@ class AudioPlaylist; class AudioFileSource; class IO; -class AudioDiskstream : public Stateful, public sigc::trackable +class AudioDiskstream : public Diskstream { public: - enum Flag { - Recordable = 0x1, - Hidden = 0x2, - Destructive = 0x4 - }; - - AudioDiskstream (Session &, const string& name, Flag f = Recordable); + AudioDiskstream (Session &, const string& name, Diskstream::Flag f = Recordable); AudioDiskstream (Session &, const XMLNode&); - string name() const { return _name; } - - ARDOUR::IO* io() const { return _io; } - void set_io (ARDOUR::IO& io); + const PBD::ID& id() const { return _id; } + // 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_flag (Flag f) { - _flags |= f; - } - - void unset_flag (Flag f) { - _flags &= ~f; - } - - AlignStyle alignment_style() const { return _alignment_style; } - void set_align_style (AlignStyle); - void set_persistent_align_style (AlignStyle); - - bool hidden() const { return _flags & Hidden; } - bool recordable() const { return _flags & Recordable; } - bool destructive() const { return _flags & Destructive; } - - void set_destructive (bool yn); - - jack_nframes_t roll_delay() const { return _roll_delay; } - void set_roll_delay (jack_nframes_t); - - int set_name (string str, void* src); - string input_source (uint32_t n=0) const { if (n < channels.size()) { return channels[n].source ? channels[n].source->name() : ""; @@ -113,14 +80,7 @@ class AudioDiskstream : public Stateful, public sigc::trackable if (n < channels.size()) return channels[n].source; return 0; } - void set_record_enabled (bool yn, void *src); - bool record_enabled() const { return g_atomic_int_get (&_record_enabled); } - void punch_in (); - void punch_out (); - - bool reversed() const { return _actual_speed < 0.0f; } - double speed() const { return _visible_speed; } - void set_speed (double); + void set_record_enabled (bool yn); float peak_power(uint32_t n=0) { float x = channels[n].peak_power; @@ -131,14 +91,13 @@ class AudioDiskstream : public Stateful, public sigc::trackable return minus_infinity(); } } + + AudioPlaylist* audio_playlist () { return dynamic_cast(_playlist); } - int use_playlist (AudioPlaylist *); + int use_playlist (Playlist *); int use_new_playlist (); int use_copy_playlist (); - void start_scrub (jack_nframes_t where); - void end_scrub (); - Sample *playback_buffer (uint32_t n=0) { if (n < channels.size()) return channels[n].current_playback_buffer; @@ -151,51 +110,23 @@ class AudioDiskstream : public Stateful, public sigc::trackable return 0; } - AudioPlaylist *playlist () { return _playlist; } - AudioFileSource *write_source (uint32_t n=0) { if (n < channels.size()) return channels[n].write_source; return 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); - jack_nframes_t get_captured_frames (uint32_t n=0); - - uint32_t n_channels() { return _n_channels; } - int add_channel (); int remove_channel (); - static void set_disk_io_chunk_frames (uint32_t n) { - disk_io_chunk_frames = n; - } - - static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; } - sigc::signal record_enable_changed; - sigc::signal speed_changed; - sigc::signal reverse_changed; - sigc::signal PlaylistChanged; - sigc::signal AlignmentStyleChanged; - - static sigc::signal DiskOverrun; - static sigc::signal DiskUnderrun; - static sigc::signal AudioDiskstreamCreated; // XXX use a ref with sigc2 - static sigc::signal*> DeleteSources; - /* stateful */ XMLNode& get_state(void); - int set_state(const XMLNode& node); + int set_state(const XMLNode& node); void monitor_input (bool); - jack_nframes_t capture_offset() const { return _capture_offset; } - void set_capture_offset (); - static void swap_by_ptr (Sample *first, Sample *last) { while (first < last) { Sample tmp = *first; @@ -212,19 +143,7 @@ class AudioDiskstream : public Stateful, public sigc::trackable } } - bool slaved() const { return _slaved; } - void set_slaved(bool yn) { _slaved = yn; } - - int set_loop (Location *loc); - sigc::signal LoopSet; - - std::list& last_capture_regions () { - return _last_capture_regions; - } - - void handle_input_change (IOChange, void *src); - - const PBD::ID& id() const { return _id; } + std::list& last_capture_regions () { return _last_capture_regions; } XMLNode* deprecated_io_node; @@ -236,9 +155,8 @@ class AudioDiskstream : public Stateful, public sigc::trackable while they are called. */ - void set_pending_overwrite (bool); + void set_pending_overwrite(bool); int overwrite_existing_buffers (); - void reverse_scrub_buffer (bool to_forward); void set_block_size (jack_nframes_t); int internal_playback_seek (jack_nframes_t distance); int can_internal_playback_seek (jack_nframes_t distance); @@ -246,9 +164,6 @@ class AudioDiskstream : public Stateful, public sigc::trackable void reset_write_sources (bool, bool force = false); void non_realtime_input_change (); - uint32_t read_data_count() const { return _read_data_count; } - uint32_t write_data_count() const { return _write_data_count; } - protected: friend class Auditioner; int seek (jack_nframes_t which_sample, bool complete_refill = false); @@ -256,38 +171,23 @@ class AudioDiskstream : public Stateful, public sigc::trackable protected: friend class AudioTrack; - void prepare (); int process (jack_nframes_t transport_frame, jack_nframes_t nframes, jack_nframes_t offset, bool can_record, bool rec_monitors_input); bool commit (jack_nframes_t nframes); - void recover (); /* called if commit will not be called, but process was */ private: /* use unref() to destroy a diskstream */ - ~AudioDiskstream(); - enum TransitionType { - CaptureStart = 0, - CaptureEnd - }; - - struct CaptureTransition { - - TransitionType type; - // the start or end file frame pos - jack_nframes_t capture_val; - }; - struct ChannelInfo { Sample *playback_wrap_buffer; Sample *capture_wrap_buffer; Sample *speed_buffer; - float peak_power; + float peak_power; - AudioFileSource *fades_source; + AudioFileSource *fades_source; AudioFileSource *write_source; Port *source; @@ -309,129 +209,30 @@ class AudioDiskstream : public Stateful, public sigc::trackable jack_nframes_t curr_capture_cnt; }; - typedef vector ChannelList; - - - string _name; - ARDOUR::Session& _session; - ARDOUR::IO* _io; - ChannelList channels; - uint32_t _n_channels; - PBD::ID _id; - - mutable gint _record_enabled; - AudioPlaylist* _playlist; - double _visible_speed; - double _actual_speed; - /* items needed for speed change logic */ - bool _buffer_reallocation_required; - bool _seek_required; - - bool force_refill; - jack_nframes_t capture_start_frame; - jack_nframes_t capture_captured; - bool was_recording; - jack_nframes_t adjust_capture_position; - jack_nframes_t _capture_offset; - jack_nframes_t _roll_delay; - jack_nframes_t first_recordable_frame; - jack_nframes_t last_recordable_frame; - int last_possibly_recording; - AlignStyle _alignment_style; - bool _scrubbing; - bool _slaved; - bool _processed; - Location* loop_location; - jack_nframes_t overwrite_frame; - off_t overwrite_offset; - bool pending_overwrite; - bool overwrite_queued; - IOChange input_change_pending; - jack_nframes_t wrap_buffer_size; - jack_nframes_t speed_buffer_size; - - uint64_t last_phase; - uint64_t phi; - - jack_nframes_t file_frame; - jack_nframes_t playback_sample; - jack_nframes_t playback_distance; - - uint32_t _read_data_count; - uint32_t _write_data_count; - - bool in_set_state; - AlignStyle _persistent_alignment_style; - bool first_input_change; - - Glib::Mutex state_lock; - - jack_nframes_t scrub_start; - jack_nframes_t scrub_buffer_size; - jack_nframes_t scrub_offset; - uint32_t _refcnt; - - sigc::connection ports_created_c; - sigc::connection plmod_connection; - sigc::connection plstate_connection; - sigc::connection plgone_connection; - - /* the two central butler operations */ - - int do_flush (char * workbuf, bool force = false); - int do_refill (Sample *mixdown_buffer, float *gain_buffer, char *workbuf); - - 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); - - uint32_t i_am_the_modifier; + /* 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); } - /* XXX fix this redundancy ... */ + int do_refill_with_alloc(); - void playlist_changed (Change); - void playlist_modified (); - void playlist_deleted (Playlist*); - void session_controls_changed (Session::ControlType); + 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); 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 (Flag); + void init (Diskstream::Flag); void init_channel (ChannelInfo &chan); void destroy_channel (ChannelInfo &chan); - static jack_nframes_t disk_io_chunk_frames; - int use_new_write_source (uint32_t n=0); - int use_new_fade_source (uint32_t n=0); int find_and_use_playlist (const string&); void allocate_temporary_buffers (); - unsigned char _flags; - - int create_input_port (); - int connect_input_port (); - int seek_unlocked (jack_nframes_t which_sample); - - int ports_created (); - - 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 (); @@ -439,10 +240,29 @@ class AudioDiskstream : public Stateful, public sigc::trackable void set_align_style_from_io(); void setup_destructive_playlist (); void use_destructive_playlist (); - void engage_record_enable (void* src); - void disengage_record_enable (void* src); + + void engage_record_enable (); + void disengage_record_enable (); + + // 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 -#endif /* __ardour_diskstream_h__ */ +#endif /* __ardour_audio_diskstream_h__ */ diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h index 5f65e2591d..15b99297c8 100644 --- a/libs/ardour/ardour/audio_track.h +++ b/libs/ardour/ardour/audio_track.h @@ -21,7 +21,7 @@ #ifndef __ardour_audio_track_h__ #define __ardour_audio_track_h__ -#include +#include namespace ARDOUR { @@ -30,76 +30,38 @@ class AudioDiskstream; class AudioPlaylist; class RouteGroup; -class AudioTrack : public Route +class AudioTrack : public Track { public: AudioTrack (Session&, string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal); AudioTrack (Session&, const XMLNode&); ~AudioTrack (); - - int set_name (string str, void *src); - - int roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, - jack_nframes_t offset, int declick, bool can_record, bool rec_monitors_input); - int no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, - jack_nframes_t offset, bool state_changing, bool can_record, bool rec_monitors_input); - int silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, - jack_nframes_t offset, bool can_record, bool rec_monitors_input); - - void toggle_monitor_input (); + int roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, + jack_nframes_t offset, int declick, bool can_record, bool rec_monitors_input); + + int no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, + jack_nframes_t offset, bool state_changing, bool can_record, bool rec_monitors_input); + + int silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, + jack_nframes_t offset, bool can_record, bool rec_monitors_input); - bool can_record() const { return true; } - void set_record_enable (bool yn, void *src); + AudioDiskstream& audio_diskstream() const; - AudioDiskstream& disk_stream() const { return *diskstream; } - int set_diskstream (AudioDiskstream&, void *); int use_diskstream (string name); int use_diskstream (const PBD::ID& id); - - TrackMode mode() const { return _mode; } - void set_mode (TrackMode m); - sigc::signal ModeChanged; - - jack_nframes_t update_total_latency(); - void set_latency_delay (jack_nframes_t); int export_stuff (vector& buffers, char * workbuf, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t end_frame); - sigc::signal diskstream_changed; - - enum FreezeState { - NoFreeze, - Frozen, - UnFrozen - }; - - FreezeState freeze_state() const; - - sigc::signal FreezeChange; - void freeze (InterThreadInfo&); void unfreeze (); void bounce (InterThreadInfo&); void bounce_range (jack_nframes_t start, jack_nframes_t end, InterThreadInfo&); - XMLNode& get_state(); - XMLNode& get_template(); int set_state(const XMLNode& node); - PBD::Controllable& rec_enable_control() { - return _rec_enable_control; - } - - bool record_enabled() const; - void set_meter_point (MeterPoint, void* src); - protected: - AudioDiskstream *diskstream; - MeterPoint _saved_meter_point; - TrackMode _mode; - XMLNode& state (bool full); void passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame, @@ -107,59 +69,12 @@ class AudioTrack : public Route bool meter); uint32_t n_process_buffers (); - + private: - struct FreezeRecordInsertInfo { - FreezeRecordInsertInfo(XMLNode& st, boost::shared_ptr ins) - : state (st), insert (ins) {} - - XMLNode state; - boost::shared_ptr insert; - PBD::ID id; - UndoAction memento; - }; - - struct FreezeRecord { - FreezeRecord() { - playlist = 0; - have_mementos = false; - } - - ~FreezeRecord(); - - AudioPlaylist* playlist; - vector insert_info; - bool have_mementos; - FreezeState state; - }; - - FreezeRecord _freeze_record; - XMLNode* pending_state; - - void diskstream_record_enable_changed (void *src); - void diskstream_input_channel_changed (void *src); - - void input_change_handler (void *src); - - sigc::connection recenable_connection; - sigc::connection ic_connection; - - int deprecated_use_diskstream_connections (); + int set_diskstream (AudioDiskstream&, void *); + int deprecated_use_diskstream_connections (); void set_state_part_two (); void set_state_part_three (); - - struct RecEnableControllable : public PBD::Controllable { - RecEnableControllable (AudioTrack&); - - void set_value (float); - float get_value (void) const; - - AudioTrack& track; - }; - - RecEnableControllable _rec_enable_control; - - bool _destructive; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 8db795ae90..81370e379c 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -34,6 +34,7 @@ #include #include #include +#include namespace ARDOUR { @@ -104,8 +105,8 @@ class AudioEngine : public sigc::trackable virtual const char *what() const throw() { return "could not connect to engine backend"; } }; - Port *register_audio_input_port (const std::string& portname); - Port *register_audio_output_port (const std::string& portname); + Port *register_input_port (DataType type, const std::string& portname); + Port *register_output_port (DataType type, const std::string& portname); int unregister_port (Port *); int connect (const std::string& source, const std::string& destination); diff --git a/libs/ardour/ardour/audioplaylist.h b/libs/ardour/ardour/audioplaylist.h index 1b60cf185d..5a77067f8f 100644 --- a/libs/ardour/ardour/audioplaylist.h +++ b/libs/ardour/ardour/audioplaylist.h @@ -77,9 +77,6 @@ class AudioPlaylist : public ARDOUR::Playlist bool destroy_region (Region*); - void get_equivalent_regions (const AudioRegion&, std::vector&); - void get_region_list_equivalent_regions (const AudioRegion&, std::vector&); - void drop_all_states (); protected: diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index d7bb0c916b..683e946713 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -27,8 +27,9 @@ #include #include -#include #include +#include +#include #include class XMLNode; @@ -43,14 +44,14 @@ class AudioSource; struct AudioRegionState : public RegionState { - AudioRegionState (std::string why); - - Curve _fade_in; - Curve _fade_out; - Curve _envelope; - gain_t _scale_amplitude; - uint32_t _fade_in_disabled; - uint32_t _fade_out_disabled; + AudioRegionState (std::string why); + + Curve _fade_in; + Curve _fade_out; + Curve _envelope; + gain_t _scale_amplitude; + uint32_t _fade_in_disabled; + uint32_t _fade_out_disabled; }; class AudioRegion : public Region @@ -75,11 +76,7 @@ class AudioRegion : public Region AudioRegion (SourceList &, const XMLNode&); ~AudioRegion(); - bool region_list_equivalent (const AudioRegion&) const ; - bool source_equivalent (const AudioRegion&) const; - bool equivalent (const AudioRegion&) const; - bool size_equivalent (const AudioRegion&) const; - bool overlap_equivalent (const AudioRegion&) const; + bool source_equivalent (const Region&) const; bool speed_mismatch (float) const; @@ -96,7 +93,7 @@ class AudioRegion : public Region vector master_source_names(); bool envelope_active () const { return _flags & Region::EnvelopeActive; } - bool fade_in_active () const { return _flags & Region::FadeIn; } + bool fade_in_active () const { return _flags & Region::FadeIn; } bool fade_out_active () const { return _flags & Region::FadeOut; } bool captured() const { return !(_flags & (Region::Flag (Region::Import|Region::External))); } @@ -104,20 +101,21 @@ class AudioRegion : public Region Curve& fade_out() { return _fade_out; } Curve& envelope() { return _envelope; } - jack_nframes_t read_peaks (PeakData *buf, jack_nframes_t npeaks, jack_nframes_t offset, jack_nframes_t cnt, uint32_t chan_n=0, double samples_per_unit= 1.0) const; - - virtual jack_nframes_t read_at (Sample *buf, Sample *mixdown_buffer, - float *gain_buffer, char * workbuf, jack_nframes_t position, jack_nframes_t cnt, - uint32_t chan_n = 0, - jack_nframes_t read_frames = 0, - jack_nframes_t skip_frames = 0) const; + jack_nframes_t read_peaks (PeakData *buf, jack_nframes_t npeaks, + jack_nframes_t offset, jack_nframes_t cnt, + uint32_t chan_n=0, double samples_per_unit= 1.0) const; - jack_nframes_t master_read_at (Sample *buf, Sample *mixdown_buffer, - float *gain_buffer, char * workbuf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n=0) const; + virtual jack_nframes_t read_at (Sample *buf, Sample *mixdown_buf, + float *gain_buf, char * workbuf, jack_nframes_t position, jack_nframes_t cnt, + uint32_t chan_n = 0, + jack_nframes_t read_frames = 0, + jack_nframes_t skip_frames = 0) const; + jack_nframes_t master_read_at (Sample *buf, Sample *mixdown_buf, + float *gain_buf, char * workbuf, + jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n=0) const; XMLNode& state (bool); - XMLNode& get_state (); int set_state (const XMLNode&); static void set_default_fade (float steepness, jack_nframes_t len); @@ -144,10 +142,6 @@ class AudioRegion : public Region int separate_by_channel (ARDOUR::Session&, vector&) const; - uint32_t read_data_count() const { return _read_data_count; } - - ARDOUR::Playlist* playlist() const { return _playlist; } - UndoAction get_memento() const; /* filter */ @@ -171,20 +165,6 @@ class AudioRegion : public Region friend class Playlist; private: - SourceList sources; - SourceList master_sources; /* used when timefx are applied, so - we can always use the original - source. - */ - mutable Curve _fade_in; - FadeShape _fade_in_shape; - mutable Curve _fade_out; - FadeShape _fade_out_shape; - mutable Curve _envelope; - gain_t _scale_amplitude; - uint32_t _fade_in_disabled; - uint32_t _fade_out_disabled; - void set_default_fades (); void set_default_fade_in (); void set_default_fade_out (); @@ -196,10 +176,6 @@ class AudioRegion : public Region void recompute_gain_at_end (); void recompute_gain_at_start (); - bool copied() const { return _flags & Copied; } - void maybe_uncopy (); - void rename_after_first_edit (); - jack_nframes_t _read_at (const SourceList&, Sample *buf, Sample *mixdown_buffer, float *gain_buffer, char * workbuf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n = 0, @@ -216,6 +192,21 @@ class AudioRegion : public Region void envelope_changed (Change); void source_deleted (Source*); + + + SourceList sources; + + /** Used when timefx are applied, so we can always use the original source. */ + SourceList master_sources; + + mutable Curve _fade_in; + FadeShape _fade_in_shape; + mutable Curve _fade_out; + FadeShape _fade_out_shape; + mutable Curve _envelope; + gain_t _scale_amplitude; + uint32_t _fade_in_disabled; + uint32_t _fade_out_disabled; }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/buffer.h b/libs/ardour/ardour/buffer.h new file mode 100644 index 0000000000..6604e5533b --- /dev/null +++ b/libs/ardour/ardour/buffer.h @@ -0,0 +1,144 @@ +/* + Copyright (C) 2006 Paul Davis + Written by Dave Robillard, 2006 + + 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 the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + 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. +*/ + +#ifndef __ardour_buffer_h__ +#define __ardour_buffer_h__ + +#define _XOPEN_SOURCE 600 +#include // for posix_memalign +#include +#include +#include + +namespace ARDOUR { + + +/* Yes, this is a bit of a mess right now. I'll clean it up when everything + * using it works out.. */ + + +/** A buffer of recordable/playable data. + * + * This is a datatype-agnostic base class for all buffers (there are no + * methods to actually access the data). This provides a way for code that + * doesn't care about the data type to still deal with buffers (which is + * why the base class can't be a template). + * + * To actually read/write buffer contents, use the appropriate derived class. + */ +class Buffer +{ +public: + Buffer(DataType type, size_t capacity) + : _type(type), _capacity(capacity), _size(0) + {} + + virtual ~Buffer() {} + + /** Maximum capacity of buffer. + * Note in some cases the entire buffer may not contain valid data, use size. */ + size_t capacity() const { return _capacity; } + + /** Amount of valid data in buffer. Use this over capacity almost always. */ + size_t size() const { return _size; } + + /** Type of this buffer. + * Based on this you can static cast a Buffer* to the desired type. */ + virtual DataType type() const { return _type; } + + /** Jack type (eg JACK_DEFAULT_AUDIO_TYPE) */ + const char* jack_type() const { return type_to_jack_type(type()); } + + /** String type as saved in session XML files (eg "audio" or "midi") */ + const char* type_string() const { return type_to_string(type()); } + + /* The below static methods need to be separate from the above methods + * because the conversion is needed in places where there's no Buffer. + * These should probably live somewhere else... + */ + + static const char* type_to_jack_type(DataType t) { + switch (t) { + case AUDIO: return JACK_DEFAULT_AUDIO_TYPE; + case MIDI: return JACK_DEFAULT_MIDI_TYPE; + default: return ""; + } + } + + static const char* type_to_string(DataType t) { + switch (t) { + case AUDIO: return "audio"; + case MIDI: return "midi"; + default: return "unknown"; // reeeally shouldn't ever happen + } + } + + /** Used for loading from XML (route default types etc) */ + static DataType type_from_string(const string& str) { + if (str == "audio") + return AUDIO; + else if (str == "midi") + return MIDI; + else + return NIL; + } + +protected: + DataType _type; + size_t _capacity; + size_t _size; +}; + + +/* Inside every class with a type in it's name is a template waiting to get out... */ + + +/** Buffer containing 32-bit floating point (audio) data. */ +class AudioBuffer : public Buffer +{ +public: + AudioBuffer(size_t capacity) + : Buffer(AUDIO, capacity) + , _data(NULL) + { + _size = capacity; // For audio buffers, size = capacity (always) +#ifdef NO_POSIX_MEMALIGN + b = (Sample *) malloc(sizeof(Sample) * capacity); +#else + posix_memalign((void**)_data, 16, sizeof(Sample) * capacity); +#endif + assert(_data); + memset(_data, 0, sizeof(Sample) * capacity); + } + + const Sample* data() const { return _data; } + Sample* data() { return _data; } + +private: + // These are undefined (prevent copies) + AudioBuffer(const AudioBuffer& copy); + AudioBuffer& operator=(const AudioBuffer& copy); + + Sample* const _data; ///< Actual buffer contents +}; + + +} // namespace ARDOUR + +#endif // __ardour_buffer_h__ diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h new file mode 100644 index 0000000000..ebce516d8b --- /dev/null +++ b/libs/ardour/ardour/diskstream.h @@ -0,0 +1,319 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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_diskstream_h__ +#define __ardour_diskstream_h__ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +struct tm; + +namespace ARDOUR { + +class AudioEngine; +class Send; +class Session; +class Playlist; +class IO; + +class Diskstream : public Stateful, public sigc::trackable +{ + public: + enum Flag { + Recordable = 0x1, + Hidden = 0x2, + Destructive = 0x4 + }; + + string name () const { return _name; } + virtual int set_name (string str); + + ARDOUR::IO* io() const { return _io; } + void set_io (ARDOUR::IO& io); + + virtual Diskstream& ref() { _refcnt++; return *this; } + void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; } + uint32_t refcnt() const { return _refcnt; } + + virtual float playback_buffer_load() const = 0; + virtual float capture_buffer_load() const = 0; + + void set_flag (Flag f) { _flags |= f; } + void unset_flag (Flag f) { _flags &= ~f; } + + AlignStyle alignment_style() const { return _alignment_style; } + void set_align_style (AlignStyle); + void set_persistent_align_style (AlignStyle a) { _persistent_alignment_style = a; } + + jack_nframes_t roll_delay() const { return _roll_delay; } + void set_roll_delay (jack_nframes_t); + + bool record_enabled() const { return g_atomic_int_get (&_record_enabled); } + virtual void set_record_enabled (bool yn) = 0; + + bool destructive() const { return _flags & Destructive; } + virtual void set_destructive (bool yn); + + const PBD::ID& id() const { return _id; } + bool hidden() const { return _flags & Hidden; } + bool recordable() const { return _flags & Recordable; } + bool reversed() const { return _actual_speed < 0.0f; } + double speed() const { return _visible_speed; } + + virtual void punch_in() {} + virtual void punch_out() {} + + void set_speed (double); + void non_realtime_set_speed (); + + Playlist* playlist () { return _playlist; } + + virtual int use_playlist (Playlist *); + virtual int use_new_playlist () = 0; + virtual int use_copy_playlist () = 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); + jack_nframes_t get_captured_frames (uint32_t n=0); + + uint32_t n_channels() { return _n_channels; } + + 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 */ + virtual XMLNode& get_state(void) = 0; + virtual int set_state(const XMLNode& node) = 0; + + // FIXME: makes sense for all diskstream types? + virtual void monitor_input (bool) {} + + jack_nframes_t capture_offset() const { return _capture_offset; } + virtual void set_capture_offset (); + + bool slaved() const { return _slaved; } + void set_slaved(bool yn) { _slaved = yn; } + + int set_loop (Location *loc); + + std::list& last_capture_regions () { return _last_capture_regions; } + + void handle_input_change (IOChange, void *src); + + sigc::signal RecordEnableChanged; + sigc::signal SpeedChanged; + sigc::signal ReverseChanged; + sigc::signal PlaylistChanged; + sigc::signal AlignmentStyleChanged; + sigc::signal LoopSet; + + static sigc::signal DiskOverrun; + static sigc::signal DiskUnderrun; + static sigc::signal DiskstreamCreated; // XXX use a ref with sigc2 + static sigc::signal*> DeleteSources; + + protected: + friend class Session; + + Diskstream (Session &, const string& name, Flag f = Recordable); + Diskstream (Session &, const XMLNode&); + + /* the Session is the only point of access for these because they require + * that the Session is "inactive" while they are called. + */ + + virtual void set_pending_overwrite (bool) = 0; + virtual int overwrite_existing_buffers () = 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; + virtual int rename_write_sources () = 0; + virtual void reset_write_sources (bool, bool force = false) = 0; + virtual void non_realtime_input_change () = 0; + + uint32_t read_data_count() const { return _read_data_count; } + uint32_t write_data_count() const { return _write_data_count; } + + protected: + friend class Auditioner; + virtual int seek (jack_nframes_t which_sample, bool complete_refill = false) = 0; + + protected: + friend class Track; + + virtual void prepare (); + virtual int process (jack_nframes_t transport_frame, jack_nframes_t nframes, jack_nframes_t offset, bool can_record, bool rec_monitors_input) = 0; + virtual bool commit (jack_nframes_t nframes) = 0; + virtual void recover (); /* called if commit will not be called, but process was */ + + //private: + + /** Use unref() to destroy a diskstream */ + virtual ~Diskstream(); + + enum TransitionType { + CaptureStart = 0, + CaptureEnd + }; + + struct CaptureTransition { + TransitionType type; + jack_nframes_t capture_val; ///< The start or end file frame position + }; + + /* The two central butler operations */ + virtual int do_flush (Session::RunContext context, bool force = false) = 0; + virtual int do_refill () = 0; + + /** For non-butler contexts (allocates temporary working buffers) */ + virtual int do_refill_with_alloc() = 0; + + + /* XXX fix this redundancy ... */ + + virtual void playlist_changed (Change); + virtual void playlist_modified (); + virtual void playlist_deleted (Playlist*); + + virtual void finish_capture (bool rec_monitors_input) = 0; + virtual void transport_stopped (struct tm&, time_t, bool abort) = 0; + + struct CaptureInfo { + uint32_t start; + uint32_t frames; + }; + + virtual void init (Flag); + + virtual int use_new_write_source (uint32_t n=0) = 0; + + virtual int find_and_use_playlist (const string&) = 0; + + virtual void allocate_temporary_buffers () = 0; + + virtual bool realtime_set_speed (double, bool global_change); + + std::list _last_capture_regions; + 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; + virtual void set_align_style_from_io() {} + virtual void setup_destructive_playlist () = 0; + virtual void use_destructive_playlist () = 0; + + static jack_nframes_t disk_io_chunk_frames; + vector capture_info; + Glib::Mutex capture_info_lock; + + uint32_t i_am_the_modifier; + + string _name; + ARDOUR::Session& _session; + ARDOUR::IO* _io; + uint32_t _n_channels; + PBD::ID _id; + Playlist* _playlist; + + mutable gint _record_enabled; + double _visible_speed; + double _actual_speed; + /* items needed for speed change logic */ + bool _buffer_reallocation_required; + bool _seek_required; + + bool force_refill; + jack_nframes_t capture_start_frame; + jack_nframes_t capture_captured; + bool was_recording; + jack_nframes_t adjust_capture_position; + jack_nframes_t _capture_offset; + jack_nframes_t _roll_delay; + jack_nframes_t first_recordable_frame; + jack_nframes_t last_recordable_frame; + int last_possibly_recording; + AlignStyle _alignment_style; + bool _scrubbing; + bool _slaved; + bool _processed; + Location* loop_location; + jack_nframes_t overwrite_frame; + off_t overwrite_offset; + bool pending_overwrite; + bool overwrite_queued; + IOChange input_change_pending; + jack_nframes_t wrap_buffer_size; + jack_nframes_t speed_buffer_size; + + uint64_t last_phase; + uint64_t phi; + + jack_nframes_t file_frame; + jack_nframes_t playback_sample; + jack_nframes_t playback_distance; + + uint32_t _read_data_count; + uint32_t _write_data_count; + + bool in_set_state; + AlignStyle _persistent_alignment_style; + bool first_input_change; + + Glib::Mutex state_lock; + + jack_nframes_t scrub_start; + jack_nframes_t scrub_buffer_size; + jack_nframes_t scrub_offset; + + uint32_t _refcnt; + + sigc::connection ports_created_c; + sigc::connection plmod_connection; + sigc::connection plstate_connection; + sigc::connection plgone_connection; + + unsigned char _flags; +}; + +}; /* namespace ARDOUR */ + +#endif /* __ardour_diskstream_h__ */ diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index 0356da8dc8..35b20f655e 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -38,6 +38,7 @@ #include #include #include +#include using std::string; using std::vector; @@ -52,6 +53,11 @@ class Port; class Connection; class Panner; +/** A collection of input and output ports with connections. + * + * An IO can contain ports of varying types, making routes/inserts/etc with + * varied combinations of types (eg MIDI and audio) possible. + */ class IO : public Stateful, public ARDOUR::StateManager { @@ -60,7 +66,8 @@ class IO : public Stateful, public ARDOUR::StateManager IO (Session&, string name, int input_min = -1, int input_max = -1, - int output_min = -1, int output_max = -1); + int output_min = -1, int output_max = -1, + DataType default_type = AUDIO); virtual ~IO(); @@ -74,25 +81,29 @@ class IO : public Stateful, public ARDOUR::StateManager void set_output_minimum (int n); void set_output_maximum (int n); + DataType default_type() const { return _default_type; } + const string& name() const { return _name; } virtual int set_name (string str, void *src); virtual void silence (jack_nframes_t, jack_nframes_t offset); + // These should be moved in to a separate object that manipulates an IO + void pan (vector& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset, gain_t gain_coeff); void pan_automated (vector& bufs, uint32_t nbufs, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset); void collect_input (vector&, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset); - void deliver_output (vector&, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset); - void deliver_output_no_pan (vector&, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset); + void deliver_output (vector&, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset); + void deliver_output_no_pan (vector&, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t offset); void just_meter_input (jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset); virtual uint32_t n_process_buffers () { return 0; } virtual void set_gain (gain_t g, void *src); - void inc_gain (gain_t delta, void *src); - gain_t gain () const { return _desired_gain; } + void inc_gain (gain_t delta, void *src); + gain_t gain () const { return _desired_gain; } virtual gain_t effective_gain () const; Panner& panner() { return *_panner; } @@ -105,8 +116,8 @@ class IO : public Stateful, public ARDOUR::StateManager Connection *input_connection() const { return _input_connection; } Connection *output_connection() const { return _output_connection; } - int add_input_port (string source, void *src); - int add_output_port (string destination, void *src); + int add_input_port (string source, void *src, DataType type = NIL); + int add_output_port (string destination, void *src, DataType type = NIL); int remove_input_port (Port *, void *src); int remove_output_port (Port *, void *src); @@ -273,6 +284,7 @@ public: PBD::ID _id; bool no_panner_reset; XMLNode* deferred_state; + DataType _default_type; virtual void set_deferred_state() {} diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index 9fb1950bfa..9fb5b0eb2b 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -54,7 +54,6 @@ class Playlist : public Stateful, public StateManager { Playlist (const Playlist&, string name, bool hidden = false); Playlist (const Playlist&, jack_nframes_t start, jack_nframes_t cnt, string name, bool hidden = false); - virtual jack_nframes_t read (Sample *dst, Sample *mixdown, float *gain_buffer, char * workbuf, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0) = 0; virtual void clear (bool with_delete = false, bool with_save = true); virtual void dump () const; virtual UndoAction get_memento() const = 0; @@ -81,6 +80,8 @@ class Playlist : public Stateful, public StateManager { void add_region (const Region&, jack_nframes_t position, float times = 1, bool with_save = true); void remove_region (Region *); + void get_equivalent_regions (const Region&, std::vector&); + void get_region_list_equivalent_regions (const Region&, std::vector&); void replace_region (Region& old, Region& newr, jack_nframes_t pos); void split_region (Region&, jack_nframes_t position); void partition (jack_nframes_t start, jack_nframes_t end, bool just_top_level); @@ -108,16 +109,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/port.h b/libs/ardour/ardour/port.h index 93ed2777e4..86c99cb7e3 100644 --- a/libs/ardour/ardour/port.h +++ b/libs/ardour/ardour/port.h @@ -33,24 +33,24 @@ class AudioEngine; class Port : public sigc::trackable { public: virtual ~Port() { - free (port); + free (_port); } Sample *get_buffer (jack_nframes_t nframes) { if (_flags & JackPortIsOutput) { return _buffer; } else { - return (Sample *) jack_port_get_buffer (port, nframes); + return (Sample *) jack_port_get_buffer (_port, nframes); } } void reset_buffer () { if (_flags & JackPortIsOutput) { - _buffer = (Sample *) jack_port_get_buffer (port, 0); + _buffer = (Sample *) jack_port_get_buffer (_port, 0); } else { _buffer = 0; /* catch illegal attempts to use it */ } - silent = false; + _silent = false; } std::string name() { @@ -58,7 +58,7 @@ class Port : public sigc::trackable { } std::string short_name() { - return jack_port_short_name (port); + return jack_port_short_name (_port); } int set_name (std::string str); @@ -68,7 +68,7 @@ class Port : public sigc::trackable { } bool is_mine (jack_client_t *client) { - return jack_port_is_mine (client, port); + return jack_port_is_mine (client, _port); } const char* type() const { @@ -76,21 +76,21 @@ class Port : public sigc::trackable { } int connected () const { - return jack_port_connected (port); + return jack_port_connected (_port); } bool connected_to (const std::string& portname) const { - return jack_port_connected_to (port, portname.c_str()); + return jack_port_connected_to (_port, portname.c_str()); } const char ** get_connections () const { - return jack_port_get_connections (port); + return jack_port_get_connections (_port); } void reset_overs () { _short_overs = 0; _long_overs = 0; - overlen = 0; + _overlen = 0; } void reset_peak_meter () { @@ -103,18 +103,18 @@ class Port : public sigc::trackable { } void enable_metering() { - metering++; + _metering++; } void disable_metering () { - if (metering) { metering--; } + if (_metering) { _metering--; } } - float peak_db() const { return _peak_db; } + float peak_db() const { return _peak_db; } jack_default_audio_sample_t peak() const { return _peak; } uint32_t short_overs () const { return _short_overs; } - uint32_t long_overs () const { return _long_overs; } + uint32_t long_overs () const { return _long_overs; } static void set_short_over_length (jack_nframes_t); static void set_long_over_length (jack_nframes_t); @@ -128,7 +128,7 @@ class Port : public sigc::trackable { } bool monitoring_input () const { - return jack_port_monitoring_input (port); + return jack_port_monitoring_input (_port); } bool can_monitor () const { @@ -136,30 +136,29 @@ class Port : public sigc::trackable { } void ensure_monitor_input (bool yn) { - jack_port_request_monitor (port, yn); + jack_port_request_monitor (_port, yn); } void request_monitor_input (bool yn) { - jack_port_request_monitor (port, yn); + jack_port_request_monitor (_port, yn); } jack_nframes_t latency () const { - return jack_port_get_latency (port); + return jack_port_get_latency (_port); } void set_latency (jack_nframes_t nframes) { - jack_port_set_latency (port, nframes); + jack_port_set_latency (_port, nframes); } sigc::signal MonitorInputChanged; sigc::signal ClockSyncChanged; - bool is_silent() const { return silent; } + bool is_silent() const { return _silent; } + /** Assumes that the port is an audio output port */ void silence (jack_nframes_t nframes, jack_nframes_t offset) { - /* assumes that the port is an output port */ - - if (!silent) { + if (!_silent) { memset (_buffer + offset, 0, sizeof (Sample) * nframes); if (offset == 0) { /* XXX this isn't really true, but i am not sure @@ -167,13 +166,13 @@ class Port : public sigc::trackable { want to set it true when the entire port buffer has been overrwritten. */ - silent = true; + _silent = true; } } } void mark_silence (bool yn) { - silent = yn; + _silent = yn; } private: @@ -184,7 +183,7 @@ class Port : public sigc::trackable { /* engine isn't supposed to below here */ - Sample *_buffer; + Sample *_buffer; /* cache these 3 from JACK so that we can access them for reconnecting. @@ -194,18 +193,18 @@ class Port : public sigc::trackable { std::string _type; std::string _name; - bool last_monitor : 1; - bool silent : 1; - jack_port_t *port; - jack_nframes_t overlen; - jack_default_audio_sample_t _peak; - float _peak_db; - uint32_t _short_overs; - uint32_t _long_overs; - unsigned short metering; + bool _last_monitor : 1; + bool _silent : 1; + jack_port_t *_port; + jack_nframes_t _overlen; + jack_default_audio_sample_t _peak; + float _peak_db; + uint32_t _short_overs; + uint32_t _long_overs; + unsigned short _metering; - static jack_nframes_t long_over_length; - static jack_nframes_t short_over_length; + static jack_nframes_t _long_over_length; + static jack_nframes_t _short_over_length; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index baf93a8f77..3773a3b893 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -24,7 +24,6 @@ #include #include -#include #include class XMLNode; @@ -36,22 +35,22 @@ class Source; enum RegionEditState { EditChangesNothing = 0, - EditChangesName = 1, - EditChangesID = 2 + EditChangesName = 1, + EditChangesID = 2 }; -struct RegionState : public StateManager::State { - - RegionState (std::string why) : StateManager::State (why) {} - - jack_nframes_t _start; - jack_nframes_t _length; - jack_nframes_t _position; - uint32_t _flags; - jack_nframes_t _sync_position; - layer_t _layer; - string _name; - mutable RegionEditState _first_edit; +struct RegionState : public StateManager::State +{ + RegionState (std::string why) : StateManager::State (why) {} + + jack_nframes_t _start; + jack_nframes_t _length; + jack_nframes_t _position; + uint32_t _flags; + jack_nframes_t _sync_position; + layer_t _layer; + string _name; + mutable RegionEditState _first_edit; }; class Region : public Stateful, public StateManager @@ -95,7 +94,7 @@ class Region : public Stateful, public StateManager Region (const Region&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Flag flags = DefaultFlags); Region (const Region&); Region (const XMLNode&); - ~Region(); + virtual ~Region(); const PBD::ID& id() const { return _id; } @@ -105,9 +104,10 @@ class Region : public Stateful, public StateManager void set_name (string str); jack_nframes_t position () const { return _position; } - jack_nframes_t start () const { return _start; } - jack_nframes_t length() const { return _length; } - layer_t layer () const { return _layer; } + jack_nframes_t start () const { return _start; } + jack_nframes_t length() const { return _length; } + layer_t layer () const { return _layer; } + jack_nframes_t sync_offset(int& dir) const; jack_nframes_t sync_position() const; @@ -118,14 +118,13 @@ class Region : public Stateful, public StateManager jack_nframes_t first_frame() const { return _position; } jack_nframes_t last_frame() const { return _position + _length - 1; } - bool hidden() const { return _flags & Hidden; } - bool muted() const { return _flags & Muted; } - bool opaque () const { return _flags & Opaque; } - bool envelope_active () const { return _flags & EnvelopeActive; } - bool locked() const { return _flags & Locked; } - bool automatic() const { return _flags & Automatic; } + bool hidden() const { return _flags & Hidden; } + bool muted() const { return _flags & Muted; } + bool opaque () const { return _flags & Opaque; } + bool locked() const { return _flags & Locked; } + bool automatic() const { return _flags & Automatic; } bool whole_file() const { return _flags & WholeFile ; } - Flag flags() const { return _flags; } + Flag flags() const { return _flags; } virtual bool should_save_state () const { return !(_flags & DoNotSaveState); }; @@ -139,12 +138,14 @@ class Region : public Stateful, public StateManager OverlapType coverage (jack_nframes_t start, jack_nframes_t end) const { return ARDOUR::coverage (_position, _position + _length - 1, start, end); } - - virtual jack_nframes_t read_at (Sample *buf, Sample *mixdown_buffer, - float *gain_buffer, char * workbuf, jack_nframes_t position, jack_nframes_t cnt, - uint32_t chan_n = 0, - jack_nframes_t read_frames = 0, - jack_nframes_t skip_frames = 0) const = 0; + + bool equivalent (const Region&) const; + bool size_equivalent (const Region&) const; + 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; /* EDITING OPERATIONS */ @@ -173,7 +174,6 @@ class Region : public Stateful, public StateManager void set_hidden (bool yn); void set_muted (bool yn); void set_opaque (bool yn); - void set_envelope_active (bool yn); void set_locked (bool yn); virtual uint32_t read_data_count() const { return _read_data_count; } @@ -189,9 +189,9 @@ class Region : public Stateful, public StateManager /* serialization */ + XMLNode& get_state (); virtual XMLNode& state (bool); - XMLNode& get_state (); - int set_state (const XMLNode&); + virtual int set_state (const XMLNode&); sigc::signal GoingAway; @@ -211,23 +211,6 @@ class Region : public Stateful, public StateManager void set_last_layer_op (uint64_t when); protected: - - jack_nframes_t _start; - jack_nframes_t _length; - jack_nframes_t _position; - Flag _flags; - jack_nframes_t _sync_position; - layer_t _layer; - string _name; - mutable RegionEditState _first_edit; - int _frozen; - Glib::Mutex lock; - PBD::ID _id; - ARDOUR::Playlist* _playlist; - mutable uint32_t _read_data_count; // modified in read() - Change pending_changed; - uint64_t _last_layer_op; // timestamp - XMLNode& get_short_state (); /* used only by Session */ /* state management */ @@ -251,6 +234,23 @@ class Region : public Stateful, public StateManager virtual bool verify_length (jack_nframes_t) = 0; virtual void recompute_at_start () = 0; virtual void recompute_at_end () = 0; + + + jack_nframes_t _start; + jack_nframes_t _length; + jack_nframes_t _position; + Flag _flags; + jack_nframes_t _sync_position; + layer_t _layer; + string _name; + mutable RegionEditState _first_edit; + int _frozen; + Glib::Mutex lock; + PBD::ID _id; + ARDOUR::Playlist* _playlist; + mutable uint32_t _read_data_count; // modified in read() + Change pending_changed; + uint64_t _last_layer_op; // timestamp }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index b8a11301ca..ea4a2374d4 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -40,6 +40,7 @@ #include #include #include +#include namespace ARDOUR { @@ -68,7 +69,9 @@ class Route : public IO }; - Route (Session&, std::string name, int input_min, int input_max, int output_min, int output_max, Flag flags = Flag(0)); + Route (Session&, std::string name, int input_min, int input_max, int output_min, int output_max, + Flag flags = Flag(0), DataType default_type = AUDIO); + Route (Session&, const XMLNode&); virtual ~Route(); diff --git a/libs/ardour/ardour/route_group.h b/libs/ardour/ardour/route_group.h index 11253eda5b..e9fad1aa2b 100644 --- a/libs/ardour/ardour/route_group.h +++ b/libs/ardour/ardour/route_group.h @@ -35,6 +35,7 @@ using std::list; namespace ARDOUR { class Route; +class Track; class AudioTrack; class Session; @@ -90,7 +91,7 @@ class RouteGroup : public Stateful, public sigc::trackable { /* to use these, #include */ - template void apply (void (AudioTrack::*func)(T, void *), T val, void *src); + template void apply (void (Track::*func)(T, void *), T val, void *src); /* fills at_set with all members of the group that are AudioTracks */ diff --git a/libs/ardour/ardour/route_group_specialized.h b/libs/ardour/ardour/route_group_specialized.h index 0424002dcd..250d3744df 100644 --- a/libs/ardour/ardour/route_group_specialized.h +++ b/libs/ardour/ardour/route_group_specialized.h @@ -7,11 +7,11 @@ namespace ARDOUR { template void -RouteGroup::apply (void (AudioTrack::*func)(T, void *), T val, void *src) +RouteGroup::apply (void (Track::*func)(T, void *), T val, void *src) { for (list::iterator i = routes.begin(); i != routes.end(); i++) { - AudioTrack *at; - if ((at = dynamic_cast(*i)) != 0) { + Track *at; + if ((at = dynamic_cast(*i)) != 0) { (at->*func)(val, this); } } diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index dbcd830a04..8d10d9f598 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -66,6 +66,7 @@ namespace ARDOUR { class Port; class AudioEngine; class Slave; +class Diskstream; class AudioDiskstream; class Route; class AuxInput; @@ -157,17 +158,17 @@ class Session : public sigc::trackable, public Stateful Clear }; - Type type; - Action action; - jack_nframes_t action_frame; - jack_nframes_t target_frame; - float speed; + Type type; + Action action; + jack_nframes_t action_frame; + jack_nframes_t target_frame; + float speed; union { - void* ptr; - bool yes_or_no; - Session::SlaveSource slave; - Route* route; + void* ptr; + bool yes_or_no; + Session::SlaveSource slave; + Route* route; }; list audio_range; @@ -269,30 +270,18 @@ class Session : public sigc::trackable, public Stateful vector& get_silent_buffers (uint32_t howmany); vector& get_send_buffers () { return _send_buffers; } - AudioDiskstream *diskstream_by_id (const PBD::ID& id); - AudioDiskstream *diskstream_by_name (string name); + Diskstream* diskstream_by_id (const PBD::ID& id); + Diskstream* diskstream_by_name (string name); bool have_captured() const { return _have_captured; } void refill_all_diskstream_buffers (); uint32_t diskstream_buffer_size() const { return dstream_buffer_size; } - /* XXX fix required here when we get new diskstream types *, but - not sure of the direction to take this in until then. - */ - - uint32_t get_next_diskstream_id() const { return n_audio_diskstreams(); } - uint32_t n_audio_diskstreams() const; + uint32_t get_next_diskstream_id() const { return n_diskstreams(); } + uint32_t n_diskstreams() const; - typedef list AudioDiskstreamList; - - Session::AudioDiskstreamList audio_disk_streams() const { - Glib::RWLock::ReaderLock lm (diskstream_lock); - return audio_diskstreams; /* XXX yes, force a copy */ - } - - void foreach_audio_diskstream (void (AudioDiskstream::*func)(void)); - template void foreach_audio_diskstream (T *obj, void (T::*func)(AudioDiskstream&)); + typedef list DiskstreamList; typedef std::list > RouteList; @@ -356,7 +345,7 @@ class Session : public sigc::trackable, public Stateful sigc::signal HaltOnXrun; sigc::signal > RouteAdded; - sigc::signal AudioDiskstreamAdded; + sigc::signal DiskstreamAdded; // FIXME: make a shared_ptr void request_roll (); void request_bounded_roll (jack_nframes_t start, jack_nframes_t end); @@ -368,15 +357,14 @@ class Session : public sigc::trackable, public Stateful void goto_start () { request_locate (start_location->start(), false); } void use_rf_shuttle_speed (); void request_transport_speed (float speed); - void request_overwrite_buffer (AudioDiskstream*); - void request_diskstream_speed (AudioDiskstream&, float speed); + void request_overwrite_buffer (Diskstream*); + void request_diskstream_speed (Diskstream&, float speed); void request_input_change_handling (); bool locate_pending() const { return static_cast(post_transport_work&PostTransportLocate); } bool transport_locked () const; int wipe (); - int wipe_diskstream (AudioDiskstream *); int remove_region_from_region_list (Region&); @@ -553,9 +541,6 @@ class Session : public sigc::trackable, public Stateful void resort_routes (); void resort_routes_using (boost::shared_ptr); - void resort_routes_proxy (void* src) { - resort_routes (); - } AudioEngine &engine() { return _engine; }; @@ -636,7 +621,7 @@ class Session : public sigc::trackable, public Stateful string path_from_region_name (string name, string identifier); AudioRegion* find_whole_file_parent (AudioRegion&); - void find_equivalent_playlist_regions (AudioRegion&, std::vector& result); + void find_equivalent_playlist_regions (Region&, std::vector& result); AudioRegion *XMLRegionFactory (const XMLNode&, bool full); @@ -713,8 +698,6 @@ class Session : public sigc::trackable, public Stateful sigc::signal PlaylistAdded; sigc::signal PlaylistRemoved; - Playlist *get_playlist (string name); - uint32_t n_playlists() const; template void foreach_playlist (T *obj, void (T::*func)(Playlist *)); @@ -739,7 +722,7 @@ class Session : public sigc::trackable, public Stateful boost::shared_ptr the_auditioner() { return auditioner; } void audition_playlist (); - void audition_region (AudioRegion&); + void audition_region (Region&); void cancel_audition (); bool is_auditioning () const; @@ -980,7 +963,7 @@ class Session : public sigc::trackable, public Stateful void set_frame_rate (jack_nframes_t nframes); protected: - friend class AudioDiskstream; + friend class Diskstream; void stop_butler (); void wait_till_butler_finished(); @@ -1442,12 +1425,12 @@ class Session : public sigc::trackable, public Stateful bool waiting_to_start; void set_auto_loop (bool yn); - void overwrite_some_buffers (AudioDiskstream*); + void overwrite_some_buffers (Diskstream*); void flush_all_redirects (); void locate (jack_nframes_t, bool with_roll, bool with_flush, bool with_loop=false); void start_locate (jack_nframes_t, bool with_roll, bool with_flush, bool with_loop=false); void force_locate (jack_nframes_t frame, bool with_roll = false); - void set_diskstream_speed (AudioDiskstream*, float speed); + void set_diskstream_speed (Diskstream*, float speed); void set_transport_speed (float speed, bool abort = false); void stop_transport (bool abort = false); void start_transport (); @@ -1478,10 +1461,10 @@ class Session : public sigc::trackable, public Stateful /* disk-streams */ - AudioDiskstreamList audio_diskstreams; + DiskstreamList diskstreams; mutable Glib::RWLock diskstream_lock; uint32_t dstream_buffer_size; - void add_diskstream (AudioDiskstream*); + void add_diskstream (Diskstream*); int load_diskstreams (const XMLNode&); /* routes stuff */ @@ -1549,7 +1532,7 @@ class Session : public sigc::trackable, public Stateful Playlist *XMLPlaylistFactory (const XMLNode&); void playlist_length_changed (Playlist *); - void diskstream_playlist_changed (AudioDiskstream *); + void diskstream_playlist_changed (Diskstream *); /* NAMED SELECTIONS */ diff --git a/libs/ardour/ardour/session_diskstream.h b/libs/ardour/ardour/session_diskstream.h deleted file mode 100644 index 33fc5419ba..0000000000 --- a/libs/ardour/ardour/session_diskstream.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - Copyright (C) 2002 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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$ -*/ - -#ifndef __ardour_session_diskstream_h__ -#define __ardour_session_diskstream_h__ - -#include -#include - -namespace ARDOUR { - -template void -Session::foreach_audio_diskstream (T *obj, void (T::*func)(AudioDiskstream&)) -{ - Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); i++) { - if (!(*i)->hidden()) { - (obj->*func) (**i); - } - } -} - -} /* namespace */ - -#endif /* __ardour_session_diskstream_h__ */ diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h new file mode 100644 index 0000000000..707ead1573 --- /dev/null +++ b/libs/ardour/ardour/track.h @@ -0,0 +1,158 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. +*/ + +#ifndef __ardour_track_h__ +#define __ardour_track_h__ + +#include + +namespace ARDOUR { + +class Session; +class Diskstream; +class Playlist; +class RouteGroup; + +class Track : public Route +{ + public: + Track (Session&, string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal, DataType default_type = AUDIO); + + virtual ~Track (); + + int set_name (string str, void *src); + + virtual int roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, + jack_nframes_t offset, int declick, bool can_record, bool rec_monitors_input) = 0; + + virtual int no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, + jack_nframes_t offset, bool state_changing, bool can_record, bool rec_monitors_input) = 0; + + virtual int silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, + jack_nframes_t offset, bool can_record, bool rec_monitors_input) = 0; + + void toggle_monitor_input (); + + bool can_record() const { return true; } + + Diskstream& diskstream() const { return *_diskstream; } + + virtual int use_diskstream (string name) = 0; + virtual int use_diskstream (const PBD::ID& id) = 0; + + TrackMode mode() const { return _mode; } + void set_mode (TrackMode m); + + jack_nframes_t update_total_latency(); + void set_latency_delay (jack_nframes_t); + + enum FreezeState { + NoFreeze, + Frozen, + UnFrozen + }; + + FreezeState freeze_state() const; + + virtual void freeze (InterThreadInfo&) = 0; + virtual void unfreeze () = 0; + + virtual void bounce (InterThreadInfo&) = 0; + virtual void bounce_range (jack_nframes_t start, jack_nframes_t end, InterThreadInfo&) = 0; + + XMLNode& get_state(); + XMLNode& get_template(); + virtual int set_state(const XMLNode& node) = 0; + + PBD::Controllable& rec_enable_control() { return _rec_enable_control; } + + bool record_enabled() const; + void set_record_enable (bool yn, void *src); + + void set_meter_point (MeterPoint, void* src); + + sigc::signal ModeChanged; + sigc::signal DiskstreamChanged; + sigc::signal FreezeChange; + + protected: + Track (Session& sess, const XMLNode& node, DataType default_type = AUDIO); + + virtual XMLNode& state (bool full) = 0; + + virtual void passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame, + jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter) = 0; + + virtual uint32_t n_process_buffers () = 0; + + Diskstream *_diskstream; + MeterPoint _saved_meter_point; + TrackMode _mode; + + //private: (FIXME) + struct FreezeRecordInsertInfo { + FreezeRecordInsertInfo(XMLNode& st, boost::shared_ptr ins) + : state (st), insert (ins) {} + + XMLNode state; + boost::shared_ptr insert; + PBD::ID id; + UndoAction memento; + }; + + struct FreezeRecord { + FreezeRecord() + : playlist(0) + , have_mementos(false) + {} + + ~FreezeRecord(); + + Playlist* playlist; + vector insert_info; + bool have_mementos; + FreezeState state; + }; + + struct RecEnableControllable : public PBD::Controllable { + RecEnableControllable (Track&); + + void set_value (float); + float get_value (void) const; + + Track& track; + }; + + //virtual void diskstream_record_enable_changed (void *src) = 0; + //virtual void diskstream_input_channel_changed (void *src) = 0; + + //virtual void input_change_handler (void *src) = 0; + + virtual void set_state_part_two () = 0; + + FreezeRecord _freeze_record; + XMLNode* pending_state; + sigc::connection recenable_connection; + sigc::connection ic_connection; + RecEnableControllable _rec_enable_control; + bool _destructive; +}; + +}; /* namespace ARDOUR*/ + +#endif /* __ardour_track_h__ */ diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index fa1d121d02..e073b413bb 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -243,6 +243,12 @@ namespace ARDOUR { PeakDatum min; PeakDatum max; }; + + enum DataType { + NIL = 0, + AUDIO, + MIDI + }; } std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf); diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index e7cb48452b..7f0cb55821 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 @@ -55,32 +54,30 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -jack_nframes_t AudioDiskstream::disk_io_chunk_frames; - -sigc::signal AudioDiskstream::AudioDiskstreamCreated; -sigc::signal*> AudioDiskstream::DeleteSources; -sigc::signal AudioDiskstream::DiskOverrun; -sigc::signal AudioDiskstream::DiskUnderrun; +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, Flag flag) - : _name (name), - _session (sess) +AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream::Flag flag) + : Diskstream(sess, name, flag) + , deprecated_io_node(NULL) { /* prevent any write sources from being created */ in_set_state = true; - init (flag); + init(flag); use_new_playlist (); in_set_state = false; - AudioDiskstreamCreated (this); /* EMIT SIGNAL */ + DiskstreamCreated (this); /* EMIT SIGNAL */ } AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node) - : _session (sess) - + : Diskstream(sess, node) + , deprecated_io_node(NULL) { in_set_state = true; init (Recordable); @@ -96,7 +93,7 @@ AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node) use_destructive_playlist (); } - AudioDiskstreamCreated (this); /* EMIT SIGNAL */ + DiskstreamCreated (this); /* EMIT SIGNAL */ } void @@ -129,43 +126,9 @@ AudioDiskstream::init_channel (ChannelInfo &chan) void -AudioDiskstream::init (Flag f) +AudioDiskstream::init (Diskstream::Flag f) { - _refcnt = 0; - _flags = f; - _io = 0; - _alignment_style = ExistingMaterial; - _persistent_alignment_style = ExistingMaterial; - first_input_change = true; - _playlist = 0; - i_am_the_modifier = 0; - g_atomic_int_set (&_record_enabled, 0); - was_recording = false; - capture_start_frame = 0; - capture_captured = 0; - _visible_speed = 1.0f; - _actual_speed = 1.0f; - _buffer_reallocation_required = false; - _seek_required = false; - first_recordable_frame = max_frames; - last_recordable_frame = max_frames; - _roll_delay = 0; - _capture_offset = 0; - _processed = false; - _slaved = false; - adjust_capture_position = 0; - last_possibly_recording = 0; - loop_location = 0; - wrap_buffer_size = 0; - speed_buffer_size = 0; - last_phase = 0; - phi = (uint64_t) (0x1000000); - file_frame = 0; - playback_sample = 0; - playback_distance = 0; - _read_data_count = 0; - _write_data_count = 0; - deprecated_io_node = 0; + Diskstream::init(f); /* there are no channels at this point, so these two calls just get speed_buffer_size and wrap_buffer @@ -175,13 +138,8 @@ AudioDiskstream::init (Flag f) 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 = 1; + assert(_n_channels == 1); } void @@ -215,26 +173,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 @@ -332,9 +297,9 @@ AudioDiskstream::find_and_use_playlist (const string& name) Playlist* pl; AudioPlaylist* playlist; - if ((pl = _session.get_playlist (name)) == 0) { - error << string_compose(_("AudioDiskstream: Session doesn't know about a Playlist called \"%1\""), name) << endmsg; - return -1; + if ((pl = _session.playlist_by_name (name)) == 0) { + playlist = new AudioPlaylist(_session, name); + pl = playlist; } if ((playlist = dynamic_cast (pl)) == 0) { @@ -346,57 +311,15 @@ AudioDiskstream::find_and_use_playlist (const string& name) } int -AudioDiskstream::use_playlist (AudioPlaylist* playlist) +AudioDiskstream::use_playlist (Playlist* playlist) { - { - Glib::Mutex::Lock lm (state_lock); + assert(dynamic_cast(playlist)); - 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, &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; } -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; -} - int AudioDiskstream::use_new_playlist () { @@ -424,6 +347,8 @@ AudioDiskstream::use_new_playlist () int AudioDiskstream::use_copy_playlist () { + assert(audio_playlist()); + if (destructive()) { return 0; } @@ -438,7 +363,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 { @@ -488,110 +413,13 @@ AudioDiskstream::use_destructive_playlist () for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) { (*chan).write_source = dynamic_cast(®ion->source (n)); + assert((*chan).write_source); (*chan).write_source->set_allow_remove_if_empty (false); } /* the source list will never be reset for a destructive track */ } -void -AudioDiskstream::set_io (IO& io) -{ - _io = &io; - set_align_style_from_io (); -} - -int -AudioDiskstream::set_name (string str, void *src) -{ - if (str != _name) { - _playlist->set_name (str); - _name = str; - - if (!in_set_state && recordable()) { - /* rename existing capture files so that they have the correct name */ - return rename_write_sources (); - } else { - return -1; - } - } - - return 0; -} - -void -AudioDiskstream::set_speed (double sp) -{ - _session.request_diskstream_speed (*this, sp); - - /* to force a rebuffering at the right place */ - playlist_modified(); -} - -bool -AudioDiskstream::realtime_set_speed (double sp, bool global) -{ - bool changed = false; - double new_speed = sp * _session.transport_speed(); - - if (_visible_speed != sp) { - _visible_speed = sp; - changed = true; - } - - if (new_speed != _actual_speed) { - - jack_nframes_t required_wrap_size = (jack_nframes_t) floor (_session.get_block_size() * - fabs (new_speed)) + 1; - - if (required_wrap_size > wrap_buffer_size) { - _buffer_reallocation_required = true; - } - - _actual_speed = new_speed; - phi = (uint64_t) (0x1000000 * fabs(_actual_speed)); - } - - if (changed) { - if (!global) { - _seek_required = true; - } - speed_changed (); /* EMIT SIGNAL */ - } - - return _buffer_reallocation_required || _seek_required; -} - -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::prepare () -{ - _processed = false; - playback_distance = 0; -} - void AudioDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record) { @@ -755,7 +583,7 @@ AudioDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes returns a non-zero value, in which case, ::commit should not be called. */ - // If we can't take the state lock return. + // If we can't take the state lock return. if (!state_lock.trylock()) { return 1; } @@ -1011,13 +839,6 @@ AudioDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes return ret; } -void -AudioDiskstream::recover () -{ - state_lock.unlock(); - _processed = false; -} - bool AudioDiskstream::commit (jack_nframes_t nframes) { @@ -1156,16 +977,16 @@ AudioDiskstream::seek (jack_nframes_t frame, bool complete_refill) /* can't rec-enable in destructive mode if transport is before start */ if (destructive() && record_enabled() && frame < _session.current_start_frame()) { - disengage_record_enable (this); + disengage_record_enable (); } playback_sample = frame; file_frame = frame; if (complete_refill) { - while ((ret = do_refill (0, 0, 0)) > 0); + while ((ret = do_refill_with_alloc ()) > 0) ; } else { - ret = do_refill (0, 0, 0); + ret = do_refill_with_alloc (); } return ret; @@ -1257,7 +1078,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; @@ -1291,14 +1112,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; @@ -1306,6 +1140,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) { @@ -1412,33 +1250,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; @@ -1507,37 +1318,30 @@ 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; } +/** Flush pending data to disk. + * + * Important note: this function will write *AT MOST* disk_io_chunk_frames + * of data to disk. it will never write more than that. If it writes that + * much and there is more than that waiting to be written, it will return 1, + * otherwise 0 on success or -1 on failure. + * + * If there is less than disk_io_chunk_frames to be written, no data will be + * written at all unless @a force_flush is true. + */ 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; RingBufferNPT::rw_vector transvec; jack_nframes_t total; - - /* important note: this function will write *AT MOST* - disk_io_chunk_frames of data to disk. it will never - write more than that. if its writes that much and there - is more than that waiting to be written, it will return 1, - otherwise 0 on success or -1 on failure. - - if there is less than disk_io_chunk_frames to be written, - no data will be written at all unless `force_flush' is true. - */ _write_data_count = 0; @@ -1552,7 +1356,6 @@ AudioDiskstream::do_flush (char * workbuf, bool force_flush) goto out; } - /* if there are 2+ chunks of disk i/o possible for this track, let the caller know so that it can arrange for us to be called again, ASAP. @@ -1656,21 +1459,6 @@ AudioDiskstream::do_flush (char * workbuf, bool force_flush) return ret; } -void -AudioDiskstream::playlist_changed (Change ignored) -{ - playlist_modified (); -} - -void -AudioDiskstream::playlist_modified () -{ - if (!i_am_the_modifier && !overwrite_queued) { - _session.request_overwrite_buffer (this); - overwrite_queued = true; - } -} - void AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture) { @@ -1684,7 +1472,6 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca ChannelList::iterator chan; vector::iterator ci; uint32_t n = 0; - list* deletion_list; bool mark_write_completed = false; finish_capture (true); @@ -1694,7 +1481,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; @@ -1717,7 +1504,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca ChannelList::iterator chan; - deletion_list = new list; + list* deletion_list = new list; for ( chan = channels.begin(); chan != channels.end(); ++chan) { @@ -1904,7 +1691,7 @@ AudioDiskstream::finish_capture (bool rec_monitors_input) } void -AudioDiskstream::set_record_enabled (bool yn, void* src) +AudioDiskstream::set_record_enabled (bool yn) { if (!recordable() || !_session.record_enabling_legal()) { return; @@ -1931,17 +1718,17 @@ AudioDiskstream::set_record_enabled (bool yn, void* src) if (record_enabled() != yn) { if (yn) { - engage_record_enable (src); + engage_record_enable (); } else { - disengage_record_enable (src); + disengage_record_enable (); } } } void -AudioDiskstream::engage_record_enable (void* src) +AudioDiskstream::engage_record_enable () { - bool rolling = _session.transport_speed() != 0.0f; + bool rolling = _session.transport_speed() != 0.0f; g_atomic_int_set (&_record_enabled, 1); capturing_sources.clear (); @@ -1958,11 +1745,11 @@ AudioDiskstream::engage_record_enable (void* src) } } - record_enable_changed (src); /* EMIT SIGNAL */ + RecordEnableChanged (); /* EMIT SIGNAL */ } void -AudioDiskstream::disengage_record_enable (void* src) +AudioDiskstream::disengage_record_enable () { g_atomic_int_set (&_record_enabled, 0); if (Config->get_use_hardware_monitoring()) { @@ -1973,7 +1760,7 @@ AudioDiskstream::disengage_record_enable (void* src) } } capturing_sources.clear (); - record_enable_changed (src); /* EMIT SIGNAL */ + RecordEnableChanged (); /* EMIT SIGNAL */ } @@ -1981,7 +1768,7 @@ XMLNode& AudioDiskstream::get_state () { XMLNode* node = new XMLNode ("AudioDiskstream"); - char buf[64]; + char buf[64] = ""; LocaleGuard lg (X_("POSIX")); snprintf (buf, sizeof(buf), "0x%x", _flags); @@ -2080,8 +1867,7 @@ AudioDiskstream::set_state (const XMLNode& node) } // create necessary extra channels - // we are always constructed with one - // and we always need one + // we are always constructed with one and we always need one if (nchans > _n_channels) { @@ -2311,23 +2097,6 @@ AudioDiskstream::monitor_input (bool yn) } } -void -AudioDiskstream::set_capture_offset () -{ - if (_io == 0) { - /* can't capture, so forget it */ - return; - } - - _capture_offset = _io->input_latency(); -} - -void -AudioDiskstream::set_persistent_align_style (AlignStyle a) -{ - _persistent_alignment_style = a; -} - void AudioDiskstream::set_align_style_from_io () { @@ -2353,20 +2122,6 @@ AudioDiskstream::set_align_style_from_io () } } -void -AudioDiskstream::set_align_style (AlignStyle a) -{ - if (record_enabled() && _session.actively_recording()) { - return; - } - - - if (a != _alignment_style) { - _alignment_style = a; - AlignmentStyleChanged (); - } -} - int AudioDiskstream::add_channel () { @@ -2417,58 +2172,6 @@ AudioDiskstream::capture_buffer_load () const (double) channels.front().capture_buf->bufsize()); } -int -AudioDiskstream::set_loop (Location *location) -{ - if (location) { - if (location->start() >= location->end()) { - error << string_compose(_("Location \"%1\" not valid for track loop (start >= end)"), location->name()) << endl; - return -1; - } - } - - loop_location = location; - - LoopSet (location); /* EMIT SIGNAL */ - return 0; -} - -jack_nframes_t -AudioDiskstream::get_capture_start_frame (uint32_t n) -{ - Glib::Mutex::Lock lm (capture_info_lock); - - if (capture_info.size() > n) { - return capture_info[n]->start; - } - else { - return capture_start_frame; - } -} - -jack_nframes_t -AudioDiskstream::get_captured_frames (uint32_t n) -{ - Glib::Mutex::Lock lm (capture_info_lock); - - if (capture_info.size() > n) { - return capture_info[n]->frames; - } - else { - return capture_captured; - } -} - -void -AudioDiskstream::punch_in () -{ -} - -void -AudioDiskstream::punch_out () -{ -} - int AudioDiskstream::use_pending_capture_data (XMLNode& node) { @@ -2564,22 +2267,3 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node) return 0; } - -void -AudioDiskstream::set_roll_delay (jack_nframes_t nframes) -{ - _roll_delay = nframes; -} - -void -AudioDiskstream::set_destructive (bool yn) -{ - if (yn != destructive()) { - reset_write_sources (true, true); - if (yn) { - _flags |= Destructive; - } else { - _flags &= ~Destructive; - } - } -} diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index 85c11647f4..93d380679d 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -243,16 +243,18 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, ch for (vector::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) { + // FIXME: Should be vector vector& r (relevant_regions[*l]); vector& x (relevant_xfades[*l]); for (vector::iterator i = r.begin(); i != r.end(); ++i) { - (*i)->read_at (buf, mixdown_buffer, gain_buffer, workbuf, start, cnt, chan_n, read_frames, skip_frames); - _read_data_count += (*i)->read_data_count(); + AudioRegion* const ar = dynamic_cast(*i); + assert(ar); + ar->read_at (buf, mixdown_buffer, gain_buffer, workbuf, start, cnt, chan_n, read_frames, skip_frames); + _read_data_count += ar->read_data_count(); } for (vector::iterator i = x.begin(); i != x.end(); ++i) { - (*i)->read_at (buf, mixdown_buffer, gain_buffer, workbuf, start, cnt, chan_n); /* don't JACK up _read_data_count, since its the same data as we just @@ -880,38 +882,6 @@ AudioPlaylist::crossfade_changed (Change ignored) notify_modified (); } -void -AudioPlaylist::get_equivalent_regions (const AudioRegion& other, vector& results) -{ - for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - - AudioRegion* ar = dynamic_cast (*i); - - if (ar) { - if (Config->get_use_overlap_equivalency()) { - if (ar->overlap_equivalent (other)) { - results.push_back (ar); - } else if (ar->equivalent (other)) { - results.push_back (ar); - } - } - } - } -} - -void -AudioPlaylist::get_region_list_equivalent_regions (const AudioRegion& other, vector& results) -{ - for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - - AudioRegion* ar = dynamic_cast (*i); - - if (ar && ar->region_list_equivalent (other)) { - results.push_back (ar); - } - } -} - bool AudioPlaylist::region_changed (Change what_changed, Region* region) { diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc index f425f0172e..78af23e3df 100644 --- a/libs/ardour/audio_track.cc +++ b/libs/ardour/audio_track.cc @@ -41,9 +41,7 @@ using namespace ARDOUR; using namespace PBD; AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode mode) - : Route (sess, name, 1, -1, -1, -1, flag), - diskstream (0), - _rec_enable_control (*this) + : Track (sess, name, flag, mode) { AudioDiskstream::Flag dflags = AudioDiskstream::Flag (0); @@ -59,45 +57,34 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode AudioDiskstream* ds = new AudioDiskstream (_session, name, dflags); - _declickable = true; - _freeze_record.state = NoFreeze; - _saved_meter_point = _meter_point; - _mode = mode; - set_diskstream (*ds, this); } AudioTrack::AudioTrack (Session& sess, const XMLNode& node) - : Route (sess, "to be renamed", 0, 0, -1, -1), - diskstream (0), - _rec_enable_control (*this) + : Track (sess, node) { - _freeze_record.state = NoFreeze; set_state (node); - _declickable = true; - _saved_meter_point = _meter_point; } AudioTrack::~AudioTrack () { - if (diskstream) { - diskstream->unref(); - } } int AudioTrack::deprecated_use_diskstream_connections () { - if (diskstream->deprecated_io_node == 0) { + AudioDiskstream& diskstream = audio_diskstream(); + + if (diskstream.deprecated_io_node == 0) { return 0; } const XMLProperty* prop; - XMLNode& node (*diskstream->deprecated_io_node); + XMLNode& node (*diskstream.deprecated_io_node); /* don't do this more than once. */ - diskstream->deprecated_io_node = 0; + diskstream.deprecated_io_node = 0; set_input_minimum (-1); set_input_maximum (-1); @@ -140,15 +127,15 @@ AudioTrack::deprecated_use_diskstream_connections () int AudioTrack::set_diskstream (AudioDiskstream& ds, void *src) { - if (diskstream) { - diskstream->unref(); + if (_diskstream) { + _diskstream->unref(); } - diskstream = &ds.ref(); - diskstream->set_io (*this); - diskstream->set_destructive (_mode == Destructive); + _diskstream = &ds.ref(); + _diskstream->set_io (*this); + _diskstream->set_destructive (_mode == Destructive); - if (diskstream->deprecated_io_node) { + if (audio_diskstream().deprecated_io_node) { if (!connecting_legal) { ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections)); @@ -157,13 +144,13 @@ AudioTrack::set_diskstream (AudioDiskstream& ds, void *src) } } - diskstream->set_record_enabled (false, this); - diskstream->monitor_input (false); + _diskstream->set_record_enabled (false); + _diskstream->monitor_input (false); ic_connection.disconnect(); - ic_connection = input_changed.connect (mem_fun (*diskstream, &AudioDiskstream::handle_input_change)); + ic_connection = input_changed.connect (mem_fun (*_diskstream, &Diskstream::handle_input_change)); - diskstream_changed (src); /* EMIT SIGNAL */ + DiskstreamChanged (); /* EMIT SIGNAL */ return 0; } @@ -173,8 +160,8 @@ AudioTrack::use_diskstream (string name) { AudioDiskstream *dstream; - if ((dstream = _session.diskstream_by_name (name)) == 0) { - error << string_compose(_("AudioTrack: diskstream \"%1\" not known by session"), name) << endmsg; + if ((dstream = dynamic_cast(_session.diskstream_by_name (name))) == 0) { + error << string_compose(_("AudioTrack: audio diskstream \"%1\" not known by session"), name) << endmsg; return -1; } @@ -186,53 +173,18 @@ AudioTrack::use_diskstream (const PBD::ID& id) { AudioDiskstream *dstream; - if ((dstream = _session.diskstream_by_id (id)) == 0) { - error << string_compose(_("AudioTrack: diskstream \"%1\" not known by session"), id) << endmsg; + if ((dstream = dynamic_cast(_session.diskstream_by_id (id))) == 0) { + error << string_compose(_("AudioTrack: audio diskstream \"%1\" not known by session"), id) << endmsg; return -1; } return set_diskstream (*dstream, this); } -bool -AudioTrack::record_enabled () const -{ - return diskstream->record_enabled (); -} - -void -AudioTrack::set_record_enable (bool yn, void *src) -{ - if (_freeze_record.state == Frozen) { - return; - } - - if (_mix_group && src != _mix_group && _mix_group->is_active()) { - _mix_group->apply (&AudioTrack::set_record_enable, yn, _mix_group); - return; - } - - /* keep track of the meter point as it was before we rec-enabled */ - - if (!diskstream->record_enabled()) { - _saved_meter_point = _meter_point; - } - - diskstream->set_record_enabled (yn, src); - - if (diskstream->record_enabled()) { - set_meter_point (MeterInput, this); - } else { - set_meter_point (_saved_meter_point, this); - } - - _rec_enable_control.Changed (); -} - -void -AudioTrack::set_meter_point (MeterPoint p, void *src) +AudioDiskstream& +AudioTrack::audio_diskstream() const { - Route::set_meter_point (p, src); + return *dynamic_cast(_diskstream); } int @@ -306,18 +258,6 @@ AudioTrack::set_state (const XMLNode& node) return 0; } -XMLNode& -AudioTrack::get_template () -{ - return state (false); -} - -XMLNode& -AudioTrack::get_state () -{ - return state (true); -} - XMLNode& AudioTrack::state(bool full_state) { @@ -348,7 +288,7 @@ AudioTrack::state(bool full_state) /* Alignment: act as a proxy for the diskstream */ XMLNode* align_node = new XMLNode (X_("alignment")); - switch (diskstream->alignment_style()) { + switch (_diskstream->alignment_style()) { case ExistingMaterial: snprintf (buf, sizeof (buf), X_("existing")); break; @@ -379,7 +319,7 @@ AudioTrack::state(bool full_state) diskstream. */ - diskstream->id().print (buf); + _diskstream->id().print (buf); root.add_property ("diskstream-id", buf); return root; @@ -451,9 +391,9 @@ AudioTrack::set_state_part_two () if ((prop = fnode->property (X_("style"))) != 0) { if (prop->value() == "existing") { - diskstream->set_persistent_align_style (ExistingMaterial); + _diskstream->set_persistent_align_style (ExistingMaterial); } else if (prop->value() == "capture") { - diskstream->set_persistent_align_style (CaptureTime); + _diskstream->set_persistent_align_style (CaptureTime); } } } @@ -463,7 +403,7 @@ AudioTrack::set_state_part_two () uint32_t AudioTrack::n_process_buffers () { - return max ((uint32_t) diskstream->n_channels(), redirect_max_outs); + return max ((uint32_t) _diskstream->n_channels(), redirect_max_outs); } void @@ -494,7 +434,7 @@ AudioTrack::no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nf return 0; } - diskstream->check_record_status (start_frame, nframes, can_record); + audio_diskstream().check_record_status (start_frame, nframes, can_record); bool send_silence; @@ -513,7 +453,7 @@ AudioTrack::no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nf send_silence = true; } } else { - if (diskstream->record_enabled()) { + if (_diskstream->record_enabled()) { if (Config->get_use_sw_monitoring()) { send_silence = false; } else { @@ -561,7 +501,8 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram Sample* b; Sample* tmpb; jack_nframes_t transport_frame; - + AudioDiskstream& diskstream = audio_diskstream(); + { Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK); if (lm.locked()) { @@ -587,13 +528,13 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram playback distance to zero, thus causing diskstream::commit to do nothing. */ - return diskstream->process (transport_frame, 0, 0, can_record, rec_monitors_input); + return diskstream.process (transport_frame, 0, 0, can_record, rec_monitors_input); } _silent = false; apply_gain_automation = false; - if ((dret = diskstream->process (transport_frame, nframes, offset, can_record, rec_monitors_input)) != 0) { + if ((dret = diskstream.process (transport_frame, nframes, offset, can_record, rec_monitors_input)) != 0) { silence (nframes, offset); @@ -606,7 +547,7 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram just_meter_input (start_frame, end_frame, nframes, offset); } - if (diskstream->record_enabled() && !can_record && !_session.get_auto_input()) { + if (diskstream.record_enabled() && !can_record && !_session.get_auto_input()) { /* not actually recording, but we want to hear the input material anyway, at least potentially (depending on monitoring options) @@ -614,7 +555,7 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram passthru (start_frame, end_frame, nframes, offset, 0, true); - } else if ((b = diskstream->playback_buffer(0)) != 0) { + } else if ((b = diskstream.playback_buffer(0)) != 0) { /* XXX is it true that the earlier test on n_outputs() @@ -636,8 +577,8 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram for (i = 0, n = 1; i < limit; ++i, ++n) { memcpy (bufs[i], b, sizeof (Sample) * nframes); - if (n < diskstream->n_channels()) { - tmpb = diskstream->playback_buffer(n); + if (n < diskstream.n_channels()) { + tmpb = diskstream.playback_buffer(n); if (tmpb!=0) { b = tmpb; } @@ -646,7 +587,7 @@ AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfram /* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */ - if (!diskstream->record_enabled() && _session.transport_rolling()) { + if (!diskstream.record_enabled() && _session.transport_rolling()) { Glib::Mutex::Lock am (automation_lock, Glib::TRY_LOCK); if (am.locked() && gain_automation_playback()) { @@ -682,37 +623,7 @@ AudioTrack::silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jac silence (nframes, offset); - return diskstream->process (_session.transport_frame() + offset, nframes, offset, can_record, rec_monitors_input); -} - -void -AudioTrack::toggle_monitor_input () -{ - for (vector::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { - (*i)->request_monitor_input(!(*i)->monitoring_input()); - } -} - -int -AudioTrack::set_name (string str, void *src) -{ - int ret; - - if (record_enabled() && _session.actively_recording()) { - /* this messes things up if done while recording */ - return -1; - } - - if (diskstream->set_name (str, src)) { - return -1; - } - - /* save state so that the statefile fully reflects any filename changes */ - - if ((ret = IO::set_name (str, src)) == 0) { - _session.save_state (""); - } - return ret; + return audio_diskstream().process (_session.transport_frame() + offset, nframes, offset, can_record, rec_monitors_input); } int @@ -726,10 +637,15 @@ AudioTrack::export_stuff (vector& buffers, char * workbuf, uint32_t nbu gain_t this_gain = _gain; vector::iterator bi; Sample * b; + AudioDiskstream& diskstream = audio_diskstream(); Glib::RWLock::ReaderLock rlock (redirect_lock); - - if (diskstream->playlist()->read (buffers[0], mix_buffer, gain_buffer, workbuf, start, nframes) != nframes) { + + // FIXME + AudioPlaylist* const apl = dynamic_cast(diskstream.playlist()); + assert(apl); + + if (apl->read (buffers[0], mix_buffer, gain_buffer, workbuf, start, nframes) != nframes) { return -1; } @@ -738,8 +654,8 @@ AudioTrack::export_stuff (vector& buffers, char * workbuf, uint32_t nbu b = buffers[0]; ++bi; for (; bi != buffers.end(); ++bi, ++n) { - if (n < diskstream->n_channels()) { - if (diskstream->playlist()->read ((*bi), mix_buffer, gain_buffer, workbuf, start, nframes, n) != nframes) { + if (n < diskstream.n_channels()) { + if (apl->read ((*bi), mix_buffer, gain_buffer, workbuf, start, nframes, n) != nframes) { return -1; } b = (*bi); @@ -811,29 +727,6 @@ AudioTrack::export_stuff (vector& buffers, char * workbuf, uint32_t nbu return 0; } -void -AudioTrack::set_latency_delay (jack_nframes_t longest_session_latency) -{ - Route::set_latency_delay (longest_session_latency); - diskstream->set_roll_delay (_roll_delay); -} - -jack_nframes_t -AudioTrack::update_total_latency () -{ - _own_latency = 0; - - for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { - if ((*i)->active ()) { - _own_latency += (*i)->latency (); - } - } - - set_port_latency (_own_latency); - - return _own_latency; -} - void AudioTrack::bounce (InterThreadInfo& itt) { @@ -858,8 +751,9 @@ AudioTrack::freeze (InterThreadInfo& itt) string dir; AudioRegion* region; string region_name; + AudioDiskstream& diskstream = audio_diskstream(); - if ((_freeze_record.playlist = diskstream->playlist()) == 0) { + if ((_freeze_record.playlist = dynamic_cast(diskstream.playlist())) == 0) { return; } @@ -881,7 +775,7 @@ AudioTrack::freeze (InterThreadInfo& itt) } if (n == (UINT_MAX-1)) { - error << string_compose (X_("There Are too many frozen versions of playlist \"%1\"" + error << string_compose (X_("There are too many frozen versions of playlist \"%1\"" " to create another one"), _freeze_record.playlist->name()) << endmsg; return; @@ -927,13 +821,13 @@ AudioTrack::freeze (InterThreadInfo& itt) (AudioRegion::Flag) (AudioRegion::WholeFile|AudioRegion::DefaultFlags), false); - new_playlist->set_orig_diskstream_id (diskstream->id()); + new_playlist->set_orig_diskstream_id (diskstream.id()); new_playlist->add_region (*region, 0); new_playlist->set_frozen (true); region->set_locked (true); - diskstream->use_playlist (dynamic_cast(new_playlist)); - diskstream->set_record_enabled (false, this); + diskstream.use_playlist (dynamic_cast(new_playlist)); + diskstream.set_record_enabled (false); _freeze_record.state = Frozen; FreezeChange(); /* EMIT SIGNAL */ @@ -943,7 +837,7 @@ void AudioTrack::unfreeze () { if (_freeze_record.playlist) { - diskstream->use_playlist (_freeze_record.playlist); + audio_diskstream().use_playlist (_freeze_record.playlist); if (_freeze_record.have_mementos) { @@ -971,46 +865,3 @@ AudioTrack::unfreeze () FreezeChange (); /* EMIT SIGNAL */ } -AudioTrack::FreezeRecord::~FreezeRecord () -{ - for (vector::iterator i = insert_info.begin(); i != insert_info.end(); ++i) { - delete *i; - } -} - -AudioTrack::FreezeState -AudioTrack::freeze_state() const -{ - return _freeze_record.state; -} - -AudioTrack::RecEnableControllable::RecEnableControllable (AudioTrack& s) - : track (s) -{ -} - -void -AudioTrack::RecEnableControllable::set_value (float val) -{ - bool bval = ((val >= 0.5f) ? true: false); - track.set_record_enable (bval, this); -} - -float -AudioTrack::RecEnableControllable::get_value (void) const -{ - if (track.record_enabled()) { return 1.0f; } - return 0.0f; -} - -void -AudioTrack::set_mode (TrackMode m) -{ - if (diskstream) { - if (_mode != m) { - _mode = m; - diskstream->set_destructive (m == Destructive); - ModeChanged(); - } - } -} diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 5a5e200531..5618c7ef5f 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -42,8 +43,8 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -jack_nframes_t Port::short_over_length = 2; -jack_nframes_t Port::long_over_length = 10; +jack_nframes_t Port::_short_over_length = 2; +jack_nframes_t Port::_long_over_length = 10; AudioEngine::AudioEngine (string client_name) { @@ -274,8 +275,8 @@ AudioEngine::process_callback (jack_nframes_t nframes) Port *port = (*i); bool x; - if (port->last_monitor != (x = port->monitoring_input ())) { - port->last_monitor = x; + if (port->_last_monitor != (x = port->monitoring_input ())) { + port->_last_monitor = x; /* XXX I think this is dangerous, due to a likely mutex in the signal handlers ... */ @@ -388,18 +389,19 @@ AudioEngine::remove_session () } Port * -AudioEngine::register_audio_input_port (const string& portname) +AudioEngine::register_input_port (DataType type, const string& portname) { if (!_running) { if (!_has_run) { - fatal << _("register audio input port called before engine was started") << endmsg; + fatal << _("register input port called before engine was started") << endmsg; /*NOTREACHED*/ } else { return 0; } } - jack_port_t *p = jack_port_register (_jack, portname.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + jack_port_t *p = jack_port_register (_jack, portname.c_str(), + Buffer::type_to_jack_type(type), JackPortIsInput, 0); if (p) { @@ -419,11 +421,11 @@ AudioEngine::register_audio_input_port (const string& portname) } Port * -AudioEngine::register_audio_output_port (const string& portname) +AudioEngine::register_output_port (DataType type, const string& portname) { if (!_running) { if (!_has_run) { - fatal << _("register audio output port called before engine was started") << endmsg; + fatal << _("register output port called before engine was started") << endmsg; /*NOTREACHED*/ } else { return 0; @@ -432,7 +434,8 @@ AudioEngine::register_audio_output_port (const string& portname) jack_port_t *p; - if ((p = jack_port_register (_jack, portname.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) != 0) { + if ((p = jack_port_register (_jack, portname.c_str(), + Buffer::type_to_jack_type(type), JackPortIsOutput, 0)) != 0) { Port *newport = new Port (p); ports.insert (ports.begin(), newport); return newport; @@ -446,6 +449,7 @@ AudioEngine::register_audio_output_port (const string& portname) return 0; } + int AudioEngine::unregister_port (Port *port) { @@ -458,7 +462,7 @@ AudioEngine::unregister_port (Port *port) if (port) { - int ret = jack_port_unregister (_jack, port->port); + int ret = jack_port_unregister (_jack, port->_port); if (ret == 0) { @@ -549,7 +553,7 @@ AudioEngine::disconnect (Port *port) } } - int ret = jack_port_disconnect (_jack, port->port); + int ret = jack_port_disconnect (_jack, port->_port); if (ret == 0) { remove_connections_for (port); @@ -699,7 +703,6 @@ AudioEngine::n_physical_inputs () const } string - AudioEngine::get_nth_physical (uint32_t n, int flag) { const char ** ports; @@ -747,7 +750,7 @@ AudioEngine::get_port_total_latency (const Port& port) } } - return jack_port_get_total_latency (_jack, port.port); + return jack_port_get_total_latency (_jack, port._port); } void @@ -825,7 +828,7 @@ AudioEngine::remove_all_ports () if (_jack) { for (Ports::iterator i = ports.begin(); i != ports.end(); ++i) { - jack_port_unregister (_jack, (*i)->port); + jack_port_unregister (_jack, (*i)->_port); } } @@ -948,7 +951,7 @@ AudioEngine::reconnect_to_jack () short_name = long_name.substr (long_name.find_last_of (':') + 1); - if (((*i)->port = jack_port_register (_jack, short_name.c_str(), (*i)->type(), (*i)->flags(), 0)) == 0) { + if (((*i)->_port = jack_port_register (_jack, short_name.c_str(), (*i)->type(), (*i)->flags(), 0)) == 0) { error << string_compose (_("could not reregister %1"), (*i)->name()) << endmsg; break; } else { @@ -963,7 +966,7 @@ AudioEngine::reconnect_to_jack () if (i != ports.end()) { for (Ports::iterator i = ports.begin(); i != ports.end(); ++i) { - jack_port_unregister (_jack, (*i)->port); + jack_port_unregister (_jack, (*i)->_port); } return -1; } diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 4a8593cd63..fff1c99598 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -48,13 +48,13 @@ using namespace ARDOUR; /* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */ -Change AudioRegion::FadeInChanged = ARDOUR::new_change(); -Change AudioRegion::FadeOutChanged = ARDOUR::new_change(); -Change AudioRegion::FadeInActiveChanged = ARDOUR::new_change(); -Change AudioRegion::FadeOutActiveChanged = ARDOUR::new_change(); +Change AudioRegion::FadeInChanged = ARDOUR::new_change(); +Change AudioRegion::FadeOutChanged = ARDOUR::new_change(); +Change AudioRegion::FadeInActiveChanged = ARDOUR::new_change(); +Change AudioRegion::FadeOutActiveChanged = ARDOUR::new_change(); Change AudioRegion::EnvelopeActiveChanged = ARDOUR::new_change(); Change AudioRegion::ScaleAmplitudeChanged = ARDOUR::new_change(); -Change AudioRegion::EnvelopeChanged = ARDOUR::new_change(); +Change AudioRegion::EnvelopeChanged = ARDOUR::new_change(); AudioRegionState::AudioRegionState (string why) : RegionState (why), @@ -633,12 +633,6 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff return to_read; } -XMLNode& -AudioRegion::get_state () -{ - return state (true); -} - XMLNode& AudioRegion::state (bool full) { @@ -1139,24 +1133,22 @@ AudioRegion::master_source_names () } bool -AudioRegion::region_list_equivalent (const AudioRegion& other) const +AudioRegion::source_equivalent (const Region& o) const { - return size_equivalent (other) && source_equivalent (other) && _name == other._name; -} + const AudioRegion* other = dynamic_cast(&o); + if (!other) + return false; -bool -AudioRegion::source_equivalent (const AudioRegion& other) const -{ SourceList::const_iterator i; SourceList::const_iterator io; - for (i = sources.begin(), io = other.sources.begin(); i != sources.end() && io != other.sources.end(); ++i, ++io) { + for (i = sources.begin(), io = other->sources.begin(); i != sources.end() && io != other->sources.end(); ++i, ++io) { if ((*i)->id() != (*io)->id()) { return false; } } - for (i = master_sources.begin(), io = other.master_sources.begin(); i != master_sources.end() && io != other.master_sources.end(); ++i, ++io) { + for (i = master_sources.begin(), io = other->master_sources.begin(); i != master_sources.end() && io != other->master_sources.end(); ++i, ++io) { if ((*i)->id() != (*io)->id()) { return false; } @@ -1165,27 +1157,6 @@ AudioRegion::source_equivalent (const AudioRegion& other) const return true; } -bool -AudioRegion::overlap_equivalent (const AudioRegion& other) const -{ - return coverage (other.first_frame(), other.last_frame()) != OverlapNone; -} - -bool -AudioRegion::equivalent (const AudioRegion& other) const -{ - return _start == other._start && - _position == other._position && - _length == other._length; -} - -bool -AudioRegion::size_equivalent (const AudioRegion& other) const -{ - return _start == other._start && - _length == other._length; -} - int AudioRegion::apply (AudioFilter& filter) { diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc index 2f0b943c0e..81f64d2671 100644 --- a/libs/ardour/auditioner.cc +++ b/libs/ardour/auditioner.cc @@ -44,12 +44,12 @@ Auditioner::Auditioner (Session& s) defer_pan_reset (); if (left.length()) { - add_output_port (left, this); + add_output_port (left, this, AUDIO); } if (right.length()) { - disk_stream().add_channel(); - add_output_port (right, this); + audio_diskstream().add_channel(); + add_output_port (right, this, AUDIO); } allow_pan_reset (); @@ -67,8 +67,12 @@ Auditioner::~Auditioner () AudioPlaylist& Auditioner::prepare_playlist () { - diskstream->playlist()->clear (false, false); - return *diskstream->playlist(); + // FIXME auditioner is still audio-only + AudioPlaylist* const apl = dynamic_cast(_diskstream->playlist()); + assert(apl); + + apl->clear (false, false); + return *apl; } void @@ -82,13 +86,13 @@ Auditioner::audition_current_playlist () } Glib::Mutex::Lock lm (lock); - diskstream->seek (0); - length = diskstream->playlist()->get_maximum_extent(); + _diskstream->seek (0); + length = _diskstream->playlist()->get_maximum_extent(); current_frame = 0; /* force a panner reset now that we have all channels */ - _panner->reset (n_outputs(), diskstream->n_channels()); + _panner->reset (n_outputs(), _diskstream->n_channels()); g_atomic_int_set (&_active, 1); } @@ -108,23 +112,23 @@ Auditioner::audition_region (AudioRegion& region) the_region = new AudioRegion (region); the_region->set_position (0, this); - diskstream->playlist()->clear (true, false); - diskstream->playlist()->add_region (*the_region, 0, 1, false); + _diskstream->playlist()->clear (true, false); + _diskstream->playlist()->add_region (*the_region, 0, 1, false); - while (diskstream->n_channels() < the_region->n_channels()) { - diskstream->add_channel (); + while (_diskstream->n_channels() < the_region->n_channels()) { + audio_diskstream().add_channel (); } - while (diskstream->n_channels() > the_region->n_channels()) { - diskstream->remove_channel (); + while (_diskstream->n_channels() > the_region->n_channels()) { + audio_diskstream().remove_channel (); } /* force a panner reset now that we have all channels */ - _panner->reset (n_outputs(), diskstream->n_channels()); + _panner->reset (n_outputs(), _diskstream->n_channels()); length = the_region->length(); - diskstream->seek (0); + _diskstream->seek (0); current_frame = 0; g_atomic_int_set (&_active, 1); } @@ -143,14 +147,14 @@ Auditioner::play_audition (jack_nframes_t nframes) this_nframes = min (nframes, length - current_frame); - diskstream->prepare (); + _diskstream->prepare (); if ((ret = roll (this_nframes, current_frame, current_frame + nframes, 0, false, false, false)) != 0) { silence (nframes, 0); return ret; } - need_butler = diskstream->commit (this_nframes); + need_butler = _diskstream->commit (this_nframes); current_frame += this_nframes; if (current_frame >= length) { diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc new file mode 100644 index 0000000000..9312de5bf1 --- /dev/null +++ b/libs/ardour/diskstream.cc @@ -0,0 +1,401 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i18n.h" +#include + +using namespace std; +using namespace ARDOUR; +using namespace PBD; + +jack_nframes_t Diskstream::disk_io_chunk_frames = 0; + +sigc::signal Diskstream::DiskstreamCreated; +sigc::signal*> Diskstream::DeleteSources; +sigc::signal Diskstream::DiskOverrun; +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); +} + +void +Diskstream::init (Flag f) +{ + _refcnt = 0; + _flags = f; + _io = 0; + _alignment_style = ExistingMaterial; + _persistent_alignment_style = ExistingMaterial; + first_input_change = true; + i_am_the_modifier = 0; + g_atomic_int_set (&_record_enabled, 0); + was_recording = false; + capture_start_frame = 0; + capture_captured = 0; + _visible_speed = 1.0f; + _actual_speed = 1.0f; + _buffer_reallocation_required = false; + _seek_required = false; + first_recordable_frame = max_frames; + last_recordable_frame = max_frames; + _roll_delay = 0; + _capture_offset = 0; + _processed = false; + _slaved = false; + adjust_capture_position = 0; + last_possibly_recording = 0; + loop_location = 0; + wrap_buffer_size = 0; + speed_buffer_size = 0; + last_phase = 0; + phi = (uint64_t) (0x1000000); + file_frame = 0; + playback_sample = 0; + playback_distance = 0; + _read_data_count = 0; + _write_data_count = 0; + + pending_overwrite = false; + overwrite_frame = 0; + overwrite_queued = false; + input_change_pending = NoChange; + + _n_channels = 0; +} + +Diskstream::~Diskstream () +{ + // Taken by derived class destrctors.. should assure locked here somehow? + //Glib::Mutex::Lock lm (state_lock); + + if (_playlist) + _playlist->unref (); +} + +void +Diskstream::set_io (IO& io) +{ + _io = &io; + set_align_style_from_io (); +} + +void +Diskstream::handle_input_change (IOChange change, void *src) +{ + Glib::Mutex::Lock lm (state_lock); + + if (!(input_change_pending & change)) { + input_change_pending = IOChange (input_change_pending|change); + _session.request_input_change_handling (); + } +} + +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) +{ + bool changed = false; + double new_speed = sp * _session.transport_speed(); + + if (_visible_speed != sp) { + _visible_speed = sp; + changed = true; + } + + if (new_speed != _actual_speed) { + + jack_nframes_t required_wrap_size = (jack_nframes_t) floor (_session.get_block_size() * + fabs (new_speed)) + 1; + + if (required_wrap_size > wrap_buffer_size) { + _buffer_reallocation_required = true; + } + + _actual_speed = new_speed; + phi = (uint64_t) (0x1000000 * fabs(_actual_speed)); + } + + if (changed) { + if (!global) { + _seek_required = true; + } + SpeedChanged (); /* EMIT SIGNAL */ + } + + return _buffer_reallocation_required || _seek_required; +} + +void +Diskstream::prepare () +{ + _processed = false; + playback_distance = 0; +} + +void +Diskstream::recover () +{ + state_lock.unlock(); + _processed = false; +} + +void +Diskstream::set_capture_offset () +{ + if (_io == 0) { + /* can't capture, so forget it */ + return; + } + + _capture_offset = _io->input_latency(); +} + +void +Diskstream::set_align_style (AlignStyle a) +{ + if (record_enabled() && _session.actively_recording()) { + return; + } + + if (a != _alignment_style) { + _alignment_style = a; + AlignmentStyleChanged (); + } +} + +int +Diskstream::set_loop (Location *location) +{ + if (location) { + if (location->start() >= location->end()) { + error << string_compose(_("Location \"%1\" not valid for track loop (start >= end)"), location->name()) << endl; + return -1; + } + } + + loop_location = location; + + LoopSet (location); /* EMIT SIGNAL */ + return 0; +} + +jack_nframes_t +Diskstream::get_capture_start_frame (uint32_t n) +{ + Glib::Mutex::Lock lm (capture_info_lock); + + if (capture_info.size() > n) { + return capture_info[n]->start; + } + else { + return capture_start_frame; + } +} + +jack_nframes_t +Diskstream::get_captured_frames (uint32_t n) +{ + Glib::Mutex::Lock lm (capture_info_lock); + + if (capture_info.size() > n) { + return capture_info[n]->frames; + } + else { + return capture_captured; + } +} + +void +Diskstream::set_roll_delay (jack_nframes_t nframes) +{ + _roll_delay = nframes; +} + +void +Diskstream::set_speed (double sp) +{ + _session.request_diskstream_speed (*this, sp); + + /* to force a rebuffering at the right place */ + 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) +{ + playlist_modified (); +} + +void +Diskstream::playlist_modified () +{ + if (!i_am_the_modifier && !overwrite_queued) { + _session.request_overwrite_buffer (this); + overwrite_queued = true; + } +} + +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) +{ + if (str != _name) { + assert(playlist()); + playlist()->set_name (str); + _name = str; + + if (!in_set_state && recordable()) { + /* rename existing capture files so that they have the correct name */ + return rename_write_sources (); + } else { + return -1; + } + } + + return 0; +} + +void +Diskstream::set_destructive (bool yn) +{ + if (yn != destructive()) { + reset_write_sources (true, true); + if (yn) { + _flags |= Destructive; + } else { + _flags &= ~Destructive; + } + } +} diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index bb2bb52e9e..a70bf8abd3 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -97,11 +97,15 @@ static bool sort_ports_by_name (Port* a, Port* b) } +/** @param default_type The type of port that will be created by ensure_io + * and friends if no type is explicitly requested (to avoid breakage). + */ IO::IO (Session& s, string name, - - int input_min, int input_max, int output_min, int output_max) + int input_min, int input_max, int output_min, int output_max, + DataType default_type) : _session (s), _name (name), + _default_type(default_type), _gain_control (*this), _gain_automation_curve (0.0, 2.0, 1.0), _input_minimum (input_min), @@ -781,11 +785,20 @@ IO::remove_output_port (Port* port, void* src) return -1; } +/** Add an output port. + * + * @param destination Name of input port to connect new port to. + * @param src Source for emitted ConfigurationChanged signal. + * @param type Data type of port. Default value (NIL) will use this IO's default type. + */ int -IO::add_output_port (string destination, void* src) +IO::add_output_port (string destination, void* src, DataType type) { Port* our_port; - char buf[64]; + char name[64]; + + if (type == NIL) + type = _default_type; { Glib::Mutex::Lock em(_session.engine().process_lock()); @@ -799,14 +812,15 @@ IO::add_output_port (string destination, void* src) /* Create a new output port */ + // FIXME: naming scheme for differently typed ports? if (_output_maximum == 1) { - snprintf (buf, sizeof (buf), _("%s/out"), _name.c_str()); + snprintf (name, sizeof (name), _("%s/out"), _name.c_str()); } else { - snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole()); + snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole()); } - if ((our_port = _session.engine().register_audio_output_port (buf)) == 0) { - error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg; + if ((our_port = _session.engine().register_output_port (type, name)) == 0) { + error << string_compose(_("IO: cannot register output port %1"), name) << endmsg; return -1; } @@ -882,11 +896,21 @@ IO::remove_input_port (Port* port, void* src) return -1; } + +/** Add an input port. + * + * @param type Data type of port. The appropriate Jack port type, and @ref Port will be created. + * @param destination Name of input port to connect new port to. + * @param src Source for emitted ConfigurationChanged signal. + */ int -IO::add_input_port (string source, void* src) +IO::add_input_port (string source, void* src, DataType type) { Port* our_port; - char buf[64]; + char name[64]; + + if (type == NIL) + type = _default_type; { Glib::Mutex::Lock em (_session.engine().process_lock()); @@ -900,14 +924,15 @@ IO::add_input_port (string source, void* src) /* Create a new input port */ + // FIXME: naming scheme for differently typed ports? if (_input_maximum == 1) { - snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str()); + snprintf (name, sizeof (name), _("%s/in"), _name.c_str()); } else { - snprintf (buf, sizeof (buf), _("%s/in %u"), _name.c_str(), find_input_port_hole()); + snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole()); } - if ((our_port = _session.engine().register_audio_input_port (buf)) == 0) { - error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg; + if ((our_port = _session.engine().register_input_port (type, name)) == 0) { + error << string_compose(_("IO: cannot register input port %1"), name) << endmsg; return -1; } @@ -1001,7 +1026,7 @@ IO::ensure_inputs_locked (uint32_t n, bool clear, void* src) char buf[64]; - /* Create a new input port */ + /* Create a new input port (of the default type) */ if (_input_maximum == 1) { snprintf (buf, sizeof (buf), _("%s/in"), _name.c_str()); @@ -1012,7 +1037,7 @@ IO::ensure_inputs_locked (uint32_t n, bool clear, void* src) try { - if ((input_port = _session.engine().register_audio_input_port (buf)) == 0) { + if ((input_port = _session.engine().register_input_port (_default_type, buf)) == 0) { error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg; return -1; } @@ -1101,7 +1126,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) out_changed = true; } - /* create any necessary new ports */ + /* create any necessary new ports (of the default type) */ while (_ninputs < nin) { @@ -1117,7 +1142,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) } try { - if ((port = _session.engine().register_audio_input_port (buf)) == 0) { + if ((port = _session.engine().register_input_port (_default_type, buf)) == 0) { error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg; return -1; } @@ -1150,7 +1175,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src) } try { - if ((port = _session.engine().register_audio_output_port (buf)) == 0) { + if ((port = _session.engine().register_output_port (_default_type, buf)) == 0) { error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg; return -1; } @@ -1275,7 +1300,7 @@ IO::ensure_outputs_locked (uint32_t n, bool clear, void* src) snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole()); } - if ((output_port = _session.engine().register_audio_output_port (buf)) == 0) { + if ((output_port = _session.engine().register_output_port (_default_type, buf)) == 0) { error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg; return -1; } diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index fc1dd84066..6d5e8f7847 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -598,6 +598,31 @@ Playlist::remove_region_internal (Region *region, bool delay_sort) return -1; } +void +Playlist::get_equivalent_regions (const Region& other, vector& results) +{ + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + if (Config->get_use_overlap_equivalency()) { + if ((*i)->overlap_equivalent (other)) { + results.push_back ((*i)); + } else if ((*i)->equivalent (other)) { + results.push_back ((*i)); + } + } + } +} + +void +Playlist::get_region_list_equivalent_regions (const Region& other, vector& results) +{ + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + + if ((*i) && (*i)->region_list_equivalent (other)) { + results.push_back (*i); + } + } +} + void Playlist::partition (jack_nframes_t start, jack_nframes_t end, bool just_top_level) { diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index c5c03d0a05..7ec0d5a05a 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -24,15 +24,15 @@ using namespace ARDOUR; using namespace std; Port::Port (jack_port_t *p) - : port (p) + : _port (p) { - if (port == 0) { + if (_port == 0) { throw failed_constructor(); } - _flags = JackPortFlags (jack_port_flags (port)); - _type = jack_port_type (port); - _name = jack_port_name (port); + _flags = JackPortFlags (jack_port_flags (_port)); + _type = jack_port_type (_port); + _name = jack_port_name (_port); reset (); } @@ -42,9 +42,9 @@ Port::reset () { reset_buffer (); - last_monitor = false; - silent = false; - metering = 0; + _last_monitor = false; + _silent = false; + _metering = 0; reset_meters (); } @@ -54,7 +54,7 @@ Port::set_name (string str) { int ret; - if ((ret = jack_port_set_name (port, str.c_str())) == 0) { + if ((ret = jack_port_set_name (_port, str.c_str())) == 0) { _name = str; } diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index f195e42148..037c844324 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -39,13 +39,13 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -Change Region::FadeChanged = ARDOUR::new_change (); +Change Region::FadeChanged = ARDOUR::new_change (); Change Region::SyncOffsetChanged = ARDOUR::new_change (); -Change Region::MuteChanged = ARDOUR::new_change (); -Change Region::OpacityChanged = ARDOUR::new_change (); -Change Region::LockChanged = ARDOUR::new_change (); -Change Region::LayerChanged = ARDOUR::new_change (); -Change Region::HiddenChanged = ARDOUR::new_change (); +Change Region::MuteChanged = ARDOUR::new_change (); +Change Region::OpacityChanged = ARDOUR::new_change (); +Change Region::LockChanged = ARDOUR::new_change (); +Change Region::LayerChanged = ARDOUR::new_change (); +Change Region::HiddenChanged = ARDOUR::new_change (); sigc::signal Region::CheckNewRegion; @@ -990,3 +990,30 @@ Region::set_last_layer_op (uint64_t when) { _last_layer_op = when; } + +bool +Region::overlap_equivalent (const Region& other) const +{ + return coverage (other.first_frame(), other.last_frame()) != OverlapNone; +} + +bool +Region::equivalent (const Region& other) const +{ + return _start == other._start && + _position == other._position && + _length == other._length; +} + +bool +Region::size_equivalent (const Region& other) const +{ + return _start == other._start && + _length == other._length; +} + +bool +Region::region_list_equivalent (const Region& other) const +{ + return size_equivalent (other) && source_equivalent (other) && _name == other._name; +} diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index f3162f9131..effb8432d1 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -20,11 +20,13 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -50,8 +52,8 @@ using namespace PBD; uint32_t Route::order_key_cnt = 0; -Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg) - : IO (sess, name, input_min, input_max, output_min, output_max), +Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg, DataType default_type) + : IO (sess, name, input_min, input_max, output_min, output_max, default_type), _flags (flg), _solo_control (*this, ToggleControllable::SoloControl), _mute_control (*this, ToggleControllable::MuteControl) @@ -1330,6 +1332,9 @@ Route::state(bool full_state) snprintf (buf, sizeof (buf), "0x%x", _flags); node->add_property("flags", buf); } + + node->add_property("default-type", Buffer::type_to_string(_default_type)); + node->add_property("active", _active?"yes":"no"); node->add_property("muted", _muted?"yes":"no"); node->add_property("soloed", _soloed?"yes":"no"); @@ -1503,6 +1508,11 @@ Route::set_state (const XMLNode& node) } else { _flags = Flag (0); } + + if ((prop = node.property ("default-type")) != 0) { + _default_type = Buffer::type_from_string(prop->value()); + assert(_default_type != NIL); + } if ((prop = node.property ("phase-invert")) != 0) { set_phase_invert(prop->value()=="yes"?true:false, this); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index ae879ed083..45afdf479f 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -397,6 +397,8 @@ Session::~Session () delete [] (i->second); } + AudioDiskstream::free_working_buffers(); + #undef TRACK_DESTRUCTION #ifdef TRACK_DESTRUCTION cerr << "delete named selections\n"; @@ -440,10 +442,10 @@ Session::~Session () } #ifdef TRACK_DESTRUCTION - cerr << "delete audio_diskstreams\n"; + cerr << "delete diskstreams\n"; #endif /* TRACK_DESTRUCTION */ - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ) { - AudioDiskstreamList::iterator tmp; + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ) { + DiskstreamList::iterator tmp; tmp = i; ++tmp; @@ -860,7 +862,7 @@ Session::playlist_length_changed (Playlist* pl) } void -Session::diskstream_playlist_changed (AudioDiskstream* dstream) +Session::diskstream_playlist_changed (Diskstream* dstream) { Playlist *playlist; @@ -940,7 +942,7 @@ Session::set_auto_input (bool yn) The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (!auto_input); @@ -958,7 +960,7 @@ Session::reset_input_monitor_state () { if (transport_rolling()) { Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (Config->get_use_hardware_monitoring() && !auto_input); @@ -966,7 +968,7 @@ Session::reset_input_monitor_state () } } else { Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (Config->get_use_hardware_monitoring()); @@ -1047,7 +1049,7 @@ Session::auto_loop_changed (Location* location) } else if (seamless_loop && !loop_changing) { - // schedule a locate-roll to refill the audio_diskstreams at the + // schedule a locate-roll to refill the diskstreams at the // previous loop end loop_changing = true; @@ -1244,7 +1246,7 @@ Session::enable_record () */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { (*i)->monitor_input (true); } @@ -1279,7 +1281,7 @@ Session::disable_record (bool rt_context, bool force) */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { (*i)->monitor_input (false); } @@ -1306,7 +1308,7 @@ Session::step_back_from_record () */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (auto_input && (*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (false); @@ -1476,7 +1478,7 @@ Session::set_block_size (jack_nframes_t nframes) (*i)->set_block_size (nframes); } - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->set_block_size (nframes); } @@ -1760,7 +1762,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod track->set_control_outs (cports); } - track->diskstream_changed.connect (mem_fun (this, &Session::resort_routes_proxy)); + track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes)); add_route (track); @@ -1805,7 +1807,7 @@ Session::new_audio_route (int input_channels, int output_channels) } while (n < (UINT_MAX-1)); try { - shared_ptr bus (new Route (*this, bus_name, -1, -1, -1, -1)); + shared_ptr bus (new Route (*this, bus_name, -1, -1, -1, -1, Route::Flag(0), AUDIO)); if (bus->ensure_io (input_channels, output_channels, false, this)) { error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"), @@ -1858,7 +1860,7 @@ Session::new_audio_route (int input_channels, int output_channels) } catch (failed_constructor &err) { - error << _("Session: could not create new route.") << endmsg; + error << _("Session: could not create new audio route.") << endmsg; return shared_ptr ((Route*) 0); } } @@ -1893,14 +1895,14 @@ Session::add_route (shared_ptr route) } void -Session::add_diskstream (AudioDiskstream* dstream) +Session::add_diskstream (Diskstream* dstream) { /* need to do this in case we're rolling at the time, to prevent false underruns */ - dstream->do_refill(0, 0, 0); + dstream->do_refill_with_alloc(); { Glib::RWLock::WriterLock lm (diskstream_lock); - audio_diskstreams.push_back (dstream); + diskstreams.push_back (dstream); } /* take a reference to the diskstream, preventing it from @@ -1920,7 +1922,7 @@ Session::add_diskstream (AudioDiskstream* dstream) set_dirty(); save_state (_current_snapshot_name); - AudioDiskstreamAdded (dstream); /* EMIT SIGNAL */ + DiskstreamAdded (dstream); /* EMIT SIGNAL */ } void @@ -1957,18 +1959,19 @@ Session::remove_route (shared_ptr route) /* writer goes out of scope, forces route list update */ } + // FIXME: audio specific AudioTrack* at; AudioDiskstream* ds = 0; if ((at = dynamic_cast(route.get())) != 0) { - ds = &at->disk_stream(); + ds = &at->audio_diskstream(); } if (ds) { { Glib::RWLock::WriterLock lm (diskstream_lock); - audio_diskstreams.remove (ds); + diskstreams.remove (ds); } ds->unref (); @@ -2261,7 +2264,7 @@ Session::get_maximum_extent () const ensure atomicity. */ - for (AudioDiskstreamList::const_iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::const_iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { Playlist* pl = (*i)->playlist(); if ((me = pl->get_maximum_extent()) > max) { max = me; @@ -2271,12 +2274,12 @@ Session::get_maximum_extent () const return max; } -AudioDiskstream * +Diskstream * Session::diskstream_by_name (string name) { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->name() == name) { return* i; } @@ -2285,12 +2288,12 @@ Session::diskstream_by_name (string name) return 0; } -AudioDiskstream * +Diskstream * Session::diskstream_by_id (const PBD::ID& id) { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->id() == id) { return *i; } @@ -2555,18 +2558,10 @@ Session::find_whole_file_parent (AudioRegion& child) } void -Session::find_equivalent_playlist_regions (AudioRegion& region, vector& result) +Session::find_equivalent_playlist_regions (Region& region, vector& result) { - for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) { - - AudioPlaylist* pl; - - if ((pl = dynamic_cast(*i)) == 0) { - continue; - } - - pl->get_region_list_equivalent_regions (region, result); - } + for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) + (*i)->get_region_list_equivalent_regions (region, result); } int @@ -2618,7 +2613,7 @@ Session::remove_last_capture () Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { list& l = (*i)->last_capture_regions(); if (!l.empty()) { @@ -2925,18 +2920,6 @@ Session::create_audio_source_for_session (AudioDiskstream& ds, uint32_t chan, bo /* Playlist management */ -Playlist * -Session::get_playlist (string name) -{ - Playlist* ret = 0; - - if ((ret = playlist_by_name (name)) == 0) { - ret = new AudioPlaylist (*this, name); - } - - return ret; -} - Playlist * Session::playlist_by_name (string name) { @@ -3066,11 +3049,14 @@ Session::audition_playlist () } void -Session::audition_region (AudioRegion& r) +Session::audition_region (Region& r) { - Event* ev = new Event (Event::Audition, Event::Add, Event::Immediate, 0, 0.0); - ev->set_ptr (&r); - queue_event (ev); + AudioRegion* ar = dynamic_cast(&r); + if (ar) { + Event* ev = new Event (Event::Audition, Event::Add, Event::Immediate, 0, 0.0); + ev->set_ptr (ar); + queue_event (ev); + } } void @@ -3155,12 +3141,12 @@ Session::set_all_mute (bool yn) } uint32_t -Session::n_audio_diskstreams () const +Session::n_diskstreams () const { Glib::RWLock::ReaderLock lm (diskstream_lock); uint32_t n = 0; - for (AudioDiskstreamList::const_iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::const_iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { n++; } @@ -3168,17 +3154,6 @@ Session::n_audio_diskstreams () const return n; } -void -Session::foreach_audio_diskstream (void (AudioDiskstream::*func)(void)) -{ - Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { - if (!(*i)->hidden()) { - ((*i)->*func)(); - } - } -} - void Session::graph_reordered () { @@ -3198,7 +3173,7 @@ Session::graph_reordered () reflect any changes in latencies within the graph. */ - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->set_capture_offset (); } } @@ -3481,7 +3456,7 @@ Session::reset_native_file_format () //RWLockMonitor lm1 (route_lock, true, __LINE__, __FILE__); Glib::RWLock::ReaderLock lm2 (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->reset_write_sources (false); } } @@ -3592,7 +3567,7 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf /* call tree *MUST* hold route_lock */ - if ((playlist = track.disk_stream().playlist()) == 0) { + if ((playlist = track.diskstream().playlist()) == 0) { goto out; } @@ -3602,7 +3577,7 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf goto out; } - nchans = track.disk_stream().n_channels(); + nchans = track.audio_diskstream().n_channels(); dir = discover_best_sound_dir (); diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc index 4613bfccf9..6509a783bb 100644 --- a/libs/ardour/session_butler.cc +++ b/libs/ardour/session_butler.cc @@ -168,15 +168,9 @@ Session::butler_thread_work () struct timeval begin, end; struct pollfd pfd[1]; bool disk_work_outstanding = false; - AudioDiskstreamList::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); + DiskstreamList::iterator i; while (true) { - pfd[0].fd = butler_request_pipe[0]; pfd[0].events = POLLIN|POLLERR|POLLHUP; @@ -198,14 +192,13 @@ Session::butler_thread_work () } if (pfd[0].revents & POLLIN) { - + char req; /* empty the pipe of all current requests */ while (1) { size_t nread = ::read (butler_request_pipe[0], &req, sizeof (req)); - if (nread == 1) { switch ((ButlerRequest::Type) req) { @@ -240,10 +233,10 @@ Session::butler_thread_work () } } } - - for (i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + + //for (i = diskstreams.begin(); i != diskstreams.end(); ++i) { // cerr << "BEFORE " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl; - } + //} if (transport_work_requested()) { butler_transport_work (); @@ -257,16 +250,16 @@ Session::butler_thread_work () Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (i = audio_diskstreams.begin(); !transport_work_requested() && butler_should_run && i != audio_diskstreams.end(); ++i) { - - // cerr << "rah fondr " << (*i)->io()->name () << endl; + for (i = diskstreams.begin(); !transport_work_requested() && butler_should_run && i != diskstreams.end(); ++i) { + + Diskstream* const ds = *i; - switch ((*i)->do_refill (butler_mixdown_buffer, butler_gain_buffer, conv_buffer)) { + switch (ds->do_refill ()) { case 0: - bytes += (*i)->read_data_count(); + bytes += ds->read_data_count(); break; case 1: - bytes += (*i)->read_data_count(); + bytes += ds->read_data_count(); disk_work_outstanding = true; break; @@ -278,7 +271,7 @@ Session::butler_thread_work () } - if (i != audio_diskstreams.end()) { + if (i != diskstreams.end()) { /* we didn't get to all the streams */ disk_work_outstanding = true; } @@ -299,12 +292,11 @@ Session::butler_thread_work () bytes = 0; compute_io = true; gettimeofday (&begin, 0); - - for (i = audio_diskstreams.begin(); !transport_work_requested() && butler_should_run && i != audio_diskstreams.end(); ++i) { - + + 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; @@ -330,7 +322,7 @@ Session::butler_thread_work () request_stop (); } - if (i != audio_diskstreams.end()) { + if (i != diskstreams.end()) { /* we didn't get to all the streams */ disk_work_outstanding = true; } @@ -357,7 +349,7 @@ Session::butler_thread_work () Glib::Mutex::Lock lm (butler_request_lock); if (butler_should_run && (disk_work_outstanding || transport_work_requested())) { -// for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { +// for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { // cerr << "AFTER " << (*i)->name() << ": pb = " << (*i)->playback_buffer_load() << " cp = " << (*i)->capture_buffer_load() << endl; // } @@ -375,18 +367,17 @@ Session::butler_thread_work () void -Session::request_overwrite_buffer (AudioDiskstream* stream) +Session::request_overwrite_buffer (Diskstream* stream) { Event *ev = new Event (Event::Overwrite, Event::Add, Event::Immediate, 0, 0, 0.0); ev->set_ptr (stream); queue_event (ev); } +/** Process thread. */ void -Session::overwrite_some_buffers (AudioDiskstream* ds) +Session::overwrite_some_buffers (Diskstream* ds) { - /* executed by the audio thread */ - if (actively_recording()) { return; } @@ -398,7 +389,7 @@ Session::overwrite_some_buffers (AudioDiskstream* ds) } else { Glib::RWLock::ReaderLock dm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->set_pending_overwrite (true); } } diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index ad8ce7c407..b39c4f2218 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -496,7 +496,7 @@ Session::prepare_to_export (AudioExportSpecification& spec) { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)-> seek (spec.start_frame, true)) { error << string_compose (_("%1: cannot seek to %2 for export"), (*i)->name(), spec.start_frame) diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index 2024730292..88b111a1fb 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -66,7 +66,7 @@ Session::process (jack_nframes_t nframes) void Session::prepare_diskstreams () { - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->prepare (); } } @@ -141,7 +141,7 @@ Session::process_routes (jack_nframes_t nframes, jack_nframes_t offset) call path, so make sure we release any outstanding locks here before we return failure. */ - for (AudioDiskstreamList::iterator ids = audio_diskstreams.begin(); ids != audio_diskstreams.end(); ++ids) { + for (DiskstreamList::iterator ids = diskstreams.begin(); ids != diskstreams.end(); ++ids) { (*ids)->recover (); } @@ -181,7 +181,7 @@ Session::silent_process_routes (jack_nframes_t nframes, jack_nframes_t offset) call path, so make sure we release any outstanding locks here before we return failure. */ - for (AudioDiskstreamList::iterator ids = audio_diskstreams.begin(); ids != audio_diskstreams.end(); ++ids) { + for (DiskstreamList::iterator ids = diskstreams.begin(); ids != diskstreams.end(); ++ids) { (*ids)->recover (); } @@ -200,7 +200,7 @@ Session::commit_diskstreams (jack_nframes_t nframes, bool &needs_butler) float pworst = 1.0f; float cworst = 1.0f; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->hidden()) { continue; @@ -570,7 +570,7 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset) bool ok = true; jack_nframes_t frame_delta = slave_transport_frame - _transport_frame; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->can_internal_playback_seek (frame_delta)) { ok = false; break; @@ -578,7 +578,7 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset) } if (ok) { - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->internal_playback_seek (frame_delta); } _transport_frame += frame_delta; diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 2f6f57e2d8..c90fd91d73 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -194,6 +194,7 @@ 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 */ @@ -266,7 +267,7 @@ Session::first_stage_init (string fullpath, string snapshot_name) AudioSource::AudioSourceCreated.connect (mem_fun (*this, &Session::add_audio_source)); Playlist::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist)); Redirect::RedirectCreated.connect (mem_fun (*this, &Session::add_redirect)); - AudioDiskstream::AudioDiskstreamCreated.connect (mem_fun (*this, &Session::add_diskstream)); + AudioDiskstream::DiskstreamCreated.connect (mem_fun (*this, &Session::add_diskstream)); NamedSelection::NamedSelectionCreated.connect (mem_fun (*this, &Session::add_named_selection)); Controllable::Created.connect (mem_fun (*this, &Session::add_controllable)); @@ -1386,7 +1387,7 @@ Session::state(bool full_state) { Glib::RWLock::ReaderLock dl (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { child->add_child_nocopy ((*i)->get_state()); } diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 03e078ecde..d850fb94c8 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -79,7 +79,7 @@ Session::request_transport_speed (float speed) } void -Session::request_diskstream_speed (AudioDiskstream& ds, float speed) +Session::request_diskstream_speed (Diskstream& ds, float speed) { Event* ev = new Event (Event::SetDiskstreamSpeed, Event::Add, Event::Immediate, 0, speed); ev->set_ptr (&ds); @@ -201,7 +201,7 @@ Session::butler_transport_work () } if (post_transport_work & PostTransportInputChange) { - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->non_realtime_input_change (); } } @@ -217,7 +217,7 @@ Session::butler_transport_work () cumulative_rf_motion = 0; reset_rf_scale (0); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) { (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed())); @@ -249,7 +249,7 @@ Session::non_realtime_set_speed () { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->non_realtime_set_speed (); } } @@ -259,7 +259,7 @@ Session::non_realtime_overwrite () { Glib::RWLock::ReaderLock lm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->pending_overwrite) { (*i)->overwrite_existing_buffers (); } @@ -275,7 +275,7 @@ Session::non_realtime_stop (bool abort) did_record = false; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->get_captured_frames () != 0) { did_record = true; break; @@ -328,7 +328,7 @@ Session::non_realtime_stop (bool abort) _have_captured = true; } - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->transport_stopped (*now, xnow, abort); } @@ -367,7 +367,7 @@ Session::non_realtime_stop (bool abort) } #endif - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) { (*i)->seek ((jack_nframes_t) (_transport_frame * (double) (*i)->speed())); @@ -494,7 +494,7 @@ Session::set_auto_loop (bool yn) if (seamless_loop) { // set all diskstreams to use internal looping - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { (*i)->set_loop (loc); } @@ -502,7 +502,7 @@ Session::set_auto_loop (bool yn) } else { // set all diskstreams to NOT use internal looping - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { (*i)->set_loop (0); } @@ -532,7 +532,7 @@ Session::set_auto_loop (bool yn) clear_events (Event::AutoLoop); // set all diskstreams to NOT use internal looping - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { (*i)->set_loop (0); } @@ -650,7 +650,7 @@ Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, b The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (!auto_input); @@ -665,7 +665,7 @@ Session::locate (jack_nframes_t target_frame, bool with_roll, bool with_flush, b The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (true); @@ -709,7 +709,7 @@ Session::set_transport_speed (float speed, bool abort) The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (true); @@ -735,7 +735,7 @@ Session::set_transport_speed (float speed, bool abort) The rarity and short potential lock duration makes this "OK" */ Glib::RWLock::ReaderLock dsm (diskstream_lock); - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (auto_input && (*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; (*i)->monitor_input (false); @@ -786,7 +786,7 @@ Session::set_transport_speed (float speed, bool abort) _last_transport_speed = _transport_speed; _transport_speed = speed; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if ((*i)->realtime_set_speed ((*i)->speed(), true)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); } @@ -876,7 +876,7 @@ Session::actually_start_transport () transport_sub_state |= PendingDeclickIn; _transport_speed = 1.0; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->realtime_set_speed ((*i)->speed(), true); } @@ -1006,7 +1006,7 @@ Session::set_slave_source (SlaveSource src, jack_nframes_t frame) _slave_type = src; - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { if (!(*i)->hidden()) { if ((*i)->realtime_set_speed ((*i)->speed(), true)) { non_rt_required = true; @@ -1038,7 +1038,7 @@ Session::reverse_diskstream_buffers () } void -Session::set_diskstream_speed (AudioDiskstream* stream, float speed) +Session::set_diskstream_speed (Diskstream* stream, float speed) { if (stream->realtime_set_speed (speed, false)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); @@ -1235,7 +1235,7 @@ Session::update_latency_compensation (bool with_stop, bool abort) /* reflect any changes in latencies into capture offsets */ - for (AudioDiskstreamList::iterator i = audio_diskstreams.begin(); i != audio_diskstreams.end(); ++i) { + for (DiskstreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) { (*i)->set_capture_offset (); } } diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc new file mode 100644 index 0000000000..3b3b705a87 --- /dev/null +++ b/libs/ardour/track.cc @@ -0,0 +1,219 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. +*/ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i18n.h" + +using namespace std; +using namespace ARDOUR; +using namespace PBD; + +Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, DataType default_type) + : Route (sess, name, 1, -1, -1, -1, flag, default_type) + , _diskstream (0) + , _rec_enable_control (*this) +{ + _declickable = true; + _freeze_record.state = NoFreeze; + _saved_meter_point = _meter_point; + _mode = mode; +} + +Track::Track (Session& sess, const XMLNode& node, DataType default_type) + : Route (sess, "to be renamed", 0, 0, -1, -1, Route::Flag(0), default_type) + , _diskstream (0) + , _rec_enable_control (*this) +{ + _freeze_record.state = NoFreeze; + _declickable = true; + _saved_meter_point = _meter_point; +} + +Track::~Track () +{ + if (_diskstream) { + _diskstream->unref(); + } +} + +void +Track::set_meter_point (MeterPoint p, void *src) +{ + Route::set_meter_point (p, src); +} + +XMLNode& +Track::get_state () +{ + return state (true); +} + +XMLNode& +Track::get_template () +{ + return state (false); +} + +void +Track::toggle_monitor_input () +{ + for (vector::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + (*i)->request_monitor_input(!(*i)->monitoring_input()); + } +} + +jack_nframes_t +Track::update_total_latency () +{ + _own_latency = 0; + + for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { + if ((*i)->active ()) { + _own_latency += (*i)->latency (); + } + } + + set_port_latency (_own_latency); + + return _own_latency; +} + + +Track::FreezeRecord::~FreezeRecord () +{ + for (vector::iterator i = insert_info.begin(); i != insert_info.end(); ++i) { + delete *i; + } +} + +Track::FreezeState +Track::freeze_state() const +{ + return _freeze_record.state; +} + +Track::RecEnableControllable::RecEnableControllable (Track& s) + : track (s) +{ +} + +void +Track::RecEnableControllable::set_value (float val) +{ + bool bval = ((val >= 0.5f) ? true: false); + track.set_record_enable (bval, this); +} + +float +Track::RecEnableControllable::get_value (void) const +{ + if (track.record_enabled()) { return 1.0f; } + return 0.0f; +} + +bool +Track::record_enabled () const +{ + return _diskstream->record_enabled (); +} + +void +Track::set_record_enable (bool yn, void *src) +{ + if (_freeze_record.state == Frozen) { + return; + } + + if (_mix_group && src != _mix_group && _mix_group->is_active()) { + _mix_group->apply (&Track::set_record_enable, yn, _mix_group); + return; + } + + /* keep track of the meter point as it was before we rec-enabled */ + + if (!_diskstream->record_enabled()) { + _saved_meter_point = _meter_point; + } + + _diskstream->set_record_enabled (yn); + + if (_diskstream->record_enabled()) { + set_meter_point (MeterInput, this); + } else { + set_meter_point (_saved_meter_point, this); + } + + _rec_enable_control.Changed (); +} + +void +Track::set_mode (TrackMode m) +{ + if (_diskstream) { + if (_mode != m) { + _mode = m; + _diskstream->set_destructive (m == Destructive); + ModeChanged(); + } + } +} + +int +Track::set_name (string str, void *src) +{ + int ret; + + if (record_enabled() && _session.actively_recording()) { + /* this messes things up if done while recording */ + return -1; + } + + if (_diskstream->set_name (str)) { + return -1; + } + + /* save state so that the statefile fully reflects any filename changes */ + + if ((ret = IO::set_name (str, src)) == 0) { + _session.save_state (""); + } + return ret; +} + +void +Track::set_latency_delay (jack_nframes_t longest_session_latency) +{ + Route::set_latency_delay (longest_session_latency); + _diskstream->set_roll_delay (_roll_delay); +} +