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