From 8849cb428741d7d60261d1e44ceec665912281f5 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 9 Mar 2011 05:19:44 +0000 Subject: add new concept for managing alignment style (AlignChoice); switch to using worst_playback_latency() just about everywhere we were using worst_output_latency() - the former includes plugin latency. answer appears to break earlier fixes to alignment, but is semantically right, so plan to investigate in another 8 hours or so git-svn-id: svn://localhost/ardour2/branches/3.0@9112 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/route_time_axis.cc | 121 ++++++++++++++++++++++++++++++--------- gtk2_ardour/route_time_axis.h | 2 +- libs/ardour/ardour/diskstream.h | 8 +-- libs/ardour/ardour/session.h | 1 + libs/ardour/ardour/track.h | 2 + libs/ardour/ardour/types.h | 6 ++ libs/ardour/audio_diskstream.cc | 14 ++--- libs/ardour/diskstream.cc | 53 +++++++++++++---- libs/ardour/enums.cc | 6 ++ libs/ardour/midi_diskstream.cc | 14 ++--- libs/ardour/mtc_slave.cc | 2 +- libs/ardour/session.cc | 2 +- libs/ardour/session_midi.cc | 2 +- libs/ardour/session_transport.cc | 10 ++-- libs/ardour/track.cc | 12 ++++ 15 files changed, 188 insertions(+), 67 deletions(-) diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index cde6d552b4..94e4601db1 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -506,36 +506,96 @@ RouteTimeAxisView::build_display_menu () int existing = 0; int capture = 0; + int automatic = 0; + int styles = 0; + boost::shared_ptr first_track; + TrackSelection const & s = _editor.get_selection().tracks; for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) { RouteTimeAxisView* r = dynamic_cast (*i); if (!r || !r->is_track ()) { continue; } - - switch (r->track()->alignment_style()) { - case ExistingMaterial: - ++existing; - break; - case CaptureTime: - ++capture; - break; - } + + if (!first_track) { + first_track = r->track(); + } + + switch (r->track()->alignment_choice()) { + case Automatic: + ++automatic; + styles |= 0x1; + switch (r->track()->alignment_style()) { + case ExistingMaterial: + ++existing; + break; + case CaptureTime: + ++capture; + break; + } + break; + case UseExistingMaterial: + ++existing; + styles |= 0x2; + break; + case UseCaptureTime: + ++capture; + styles |= 0x4; + break; + } } - - alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material"))); - RadioMenuItem* i = dynamic_cast (&alignment_items.back()); - i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), ExistingMaterial, true)); - i->set_active (existing != 0 && capture == 0); - i->set_inconsistent (existing != 0 && capture != 0); - - alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time"))); - i = dynamic_cast (&alignment_items.back()); - i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), CaptureTime, true)); - i->set_active (existing == 0 && capture != 0); - i->set_inconsistent (existing != 0 && capture != 0); - - items.push_back (MenuElem (_("Alignment"), *alignment_menu)); + + bool inconsistent; + switch (styles) { + case 1: + case 2: + case 4: + inconsistent = false; + break; + default: + inconsistent = true; + break; + } + + RadioMenuItem* i; + + if (!inconsistent && first_track) { + + alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)"))); + i = dynamic_cast (&alignment_items.back()); + i->set_active (automatic != 0 && existing == 0 && capture == 0); + i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true)); + + switch (first_track->alignment_choice()) { + case Automatic: + switch (first_track->alignment_style()) { + case ExistingMaterial: + alignment_items.push_back (MenuElem (_("(Currently: Existing Material)"))); + break; + case CaptureTime: + alignment_items.push_back (MenuElem (_("(Currently: Capture Time)"))); + break; + } + break; + default: + break; + } + + alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material"))); + i = dynamic_cast (&alignment_items.back()); + i->set_active (existing != 0 && capture == 0 && automatic == 0); + i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true)); + + alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time"))); + i = dynamic_cast (&alignment_items.back()); + i->set_active (existing == 0 && capture != 0 && automatic == 0); + i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true)); + + items.push_back (MenuElem (_("Alignment"), *alignment_menu)); + + } else { + /* show nothing */ + } Menu* mode_menu = manage (new Menu); MenuList& mode_items = mode_menu->items (); @@ -922,13 +982,21 @@ RouteTimeAxisView::set_samples_per_unit (double spu) } void -RouteTimeAxisView::set_align_style (AlignStyle style, bool apply_to_selection) +RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection) { + /* this is one of the two calls made when these radio menu items change status. this one + is for the item that became inactive, and we want to ignore it. + */ + + if (!mitem->get_active()) { + return; + } + if (apply_to_selection) { - _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_style, _1, style, false)); + _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false)); } else { if (track ()) { - track()->set_align_style (style); + track()->set_align_choice (choice); } } } @@ -1524,7 +1592,6 @@ RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr boost::shared_ptr track = boost::dynamic_pointer_cast(*i); if (!track) { - std::cerr << "route " << (*i)->name() << " is not a Track" << std::endl; continue; } diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h index 91bc1ff5c6..c68dc573ea 100644 --- a/gtk2_ardour/route_time_axis.h +++ b/gtk2_ardour/route_time_axis.h @@ -216,7 +216,7 @@ protected: virtual void append_extra_display_menu_items () {} void build_display_menu (); - void set_align_style (ARDOUR::AlignStyle, bool apply_to_selection = false); + void set_align_choice (Gtk::RadioMenuItem*, ARDOUR::AlignChoice, bool apply_to_selection = false); void playlist_click (); void show_playlist_selector (); diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h index b0896349b5..c6651473e5 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -75,9 +75,10 @@ class Diskstream : public SessionObject, public PublicDiskstream void set_flag (Flag f) { _flags = Flag (_flags | f); } void unset_flag (Flag f) { _flags = Flag (_flags & ~f); } - AlignStyle alignment_style() const { return _alignment_style; } + AlignStyle alignment_style() const { return _alignment_style; } + AlignChoice alignment_choice() const { return _alignment_choice; } void set_align_style (AlignStyle); - void set_persistent_align_style (AlignStyle a) { _persistent_alignment_style = a; } + void set_align_choice (AlignChoice a); framecnt_t roll_delay() const { return _roll_delay; } void set_roll_delay (framecnt_t); @@ -272,6 +273,7 @@ class Diskstream : public SessionObject, public PublicDiskstream framepos_t last_recordable_frame; int last_possibly_recording; AlignStyle _alignment_style; + AlignChoice _alignment_choice; bool _scrubbing; bool _slaved; Location* loop_location; @@ -294,8 +296,6 @@ class Diskstream : public SessionObject, public PublicDiskstream uint32_t _write_data_count; bool in_set_state; - AlignStyle _persistent_alignment_style; - bool first_input_change; Glib::Mutex state_lock; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 7d720cfa08..47285088ff 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -351,6 +351,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi framecnt_t worst_output_latency () const { return _worst_output_latency; } framecnt_t worst_input_latency () const { return _worst_input_latency; } framecnt_t worst_track_latency () const { return _worst_track_latency; } + framecnt_t worst_playback_latency () const { return _worst_output_latency + _worst_track_latency; } #ifdef HAVE_JACK_SESSION void jack_session_event (jack_session_event_t* event); diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index 8faff74bc3..aadc2f7797 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -139,11 +139,13 @@ class Track : public Route, public PublicDiskstream ChanCount n_channels (); framepos_t get_capture_start_frame (uint32_t n = 0) const; AlignStyle alignment_style () const; + AlignChoice alignment_choice () const; framepos_t current_capture_start () const; framepos_t current_capture_end () const; void playlist_modified (); int use_playlist (boost::shared_ptr); void set_align_style (AlignStyle); + void set_align_choice (AlignChoice); int use_copy_playlist (); int use_new_playlist (); void adjust_playback_buffering (); diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index e0c738270e..d831dfae2b 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -168,6 +168,12 @@ namespace ARDOUR { ExistingMaterial }; + enum AlignChoice { + UseCaptureTime, + UseExistingMaterial, + Automatic + }; + enum MeterPoint { MeterInput, MeterPreFader, diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 6da9fb6f0a..dd4310294b 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -177,13 +177,7 @@ AudioDiskstream::non_realtime_input_change () get_input_sources (); set_capture_offset (); - - if (first_input_change) { - set_align_style (_persistent_alignment_style); - first_input_change = false; - } else { - set_align_style_from_io (); - } + set_align_style_from_io (); input_change_pending = IOChange::NoChange; @@ -1554,7 +1548,7 @@ AudioDiskstream::transport_looped (framepos_t transport_frame) capture_captured += _capture_offset; if (_alignment_style == ExistingMaterial) { - capture_captured += _session.worst_output_latency(); + capture_captured += _session.worst_playback_latency(); } else { capture_captured += _roll_delay; } @@ -2006,6 +2000,10 @@ AudioDiskstream::set_align_style_from_io () { bool have_physical = false; + if (_alignment_choice != Automatic) { + return; + } + if (_io == 0) { return; } diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index 97780972f8..647d62e00f 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -32,11 +32,12 @@ #include +#include + #include "pbd/error.h" #include "pbd/basename.h" -#include -#include "pbd/xml++.h" #include "pbd/memento_command.h" +#include "pbd/xml++.h" #include "ardour/ardour.h" #include "ardour/audioengine.h" @@ -93,6 +94,7 @@ Diskstream::Diskstream (Session &sess, const string &name, Flag flag) , last_recordable_frame (max_framepos) , last_possibly_recording (0) , _alignment_style (ExistingMaterial) + , _alignment_choice (Automatic) , _scrubbing (false) , _slaved (false) , loop_location (0) @@ -110,8 +112,6 @@ Diskstream::Diskstream (Session &sess, const string &name, Flag flag) , _read_data_count (0) , _write_data_count (0) , in_set_state (false) - , _persistent_alignment_style (ExistingMaterial) - , first_input_change (true) , _flags (flag) , deprecated_io_node (0) { @@ -137,6 +137,7 @@ Diskstream::Diskstream (Session& sess, const XMLNode& /*node*/) , last_recordable_frame (max_framepos) , last_possibly_recording (0) , _alignment_style (ExistingMaterial) + , _alignment_choice (Automatic) , _scrubbing (false) , _slaved (false) , loop_location (0) @@ -154,8 +155,6 @@ Diskstream::Diskstream (Session& sess, const XMLNode& /*node*/) , _read_data_count (0) , _write_data_count (0) , in_set_state (false) - , _persistent_alignment_style (ExistingMaterial) - , first_input_change (true) , _flags (Recordable) , deprecated_io_node (0) { @@ -270,6 +269,7 @@ Diskstream::set_capture_offset () DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: using IO latency, capture offset set to %2\n", name(), _capture_offset)); } + void Diskstream::set_align_style (AlignStyle a) { @@ -283,6 +283,30 @@ Diskstream::set_align_style (AlignStyle a) } } +void +Diskstream::set_align_choice (AlignChoice a) +{ + if (record_enabled() && _session.actively_recording()) { + return; + } + + if (a != _alignment_choice) { + _alignment_choice = a; + + switch (_alignment_choice) { + case Automatic: + set_align_style_from_io (); + break; + case UseExistingMaterial: + set_align_style (ExistingMaterial); + break; + case UseCaptureTime: + set_align_style (CaptureTime); + break; + } + } +} + int Diskstream::set_loop (Location *location) { @@ -452,6 +476,7 @@ Diskstream::get_state () node->add_property("id", buf); snprintf (buf, sizeof(buf), "%f", _visible_speed); node->add_property ("speed", buf); + node->add_property ("capture-alignment", enum_2_string (_alignment_choice)); if (_extra_xml) { node->add_child_copy (*_extra_xml); @@ -483,6 +508,12 @@ Diskstream::set_state (const XMLNode& node, int /*version*/) _flags = Flag (string_2_enum (prop->value(), _flags)); } + if ((prop = node.property (X_("capture-alignment"))) != 0) { + _alignment_choice = AlignChoice (string_2_enum (prop->value(), _alignment_choice)); + } else { + _alignment_choice = Automatic; + } + if ((prop = node.property ("playlist")) == 0) { return -1; } @@ -621,10 +652,10 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record) last_recordable_frame = max_framepos; capture_start_frame = transport_frame; - DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 basic FRF = %2 LRF = %3 CSF = %4 CO = %5, WLO = %6\n", + DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 basic FRF = %2 LRF = %3 CSF = %4 CO = %5, WPL = %6\n", name(), first_recordable_frame, last_recordable_frame, capture_start_frame, _capture_offset, - _session.worst_output_latency(), + _session.worst_playback_latency(), transport_frame)); @@ -635,13 +666,13 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record) if (_alignment_style == ExistingMaterial) { - /* audio played by ardour will take (up to) _session.worst_output_latency() ("WOL") to + /* audio played by ardour will take (up to) _session.worst_playback_latency() ("WOL") to appear at the speakers; audio played at the time when it does appear at the speakers will take _capture_offset to arrive back here. we've already added _capture_offset, so now add WOL. */ - first_recordable_frame += _session.worst_output_latency(); + first_recordable_frame += _session.worst_playback_latency(); DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tROLL: shift FRF by delta between WOL %1\n", first_recordable_frame)); } else { @@ -657,7 +688,7 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record) if (_alignment_style == ExistingMaterial) { /* see comment in ExistingMaterial block above */ - first_recordable_frame += _session.worst_output_latency(); + first_recordable_frame += _session.worst_playback_latency(); DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tMANUAL PUNCH: shift FRF by delta between WOL and CO to %1\n", first_recordable_frame)); } else { diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index a524db3d23..878da1e381 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -54,6 +54,7 @@ setup_enum_writer () OverlapType _OverlapType; AlignStyle _AlignStyle; + AlignChoice _AlignChoice; MeterPoint _MeterPoint; TrackMode _TrackMode; NoteMode _NoteMode; @@ -162,6 +163,11 @@ setup_enum_writer () REGISTER_ENUM (ExistingMaterial); REGISTER (_AlignStyle); + REGISTER_ENUM (UseCaptureTime); + REGISTER_ENUM (UseExistingMaterial); + REGISTER_ENUM (Automatic); + REGISTER (_AlignChoice); + REGISTER_ENUM (MeterInput); REGISTER_ENUM (MeterPreFader); REGISTER_ENUM (MeterPostFader); diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 0a9b361f35..e2233fa418 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -171,13 +171,7 @@ MidiDiskstream::non_realtime_input_change () get_input_sources (); set_capture_offset (); - - if (first_input_change) { - set_align_style (_persistent_alignment_style); - first_input_change = false; - } else { - set_align_style_from_io (); - } + set_align_style_from_io (); input_change_pending.type = IOChange::NoChange; @@ -1110,7 +1104,7 @@ MidiDiskstream::transport_looped (framepos_t transport_frame) capture_captured += _capture_offset; if (_alignment_style == ExistingMaterial) { - capture_captured += _session.worst_output_latency(); + capture_captured += _session.worst_playback_latency(); } else { capture_captured += _roll_delay; } @@ -1389,6 +1383,10 @@ MidiDiskstream::set_align_style_from_io () { bool have_physical = false; + if (_alignment_choice != Automatic) { + return; + } + if (_io == 0) { return; } diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc index 9564770f7f..ee9bef0570 100644 --- a/libs/ardour/mtc_slave.cc +++ b/libs/ardour/mtc_slave.cc @@ -212,7 +212,7 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now) frames. Also compensate for audio latency. */ - mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency(); + mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_playback_latency(); if (now) { diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 759495351a..787de5993c 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -1106,7 +1106,7 @@ Session::audible_frame () const in the absence of any plugin latency compensation */ - offset = _worst_output_latency; + offset = worst_playback_latency (); if (offset > current_block_size) { offset -= current_block_size; diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index ae6d383092..df1abba5dd 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -379,7 +379,7 @@ Session::send_full_time_code (framepos_t const t) } // Compensate for audio latency - outbound_mtc_timecode_frame += _worst_output_latency; + outbound_mtc_timecode_frame += worst_playback_latency(); next_quarter_frame_to_send = 0; // Sync slave to the same Timecode time as we are on diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index dcbf25777a..f06e34849b 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -222,11 +222,11 @@ Session::realtime_stop (bool abort, bool clear_state) past that point to pick up delayed input (and/or to delick) */ - if (_worst_output_latency > current_block_size) { + if (worst_playback_latency() > current_block_size) { /* we rolled past the stop point to pick up data that had not yet arrived. move back to where the stop occured. */ - decrement_transport_position (current_block_size + (_worst_output_latency - current_block_size)); + decrement_transport_position (current_block_size + (worst_playback_latency() - current_block_size)); } else { decrement_transport_position (current_block_size); } @@ -1041,7 +1041,7 @@ Session::stop_transport (bool abort, bool clear_state) return; } - if (actively_recording() && !(transport_sub_state & StopPendingCapture) && _worst_output_latency > current_block_size) { + if (actively_recording() && !(transport_sub_state & StopPendingCapture) && worst_playback_latency() > current_block_size) { boost::shared_ptr rl = routes.reader(); for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { @@ -1060,8 +1060,8 @@ Session::stop_transport (bool abort, bool clear_state) */ SessionEvent *ev = new SessionEvent (SessionEvent::StopOnce, SessionEvent::Replace, - _transport_frame + _worst_output_latency - current_block_size, - 0, 0, abort); + _transport_frame + _worst_input_latency - current_block_size, + 0, 0, abort); merge_event (ev); transport_sub_state |= StopPendingCapture; diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index be992eaa61..d51344eb0d 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -563,6 +563,12 @@ Track::alignment_style () const return _diskstream->alignment_style (); } +AlignChoice +Track::alignment_choice () const +{ + return _diskstream->alignment_choice (); +} + framepos_t Track::current_capture_start () const { @@ -611,6 +617,12 @@ Track::set_align_style (AlignStyle s) _diskstream->set_align_style (s); } +void +Track::set_align_choice (AlignChoice s) +{ + _diskstream->set_align_choice (s); +} + uint32_t Track::write_data_count () const { -- cgit v1.2.3