diff --git a/libs/appleutility/wscript b/libs/appleutility/wscript index 27dc1b9d26..87b713a0dc 100644 --- a/libs/appleutility/wscript +++ b/libs/appleutility/wscript @@ -28,7 +28,7 @@ def configure(conf): def build(bld): obj = bld.new_task_gen('cxx', 'shlib', - uselib = 'COREAUDIO CORESERVICES COREFOUNDATION AUDIOTOOLBOX AUDIOUNITS OSX GTKOSX') + uselib = 'COREAUDIO CORESERVICES COREFOUNDATION AUDIOTOOLBOX AUDIOUNITS OSX GTKOSX') obj.source = libappleutility_sources obj.export_incdirs = ['.'] obj.includes = ['.'] @@ -41,4 +41,4 @@ def shutdown(): autowaf.shutdown() def i18n(bld): - pass \ No newline at end of file + pass diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index a3505ec587..4f0acc9381 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -986,6 +986,13 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable PostTransportClearSubstate = 0x80000 }; + enum SlaveState { + Stopped, + Waiting, + Running + }; + + SlaveState slave_state() const { return _slave_state; } protected: friend class AudioEngine; @@ -1088,20 +1095,13 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable int average_dir; bool have_first_delta_accumulator; - enum SlaveState { - Stopped, - Waiting, - Running - }; - - SlaveState slave_state; + SlaveState _slave_state; nframes_t slave_wait_end; void reset_slave_state (); bool follow_slave (nframes_t); void calculate_moving_average_of_slave_delta(int dir, nframes_t this_delta); - void track_slave_state(float slave_speed, nframes_t slave_transport_frame, - nframes_t this_delta, bool starting); + void track_slave_state(float slave_speed, nframes_t slave_transport_frame, nframes_t this_delta); void follow_slave_silently(nframes_t nframes, float slave_speed); void use_sync_source (SyncSource); diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h index 16e11097ea..dae0d80d10 100644 --- a/libs/ardour/ardour/slave.h +++ b/libs/ardour/ardour/slave.h @@ -29,6 +29,8 @@ #include "midi++/parser.h" #include "midi++/types.h" +class PIController; + namespace MIDI { class Port; } @@ -140,11 +142,18 @@ class Slave { virtual nframes_t resolution() const = 0; /** - * @return - when returning true, ARDOUR will wait for one second before transport + * @return - when returning true, ARDOUR will wait for seekahead_distance() before transport * starts rolling */ virtual bool requires_seekahead () const = 0; + /** + * @return the number of frames that this slave wants to seek ahead. Relevant + * only if @func requires_seekahead() returns true. + */ + + virtual nframes64_t seekahead_distance() const { return 0; } + /** * @return - when returning true, ARDOUR will use transport speed 1.0 no matter what * the slave returns @@ -222,35 +231,40 @@ class MTC_Slave : public Slave, public sigc::trackable { nframes_t resolution() const; bool requires_seekahead () const { return true; } + nframes64_t seekahead_distance() const; + bool give_slave_full_control_over_transport_speed() const; private: Session& session; MIDI::Port* port; std::vector connections; bool can_notify_on_unknown_rate; - + PIController* pic; + SafeTime current; - double instantaneous_speed; nframes_t mtc_frame; /* current time */ nframes_t last_inbound_frame; /* when we got it; audio clocked */ MIDI::byte last_mtc_fps_byte; - bool qtr_frame_messages_valid_for_time; - + nframes64_t window_begin; + nframes64_t window_end; + nframes64_t last_mtc_timestamp; + nframes64_t last_mtc_frame; bool did_reset_tc_format; TimecodeFormat saved_tc_format; - - static const int32_t accumulator_size = 128; - double accumulator[accumulator_size]; - int32_t accumulator_index; - bool have_first_accumulated_speed; + size_t speed_accumulator_size; + double* speed_accumulator; + size_t speed_accumulator_cnt; + bool have_first_speed_accumulator; + double average_speed; void reset (); void update_mtc_qtr (MIDI::Parser&, int, nframes_t); void update_mtc_time (const MIDI::byte *, bool, nframes_t); - void update_mtc_status (MIDI::Parser::MTC_Status); + void update_mtc_status (MIDI::MTC_Status); void read_current (SafeTime *) const; - double compute_apparent_speed (nframes64_t); - + void reset_window (nframes64_t); + bool outside_window (nframes64_t) const; + void process_apparent_speed (double); }; class MIDIClock_Slave : public Slave, public sigc::trackable { @@ -337,24 +351,6 @@ class MIDIClock_Slave : public Slave, public sigc::trackable { bool _starting; }; -class ADAT_Slave : public Slave -{ - public: - ADAT_Slave () {} - ~ADAT_Slave () {} - - bool speed_and_position (double& speed, nframes64_t& pos) { - speed = 0; - pos = 0; - return false; - } - - bool locked() const { return false; } - bool ok() const { return false; } - nframes_t resolution() const { return 1; } - bool requires_seekahead () const { return true; } -}; - class JACK_Slave : public Slave { public: diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 2e5aea9047..2f344eb8ba 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -136,9 +136,13 @@ _thread_init_callback (void * /*arg*/) */ PBD::notify_gui_about_thread_creation (pthread_self(), X_("Audioengine"), 4096); -#ifdef WITH_JACK_MIDI MIDI::JACK_MidiPort::set_process_thread (pthread_self()); -#endif // WITH_JACK_MIDI +} + +static void +ardour_jack_error (const char* msg) +{ + error << "JACK: " << msg << endmsg; } int @@ -188,6 +192,8 @@ AudioEngine::start () jack_set_timebase_callback (_priv_jack, 0, _jack_timebase_callback, this); } + jack_set_error_function (ardour_jack_error); + if (jack_activate (_priv_jack) == 0) { _running = true; _has_run = true; @@ -1121,12 +1127,6 @@ AudioEngine::remove_all_ports () ports.flush (); } -static void -ardour_jack_error (const char* msg) -{ - error << "JACK: " << msg << endmsg; -} - int AudioEngine::connect_to_jack (string client_name) { @@ -1148,8 +1148,6 @@ AudioEngine::connect_to_jack (string client_name) jack_client_name = jack_get_client_name (_priv_jack); } - jack_set_error_function (ardour_jack_error); - return 0; } diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 870c60eec7..4b82950f3e 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -18,6 +18,7 @@ */ #include "pbd/enumwriter.h" +#include "midi++/types.h" #include "ardour/audiofilesource.h" #include "ardour/audioregion.h" @@ -40,6 +41,7 @@ using namespace std; using namespace PBD; using namespace ARDOUR; +using namespace MIDI; void setup_enum_writer () @@ -115,7 +117,9 @@ setup_enum_writer () WaveformShape _WaveformShape; QuantizeType _QuantizeType; Session::PostTransportWork _Session_PostTransportWork; - + Session::SlaveState _Session_SlaveState; + MTC_Status _MIDI_MTC_Status; + #define REGISTER(e) enum_writer->register_distinct (typeid(e).name(), i, s); i.clear(); s.clear() #define REGISTER_BITS(e) enum_writer->register_bits (typeid(e).name(), i, s); i.clear(); s.clear() #define REGISTER_ENUM(e) i.push_back (e); s.push_back (#e) @@ -305,6 +309,16 @@ setup_enum_writer () REGISTER_CLASS_ENUM (Session::Event, AutoLoop); REGISTER (_Session_Event_Type); + REGISTER_CLASS_ENUM (Session, Stopped); + REGISTER_CLASS_ENUM (Session, Waiting); + REGISTER_CLASS_ENUM (Session, Running); + REGISTER (_Session_SlaveState); + + REGISTER_ENUM (MTC_Stopped); + REGISTER_ENUM (MTC_Forward); + REGISTER_ENUM (MTC_Backward); + REGISTER (_MIDI_MTC_Status); + REGISTER_CLASS_ENUM (Session, PostTransportStop); REGISTER_CLASS_ENUM (Session, PostTransportDisableRecord); REGISTER_CLASS_ENUM (Session, PostTransportPosition); diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc index 4ca86236b7..9e566367bc 100644 --- a/libs/ardour/mtc_slave.cc +++ b/libs/ardour/mtc_slave.cc @@ -22,6 +22,7 @@ #include #include #include "pbd/error.h" +#include "pbd/enumwriter.h" #include "pbd/failed_constructor.h" #include "pbd/pthread_utils.h" @@ -30,7 +31,7 @@ #include "ardour/slave.h" #include "ardour/session.h" #include "ardour/audioengine.h" -#include "ardour/cycles.h" +#include "ardour/pi_controller.h" #include "i18n.h" @@ -45,8 +46,14 @@ MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p) { can_notify_on_unknown_rate = true; did_reset_tc_format = false; + + pic = new PIController (1.0, 8); last_mtc_fps_byte = session.get_mtc_timecode_bits (); + mtc_frame = 0; + + speed_accumulator_size = 16; + speed_accumulator = new double[speed_accumulator_size]; rebind (p); reset (); @@ -57,6 +64,15 @@ MTC_Slave::~MTC_Slave() if (did_reset_tc_format) { session.config.set_timecode_format (saved_tc_format); } + delete pic; + delete [] speed_accumulator; +} + +bool +MTC_Slave::give_slave_full_control_over_transport_speed() const +{ + return true; // for PiC control */ + // return false; // for Session-level computed varispeed } void @@ -68,6 +84,8 @@ MTC_Slave::rebind (MIDI::Port& p) port = &p; + cerr << "Bind to port MTC messages\n"; + connections.push_back (port->input()->mtc_time.connect (mem_fun (*this, &MTC_Slave::update_mtc_time))); connections.push_back (port->input()->mtc_qtr.connect (mem_fun (*this, &MTC_Slave::update_mtc_qtr))); connections.push_back (port->input()->mtc_status.connect (mem_fun (*this, &MTC_Slave::update_mtc_status))); @@ -76,34 +94,8 @@ MTC_Slave::rebind (MIDI::Port& p) void MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now) { - DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2, valid-for-time? %3\n", which_qtr, now, qtr_frame_messages_valid_for_time)); - - if (qtr_frame_messages_valid_for_time) { - - if (which_qtr != 7) { - - /* leave position and speed updates for the last - qtr frame message of the 8 to be taken - care of in update_mtc_time(), invoked - by the Parser right after this. - */ - - nframes_t qtr; - - qtr = (long) (session.frames_per_timecode_frame() / 4); - mtc_frame += qtr; - - double speed = compute_apparent_speed (now); - - current.guard1++; - current.position = mtc_frame; - current.timestamp = now; - current.speed = speed; - current.guard2++; - } - - last_inbound_frame = now; - } + DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now)); + last_inbound_frame = now; } void @@ -116,7 +108,8 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now) Timecode::Time timecode; TimecodeFormat tc_format; bool reset_tc = true; - + nframes64_t window_root = -1; + DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full)); timecode.hours = msg[3]; @@ -175,24 +168,28 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now) DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n", now, timecode, mtc_frame, was_full)); - if (was_full) { + if (was_full || outside_window (mtc_frame)) { session.timecode_to_sample (timecode, mtc_frame, true, false); session.request_locate (mtc_frame, false); session.request_transport_speed (0); - update_mtc_status (MIDI::Parser::MTC_Stopped); - + update_mtc_status (MIDI::MTC_Stopped); + window_root = mtc_frame; + reset (); } else { - /* we've had the first set of 8 qtr frame messages, determine position - and allow continuing qtr frame messages to provide position - and speed information. + and allow continuing qtr frame messages to provide position + and speed information. */ - qtr_frame_messages_valid_for_time = true; + /* do a careful conversion of the timecode value to a position + so that we take drop/nondrop and all that nonsense into + consideration. + */ + session.timecode_to_sample (timecode, mtc_frame, true, false); /* We received the last quarter frame 7 quarter frames (1.75 mtc @@ -203,56 +200,84 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now) mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency(); + if (now) { - double speed = compute_apparent_speed (now); - + + if (last_mtc_timestamp == 0) { + + last_mtc_timestamp = now; + last_mtc_frame = mtc_frame; + + } else { + + if (give_slave_full_control_over_transport_speed()) { + /* PIC + * + * its not the average, but we will assign it to current.speed below + */ + + average_speed = pic->get_ratio (session.audible_frame() - mtc_frame); + + } else { + + /* Non-PiC + */ + + nframes64_t time_delta = (now - last_mtc_timestamp); + + if (time_delta != 0) { + double apparent_speed = (mtc_frame - last_mtc_frame) / (double) (time_delta); + + process_apparent_speed (apparent_speed); + DEBUG_TRACE (DEBUG::Slave, string_compose ("apparent speed was %1 average is now %2\n", apparent_speed, average_speed)); + } else { + DEBUG_TRACE (DEBUG::Slave, string_compose ("no apparent calc, average is %1\n", average_speed)); + } + + /* every second, recalibrate the starting point for the speed measurement */ + if (mtc_frame - last_mtc_frame > session.frame_rate()) { + last_mtc_timestamp = now; + last_mtc_frame = mtc_frame; + } + } + } + current.guard1++; current.position = mtc_frame; current.timestamp = now; - current.speed = speed; + current.speed = average_speed; current.guard2++; + window_root = mtc_frame; } } if (now) { last_inbound_frame = now; } + + if (window_root >= 0) { + reset_window (window_root); + } } -double -MTC_Slave::compute_apparent_speed (nframes64_t now) +void +MTC_Slave::process_apparent_speed (double this_speed) { - if (current.timestamp != 0) { - - double speed = (double) ((mtc_frame - current.position) / (double) (now - current.timestamp)); - DEBUG_TRACE (DEBUG::MTC, string_compose ("instantaneous speed = %1 from %2 / %3\n", - speed, mtc_frame - current.position, now - current.timestamp)); - - /* crude low pass filter/smoother for speed */ + DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator)); - accumulator[accumulator_index++] = speed; - - if (accumulator_index >= accumulator_size) { - have_first_accumulated_speed = true; - accumulator_index = 0; + if (speed_accumulator_cnt >= speed_accumulator_size) { + have_first_speed_accumulator = true; + speed_accumulator_cnt = 0; + } + + speed_accumulator[speed_accumulator_cnt++] = this_speed; + + if (have_first_speed_accumulator) { + average_speed = 0.0; + for (size_t i = 0; i < speed_accumulator_size; ++i) { + average_speed += speed_accumulator[i]; } - - if (have_first_accumulated_speed) { - double total = 0; - - for (int32_t i = 0; i < accumulator_size; ++i) { - total += accumulator[i]; - } - - speed = total / accumulator_size; - DEBUG_TRACE (DEBUG::MTC, string_compose ("speed smoothed to %1\n", speed)); - } - - return speed; - - } else { - - return 0; + average_speed /= speed_accumulator_size; } } @@ -271,16 +296,16 @@ MTC_Slave::handle_locate (const MIDI::byte* mmc_tc) } void -MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status) +MTC_Slave::update_mtc_status (MIDI::MTC_Status status) { /* XXX !!! thread safety ... called from MIDI I/O context and process() context (via ::speed_and_position()) */ + + DEBUG_TRACE (DEBUG::MTC, string_compose ("new MTC status %1\n", enum_2_string (status))); switch (status) { case MTC_Stopped: - mtc_frame = 0; - current.guard1++; current.position = mtc_frame; current.timestamp = 0; @@ -290,27 +315,22 @@ MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status) break; case MTC_Forward: - mtc_frame = 0; - current.guard1++; current.position = mtc_frame; current.timestamp = 0; current.speed = 0; current.guard2++; - break; case MTC_Backward: - mtc_frame = 0; - current.guard1++; current.position = mtc_frame; current.timestamp = 0; current.speed = 0; current.guard2++; - break; } + } void @@ -365,7 +385,7 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos) pos = last.position; session.request_locate (pos, false); session.request_transport_speed (0); - update_mtc_status (MIDI::Parser::MTC_Stopped); + update_mtc_status (MIDI::MTC_Stopped); reset(); DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n"); return false; @@ -384,7 +404,7 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos) if (last.timestamp && (now > last.timestamp)) { elapsed = (nframes_t) floor (last.speed * (now - last.timestamp)); DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n", - last.timestamp, now, elapsed, speed)); + last.timestamp, now, elapsed, last.speed)); } else { elapsed = 0; /* XXX is this right? */ } @@ -422,7 +442,42 @@ MTC_Slave::reset () current.timestamp = 0; current.speed = 0; current.guard2++; - accumulator_index = 0; - have_first_accumulated_speed = false; - qtr_frame_messages_valid_for_time = false; + + window_begin = 0; + window_end = 0; + last_mtc_frame = 0; + last_mtc_timestamp = 0; + + average_speed = 0; + have_first_speed_accumulator = false; + speed_accumulator_cnt = 0; + + pic->out_of_bounds(); +} + +void +MTC_Slave::reset_window (nframes64_t root) +{ + window_begin = root; + + if (session.slave_state() == Session::Running) { + window_end = root + (session.frames_per_timecode_frame() * 2); + } else { + window_end = root + seekahead_distance (); + } + + DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end)); +} + +nframes64_t +MTC_Slave::seekahead_distance () const +{ + /* 1 second */ + return session.frame_rate(); +} + +bool +MTC_Slave::outside_window (nframes64_t pos) const +{ + return ((pos < window_begin) || (pos > window_end)); } diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index d205cc1ca8..b05cfc83a2 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -1261,7 +1261,7 @@ Session::midi_thread_work () } if (pfd[p].revents & POLLIN) { - DEBUG_TRACE (DEBUG::MidiIO, string_compose ("MIDI fd # %1 has data ready\n", p)); + DEBUG_TRACE (DEBUG::MidiIO, string_compose ("MIDI fd # %1 has data ready @ %2\n", p, now)); fds_ready++; ports[p]->parse (now); } diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index e270a7c3ec..4142490af6 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -461,7 +461,7 @@ Session::reset_slave_state () average_slave_delta = 1800; delta_accumulator_cnt = 0; have_first_delta_accumulator = false; - slave_state = Stopped; + _slave_state = Stopped; } bool @@ -483,7 +483,6 @@ Session::follow_slave (nframes_t nframes) nframes64_t slave_transport_frame; nframes_t this_delta; int dir; - bool starting; if (!_slave->ok()) { stop_transport (); @@ -493,7 +492,7 @@ Session::follow_slave (nframes_t nframes) _slave->speed_and_position (slave_speed, slave_transport_frame); - DEBUG_TRACE (DEBUG::Slave, string_compose ("Slave @ %2 speed %1\n", slave_speed, slave_transport_frame)); + DEBUG_TRACE (DEBUG::Slave, string_compose ("Slave position %1 speed %2\n", slave_transport_frame, slave_speed)); if (!_slave->locked()) { DEBUG_TRACE (DEBUG::Slave, "slave not locked\n"); @@ -508,7 +507,7 @@ Session::follow_slave (nframes_t nframes) dir = -1; } - if ((starting = _slave->starting())) { + if (_slave->starting()) { slave_speed = 0.0f; } @@ -524,21 +523,23 @@ Session::follow_slave (nframes_t nframes) } else { - /* TC source is able to drift relative to us (slave) - so we need to keep track of the drift and adjust - our speed to remain locked. + /* if we are chasing and the average delta between us and the + master gets too big, we want to switch to silent + motion. so keep track of that here. */ - calculate_moving_average_of_slave_delta(dir, this_delta); + if (_slave_state == Running) { + calculate_moving_average_of_slave_delta(dir, this_delta); + } } - track_slave_state (slave_speed, slave_transport_frame, this_delta, starting); + track_slave_state (slave_speed, slave_transport_frame, this_delta); - DEBUG_TRACE (DEBUG::Slave, string_compose ("slave state %1 @ %2 speed %3 cur delta %4 starting %5\n", - slave_state, slave_transport_frame, slave_speed, this_delta, starting)); + DEBUG_TRACE (DEBUG::Slave, string_compose ("slave state %1 @ %2 speed %3 cur delta %4 avg delta %5\n", + _slave_state, slave_transport_frame, slave_speed, this_delta, average_slave_delta)); - if (slave_state == Running && !_slave->is_always_synced() && !config.get_timecode_source_is_synced()) { + if (_slave_state == Running && !_slave->is_always_synced() && !config.get_timecode_source_is_synced()) { if (_transport_speed != 0.0f) { @@ -548,7 +549,6 @@ Session::follow_slave (nframes_t nframes) float delta; -#ifdef USE_MOVING_AVERAGE_OF_SLAVE if (average_slave_delta == 0) { delta = this_delta; delta *= dir; @@ -556,52 +556,38 @@ Session::follow_slave (nframes_t nframes) delta = average_slave_delta; delta *= average_dir; } -#else - delta = this_delta; - delta *= dir; -#endif #ifndef NDEBUG - if (slave_speed != 0.0) { - DEBUG_TRACE (DEBUG::Slave, string_compose ("delta = %1 speed = %2 ts = %3 M@%4 S@%5 avgdelta %6\n", - (int) (dir * this_delta), - slave_speed, - _transport_speed, - _transport_frame, - slave_transport_frame, - _transport_frame, - average_slave_delta)); - } + if (slave_speed != 0.0) { + DEBUG_TRACE (DEBUG::Slave, string_compose ("delta = %1 speed = %2 ts = %3 M@%4 S@%5 avgdelta %6\n", + (int) (dir * this_delta), + slave_speed, + _transport_speed, + _transport_frame, + slave_transport_frame, + average_slave_delta)); + } #endif - if (fabs(delta) > 2048) { - nframes64_t jump_to = slave_transport_frame + lrintf (_current_frame_rate/5.0f); - /* too far off, so locate and keep rolling */ - DEBUG_TRACE (DEBUG::Slave, string_compose ("slave delta %1 is too big, locate to %2\n", - delta, jump_to)); - request_locate (jump_to, true); - return false; + + if (_slave->give_slave_full_control_over_transport_speed()) { + set_transport_speed (slave_speed, false, false); } else { float adjusted_speed = slave_speed + (delta / float(_current_frame_rate)); - - if (_slave->give_slave_full_control_over_transport_speed()) { - request_transport_speed (slave_speed); - } else { - request_transport_speed (adjusted_speed); - DEBUG_TRACE (DEBUG::Slave, string_compose ("adjust using %1 towards %2 ratio %3 current %4 slave @ %5\n", - delta, adjusted_speed, adjusted_speed/slave_speed, _transport_speed, - slave_speed)); - } + request_transport_speed (adjusted_speed); + DEBUG_TRACE (DEBUG::Slave, string_compose ("adjust using %1 towards %2 ratio %3 current %4 slave @ %5\n", + delta, adjusted_speed, adjusted_speed/slave_speed, _transport_speed, + slave_speed)); } - if (abs(average_slave_delta) > (long) _slave->resolution()) { - cerr << "average slave delta greater than slave resolution, going to silent motion\n"; + if (abs(average_slave_delta) > _slave->resolution()) { + cerr << "average slave delta greater than slave resolution (" << _slave->resolution() << "), going to silent motion\n"; goto silent_motion; } } } - if (!starting && !non_realtime_work_pending()) { + if (_slave_state == Running && !non_realtime_work_pending()) { /* speed is set, we're locked, and good to go */ return true; } @@ -645,24 +631,24 @@ Session::calculate_moving_average_of_slave_delta(int dir, nframes_t this_delta) } void -Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame, nframes_t this_delta, bool starting) +Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame, nframes_t this_delta) { if (slave_speed != 0.0f) { /* slave is running */ - switch (slave_state) { + switch (_slave_state) { case Stopped: if (_slave->requires_seekahead()) { - slave_wait_end = slave_transport_frame + _current_frame_rate; + slave_wait_end = slave_transport_frame + _slave->seekahead_distance (); DEBUG_TRACE (DEBUG::Slave, string_compose ("slave stopped, but running, requires seekahead to %1\n", slave_wait_end)); + /* we can call locate() here because we are in process context */ locate (slave_wait_end, false, false); - slave_state = Waiting; - starting = true; + _slave_state = Waiting; } else { - slave_state = Running; + _slave_state = Running; Location* al = _locations.auto_loop_location(); @@ -678,13 +664,24 @@ Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame, break; case Waiting: + default: + break; + } + + if (_slave_state == Waiting) { + DEBUG_TRACE (DEBUG::Slave, string_compose ("slave waiting at %1\n", slave_transport_frame)); if (slave_transport_frame >= slave_wait_end) { DEBUG_TRACE (DEBUG::Slave, string_compose ("slave start at %1 vs %2\n", slave_transport_frame, _transport_frame)); - slave_state = Running; + _slave_state = Running; + + /* now perform a "micro-seek" within the disk buffers to realign ourselves + precisely with the master. + */ + bool ok = true; nframes_t frame_delta = slave_transport_frame - _transport_frame; @@ -713,13 +710,9 @@ Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame, average_slave_delta = 0L; this_delta = 0; } - break; - - default: - break; } - if (slave_state == Running && _transport_speed == 0.0f) { + if (_slave_state == Running && _transport_speed == 0.0f) { DEBUG_TRACE (DEBUG::Slave, "slave starts transport\n"); start_transport (); } @@ -738,7 +731,7 @@ Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame, force_locate (slave_transport_frame, false); } - slave_state = Stopped; + _slave_state = Stopped; } } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 86a317d1d1..bcc3afbb05 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -263,7 +263,7 @@ Session::first_stage_init (string fullpath, string snapshot_name) average_slave_delta = 1800; // !!! why 1800 ???? have_first_delta_accumulator = false; delta_accumulator_cnt = 0; - slave_state = Stopped; + _slave_state = Stopped; _engine.GraphReordered.connect (mem_fun (*this, &Session::graph_reordered)); diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 48cd6ccb6f..bf850ebeab 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -132,6 +132,7 @@ libardour_sources = [ 'onset_detector.cc', 'panner.cc', 'pcm_utils.cc', + 'pi_controller.cc', 'playlist.cc', 'playlist_factory.cc', 'plugin.cc', diff --git a/libs/midi++2/midi++/parser.h b/libs/midi++2/midi++/parser.h index b8364cc025..365f2fb46a 100644 --- a/libs/midi++2/midi++/parser.h +++ b/libs/midi++2/midi++/parser.h @@ -116,12 +116,6 @@ class Parser : public sigc::trackable { /* MTC */ - enum MTC_Status { - MTC_Stopped = 0, - MTC_Forward, - MTC_Backward - }; - MTC_FPS mtc_fps() const { return _mtc_fps; } MTC_Status mtc_running() const { return _mtc_running; } const byte *mtc_current() const { return _mtc_time; } diff --git a/libs/midi++2/mtc.cc b/libs/midi++2/mtc.cc index 74b528e5e3..a49f469d2b 100644 --- a/libs/midi++2/mtc.cc +++ b/libs/midi++2/mtc.cc @@ -226,7 +226,7 @@ Parser::process_mtc_quarter_frame (byte *msg) /* time code is looking good */ #ifdef DEBUG_MTC - cerr << "for quarter frame " << which_quarter_frame << " byte = " << hex << (int) msg[1] << dec << endl; + // cerr << "for quarter frame " << which_quarter_frame << " byte = " << hex << (int) msg[1] << dec << endl; #endif switch (which_quarter_frame) { @@ -276,6 +276,10 @@ Parser::process_mtc_quarter_frame (byte *msg) } +#ifdef DEBUG_MTC + cerr << "Emit MTC Qtr\n"; +#endif + mtc_qtr (*this, which_quarter_frame, _timestamp); /* EMIT_SIGNAL */ // mtc (*this, &msg[1], msglen - 1);