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:
parent
c17b4a30a5
commit
9dddffcc8f
|
@ -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
|
||||
pass
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<sigc::connection> 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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -132,6 +132,7 @@ libardour_sources = [
|
|||
'onset_detector.cc',
|
||||
'panner.cc',
|
||||
'pcm_utils.cc',
|
||||
'pi_controller.cc',
|
||||
'playlist.cc',
|
||||
'playlist_factory.cc',
|
||||
'plugin.cc',
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue