13
0

more MTC stuff, including toggleable use of torben's PI controller

git-svn-id: svn://localhost/ardour2/branches/3.0@6265 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-12-02 21:26:26 +00:00
parent c17b4a30a5
commit 9dddffcc8f
12 changed files with 261 additions and 206 deletions

View File

@ -986,6 +986,13 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
PostTransportClearSubstate = 0x80000 PostTransportClearSubstate = 0x80000
}; };
enum SlaveState {
Stopped,
Waiting,
Running
};
SlaveState slave_state() const { return _slave_state; }
protected: protected:
friend class AudioEngine; friend class AudioEngine;
@ -1088,20 +1095,13 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
int average_dir; int average_dir;
bool have_first_delta_accumulator; bool have_first_delta_accumulator;
enum SlaveState { SlaveState _slave_state;
Stopped,
Waiting,
Running
};
SlaveState slave_state;
nframes_t slave_wait_end; nframes_t slave_wait_end;
void reset_slave_state (); void reset_slave_state ();
bool follow_slave (nframes_t); bool follow_slave (nframes_t);
void calculate_moving_average_of_slave_delta(int dir, nframes_t this_delta); 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, void track_slave_state(float slave_speed, nframes_t slave_transport_frame, nframes_t this_delta);
nframes_t this_delta, bool starting);
void follow_slave_silently(nframes_t nframes, float slave_speed); void follow_slave_silently(nframes_t nframes, float slave_speed);
void use_sync_source (SyncSource); void use_sync_source (SyncSource);

View File

@ -29,6 +29,8 @@
#include "midi++/parser.h" #include "midi++/parser.h"
#include "midi++/types.h" #include "midi++/types.h"
class PIController;
namespace MIDI { namespace MIDI {
class Port; class Port;
} }
@ -140,11 +142,18 @@ class Slave {
virtual nframes_t resolution() const = 0; 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 * starts rolling
*/ */
virtual bool requires_seekahead () const = 0; 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 * @return - when returning true, ARDOUR will use transport speed 1.0 no matter what
* the slave returns * the slave returns
@ -222,35 +231,40 @@ class MTC_Slave : public Slave, public sigc::trackable {
nframes_t resolution() const; nframes_t resolution() const;
bool requires_seekahead () const { return true; } bool requires_seekahead () const { return true; }
nframes64_t seekahead_distance() const;
bool give_slave_full_control_over_transport_speed() const;
private: private:
Session& session; Session& session;
MIDI::Port* port; MIDI::Port* port;
std::vector<sigc::connection> connections; std::vector<sigc::connection> connections;
bool can_notify_on_unknown_rate; bool can_notify_on_unknown_rate;
PIController* pic;
SafeTime current; SafeTime current;
double instantaneous_speed;
nframes_t mtc_frame; /* current time */ nframes_t mtc_frame; /* current time */
nframes_t last_inbound_frame; /* when we got it; audio clocked */ nframes_t last_inbound_frame; /* when we got it; audio clocked */
MIDI::byte last_mtc_fps_byte; 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; bool did_reset_tc_format;
TimecodeFormat saved_tc_format; TimecodeFormat saved_tc_format;
size_t speed_accumulator_size;
static const int32_t accumulator_size = 128; double* speed_accumulator;
double accumulator[accumulator_size]; size_t speed_accumulator_cnt;
int32_t accumulator_index; bool have_first_speed_accumulator;
bool have_first_accumulated_speed; double average_speed;
void reset (); void reset ();
void update_mtc_qtr (MIDI::Parser&, int, nframes_t); void update_mtc_qtr (MIDI::Parser&, int, nframes_t);
void update_mtc_time (const MIDI::byte *, bool, 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; 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 { class MIDIClock_Slave : public Slave, public sigc::trackable {
@ -337,24 +351,6 @@ class MIDIClock_Slave : public Slave, public sigc::trackable {
bool _starting; 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 class JACK_Slave : public Slave
{ {
public: public:

View File

@ -136,9 +136,13 @@ _thread_init_callback (void * /*arg*/)
*/ */
PBD::notify_gui_about_thread_creation (pthread_self(), X_("Audioengine"), 4096); PBD::notify_gui_about_thread_creation (pthread_self(), X_("Audioengine"), 4096);
#ifdef WITH_JACK_MIDI
MIDI::JACK_MidiPort::set_process_thread (pthread_self()); 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 int
@ -188,6 +192,8 @@ AudioEngine::start ()
jack_set_timebase_callback (_priv_jack, 0, _jack_timebase_callback, this); jack_set_timebase_callback (_priv_jack, 0, _jack_timebase_callback, this);
} }
jack_set_error_function (ardour_jack_error);
if (jack_activate (_priv_jack) == 0) { if (jack_activate (_priv_jack) == 0) {
_running = true; _running = true;
_has_run = true; _has_run = true;
@ -1121,12 +1127,6 @@ AudioEngine::remove_all_ports ()
ports.flush (); ports.flush ();
} }
static void
ardour_jack_error (const char* msg)
{
error << "JACK: " << msg << endmsg;
}
int int
AudioEngine::connect_to_jack (string client_name) 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_client_name = jack_get_client_name (_priv_jack);
} }
jack_set_error_function (ardour_jack_error);
return 0; return 0;
} }

View File

@ -18,6 +18,7 @@
*/ */
#include "pbd/enumwriter.h" #include "pbd/enumwriter.h"
#include "midi++/types.h"
#include "ardour/audiofilesource.h" #include "ardour/audiofilesource.h"
#include "ardour/audioregion.h" #include "ardour/audioregion.h"
@ -40,6 +41,7 @@
using namespace std; using namespace std;
using namespace PBD; using namespace PBD;
using namespace ARDOUR; using namespace ARDOUR;
using namespace MIDI;
void void
setup_enum_writer () setup_enum_writer ()
@ -115,6 +117,8 @@ setup_enum_writer ()
WaveformShape _WaveformShape; WaveformShape _WaveformShape;
QuantizeType _QuantizeType; QuantizeType _QuantizeType;
Session::PostTransportWork _Session_PostTransportWork; 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(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_BITS(e) enum_writer->register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
@ -305,6 +309,16 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (Session::Event, AutoLoop); REGISTER_CLASS_ENUM (Session::Event, AutoLoop);
REGISTER (_Session_Event_Type); 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, PostTransportStop);
REGISTER_CLASS_ENUM (Session, PostTransportDisableRecord); REGISTER_CLASS_ENUM (Session, PostTransportDisableRecord);
REGISTER_CLASS_ENUM (Session, PostTransportPosition); REGISTER_CLASS_ENUM (Session, PostTransportPosition);

View File

@ -22,6 +22,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "pbd/error.h" #include "pbd/error.h"
#include "pbd/enumwriter.h"
#include "pbd/failed_constructor.h" #include "pbd/failed_constructor.h"
#include "pbd/pthread_utils.h" #include "pbd/pthread_utils.h"
@ -30,7 +31,7 @@
#include "ardour/slave.h" #include "ardour/slave.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/audioengine.h" #include "ardour/audioengine.h"
#include "ardour/cycles.h" #include "ardour/pi_controller.h"
#include "i18n.h" #include "i18n.h"
@ -46,7 +47,13 @@ MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
can_notify_on_unknown_rate = true; can_notify_on_unknown_rate = true;
did_reset_tc_format = false; did_reset_tc_format = false;
pic = new PIController (1.0, 8);
last_mtc_fps_byte = session.get_mtc_timecode_bits (); 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); rebind (p);
reset (); reset ();
@ -57,6 +64,15 @@ MTC_Slave::~MTC_Slave()
if (did_reset_tc_format) { if (did_reset_tc_format) {
session.config.set_timecode_format (saved_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 void
@ -68,6 +84,8 @@ MTC_Slave::rebind (MIDI::Port& p)
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_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_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))); 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 void
MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now) 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)); DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now));
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; last_inbound_frame = now;
}
} }
void void
@ -116,6 +108,7 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
Timecode::Time timecode; Timecode::Time timecode;
TimecodeFormat tc_format; TimecodeFormat tc_format;
bool reset_tc = true; 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)); DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
@ -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", 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)); 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.timecode_to_sample (timecode, mtc_frame, true, false);
session.request_locate (mtc_frame, false); session.request_locate (mtc_frame, false);
session.request_transport_speed (0); session.request_transport_speed (0);
update_mtc_status (MIDI::Parser::MTC_Stopped); update_mtc_status (MIDI::MTC_Stopped);
window_root = mtc_frame;
reset (); reset ();
} else { } else {
/* we've had the first set of 8 qtr frame messages, determine position /* we've had the first set of 8 qtr frame messages, determine position
and allow continuing qtr frame messages to provide position and allow continuing qtr frame messages to provide position
and speed information. 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); session.timecode_to_sample (timecode, mtc_frame, true, false);
/* We received the last quarter frame 7 quarter frames (1.75 mtc /* 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(); mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
if (now) { 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.guard1++;
current.position = mtc_frame; current.position = mtc_frame;
current.timestamp = now; current.timestamp = now;
current.speed = speed; current.speed = average_speed;
current.guard2++; current.guard2++;
window_root = mtc_frame;
} }
} }
if (now) { if (now) {
last_inbound_frame = now; last_inbound_frame = now;
} }
if (window_root >= 0) {
reset_window (window_root);
}
} }
double void
MTC_Slave::compute_apparent_speed (nframes64_t now) MTC_Slave::process_apparent_speed (double this_speed)
{ {
if (current.timestamp != 0) { DEBUG_TRACE (DEBUG::MTC, string_compose ("speed cnt %1 sz %2 have %3\n", speed_accumulator_cnt, speed_accumulator_size, have_first_speed_accumulator));
double speed = (double) ((mtc_frame - current.position) / (double) (now - current.timestamp)); if (speed_accumulator_cnt >= speed_accumulator_size) {
DEBUG_TRACE (DEBUG::MTC, string_compose ("instantaneous speed = %1 from %2 / %3\n", have_first_speed_accumulator = true;
speed, mtc_frame - current.position, now - current.timestamp)); speed_accumulator_cnt = 0;
/* crude low pass filter/smoother for speed */
accumulator[accumulator_index++] = speed;
if (accumulator_index >= accumulator_size) {
have_first_accumulated_speed = true;
accumulator_index = 0;
} }
if (have_first_accumulated_speed) { speed_accumulator[speed_accumulator_cnt++] = this_speed;
double total = 0;
for (int32_t i = 0; i < accumulator_size; ++i) { if (have_first_speed_accumulator) {
total += accumulator[i]; average_speed = 0.0;
for (size_t i = 0; i < speed_accumulator_size; ++i) {
average_speed += speed_accumulator[i];
} }
average_speed /= speed_accumulator_size;
speed = total / accumulator_size;
DEBUG_TRACE (DEBUG::MTC, string_compose ("speed smoothed to %1\n", speed));
}
return speed;
} else {
return 0;
} }
} }
@ -271,16 +296,16 @@ MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
} }
void 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 /* XXX !!! thread safety ... called from MIDI I/O context
and process() context (via ::speed_and_position()) and process() context (via ::speed_and_position())
*/ */
DEBUG_TRACE (DEBUG::MTC, string_compose ("new MTC status %1\n", enum_2_string (status)));
switch (status) { switch (status) {
case MTC_Stopped: case MTC_Stopped:
mtc_frame = 0;
current.guard1++; current.guard1++;
current.position = mtc_frame; current.position = mtc_frame;
current.timestamp = 0; current.timestamp = 0;
@ -290,27 +315,22 @@ MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
break; break;
case MTC_Forward: case MTC_Forward:
mtc_frame = 0;
current.guard1++; current.guard1++;
current.position = mtc_frame; current.position = mtc_frame;
current.timestamp = 0; current.timestamp = 0;
current.speed = 0; current.speed = 0;
current.guard2++; current.guard2++;
break; break;
case MTC_Backward: case MTC_Backward:
mtc_frame = 0;
current.guard1++; current.guard1++;
current.position = mtc_frame; current.position = mtc_frame;
current.timestamp = 0; current.timestamp = 0;
current.speed = 0; current.speed = 0;
current.guard2++; current.guard2++;
break; break;
} }
} }
void void
@ -365,7 +385,7 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
pos = last.position; pos = last.position;
session.request_locate (pos, false); session.request_locate (pos, false);
session.request_transport_speed (0); session.request_transport_speed (0);
update_mtc_status (MIDI::Parser::MTC_Stopped); update_mtc_status (MIDI::MTC_Stopped);
reset(); reset();
DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n"); DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n");
return false; return false;
@ -384,7 +404,7 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
if (last.timestamp && (now > last.timestamp)) { if (last.timestamp && (now > last.timestamp)) {
elapsed = (nframes_t) floor (last.speed * (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", 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 { } else {
elapsed = 0; /* XXX is this right? */ elapsed = 0; /* XXX is this right? */
} }
@ -422,7 +442,42 @@ MTC_Slave::reset ()
current.timestamp = 0; current.timestamp = 0;
current.speed = 0; current.speed = 0;
current.guard2++; current.guard2++;
accumulator_index = 0;
have_first_accumulated_speed = false; window_begin = 0;
qtr_frame_messages_valid_for_time = false; 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));
} }

View File

@ -1261,7 +1261,7 @@ Session::midi_thread_work ()
} }
if (pfd[p].revents & POLLIN) { 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++; fds_ready++;
ports[p]->parse (now); ports[p]->parse (now);
} }

View File

@ -461,7 +461,7 @@ Session::reset_slave_state ()
average_slave_delta = 1800; average_slave_delta = 1800;
delta_accumulator_cnt = 0; delta_accumulator_cnt = 0;
have_first_delta_accumulator = false; have_first_delta_accumulator = false;
slave_state = Stopped; _slave_state = Stopped;
} }
bool bool
@ -483,7 +483,6 @@ Session::follow_slave (nframes_t nframes)
nframes64_t slave_transport_frame; nframes64_t slave_transport_frame;
nframes_t this_delta; nframes_t this_delta;
int dir; int dir;
bool starting;
if (!_slave->ok()) { if (!_slave->ok()) {
stop_transport (); stop_transport ();
@ -493,7 +492,7 @@ Session::follow_slave (nframes_t nframes)
_slave->speed_and_position (slave_speed, slave_transport_frame); _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()) { if (!_slave->locked()) {
DEBUG_TRACE (DEBUG::Slave, "slave not locked\n"); DEBUG_TRACE (DEBUG::Slave, "slave not locked\n");
@ -508,7 +507,7 @@ Session::follow_slave (nframes_t nframes)
dir = -1; dir = -1;
} }
if ((starting = _slave->starting())) { if (_slave->starting()) {
slave_speed = 0.0f; slave_speed = 0.0f;
} }
@ -524,21 +523,23 @@ Session::follow_slave (nframes_t nframes)
} else { } else {
/* TC source is able to drift relative to us (slave) /* if we are chasing and the average delta between us and the
so we need to keep track of the drift and adjust master gets too big, we want to switch to silent
our speed to remain locked. motion. so keep track of that here.
*/ */
if (_slave_state == Running) {
calculate_moving_average_of_slave_delta(dir, this_delta); 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", 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, starting)); _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) { if (_transport_speed != 0.0f) {
@ -548,7 +549,6 @@ Session::follow_slave (nframes_t nframes)
float delta; float delta;
#ifdef USE_MOVING_AVERAGE_OF_SLAVE
if (average_slave_delta == 0) { if (average_slave_delta == 0) {
delta = this_delta; delta = this_delta;
delta *= dir; delta *= dir;
@ -556,10 +556,6 @@ Session::follow_slave (nframes_t nframes)
delta = average_slave_delta; delta = average_slave_delta;
delta *= average_dir; delta *= average_dir;
} }
#else
delta = this_delta;
delta *= dir;
#endif
#ifndef NDEBUG #ifndef NDEBUG
if (slave_speed != 0.0) { if (slave_speed != 0.0) {
@ -569,39 +565,29 @@ Session::follow_slave (nframes_t nframes)
_transport_speed, _transport_speed,
_transport_frame, _transport_frame,
slave_transport_frame, slave_transport_frame,
_transport_frame,
average_slave_delta)); average_slave_delta));
} }
#endif #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;
} else {
float adjusted_speed = slave_speed + (delta / float(_current_frame_rate));
if (_slave->give_slave_full_control_over_transport_speed()) { if (_slave->give_slave_full_control_over_transport_speed()) {
request_transport_speed (slave_speed); set_transport_speed (slave_speed, false, false);
} else { } else {
float adjusted_speed = slave_speed + (delta / float(_current_frame_rate));
request_transport_speed (adjusted_speed); request_transport_speed (adjusted_speed);
DEBUG_TRACE (DEBUG::Slave, string_compose ("adjust using %1 towards %2 ratio %3 current %4 slave @ %5\n", 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, delta, adjusted_speed, adjusted_speed/slave_speed, _transport_speed,
slave_speed)); slave_speed));
} }
}
if (abs(average_slave_delta) > (long) _slave->resolution()) { if (abs(average_slave_delta) > _slave->resolution()) {
cerr << "average slave delta greater than slave resolution, going to silent motion\n"; cerr << "average slave delta greater than slave resolution (" << _slave->resolution() << "), going to silent motion\n";
goto silent_motion; 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 */ /* speed is set, we're locked, and good to go */
return true; return true;
} }
@ -645,24 +631,24 @@ Session::calculate_moving_average_of_slave_delta(int dir, nframes_t this_delta)
} }
void 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) { if (slave_speed != 0.0f) {
/* slave is running */ /* slave is running */
switch (slave_state) { switch (_slave_state) {
case Stopped: case Stopped:
if (_slave->requires_seekahead()) { 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)); 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); locate (slave_wait_end, false, false);
slave_state = Waiting; _slave_state = Waiting;
starting = true;
} else { } else {
slave_state = Running; _slave_state = Running;
Location* al = _locations.auto_loop_location(); Location* al = _locations.auto_loop_location();
@ -678,13 +664,24 @@ Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame,
break; break;
case Waiting: case Waiting:
default:
break;
}
if (_slave_state == Waiting) {
DEBUG_TRACE (DEBUG::Slave, string_compose ("slave waiting at %1\n", slave_transport_frame)); DEBUG_TRACE (DEBUG::Slave, string_compose ("slave waiting at %1\n", slave_transport_frame));
if (slave_transport_frame >= slave_wait_end) { 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)); 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; bool ok = true;
nframes_t frame_delta = slave_transport_frame - _transport_frame; 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; average_slave_delta = 0L;
this_delta = 0; 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"); DEBUG_TRACE (DEBUG::Slave, "slave starts transport\n");
start_transport (); start_transport ();
} }
@ -738,7 +731,7 @@ Session::track_slave_state (float slave_speed, nframes_t slave_transport_frame,
force_locate (slave_transport_frame, false); force_locate (slave_transport_frame, false);
} }
slave_state = Stopped; _slave_state = Stopped;
} }
} }

View File

@ -263,7 +263,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
average_slave_delta = 1800; // !!! why 1800 ???? average_slave_delta = 1800; // !!! why 1800 ????
have_first_delta_accumulator = false; have_first_delta_accumulator = false;
delta_accumulator_cnt = 0; delta_accumulator_cnt = 0;
slave_state = Stopped; _slave_state = Stopped;
_engine.GraphReordered.connect (mem_fun (*this, &Session::graph_reordered)); _engine.GraphReordered.connect (mem_fun (*this, &Session::graph_reordered));

View File

@ -132,6 +132,7 @@ libardour_sources = [
'onset_detector.cc', 'onset_detector.cc',
'panner.cc', 'panner.cc',
'pcm_utils.cc', 'pcm_utils.cc',
'pi_controller.cc',
'playlist.cc', 'playlist.cc',
'playlist_factory.cc', 'playlist_factory.cc',
'plugin.cc', 'plugin.cc',

View File

@ -116,12 +116,6 @@ class Parser : public sigc::trackable {
/* MTC */ /* MTC */
enum MTC_Status {
MTC_Stopped = 0,
MTC_Forward,
MTC_Backward
};
MTC_FPS mtc_fps() const { return _mtc_fps; } MTC_FPS mtc_fps() const { return _mtc_fps; }
MTC_Status mtc_running() const { return _mtc_running; } MTC_Status mtc_running() const { return _mtc_running; }
const byte *mtc_current() const { return _mtc_time; } const byte *mtc_current() const { return _mtc_time; }

View File

@ -226,7 +226,7 @@ Parser::process_mtc_quarter_frame (byte *msg)
/* time code is looking good */ /* time code is looking good */
#ifdef DEBUG_MTC #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 #endif
switch (which_quarter_frame) { 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_qtr (*this, which_quarter_frame, _timestamp); /* EMIT_SIGNAL */
// mtc (*this, &msg[1], msglen - 1); // mtc (*this, &msg[1], msglen - 1);