X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fmtc_slave.cc;h=0f277a7f5550f1f99e6a14251278e8545b744d91;hb=3ac47220a0ddd24a89ff6603934ac3b7b7613fe2;hp=c41c6d6c94a50c40310870ded6e2032f6be3edc8;hpb=ee1b49f87e4b8e6406c059f29371892872d3fb85;p=ardour.git diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc index c41c6d6c94..0f277a7f55 100644 --- a/libs/ardour/mtc_slave.cc +++ b/libs/ardour/mtc_slave.cc @@ -25,15 +25,16 @@ #include "pbd/error.h" #include "pbd/pthread_utils.h" -#include "midi++/port.h" +#include "ardour/audioengine.h" #include "ardour/debug.h" -#include "ardour/slave.h" +#include "ardour/midi_buffer.h" +#include "ardour/midi_port.h" #include "ardour/session.h" -#include "ardour/audioengine.h" +#include "ardour/slave.h" #include -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; @@ -48,10 +49,11 @@ using namespace Timecode; recently received position (and without the direction of timecode reversing too), we will stop+locate+wait+chase. */ -const int MTC_Slave::frame_tolerance = 2; +const int MTC_Slave::sample_tolerance = 2; -MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p) +MTC_Slave::MTC_Slave (Session& s, MidiPort& p) : session (s) + , port (&p) { can_notify_on_unknown_rate = true; did_reset_tc_format = false; @@ -63,7 +65,7 @@ MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p) busy_guard1 = busy_guard2 = 0; last_mtc_fps_byte = session.get_mtc_timecode_bits (); - quarter_frame_duration = (double(session.frames_per_timecode_frame()) / 4.0); + quarter_frame_duration = (double(session.samples_per_timecode_frame()) / 4.0); mtc_timecode = session.config.get_timecode_format(); a3e_timecode = session.config.get_timecode_format(); @@ -72,7 +74,10 @@ MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p) session.config.ParameterChanged.connect_same_thread (config_connection, boost::bind (&MTC_Slave::parameter_changed, this, _1)); parse_timecode_offset(); reset (true); - rebind (p); + + port->self_parser().mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3)); + port->self_parser().mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3)); + port->self_parser().mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1)); } MTC_Slave::~MTC_Slave() @@ -96,15 +101,12 @@ MTC_Slave::~MTC_Slave() } void -MTC_Slave::rebind (MIDI::Port& p) +MTC_Slave::rebind (MidiPort& p) { port_connections.drop_connections (); port = &p; - port->parser()->mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3)); - port->parser()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3)); - port->parser()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1)); } void @@ -134,20 +136,20 @@ MTC_Slave::give_slave_full_control_over_transport_speed() const // return false; // for Session-level computed varispeed } -ARDOUR::framecnt_t +ARDOUR::samplecnt_t MTC_Slave::resolution () const { - return (framecnt_t) quarter_frame_duration * 4.0; + return (samplecnt_t) quarter_frame_duration * 4.0; } -ARDOUR::framecnt_t +ARDOUR::samplecnt_t MTC_Slave::seekahead_distance () const { return quarter_frame_duration * 8 * transport_direction; } bool -MTC_Slave::outside_window (framepos_t pos) const +MTC_Slave::outside_window (samplepos_t pos) const { return ((pos < window_begin) || (pos > window_end)); } @@ -156,7 +158,8 @@ MTC_Slave::outside_window (framepos_t pos) const bool MTC_Slave::locked () const { - return port->parser()->mtc_locked() && last_inbound_frame !=0 && engine_dll_initstate !=0; + DEBUG_TRACE (DEBUG::MTC, string_compose ("locked ? %1 last %2 initstate %3\n", port->self_parser().mtc_locked(), last_inbound_frame, engine_dll_initstate)); + return port->self_parser().mtc_locked() && last_inbound_frame !=0 && engine_dll_initstate !=0; } bool @@ -210,6 +213,7 @@ MTC_Slave::reset (bool with_position) window_end = 0; transport_direction = 1; current_delta = 0; + ActiveChanged(false); } void @@ -245,9 +249,9 @@ MTC_Slave::read_current (SafeTime *st) const } void -MTC_Slave::init_mtc_dll(framepos_t tme, double qtr) +MTC_Slave::init_mtc_dll(samplepos_t tme, double qtr) { - omega = 2.0 * M_PI * qtr / 2.0 / double(session.frame_rate()); + omega = 2.0 * M_PI * qtr / 2.0 / double(session.sample_rate()); b = 1.4142135623730950488 * omega; c = omega * omega; @@ -257,10 +261,9 @@ MTC_Slave::init_mtc_dll(framepos_t tme, double qtr) DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2)); } - /* called from MIDI parser */ void -MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, framepos_t now) +MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, samplepos_t now) { busy_guard1++; const double qtr_d = quarter_frame_duration; @@ -268,7 +271,7 @@ MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, framepos_t now) mtc_frame_dll += qtr_d * (double) transport_direction; mtc_frame = rint(mtc_frame_dll); - DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame)); + DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample %1 at %2 -> mtc_frame: %3\n", which_qtr, now, mtc_frame)); double mtc_speed = 0; if (first_mtc_timestamp != 0) { @@ -279,7 +282,7 @@ MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, framepos_t now) e2 += c * e; mtc_speed = (t1 - t0) / qtr_d; - DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, mtc_speed, e2 - qtr_d)); + DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr sample DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, mtc_speed, e2 - qtr_d)); current.guard1++; current.position = mtc_frame; @@ -299,7 +302,7 @@ MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, framepos_t now) * when a full TC has been received * OR on locate */ void -MTC_Slave::update_mtc_time (const MIDI::byte *msg, bool was_full, framepos_t now) +MTC_Slave::update_mtc_time (const MIDI::byte *msg, bool was_full, samplepos_t now) { busy_guard1++; @@ -307,8 +310,7 @@ MTC_Slave::update_mtc_time (const MIDI::byte *msg, bool was_full, framepos_t now to use a timestamp indicating when this MTC time was received. example: when we received a locate command via MMC. */ - - //DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name())); + DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", pthread_name())); TimecodeFormat tc_format; bool reset_tc = true; @@ -412,10 +414,10 @@ MTC_Slave::update_mtc_time (const MIDI::byte *msg, bool was_full, framepos_t now consideration. */ - quarter_frame_duration = (double(session.frame_rate()) / (double) timecode.rate / 4.0); + quarter_frame_duration = (double(session.sample_rate()) / (double) timecode.rate / 4.0); Timecode::timecode_to_sample (timecode, mtc_frame, true, false, - double(session.frame_rate()), + double(session.sample_rate()), session.config.get_subframes_per_frame(), timecode_negative_offset, timecode_offset ); @@ -424,31 +426,32 @@ MTC_Slave::update_mtc_time (const MIDI::byte *msg, bool was_full, framepos_t now now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch)); if (was_full || outside_window (mtc_frame)) { - DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC or outside window. - TID:%1\n", pthread_name())); - session.request_locate (mtc_frame, false); + DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC %1 or outside window %2 MTC %3\n", was_full, outside_window (mtc_frame), mtc_frame)); + session.set_requested_return_sample (-1); session.request_transport_speed (0); + session.request_locate (mtc_frame, false); update_mtc_status (MIDI::MTC_Stopped); reset (false); reset_window (mtc_frame); } else { - /* we've had the first set of 8 qtr frame messages, determine position - and allow continuing qtr frame messages to provide position + /* we've had the first set of 8 qtr sample messages, determine position + and allow continuing qtr sample messages to provide position and speed information. */ /* We received the last quarter frame 7 quarter frames (1.75 mtc - frames) after the instance when the contents of the mtc quarter - frames were decided. Add time to compensate for the elapsed 1.75 - frames. + samples) after the instance when the contents of the mtc quarter + samples were decided. Add time to compensate for the elapsed 1.75 + samples. */ double qtr = quarter_frame_duration; long int mtc_off = (long) rint(7.0 * qtr); DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n", - mtc_frame, (4.0*qtr), session.frames_per_timecode_frame())); + mtc_frame, (4.0*qtr), session.samples_per_timecode_frame())); - switch (port->parser()->mtc_running()) { + switch (port->self_parser().mtc_running()) { case MTC_Backward: mtc_frame -= mtc_off; qtr *= -1.0; @@ -467,6 +470,7 @@ MTC_Slave::update_mtc_time (const MIDI::byte *msg, bool was_full, framepos_t now first_mtc_timestamp = now; init_mtc_dll(mtc_frame, qtr); mtc_frame_dll = mtc_frame; + ActiveChanged (true); // emit signal } current.guard1++; current.position = mtc_frame; @@ -488,7 +492,7 @@ MTC_Slave::update_mtc_status (MIDI::MTC_Status status) /* XXX !!! thread safety ... called from MIDI I/O context * on locate (via ::update_mtc_time()) */ - DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_Slave::update_mtc_status - TID:%1\n", pthread_name())); + DEBUG_TRACE (DEBUG::MTC, string_compose("MTC_Slave::update_mtc_status - TID:%1 MTC:%2\n", pthread_name(), mtc_frame)); return; // why was this fn needed anyway ? it just messes up things -> use reset. busy_guard1++; @@ -522,15 +526,16 @@ MTC_Slave::update_mtc_status (MIDI::MTC_Status status) } void -MTC_Slave::reset_window (framepos_t root) +MTC_Slave::reset_window (samplepos_t root) { /* if we're waiting for the master to catch us after seeking ahead, keep the window - of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames + of acceptable MTC samples wide open. otherwise, shrink it down to just 2 video frames ahead of the window root (taking direction into account). */ - framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance); - switch (port->parser()->mtc_running()) { + samplecnt_t const d = (quarter_frame_duration * 4 * sample_tolerance); + + switch (port->self_parser().mtc_running()) { case MTC_Forward: window_begin = root; transport_direction = 1; @@ -553,11 +558,11 @@ MTC_Slave::reset_window (framepos_t root) break; } - DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end)); + DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root)); } void -MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc) +MTC_Slave::init_engine_dll (samplepos_t pos, samplepos_t inc) { /* the bandwidth of the DLL is a trade-off, * because the max-speed of the transport in ardour is @@ -566,7 +571,7 @@ MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc) * But this is only really a problem if the user performs manual * seeks while transport is running and slaved to MTC. */ - oe = 2.0 * M_PI * double(inc) / 2.0 / double(session.frame_rate()); + oe = 2.0 * M_PI * double(inc) / 2.0 / double(session.sample_rate()); be = 1.4142135623730950488 * oe; ce = oe * oe; @@ -577,44 +582,56 @@ MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc) } /* main entry point from session_process.cc - * in jack_process callback context */ +xo * in process callback context */ bool -MTC_Slave::speed_and_position (double& speed, framepos_t& pos) +MTC_Slave::speed_and_position (double& speed, samplepos_t& pos) { - framepos_t now = session.engine().frame_time_at_cycle_start(); - framepos_t sess_pos = session.transport_frame(); // corresponds to now - //sess_pos -= session.engine().frames_since_cycle_start(); + samplepos_t now = session.engine().sample_time_at_cycle_start(); + samplepos_t sess_pos = session.transport_sample(); // corresponds to now + //sess_pos -= session.engine().samples_since_cycle_start(); SafeTime last; - frameoffset_t elapsed; + sampleoffset_t elapsed; bool engine_dll_reinitialized = false; read_current (&last); + DEBUG_TRACE (DEBUG::MTC, string_compose ("speed&pos: timestamp %1 speed %2 initstate %3 dir %4 tpos %5 now %6 last-in %7\n", + last.timestamp, + last.speed, + engine_dll_initstate, + transport_direction, + sess_pos, + now, + last_inbound_frame)); + /* re-init engine DLL here when state changed (direction, first_mtc_timestamp) */ - if (last.timestamp == 0) { engine_dll_initstate = 0; } - else if (engine_dll_initstate != transport_direction && last.speed != 0) { + if (last.timestamp == 0) { + engine_dll_initstate = 0; + } else if (engine_dll_initstate != transport_direction && last.speed != 0) { engine_dll_initstate = transport_direction; - init_engine_dll(last.position, session.engine().frames_per_cycle()); + init_engine_dll(last.position, session.engine().samples_per_cycle()); engine_dll_reinitialized = true; } if (last.timestamp == 0) { speed = 0; - pos = session.transport_frame() ; // last.position; + pos = session.transport_sample() ; // last.position; DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", pos)); return true; } - /* no timecode for two frames - conclude that it's stopped */ + /* no timecode for two samples - conclude that it's stopped */ if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > labs(seekahead_distance())) { speed = 0; pos = last.position; + session.set_requested_return_sample (-1); session.request_locate (pos, false); session.request_transport_speed (0); engine_dll_initstate = 0; queue_reset (false); - DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 2 frames - reset pending\n"); + ActiveChanged (false); + DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC not seen for 2 samples - reset pending, pos = %1\n", pos)); return false; } @@ -627,13 +644,11 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos) /* interpolate position according to speed and time since last quarter-frame*/ if (speed_flt == 0.0f) { elapsed = 0; - } - else - { + } else { /* scale elapsed time by the current MTC speed */ - elapsed = (framecnt_t) rint (speed_flt * (now - last.timestamp)); + elapsed = (samplecnt_t) rint (speed_flt * (now - last.timestamp)); if (give_slave_full_control_over_transport_speed() && !engine_dll_reinitialized) { - /* there is an engine vs MTC position frame-delta. + /* there is an engine vs MTC position sample-delta. * This mostly due to quantization and rounding of (speed * nframes) * but can also due to the session-process not calling * speed_and_position() every cycle under some circumstances. @@ -645,8 +660,8 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos) te0 = te1; te1 += be * e + ee2; ee2 += ce * e; - speed_flt = (te1 - te0) / double(session.engine().frames_per_cycle()); - DEBUG_TRACE (DEBUG::MTC, string_compose ("engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", te0, te1, e, speed_flt, ee2 - session.engine().frames_per_cycle() )); + speed_flt = (te1 - te0) / double(session.engine().samples_per_cycle()); + DEBUG_TRACE (DEBUG::MTC, string_compose ("engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", te0, te1, e, speed_flt, ee2 - session.engine().samples_per_cycle() )); } } @@ -659,14 +674,13 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos) */ if (!session.actively_recording() && speed != 0 - && ( (pos < 0) || (labs(pos - sess_pos) > 3 * session.frame_rate()) ) - ) { + && ((pos < 0) || (labs(pos - sess_pos) > 3 * session.sample_rate()))) { engine_dll_initstate = 0; queue_reset (false); } /* provide a .1% deadzone to lock the speed */ - if (fabs(speed - 1.0) <= 0.001) + if (fabs (speed - 1.0) <= 0.001) speed = 1.0; DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n", @@ -693,7 +707,7 @@ MTC_Slave::approximate_current_position() const } return Timecode::timecode_format_sampletime( last.position, - double(session.frame_rate()), + double(session.sample_rate()), Timecode::timecode_to_frames_per_second(mtc_timecode), Timecode::timecode_has_drop_frames(mtc_timecode)); }