mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-05 05:05:43 +01:00
rework MTC slave so that speed is computed in the MIDI I/O context, not process() context
git-svn-id: svn://localhost/ardour2/branches/3.0@6233 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
63f5e14e01
commit
2ad2792bcb
3 changed files with 69 additions and 74 deletions
|
|
@ -193,16 +193,19 @@ class SlaveSessionProxy : public ISlaveSessionProxy {
|
|||
};
|
||||
|
||||
struct SafeTime {
|
||||
int guard1;
|
||||
nframes_t position;
|
||||
nframes_t timestamp;
|
||||
int guard2;
|
||||
|
||||
SafeTime() {
|
||||
guard1 = 0;
|
||||
guard2 = 0;
|
||||
timestamp = 0;
|
||||
}
|
||||
volatile int guard1;
|
||||
nframes64_t position;
|
||||
nframes64_t timestamp;
|
||||
double speed;
|
||||
volatile int guard2;
|
||||
|
||||
SafeTime() {
|
||||
guard1 = 0;
|
||||
position = 0;
|
||||
timestamp = 0;
|
||||
speed = 0;
|
||||
guard2 = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class MTC_Slave : public Slave, public sigc::trackable {
|
||||
|
|
@ -225,16 +228,13 @@ class MTC_Slave : public Slave, public sigc::trackable {
|
|||
MIDI::Port* port;
|
||||
std::vector<sigc::connection> connections;
|
||||
bool can_notify_on_unknown_rate;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
double mtc_speed;
|
||||
nframes_t first_mtc_frame;
|
||||
nframes_t first_mtc_time;
|
||||
|
||||
static const int32_t accumulator_size = 128;
|
||||
double accumulator[accumulator_size];
|
||||
int32_t accumulator_index;
|
||||
|
|
|
|||
|
|
@ -72,14 +72,11 @@ MTC_Slave::rebind (MIDI::Port& p)
|
|||
void
|
||||
MTC_Slave::update_mtc_qtr (Parser& /*p*/)
|
||||
{
|
||||
cycles_t cnow = get_cycles ();
|
||||
nframes64_t now = session.engine().frame_time();
|
||||
nframes_t qtr;
|
||||
static cycles_t last_qtr = 0;
|
||||
|
||||
qtr = (long) (session.frames_per_timecode_frame() / 4);
|
||||
mtc_frame += qtr;
|
||||
last_qtr = cnow;
|
||||
|
||||
current.guard1++;
|
||||
current.position = mtc_frame;
|
||||
|
|
@ -144,6 +141,7 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
|
|||
current.guard1++;
|
||||
current.position = mtc_frame;
|
||||
current.timestamp = 0;
|
||||
current.speed = 0;
|
||||
current.guard2++;
|
||||
|
||||
session.request_locate (mtc_frame, false);
|
||||
|
|
@ -154,6 +152,8 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
|
|||
|
||||
} else {
|
||||
|
||||
double speed;
|
||||
|
||||
/* We received the last quarter frame 7 quarter frames (1.75 mtc
|
||||
frames) after the instance when the contents of the mtc quarter
|
||||
frames were decided. Add time to compensate for the elapsed 1.75
|
||||
|
|
@ -163,14 +163,39 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
|
|||
|
||||
mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
|
||||
|
||||
if (first_mtc_frame == 0) {
|
||||
first_mtc_frame = mtc_frame;
|
||||
first_mtc_time = now;
|
||||
if (current.timestamp != 0) {
|
||||
|
||||
speed = (double) ((mtc_frame - current.position) / (double) (now - current.timestamp));
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("instantaneous speed = %1 from %2 - %3 / %4 - %5\n",
|
||||
speed, mtc_frame, current.position, now, current.timestamp));
|
||||
|
||||
accumulator[accumulator_index++] = speed;
|
||||
|
||||
if (accumulator_index >= accumulator_size) {
|
||||
have_first_accumulated_speed = true;
|
||||
accumulator_index = 0;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
speed = 0;
|
||||
}
|
||||
|
||||
current.guard1++;
|
||||
current.position = mtc_frame;
|
||||
current.timestamp = now;
|
||||
current.speed = speed;
|
||||
current.guard2++;
|
||||
}
|
||||
|
||||
|
|
@ -194,37 +219,40 @@ MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
|
|||
void
|
||||
MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
|
||||
{
|
||||
/* XXX !!! thread safety ... called from MIDI I/O context
|
||||
and process() context (via ::speed_and_position())
|
||||
*/
|
||||
|
||||
switch (status) {
|
||||
case MTC_Stopped:
|
||||
mtc_speed = 0.0f;
|
||||
mtc_frame = 0;
|
||||
|
||||
current.guard1++;
|
||||
current.position = mtc_frame;
|
||||
current.timestamp = 0;
|
||||
current.speed = 0;
|
||||
current.guard2++;
|
||||
|
||||
break;
|
||||
|
||||
case MTC_Forward:
|
||||
mtc_speed = 0.0f;
|
||||
mtc_frame = 0;
|
||||
|
||||
current.guard1++;
|
||||
current.position = mtc_frame;
|
||||
current.timestamp = 0;
|
||||
current.speed = 0;
|
||||
current.guard2++;
|
||||
|
||||
break;
|
||||
|
||||
case MTC_Backward:
|
||||
mtc_speed = 0.0f;
|
||||
mtc_frame = 0;
|
||||
|
||||
current.guard1++;
|
||||
current.position = mtc_frame;
|
||||
current.timestamp = 0;
|
||||
current.speed = 0;
|
||||
current.guard2++;
|
||||
|
||||
break;
|
||||
|
|
@ -265,13 +293,11 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
|
|||
{
|
||||
nframes64_t now = session.engine().frame_time();
|
||||
SafeTime last;
|
||||
nframes_t frame_rate;
|
||||
nframes_t elapsed;
|
||||
double speed_now;
|
||||
|
||||
read_current (&last);
|
||||
|
||||
if (first_mtc_time == 0) {
|
||||
if (last.timestamp == 0) {
|
||||
speed = 0;
|
||||
pos = last.position;
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
|
||||
|
|
@ -281,7 +307,7 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
|
|||
/* no timecode for 1/4 second ? conclude that its stopped */
|
||||
|
||||
if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
|
||||
mtc_speed = 0;
|
||||
speed = 0;
|
||||
pos = last.position;
|
||||
session.request_locate (pos, false);
|
||||
session.request_transport_speed (0);
|
||||
|
|
@ -291,37 +317,9 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
|
|||
return false;
|
||||
}
|
||||
|
||||
frame_rate = session.frame_rate();
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
|
||||
|
||||
speed_now = (double) ((last.position - first_mtc_frame) / (double) (now - first_mtc_time));
|
||||
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("apparent speed = %1 from last %2 now %3 first %4\n",
|
||||
speed_now, last.position, now, first_mtc_time));
|
||||
|
||||
|
||||
accumulator[accumulator_index++] = speed_now;
|
||||
|
||||
if (accumulator_index >= accumulator_size) {
|
||||
have_first_accumulated_speed = true;
|
||||
accumulator_index = 0;
|
||||
}
|
||||
|
||||
if (have_first_accumulated_speed) {
|
||||
double total = 0;
|
||||
|
||||
for (int32_t i = 0; i < accumulator_size; ++i) {
|
||||
total += accumulator[i];
|
||||
}
|
||||
|
||||
mtc_speed = total / accumulator_size;
|
||||
|
||||
} else {
|
||||
|
||||
mtc_speed = speed_now;
|
||||
|
||||
}
|
||||
|
||||
if (mtc_speed == 0.0f) {
|
||||
if (last.speed == 0.0f) {
|
||||
|
||||
elapsed = 0;
|
||||
|
||||
|
|
@ -330,7 +328,7 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
|
|||
/* scale elapsed time by the current MTC speed */
|
||||
|
||||
if (last.timestamp && (now > last.timestamp)) {
|
||||
elapsed = (nframes_t) floor (mtc_speed * (now - last.timestamp));
|
||||
elapsed = (nframes_t) floor (speed * (now - last.timestamp));
|
||||
} else {
|
||||
elapsed = 0; /* XXX is this right? */
|
||||
}
|
||||
|
|
@ -339,8 +337,10 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
|
|||
/* now add the most recent timecode value plus the estimated elapsed interval */
|
||||
|
||||
pos = elapsed + last.position;
|
||||
speed = last.speed;
|
||||
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
|
||||
|
||||
speed = mtc_speed;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -364,11 +364,8 @@ MTC_Slave::reset ()
|
|||
current.guard1++;
|
||||
current.position = 0;
|
||||
current.timestamp = 0;
|
||||
current.speed = 0;
|
||||
current.guard2++;
|
||||
first_mtc_frame = 0;
|
||||
first_mtc_time = 0;
|
||||
|
||||
accumulator_index = 0;
|
||||
have_first_accumulated_speed = false;
|
||||
mtc_speed = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "pbd/pthread_utils.h"
|
||||
|
||||
#include "ardour/configuration.h"
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/audio_track.h"
|
||||
|
|
@ -833,8 +834,8 @@ Session::send_midi_time_code_for_cycle(nframes_t nframes)
|
|||
/* Duration of one quarter frame */
|
||||
nframes_t quarter_frame_duration = ((long) _frames_per_timecode_frame) >> 2;
|
||||
|
||||
// cerr << "(MTC) TR: " << _transport_frame << " - SF: " << outbound_mtc_timecode_frame
|
||||
// << " - NQ: " << next_quarter_frame_to_send << " - FD" << quarter_frame_duration << endl;
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("TF %1 SF %2 NQ %3 FD %\4n", _transport_frame, outbound_mtc_timecode_frame,
|
||||
next_quarter_frame_to_send, quarter_frame_duration));
|
||||
|
||||
// FIXME: this should always be true
|
||||
//assert((outbound_mtc_timecode_frame + (next_quarter_frame_to_send * quarter_frame_duration))
|
||||
|
|
@ -845,7 +846,7 @@ Session::send_midi_time_code_for_cycle(nframes_t nframes)
|
|||
while (_transport_frame + nframes > (outbound_mtc_timecode_frame +
|
||||
(next_quarter_frame_to_send * quarter_frame_duration))) {
|
||||
|
||||
// cerr << "(MTC) Next frame to send: " << next_quarter_frame_to_send << endl;
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("next frame to send: %1\n", next_quarter_frame_to_send));
|
||||
|
||||
switch (next_quarter_frame_to_send) {
|
||||
case 0:
|
||||
|
|
@ -890,13 +891,10 @@ Session::send_midi_time_code_for_cycle(nframes_t nframes)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/*cerr << "(MTC) Timecode: " << transmitting_timecode_time.hours
|
||||
<< ":" << transmitting_timecode_time.minutes
|
||||
<< ":" << transmitting_timecode_time.seconds
|
||||
<< ":" << transmitting_timecode_time.frames
|
||||
<< ", qfm = " << next_quarter_frame_to_send
|
||||
<< ", stamp = " << out_stamp
|
||||
<< ", delta = " << _transport_frame + out_stamp - last_time << endl;*/
|
||||
DEBUG_STR_SET(foo,"sending ");
|
||||
DEBUG_STR(foo) << transmitting_timecode_time;
|
||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("%1 qfm = %2, stamp = %3\n", DEBUG_STR(foo).str(), next_quarter_frame_to_send,
|
||||
out_stamp));
|
||||
|
||||
// Increment quarter frame counter
|
||||
next_quarter_frame_to_send++;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue