new files from sakari, missed last time
[ardour.git] / libs / ardour / midi_clock_slave.cc
1 /*
2     Copyright (C) 2002-4 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <errno.h>
21 #include <poll.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <pbd/error.h>
25 #include <pbd/failed_constructor.h>
26 #include <pbd/pthread_utils.h>
27
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>
33 #include <ardour/tempo.h>
34
35 #include "i18n.h"
36
37 using namespace ARDOUR;
38 using namespace sigc;
39 using namespace MIDI;
40 using namespace PBD;
41
42 MIDIClock_Slave::MIDIClock_Slave (Session& s, MIDI::Port& p, int ppqn)
43         : session (s)
44         , ppqn (ppqn)
45 {
46         rebind (p);
47         reset ();
48 }
49
50 MIDIClock_Slave::~MIDIClock_Slave()
51 {
52 }
53
54 void
55 MIDIClock_Slave::rebind (MIDI::Port& p)
56 {
57         for (vector<sigc::connection>::iterator i = connections.begin(); i != connections.end(); ++i) {
58                 (*i).disconnect ();
59         }
60
61         port = &p;
62
63         std::cerr << "MIDIClock_Slave: connecting to port " << port->name() << std::endl;
64
65         connections.push_back (port->input()->timing.connect (mem_fun (*this, &MIDIClock_Slave::update_midi_clock)));
66         connections.push_back (port->input()->start.connect  (mem_fun (*this, &MIDIClock_Slave::start)));
67         connections.push_back (port->input()->stop.connect   (mem_fun (*this, &MIDIClock_Slave::stop)));
68 }
69
70 void
71 MIDIClock_Slave::update_midi_clock (Parser& parser)
72 {
73         // ignore clock events if no start event received
74         if(!_started)
75                 return;
76
77         nframes_t now = session.engine().frame_time();
78
79         SafeTime last;
80         read_current (&last);
81
82         const Tempo& current_tempo = session.tempo_map().tempo_at(now);
83         const Meter& current_meter = session.tempo_map().meter_at(now);
84         double frames_per_beat =
85                 current_tempo.frames_per_beat(session.nominal_frame_rate(),
86                                               current_meter);
87
88         double quarter_notes_per_beat = 4.0 / current_tempo.note_type();
89         double frames_per_quarter_note = frames_per_beat / quarter_notes_per_beat;
90
91         one_ppqn_in_frames = frames_per_quarter_note / ppqn;
92
93         /*
94            Also compensate for audio latency.
95         */
96
97         midi_clock_frame += (long) (one_ppqn_in_frames)
98                             + session.worst_output_latency();
99
100         /*
101         std::cerr << "got MIDI Clock message at time " << now  
102                   << " midi_clock_frame: " << midi_clock_frame 
103                   << " one_ppqn_in_frames: " << one_ppqn_in_frames << std::endl;
104         */
105         if (first_midi_clock_frame == 0) {
106                 first_midi_clock_frame = midi_clock_frame;
107                 first_midi_clock_time = now;
108         }
109
110         current.guard1++;
111         current.position = midi_clock_frame;
112         current.timestamp = now;
113         current.guard2++;
114
115         last_inbound_frame = now;
116 }
117
118 void
119 MIDIClock_Slave::start (Parser& parser)
120 {
121         std::cerr << "MIDIClock_Slave got start message" << endl;
122
123         session.request_transport_speed (1.0);
124         midi_clock_speed = 1.0;
125         _starting = true;
126         _started  = true;
127 }
128
129 void
130 MIDIClock_Slave::stop (Parser& parser)
131 {
132         std::cerr << "MIDIClock_Slave got stop message" << endl;
133
134         session.request_transport_speed (0);
135         midi_clock_speed = 0.0f;
136         midi_clock_frame = 0;
137         _starting = false;
138         _started = false;
139         reset();
140 }
141
142 void
143 MIDIClock_Slave::read_current (SafeTime *st) const
144 {
145         int tries = 0;
146         do {
147                 if (tries == 10) {
148                         error << _("MIDI Clock Slave: atomic read of current time failed, sleeping!") << endmsg;
149                         usleep (20);
150                         tries = 0;
151                 }
152
153                 *st = current;
154                 tries++;
155
156         } while (st->guard1 != st->guard2);
157 }
158
159 bool
160 MIDIClock_Slave::locked () const
161 {
162         return true;
163 }
164
165 bool
166 MIDIClock_Slave::ok() const
167 {
168         return true;
169 }
170
171 bool
172 MIDIClock_Slave::speed_and_position (float& speed, nframes_t& pos)
173 {
174         //std::cerr << "MIDIClock_Slave speed and position() called" << endl;
175         nframes_t now = session.engine().frame_time();
176         nframes_t frame_rate = session.frame_rate();
177         nframes_t elapsed;
178         float speed_now;
179
180         SafeTime last;
181         read_current (&last);
182
183         if (first_midi_clock_time == 0) {
184                 speed = 0;
185                 pos = last.position;
186                 return true;
187         }
188
189         /* no timecode for 1/4 second ? conclude that its stopped */
190
191         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > frame_rate / 4) {
192                 midi_clock_speed = 0;
193                 pos = last.position;
194                 session.request_locate (pos, false);
195                 session.request_transport_speed (0);
196                 this->stop(*port->input());
197                 reset();
198                 return false;
199         }
200
201         if(_starting) {
202                 speed_now = 1.0;
203                 _starting = false;
204         } else {
205                 speed_now = (float) ((last.position - first_midi_clock_frame) / (double) (now - first_midi_clock_time));
206         }
207
208         //cerr << "speed_and_position: speed_now: " << speed_now ;
209         
210         accumulator[accumulator_index++] = speed_now;
211
212         if (accumulator_index >= accumulator_size) {
213                 have_first_accumulated_speed = true;
214                 accumulator_index = 0;
215         }
216
217         if (have_first_accumulated_speed) {
218                 float total = 0;
219
220                 for (int32_t i = 0; i < accumulator_size; ++i) {
221                         total += accumulator[i];
222                 }
223
224                 midi_clock_speed = total / accumulator_size;
225
226         } else {
227
228                 midi_clock_speed = speed_now;
229
230         }
231
232         if (midi_clock_speed == 0.0f) {
233
234                 elapsed = 0;
235
236         } else {
237
238                 /* scale elapsed time by the current MIDI Clock speed */
239
240                 if (last.timestamp && (now > last.timestamp)) {
241                         elapsed = (nframes_t) floor (midi_clock_speed * (now - last.timestamp));
242                 } else {
243                         elapsed = 0; /* XXX is this right? */
244                 }
245         }
246
247         /* now add the most recent timecode value plus the estimated elapsed interval */
248
249         pos =  elapsed + last.position;
250
251         speed = midi_clock_speed;
252         
253         //cerr << " final speed: " << speed << " position: " << pos << endl;
254         return true;
255 }
256
257 ARDOUR::nframes_t
258 MIDIClock_Slave::resolution() const
259 {
260         return (nframes_t) one_ppqn_in_frames;
261 }
262
263 void
264 MIDIClock_Slave::reset ()
265 {
266         /* XXX massive thread safety issue here. MTC could
267            be being updated as we call this. but this
268            supposed to be a realtime-safe call.
269         */
270
271         last_inbound_frame = 0;
272         current.guard1++;
273         current.position = 0;
274         current.timestamp = 0;
275         current.guard2++;
276         first_midi_clock_frame = 0;
277         first_midi_clock_time = 0;
278
279         midi_clock_speed = 0;
280 }