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;
50 MTC_Slave::~MTC_Slave()
55 MTC_Slave::rebind (MIDI::Port& p)
57 for (vector<sigc::connection>::iterator i = connections.begin(); i != connections.end(); ++i) {
63 connections.push_back (port->input()->mtc_time.connect (mem_fun (*this, &MTC_Slave::update_mtc_time)));
64 connections.push_back (port->input()->mtc_qtr.connect (mem_fun (*this, &MTC_Slave::update_mtc_qtr)));
65 connections.push_back (port->input()->mtc_status.connect (mem_fun (*this, &MTC_Slave::update_mtc_status)));
69 MTC_Slave::update_mtc_qtr (Parser& p)
71 cycles_t cnow = get_cycles ();
72 nframes_t now = session.engine().frame_time();
74 static cycles_t last_qtr = 0;
76 qtr = (long) (session.frames_per_smpte_frame() / 4);
81 current.position = mtc_frame;
82 current.timestamp = now;
85 last_inbound_frame = now;
89 MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
91 nframes_t now = session.engine().frame_time();
95 smpte.minutes = msg[2];
96 smpte.seconds = msg[1];
97 smpte.frames = msg[0];
103 can_notify_on_unknown_rate = true;
108 can_notify_on_unknown_rate = true;
110 case MTC_30_FPS_DROP:
113 can_notify_on_unknown_rate = true;
118 can_notify_on_unknown_rate = true;
121 /* throttle error messages about unknown MTC rates */
122 if (can_notify_on_unknown_rate) {
123 error << _("Unknown rate/drop value in incoming MTC stream, session values used instead") << endmsg;
124 can_notify_on_unknown_rate = false;
126 smpte.rate = session.smpte_frames_per_second();
127 smpte.drop = session.smpte_drop_frames();
130 session.smpte_to_sample (smpte, mtc_frame, true, false);
135 current.position = mtc_frame;
136 current.timestamp = 0;
139 session.request_locate (mtc_frame, false);
140 update_mtc_status (MIDI::Parser::MTC_Stopped);
146 /* We received the last quarter frame 7 quarter frames (1.75 mtc
147 frames) after the instance when the contents of the mtc quarter
148 frames were decided. Add time to compensate for the elapsed 1.75
150 Also compensate for audio latency.
153 mtc_frame += (long) (1.75 * session.frames_per_smpte_frame()) + session.worst_output_latency();
155 if (first_mtc_frame == 0) {
156 first_mtc_frame = mtc_frame;
157 first_mtc_time = now;
161 current.position = mtc_frame;
162 current.timestamp = now;
166 last_inbound_frame = now;
170 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
174 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
179 update_mtc_time (mtc, true);
183 MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
192 current.position = mtc_frame;
193 current.timestamp = 0;
203 current.position = mtc_frame;
204 current.timestamp = 0;
214 current.position = mtc_frame;
215 current.timestamp = 0;
223 MTC_Slave::read_current (SafeTime *st) const
228 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
236 } while (st->guard1 != st->guard2);
240 MTC_Slave::locked () const
242 return port->input()->mtc_locked();
246 MTC_Slave::ok() const
252 MTC_Slave::speed_and_position (float& speed, nframes_t& pos)
254 nframes_t now = session.engine().frame_time();
256 nframes_t frame_rate;
260 read_current (&last);
262 if (first_mtc_time == 0) {
268 /* no timecode for 1/4 second ? conclude that its stopped */
270 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
273 session.request_locate (pos, false);
274 update_mtc_status (MIDI::Parser::MTC_Stopped);
279 frame_rate = session.frame_rate();
281 speed_now = (float) ((last.position - first_mtc_frame) / (double) (now - first_mtc_time));
283 accumulator[accumulator_index++] = speed_now;
285 if (accumulator_index >= accumulator_size) {
286 have_first_accumulated_speed = true;
287 accumulator_index = 0;
290 if (have_first_accumulated_speed) {
293 for (int32_t i = 0; i < accumulator_size; ++i) {
294 total += accumulator[i];
297 mtc_speed = total / accumulator_size;
301 mtc_speed = speed_now;
305 if (mtc_speed == 0.0f) {
311 /* scale elapsed time by the current MTC speed */
313 if (last.timestamp && (now > last.timestamp)) {
314 elapsed = (nframes_t) floor (mtc_speed * (now - last.timestamp));
316 elapsed = 0; /* XXX is this right? */
320 /* now add the most recent timecode value plus the estimated elapsed interval */
322 pos = elapsed + last.position;
329 MTC_Slave::resolution() const
331 return (nframes_t) session.frames_per_smpte_frame();
337 /* XXX massive thread safety issue here. MTC could
338 be being updated as we call this. but this
339 supposed to be a realtime-safe call.
342 port->input()->reset_mtc_state ();
344 last_inbound_frame = 0;
346 current.position = 0;
347 current.timestamp = 0;
352 accumulator_index = 0;
353 have_first_accumulated_speed = false;