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