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