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 nframes64_t now = session.engine().frame_time();
81 DEBUG_TRACE (DEBUG::MTC, string_compose ("qtr frame %1 at %2, valid-for-time? %3\n", which_qtr, now, qtr_frame_messages_valid_for_time));
83 if (qtr_frame_messages_valid_for_time) {
87 /* leave position and speed updates for the last
88 qtr frame message of the 8 to be taken
89 care of in update_mtc_time(), invoked
90 by the Parser right after this.
95 qtr = (long) (session.frames_per_timecode_frame() / 4);
98 double speed = compute_apparent_speed (now);
101 current.position = mtc_frame;
102 current.timestamp = now;
103 current.speed = speed;
107 last_inbound_frame = now;
112 MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
114 nframes64_t now = session.engine().frame_time();
115 Timecode::Time timecode;
116 TimecodeFormat tc_format;
117 bool reset_tc = true;
119 DEBUG_TRACE (DEBUG::MTC, string_compose ("full mtc time known at %1, full ? %2\n", now, was_full));
121 timecode.hours = msg[3];
122 timecode.minutes = msg[2];
123 timecode.seconds = msg[1];
124 timecode.frames = msg[0];
126 last_mtc_fps_byte = msg[4];
131 timecode.drop = false;
132 tc_format = timecode_24;
133 can_notify_on_unknown_rate = true;
137 timecode.drop = false;
138 tc_format = timecode_25;
139 can_notify_on_unknown_rate = true;
141 case MTC_30_FPS_DROP:
143 timecode.drop = true;
144 tc_format = timecode_30drop;
145 can_notify_on_unknown_rate = true;
149 timecode.drop = false;
150 can_notify_on_unknown_rate = true;
151 tc_format = timecode_30;
154 /* throttle error messages about unknown MTC rates */
155 if (can_notify_on_unknown_rate) {
156 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
159 can_notify_on_unknown_rate = false;
161 timecode.rate = session.timecode_frames_per_second();
162 timecode.drop = session.timecode_drop_frames();
167 if (!did_reset_tc_format) {
168 saved_tc_format = session.config.get_timecode_format();
169 did_reset_tc_format = true;
171 session.config.set_timecode_format (tc_format);
174 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC time timestamp = %1 TC %2 = frame %3 (from full message ? %4)\n",
175 now, timecode, mtc_frame, was_full));
179 session.timecode_to_sample (timecode, mtc_frame, true, false);
180 session.request_locate (mtc_frame, false);
181 session.request_transport_speed (0);
182 update_mtc_status (MIDI::Parser::MTC_Stopped);
189 /* we've had the first set of 8 qtr frame messages, determine position
190 and allow continuing qtr frame messages to provide position
191 and speed information.
194 qtr_frame_messages_valid_for_time = true;
195 session.timecode_to_sample (timecode, mtc_frame, true, false);
197 /* We received the last quarter frame 7 quarter frames (1.75 mtc
198 frames) after the instance when the contents of the mtc quarter
199 frames were decided. Add time to compensate for the elapsed 1.75
200 frames. Also compensate for audio latency.
203 mtc_frame += (long) (1.75 * session.frames_per_timecode_frame()) + session.worst_output_latency();
205 double speed = compute_apparent_speed (now);
208 current.position = mtc_frame;
209 current.timestamp = now;
210 current.speed = speed;
214 last_inbound_frame = now;
218 MTC_Slave::compute_apparent_speed (nframes64_t now)
220 if (current.timestamp != 0) {
222 double speed = (double) ((mtc_frame - current.position) / (double) (now - current.timestamp));
223 DEBUG_TRACE (DEBUG::MTC, string_compose ("instantaneous speed = %1 from %2 / %3\n",
224 speed, mtc_frame - current.position, now - current.timestamp));
226 /* crude low pass filter/smoother for speed */
228 accumulator[accumulator_index++] = speed;
230 if (accumulator_index >= accumulator_size) {
231 have_first_accumulated_speed = true;
232 accumulator_index = 0;
235 if (have_first_accumulated_speed) {
238 for (int32_t i = 0; i < accumulator_size; ++i) {
239 total += accumulator[i];
242 speed = total / accumulator_size;
243 DEBUG_TRACE (DEBUG::MTC, string_compose ("speed smoothed to %1\n", speed));
255 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
259 mtc[4] = last_mtc_fps_byte;
260 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
265 update_mtc_time (mtc, true);
269 MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
271 /* XXX !!! thread safety ... called from MIDI I/O context
272 and process() context (via ::speed_and_position())
280 current.position = mtc_frame;
281 current.timestamp = 0;
291 current.position = mtc_frame;
292 current.timestamp = 0;
302 current.position = mtc_frame;
303 current.timestamp = 0;
312 MTC_Slave::read_current (SafeTime *st) const
318 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
325 } while (st->guard1 != st->guard2);
329 MTC_Slave::locked () const
331 return port->input()->mtc_locked();
335 MTC_Slave::ok() const
341 MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
343 nframes64_t now = session.engine().frame_time();
347 read_current (&last);
349 if (last.timestamp == 0) {
352 DEBUG_TRACE (DEBUG::MTC, string_compose ("first call to MTC_Slave::speed_and_position, pos = %1\n", last.position));
356 /* no timecode for 1/4 second ? conclude that its stopped */
358 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
361 session.request_locate (pos, false);
362 session.request_transport_speed (0);
363 update_mtc_status (MIDI::Parser::MTC_Stopped);
365 DEBUG_TRACE (DEBUG::MTC, "MTC not seen for 1/4 second - reset\n");
369 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
371 if (last.speed == 0.0f) {
377 /* scale elapsed time by the current MTC speed */
379 if (last.timestamp && (now > last.timestamp)) {
380 elapsed = (nframes_t) floor (last.speed * (now - last.timestamp));
381 DEBUG_TRACE (DEBUG::MTC, string_compose ("last timecode received @ %1, now = %2, elapsed frames = %3 w/speed= %4\n",
382 last.timestamp, now, elapsed, speed));
384 elapsed = 0; /* XXX is this right? */
388 /* now add the most recent timecode value plus the estimated elapsed interval */
390 pos = elapsed + last.position;
393 DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
399 MTC_Slave::resolution() const
401 return (nframes_t) session.frames_per_timecode_frame();
407 /* XXX massive thread safety issue here. MTC could
408 be being updated as we call this. but this
409 supposed to be a realtime-safe call.
412 port->input()->reset_mtc_state ();
414 last_inbound_frame = 0;
416 current.position = 0;
417 current.timestamp = 0;
420 accumulator_index = 0;
421 have_first_accumulated_speed = false;
422 qtr_frame_messages_valid_for_time = false;