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.
23 #include <sys/types.h>
25 #include <pbd/error.h>
26 #include <pbd/failed_constructor.h>
27 #include <pbd/pthread_utils.h>
29 #include <midi++/port.h>
30 #include <ardour/slave.h>
31 #include <ardour/session.h>
32 #include <ardour/audioengine.h>
33 #include <ardour/cycles.h>
37 using namespace ARDOUR;
42 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
49 MTC_Slave::~MTC_Slave()
54 MTC_Slave::rebind (MIDI::Port& p)
56 for (vector<sigc::connection>::iterator i = connections.begin(); i != connections.end(); ++i) {
62 connections.push_back (port->input()->mtc_time.connect (mem_fun (*this, &MTC_Slave::update_mtc_time)));
63 connections.push_back (port->input()->mtc_qtr.connect (mem_fun (*this, &MTC_Slave::update_mtc_qtr)));
64 connections.push_back (port->input()->mtc_status.connect (mem_fun (*this, &MTC_Slave::update_mtc_status)));
68 MTC_Slave::update_mtc_qtr (Parser& p)
70 cycles_t cnow = get_cycles ();
71 nframes_t now = session.engine().frame_time();
73 static cycles_t last_qtr = 0;
75 qtr = (long) (session.frames_per_smpte_frame() / 4);
80 current.position = mtc_frame;
81 current.timestamp = now;
84 last_inbound_frame = now;
88 MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
90 nframes_t now = session.engine().frame_time();
94 smpte.minutes = msg[2];
95 smpte.seconds = msg[1];
96 smpte.frames = msg[0];
98 session.smpte_to_sample( smpte, mtc_frame, true, false );
103 current.position = mtc_frame;
104 current.timestamp = 0;
107 session.request_locate (mtc_frame, false);
108 update_mtc_status (MIDI::Parser::MTC_Stopped);
114 /* We received the last quarter frame 7 quarter frames (1.75 mtc
115 frames) after the instance when the contents of the mtc quarter
116 frames were decided. Add time to compensate for the elapsed 1.75
118 Also compensate for audio latency.
121 mtc_frame += (long) (1.75 * session.frames_per_smpte_frame()) + session.worst_output_latency();
123 if (first_mtc_frame == 0) {
124 first_mtc_frame = mtc_frame;
125 first_mtc_time = now;
129 current.position = mtc_frame;
130 current.timestamp = now;
134 last_inbound_frame = now;
138 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
142 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
147 update_mtc_time (mtc, true);
151 MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
160 current.position = mtc_frame;
161 current.timestamp = 0;
171 current.position = mtc_frame;
172 current.timestamp = 0;
182 current.position = mtc_frame;
183 current.timestamp = 0;
191 MTC_Slave::read_current (SafeTime *st) const
196 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
204 } while (st->guard1 != st->guard2);
208 MTC_Slave::locked () const
210 return port->input()->mtc_locked();
214 MTC_Slave::ok() const
220 MTC_Slave::speed_and_position (float& speed, nframes_t& pos)
222 nframes_t now = session.engine().frame_time();
224 nframes_t frame_rate;
228 read_current (&last);
230 if (first_mtc_time == 0) {
236 /* no timecode for 1/4 second ? conclude that its stopped */
238 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
241 session.request_locate (pos, false);
242 update_mtc_status (MIDI::Parser::MTC_Stopped);
247 frame_rate = session.frame_rate();
249 speed_now = (float) ((last.position - first_mtc_frame) / (double) (now - first_mtc_time));
251 accumulator[accumulator_index++] = speed_now;
253 if (accumulator_index >= accumulator_size) {
254 have_first_accumulated_speed = true;
255 accumulator_index = 0;
258 if (have_first_accumulated_speed) {
261 for (int32_t i = 0; i < accumulator_size; ++i) {
262 total += accumulator[i];
265 mtc_speed = total / accumulator_size;
269 mtc_speed = speed_now;
273 if (mtc_speed == 0.0f) {
279 /* scale elapsed time by the current MTC speed */
281 if (last.timestamp && (now > last.timestamp)) {
282 elapsed = (nframes_t) floor (mtc_speed * (now - last.timestamp));
284 elapsed = 0; /* XXX is this right? */
288 /* now add the most recent timecode value plus the estimated elapsed interval */
290 pos = elapsed + last.position;
297 MTC_Slave::resolution() const
299 return (nframes_t) session.frames_per_smpte_frame();
305 /* XXX massive thread safety issue here. MTC could
306 be being updated as we call this. but this
307 supposed to be a realtime-safe call.
310 port->input()->reset_mtc_state ();
312 last_inbound_frame = 0;
314 current.position = 0;
315 current.timestamp = 0;
320 accumulator_index = 0;
321 have_first_accumulated_speed = false;