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;
41 MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
48 MTC_Slave::~MTC_Slave()
53 MTC_Slave::rebind (MIDI::Port& p)
55 for (vector<sigc::connection>::iterator i = connections.begin(); i != connections.end(); ++i) {
61 connections.push_back (port->input()->mtc_time.connect (mem_fun (*this, &MTC_Slave::update_mtc_time)));
62 connections.push_back (port->input()->mtc_qtr.connect (mem_fun (*this, &MTC_Slave::update_mtc_qtr)));
63 connections.push_back (port->input()->mtc_status.connect (mem_fun (*this, &MTC_Slave::update_mtc_status)));
67 MTC_Slave::update_mtc_qtr (Parser& p)
69 cycles_t cnow = get_cycles ();
70 jack_nframes_t now = session.engine().frame_time();
72 static cycles_t last_qtr = 0;
74 qtr = (long) (session.frames_per_smpte_frame() / 4);
79 current.position = mtc_frame;
80 current.timestamp = now;
83 last_inbound_frame = now;
87 MTC_Slave::update_mtc_time (const byte *msg, bool was_full)
89 jack_nframes_t now = session.engine().frame_time();
93 smpte.minutes = msg[2];
94 smpte.seconds = msg[1];
95 smpte.frames = msg[0];
97 session.smpte_to_sample( smpte, mtc_frame, true, false );
102 current.position = mtc_frame;
103 current.timestamp = 0;
106 session.request_locate (mtc_frame, false);
107 update_mtc_status (MIDI::Parser::MTC_Stopped);
113 /* We received the last quarter frame 7 quarter frames (1.75 mtc
114 frames) after the instance when the contents of the mtc quarter
115 frames were decided. Add time to compensate for the elapsed 1.75
117 Also compensate for audio latency.
120 mtc_frame += (long) (1.75 * session.frames_per_smpte_frame()) + session.worst_output_latency();
122 if (first_mtc_frame == 0) {
123 first_mtc_frame = mtc_frame;
124 first_mtc_time = now;
128 current.position = mtc_frame;
129 current.timestamp = now;
133 last_inbound_frame = now;
137 MTC_Slave::handle_locate (const MIDI::byte* mmc_tc)
141 mtc[3] = mmc_tc[0] & 0xf; /* hrs only */
146 update_mtc_time (mtc, true);
150 MTC_Slave::update_mtc_status (MIDI::Parser::MTC_Status status)
159 current.position = mtc_frame;
160 current.timestamp = 0;
170 current.position = mtc_frame;
171 current.timestamp = 0;
181 current.position = mtc_frame;
182 current.timestamp = 0;
190 MTC_Slave::read_current (SafeTime *st) const
195 error << _("MTC Slave: atomic read of current time failed, sleeping!") << endmsg;
203 } while (st->guard1 != st->guard2);
207 MTC_Slave::locked () const
209 return port->input()->mtc_locked();
213 MTC_Slave::ok() const
219 MTC_Slave::speed_and_position (float& speed, jack_nframes_t& pos)
221 jack_nframes_t now = session.engine().frame_time();
223 jack_nframes_t frame_rate;
224 jack_nframes_t elapsed;
227 read_current (&last);
229 if (first_mtc_time == 0) {
235 /* no timecode for 1/4 second ? conclude that its stopped */
237 if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > session.frame_rate() / 4) {
240 session.request_locate (pos, false);
241 update_mtc_status (MIDI::Parser::MTC_Stopped);
246 frame_rate = session.frame_rate();
248 speed_now = (float) ((last.position - first_mtc_frame) / (double) (now - first_mtc_time));
250 accumulator[accumulator_index++] = speed_now;
252 if (accumulator_index >= accumulator_size) {
253 have_first_accumulated_speed = true;
254 accumulator_index = 0;
257 if (have_first_accumulated_speed) {
260 for (int32_t i = 0; i < accumulator_size; ++i) {
261 total += accumulator[i];
264 mtc_speed = total / accumulator_size;
268 mtc_speed = speed_now;
272 if (mtc_speed == 0.0f) {
278 /* scale elapsed time by the current MTC speed */
280 if (last.timestamp && (now > last.timestamp)) {
281 elapsed = (jack_nframes_t) floor (mtc_speed * (now - last.timestamp));
283 elapsed = 0; /* XXX is this right? */
287 /* now add the most recent timecode value plus the estimated elapsed interval */
289 pos = elapsed + last.position;
296 MTC_Slave::resolution() const
298 return (jack_nframes_t) session.frames_per_smpte_frame();
304 /* XXX massive thread safety issue here. MTC could
305 be being updated as we call this. but this
306 supposed to be a realtime-safe call.
309 port->input()->reset_mtc_state ();
311 last_inbound_frame = 0;
313 current.position = 0;
314 current.timestamp = 0;
319 accumulator_index = 0;
320 have_first_accumulated_speed = false;