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 cycles_t cnow = get_cycles ();
76 nframes64_t now = session.engine().frame_time();
78 static cycles_t last_qtr = 0;
80 qtr = (long) (session.frames_per_timecode_frame() / 4);
85 current.position = mtc_frame;
86 current.timestamp = now;
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 now %1 = frame %2 (from full message ? %3)\n", timecode, mtc_frame, was_full));
145 current.position = mtc_frame;
146 current.timestamp = 0;
149 session.request_locate (mtc_frame, false);
150 session.request_transport_speed (0);
151 update_mtc_status (MIDI::Parser::MTC_Stopped);
157 /* We received the last quarter frame 7 quarter frames (1.75 mtc
158 frames) after the instance when the contents of the mtc quarter
159 frames were decided. Add time to compensate for the elapsed 1.75
161 Also compensate for audio latency.
164 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
166 if (first_mtc_frame == 0) {
167 first_mtc_frame = mtc_frame;
168 first_mtc_time = now;
172 current.position = mtc_frame;
173 current.timestamp = now;
177 last_inbound_frame = now;
181 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
185 mtc[4] = last_mtc_fps_byte;
186 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
191 update_mtc_time (mtc, true);
195 MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
204 current.position = mtc_frame;
205 current.timestamp = 0;
215 current.position = mtc_frame;
216 current.timestamp = 0;
226 current.position = mtc_frame;
227 current.timestamp = 0;
235 MTC_Slave::read_current (SafeTime *st) const
240 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
248 } while (st->guard1 != st->guard2);
252 MTC_Slave::locked () const
254 return port->input()->mtc_locked();
258 MTC_Slave::ok() const
264 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
266 nframes64_t now = session.engine().frame_time();
268 nframes_t frame_rate;
272 read_current (&last);
274 if (first_mtc_time == 0) {
277 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
281 /* no timecode for 1/4 second ? conclude that its stopped */
283 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
286 session.request_locate (pos, false);
287 session.request_transport_speed (0);
288 update_mtc_status (MIDI::Parser::MTC_Stopped);
290 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n");
294 frame_rate = session.frame_rate();
296 speed_now = (double) ((last.position - first_mtc_frame) / (double) (now - first_mtc_time));
298 DEBUG_TRACE (DEBUG::MTC, string_compose ("apparent speed = %1 from last %2 now %3 first %4\n",
299 speed_now, last.position, now, first_mtc_time));
302 accumulator[accumulator_index++] = speed_now;
304 if (accumulator_index >= accumulator_size) {
305 have_first_accumulated_speed = true;
306 accumulator_index = 0;
309 if (have_first_accumulated_speed) {
312 for (int32_t i = 0; i < accumulator_size; ++i) {
313 total += accumulator[i];
316 mtc_speed = total / accumulator_size;
320 mtc_speed = speed_now;
324 if (mtc_speed == 0.0f) {
330 /* scale elapsed time by the current MTC speed */
332 if (last.timestamp && (now > last.timestamp)) {
333 elapsed = (nframes_t) floor (mtc_speed * (now - last.timestamp));
335 elapsed = 0; /* XXX is this right? */
339 /* now add the most recent timecode value plus the estimated elapsed interval */
341 pos = elapsed + last.position;
348 MTC_Slave::resolution() const
350 return (nframes_t) session.frames_per_timecode_frame();
356 /* XXX massive thread safety issue here. MTC could
357 be being updated as we call this. but this
358 supposed to be a realtime-safe call.
361 port->input()->reset_mtc_state ();
363 last_inbound_frame = 0;
365 current.position = 0;
366 current.timestamp = 0;
371 accumulator_index = 0;
372 have_first_accumulated_speed = false;