From 91850f0eb4ab9f63bc6582d042d5495ea1968031 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 6 Jul 2010 00:16:36 +0000 Subject: Remove non-JACK midi++ ports. git-svn-id: svn://localhost/ardour2/branches/3.0@7377 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/rc_option_editor.cc | 2 - libs/ardour/ardour/ticker.h | 5 +- libs/ardour/audioengine.cc | 10 +- libs/ardour/midi_clock_slave.cc | 1 - libs/ardour/midi_ui.cc | 4 +- libs/ardour/session.cc | 4 +- libs/ardour/ticker.cc | 13 +- libs/midi++2/alsa_sequencer_midiport.cc | 429 --------------------- libs/midi++2/coremidi_midiport.cc | 157 -------- libs/midi++2/factory.cc | 128 +------ libs/midi++2/fd_midiport.cc | 181 --------- libs/midi++2/fifomidi.cc | 44 --- libs/midi++2/jack_midiport.cc | 433 --------------------- libs/midi++2/manager.cc | 28 +- libs/midi++2/midi++/alsa_rawmidi.h | 52 --- libs/midi++2/midi++/alsa_sequencer.h | 76 ---- libs/midi++2/midi++/coremidi_midiport.h | 79 ---- libs/midi++2/midi++/factory.h | 43 --- libs/midi++2/midi++/fd_midiport.h | 91 ----- libs/midi++2/midi++/fifomidi.h | 52 --- libs/midi++2/midi++/jack.h | 117 ------ libs/midi++2/midi++/manager.h | 2 - libs/midi++2/midi++/nullmidi.h | 68 ---- libs/midi++2/midi++/port.h | 140 +++---- libs/midi++2/port.cc | 478 ++++++++++++++++++++---- libs/midi++2/wscript | 14 +- libs/surfaces/mackie/mackie_control_protocol.cc | 22 +- libs/surfaces/mackie/surface_port.cc | 2 - 28 files changed, 504 insertions(+), 2171 deletions(-) delete mode 100644 libs/midi++2/alsa_sequencer_midiport.cc delete mode 100644 libs/midi++2/coremidi_midiport.cc delete mode 100644 libs/midi++2/fd_midiport.cc delete mode 100644 libs/midi++2/fifomidi.cc delete mode 100644 libs/midi++2/jack_midiport.cc delete mode 100644 libs/midi++2/midi++/alsa_rawmidi.h delete mode 100644 libs/midi++2/midi++/alsa_sequencer.h delete mode 100644 libs/midi++2/midi++/coremidi_midiport.h delete mode 100644 libs/midi++2/midi++/factory.h delete mode 100644 libs/midi++2/midi++/fd_midiport.h delete mode 100644 libs/midi++2/midi++/fifomidi.h delete mode 100644 libs/midi++2/midi++/jack.h delete mode 100644 libs/midi++2/midi++/nullmidi.h diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index 14fca7a417..ec3af3e745 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -8,7 +8,6 @@ #include "pbd/cpus.h" #include "midi++/manager.h" -#include "midi++/factory.h" #include "ardour/audioengine.h" #include "ardour/dB.h" @@ -209,7 +208,6 @@ private: node.add_property ("tag", dialog.port_name.get_text()); node.add_property ("device", X_("ardour")); // XXX this can't be right for all types - node.add_property ("type", MIDI::PortFactory::default_port_type()); node.add_property ("mode", smod); if (MIDI::Manager::instance()->add_port (node) != 0) { diff --git a/libs/ardour/ardour/ticker.h b/libs/ardour/ardour/ticker.h index e133ad5d23..f5cda677ed 100644 --- a/libs/ardour/ardour/ticker.h +++ b/libs/ardour/ardour/ticker.h @@ -19,7 +19,6 @@ */ -#include "midi++/jack.h" #include "pbd/signals.h" #include "ardour/types.h" @@ -29,6 +28,10 @@ #ifndef TICKER_H_ #define TICKER_H_ +namespace MIDI { + class Port; +} + namespace ARDOUR { diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index b9ec8e465b..33a76fa7b4 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -32,7 +32,7 @@ #include "pbd/stacktrace.h" #include "pbd/unknown_type.h" -#include "midi++/jack.h" +#include "midi++/port.h" #include "midi++/mmc.h" #include "midi++/manager.h" @@ -147,7 +147,7 @@ _thread_init_callback (void * /*arg*/) SessionEvent::create_per_thread_pool (X_("Audioengine"), 512); - MIDI::JACK_MidiPort::set_process_thread (pthread_self()); + MIDI::Port::set_process_thread (pthread_self()); MIDI::MachineControl::set_sending_thread (pthread_self ()); } @@ -263,7 +263,7 @@ AudioEngine::stop (bool forever) } else { jack_deactivate (_priv_jack); Stopped(); /* EMIT SIGNAL */ - MIDI::JACK_MidiPort::JackHalted (); /* EMIT SIGNAL */ + MIDI::Port::JackHalted (); /* EMIT SIGNAL */ } } @@ -1074,7 +1074,7 @@ AudioEngine::halted (void *arg) if (was_running) { ae->Halted(""); /* EMIT SIGNAL */ - MIDI::JACK_MidiPort::JackHalted (); /* EMIT SIGNAL */ + MIDI::Port::JackHalted (); /* EMIT SIGNAL */ } } @@ -1358,7 +1358,7 @@ AudioEngine::disconnect_from_jack () if (_running) { _running = false; Stopped(); /* EMIT SIGNAL */ - MIDI::JACK_MidiPort::JackHalted (); /* EMIT SIGNAL */ + MIDI::Port::JackHalted (); /* EMIT SIGNAL */ } return 0; diff --git a/libs/ardour/midi_clock_slave.cc b/libs/ardour/midi_clock_slave.cc index c4ee65dd6b..a1682127d8 100644 --- a/libs/ardour/midi_clock_slave.cc +++ b/libs/ardour/midi_clock_slave.cc @@ -28,7 +28,6 @@ #include "pbd/pthread_utils.h" #include "midi++/port.h" -#include "midi++/jack.h" #include "ardour/debug.h" #include "ardour/slave.h" diff --git a/libs/ardour/midi_ui.cc b/libs/ardour/midi_ui.cc index be13209513..5d9407d579 100644 --- a/libs/ardour/midi_ui.cc +++ b/libs/ardour/midi_ui.cc @@ -104,9 +104,7 @@ MidiControlUI::midi_input_handler (IOCondition ioc, MIDI::Port* port) if (ioc & IO_IN) { - if (port->must_drain_selectable()) { - CrossThreadChannel::drain (port->selectable()); - } + CrossThreadChannel::drain (port->selectable()); DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", port->name())); nframes64_t now = _session.engine().frame_time(); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 4fdcb6f5f9..dd6a453080 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -98,7 +98,7 @@ #include "ardour/utils.h" #include "ardour/graph.h" -#include "midi++/jack.h" +#include "midi++/port.h" #include "midi++/mmc.h" #include "i18n.h" @@ -645,7 +645,7 @@ Session::hookup_io () /* Tell all IO objects to connect themselves together */ IO::enable_connecting (); - MIDI::JACK_MidiPort::MakeConnections (); + MIDI::Port::MakeConnections (); /* Now reset all panners */ diff --git a/libs/ardour/ticker.cc b/libs/ardour/ticker.cc index dbe81ae32c..4327e25c72 100644 --- a/libs/ardour/ticker.cc +++ b/libs/ardour/ticker.cc @@ -18,6 +18,8 @@ $Id$ */ +#include "midi++/port.h" +#include "evoral/midi_events.h" #include "ardour/ticker.h" #include "ardour/session.h" #include "ardour/tempo.h" @@ -138,9 +140,6 @@ void MidiClockTicker::tick(const nframes_t& transport_frames, const BBT_Time& /* if (!Config->get_send_midi_clock() || _session == 0 || _session->transport_speed() != 1.0f || _midi_port == 0) return; - MIDI::JACK_MidiPort* jack_port = dynamic_cast(_midi_port); - assert(jack_port); - while (true) { double next_tick = _last_tick + one_ppqn_in_frames(transport_frames); nframes_t next_tick_offset = nframes_t(next_tick) - transport_frames; @@ -150,11 +149,11 @@ void MidiClockTicker::tick(const nframes_t& transport_frames, const BBT_Time& /* << ":Last tick time:" << _last_tick << ":" << ":Next tick time:" << next_tick << ":" << "Offset:" << next_tick_offset << ":" - << "cycle length:" << jack_port->nframes_this_cycle() + << "cycle length:" << _midi_port->nframes_this_cycle() << endl; #endif - if (next_tick_offset >= jack_port->nframes_this_cycle()) + if (next_tick_offset >= _midi_port->nframes_this_cycle()) return; send_midi_clock_event(next_tick_offset); @@ -183,9 +182,7 @@ void MidiClockTicker::send_midi_clock_event(nframes_t offset) return; } -#ifdef WITH_JACK_MIDI - assert (MIDI::JACK_MidiPort::is_process_thread()); -#endif // WITH_JACK_MIDI + assert (MIDI::Port::is_process_thread()); #ifdef DEBUG_MIDI_CLOCK cerr << "Tick with offset " << offset << endl; #endif // DEBUG_MIDI_CLOCK diff --git a/libs/midi++2/alsa_sequencer_midiport.cc b/libs/midi++2/alsa_sequencer_midiport.cc deleted file mode 100644 index 4a6dc6b3ea..0000000000 --- a/libs/midi++2/alsa_sequencer_midiport.cc +++ /dev/null @@ -1,429 +0,0 @@ -/* - Copyright (C) 2004 Paul Davis - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - $Id$ -*/ - -#include -#include - -#include "pbd/failed_constructor.h" -#include "pbd/error.h" -#include "pbd/xml++.h" - -#include "midi++/types.h" -#include "midi++/alsa_sequencer.h" - -#include "i18n.h" - -//#define DOTRACE 1 - -#ifdef DOTRACE -#define TR_FN() (cerr << __FUNCTION__ << endl) -#define TR_VAL(v) (cerr << __FILE__ " " << __LINE__ << " " #v "=" << v << endl) -#else -#define TR_FN() -#define TR_VAL(v) -#endif - -using namespace std; -using namespace MIDI; -using namespace PBD; - -snd_seq_t* ALSA_SequencerMidiPort::seq = 0; - -ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (const XMLNode& node) - : Port (node) - , decoder (0) - , encoder (0) - , port_id (-1) -{ - TR_FN(); - int err; - Descriptor desc (node); - - if (!seq && init_client (desc.device) < 0) { - _ok = false; - - } else { - - if (0 <= (err = create_ports (desc)) && - 0 <= (err = snd_midi_event_new (1024, &decoder)) && // Length taken from ARDOUR::Session::midi_read () - 0 <= (err = snd_midi_event_new (64, &encoder))) { // Length taken from ARDOUR::Session::mmc_buffer - snd_midi_event_init (decoder); - snd_midi_event_init (encoder); - _ok = true; - } - } - - set_state (node); -} - -ALSA_SequencerMidiPort::~ALSA_SequencerMidiPort () -{ - if (decoder) { - snd_midi_event_free (decoder); - } - if (encoder) { - snd_midi_event_free (encoder); - } - if (port_id >= 0) { - snd_seq_delete_port (seq, port_id); - } -} - -int -ALSA_SequencerMidiPort::selectable () const -{ - struct pollfd pfd[1]; - if (0 <= snd_seq_poll_descriptors (seq, pfd, 1, POLLIN | POLLOUT)) { - return pfd[0].fd; - } - return -1; -} - -int -ALSA_SequencerMidiPort::write (byte *msg, size_t msglen, timestamp_t ignored) -{ - TR_FN (); - int R; - int totwritten = 0; - snd_midi_event_reset_encode (encoder); - int nwritten = snd_midi_event_encode (encoder, msg, msglen, &SEv); - TR_VAL (nwritten); - while (0 < nwritten) { - if (0 <= (R = snd_seq_event_output (seq, &SEv)) && - 0 <= (R = snd_seq_drain_output (seq))) { - bytes_written += nwritten; - totwritten += nwritten; - if (output_parser) { - output_parser->raw_preparse (*output_parser, msg, nwritten); - for (int i = 0; i < nwritten; i++) { - output_parser->scanner (msg[i]); - } - output_parser->raw_postparse (*output_parser, msg, nwritten); - } - } else { - TR_VAL(R); - return R; - } - - msglen -= nwritten; - msg += nwritten; - if (msglen > 0) { - nwritten = snd_midi_event_encode (encoder, msg, msglen, &SEv); - TR_VAL(nwritten); - } - else { - break; - } - } - - return totwritten; -} - -int -ALSA_SequencerMidiPort::read (byte *buf, size_t max) -{ - TR_FN(); - int err; - snd_seq_event_t *ev; - if (0 <= (err = snd_seq_event_input (seq, &ev))) { - TR_VAL(err); - err = snd_midi_event_decode (decoder, buf, max, ev); - } - - if (err > 0) { - bytes_read += err; - - if (input_parser) { - input_parser->raw_preparse (*input_parser, buf, err); - for (int i = 0; i < err; i++) { - input_parser->scanner (buf[i]); - } - input_parser->raw_postparse (*input_parser, buf, err); - } - } - return -ENOENT == err ? 0 : err; -} - -int -ALSA_SequencerMidiPort::create_ports (const Port::Descriptor& desc) -{ - int err; - unsigned int caps = 0; - - if (desc.mode == O_WRONLY || desc.mode == O_RDWR) - caps |= SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; - if (desc.mode == O_RDONLY || desc.mode == O_RDWR) - caps |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; - - if (0 <= (err = snd_seq_create_simple_port (seq, desc.tag.c_str(), caps, - (SND_SEQ_PORT_TYPE_MIDI_GENERIC| - SND_SEQ_PORT_TYPE_SOFTWARE| - SND_SEQ_PORT_TYPE_APPLICATION)))) { - - port_id = err; - - snd_seq_ev_clear (&SEv); - snd_seq_ev_set_source (&SEv, port_id); - snd_seq_ev_set_subs (&SEv); - snd_seq_ev_set_direct (&SEv); - - return 0; - } - - return err; -} - -int -ALSA_SequencerMidiPort::init_client (std::string name) -{ - static bool called = false; - - if (called) { - return -1; - } - - called = true; - - if (snd_seq_open (&seq, "default", SND_SEQ_OPEN_DUPLEX, 0) >= 0) { - snd_seq_set_client_name (seq, name.c_str()); - return 0; - } else { - warning << "The ALSA MIDI system is not available. No ports based on it will be created" - << endmsg; - return -1; - } -} - -int -ALSA_SequencerMidiPort::discover (vector& ports) -{ - int n = 0; - - snd_seq_client_info_t *client_info; - snd_seq_port_info_t *port_info; - - snd_seq_client_info_alloca (&client_info); - snd_seq_port_info_alloca (&port_info); - snd_seq_client_info_set_client (client_info, -1); - - while (snd_seq_query_next_client(seq, client_info) >= 0) { - - int alsa_client; - - if ((alsa_client = snd_seq_client_info_get_client(client_info)) <= 0) { - break; - } - - snd_seq_port_info_set_client(port_info, alsa_client); - snd_seq_port_info_set_port(port_info, -1); - - char client[256]; - snprintf (client, sizeof (client), "%d:%s", alsa_client, snd_seq_client_info_get_name(client_info)); - - ports.push_back (PortSet (client)); - - while (snd_seq_query_next_port(seq, port_info) >= 0) { - -#if 0 - int type = snd_seq_port_info_get_type(pinfo); - if (!(type & SND_SEQ_PORT_TYPE_PORT)) { - continue; - } -#endif - - unsigned int port_capability = snd_seq_port_info_get_capability(port_info); - - if ((port_capability & SND_SEQ_PORT_CAP_NO_EXPORT) == 0) { - - int alsa_port = snd_seq_port_info_get_port(port_info); - - char port[256]; - snprintf (port, sizeof (port), "%d:%s", alsa_port, snd_seq_port_info_get_name(port_info)); - - std::string mode; - - if (port_capability & SND_SEQ_PORT_CAP_READ) { - if (port_capability & SND_SEQ_PORT_CAP_WRITE) { - mode = "duplex"; - } else { - mode = "output"; - } - } else if (port_capability & SND_SEQ_PORT_CAP_WRITE) { - if (port_capability & SND_SEQ_PORT_CAP_READ) { - mode = "duplex"; - } else { - mode = "input"; - } - } - - XMLNode node (X_("MIDI-port")); - node.add_property ("device", client); - node.add_property ("tag", port); - node.add_property ("mode", mode); - node.add_property ("type", "alsa/sequencer"); - - ports.back().ports.push_back (node); - ++n; - } - } - } - - return n; -} - -void -ALSA_SequencerMidiPort::get_connections (vector& connections, int dir) const -{ - snd_seq_query_subscribe_t *subs; - snd_seq_addr_t seq_addr; - - snd_seq_query_subscribe_alloca (&subs); - - // Get port connections... - - if (dir) { - snd_seq_query_subscribe_set_type(subs, SND_SEQ_QUERY_SUBS_WRITE); - } else { - snd_seq_query_subscribe_set_type(subs, SND_SEQ_QUERY_SUBS_READ); - } - - snd_seq_query_subscribe_set_index(subs, 0); - seq_addr.client = snd_seq_client_id (seq); - seq_addr.port = port_id; - snd_seq_query_subscribe_set_root(subs, &seq_addr); - - while (snd_seq_query_port_subscribers(seq, subs) >= 0) { - - if (snd_seq_query_subscribe_get_time_real (subs)) { - /* interesting connection */ - - seq_addr = *snd_seq_query_subscribe_get_addr (subs); - - connections.push_back (SequencerPortAddress (seq_addr.client, - seq_addr.port)); - } - - snd_seq_query_subscribe_set_index(subs, snd_seq_query_subscribe_get_index(subs) + 1); - } -} - -XMLNode& -ALSA_SequencerMidiPort::get_state () const -{ - XMLNode& root (Port::get_state ()); - vector connections; - XMLNode* sub = 0; - char buf[256]; - - get_connections (connections, 1); - - if (!connections.empty()) { - if (!sub) { - sub = new XMLNode (X_("connections")); - } - for (vector::iterator i = connections.begin(); i != connections.end(); ++i) { - XMLNode* cnode = new XMLNode (X_("read")); - snprintf (buf, sizeof (buf), "%d:%d", i->first, i->second); - cnode->add_property ("dest", buf); - sub->add_child_nocopy (*cnode); - } - } - - connections.clear (); - get_connections (connections, 0); - - if (!connections.empty()) { - if (!sub) { - sub = new XMLNode (X_("connections")); - } - for (vector::iterator i = connections.begin(); i != connections.end(); ++i) { - XMLNode* cnode = new XMLNode (X_("write")); - snprintf (buf, sizeof (buf), "%d:%d", i->first, i->second); - cnode->add_property ("dest", buf); - sub->add_child_nocopy (*cnode); - } - } - - if (sub) { - root.add_child_nocopy (*sub); - } - - return root; -} - -void -ALSA_SequencerMidiPort::set_state (const XMLNode& node) -{ - Port::set_state (node); - - XMLNodeList children (node.children()); - XMLNodeIterator iter; - - for (iter = children.begin(); iter != children.end(); ++iter) { - - if ((*iter)->name() == X_("connections")) { - - XMLNodeList gchildren ((*iter)->children()); - XMLNodeIterator gciter; - - for (gciter = gchildren.begin(); gciter != gchildren.end(); ++gciter) { - XMLProperty* prop; - - if ((prop = (*gciter)->property ("dest")) != 0) { - int client; - int port; - - if (sscanf (prop->value().c_str(), "%d:%d", &client, &port) == 2) { - - snd_seq_port_subscribe_t *sub; - snd_seq_addr_t seq_addr; - - snd_seq_port_subscribe_alloca(&sub); - - if ((*gciter)->name() == X_("write")) { - - seq_addr.client = snd_seq_client_id (seq); - seq_addr.port = port_id; - snd_seq_port_subscribe_set_sender(sub, &seq_addr); - - seq_addr.client = client; - seq_addr.port = port; - snd_seq_port_subscribe_set_dest(sub, &seq_addr); - - } else { - - seq_addr.client = snd_seq_client_id (seq); - seq_addr.port = port_id; - snd_seq_port_subscribe_set_dest(sub, &seq_addr); - - seq_addr.client = client; - seq_addr.port = port; - snd_seq_port_subscribe_set_sender(sub, &seq_addr); - } - - snd_seq_subscribe_port (seq, sub); - } - } - } - - break; - } - } -} diff --git a/libs/midi++2/coremidi_midiport.cc b/libs/midi++2/coremidi_midiport.cc deleted file mode 100644 index 4349ea45f4..0000000000 --- a/libs/midi++2/coremidi_midiport.cc +++ /dev/null @@ -1,157 +0,0 @@ -/* - Copyright (C) 2004 Paul Davis - Copyright (C) 2004 Grame - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include - -#include "midi++/coremidi_midiport.h" -#include "midi++/types.h" -#include - -#include "pbd/pthread_utils.h" - -using namespace std; -using namespace MIDI; - -MIDITimeStamp CoreMidi_MidiPort::MIDIGetCurrentHostTime() -{ - return mach_absolute_time(); -} - -CoreMidi_MidiPort::CoreMidi_MidiPort (const XMLNode& node) : Port (node) -{ - Descriptor desc (node); - - firstrecv = true; - int err; - if (0 == (err = Open(desc))) { - _ok = true; - } -} - -CoreMidi_MidiPort::~CoreMidi_MidiPort () {Close();} - -void CoreMidi_MidiPort::Close () -{ - if (midi_destination) MIDIEndpointDispose(midi_destination); - if (midi_source) MIDIEndpointDispose(midi_source); - if (midi_client) MIDIClientDispose(midi_client); -} - -int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t ignored) -{ - OSStatus err; - MIDIPacketList* pktlist = (MIDIPacketList*)midi_buffer; - MIDIPacket* packet = MIDIPacketListInit(pktlist); - packet = MIDIPacketListAdd(pktlist,sizeof(midi_buffer),packet,MIDIGetCurrentHostTime(),msglen,msg); - - if (packet) { - - err = MIDIReceived(midi_source,pktlist); - if (err != noErr) { - //error << "MIDIReceived error" << err << endmsg. - } - - bytes_written += msglen; - return msglen; - }else{ - return 0; - } -} - -int CoreMidi_MidiPort::Open (const Descriptor& desc) -{ - OSStatus err; - CFStringRef coutputStr; - string str; - - coutputStr = CFStringCreateWithCString(0, desc.device.c_str(), CFStringGetSystemEncoding()); - err = MIDIClientCreate(coutputStr, 0, 0, &midi_client); - CFRelease(coutputStr); - if (!midi_client) { - //error << "Cannot open CoreMidi client : " << err << endmsg. - goto error; - } - - str = desc.tag + string("_in"); - coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding()); - err = MIDIDestinationCreate(midi_client, coutputStr, read_proc, this, &midi_destination); - CFRelease(coutputStr); - if (!midi_destination) { - //error << "Cannot create CoreMidi destination : " << err << endmsg. - goto error; - } - - str = desc.tag + string("_out"); - coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding()); - err = MIDISourceCreate(midi_client, coutputStr, &midi_source); - CFRelease(coutputStr); - if (!midi_source) { - //error << "Cannot create CoreMidi source : " << err << endmsg. - goto error; - } - - return err; - -error: - Close(); - return err; -} - -void CoreMidi_MidiPort::read_proc (const MIDIPacketList *pktlist, void *refCon, void *connRefCon) -{ - CoreMidi_MidiPort* driver = (CoreMidi_MidiPort*)refCon; - MIDIPacket *packet = (MIDIPacket *)pktlist->packet; - - if (driver->firstrecv) { - driver->firstrecv = false; - PBD::notify_gui_about_thread_creation ("gui", pthread_self(), "COREMIDI", 256); - } - - for (unsigned int i = 0; i < pktlist->numPackets; ++i) { - - driver->bytes_read += packet->length; - - if (driver->input_parser) { - //driver->input_parser->raw_preparse (*driver->input_parser, packet->data, packet->length); - - /* XXX This is technically the wrong timebase, since it is based on - host time. - */ - driver->input_parser->set_timestamp (packet->timestamp); - - for (int i = 0; i < packet->length; i++) { - driver->input_parser->scanner (packet->data[i]); - } - - //driver->input_parser->raw_postparse (*driver->input_parser, packet->data, packet->length); - } - - packet = MIDIPacketNext(packet); - } -} - -int -CoreMidi_MidiPort::discover (vector& ports) -{ - /* XXX do dynamic port discovery here */ - - return 0; -} diff --git a/libs/midi++2/factory.cc b/libs/midi++2/factory.cc index 4c23a94671..73dfb6f69e 100644 --- a/libs/midi++2/factory.cc +++ b/libs/midi++2/factory.cc @@ -25,78 +25,13 @@ #include "midi++/types.h" #include "midi++/factory.h" -#include "midi++/fifomidi.h" -#ifdef WITH_JACK_MIDI #include "midi++/jack.h" -std::string MIDI::JACK_MidiPort::typestring = "jack"; -#endif // WITH_JACK_MIDI - -std::string MIDI::FIFO_MidiPort::typestring = "fifo"; - -#ifdef WITH_ALSA -#include "midi++/alsa_sequencer.h" -#include "midi++/alsa_rawmidi.h" - -std::string MIDI::ALSA_SequencerMidiPort::typestring = "alsa/sequencer"; -std::string MIDI::ALSA_RawMidiPort::typestring = "alsa/raw"; - -#endif // WITH_ALSA - -#ifdef WITH_COREMIDI -#include "midi++/coremidi_midiport.h" - -std::string MIDI::CoreMidi_MidiPort::typestring = "coremidi"; - -#endif // WITH_COREMIDI - using namespace std; using namespace MIDI; using namespace PBD; -// FIXME: void* data pointer, filthy -Port * -PortFactory::create_port (const XMLNode& node, void* data) - -{ - Port::Descriptor desc (node); - Port *port; - - switch (desc.type) { -#ifdef WITH_JACK_MIDI - case Port::JACK_Midi: - assert(data != NULL); - port = new JACK_MidiPort (node, (jack_client_t*) data); - break; -#endif // WITH_JACK_MIDI - -#ifdef WITH_ALSA - case Port::ALSA_RawMidi: - port = new ALSA_RawMidiPort (node); - break; - - case Port::ALSA_Sequencer: - port = new ALSA_SequencerMidiPort (node); - break; -#endif // WITH_ALSA - -#ifdef WITH_COREMIDI - case Port::CoreMidi_MidiPort: - port = new CoreMidi_MidiPort (node); - break; -#endif // WITH_COREMIDI - - case Port::FIFO: - port = new FIFO_MidiPort (node); - break; - - default: - return 0; - } - - return port; -} bool PortFactory::ignore_duplicate_devices (Port::Type type) @@ -104,23 +39,10 @@ PortFactory::ignore_duplicate_devices (Port::Type type) bool ret = false; switch (type) { -#ifdef WITH_ALSA - case Port::ALSA_Sequencer: - ret = true; - break; -#endif // WITH_ALSA -#ifdef WITH_JACK_MIDI case Port::JACK_Midi: ret = true; break; -#endif // WITH_JACK_MIDI - -#ifdef WITH_COREMIDI - case Port::CoreMidi_MidiPort: - ret = true; - break; -#endif // WITH_COREMIDI default: break; @@ -129,65 +51,17 @@ PortFactory::ignore_duplicate_devices (Port::Type type) return ret; } -int -#if defined (WITH_ALSA) || defined (WITH_COREMIDI) -PortFactory::get_known_ports (vector& ports) -#else -PortFactory::get_known_ports (vector&) -#endif -{ - int n = 0; -#ifdef WITH_ALSA - n += ALSA_SequencerMidiPort::discover (ports); -#endif // WITH_ALSA - -#ifdef WITH_COREMIDI - n += CoreMidi_MidiPort::discover (ports); -#endif // WITH_COREMIDI - - return n; -} - std::string PortFactory::default_port_type () { -#ifdef WITH_JACK_MIDI return "jack"; -#endif - -#ifdef WITH_ALSA - return "alsa/sequencer"; -#endif - -#ifdef WITH_COREMIDI - return "coremidi"; -#endif // WITH_COREMIDI - - PBD::fatal << "programming error: no default port type defined in midifactory.cc" << endmsg; - /*NOTREACHED*/ - return ""; } Port::Type PortFactory::string_to_type (const string& xtype) { - if (0){ -#ifdef WITH_ALSA - } else if (strings_equal_ignore_case (xtype, ALSA_RawMidiPort::typestring)) { - return Port::ALSA_RawMidi; - } else if (strings_equal_ignore_case (xtype, ALSA_SequencerMidiPort::typestring)) { - return Port::ALSA_Sequencer; -#endif -#ifdef WITH_COREMIDI - } else if (strings_equal_ignore_case (xtype, CoreMidi_MidiPort::typestring)) { - return Port::CoreMidi_MidiPort; -#endif - } else if (strings_equal_ignore_case (xtype, FIFO_MidiPort::typestring)) { - return Port::FIFO; -#ifdef WITH_JACK_MIDI - } else if (strings_equal_ignore_case (xtype, JACK_MidiPort::typestring)) { + if (strings_equal_ignore_case (xtype, JACK_MidiPort::typestring)) { return Port::JACK_Midi; -#endif } return Port::Unknown; diff --git a/libs/midi++2/fd_midiport.cc b/libs/midi++2/fd_midiport.cc deleted file mode 100644 index 9736d2b4da..0000000000 --- a/libs/midi++2/fd_midiport.cc +++ /dev/null @@ -1,181 +0,0 @@ -/* - Copyright (C) 1999 Paul Barton-Davis - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - $Id$ -*/ - -#include -#include -#include - -#include "pbd/error.h" -#include "pbd/pathscanner.h" - -#include "midi++/types.h" -#include "midi++/fd_midiport.h" - -using namespace std; -using namespace MIDI; -using namespace PBD; - -string *FD_MidiPort::midi_dirpath = 0; -string *FD_MidiPort::midi_filename_pattern = 0; - -FD_MidiPort::FD_MidiPort (const XMLNode& node, - const string &dirpath, - const string &pattern) - : Port (node) -{ - Descriptor desc (node); - - open (desc); - - if (_fd < 0) { - switch (errno) { - case EBUSY: - error << "MIDI: port device in use" << endmsg; - break; - case ENOENT: - error << "MIDI: no such port device" << endmsg; - break; - case EACCES: - error << "MIDI: access to port denied" << endmsg; - break; - default: - break; - } - } else { - _ok = true; - - if (midi_dirpath == 0) { - midi_dirpath = new string (dirpath); - midi_filename_pattern = new string (pattern); - } - - if ((desc.mode & O_NONBLOCK) == 0) { - /* we unconditionally set O_NONBLOCK during - open, but the request didn't ask for it, - so remove it. - */ - - int flags = fcntl (_fd, F_GETFL, 0); - fcntl (_fd, F_SETFL, flags & ~(O_NONBLOCK)); - } - } -} - -void -FD_MidiPort::open (const Descriptor& desc) - -{ - int mode = desc.mode | O_NONBLOCK; - _fd = ::open (desc.device.c_str(), mode); -} - -vector * -FD_MidiPort::list_devices () - -{ - PathScanner scanner; - - return scanner (*midi_dirpath, *midi_filename_pattern, false, true, false); -} - -int -FD_MidiPort::selectable () const - -{ - long flags; - - /* turn on non-blocking mode, since we plan to use select/poll - to tell us when there is data to read. - */ - - flags = fcntl (_fd, F_GETFL); - flags |= O_NONBLOCK; - - if (fcntl (_fd, F_SETFL, flags)) { - error << "FD_MidiPort: could not turn on non-blocking mode" - << " (" << strerror (errno) - << ')' - << endmsg; - - return -1; - } - - return _fd; -} - - -int -FD_MidiPort::do_slow_write (byte *msg, unsigned int msglen) - -{ - size_t n; - size_t i; - - for (n = 0; n < msglen; n++) { - - if (::write (_fd, &msg[n], 1) != 1) { - break; - } - - bytes_written++; - for (i = 0; i < slowdown * 10000; i++) {} - } - - - if (n && output_parser) { - output_parser->raw_preparse (*output_parser, msg, n); - for (unsigned int i = 0; i < n; i++) { - output_parser->scanner (msg[i]); - } - output_parser->raw_postparse (*output_parser, msg, n); - } - - return n; -} - -int -FD_MidiPort::read (byte* buf, size_t max) -{ - int nread; - - if ((_mode & O_ACCMODE) == O_WRONLY) { - return -EACCES; - } - - // cerr << "MIDI: read up to " << max << " from " << _fd << " (" << name() << ')' << endl; - - if ((nread = ::read (_fd, buf, max)) > 0) { - bytes_read += nread; - - // cerr << " read " << nread << endl; - - if (input_parser) { - input_parser->raw_preparse - (*input_parser, buf, nread); - for (int i = 0; i < nread; i++) { - input_parser->scanner (buf[i]); - } - input_parser->raw_postparse - (*input_parser, buf, nread); - } - } - - return nread; -} diff --git a/libs/midi++2/fifomidi.cc b/libs/midi++2/fifomidi.cc deleted file mode 100644 index 3bf340f3d3..0000000000 --- a/libs/midi++2/fifomidi.cc +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright (C) 1998-99 Paul Barton-Davis - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - $Id$ -*/ - -#include -#include -#include - -#include "midi++/types.h" -#include "midi++/fifomidi.h" - -using namespace MIDI; - -FIFO_MidiPort::FIFO_MidiPort (const XMLNode& node) - : FD_MidiPort (node, ".", "midi") - -{ -} - -void -FIFO_MidiPort::open (const Port::Descriptor& desc) - -{ - /* This is a placeholder for the fun-and-games I think we will - need to do with FIFO's. - */ - - _fd = ::open (desc.device.c_str(), desc.mode|O_NDELAY); -} diff --git a/libs/midi++2/jack_midiport.cc b/libs/midi++2/jack_midiport.cc deleted file mode 100644 index b55cf3adf6..0000000000 --- a/libs/midi++2/jack_midiport.cc +++ /dev/null @@ -1,433 +0,0 @@ -/* - Copyright (C) 2006 Paul Davis - Written by Dave Robillard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include - -#include "pbd/error.h" -#include "pbd/compose.h" -#include "pbd/strsplit.h" - -#include "midi++/types.h" -#include "midi++/jack.h" - -using namespace std; -using namespace MIDI; -using namespace PBD; - -pthread_t JACK_MidiPort::_process_thread; - -Signal0 JACK_MidiPort::JackHalted; -Signal0 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) - , output_fifo (512) - , input_fifo (1024) -{ - 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() -{ - 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 -JACK_MidiPort::cycle_start (nframes_t nframes) -{ - Port::cycle_start(nframes); - assert(_nframes_this_cycle == nframes); - _last_read_index = 0; - _last_write_timestamp = 0; - - if (_jack_output_port != 0) { - // output - void *buffer = jack_port_get_buffer (_jack_output_port, nframes); - jack_midi_clear_buffer (buffer); - flush (buffer); - } - - if (_jack_input_port != 0) { - // input - void* jack_buffer = jack_port_get_buffer(_jack_input_port, 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) { - jack_midi_event_get (&ev, jack_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 () -{ - if (_jack_output_port != 0) { - flush (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle)); - } - - Port::cycle_end(); -} - -int -JACK_MidiPort::write(byte * msg, size_t msglen, timestamp_t timestamp) -{ - int ret = 0; - - if (!_jack_output_port) { - return ret; - } - - if (!is_process_thread()) { - - Glib::Mutex::Lock lm (output_fifo_lock); - RingBuffer< Evoral::Event >::rw_vector vec = { { 0, 0 }, { 0, 0} }; - - 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; - return 0; - } - - 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); - } - - output_fifo.increment_write_idx (1); - - ret = msglen; - - } else { - - // XXX This had to be temporarily commented out to make export work again - if (!(timestamp < _nframes_this_cycle)) { - std::cerr << "assertion timestamp < _nframes_this_cycle failed!" << std::endl; - } - - if (_currently_in_cycle) { - if (timestamp == 0) { - timestamp = _last_write_timestamp; - } - - if (jack_midi_event_write (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle), - timestamp, msg, msglen) == 0) { - ret = msglen; - _last_write_timestamp = timestamp; - - } else { - ret = 0; - cerr << "write of " << msglen << " failed, port holds " - << jack_midi_get_event_count (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle)) - << endl; - } - } else { - cerr << "write to JACK midi port failed: not currently in a process cycle." << endl; - } - } - - if (ret > 0 && output_parser) { - // 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]); - } - // ardour doesn't care about this and neither should your app, probably - // output_parser->raw_postparse (*output_parser, msg, ret); - } - - return ret; -} - -void -JACK_MidiPort::flush (void* jack_port_buffer) -{ - RingBuffer< Evoral::Event >::rw_vector vec = { { 0, 0 }, { 0, 0 } }; - size_t written; - - 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"; - } - - if (vec.len[0]) { - Evoral::Event* evp = vec.buf[0]; - - for (size_t n = 0; n < vec.len[0]; ++n, ++evp) { - jack_midi_event_write (jack_port_buffer, - (timestamp_t) evp->time(), evp->buffer(), evp->size()); - } - } - - if (vec.len[1]) { - Evoral::Event* evp = vec.buf[1]; - - for (size_t n = 0; n < vec.len[1]; ++n, ++evp) { - jack_midi_event_write (jack_port_buffer, - (timestamp_t) evp->time(), evp->buffer(), evp->size()); - } - } - - if ((written = vec.len[0] + vec.len[1]) != 0) { - output_fifo.increment_read_idx (written); - } -} - -int -JACK_MidiPort::read (byte *, size_t) -{ - 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->set_timestamp (time); - for (uint32_t i = 0; i < size; ++i) { - input_parser->scanner (buffer[i]); - } - } - } - - return 0; -} - -int -JACK_MidiPort::create_ports(const XMLNode& node) -{ - Descriptor desc (node); - - assert(!_jack_input_port); - assert(!_jack_output_port); - - if (desc.mode == O_RDWR || desc.mode == O_WRONLY) { - _jack_output_port_name = string(desc.tag).append ("_out"); - } - - if (desc.mode == O_RDWR || desc.mode == O_RDONLY) { - _jack_input_port_name = string(desc.tag).append ("_in"); - } - - return create_ports (); -} - -int -JACK_MidiPort::create_ports () -{ - bool ret = true; - - jack_nframes_t nframes = jack_get_buffer_size(_jack_client); - - if (!_jack_output_port_name.empty()) { - _jack_output_port = jack_port_register(_jack_client, _jack_output_port_name.c_str(), - JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); - if (_jack_output_port) { - jack_midi_clear_buffer(jack_port_get_buffer(_jack_output_port, nframes)); - } - ret = ret && (_jack_output_port != NULL); - } - - if (!_jack_input_port_name.empty()) { - _jack_input_port = jack_port_register(_jack_client, _jack_input_port_name.c_str(), - JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); - if (_jack_input_port) { - jack_midi_clear_buffer(jack_port_get_buffer(_jack_input_port, nframes)); - } - ret = ret && (_jack_input_port != NULL); - } - - return ret ? 0 : -1; -} - -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 ports; - split (_inbound_connections, ports, ','); - for (vector::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 ports; - split (_outbound_connections, ports, ','); - for (vector::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 -JACK_MidiPort::set_process_thread (pthread_t thr) -{ - _process_thread = thr; -} - -bool -JACK_MidiPort::is_process_thread() -{ - return (pthread_self() == _process_thread); -} - -void -JACK_MidiPort::reestablish (void* jack) -{ - _jack_client = static_cast (jack); - int const r = create_ports (); - - if (r) { - PBD::error << "could not reregister ports for " << name() << endmsg; - } -} - -void -JACK_MidiPort::reconnect () -{ - make_connections (); -} diff --git a/libs/midi++2/manager.cc b/libs/midi++2/manager.cc index a84b5ab68a..5c464fa060 100644 --- a/libs/midi++2/manager.cc +++ b/libs/midi++2/manager.cc @@ -25,8 +25,8 @@ #include "midi++/types.h" #include "midi++/manager.h" -#include "midi++/factory.h" #include "midi++/channel.h" +#include "midi++/port.h" using namespace std; using namespace MIDI; @@ -60,7 +60,6 @@ Port * Manager::add_port (const XMLNode& node) { Port::Descriptor desc (node); - PortFactory factory; Port *port; PortList::iterator p; @@ -68,29 +67,15 @@ Manager::add_port (const XMLNode& node) if (desc.tag == (*p)->name()) { break; - } - - if (!PortFactory::ignore_duplicate_devices (desc.type)) { - if (desc.device == (*p)->device()) { - /* If the existing is duplex, and this request - is not, then fail, because most drivers won't - allow opening twice with duplex and non-duplex - operation. - */ - - if ((desc.mode == O_RDWR && (*p)->mode() != O_RDWR) || - (desc.mode != O_RDWR && (*p)->mode() == O_RDWR)) { - break; - } - } } + } if (p != _ports.end()) { return 0; } - port = factory.create_port (node, api_data); + port = new Port (node, (jack_client_t *) api_data); if (port == 0) { return 0; @@ -228,13 +213,6 @@ Manager::cycle_end() } } - -int -Manager::get_known_ports (vector& ports) -{ - return PortFactory::get_known_ports (ports); -} - /** Re-register ports that disappear on JACK shutdown */ void Manager::reestablish (void* a) diff --git a/libs/midi++2/midi++/alsa_rawmidi.h b/libs/midi++2/midi++/alsa_rawmidi.h deleted file mode 100644 index 5c0c0ff0ea..0000000000 --- a/libs/midi++2/midi++/alsa_rawmidi.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright (C) 1998-99 Paul Barton-Davis - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __alsa_rawmidi_h__ -#define __alsa_rawmidi_h__ - -#include -#include - -#include -#include - -#include "midi++/port.h" -#include "midi++/fd_midiport.h" - -namespace MIDI { - -class ALSA_RawMidiPort : public MIDI::FD_MidiPort - -{ - public: - ALSA_RawMidiPort (const XMLNode& node) - : FD_MidiPort (node, "/dev/snd", "midi") {} - virtual ~ALSA_RawMidiPort () {} - - static std::string typestring; - - protected: - std::string get_typestring () const { - return typestring; - } -}; - -} - -#endif // __alsa_rawmidi_h__ - diff --git a/libs/midi++2/midi++/alsa_sequencer.h b/libs/midi++2/midi++/alsa_sequencer.h deleted file mode 100644 index 889dd972b8..0000000000 --- a/libs/midi++2/midi++/alsa_sequencer.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - Copyright (C) 2004 Paul Davis - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __alsa_sequencer_midiport_h__ -#define __alsa_sequencer_midiport_h__ - -#include -#include - -#include -#include - -#include -#include "midi++/port.h" - -namespace MIDI { - -class ALSA_SequencerMidiPort : public Port - -{ - public: - ALSA_SequencerMidiPort (const XMLNode&); - virtual ~ALSA_SequencerMidiPort (); - - int write (byte *msg, size_t msglen, timestamp_t timestamp); - int read (byte *buf, size_t max); - - /* select(2)/poll(2)-based I/O */ - - virtual int selectable() const; - - static int discover (std::vector&); - static std::string typestring; - - XMLNode& get_state() const; - void set_state (const XMLNode&); - - protected: - - std::string get_typestring () const { - return typestring; - } - - private: - snd_midi_event_t *decoder, *encoder; - int port_id; - snd_seq_event_t SEv; - - int create_ports (const Port::Descriptor&); - - static int init_client (std::string name); - static snd_seq_t* seq; - - typedef std::pair SequencerPortAddress; - void get_connections (std::vector&, int dir) const; -}; - -}; /* namespace MIDI */ - -#endif // __alsa_sequencer_midiport_h__ - diff --git a/libs/midi++2/midi++/coremidi_midiport.h b/libs/midi++2/midi++/coremidi_midiport.h deleted file mode 100644 index 74207238ad..0000000000 --- a/libs/midi++2/midi++/coremidi_midiport.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright (C) 2004 Paul Davis - Copyright (C) 2004 Grame - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ĘSee the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#ifndef __coremidi_midiport_h__ -#define __coremidi_midiport_h__ - -#include -#include -#include - -#include -#include - -#include "midi++/port.h" - -#include - -namespace MIDI { - - class CoreMidi_MidiPort:public Port { - public: - CoreMidi_MidiPort(const XMLNode& node); - virtual ~ CoreMidi_MidiPort(); - - int write (byte * msg, size_t msglen, timestamp_t timestamp); - int read (byte * buf, size_t max) { - return 0; - } - - virtual int selectable() const { - return -1; - } - - static int discover (std::vector&); - static std::string typestring; - - protected: - - /* CoreMidi callback */ - static void read_proc(const MIDIPacketList * pktlist, - void *refCon, void *connRefCon); - - std::string get_typestring () const { - return typestring; - } - - private: - byte midi_buffer[1024]; - MIDIClientRef midi_client; - MIDIEndpointRef midi_destination; - MIDIEndpointRef midi_source; - - int Open(const Port::Descriptor&); - void Close(); - static MIDITimeStamp MIDIGetCurrentHostTime(); - - bool firstrecv; - - }; - -} // namespace MIDI - -#endif // __coremidi_midiport_h__ diff --git a/libs/midi++2/midi++/factory.h b/libs/midi++2/midi++/factory.h deleted file mode 100644 index 3f130c41a7..0000000000 --- a/libs/midi++2/midi++/factory.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright (C) 1998-99 Paul Barton-Davis - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __midi_factory_h__ -#define __midi_factory_h__ - -#include -#include - -#include "midi++/port.h" - -namespace MIDI { - -class PortFactory { - public: - Port *create_port (const XMLNode&, void* data); - - static bool ignore_duplicate_devices (Port::Type); - static int get_known_ports (std::vector&); - static std::string default_port_type (); - static Port::Type string_to_type (const std::string&); - static std::string mode_to_string (int); - static int string_to_mode (const std::string&); -}; - -} // namespace MIDI - -#endif // __midi_factory_h__ diff --git a/libs/midi++2/midi++/fd_midiport.h b/libs/midi++2/midi++/fd_midiport.h deleted file mode 100644 index 673037cc5d..0000000000 --- a/libs/midi++2/midi++/fd_midiport.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - Copyright (C) 1999 Paul Barton-Davis - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __fd_midiport_h__ -#define __fd_midiport_h__ - -#include -#include -#include - -#include -#include -#include - -#include "midi++/port.h" - -namespace MIDI { - -class FD_MidiPort : public Port - -{ - public: - FD_MidiPort (const XMLNode& node, - const std::string &dirpath, - const std::string &pattern); - - virtual ~FD_MidiPort () { - ::close (_fd); - } - - virtual int selectable() const; - - static std::vector *list_devices (); - - protected: - int _fd; - virtual void open (const Port::Descriptor&); - - virtual int write (byte *msg, size_t msglen, timestamp_t) { - int nwritten; - - if ((_mode & O_ACCMODE) == O_RDONLY) { - return -EACCES; - } - - if (slowdown) { - return do_slow_write (msg, msglen); - } - - if ((nwritten = ::write (_fd, msg, msglen)) > 0) { - bytes_written += nwritten; - - if (output_parser) { - output_parser->raw_preparse (*output_parser, msg, nwritten); - for (int i = 0; i < nwritten; i++) { - output_parser->scanner (msg[i]); - } - output_parser->raw_postparse (*output_parser, msg, nwritten); - } - } - return nwritten; - } - - int read (byte *buf, size_t max); - - private: - static std::string *midi_dirpath; - static std::string *midi_filename_pattern; - - int do_slow_write (byte *msg, unsigned int msglen); -}; - -} // namespace MIDI - -#endif // __fd_midiport_h__ diff --git a/libs/midi++2/midi++/fifomidi.h b/libs/midi++2/midi++/fifomidi.h deleted file mode 100644 index 022d055d92..0000000000 --- a/libs/midi++2/midi++/fifomidi.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright (C) 1998-99 Paul Barton-Davis - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __fifomidi_h__ -#define __fifomidi_h__ - -#include -#include -#include -#include - -#include "midi++/port.h" -#include "midi++/fd_midiport.h" - -namespace MIDI { - -class FIFO_MidiPort : public MIDI::FD_MidiPort - -{ - public: - FIFO_MidiPort (const XMLNode&); - ~FIFO_MidiPort () {}; - - static std::string typestring; - - protected: - std::string get_typestring () const { - return typestring; - } - - private: - void open (const Port::Descriptor&); -}; - -} // namespace MIDI - -#endif // __fifomidi_h__ diff --git a/libs/midi++2/midi++/jack.h b/libs/midi++2/midi++/jack.h deleted file mode 100644 index 099bc4e639..0000000000 --- a/libs/midi++2/midi++/jack.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - Copyright (C) 2006 Paul Davis - Written by Dave Robillard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - $Id: jack.h 4 2005-05-13 20:47:18Z taybin $ -*/ - -#ifndef __jack_midiport_h__ -#define __jack_midiport_h__ - -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#include "pbd/ringbuffer.h" -#include "pbd/signals.h" -#include "pbd/crossthread.h" -#include "evoral/EventRingBuffer.hpp" - -#include "midi++/port.h" -#include "midi++/event.h" - -namespace MIDI -{ - -class JACK_MidiPort : public Port -{ -public: - JACK_MidiPort (const XMLNode& node, jack_client_t* jack_client); - virtual ~JACK_MidiPort (); - - int write(byte *msg, size_t msglen, timestamp_t timestamp); - int read(byte *buf, size_t max); - - int selectable() const { return xthread.selectable(); } - bool must_drain_selectable() const { return true; } - - void cycle_start(nframes_t nframes); - void cycle_end(); - - static std::string typestring; - - XMLNode& get_state () const; - void set_state (const XMLNode&); - - static void set_process_thread (pthread_t); - static pthread_t get_process_thread () { return _process_thread; } - static bool is_process_thread(); - - nframes_t nframes_this_cycle() const { return _nframes_this_cycle; } - - void reestablish (void *); - void reconnect (); - - static PBD::Signal0 MakeConnections; - static PBD::Signal0 JackHalted; - - protected: - std::string get_typestring () const { - return typestring; - } - -private: - int create_ports(const XMLNode&); - int create_ports (); - - jack_client_t* _jack_client; - std::string _jack_input_port_name; /// input port name, or empty if there isn't one - jack_port_t* _jack_input_port; - std::string _jack_output_port_name; /// output port name, or empty if there isn't one - jack_port_t* _jack_output_port; - nframes_t _last_read_index; - timestamp_t _last_write_timestamp; - CrossThreadChannel xthread; - std::string _inbound_connections; - std::string _outbound_connections; - PBD::ScopedConnection connect_connection; - PBD::ScopedConnection halt_connection; - void flush (void* jack_port_buffer); - void jack_halted (); - void make_connections(); - - static pthread_t _process_thread; - - RingBuffer< Evoral::Event > output_fifo; - Evoral::EventRingBuffer input_fifo; - - Glib::Mutex output_fifo_lock; -}; - - -} /* namespace MIDI */ - -#endif // __jack_midiport_h__ - diff --git a/libs/midi++2/midi++/manager.h b/libs/midi++2/midi++/manager.h index 33835a05bf..563062aaea 100644 --- a/libs/midi++2/midi++/manager.h +++ b/libs/midi++2/midi++/manager.h @@ -81,8 +81,6 @@ class Manager { return theManager; } - int get_known_ports (std::vector&); - void reestablish (void *); void reconnect (); diff --git a/libs/midi++2/midi++/nullmidi.h b/libs/midi++2/midi++/nullmidi.h deleted file mode 100644 index 0ed221a78d..0000000000 --- a/libs/midi++2/midi++/nullmidi.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - Copyright (C) 1998-99 Paul Barton-Davis - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __nullmidi_h__ -#define __nullmidi_h__ - -#include -#include -#include - -#include "midi++/port.h" - -namespace MIDI { - -class Null_MidiPort : public Port - -{ - public: - Null_MidiPort (PortRequest &req) - : Port (req) { - - /* reset devname and tagname */ - - _devname = "nullmidi"; - _tagname = "null"; - _type = Port::Null; - _ok = true; - } - - virtual ~Null_MidiPort () {}; - - /* Direct I/O */ - int write (byte *msg, size_t msglen, timestamp_t timestamp) { - return msglen; - } - - int read (byte *buf, size_t max) { - return 0; - } - - virtual int selectable() const { return -1; } - - static std::string typestring; - - protected: - std::string get_typestring () const { - return typestring; - } -}; - -} // namespace MIDI - -#endif // __nullmidi_h__ diff --git a/libs/midi++2/midi++/port.h b/libs/midi++2/midi++/port.h index c45f5ba2fc..8c875a6615 100644 --- a/libs/midi++2/midi++/port.h +++ b/libs/midi++2/midi++/port.h @@ -1,5 +1,5 @@ /* - Copyright (C) 1998-99 Paul Barton-Davis + Copyright (C) 1998-2010 Paul Barton-Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -22,7 +22,15 @@ #include #include +#include + #include "pbd/xml++.h" +#include "pbd/crossthread.h" +#include "pbd/signals.h" +#include "pbd/ringbuffer.h" + +#include "evoral/Event.hpp" +#include "evoral/EventRingBuffer.hpp" #include "midi++/types.h" #include "midi++/parser.h" @@ -34,29 +42,18 @@ class PortRequest; class Port { public: - enum Type { - Unknown, - JACK_Midi, - ALSA_RawMidi, - ALSA_Sequencer, - CoreMidi_MidiPort, - Null, - FIFO - }; - + Port (const XMLNode&, jack_client_t *); + ~Port (); - Port (const XMLNode&); - virtual ~Port (); - - virtual XMLNode& get_state () const; - virtual void set_state (const XMLNode&); + XMLNode& get_state () const; + void set_state (const XMLNode&); // FIXME: make Manager a friend of port so these can be hidden? /* Only for use by MidiManager. Don't ever call this. */ - virtual void cycle_start(nframes_t nframes); + void cycle_start(nframes_t nframes); /* Only for use by MidiManager. Don't ever call this. */ - virtual void cycle_end(); + void cycle_end(); /** Write a message to port. * @param msg Raw MIDI message to send @@ -64,14 +61,14 @@ class Port { * @param timestamp Time stamp in frames of this message (relative to cycle start) * @return number of bytes successfully written */ - virtual int write (byte *msg, size_t msglen, timestamp_t timestamp) = 0; + int write (byte *msg, size_t msglen, timestamp_t timestamp); /** Read raw bytes from a port. * @param buf memory to store read data in * @param bufsize size of @a buf * @return number of bytes successfully read, negative if error */ - virtual int read (byte *buf, size_t bufsize) = 0; + int read (byte *buf, size_t bufsize); void parse (nframes_t timestamp); @@ -83,103 +80,90 @@ class Port { return !(write (msg, len, timestamp) == (int) len); } - int three_byte_msg (byte a, byte b, byte c, timestamp_t timestamp) { - byte msg[3]; - - msg[0] = a; - msg[1] = b; - msg[2] = c; - - return !(write (msg, 3, timestamp) == 3); - } - bool clock (timestamp_t timestamp); - - /* slowdown i/o to a loop of single byte emissions - interspersed with a busy loop of 10000 * this value. - - This may be ignored by a particular instance - of this virtual class. See FD_MidiPort for an - example of where it used. - */ - - void set_slowdown (size_t n) { slowdown = n; } /* select(2)/poll(2)-based I/O */ /** Get the file descriptor for port. * @return File descriptor, or -1 if not selectable. */ - virtual int selectable() const = 0; - virtual bool must_drain_selectable() const { return false; } + int selectable () const { + return xthread.selectable(); + } - static void gtk_read_callback (void *ptr, int fd, int cond); - static void write_callback (byte *msg, unsigned int len, void *); - Channel *channel (channel_t chn) { return _channel[chn&0x7F]; } Parser *input() { return input_parser; } Parser *output() { return output_parser; } - - void iostat (int *written, int *read, - const size_t **in_counts, - const size_t **out_counts) { - - *written = bytes_written; - *read = bytes_read; - if (input_parser) { - *in_counts = input_parser->message_counts(); - } else { - *in_counts = 0; - } - if (output_parser) { - *out_counts = output_parser->message_counts(); - } else { - *out_counts = 0; - } - } - const char *device () const { return _devname.c_str(); } const char *name () const { return _tagname.c_str(); } - Type type () const { return _type; } int mode () const { return _mode; } bool ok () const { return _ok; } struct Descriptor { std::string tag; - std::string device; int mode; - Port::Type type; Descriptor (const XMLNode&); XMLNode& get_state(); }; - virtual void reestablish (void *) {} - virtual void reconnect () {} + nframes_t nframes_this_cycle() const { return _nframes_this_cycle; } - protected: + void reestablish (void *); + void reconnect (); + + static void set_process_thread (pthread_t); + static pthread_t get_process_thread () { return _process_thread; } + static bool is_process_thread(); + + static PBD::Signal0 MakeConnections; + static PBD::Signal0 JackHalted; + +private: bool _ok; bool _currently_in_cycle; nframes_t _nframes_this_cycle; - Type _type; - std::string _devname; std::string _tagname; int _mode; size_t _number; Channel *_channel[16]; - unsigned int bytes_written; - unsigned int bytes_read; Parser *input_parser; Parser *output_parser; - size_t slowdown; - - virtual std::string get_typestring () const = 0; - private: static size_t nports; + + int create_ports(const XMLNode&); + int create_ports (); + + jack_client_t* _jack_client; + std::string _jack_input_port_name; /// input port name, or empty if there isn't one + jack_port_t* _jack_input_port; + std::string _jack_output_port_name; /// output port name, or empty if there isn't one + jack_port_t* _jack_output_port; + nframes_t _last_read_index; + timestamp_t _last_write_timestamp; + + /** Channel used to signal to the MidiControlUI that input has arrived */ + CrossThreadChannel xthread; + + std::string _inbound_connections; + std::string _outbound_connections; + PBD::ScopedConnection connect_connection; + PBD::ScopedConnection halt_connection; + void flush (void* jack_port_buffer); + void jack_halted (); + void make_connections(); + + static pthread_t _process_thread; + + RingBuffer< Evoral::Event > output_fifo; + Evoral::EventRingBuffer input_fifo; + + Glib::Mutex output_fifo_lock; + }; struct PortSet { diff --git a/libs/midi++2/port.cc b/libs/midi++2/port.cc index 6694249b61..457ff1c358 100644 --- a/libs/midi++2/port.cc +++ b/libs/midi++2/port.cc @@ -22,24 +22,37 @@ #include #include +#include +#include + #include "pbd/xml++.h" #include "pbd/error.h" #include "pbd/failed_constructor.h" +#include "pbd/convert.h" +#include "pbd/strsplit.h" #include "midi++/types.h" #include "midi++/port.h" #include "midi++/channel.h" -#include "midi++/factory.h" using namespace MIDI; using namespace std; using namespace PBD; size_t Port::nports = 0; - -Port::Port (const XMLNode& node) - : _currently_in_cycle(false) - , _nframes_this_cycle(0) +pthread_t Port::_process_thread; +Signal0 Port::JackHalted; +Signal0 Port::MakeConnections; + +Port::Port (const XMLNode& node, jack_client_t* jack_client) + : _currently_in_cycle (false) + , _nframes_this_cycle (0) + , _jack_client (jack_client) + , _jack_input_port (0) + , _jack_output_port (0) + , _last_read_index (0) + , output_fifo (512) + , input_fifo (1024) { Descriptor desc (node); @@ -47,13 +60,9 @@ Port::Port (const XMLNode& node) succeeds. */ - bytes_written = 0; - bytes_read = 0; input_parser = 0; output_parser = 0; - slowdown = 0; - _devname = desc.device; _tagname = desc.tag; _mode = desc.mode; @@ -80,6 +89,15 @@ Port::Port (const XMLNode& node) _channel[i]->connect_output_signals (); } } + + if (!create_ports (node)) { + _ok = true; + } + + MakeConnections.connect_same_thread (connect_connection, boost::bind (&Port::make_connections, this)); + JackHalted.connect_same_thread (halt_connection, boost::bind (&Port::jack_halted, this)); + + set_state (node); } @@ -88,6 +106,20 @@ Port::~Port () for (int i = 0; i < 16; i++) { delete _channel[i]; } + + 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 @@ -149,24 +181,293 @@ Port::cycle_start (nframes_t nframes) { _currently_in_cycle = true; _nframes_this_cycle = nframes; + + assert(_nframes_this_cycle == nframes); + _last_read_index = 0; + _last_write_timestamp = 0; + + if (_jack_output_port != 0) { + // output + void *buffer = jack_port_get_buffer (_jack_output_port, nframes); + jack_midi_clear_buffer (buffer); + flush (buffer); + } + + if (_jack_input_port != 0) { + // input + void* jack_buffer = jack_port_get_buffer(_jack_input_port, 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) { + jack_midi_event_get (&ev, jack_buffer, i); + input_fifo.write (cycle_start_frame + ev.time, (Evoral::EventType) 0, ev.size, ev.buffer); + } + + if (event_count) { + xthread.wakeup (); + } + } } void Port::cycle_end () { + if (_jack_output_port != 0) { + flush (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle)); + } + _currently_in_cycle = false; _nframes_this_cycle = 0; } -XMLNode& +std::ostream & MIDI::operator << ( std::ostream & os, const MIDI::Port & port ) +{ + using namespace std; + os << "MIDI::Port { "; + os << "name: " << port.name(); + os << "; "; + os << "mode: " << port.mode(); + os << "; "; + os << "ok: " << port.ok(); + os << "; "; + os << " }"; + return os; +} + +Port::Descriptor::Descriptor (const XMLNode& node) +{ + const XMLProperty *prop; + bool have_tag = false; + bool have_mode = false; + + if ((prop = node.property ("tag")) != 0) { + tag = prop->value(); + have_tag = true; + } + + if ((prop = node.property ("mode")) != 0) { + + mode = O_RDWR; + + if (strings_equal_ignore_case (prop->value(), "output") || strings_equal_ignore_case (prop->value(), "out")) { + mode = O_WRONLY; + } else if (strings_equal_ignore_case (prop->value(), "input") || strings_equal_ignore_case (prop->value(), "in")) { + mode = O_RDONLY; + } + + have_mode = true; + } + + if (!have_tag || !have_mode) { + throw failed_constructor(); + } +} + +void +Port::jack_halted () +{ + _jack_client = 0; + _jack_input_port = 0; + _jack_output_port = 0; +} + +int +Port::write(byte * msg, size_t msglen, timestamp_t timestamp) +{ + int ret = 0; + + if (!_jack_output_port) { + return ret; + } + + if (!is_process_thread()) { + + Glib::Mutex::Lock lm (output_fifo_lock); + RingBuffer< Evoral::Event >::rw_vector vec = { { 0, 0 }, { 0, 0} }; + + 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; + return 0; + } + + 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); + } + + output_fifo.increment_write_idx (1); + + ret = msglen; + + } else { + + // XXX This had to be temporarily commented out to make export work again + if (!(timestamp < _nframes_this_cycle)) { + std::cerr << "assertion timestamp < _nframes_this_cycle failed!" << std::endl; + } + + if (_currently_in_cycle) { + if (timestamp == 0) { + timestamp = _last_write_timestamp; + } + + if (jack_midi_event_write (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle), + timestamp, msg, msglen) == 0) { + ret = msglen; + _last_write_timestamp = timestamp; + + } else { + ret = 0; + cerr << "write of " << msglen << " failed, port holds " + << jack_midi_get_event_count (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle)) + << endl; + } + } else { + cerr << "write to JACK midi port failed: not currently in a process cycle." << endl; + } + } + + if (ret > 0 && output_parser) { + // 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]); + } + // ardour doesn't care about this and neither should your app, probably + // output_parser->raw_postparse (*output_parser, msg, ret); + } + + return ret; +} + +void +Port::flush (void* jack_port_buffer) +{ + RingBuffer< Evoral::Event >::rw_vector vec = { { 0, 0 }, { 0, 0 } }; + size_t written; + + 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"; + } + + if (vec.len[0]) { + Evoral::Event* evp = vec.buf[0]; + + for (size_t n = 0; n < vec.len[0]; ++n, ++evp) { + jack_midi_event_write (jack_port_buffer, + (timestamp_t) evp->time(), evp->buffer(), evp->size()); + } + } + + if (vec.len[1]) { + Evoral::Event* evp = vec.buf[1]; + + for (size_t n = 0; n < vec.len[1]; ++n, ++evp) { + jack_midi_event_write (jack_port_buffer, + (timestamp_t) evp->time(), evp->buffer(), evp->size()); + } + } + + if ((written = vec.len[0] + vec.len[1]) != 0) { + output_fifo.increment_read_idx (written); + } +} + +int +Port::read (byte *, size_t) +{ + 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->set_timestamp (time); + for (uint32_t i = 0; i < size; ++i) { + input_parser->scanner (buffer[i]); + } + } + } + + return 0; +} + +int +Port::create_ports(const XMLNode& node) +{ + Descriptor desc (node); + + assert(!_jack_input_port); + assert(!_jack_output_port); + + if (desc.mode == O_RDWR || desc.mode == O_WRONLY) { + _jack_output_port_name = string(desc.tag).append ("_out"); + } + + if (desc.mode == O_RDWR || desc.mode == O_RDONLY) { + _jack_input_port_name = string(desc.tag).append ("_in"); + } + + return create_ports (); +} + +int +Port::create_ports () +{ + bool ret = true; + + jack_nframes_t nframes = jack_get_buffer_size(_jack_client); + + if (!_jack_output_port_name.empty()) { + _jack_output_port = jack_port_register(_jack_client, _jack_output_port_name.c_str(), + JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); + if (_jack_output_port) { + jack_midi_clear_buffer(jack_port_get_buffer(_jack_output_port, nframes)); + } + ret = ret && (_jack_output_port != NULL); + } + + if (!_jack_input_port_name.empty()) { + _jack_input_port = jack_port_register(_jack_client, _jack_input_port_name.c_str(), + JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); + if (_jack_input_port) { + jack_midi_clear_buffer(jack_port_get_buffer(_jack_input_port, nframes)); + } + ret = ret && (_jack_input_port != NULL); + } + + return ret ? 0 : -1; +} + +XMLNode& Port::get_state () const { - XMLNode* node = new XMLNode ("MIDI-port"); - node->add_property ("tag", _tagname); - node->add_property ("device", _devname); - node->add_property ("mode", PortFactory::mode_to_string (_mode)); - node->add_property ("type", get_typestring()); + XMLNode* root = new XMLNode ("MIDI-port"); + root->add_property ("tag", _tagname); + if (_mode == O_RDONLY) { + root->add_property ("mode", "input"); + } else if (_mode == O_WRONLY) { + root->add_property ("mode", "output"); + } else { + root->add_property ("mode", "duplex"); + } + #if 0 byte device_inquiry[6]; @@ -180,76 +481,121 @@ Port::get_state () const write (device_inquiry, sizeof (device_inquiry), 0); #endif - return *node; + 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 -Port::set_state (const XMLNode& /*node*/) +Port::set_state (const XMLNode& node) { - // relax + 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 -Port::gtk_read_callback (void *ptr, int /*fd*/, int /*cond*/) +Port::make_connections () { - byte buf[64]; - ((Port *)ptr)->read (buf, sizeof (buf)); + if (!_inbound_connections.empty()) { + vector ports; + split (_inbound_connections, ports, ','); + for (vector::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 ports; + split (_outbound_connections, ports, ','); + for (vector::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 -Port::write_callback (byte *msg, unsigned int len, void *ptr) +Port::set_process_thread (pthread_t thr) { - ((Port *)ptr)->write (msg, len, 0); + _process_thread = thr; } -std::ostream & MIDI::operator << ( std::ostream & os, const MIDI::Port & port ) +bool +Port::is_process_thread() { - using namespace std; - os << "MIDI::Port { "; - os << "device: " << port.device(); - os << "; "; - os << "name: " << port.name(); - os << "; "; - os << "type: " << port.type(); - os << "; "; - os << "mode: " << port.mode(); - os << "; "; - os << "ok: " << port.ok(); - os << "; "; - os << " }"; - return os; + return (pthread_self() == _process_thread); } -Port::Descriptor::Descriptor (const XMLNode& node) +void +Port::reestablish (void* jack) { - const XMLProperty *prop; - bool have_tag = false; - bool have_device = false; - bool have_type = false; - bool have_mode = false; - - if ((prop = node.property ("tag")) != 0) { - tag = prop->value(); - have_tag = true; - } + _jack_client = static_cast (jack); + int const r = create_ports (); - if ((prop = node.property ("device")) != 0) { - device = prop->value(); - have_device = true; - } - - if ((prop = node.property ("type")) != 0) { - type = PortFactory::string_to_type (prop->value()); - have_type = true; - } - - if ((prop = node.property ("mode")) != 0) { - mode = PortFactory::string_to_mode (prop->value()); - have_mode = true; - } - - if (!have_tag || !have_device || !have_type || !have_mode) { - throw failed_constructor(); + if (r) { + PBD::error << "could not reregister ports for " << name() << endmsg; } } +void +Port::reconnect () +{ + make_connections (); +} diff --git a/libs/midi++2/wscript b/libs/midi++2/wscript index 60ac03d77a..aa6f8a67ca 100644 --- a/libs/midi++2/wscript +++ b/libs/midi++2/wscript @@ -45,11 +45,8 @@ def build(bld): # Library obj = bld.new_task_gen('cxx', 'shlib') obj.source = ''' - fd_midiport.cc - fifomidi.cc midi.cc channel.cc - factory.cc manager.cc parser.cc port.cc @@ -59,21 +56,12 @@ def build(bld): version.cc ''' # everybody loves JACK - obj.source += ' jack_midiport.cc ' obj.cxxflags = [ '-DWITH_JACK_MIDI' ] - if bld.env['HAVE_COREAUDIO'] and bld.env['COREAUDIO']: - # OS X - obj.source += ' coremidi_midiport.cc ' - obj.cxxflags += [ '-DWITH_COREMIDI' ] - elif sys.platform == 'linux': - # linux - obj.source += ' alsa_sequencer_midiport.cc ' - obj.cxxflags += [ '-DWITH_ALSA' ] obj.export_incdirs = ['.'] obj.includes = ['.', '../surfaces/control_protocol'] obj.name = 'libmidipp' obj.target = 'midipp' - obj.uselib = 'GLIBMM SIGCPP XML JACK OSX COREAUDIO' + obj.uselib = 'GLIBMM SIGCPP XML JACK OSX' obj.uselib_local = 'libpbd libevoral' obj.vnum = LIBMIDIPP_LIB_VERSION obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3') diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc index 3fa1686d9b..a49c67acc5 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.cc +++ b/libs/surfaces/mackie/mackie_control_protocol.cc @@ -563,20 +563,14 @@ MackieControlProtocol::connect_session_signals() void MackieControlProtocol::add_port (MIDI::Port & midi_port, int number) { - DEBUG_TRACE (DEBUG::MackieControl, string_compose ("add port %1,%2,%3\n", midi_port.name(), midi_port.device(), midi_port.type())); - - if (string (midi_port.device()) == string ("ardour") && midi_port.type() == MIDI::Port::ALSA_Sequencer) { - throw MackieControlException ("The Mackie MCU driver will not use a port with device=ardour"); - } else if (midi_port.type() == MIDI::Port::ALSA_Sequencer) { - throw MackieControlException ("alsa/sequencer ports don't work with the Mackie MCU driver right now"); - } else { - MackiePort * sport = new MackiePort (*this, midi_port, number); - _ports.push_back (sport); - - sport->init_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_init, this, sport)); - sport->active_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_active, this, sport)); - sport->inactive_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_inactive, this, sport)); - } + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("add port %1\n", midi_port.name())); + + MackiePort * sport = new MackiePort (*this, midi_port, number); + _ports.push_back (sport); + + sport->init_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_init, this, sport)); + sport->active_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_active, this, sport)); + sport->inactive_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_inactive, this, sport)); } void diff --git a/libs/surfaces/mackie/surface_port.cc b/libs/surfaces/mackie/surface_port.cc index 8aaea1d5ba..9dd456157e 100644 --- a/libs/surfaces/mackie/surface_port.cc +++ b/libs/surfaces/mackie/surface_port.cc @@ -173,8 +173,6 @@ void SurfacePort::write_sysex( MIDI::byte msg ) ostream & Mackie::operator << ( ostream & os, const SurfacePort & port ) { os << "{ "; - os << "device: " << port.port().device(); - os << "; "; os << "name: " << port.port().name(); os << "; "; os << " }"; -- cgit v1.2.3