Disable non-realtime midi ports in windows build - THIS NEEDS FIXING
[ardour.git] / libs / midi++2 / jack_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 #include <iostream>
21 #include <cstdio>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25
26 #include <jack/jack.h>
27 #include <jack/midiport.h>
28
29 #include "pbd/xml++.h"
30 #include "pbd/error.h"
31 #include "pbd/failed_constructor.h"
32 #include "pbd/convert.h"
33 #include "pbd/strsplit.h"
34 #include "pbd/stacktrace.h"
35
36 #include "midi++/types.h"
37 #include "midi++/jack_midi_port.h"
38 #include "midi++/channel.h"
39
40 using namespace MIDI;
41 using namespace std;
42 using namespace PBD;
43
44 namespace Evoral {
45 template class EventRingBuffer<timestamp_t>;
46 }
47
48 pthread_t JackMIDIPort::_process_thread;
49 Signal0<void> JackMIDIPort::JackHalted;
50 Signal0<void> JackMIDIPort::MakeConnections;
51
52 JackMIDIPort::JackMIDIPort (string const & name, Flags flags, jack_client_t* jack_client)
53         : Port (name, flags)
54         , _currently_in_cycle (false)
55         , _nframes_this_cycle (0)
56         , _jack_client (jack_client)
57         , _jack_port (0)
58         , _last_write_timestamp (0)
59         , output_fifo (512)
60         , input_fifo (1024)
61 #ifndef WIN32
62         , xthread (true)
63 #endif
64 {
65         assert (jack_client);
66         init (name, flags);
67 }
68
69 JackMIDIPort::JackMIDIPort (const XMLNode& node, jack_client_t* jack_client)
70         : Port (node)
71         , _currently_in_cycle (false)
72         , _nframes_this_cycle (0)
73         , _jack_client (jack_client)
74         , _jack_port (0)
75         , _last_write_timestamp (0)
76         , output_fifo (512)
77         , input_fifo (1024)
78 #ifndef WIN32
79         , xthread (true)
80 #endif
81 {
82         assert (jack_client);
83
84         Descriptor desc (node);
85         init (desc.tag, desc.flags);
86         set_state (node);
87 }
88
89 void
90 JackMIDIPort::init (const string& /*name*/, Flags /*flags*/)
91 {
92         if (!create_port ()) {
93                 _ok = true;
94         }
95
96         MakeConnections.connect_same_thread (connect_connection, boost::bind (&JackMIDIPort::make_connections, this));
97         JackHalted.connect_same_thread (halt_connection, boost::bind (&JackMIDIPort::jack_halted, this));
98 }
99
100
101 JackMIDIPort::~JackMIDIPort ()
102 {
103         if (_jack_port) {
104                 if (_jack_client) {
105                         jack_port_unregister (_jack_client, _jack_port);
106                         _jack_port = 0;
107                 }
108         }
109 }
110
111 void
112 JackMIDIPort::parse (framecnt_t timestamp)
113 {
114         byte buf[512];
115
116         /* NOTE: parsing is done (if at all) by initiating a read from 
117            the port. Each port implementation calls on the parser
118            once it has data ready.
119         */
120         
121         _parser->set_timestamp (timestamp);
122
123         while (1) {
124                 
125                 // cerr << "+++ READ ON " << name() << endl;
126
127                 int nread = read (buf, sizeof (buf));
128
129                 // cerr << "-- READ (" << nread << " ON " << name() << endl;
130                 
131                 if (nread > 0) {
132                         if ((size_t) nread < sizeof (buf)) {
133                                 break;
134                         } else {
135                                 continue;
136                         }
137                 } else if (nread == 0) {
138                         break;
139                 } else if (errno == EAGAIN) {
140                         break;
141                 } else {
142                         fatal << "Error reading from MIDI port " << name() << endmsg;
143                         /*NOTREACHED*/
144                 }
145         }
146 }
147
148 void
149 JackMIDIPort::cycle_start (pframes_t nframes)
150 {
151         assert (_jack_port);
152         
153         _currently_in_cycle = true;
154         _nframes_this_cycle = nframes;
155
156         assert(_nframes_this_cycle == nframes);
157
158         if (sends_output()) {
159                 void *buffer = jack_port_get_buffer (_jack_port, nframes);
160                 jack_midi_clear_buffer (buffer);
161                 flush (buffer); 
162         }
163         
164         if (receives_input()) {
165                 void* jack_buffer = jack_port_get_buffer(_jack_port, nframes);
166                 const pframes_t event_count = jack_midi_get_event_count(jack_buffer);
167
168                 jack_midi_event_t ev;
169                 timestamp_t cycle_start_frame = jack_last_frame_time (_jack_client);
170
171                 for (pframes_t i = 0; i < event_count; ++i) {
172                         jack_midi_event_get (&ev, jack_buffer, i);
173                         input_fifo.write (cycle_start_frame + ev.time, (Evoral::EventType) 0, ev.size, ev.buffer);
174                 }       
175                 
176                 if (event_count) {
177 #ifndef WIN32
178                         xthread.wakeup ();
179 #endif
180                 }
181         }
182 }
183
184 void
185 JackMIDIPort::cycle_end ()
186 {
187         if (sends_output()) {
188                 flush (jack_port_get_buffer (_jack_port, _nframes_this_cycle));
189         }
190
191         _currently_in_cycle = false;
192         _nframes_this_cycle = 0;
193 }
194
195 void
196 JackMIDIPort::jack_halted ()
197 {
198         _jack_client = 0;
199         _jack_port = 0;
200 }
201
202 void
203 JackMIDIPort::drain (int check_interval_usecs)
204 {
205         RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
206
207         if (is_process_thread()) {
208                 error << "Process thread called MIDI::JackMIDIPort::drain() - this cannot work" << endmsg;
209                 return;
210         }
211
212         while (1) {
213                 output_fifo.get_write_vector (&vec);
214                 if (vec.len[0] + vec.len[1] >= output_fifo.bufsize() - 1) {
215                         break;
216                 }
217                 usleep (check_interval_usecs);
218         }
219 }
220
221 int
222 JackMIDIPort::write (const byte * msg, size_t msglen, timestamp_t timestamp)
223 {
224         int ret = 0;
225
226         if (!_jack_client || !_jack_port) {
227                 /* poof ! make it just vanish into thin air, since we are no
228                    longer connected to JACK.
229                 */
230                 return msglen;
231         }
232
233         if (!sends_output()) {
234                 return ret;
235         }
236         
237         if (!is_process_thread()) {
238
239                 Glib::Threads::Mutex::Lock lm (output_fifo_lock);
240                 RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
241                 
242                 output_fifo.get_write_vector (&vec);
243
244                 if (vec.len[0] + vec.len[1] < 1) {
245                         error << "no space in FIFO for non-process thread MIDI write" << endmsg;
246                         return 0;
247                 }
248
249                 if (vec.len[0]) {
250                         if (!vec.buf[0]->owns_buffer()) {
251                                 vec.buf[0]->set_buffer (0, 0, true);
252                         }
253                         vec.buf[0]->set (msg, msglen, timestamp);
254                 } else {
255                         if (!vec.buf[1]->owns_buffer()) {
256                                 vec.buf[1]->set_buffer (0, 0, true);
257                         }
258                         vec.buf[1]->set (msg, msglen, timestamp);
259                 }
260
261                 output_fifo.increment_write_idx (1);
262                 
263                 ret = msglen;
264
265         } else {
266
267                 if (timestamp >= _nframes_this_cycle) {
268                         std::cerr << "attempting to write MIDI event of " << msglen << " bytes at time "
269                                   << timestamp << " of " << _nframes_this_cycle
270                                   << " (this will not work - needs a code fix)"
271                                   << std::endl;
272                 }
273
274                 if (_currently_in_cycle) {
275                         if (timestamp == 0) {
276                                 timestamp = _last_write_timestamp;
277                         } 
278
279                         if ((ret = jack_midi_event_write (jack_port_get_buffer (_jack_port, _nframes_this_cycle), 
280                                                           timestamp, msg, msglen)) == 0) {
281                                 ret = msglen;
282                                 _last_write_timestamp = timestamp;
283
284                         } else {
285                                 cerr << "write of " << msglen << " @ " << timestamp << " failed, port holds "
286                                         << jack_midi_get_event_count (jack_port_get_buffer (_jack_port, _nframes_this_cycle))
287                                      << " port is " << _jack_port
288                                      << " ntf = " << _nframes_this_cycle
289                                      << " buf = " << jack_port_get_buffer (_jack_port, _nframes_this_cycle)
290                                      << " ret = " << ret
291                                      << endl;
292                                 PBD::stacktrace (cerr, 20);
293                                 ret = 0;
294                         }
295                 } else {
296                         cerr << "write to JACK midi port failed: not currently in a process cycle." << endl;
297                         PBD::stacktrace (cerr, 20);
298                 }
299         }
300
301         if (ret > 0 && _parser) {
302                 // ardour doesn't care about this and neither should your app, probably
303                 // output_parser->raw_preparse (*output_parser, msg, ret);
304                 for (int i = 0; i < ret; i++) {
305                         _parser->scanner (msg[i]);
306                 }
307                 // ardour doesn't care about this and neither should your app, probably
308                 // output_parser->raw_postparse (*output_parser, msg, ret);
309         }       
310
311         return ret;
312 }
313
314 void
315 JackMIDIPort::flush (void* jack_port_buffer)
316 {
317         RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } };
318         size_t written;
319
320         output_fifo.get_read_vector (&vec);
321
322         if (vec.len[0] + vec.len[1]) {
323                 // cerr << "Flush " << vec.len[0] + vec.len[1] << " events from non-process FIFO\n";
324         }
325
326         if (vec.len[0]) {
327                 Evoral::Event<double>* evp = vec.buf[0];
328                 
329                 for (size_t n = 0; n < vec.len[0]; ++n, ++evp) {
330                         jack_midi_event_write (jack_port_buffer,
331                                                (timestamp_t) evp->time(), evp->buffer(), evp->size());
332                 }
333         }
334         
335         if (vec.len[1]) {
336                 Evoral::Event<double>* evp = vec.buf[1];
337
338                 for (size_t n = 0; n < vec.len[1]; ++n, ++evp) {
339                         jack_midi_event_write (jack_port_buffer,
340                                                (timestamp_t) evp->time(), evp->buffer(), evp->size());
341                 }
342         }
343         
344         if ((written = vec.len[0] + vec.len[1]) != 0) {
345                 output_fifo.increment_read_idx (written);
346         }
347 }
348
349 int
350 JackMIDIPort::read (byte *, size_t)
351 {
352         if (!receives_input()) {
353                 return 0;
354         }
355         
356         timestamp_t time;
357         Evoral::EventType type;
358         uint32_t size;
359         byte buffer[input_fifo.capacity()];
360
361         while (input_fifo.read (&time, &type, &size, buffer)) {
362                 _parser->set_timestamp (time);
363                 for (uint32_t i = 0; i < size; ++i) {
364                         _parser->scanner (buffer[i]);
365                 }
366         }
367
368         return 0;
369 }
370
371 int
372 JackMIDIPort::create_port ()
373 {
374         _jack_port = jack_port_register(_jack_client, _tagname.c_str(), JACK_DEFAULT_MIDI_TYPE, _flags, 0);
375         return _jack_port == 0 ? -1 : 0;
376 }
377
378 XMLNode& 
379 JackMIDIPort::get_state () const
380 {
381         XMLNode& root = Port::get_state ();
382         
383 #if 0
384         byte device_inquiry[6];
385
386         device_inquiry[0] = 0xf0;
387         device_inquiry[0] = 0x7e;
388         device_inquiry[0] = 0x7f;
389         device_inquiry[0] = 0x06;
390         device_inquiry[0] = 0x02;
391         device_inquiry[0] = 0xf7;
392         
393         write (device_inquiry, sizeof (device_inquiry), 0);
394 #endif
395
396         if (_jack_port) {
397                 
398                 const char** jc = jack_port_get_connections (_jack_port);
399                 string connection_string;
400                 if (jc) {
401                         for (int i = 0; jc[i]; ++i) {
402                                 if (i > 0) {
403                                         connection_string += ',';
404                                 }
405                                 connection_string += jc[i];
406                         }
407                         free (jc);
408                 }
409                 
410                 if (!connection_string.empty()) {
411                         root.add_property ("connections", connection_string);
412                 }
413         } else {
414                 if (!_connections.empty()) {
415                         root.add_property ("connections", _connections);
416                 }
417         }
418
419         return root;
420 }
421
422 void
423 JackMIDIPort::set_state (const XMLNode& node)
424 {
425         const XMLProperty* prop;
426
427         if ((prop = node.property ("tag")) == 0 || prop->value() != _tagname) {
428                 return;
429         }
430         
431         Port::set_state (node);
432
433         if ((prop = node.property ("connections")) != 0) {
434                 _connections = prop->value ();
435         }
436 }
437
438 void
439 JackMIDIPort::make_connections ()
440 {
441         if (!_connections.empty()) {
442                 vector<string> ports;
443                 split (_connections, ports, ',');
444                 for (vector<string>::iterator x = ports.begin(); x != ports.end(); ++x) {
445                         if (_jack_client) {
446                                 if (receives_input()) {
447                                         jack_connect (_jack_client, (*x).c_str(), jack_port_name (_jack_port));
448                                 } else {
449                                         jack_connect (_jack_client, jack_port_name (_jack_port), (*x).c_str());
450                                 }
451                                 /* ignore failures */
452                         }
453                 }
454         }
455
456         connect_connection.disconnect ();
457 }
458
459 void
460 JackMIDIPort::set_process_thread (pthread_t thr)
461 {
462         _process_thread = thr;
463 }
464
465 bool
466 JackMIDIPort::is_process_thread()
467 {
468         return (pthread_equal(pthread_self(), _process_thread));
469 }
470
471 void
472 JackMIDIPort::reestablish (jack_client_t* jack)
473 {
474         _jack_client = jack;
475         int const r = create_port ();
476
477         if (r) {
478                 PBD::error << "could not reregister ports for " << name() << endmsg;
479         }
480 }
481
482 void
483 JackMIDIPort::reconnect ()
484 {
485         make_connections ();
486 }