* fixed JACK_MidiPort to get the events into the slave
[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                   << " result: " << midi_clock_frame 
103                   << " open_ppqn_in_frames: " << one_ppqn_in_frames << std::endl;
104          */
105         
106         if (first_midi_clock_frame == 0) {
107                 first_midi_clock_frame = midi_clock_frame;
108                 first_midi_clock_time = now;
109         }
110
111         current.guard1++;
112         current.position = midi_clock_frame;
113         current.timestamp = now;
114         current.guard2++;
115
116         last_inbound_frame = now;
117 }
118
119 void
120 MIDIClock_Slave::start (Parser& parser)
121 {
122         std::cerr << "MIDIClock_Slave got start message" << endl;
123
124         midi_clock_speed = 1.0f;
125         _started = true;
126 }
127
128 void
129 MIDIClock_Slave::stop (Parser& parser)
130 {
131         std::cerr << "MIDIClock_Slave got stop message" << endl;
132
133         midi_clock_speed = 0.0f;
134         _started = false;
135 }
136
137 void
138 MIDIClock_Slave::read_current (SafeTime *st) const
139 {
140         int tries = 0;
141         do {
142                 if (tries == 10) {
143                         error << _("MIDI Clock Slave: atomic read of current time failed, sleeping!") << endmsg;
144                         usleep (20);
145                         tries = 0;
146                 }
147
148                 *st = current;
149                 tries++;
150
151         } while (st->guard1 != st->guard2);
152 }
153
154 bool
155 MIDIClock_Slave::locked () const
156 {
157         return true;
158 }
159
160 bool
161 MIDIClock_Slave::ok() const
162 {
163         return true;
164 }
165
166 bool
167 MIDIClock_Slave::speed_and_position (float& speed, nframes_t& pos)
168 {
169         //std::cerr << "MIDIClock_Slave speed and position() called" << endl;
170
171         nframes_t now = session.engine().frame_time();
172         nframes_t frame_rate = session.frame_rate();
173         nframes_t elapsed;
174         float speed_now;
175
176         SafeTime last;
177         read_current (&last);
178
179         if (first_midi_clock_time == 0) {
180                 speed = 0;
181                 pos = last.position;
182                 return true;
183         }
184
185         /* no timecode for 1/4 second ? conclude that its stopped */
186
187         if (last_inbound_frame && now > last_inbound_frame && now - last_inbound_frame > frame_rate / 4) {
188                 midi_clock_speed = 0;
189                 pos = last.position;
190                 session.request_locate (pos, false);
191                 session.request_transport_speed (0);
192                 this->stop(*port->input());
193                 reset();
194                 return false;
195         }
196
197         speed_now = (float) ((last.position - first_midi_clock_frame) / (double) (now - first_midi_clock_time));
198
199         cerr << "speed_and_position: speed_now: " << speed_now ;
200         
201         accumulator[accumulator_index++] = speed_now;
202
203         if (accumulator_index >= accumulator_size) {
204                 have_first_accumulated_speed = true;
205                 accumulator_index = 0;
206         }
207
208         if (have_first_accumulated_speed) {
209                 float total = 0;
210
211                 for (int32_t i = 0; i < accumulator_size; ++i) {
212                         total += accumulator[i];
213                 }
214
215                 midi_clock_speed = total / accumulator_size;
216
217         } else {
218
219                 midi_clock_speed = speed_now;
220
221         }
222
223         if (midi_clock_speed == 0.0f) {
224
225                 elapsed = 0;
226
227         } else {
228
229                 /* scale elapsed time by the current MIDI Clock speed */
230
231                 if (last.timestamp && (now > last.timestamp)) {
232                         elapsed = (nframes_t) floor (midi_clock_speed * (now - last.timestamp));
233                 } else {
234                         elapsed = 0; /* XXX is this right? */
235                 }
236         }
237
238         /* now add the most recent timecode value plus the estimated elapsed interval */
239
240         pos =  elapsed + last.position;
241
242         speed = midi_clock_speed;
243         
244         cerr << " final speed: " << speed << " position: " << pos << endl;
245         return true;
246 }
247
248 ARDOUR::nframes_t
249 MIDIClock_Slave::resolution() const
250 {
251         return (nframes_t) one_ppqn_in_frames;
252 }
253
254 void
255 MIDIClock_Slave::reset ()
256 {
257         /* XXX massive thread safety issue here. MTC could
258            be being updated as we call this. but this
259            supposed to be a realtime-safe call.
260         */
261
262         last_inbound_frame = 0;
263         current.guard1++;
264         current.position = 0;
265         current.timestamp = 0;
266         current.guard2++;
267         first_midi_clock_frame = 0;
268         first_midi_clock_time = 0;
269
270         accumulator_index = 0;
271         have_first_accumulated_speed = false;
272         midi_clock_speed = 0;
273 }