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/slave.h>
30 #include <ardour/session.h>
31 #include <ardour/audioengine.h>
32 #include <ardour/cycles.h>
36 using namespace ARDOUR;
41 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
44 can_notify_on_unknown_rate = true;
46 last_mtc_fps_byte = session.get_mtc_smpte_bits ();
52 MTC_Slave::~MTC_Slave()
57 MTC_Slave::rebind (MIDI::Port& p)
59 for (vector<sigc::connection>::iterator i = connections.begin(); i != connections.end(); ++i) {
65 connections.push_back (port->input()->mtc_time.connect (mem_fun (*this, &MTC_Slave::update_mtc_time)));
66 connections.push_back (port->input()->mtc_qtr.connect (mem_fun (*this, &MTC_Slave::update_mtc_qtr)));
67 connections.push_back (port->input()->mtc_status.connect (mem_fun (*this, &MTC_Slave::update_mtc_status)));
71 MTC_Slave::update_mtc_qtr (Parser& p)
73 cycles_t cnow = get_cycles ();
74 nframes_t now = session.engine().frame_time();
76 static cycles_t last_qtr = 0;
78 qtr = (long) (session.frames_per_smpte_frame() / 4);
83 current.position = mtc_frame;
84 current.timestamp = now;
87 last_inbound_frame = now;
91 MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
93 nframes_t now = session.engine().frame_time();
97 smpte.minutes = msg[2];
98 smpte.seconds = msg[1];
99 smpte.frames = msg[0];
101 last_mtc_fps_byte = msg[4];
107 can_notify_on_unknown_rate = true;
112 can_notify_on_unknown_rate = true;
114 case MTC_30_FPS_DROP:
117 can_notify_on_unknown_rate = true;
122 can_notify_on_unknown_rate = true;
125 /* throttle error messages about unknown MTC rates */
126 if (can_notify_on_unknown_rate) {
127 error << string_compose (_("Unknown rate/drop value %1 in incoming MTC stream, session values used instead"),
130 can_notify_on_unknown_rate = false;
132 smpte.rate = session.smpte_frames_per_second();
133 smpte.drop = session.smpte_drop_frames();
136 session.smpte_to_sample (smpte, mtc_frame, true, false);
141 current.position = mtc_frame;
142 current.timestamp = 0;
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_smpte_frame()) + session.worst_output_latency();
162 if (first_mtc_frame == 0) {
163 first_mtc_frame = mtc_frame;
164 first_mtc_time = now;
168 current.position = mtc_frame;
169 current.timestamp = now;
173 last_inbound_frame = now;
177 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
181 mtc[4] = last_mtc_fps_byte;
182 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
187 update_mtc_time (mtc, true);
191 MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
200 current.position = mtc_frame;
201 current.timestamp = 0;
211 current.position = mtc_frame;
212 current.timestamp = 0;
222 current.position = mtc_frame;
223 current.timestamp = 0;
231 MTC_Slave::read_current (SafeTime *st) const
236 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
244 } while (st->guard1 != st->guard2);
248 MTC_Slave::locked () const
250 return port->input()->mtc_locked();
254 MTC_Slave::ok() const
260 MTC_Slave::speed_and_position (double& speed, nframes_t& pos)
262 nframes_t now = session.engine().frame_time();
264 nframes_t frame_rate;
268 read_current (&last);
270 if (first_mtc_time == 0) {
276 /* no timecode for 1/4 second ? conclude that its stopped */
278 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
281 session.request_locate (pos, false);
282 session.request_transport_speed (0);
283 update_mtc_status (MIDI::Parser::MTC_Stopped);
288 frame_rate = session.frame_rate();
290 speed_now = (double) ((last.position - first_mtc_frame) / (double) (now - first_mtc_time));
292 accumulator[accumulator_index++] = speed_now;
294 if (accumulator_index >= accumulator_size) {
295 have_first_accumulated_speed = true;
296 accumulator_index = 0;
299 if (have_first_accumulated_speed) {
302 for (int32_t i = 0; i < accumulator_size; ++i) {
303 total += accumulator[i];
306 mtc_speed = total / accumulator_size;
310 mtc_speed = speed_now;
314 if (mtc_speed == 0.0f) {
320 /* scale elapsed time by the current MTC speed */
322 if (last.timestamp && (now > last.timestamp)) {
323 elapsed = (nframes_t) floor (mtc_speed * (now - last.timestamp));
325 elapsed = 0; /* XXX is this right? */
329 /* now add the most recent timecode value plus the estimated elapsed interval */
331 pos = elapsed + last.position;
338 MTC_Slave::resolution() const
340 return (nframes_t) session.frames_per_smpte_frame();
346 /* XXX massive thread safety issue here. MTC could
347 be being updated as we call this. but this
348 supposed to be a realtime-safe call.
351 port->input()->reset_mtc_state ();
353 last_inbound_frame = 0;
355 current.position = 0;
356 current.timestamp = 0;
361 accumulator_index = 0;
362 have_first_accumulated_speed = false;