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;
47 did_reset_tc_format = false;
49 last_mtc_fps_byte = session.get_mtc_timecode_bits ();
55 MTC_Slave::~MTC_Slave()
57 if (did_reset_tc_format) {
58 session.config.set_timecode_format (saved_tc_format);
63 MTC_Slave::rebind (MIDI::Port& p)
65 for (vector<sigc::connection>::iterator i = connections.begin(); i != connections.end(); ++i) {
71 connections.push_back (port->input()->mtc_time.connect (mem_fun (*this, &MTC_Slave::update_mtc_time)));
72 connections.push_back (port->input()->mtc_qtr.connect (mem_fun (*this, &MTC_Slave::update_mtc_qtr)));
73 connections.push_back (port->input()->mtc_status.connect (mem_fun (*this, &MTC_Slave::update_mtc_status)));
77 MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr)
79 if (qtr_frame_messages_valid_for_time) {
81 nframes64_t now = session.engine().frame_time();
85 /* leave position and speed updates for the last
86 qtr frame message of the 8 to be taken
87 care of in update_mtc_time(), invoked
88 by the Parser right after this.
93 qtr = (long) (session.frames_per_timecode_frame() / 4);
96 double speed = compute_apparent_speed (now);
99 current.position = mtc_frame;
100 current.timestamp = now;
101 current.speed = speed;
105 last_inbound_frame = now;
110 MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
112 nframes64_t now = session.engine().frame_time();
113 Timecode::Time timecode;
114 TimecodeFormat tc_format;
115 bool reset_tc = true;
117 timecode.hours = msg[3];
118 timecode.minutes = msg[2];
119 timecode.seconds = msg[1];
120 timecode.frames = msg[0];
122 last_mtc_fps_byte = msg[4];
127 timecode.drop = false;
128 tc_format = timecode_24;
129 can_notify_on_unknown_rate = true;
133 timecode.drop = false;
134 tc_format = timecode_25;
135 can_notify_on_unknown_rate = true;
137 case MTC_30_FPS_DROP:
139 timecode.drop = true;
140 tc_format = timecode_30drop;
141 can_notify_on_unknown_rate = true;
145 timecode.drop = false;
146 can_notify_on_unknown_rate = true;
147 tc_format = timecode_30;
150 /* throttle error messages about unknown MTC rates */
151 if (can_notify_on_unknown_rate) {
152 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
155 can_notify_on_unknown_rate = false;
157 timecode.rate = session.timecode_frames_per_second();
158 timecode.drop = session.timecode_drop_frames();
163 if (!did_reset_tc_format) {
164 saved_tc_format = session.config.get_timecode_format();
165 did_reset_tc_format = true;
167 session.config.set_timecode_format (tc_format);
170 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n",
171 now, timecode, mtc_frame, was_full));
175 session.timecode_to_sample (timecode, mtc_frame, true, false);
176 session.request_locate (mtc_frame, false);
177 session.request_transport_speed (0);
178 update_mtc_status (MIDI::Parser::MTC_Stopped);
185 /* we've had the first set of 8 qtr frame messages, determine position
186 and allow continuing qtr frame messages to provide position
187 and speed information.
190 qtr_frame_messages_valid_for_time = true;
191 session.timecode_to_sample (timecode, mtc_frame, true, false);
193 /* We received the last quarter frame 7 quarter frames (1.75 mtc
194 frames) after the instance when the contents of the mtc quarter
195 frames were decided. Add time to compensate for the elapsed 1.75
196 frames. Also compensate for audio latency.
199 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
201 double speed = compute_apparent_speed (now);
204 current.position = mtc_frame;
205 current.timestamp = now;
206 current.speed = speed;
210 last_inbound_frame = now;
214 MTC_Slave::compute_apparent_speed (nframes64_t now)
216 if (current.timestamp != 0) {
218 double speed = (double) ((mtc_frame - current.position) / (double) (now - current.timestamp));
219 DEBUG_TRACE (DEBUG::MTC, string_compose ("instantaneous speed = %1 from %2 - %3 / %4 - %5\n",
220 speed, mtc_frame, current.position, now, current.timestamp));
222 /* crude low pass filter/smoother for speed */
224 accumulator[accumulator_index++] = speed;
226 if (accumulator_index >= accumulator_size) {
227 have_first_accumulated_speed = true;
228 accumulator_index = 0;
231 if (have_first_accumulated_speed) {
234 for (int32_t i = 0; i < accumulator_size; ++i) {
235 total += accumulator[i];
238 speed = total / accumulator_size;
239 DEBUG_TRACE (DEBUG::MTC, string_compose ("speed smoothed to %1\n", speed));
251 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
255 mtc[4] = last_mtc_fps_byte;
256 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
261 update_mtc_time (mtc, true);
265 MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
267 /* XXX !!! thread safety ... called from MIDI I/O context
268 and process() context (via ::speed_and_position())
276 current.position = mtc_frame;
277 current.timestamp = 0;
287 current.position = mtc_frame;
288 current.timestamp = 0;
298 current.position = mtc_frame;
299 current.timestamp = 0;
308 MTC_Slave::read_current (SafeTime *st) const
314 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
321 } while (st->guard1 != st->guard2);
325 MTC_Slave::locked () const
327 return port->input()->mtc_locked();
331 MTC_Slave::ok() const
337 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
339 nframes64_t now = session.engine().frame_time();
343 read_current (&last);
345 if (last.timestamp == 0) {
348 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
352 /* no timecode for 1/4 second ? conclude that its stopped */
354 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
357 session.request_locate (pos, false);
358 session.request_transport_speed (0);
359 update_mtc_status (MIDI::Parser::MTC_Stopped);
361 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n");
365 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
367 if (last.speed == 0.0f) {
373 /* scale elapsed time by the current MTC speed */
375 if (last.timestamp && (now > last.timestamp)) {
376 elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
377 DEBUG_TRACE (DEBUG_MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
378 last.timestamp, now, elapsed, speed);
380 elapsed = 0; /* XXX is this right? */
384 /* now add the most recent timecode value plus the estimated elapsed interval */
386 pos = elapsed + last.position;
389 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
395 MTC_Slave::resolution() const
397 return (nframes_t) session.frames_per_timecode_frame();
403 /* XXX massive thread safety issue here. MTC could
404 be being updated as we call this. but this
405 supposed to be a realtime-safe call.
408 port->input()->reset_mtc_state ();
410 last_inbound_frame = 0;
412 current.position = 0;
413 current.timestamp = 0;
416 accumulator_index = 0;
417 have_first_accumulated_speed = false;
418 qtr_frame_messages_valid_for_time = false;