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);
82 current.position = mtc_frame;
83 current.timestamp = now;
86 last_inbound_frame = now;
90 MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
92 nframes64_t now = session.engine().frame_time();
93 Timecode::Time timecode;
95 timecode.hours = msg[3];
96 timecode.minutes = msg[2];
97 timecode.seconds = msg[1];
98 timecode.frames = msg[0];
100 last_mtc_fps_byte = msg[4];
105 timecode.drop = false;
106 can_notify_on_unknown_rate = true;
110 timecode.drop = false;
111 can_notify_on_unknown_rate = true;
113 case MTC_30_FPS_DROP:
115 timecode.drop = true;
116 can_notify_on_unknown_rate = true;
120 timecode.drop = false;
121 can_notify_on_unknown_rate = true;
124 /* throttle error messages about unknown MTC rates */
125 if (can_notify_on_unknown_rate) {
126 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
129 can_notify_on_unknown_rate = false;
131 timecode.rate = session.timecode_frames_per_second();
132 timecode.drop = session.timecode_drop_frames();
135 session.timecode_to_sample (timecode, mtc_frame, true, false);
137 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n",
138 now, timecode, mtc_frame, was_full));
142 session.request_locate (mtc_frame, false);
143 session.request_transport_speed (0);
144 update_mtc_status (MIDI::Parser::MTC_Stopped);
151 /* We received the last quarter frame 7 quarter frames (1.75 mtc
152 frames) after the instance when the contents of the mtc quarter
153 frames were decided. Add time to compensate for the elapsed 1.75
155 Also compensate for audio latency.
158 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
160 if (current.timestamp != 0) {
162 speed = (double) ((mtc_frame - current.position) / (double) (now - current.timestamp));
163 DEBUG_TRACE (DEBUG::MTC, string_compose ("instantaneous speed = %1 from %2 - %3 / %4 - %5\n",
164 speed, mtc_frame, current.position, now, current.timestamp));
166 accumulator[accumulator_index++] = speed;
168 if (accumulator_index >= accumulator_size) {
169 have_first_accumulated_speed = true;
170 accumulator_index = 0;
173 if (have_first_accumulated_speed) {
176 for (int32_t i = 0; i < accumulator_size; ++i) {
177 total += accumulator[i];
180 speed = total / accumulator_size;
181 DEBUG_TRACE (DEBUG::MTC, string_compose ("speed smoothed to %1\n", speed));
190 current.position = mtc_frame;
191 current.timestamp = now;
192 current.speed = speed;
194 DEBUG_TRACE (DEBUG::MTC, string_compose ("stored TC frame = %1 @ %2, sp = %3\n", mtc_frame, now, speed));
197 last_inbound_frame = now;
201 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
205 mtc[4] = last_mtc_fps_byte;
206 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
211 update_mtc_time (mtc, true);
215 MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
217 /* XXX !!! thread safety ... called from MIDI I/O context
218 and process() context (via ::speed_and_position())
226 current.position = mtc_frame;
227 current.timestamp = 0;
237 current.position = mtc_frame;
238 current.timestamp = 0;
248 current.position = mtc_frame;
249 current.timestamp = 0;
258 MTC_Slave::read_current (SafeTime *st) const
264 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
271 } while (st->guard1 != st->guard2);
275 MTC_Slave::locked () const
277 return port->input()->mtc_locked();
281 MTC_Slave::ok() const
287 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
289 nframes64_t now = session.engine().frame_time();
293 read_current (&last);
295 if (last.timestamp == 0) {
298 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
302 /* no timecode for 1/4 second ? conclude that its stopped */
304 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
307 session.request_locate (pos, false);
308 session.request_transport_speed (0);
309 update_mtc_status (MIDI::Parser::MTC_Stopped);
311 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n");
315 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
317 if (last.speed == 0.0f) {
323 /* scale elapsed time by the current MTC speed */
325 if (last.timestamp && (now > last.timestamp)) {
326 elapsed = (nframes_t) floor (speed * (now - last.timestamp));
328 elapsed = 0; /* XXX is this right? */
332 /* now add the most recent timecode value plus the estimated elapsed interval */
334 pos = elapsed + last.position;
337 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
343 MTC_Slave::resolution() const
345 return (nframes_t) session.frames_per_timecode_frame();
351 /* XXX massive thread safety issue here. MTC could
352 be being updated as we call this. but this
353 supposed to be a realtime-safe call.
356 port->input()->reset_mtc_state ();
358 last_inbound_frame = 0;
360 current.position = 0;
361 current.timestamp = 0;
364 accumulator_index = 0;
365 have_first_accumulated_speed = false;