summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2009-12-03 18:44:06 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2009-12-03 18:44:06 +0000
commit03c74e45a871f2e09fb1ee855f830c94d1cdb163 (patch)
treee0bd9da870df25c4127d22a4fb79359bdebea701 /libs/ardour
parentc9dda81a693ba9c06b9d62f5df56c04be75adfca (diff)
more tweaks to MTC slave code (still not functional), including removing race conditions when resetting slave state; make Session catch on its own saved preferences, which has not been happening; make switching sync sources avoid race conditions
git-svn-id: svn://localhost/ardour2/branches/3.0@6269 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/session.h9
-rw-r--r--libs/ardour/ardour/slave.h21
-rw-r--r--libs/ardour/jack_slave.cc2
-rw-r--r--libs/ardour/mtc_slave.cc111
-rw-r--r--libs/ardour/session.cc1
-rw-r--r--libs/ardour/session_events.cc2
-rw-r--r--libs/ardour/session_process.cc2
-rw-r--r--libs/ardour/session_state.cc3
-rw-r--r--libs/ardour/session_transport.cc80
9 files changed, 152 insertions, 79 deletions
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 4f0acc9381..449bbc790d 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -175,7 +175,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
void* ptr;
bool yes_or_no;
nframes64_t target2_frame;
- SyncSource sync_source;
+ Slave* slave;
Route* route;
};
@@ -584,7 +584,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
static sigc::signal<void> TimecodeOffsetChanged;
std::vector<SyncSource> get_available_sync_options() const;
- void request_sync_source (SyncSource);
+ void request_sync_source (Slave*);
bool synced_to_jack() const { return config.get_external_sync() && config.get_sync_source() == JACK; }
double transport_speed() const { return _transport_speed; }
@@ -1104,8 +1104,9 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
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);
- void drop_sync_source ();
+ void switch_to_sync_source (SyncSource); /* !RT context */
+ void drop_sync_source (); /* !RT context */
+ void use_sync_source (Slave*); /* RT context */
bool post_export_sync;
nframes_t post_export_position;
diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h
index dae0d80d10..62a52155c4 100644
--- a/libs/ardour/ardour/slave.h
+++ b/libs/ardour/ardour/slave.h
@@ -22,6 +22,8 @@
#include <vector>
+#include <glibmm/thread.h>
+
#include <jack/jack.h>
#include <sigc++/signal.h>
@@ -241,12 +243,14 @@ class MTC_Slave : public Slave, public sigc::trackable {
bool can_notify_on_unknown_rate;
PIController* pic;
- SafeTime current;
- nframes_t mtc_frame; /* current time */
- nframes_t last_inbound_frame; /* when we got it; audio clocked */
- MIDI::byte last_mtc_fps_byte;
- nframes64_t window_begin;
- nframes64_t window_end;
+ static const int frame_tolerance;
+
+ SafeTime current;
+ nframes_t mtc_frame; /* current time */
+ nframes_t last_inbound_frame; /* when we got it; audio clocked */
+ MIDI::byte last_mtc_fps_byte;
+ nframes64_t window_begin;
+ nframes64_t window_end;
nframes64_t last_mtc_timestamp;
nframes64_t last_mtc_frame;
bool did_reset_tc_format;
@@ -256,8 +260,13 @@ class MTC_Slave : public Slave, public sigc::trackable {
size_t speed_accumulator_cnt;
bool have_first_speed_accumulator;
double average_speed;
+ Glib::Mutex reset_lock;
+ bool reset_pending;
void reset ();
+ void queue_reset ();
+ void maybe_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::MTC_Status);
diff --git a/libs/ardour/jack_slave.cc b/libs/ardour/jack_slave.cc
index 0f425d09c6..94a12319f2 100644
--- a/libs/ardour/jack_slave.cc
+++ b/libs/ardour/jack_slave.cc
@@ -18,8 +18,8 @@
*/
#include <iostream>
+#include <cerrno>
-#include <errno.h>
#include <jack/jack.h>
#include <jack/transport.h>
diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc
index 9e566367bc..41aaaccbcf 100644
--- a/libs/ardour/mtc_slave.cc
+++ b/libs/ardour/mtc_slave.cc
@@ -41,6 +41,16 @@ using namespace sigc;
using namespace MIDI;
using namespace PBD;
+/* length (in timecode frames) of the "window" that we consider legal given receipt of
+ a given timecode position. Ardour will try to chase within this window, and will
+ stop+locate+wait+chase if timecode arrives outside of it. The window extends entirely
+ in the current direction of motion, so if any timecode arrives that is before the most
+ recently received position (and without the direction of timecode reversing too), we
+ will stop+locate+wait+chase.
+*/
+
+const int MTC_Slave::frame_tolerance = 2;
+
MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
: session (s)
{
@@ -71,8 +81,8 @@ MTC_Slave::~MTC_Slave()
bool
MTC_Slave::give_slave_full_control_over_transport_speed() const
{
- return true; // for PiC control */
- // return false; // for Session-level computed varispeed
+ // return true; // for PiC control */
+ return false; // for Session-level computed varispeed
}
void
@@ -84,8 +94,6 @@ 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)));
@@ -94,6 +102,8 @@ MTC_Slave::rebind (MIDI::Port& p)
void
MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, nframes_t now)
{
+ maybe_reset ();
+
DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2\n", which_qtr, now));
last_inbound_frame = now;
}
@@ -102,9 +112,14 @@ void
MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
{
/* "now" can be zero if this is called from a context where we do not have or do not want
- to use a timestamp indicating when this MTC time was received.
+ to use a timestamp indicating when this MTC time was received. example: when we received
+ a locate command via MMC.
*/
+ if (now) {
+ maybe_reset ();
+ }
+
Timecode::Time timecode;
TimecodeFormat tc_format;
bool reset_tc = true;
@@ -174,8 +189,7 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
session.request_locate (mtc_frame, false);
session.request_transport_speed (0);
update_mtc_status (MIDI::MTC_Stopped);
- window_root = mtc_frame;
-
+ reset_window (mtc_frame);
reset ();
} else {
@@ -265,6 +279,12 @@ MTC_Slave::process_apparent_speed (double this_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));
+ /* clamp to an expected range */
+
+ if (this_speed > 4.0 || this_speed < -4.0) {
+ this_speed = average_speed;
+ }
+
if (speed_accumulator_cnt >= speed_accumulator_size) {
have_first_speed_accumulator = true;
speed_accumulator_cnt = 0;
@@ -385,9 +405,8 @@ 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::MTC_Stopped);
- reset();
- DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n");
+ queue_reset ();
+ DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset pending\n");
return false;
}
@@ -427,13 +446,28 @@ MTC_Slave::resolution() const
}
void
-MTC_Slave::reset ()
+MTC_Slave::queue_reset ()
{
- /* XXX massive thread safety issue here. MTC could
- be being updated as we call this. but this
- supposed to be a realtime-safe call.
- */
+ Glib::Mutex::Lock lm (reset_lock);
+ reset_pending++;
+}
+
+void
+MTC_Slave::maybe_reset ()
+{
+ reset_lock.lock ();
+
+ if (reset_pending) {
+ reset ();
+ reset_pending = 0;
+ }
+
+ reset_lock.unlock ();
+}
+void
+MTC_Slave::reset ()
+{
port->input()->reset_mtc_state ();
last_inbound_frame = 0;
@@ -458,15 +492,48 @@ MTC_Slave::reset ()
void
MTC_Slave::reset_window (nframes64_t root)
{
- window_begin = 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
+ ahead of the window root (taking direction into account).
+ */
- if (session.slave_state() == Session::Running) {
- window_end = root + (session.frames_per_timecode_frame() * 2);
- } else {
- window_end = root + seekahead_distance ();
- }
+ switch (port->input()->mtc_running()) {
+ case MTC_Forward:
+ window_begin = root;
+ if (session.slave_state() == Session::Running) {
+ window_end = root + (session.frames_per_timecode_frame() * frame_tolerance);
+ } else {
+ window_end = root + seekahead_distance ();
+ }
+ DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
+ break;
- DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
+ case MTC_Backward:
+ if (session.slave_state() == Session::Running) {
+ nframes_t d = session.frames_per_timecode_frame() * frame_tolerance;
+ if (root > d) {
+ window_begin = root - d;
+ window_end = root;
+ } else {
+ window_begin = 0;
+ }
+ } else {
+ nframes_t d = seekahead_distance ();
+ if (root > d) {
+ window_begin = root - d;
+ } else {
+ window_begin = 0;
+ }
+ }
+ window_end = root;
+ DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end));
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
}
nframes64_t
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 2af304161d..b32f758ce8 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -538,6 +538,7 @@ Session::when_engine_running ()
BootMessage (_("Using configuration"));
Config->map_parameters (bind (mem_fun (*this, &Session::config_changed), false));
+ config.map_parameters (bind (mem_fun (*this, &Session::config_changed), true));
/* every time we reconnect, recompute worst case output latencies */
diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc
index b218bbdf85..88a34d5f36 100644
--- a/libs/ardour/session_events.cc
+++ b/libs/ardour/session_events.cc
@@ -395,7 +395,7 @@ Session::process_event (Event* ev)
break;
case Event::SetSyncSource:
- use_sync_source (ev->sync_source);
+ use_sync_source (ev->slave);
break;
case Event::Audition:
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index 4142490af6..d7a92de3b2 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -572,7 +572,7 @@ Session::follow_slave (nframes_t nframes)
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));
+ float adjusted_speed = slave_speed + (1.5 * (delta / float(_current_frame_rate)));
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,
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index bcc3afbb05..e2df46c83a 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -58,6 +58,7 @@
#include "midi++/port.h"
#include "pbd/boost_debug.h"
+#include "pbd/enumwriter.h"
#include "pbd/error.h"
#include "pbd/pathscanner.h"
#include "pbd/pthread_utils.h"
@@ -3212,7 +3213,7 @@ Session::config_changed (std::string p, bool ours)
if (!config.get_external_sync()) {
drop_sync_source ();
} else {
- use_sync_source (config.get_sync_source());
+ switch_to_sync_source (config.get_sync_source());
}
} else if (p == "remote-model") {
set_remote_control_ids ();
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index 69de9ead2e..4055889c9c 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -79,14 +79,14 @@ Session::request_input_change_handling ()
}
void
-Session::request_sync_source (SyncSource src)
+Session::request_sync_source (Slave* new_slave)
{
Event* ev = new Event (Event::SetSyncSource, Event::Add, Event::Immediate, 0, 0.0);
bool seamless;
seamless = Config->get_seamless_loop ();
- if (src == JACK) {
+ if (dynamic_cast<JACK_Slave*>(new_slave)) {
/* JACK cannot support seamless looping at present */
Config->set_seamless_loop (false);
} else {
@@ -97,7 +97,7 @@ Session::request_sync_source (SyncSource src)
/* save value of seamless from before the switch */
_was_seamless = seamless;
- ev->sync_source = src;
+ ev->slave = new_slave;
queue_event (ev);
}
@@ -1156,17 +1156,16 @@ Session::reset_rf_scale (nframes_t motion)
}
void
-Session::drop_sync_source ()
+Session::use_sync_source (Slave* new_slave)
{
+ /* Runs in process() context */
+
bool non_rt_required = false;
- if (_transport_speed) {
- error << _("please stop the transport before adjusting slave settings") << endmsg;
- return;
- }
+ /* XXX this deletion is problematic because we're in RT context */
delete _slave;
- _slave = 0;
+ _slave = new_slave;
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
@@ -1174,7 +1173,7 @@ Session::drop_sync_source ()
if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
non_rt_required = true;
}
- (*i)->set_slaved (0);
+ (*i)->set_slaved (_slave != 0);
}
}
@@ -1187,24 +1186,27 @@ Session::drop_sync_source ()
}
void
-Session::use_sync_source (SyncSource src)
+Session::drop_sync_source ()
{
- bool reverse = false;
- bool non_rt_required = false;
+ request_sync_source (0);
+}
- if (_transport_speed) {
- error << _("please stop the transport before adjusting slave settings") << endmsg;
- return;
- }
+void
+Session::switch_to_sync_source (SyncSource src)
+{
+ Slave* new_slave;
- delete _slave;
- _slave = 0;
+ DEBUG_TRACE (DEBUG::Slave, string_compose ("Setting up sync source %1\n", enum_2_string (src)));
switch (src) {
case MTC:
+ if (_slave && dynamic_cast<MTC_Slave*>(_slave)) {
+ return;
+ }
+
if (_mtc_port) {
try {
- _slave = new MTC_Slave (*this, *_mtc_port);
+ new_slave = new MTC_Slave (*this, *_mtc_port);
}
catch (failed_constructor& err) {
@@ -1218,9 +1220,13 @@ Session::use_sync_source (SyncSource src)
break;
case MIDIClock:
+ if (_slave && dynamic_cast<MIDIClock_Slave*>(_slave)) {
+ return;
+ }
+
if (_midi_clock_port) {
try {
- _slave = new MIDIClock_Slave (*this, *_midi_clock_port, 24);
+ new_slave = new MIDIClock_Slave (*this, *_midi_clock_port, 24);
}
catch (failed_constructor& err) {
@@ -1234,31 +1240,19 @@ Session::use_sync_source (SyncSource src)
break;
case JACK:
- _slave = new JACK_Slave (_engine.jack());
- break;
-
- };
-
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (!(*i)->hidden()) {
- if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
- non_rt_required = true;
- }
- (*i)->set_slaved (_slave);
+ if (_slave && dynamic_cast<JACK_Slave*>(_slave)) {
+ return;
}
- }
-
- if (reverse) {
- reverse_diskstream_buffers ();
- }
- if (non_rt_required) {
- add_post_transport_work (PostTransportSpeed);
- _butler->schedule_transport_work ();
- }
+ new_slave = new JACK_Slave (_engine.jack());
+ break;
+
+ default:
+ new_slave = 0;
+ break;
+ };
- set_dirty();
+ request_sync_source (new_slave);
}
void