Add option to limit automatable control parmaters
[ardour.git] / libs / ardour / async_midi_port.cc
1 /*
2     Copyright (C) 1998 Paul Barton-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     $Id$
19 */
20
21 #include <iostream>
22 #include <vector>
23
24 #include <glibmm/timer.h>
25
26 #include "pbd/error.h"
27 #include "pbd/stacktrace.h"
28
29 #include "midi++/types.h"
30
31 #include "ardour/async_midi_port.h"
32 #include "ardour/audioengine.h"
33 #include "ardour/midi_buffer.h"
34
35 using namespace MIDI;
36 using namespace ARDOUR;
37 using namespace std;
38 using namespace PBD;
39
40 pthread_t AsyncMIDIPort::_process_thread;
41
42 #define port_engine AudioEngine::instance()->port_engine()
43
44 AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags)
45         : MidiPort (name, flags)
46         , MIDI::Port (name, MIDI::Port::Flags (0))
47         , _currently_in_cycle (false)
48         , _last_write_timestamp (0)
49         , _flush_at_cycle_start (false)
50         , have_timer (false)
51         , output_fifo (2048)
52         , input_fifo (1024)
53         , _xthread (true)
54 {
55 }
56
57 AsyncMIDIPort::~AsyncMIDIPort ()
58 {
59 }
60
61 void
62 AsyncMIDIPort::set_timer (boost::function<MIDI::samplecnt_t (void)>& f)
63 {
64         timer = f;
65         have_timer = true;
66 }
67
68 void
69 AsyncMIDIPort::flush_output_fifo (MIDI::pframes_t nframes)
70 {
71         RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } };
72         size_t written = 0;
73
74         output_fifo.get_read_vector (&vec);
75
76         MidiBuffer& mb (get_midi_buffer (nframes));
77
78         if (vec.len[0]) {
79                 Evoral::Event<double>* evp = vec.buf[0];
80
81                 assert (evp->size());
82                 assert (evp->buffer());
83
84                 for (size_t n = 0; n < vec.len[0]; ++n, ++evp) {
85                         if (mb.push_back (evp->time(), evp->size(), evp->buffer())) {
86                                 written++;
87                         }
88                 }
89         }
90
91         if (vec.len[1]) {
92                 Evoral::Event<double>* evp = vec.buf[1];
93
94                 assert (evp->size());
95                 assert (evp->buffer());
96
97                 for (size_t n = 0; n < vec.len[1]; ++n, ++evp) {
98                         if (mb.push_back (evp->time(), evp->size(), evp->buffer())) {
99                                 written++;
100                         }
101                 }
102         }
103
104         /* do this "atomically" after we're done pushing events into the
105          * MidiBuffer
106          */
107
108         output_fifo.increment_read_idx (written);
109 }
110
111 void
112 AsyncMIDIPort::cycle_start (MIDI::pframes_t nframes)
113 {
114         _currently_in_cycle = true;
115         MidiPort::cycle_start (nframes);
116
117         /* dump anything waiting in the output FIFO at the start of the port
118          * buffer
119          */
120
121         if (ARDOUR::Port::sends_output()) {
122                 flush_output_fifo (nframes);
123                 if (_flush_at_cycle_start) {
124                         flush_buffers (nframes);
125                 }
126         }
127
128         /* copy incoming data from the port buffer into the input FIFO
129            and if necessary wakeup the reader
130         */
131
132         if (ARDOUR::Port::receives_input()) {
133                 MidiBuffer& mb (get_midi_buffer (nframes));
134                 samplecnt_t when;
135
136                 if (have_timer) {
137                         when = timer ();
138                 } else {
139                         when = AudioEngine::instance()->sample_time_at_cycle_start();
140                 }
141
142                 for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) {
143                         if (!have_timer) {
144                                 when += (*b).time();
145                         }
146                         input_fifo.write (when, Evoral::NO_EVENT, (*b).size(), (*b).buffer());
147                 }
148
149                 if (!mb.empty()) {
150                         _xthread.wakeup ();
151                 }
152
153         }
154 }
155
156 void
157 AsyncMIDIPort::cycle_end (MIDI::pframes_t nframes)
158 {
159         if (ARDOUR::Port::sends_output() && !_flush_at_cycle_start) {
160                 /* move any additional data from output FIFO into the port
161                    buffer.
162                 */
163                 flush_output_fifo (nframes);
164         }
165
166         MidiPort::cycle_end (nframes);
167
168         _currently_in_cycle = false;
169 }
170
171 /** wait for the output FIFO to be emptied by successive process() callbacks.
172  *
173  * Cannot be called from a processing thread.
174  */
175 void
176 AsyncMIDIPort::drain (int check_interval_usecs, int total_usecs_to_wait)
177 {
178         RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
179
180         if (!AudioEngine::instance()->running() || AudioEngine::instance()->session() == 0) {
181                 /* no more process calls - it will never drain */
182                 return;
183         }
184
185
186         if (is_process_thread()) {
187                 error << "Process thread called MIDI::AsyncMIDIPort::drain() - this cannot work" << endmsg;
188                 return;
189         }
190
191         microseconds_t now = get_microseconds ();
192         microseconds_t end = now + total_usecs_to_wait;
193
194         while (now < end) {
195                 output_fifo.get_write_vector (&vec);
196                 if (vec.len[0] + vec.len[1] >= output_fifo.bufsize() - 1) {
197                         break;
198                 }
199                 Glib::usleep (check_interval_usecs);
200                 now = get_microseconds();
201         }
202 }
203
204 int
205 AsyncMIDIPort::write (const MIDI::byte * msg, size_t msglen, MIDI::timestamp_t timestamp)
206 {
207         int ret = 0;
208
209         if (!ARDOUR::Port::sends_output()) {
210                 return ret;
211         }
212
213         if (!is_process_thread()) {
214
215                 /* this is the best estimate of "when" this MIDI data is being
216                  * delivered
217                  */
218
219                 _parser->set_timestamp (AudioEngine::instance()->sample_time() + timestamp);
220                 for (size_t n = 0; n < msglen; ++n) {
221                         _parser->scanner (msg[n]);
222                 }
223
224                 Glib::Threads::Mutex::Lock lm (output_fifo_lock);
225                 RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
226
227                 output_fifo.get_write_vector (&vec);
228
229                 if (vec.len[0] + vec.len[1] < 1) {
230                         error << "no space in FIFO for non-process thread MIDI write" << endmsg;
231                         return 0;
232                 }
233
234                 if (vec.len[0]) {
235                         /* force each event inside the ringbuffer to own its
236                            own buffer, but let that be null and of zero size
237                            initially. When ::set() is called, the buffer will
238                            be allocated to hold a *copy* of the data we're
239                            storing, and then that buffer will be used over and
240                            over, occasionally being upwardly resized as
241                            necessary.
242                         */
243                         if (!vec.buf[0]->owns_buffer()) {
244                                 vec.buf[0]->set_buffer (0, 0, true);
245                         }
246                         vec.buf[0]->set (msg, msglen, timestamp);
247                 } else {
248                         /* see comment in previous branch of if() statement */
249                         if (!vec.buf[1]->owns_buffer()) {
250                                 vec.buf[1]->set_buffer (0, 0, true);
251                         }
252                         vec.buf[1]->set (msg, msglen, timestamp);
253                 }
254
255                 output_fifo.increment_write_idx (1);
256
257                 ret = msglen;
258
259         } else {
260
261                 _parser->set_timestamp (AudioEngine::instance()->sample_time_at_cycle_start() + timestamp);
262                 for (size_t n = 0; n < msglen; ++n) {
263                         _parser->scanner (msg[n]);
264                 }
265
266                 if (timestamp >= _cycle_nframes) {
267                         std::cerr << "attempting to write MIDI event of " << msglen << " MIDI::bytes at time "
268                                   << timestamp << " of " << _cycle_nframes
269                                   << " (this will not work - needs a code fix)"
270                                   << std::endl;
271                 }
272
273                 /* This is the process thread, which makes checking
274                  * _currently_in_cycle atomic and safe, since it is only
275                  * set from cycle_start() and cycle_end(), also called
276                  * only from the process thread.
277                  */
278
279                 if (_currently_in_cycle) {
280
281                         MidiBuffer& mb (get_midi_buffer (_cycle_nframes));
282
283                         if (timestamp == 0) {
284                                 timestamp = _last_write_timestamp;
285                         }
286
287                         if (mb.push_back (timestamp, msglen, msg)) {
288                                 ret = msglen;
289                                 _last_write_timestamp = timestamp;
290
291                         } else {
292                                 cerr << "AsyncMIDIPort (" << ARDOUR::Port::name() << "): write of " << msglen << " @ " << timestamp << " failed\n" << endl;
293                                 PBD::stacktrace (cerr, 20);
294                                 ret = 0;
295                         }
296                 } else {
297                         cerr << "write to JACK midi port failed: not currently in a process cycle." << endl;
298                         PBD::stacktrace (cerr, 20);
299                 }
300         }
301
302         return ret;
303 }
304
305
306 int
307 AsyncMIDIPort::read (MIDI::byte *, size_t)
308 {
309         if (!ARDOUR::Port::receives_input()) {
310                 return 0;
311         }
312
313         timestamp_t time;
314         Evoral::EventType type;
315         uint32_t size;
316         vector<MIDI::byte> buffer(input_fifo.capacity());
317
318         while (input_fifo.read (&time, &type, &size, &buffer[0])) {
319                 _parser->set_timestamp (time);
320                 for (uint32_t i = 0; i < size; ++i) {
321                         _parser->scanner (buffer[i]);
322                 }
323         }
324
325         return 0;
326 }
327
328 void
329 AsyncMIDIPort::parse (MIDI::samplecnt_t)
330 {
331         MIDI::byte buf[1];
332
333         /* see ::read() to realize why buf is not used */
334         read (buf, sizeof (buf));
335 }
336
337 void
338 AsyncMIDIPort::set_process_thread (pthread_t thr)
339 {
340         _process_thread = thr;
341 }
342
343 bool
344 AsyncMIDIPort::is_process_thread()
345 {
346         return pthread_equal (pthread_self(), _process_thread);
347 }
348