2 Copyright (C) 2002-4 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <sys/types.h>
24 #include "pbd/error.h"
25 #include "pbd/failed_constructor.h"
26 #include "pbd/pthread_utils.h"
28 #include "midi++/port.h"
29 #include "ardour/debug.h"
30 #include "ardour/slave.h"
31 #include "ardour/session.h"
32 #include "ardour/audioengine.h"
33 #include "ardour/cycles.h"
38 using namespace ARDOUR;
43 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
46 can_notify_on_unknown_rate = true;
48 last_mtc_fps_byte = session.get_mtc_timecode_bits ();
54 MTC_Slave::~MTC_Slave()
59 MTC_Slave::rebind (MIDI::Port& p)
61 for (vector<sigc::connection>::iterator i = connections.begin(); i != connections.end(); ++i) {
67 connections.push_back (port->input()->mtc_time.connect (mem_fun (*this, &MTC_Slave::update_mtc_time)));
68 connections.push_back (port->input()->mtc_qtr.connect (mem_fun (*this, &MTC_Slave::update_mtc_qtr)));
69 connections.push_back (port->input()->mtc_status.connect (mem_fun (*this, &MTC_Slave::update_mtc_status)));
73 MTC_Slave::update_mtc_qtr (Parser& /*p*/)
75 nframes64_t now = session.engine().frame_time();
78 qtr = (long) (session.frames_per_timecode_frame() / 4);
81 double speed = compute_apparent_speed (now);
84 current.position = mtc_frame;
85 current.timestamp = now;
86 current.speed = speed;
89 last_inbound_frame = now;
93 MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
95 nframes64_t now = session.engine().frame_time();
96 Timecode::Time timecode;
98 timecode.hours = msg[3];
99 timecode.minutes = msg[2];
100 timecode.seconds = msg[1];
101 timecode.frames = msg[0];
103 last_mtc_fps_byte = msg[4];
108 timecode.drop = false;
109 can_notify_on_unknown_rate = true;
113 timecode.drop = false;
114 can_notify_on_unknown_rate = true;
116 case MTC_30_FPS_DROP:
118 timecode.drop = true;
119 can_notify_on_unknown_rate = true;
123 timecode.drop = false;
124 can_notify_on_unknown_rate = true;
127 /* throttle error messages about unknown MTC rates */
128 if (can_notify_on_unknown_rate) {
129 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
132 can_notify_on_unknown_rate = false;
134 timecode.rate = session.timecode_frames_per_second();
135 timecode.drop = session.timecode_drop_frames();
138 session.timecode_to_sample (timecode, mtc_frame, true, false);
140 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n",
141 now, timecode, mtc_frame, was_full));
145 session.request_locate (mtc_frame, false);
146 session.request_transport_speed (0);
147 update_mtc_status (MIDI::Parser::MTC_Stopped);
153 /* We received the last quarter frame 7 quarter frames (1.75 mtc
154 frames) after the instance when the contents of the mtc quarter
155 frames were decided. Add time to compensate for the elapsed 1.75
157 Also compensate for audio latency.
160 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
162 /* leave speed alone here. compute it only as we receive qtr frame messages */
165 current.position = mtc_frame;
166 current.timestamp = now;
169 DEBUG_TRACE (DEBUG::MTC, string_compose ("stored TC frame = %1 @ %2, sp = %3\n", mtc_frame, now, speed));
173 last_inbound_frame = now;
177 MTC_Slave::compute_apparent_speed (nframes64_t now)
179 if (current.timestamp != 0) {
181 double speed = (double) ((mtc_frame - current.position) / (double) (now - current.timestamp));
182 DEBUG_TRACE (DEBUG::MTC, string_compose ("instantaneous speed = %1 from %2 - %3 / %4 - %5\n",
183 speed, mtc_frame, current.position, now, current.timestamp));
185 accumulator[accumulator_index++] = speed;
187 if (accumulator_index >= accumulator_size) {
188 have_first_accumulated_speed = true;
189 accumulator_index = 0;
192 if (have_first_accumulated_speed) {
195 for (int32_t i = 0; i < accumulator_size; ++i) {
196 total += accumulator[i];
199 speed = total / accumulator_size;
200 DEBUG_TRACE (DEBUG::MTC, string_compose ("speed smoothed to %1\n", speed));
212 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
216 mtc[4] = last_mtc_fps_byte;
217 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
222 update_mtc_time (mtc, true);
226 MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
228 /* XXX !!! thread safety ... called from MIDI I/O context
229 and process() context (via ::speed_and_position())
237 current.position = mtc_frame;
238 current.timestamp = 0;
248 current.position = mtc_frame;
249 current.timestamp = 0;
259 current.position = mtc_frame;
260 current.timestamp = 0;
269 MTC_Slave::read_current (SafeTime *st) const
275 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
282 } while (st->guard1 != st->guard2);
286 MTC_Slave::locked () const
288 return port->input()->mtc_locked();
292 MTC_Slave::ok() const
298 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
300 nframes64_t now = session.engine().frame_time();
304 read_current (&last);
306 if (last.timestamp == 0) {
309 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
313 /* no timecode for 1/4 second ? conclude that its stopped */
315 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
318 session.request_locate (pos, false);
319 session.request_transport_speed (0);
320 update_mtc_status (MIDI::Parser::MTC_Stopped);
322 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n");
326 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
328 if (last.speed == 0.0f) {
334 /* scale elapsed time by the current MTC speed */
336 if (last.timestamp && (now > last.timestamp)) {
337 elapsed = (nframes_t) floor (speed * (now - last.timestamp));
339 elapsed = 0; /* XXX is this right? */
343 /* now add the most recent timecode value plus the estimated elapsed interval */
345 pos = elapsed + last.position;
348 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
354 MTC_Slave::resolution() const
356 return (nframes_t) session.frames_per_timecode_frame();
362 /* XXX massive thread safety issue here. MTC could
363 be being updated as we call this. but this
364 supposed to be a realtime-safe call.
367 port->input()->reset_mtc_state ();
369 last_inbound_frame = 0;
371 current.position = 0;
372 current.timestamp = 0;
375 accumulator_index = 0;
376 have_first_accumulated_speed = false;