ef900cededc113202e4b2540f7e124af8c066d08
[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_midi_clock_frame_duration (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         #ifdef DEBUG_MIDI_CLOCK         
71                 std::cerr << "MIDIClock_Slave: connecting to port " << port->name() << std::endl;
72         #endif
73
74         connections.push_back (port->input()->timing.connect   (mem_fun (*this, &MIDIClock_Slave::update_midi_clock)));
75         connections.push_back (port->input()->start.connect    (mem_fun (*this, &MIDIClock_Slave::start)));
76         connections.push_back (port->input()->contineu.connect (mem_fun (*this, &MIDIClock_Slave::contineu)));
77         connections.push_back (port->input()->stop.connect     (mem_fun (*this, &MIDIClock_Slave::stop)));
78 }
79
80 void 
81 MIDIClock_Slave::calculate_one_ppqn_in_frames_at(nframes_t time)
82 {
83         const Tempo& current_tempo = session.tempo_map().tempo_at(time);
84         const Meter& current_meter = session.tempo_map().meter_at(time);
85         double frames_per_beat =
86                 current_tempo.frames_per_beat(session.frame_rate(),
87                                               current_meter);
88
89         double quarter_notes_per_beat = 4.0 / current_tempo.note_type();
90         double frames_per_quarter_note = frames_per_beat / quarter_notes_per_beat;
91
92         one_ppqn_in_frames = frames_per_quarter_note / double (ppqn);
93 }
94
95 void
96 MIDIClock_Slave::update_midi_clock (Parser& parser, nframes_t timestamp)
97 {                       
98         calculate_one_ppqn_in_frames_at(last_position);
99         
100         // for the first MIDI clock event we don't have any past
101         // data, so we assume a sane tempo
102         if(_starting) {
103                 current_midi_clock_frame_duration = one_ppqn_in_frames;
104         } else {
105                 current_midi_clock_frame_duration = timestamp - last_timestamp;
106         }
107                 
108         // moving average over incoming intervals
109         accumulator[accumulator_index++] = current_midi_clock_frame_duration;
110         if(accumulator_index == accumulator_size) {
111                 accumulator_index = 0;
112         }
113         average_midi_clock_frame_duration = 0.0;
114         for(int i = 0; i < accumulator_size; i++) {
115                 average_midi_clock_frame_duration += accumulator[i];
116         }
117         average_midi_clock_frame_duration /= double(accumulator_size);
118         
119         #ifdef DEBUG_MIDI_CLOCK         
120                 std::cerr 
121                                   << " got MIDI Clock message at time " << timestamp  
122                                   << " engine time: " << session.engine().frame_time() 
123                                   << " transport position: " << session.transport_frame()
124                                   << " real delta: " << current_midi_clock_frame_duration 
125                                   << " reference: " << one_ppqn_in_frames
126                                   << " average: " << average_midi_clock_frame_duration
127                                   << std::endl;
128         #endif // DEBUG_MIDI_CLOCK
129         
130         if (_starting) {
131                 assert(last_timestamp == 0);
132                 assert(last_position == 0);
133                 
134                 last_position = 0;
135                 last_timestamp = timestamp;
136                 
137                 // let ardour go after first MIDI Clock Event
138                 _starting = false;
139                 session.request_transport_speed (1.0);
140         } else {;
141                 last_position  += double(one_ppqn_in_frames);
142                 last_timestamp = timestamp;
143         }
144
145 }
146
147 void
148 MIDIClock_Slave::start (Parser& parser, nframes_t timestamp)
149 {       
150         #ifdef DEBUG_MIDI_CLOCK 
151                 cerr << "MIDIClock_Slave got start message at time "  <<  timestamp << " session time: " << session.engine().frame_time() << endl;
152         #endif
153         
154         if(!locked()) {
155                 cerr << "Did not start because not locked!" << endl;
156                 return;
157         }
158         
159         // initialize accumulator to sane values
160         calculate_one_ppqn_in_frames_at(0);
161         
162         for(int i = 0; i < accumulator_size; i++) {
163                 accumulator[i] = one_ppqn_in_frames;
164         }
165         
166         last_position = 0;
167         last_timestamp = 0;
168         
169         _started = true;
170         _starting = true;
171 }
172
173 void
174 MIDIClock_Slave::contineu (Parser& parser, nframes_t timestamp)
175 {
176         #ifdef DEBUG_MIDI_CLOCK 
177                 std::cerr << "MIDIClock_Slave got continue message" << endl;
178         #endif
179         start(parser, timestamp);
180 }
181
182
183 void
184 MIDIClock_Slave::stop (Parser& parser, nframes_t timestamp)
185 {
186         #ifdef DEBUG_MIDI_CLOCK 
187                 std::cerr << "MIDIClock_Slave got stop message" << endl;
188         #endif
189         
190         current_midi_clock_frame_duration = 0;
191
192         last_position = 0;
193         last_timestamp = 0;
194         
195         _started = false;
196         reset();
197 }
198
199 bool
200 MIDIClock_Slave::locked () const
201 {
202         return true;
203 }
204
205 bool
206 MIDIClock_Slave::ok() const
207 {
208         return true;
209 }
210
211 bool
212 MIDIClock_Slave::starting() const
213 {
214         return false;
215 }
216
217 bool
218 MIDIClock_Slave::stop_if_no_more_clock_events(nframes_t& pos, nframes_t now)
219 {
220         /* no timecode for 1/4 second ? conclude that its stopped */
221         if (last_timestamp && 
222             now > last_timestamp && 
223             now - last_timestamp > session.frame_rate() / 4) {
224         #ifdef DEBUG_MIDI_CLOCK                 
225                         cerr << "No MIDI Clock frames received for some time, stopping!" << endl;
226         #endif          
227                 pos = last_position;
228                 session.request_locate (pos, false);
229                 session.request_transport_speed (0);
230                 this->stop(*port->input(), now);
231                 reset();
232                 return true;
233         } else {
234                 return false;
235         }
236 }
237
238 bool
239 MIDIClock_Slave::speed_and_position (float& speed, nframes_t& pos)
240 {
241         if (!_started || _starting) {
242                 speed = 0.0;
243                 pos = 0;
244                 return true;
245         }
246                 
247         nframes_t engine_now = session.engine().frame_time();
248
249         if (stop_if_no_more_clock_events(pos, engine_now)) {
250                 return false;
251         }
252         
253         #ifdef DEBUG_MIDI_CLOCK 
254                 cerr << "speed_and_position: engine time: " << engine_now << " last message timestamp: " << last_timestamp;
255         #endif
256         
257         // calculate speed
258         double speed_double = one_ppqn_in_frames / average_midi_clock_frame_duration;
259         speed = float(speed_double);
260         
261     #ifdef DEBUG_MIDI_CLOCK     
262                 cerr << " final speed: " << speed;
263     #endif
264         
265         // calculate position
266         if (engine_now > last_timestamp) {
267                 // we are in between MIDI clock messages
268                 // so we interpolate position according to speed
269                 nframes_t elapsed = engine_now - last_timestamp;
270                 pos = nframes_t (last_position + double(elapsed) * speed_double);
271         } else {
272                 // A new MIDI clock message has arrived this cycle
273                 pos = last_position;
274         }
275         
276    #ifdef DEBUG_MIDI_CLOCK      
277            cerr << " transport position engine_now: " <<  session.transport_frame(); 
278            cerr << " calculated position: " << pos; 
279            cerr << endl;
280    #endif
281    
282         return true;
283 }
284
285 ARDOUR::nframes_t
286 MIDIClock_Slave::resolution() const
287 {
288         // one beat
289         return (nframes_t) one_ppqn_in_frames * ppqn;
290 }
291
292 void
293 MIDIClock_Slave::reset ()
294 {
295
296         last_position = 0;              
297         last_timestamp = 0;
298         
299         session.request_locate(0, false);
300 }