888ead0805d8e786d2906f9d6a3c88cc58823745
[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 <midi++/jack.h>
30 #include <ardour/slave.h>
31 #include <ardour/session.h>
32 #include <ardour/audioengine.h>
33 #include <ardour/cycles.h>
34 #include <ardour/tempo.h>
35
36
37 #include "i18n.h"
38
39 using namespace ARDOUR;
40 using namespace sigc;
41 using namespace MIDI;
42 using namespace PBD;
43
44 MIDIClock_Slave::MIDIClock_Slave (Session& s, MIDI::Port& p, int ppqn)
45         : session (s)
46         , ppqn (ppqn)
47         , accumulator_index (0)
48         , average (0.0)
49 {
50         rebind (p);
51         reset ();
52
53         for(int i = 0; i < accumulator_size; i++)
54                 accumulator[i]=0.0;
55 }
56
57 MIDIClock_Slave::~MIDIClock_Slave()
58 {
59 }
60
61 void
62 MIDIClock_Slave::rebind (MIDI::Port& p)
63 {
64         for (vector<sigc::connection>::iterator i = connections.begin(); i != connections.end(); ++i) {
65                 (*i).disconnect ();
66         }
67
68         port = &p;
69
70         std::cerr << "MIDIClock_Slave: connecting to port " << port->name() << std::endl;
71
72         connections.push_back (port->input()->timing.connect (mem_fun (*this, &MIDIClock_Slave::update_midi_clock)));
73         connections.push_back (port->input()->start.connect  (mem_fun (*this, &MIDIClock_Slave::start)));
74         connections.push_back (port->input()->stop.connect   (mem_fun (*this, &MIDIClock_Slave::stop)));
75 }
76
77 void
78 MIDIClock_Slave::update_midi_clock (Parser& parser, nframes_t timestamp)
79 {       
80         nframes_t now = timestamp;
81
82         SafeTime last;
83         read_current (&last);
84                 
85         const Tempo& current_tempo = session.tempo_map().tempo_at(now);
86         const Meter& current_meter = session.tempo_map().meter_at(now);
87         double frames_per_beat =
88                 current_tempo.frames_per_beat(session.frame_rate(),
89                                               current_meter);
90
91         double quarter_notes_per_beat = 4.0 / current_tempo.note_type();
92         double frames_per_quarter_note = frames_per_beat / quarter_notes_per_beat;
93
94         one_ppqn_in_frames = frames_per_quarter_note / ppqn;
95         
96         // for the first MIDI clock event we dont have any past
97         // data, so we assume a sane tempo
98         if(last.timestamp == 0) {
99                 midi_clock_frame = one_ppqn_in_frames;
100         } else {
101                 midi_clock_frame = now - last.timestamp;
102         }
103         
104         
105         // moving average over incoming intervals
106         accumulator[accumulator_index++] = (float) midi_clock_frame;
107         if(accumulator_index == accumulator_size)
108                 accumulator_index = 0;
109         
110         average = 0.0;
111         for(int i = 0; i < accumulator_size; i++)
112                 average += accumulator[i];
113         average /= accumulator_size;
114         
115         
116 #if 1
117         JACK_MidiPort *jack_port = dynamic_cast<JACK_MidiPort *>(port);
118         pthread_t process_thread_id = 0;
119         if(jack_port) {
120                 process_thread_id = jack_port->get_process_thread();
121         }
122         
123         std::cerr 
124                   << " got MIDI Clock message at time " << now  
125                   << " session time: " << session.engine().frame_time() 
126                   << " real delta: " << midi_clock_frame 
127                   << " reference: " << one_ppqn_in_frames
128                   << " average: " << average
129                   << std::endl;
130 #endif
131         
132         current.guard1++;
133         current.position += midi_clock_frame;
134         current.timestamp = now;
135         current.guard2++;
136
137         last_inbound_frame = now;
138 }
139
140 void
141 MIDIClock_Slave::start (Parser& parser, nframes_t timestamp)
142 {
143         
144         nframes_t now = timestamp;
145         cerr << "MIDIClock_Slave got start message at time "  <<  now 
146              << " session time: " << session.engine().frame_time() << endl;
147
148         if(!locked()) {
149                 cerr << "Did not start because not locked!" << endl;
150                 return;
151         }
152         
153         midi_clock_frame = 0;
154         
155         session.request_transport_speed(one_ppqn_in_frames / average);
156         current.guard1++;
157         current.position = 0;
158         current.timestamp = now;
159         current.guard2++;
160         
161         _started = true;
162 }
163
164 void
165 MIDIClock_Slave::stop (Parser& parser, nframes_t timestamp)
166 {
167         std::cerr << "MIDIClock_Slave got stop message" << endl;
168
169         midi_clock_frame = 0;
170
171         current.guard1++;
172         current.position = 0;
173         current.timestamp = 0;
174         current.guard2++;
175         
176         _started = false;
177         reset();
178 }
179
180 void
181 MIDIClock_Slave::read_current (SafeTime *st) const
182 {
183         int tries = 0;
184         do {
185                 if (tries == 10) {
186                         error << _("MIDI Clock Slave: atomic read of current time failed, sleeping!") << endmsg;
187                         usleep (20);
188                         tries = 0;
189                 }
190
191                 *st = current;
192                 tries++;
193
194         } while (st->guard1 != st->guard2);
195 }
196
197 bool
198 MIDIClock_Slave::locked () const
199 {
200         return true;
201 }
202
203 bool
204 MIDIClock_Slave::ok() const
205 {
206         return true;
207 }
208
209 bool
210 MIDIClock_Slave::speed_and_position (float& speed, nframes_t& pos)
211 {
212         
213         if(!_started) {
214                 speed = 0.0;
215                 pos = 0;
216                 return true;
217         }
218         
219         nframes_t now = session.engine().frame_time();
220         nframes_t frame_rate = session.frame_rate();
221
222         SafeTime last;
223         read_current (&last);
224
225         /* no timecode for 1/4 second ? conclude that its stopped */
226
227         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > frame_rate / 4) {
228                 cerr << "No MIDI Clock frames received for some time, stopping!" << endl;
229                 pos = last.position;
230                 session.request_locate (pos, false);
231                 session.request_transport_speed (0);
232                 this->stop(*port->input(), now);
233                 reset();
234                 return false;
235         }
236
237         cerr << " now: " << now << " last: " << last.timestamp;
238
239         speed = one_ppqn_in_frames / average;
240         cerr << " final speed: " << speed;
241         
242         if (now > last.timestamp) {
243                 // we are in between MIDI clock messages
244                 // so we interpolate position according to speed
245                 nframes_t elapsed = now - last.timestamp;
246                 cerr << " elapsed: " << elapsed << " elapsed (scaled)  " << elapsed * speed;
247                 pos = last.position + elapsed * speed;
248                 last.position = pos;
249         } else {
250                 // A new MIDI clock message has arrived this cycle              
251                 pos = last.position;
252         }
253         
254    cerr << " position: " << pos; 
255    cerr << endl;
256         
257         return true;
258 }
259
260 ARDOUR::nframes_t
261 MIDIClock_Slave::resolution() const
262 {
263         return (nframes_t) one_ppqn_in_frames * 24;
264 }
265
266 void
267 MIDIClock_Slave::reset ()
268 {
269
270         last_inbound_frame = 0;
271         current.guard1++;
272         current.position = 0;
273         current.timestamp = 0;
274         current.guard2++;
275         
276         session.request_locate(0, false);
277 }