fix gcc4.4 compile warning
[ardour.git] / libs / midi++2 / jack_midiport.cc
index 0eb867ebe72b963a8a9716fd57ad0ffd2c93f886..ba675082a4d496392241ddd7b58433a6a512b889 100644 (file)
 #include <fcntl.h>
 #include <cerrno>
 #include <cassert>
+#include <cstring>
+#include <cstdlib>
 
-#include <pbd/error.h>
+#include "pbd/error.h"
+#include "pbd/compose.h"
+#include "pbd/strsplit.h"
 
-#include <midi++/types.h>
-#include <midi++/jack.h>
+#include "midi++/types.h"
+#include "midi++/jack.h"
 
 using namespace std;
 using namespace MIDI;
@@ -32,24 +36,51 @@ using namespace PBD;
 
 pthread_t JACK_MidiPort::_process_thread;
 
+Signal0<void> JACK_MidiPort::JackHalted;
+Signal0<void> JACK_MidiPort::MakeConnections;
+
 JACK_MidiPort::JACK_MidiPort(const XMLNode& node, jack_client_t* jack_client)
        : Port(node)
        , _jack_client(jack_client)
        , _jack_input_port(NULL)
        , _jack_output_port(NULL)
        , _last_read_index(0)
-       , non_process_thread_fifo (512)
+       , output_fifo (512)
+       , input_fifo (1024)
 {
-       int err = create_ports (node);
-
-       if (!err) {
+       if (!create_ports (node)) {
                _ok = true;
-       } 
+       }
+
+       MakeConnections.connect_same_thread (connect_connection, boost::bind (&JACK_MidiPort::make_connections, this));
+       JackHalted.connect_same_thread (halt_connection, boost::bind (&JACK_MidiPort::jack_halted, this));
+
+       set_state (node);
 }
 
 JACK_MidiPort::~JACK_MidiPort()
 {
-       // FIXME: remove port
+       if (_jack_input_port) {
+               if (_jack_client) {
+                       jack_port_unregister (_jack_client, _jack_input_port);
+               }
+               _jack_input_port = 0;
+       }
+
+       if (_jack_output_port) {
+               if (_jack_client) {
+                       jack_port_unregister (_jack_client, _jack_input_port);
+               }
+               _jack_input_port = 0;
+       }
+}
+
+void
+JACK_MidiPort::jack_halted ()
+{
+       _jack_client = 0;
+       _jack_input_port = 0;
+       _jack_output_port = 0;
 }
 
 void
@@ -73,26 +104,27 @@ JACK_MidiPort::cycle_start (nframes_t nframes)
                const nframes_t event_count = jack_midi_get_event_count(jack_buffer);
 
                jack_midi_event_t ev;
+               timestamp_t cycle_start_frame = jack_last_frame_time (_jack_client);
 
-               for (nframes_t i=0; i < event_count; ++i) {
-
+               for (nframes_t i = 0; i < event_count; ++i) {
                        jack_midi_event_get (&ev, jack_buffer, i);
-
-                       if (input_parser) {
-                               for (size_t i = 0; i < ev.size; i++) {
-                                       // the midi events here are used for MIDI clock only
-                                       input_parser->set_midi_clock_timestamp(ev.time + jack_last_frame_time(_jack_client));
-                                       input_parser->scanner (ev.buffer[i]);
-                               }       
-                       }
+                       input_fifo.write (cycle_start_frame + ev.time, (Evoral::EventType) 0, ev.size, ev.buffer);
                }       
+               
+               if (event_count) {
+                       xthread.wakeup ();
+               }
        }
 }
 
 void
 JACK_MidiPort::cycle_end ()
 {
-       flush(jack_port_get_buffer(_jack_output_port, _nframes_this_cycle));
+       if (_jack_output_port != 0) {
+               flush (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle));
+       }
+
+       Port::cycle_end();
 }
 
 int
@@ -102,10 +134,10 @@ JACK_MidiPort::write(byte * msg, size_t msglen, timestamp_t timestamp)
 
        if (!is_process_thread()) {
 
-               Glib::Mutex::Lock lm (non_process_thread_fifo_lock);
+               Glib::Mutex::Lock lm (output_fifo_lock);
                RingBuffer< Evoral::Event<double> >::rw_vector vec;
                
-               non_process_thread_fifo.get_write_vector (&vec);
+               output_fifo.get_write_vector (&vec);
 
                if (vec.len[0] + vec.len[1] < 1) {
                        error << "no space in FIFO for non-process thread MIDI write" << endmsg;
@@ -113,15 +145,21 @@ JACK_MidiPort::write(byte * msg, size_t msglen, timestamp_t timestamp)
                }
 
                if (vec.len[0]) {
+                        if (!vec.buf[0]->owns_buffer()) {
+                                vec.buf[0]->set_buffer (0, 0, true);
+                        }
                        vec.buf[0]->set (msg, msglen, timestamp);
                } else {
+                        if (!vec.buf[1]->owns_buffer()) {
+                                vec.buf[1]->set_buffer (0, 0, true);
+                        }
                        vec.buf[1]->set (msg, msglen, timestamp);
                }
 
-               non_process_thread_fifo.increment_write_idx (1);
+               output_fifo.increment_write_idx (1);
                
                ret = msglen;
-                               
+
        } else {
 
                assert(_jack_output_port);
@@ -153,11 +191,13 @@ JACK_MidiPort::write(byte * msg, size_t msglen, timestamp_t timestamp)
        }
 
        if (ret > 0 && output_parser) {
-               output_parser->raw_preparse (*output_parser, msg, ret);
+               // ardour doesn't care about this and neither should your app, probably
+               // output_parser->raw_preparse (*output_parser, msg, ret);
                for (int i = 0; i < ret; i++) {
                        output_parser->scanner (msg[i]);
                }
-               output_parser->raw_postparse (*output_parser, msg, ret);
+               // ardour doesn't care about this and neither should your app, probably
+               // output_parser->raw_postparse (*output_parser, msg, ret);
        }       
 
        return ret;
@@ -169,10 +209,10 @@ JACK_MidiPort::flush (void* jack_port_buffer)
        RingBuffer< Evoral::Event<double> >::rw_vector vec;
        size_t written;
 
-       non_process_thread_fifo.get_read_vector (&vec);
+       output_fifo.get_read_vector (&vec);
 
        if (vec.len[0] + vec.len[1]) {
-               cerr << "Flush " << vec.len[0] + vec.len[1] << " events from non-process FIFO\n";
+               // cerr << "Flush " << vec.len[0] + vec.len[1] << " events from non-process FIFO\n";
        }
 
        if (vec.len[0]) {
@@ -194,42 +234,28 @@ JACK_MidiPort::flush (void* jack_port_buffer)
        }
        
        if ((written = vec.len[0] + vec.len[1]) != 0) {
-               non_process_thread_fifo.increment_read_idx (written);
+               output_fifo.increment_read_idx (written);
        }
 }
 
 int
-JACK_MidiPort::read(byte * buf, size_t bufsize)
+JACK_MidiPort::read (byte *, size_t)
 {
-       assert(_currently_in_cycle);
-       assert(_jack_input_port);
-       
-       jack_midi_event_t ev;
-
-       cerr << "JACK_MidiPort::read called" << endl;
-       
-       int err = jack_midi_event_get (&ev,
-                                      jack_port_get_buffer(_jack_input_port, _nframes_this_cycle),
-                                      _last_read_index++);
-       
-       // XXX this doesn't handle ev.size > max
-
-       if (!err) {
-               size_t limit = min (bufsize, ev.size);
-               memcpy(buf, ev.buffer, limit);
+       timestamp_t time;
+       Evoral::EventType type;
+       uint32_t size;
+       byte buffer[input_fifo.capacity()];
 
+       while (input_fifo.read (&time, &type, &size, buffer)) {
                if (input_parser) {
-                       input_parser->raw_preparse (*input_parser, buf, limit);
-                       for (size_t i = 0; i < limit; i++) {
-                               input_parser->scanner (buf[i]);
-                       }       
-                       input_parser->raw_postparse (*input_parser, buf, limit);
+                       input_parser->set_timestamp (time);
+                       for (uint32_t i = 0; i < size; ++i) {
+                               input_parser->scanner (buffer[i]);
+                       }
                }
-
-               return limit;
-       } else {
-               return 0;
        }
+
+       return 0;
 }
 
 int
@@ -271,12 +297,96 @@ XMLNode&
 JACK_MidiPort::get_state () const
 {
        XMLNode& root (Port::get_state ());
+
+       if (_jack_output_port) {
+               
+               const char** jc = jack_port_get_connections (_jack_output_port);
+               string connection_string;
+               if (jc) {
+                       for (int i = 0; jc[i]; ++i) {
+                               if (i > 0) {
+                                       connection_string += ',';
+                               }
+                               connection_string += jc[i];
+                       }
+                       free (jc);
+               }
+               
+               if (!connection_string.empty()) {
+                       root.add_property ("outbound", connection_string);
+               }
+       } else {
+               if (!_outbound_connections.empty()) {
+                       root.add_property ("outbound", _outbound_connections);
+               }
+       }
+
+       if (_jack_input_port) {
+
+               const char** jc = jack_port_get_connections (_jack_input_port);
+               string connection_string;
+               if (jc) {
+                       for (int i = 0; jc[i]; ++i) {
+                               if (i > 0) {
+                                       connection_string += ',';
+                               }
+                               connection_string += jc[i];
+                       }
+                       free (jc);
+               }
+
+               if (!connection_string.empty()) {
+                       root.add_property ("inbound", connection_string);
+               }
+       } else {
+               if (!_inbound_connections.empty()) {
+                       root.add_property ("inbound", _inbound_connections);
+               }
+       }
+
        return root;
 }
 
 void
 JACK_MidiPort::set_state (const XMLNode& node)
 {
+       Port::set_state (node);
+       const XMLProperty* prop;
+
+       if ((prop = node.property ("inbound")) != 0 && _jack_input_port) {
+               _inbound_connections = prop->value ();
+       }
+
+       if ((prop = node.property ("outbound")) != 0 && _jack_output_port) {
+               _outbound_connections = prop->value();
+       }
+}
+
+void
+JACK_MidiPort::make_connections ()
+{
+       if (!_inbound_connections.empty()) {
+               vector<string> ports;
+               split (_inbound_connections, ports, ',');
+               for (vector<string>::iterator x = ports.begin(); x != ports.end(); ++x) {
+                       if (_jack_client) {
+                               jack_connect (_jack_client, (*x).c_str(), jack_port_name (_jack_input_port));
+                               /* ignore failures */
+                       }
+               }
+       }
+
+       if (!_outbound_connections.empty()) {
+               vector<string> ports;
+               split (_outbound_connections, ports, ',');
+               for (vector<string>::iterator x = ports.begin(); x != ports.end(); ++x) {
+                       if (_jack_client) {
+                               jack_connect (_jack_client, jack_port_name (_jack_output_port), (*x).c_str());
+                               /* ignore failures */
+                       }
+               }
+       }
+       connect_connection.disconnect ();
 }
 
 void