diff options
Diffstat (limited to 'libs/midi++2')
-rw-r--r-- | libs/midi++2/SConscript | 3 | ||||
-rw-r--r-- | libs/midi++2/alsa_sequencer_midiport.cc | 250 | ||||
-rw-r--r-- | libs/midi++2/coremidi_midiport.cc | 38 | ||||
-rw-r--r-- | libs/midi++2/fd_midiport.cc | 24 | ||||
-rw-r--r-- | libs/midi++2/fifomidi.cc | 8 | ||||
-rw-r--r-- | libs/midi++2/jack_midiport.cc | 47 | ||||
-rw-r--r-- | libs/midi++2/midi++/alsa_rawmidi.h | 6 | ||||
-rw-r--r-- | libs/midi++2/midi++/alsa_sequencer.h | 24 | ||||
-rw-r--r-- | libs/midi++2/midi++/coremidi_midiport.h | 65 | ||||
-rw-r--r-- | libs/midi++2/midi++/factory.h | 3 | ||||
-rw-r--r-- | libs/midi++2/midi++/fd_midiport.h | 21 | ||||
-rw-r--r-- | libs/midi++2/midi++/fifomidi.h | 5 | ||||
-rw-r--r-- | libs/midi++2/midi++/jack.h | 7 | ||||
-rw-r--r-- | libs/midi++2/midi++/manager.h | 26 | ||||
-rw-r--r-- | libs/midi++2/midi++/nullmidi.h | 1 | ||||
-rw-r--r-- | libs/midi++2/midi++/port.h | 101 | ||||
-rw-r--r-- | libs/midi++2/midi++/port_request.h | 66 | ||||
-rw-r--r-- | libs/midi++2/midifactory.cc | 26 | ||||
-rw-r--r-- | libs/midi++2/midimanager.cc | 196 | ||||
-rw-r--r-- | libs/midi++2/midiport.cc | 105 | ||||
-rw-r--r-- | libs/midi++2/miditrace.cc | 1 | ||||
-rw-r--r-- | libs/midi++2/mmctest.cc | 1 | ||||
-rw-r--r-- | libs/midi++2/port_request.cc | 83 |
23 files changed, 651 insertions, 456 deletions
diff --git a/libs/midi++2/SConscript b/libs/midi++2/SConscript index 04b027b6a3..769d888903 100644 --- a/libs/midi++2/SConscript +++ b/libs/midi++2/SConscript @@ -7,7 +7,7 @@ import glob Import('env libraries install_prefix') midi2 = env.Copy() -midi2.Merge([ libraries['sigc2'], libraries['xml'], libraries['glib2'], libraries['pbd'], libraries['jack'] ]) +midi2.Merge([ libraries['sigc2'], libraries['xml'], libraries['glibmm2'], libraries['glib2'], libraries['pbd'], libraries['jack'] ]) domain = 'midipp' @@ -24,7 +24,6 @@ midiparser.cc midiport.cc mmc.cc mtc.cc -port_request.cc version.cc """) diff --git a/libs/midi++2/alsa_sequencer_midiport.cc b/libs/midi++2/alsa_sequencer_midiport.cc index bf891108c6..bae8aff2ab 100644 --- a/libs/midi++2/alsa_sequencer_midiport.cc +++ b/libs/midi++2/alsa_sequencer_midiport.cc @@ -23,10 +23,12 @@ #include <pbd/failed_constructor.h> #include <pbd/error.h> +#include <pbd/xml++.h> #include <midi++/types.h> #include <midi++/alsa_sequencer.h> -#include <midi++/port_request.h> + +#include "i18n.h" //#define DOTRACE 1 @@ -44,31 +46,31 @@ using namespace PBD; snd_seq_t* ALSA_SequencerMidiPort::seq = 0; -ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (PortRequest &req) - : Port (req) +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 (req.devname) < 0) { + if (!seq && init_client (desc.device) < 0) { _ok = false; } else { - if (0 <= (err = CreatePorts (req)) && + 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; - req.status = PortRequest::OK; - } else { - req.status = PortRequest::Unknown; - } + } } + + set_state (node); } ALSA_SequencerMidiPort::~ALSA_SequencerMidiPort () @@ -94,7 +96,8 @@ ALSA_SequencerMidiPort::selectable () const return -1; } -int ALSA_SequencerMidiPort::write (byte *msg, size_t msglen, timestamp_t timestamp) +int +ALSA_SequencerMidiPort::write (byte *msg, size_t msglen, timestamp_t ignored) { TR_FN (); int R; @@ -133,7 +136,8 @@ int ALSA_SequencerMidiPort::write (byte *msg, size_t msglen, timestamp_t timesta return totwritten; } -int ALSA_SequencerMidiPort::read (byte *buf, size_t max, timestamp_t timestamp) +int +ALSA_SequencerMidiPort::read (byte *buf, size_t max, timestamp_t ignored) { TR_FN(); int err; @@ -158,17 +162,20 @@ int ALSA_SequencerMidiPort::read (byte *buf, size_t max, timestamp_t timestamp) } int -ALSA_SequencerMidiPort::CreatePorts (PortRequest &req) +ALSA_SequencerMidiPort::create_ports (const Port::Descriptor& desc) { int err; unsigned int caps = 0; - if (req.mode == O_WRONLY || req.mode == O_RDWR) + if (desc.mode == O_WRONLY || desc.mode == O_RDWR) caps |= SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; - if (req.mode == O_RDONLY || req.mode == O_RDWR) + 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, req.tagname, caps, SND_SEQ_PORT_TYPE_MIDI_GENERIC))) { + 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; @@ -203,3 +210,216 @@ ALSA_SequencerMidiPort::init_client (std::string name) return -1; } } + +int +ALSA_SequencerMidiPort::discover (vector<PortSet>& 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<SequencerPortAddress>& 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) { + + 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<SequencerPortAddress> connections; + XMLNode* sub = 0; + char buf[256]; + + get_connections (connections, 1); + + if (!connections.empty()) { + if (!sub) { + sub = new XMLNode (X_("connections")); + } + for (vector<SequencerPortAddress>::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<SequencerPortAddress>::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 index 2cd98239ec..14020a6f35 100644 --- a/libs/midi++2/coremidi_midiport.cc +++ b/libs/midi++2/coremidi_midiport.cc @@ -23,7 +23,6 @@ #include <midi++/coremidi_midiport.h> #include <midi++/types.h> -#include <midi++/port_request.h> #include <mach/mach_time.h> #include <pbd/pthread_utils.h> @@ -36,15 +35,15 @@ MIDITimeStamp CoreMidi_MidiPort::MIDIGetCurrentHostTime() return mach_absolute_time(); } -CoreMidi_MidiPort::CoreMidi_MidiPort (PortRequest &req) : Port (req) +CoreMidi_MidiPort::CoreMidi_MidiPort (const XMLNode& node) : Port (node) { + Descriptor desc (node); + firstrecv = true; int err; - if (0 == (err = Open(req))) { + if (0 == (err = Open(desc))) { _ok = true; - req.status = PortRequest::OK; - } else - req.status = PortRequest::Unknown; + } } CoreMidi_MidiPort::~CoreMidi_MidiPort () {Close();} @@ -56,10 +55,10 @@ void CoreMidi_MidiPort::Close () if (midi_client) MIDIClientDispose(midi_client); } -int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t timestamp) +int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t ignored) { OSStatus err; - MIDIPacketList* pktlist = (MIDIPacketList*)midi_buffer; + MIDIPacketList* pktlist = (MIDIPacketList*)midi_buffer; MIDIPacket* packet = MIDIPacketListInit(pktlist); packet = MIDIPacketListAdd(pktlist,sizeof(midi_buffer),packet,MIDIGetCurrentHostTime(),msglen,msg); @@ -77,21 +76,21 @@ int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t timestamp) } } -int CoreMidi_MidiPort::Open (PortRequest &req) +int CoreMidi_MidiPort::Open (const Descriptor& desc) { OSStatus err; CFStringRef coutputStr; string str; - - coutputStr = CFStringCreateWithCString(0, req.devname, CFStringGetSystemEncoding()); + + coutputStr = CFStringCreateWithCString(0, desc.device.c_str(), CFStringGetSystemEncoding()); err = MIDIClientCreate(coutputStr, 0, 0, &midi_client); CFRelease(coutputStr); - if (!midi_client) { + if (!midi_client) { //error << "Cannot open CoreMidi client : " << err << endmsg. - goto error; - } + goto error; + } - str = req.tagname + string("_in"); + str = desc.tag + string("_in"); coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding()); err = MIDIDestinationCreate(midi_client, coutputStr, read_proc, this, &midi_destination); CFRelease(coutputStr); @@ -100,7 +99,7 @@ int CoreMidi_MidiPort::Open (PortRequest &req) goto error; } - str = req.tagname + string("_out"); + str = desc.tag + string("_out"); coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding()); err = MIDISourceCreate(midi_client, coutputStr, &midi_source); CFRelease(coutputStr); @@ -142,3 +141,10 @@ void CoreMidi_MidiPort::read_proc (const MIDIPacketList *pktlist, void *refCon, } } +int +CoreMidi_MidiPort::discover (vector<PortSet>& ports) +{ + /* XXX do dynamic port discovery here */ + + return 0; +} diff --git a/libs/midi++2/fd_midiport.cc b/libs/midi++2/fd_midiport.cc index 81d81c8558..17a7eff367 100644 --- a/libs/midi++2/fd_midiport.cc +++ b/libs/midi++2/fd_midiport.cc @@ -34,40 +34,38 @@ using namespace PBD; string *FD_MidiPort::midi_dirpath = 0; string *FD_MidiPort::midi_filename_pattern = 0; -FD_MidiPort::FD_MidiPort (PortRequest &req, +FD_MidiPort::FD_MidiPort (const XMLNode& node, const string &dirpath, const string &pattern) - : Port (req) + : Port (node) { - open (req); + Descriptor desc (node); + + open (desc); if (_fd < 0) { switch (errno) { case EBUSY: error << "MIDI: port device in use" << endmsg; - req.status = PortRequest::Busy; break; case ENOENT: error << "MIDI: no such port device" << endmsg; - req.status = PortRequest::NoSuchFile; break; case EACCES: error << "MIDI: access to port denied" << endmsg; - req.status = PortRequest::NotAllowed; break; default: - req.status = PortRequest::Unknown; + break; } } else { _ok = true; - req.status = PortRequest::OK; if (midi_dirpath == 0) { midi_dirpath = new string (dirpath); midi_filename_pattern = new string (pattern); } - if (req.mode & O_NONBLOCK == 0) { + if (desc.mode & O_NONBLOCK == 0) { /* we unconditionally set O_NONBLOCK during open, but the request didn't ask for it, so remove it. @@ -80,11 +78,11 @@ FD_MidiPort::FD_MidiPort (PortRequest &req, } void -FD_MidiPort::open (PortRequest &req) +FD_MidiPort::open (const Descriptor& desc) { - int mode = req.mode | O_NONBLOCK; - _fd = ::open (req.devname, mode); + int mode = desc.mode | O_NONBLOCK; + _fd = ::open (desc.device.c_str(), mode); } vector<string *> * @@ -152,7 +150,7 @@ FD_MidiPort::do_slow_write (byte *msg, unsigned int msglen) } int -FD_MidiPort::read (byte* buf, size_t max, timestamp_t timestamp) +FD_MidiPort::read (byte* buf, size_t max, timestamp_t ignored) { int nread; diff --git a/libs/midi++2/fifomidi.cc b/libs/midi++2/fifomidi.cc index 7bb126ddeb..a81520bb95 100644 --- a/libs/midi++2/fifomidi.cc +++ b/libs/midi++2/fifomidi.cc @@ -26,19 +26,19 @@ using namespace MIDI; -FIFO_MidiPort::FIFO_MidiPort (PortRequest &req) - : FD_MidiPort (req, ".", "midi") +FIFO_MidiPort::FIFO_MidiPort (const XMLNode& node) + : FD_MidiPort (node, ".", "midi") { } void -FIFO_MidiPort::open (PortRequest &req) +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 (req.devname, req.mode|O_NDELAY); + _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 index 4b2808a698..11cd70a051 100644 --- a/libs/midi++2/jack_midiport.cc +++ b/libs/midi++2/jack_midiport.cc @@ -23,26 +23,22 @@ #include <midi++/types.h> #include <midi++/jack.h> -#include <midi++/port_request.h> using namespace std; using namespace MIDI; -JACK_MidiPort::JACK_MidiPort(PortRequest & req, jack_client_t* jack_client) - : Port(req) +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) { - int err = create_ports(req); + int err = create_ports (node); if (!err) { - req.status = PortRequest::OK; _ok = true; - } else { - req.status = PortRequest::Unknown; - } + } } JACK_MidiPort::~JACK_MidiPort() @@ -94,8 +90,10 @@ JACK_MidiPort::read(byte * buf, size_t max, timestamp_t timestamp) } int -JACK_MidiPort::create_ports(PortRequest & req) +JACK_MidiPort::create_ports(const XMLNode& node) { + Descriptor desc (node); + assert(!_jack_input_port); assert(!_jack_output_port); @@ -103,24 +101,33 @@ JACK_MidiPort::create_ports(PortRequest & req) bool ret = true; - if (req.mode == O_RDWR || req.mode == O_WRONLY) { + if (desc.mode == O_RDWR || desc.mode == O_WRONLY) { _jack_output_port = jack_port_register(_jack_client, - string(req.tagname).append("_out").c_str(), - JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); - jack_midi_clear_buffer( - jack_port_get_buffer(_jack_output_port, nframes)); + string(desc.tag).append("_out").c_str(), + JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); + jack_midi_clear_buffer(jack_port_get_buffer(_jack_output_port, nframes)); ret = ret && (_jack_output_port != NULL); } - - if (req.mode == O_RDWR || req.mode == O_RDONLY) { + + if (desc.mode == O_RDWR || desc.mode == O_RDONLY) { _jack_input_port = jack_port_register(_jack_client, - string(req.tagname).append("_in").c_str(), - JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); - jack_midi_clear_buffer( - jack_port_get_buffer(_jack_input_port, nframes)); + string(desc.tag).append("_in").c_str(), + JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); + 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 ()); + return root; +} + +void +JACK_MidiPort::set_state (const XMLNode& node) +{ +} diff --git a/libs/midi++2/midi++/alsa_rawmidi.h b/libs/midi++2/midi++/alsa_rawmidi.h index 54b86edd70..e5abc2832f 100644 --- a/libs/midi++2/midi++/alsa_rawmidi.h +++ b/libs/midi++2/midi++/alsa_rawmidi.h @@ -34,8 +34,8 @@ class ALSA_RawMidiPort : public MIDI::FD_MidiPort { public: - ALSA_RawMidiPort (MIDI::PortRequest &req) - : FD_MidiPort (req, "/dev/snd", "midi") {} + ALSA_RawMidiPort (const XMLNode& node) + : FD_MidiPort (node, "/dev/snd", "midi") {} virtual ~ALSA_RawMidiPort () {} static std::string typestring; @@ -46,7 +46,7 @@ class ALSA_RawMidiPort : public MIDI::FD_MidiPort } }; -} // namespace MIDI +} #endif // __alsa_rawmidi_h__ diff --git a/libs/midi++2/midi++/alsa_sequencer.h b/libs/midi++2/midi++/alsa_sequencer.h index b54486416a..a95f9c476f 100644 --- a/libs/midi++2/midi++/alsa_sequencer.h +++ b/libs/midi++2/midi++/alsa_sequencer.h @@ -30,39 +30,45 @@ namespace MIDI { -class PortRequest; - class ALSA_SequencerMidiPort : public Port + { public: - ALSA_SequencerMidiPort (PortRequest &req); + ALSA_SequencerMidiPort (const XMLNode&); virtual ~ALSA_SequencerMidiPort (); /* select(2)/poll(2)-based I/O */ virtual int selectable() const; - + + static int discover (std::vector<PortSet>&); static std::string typestring; - protected: - std::string get_typestring () const { - return typestring; - } + XMLNode& get_state() const; + void set_state (const XMLNode&); protected: /* Direct I/O */ + int write (byte *msg, size_t msglen, timestamp_t timestamp); int read (byte *buf, size_t max, timestamp_t timestamp); + std::string get_typestring () const { + return typestring; + } + private: snd_midi_event_t *decoder, *encoder; int port_id; snd_seq_event_t SEv; - int CreatePorts(PortRequest &req); + int create_ports (const Port::Descriptor&); static int init_client (std::string name); static snd_seq_t* seq; + + typedef std::pair<int,int> SequencerPortAddress; + void get_connections (std::vector<SequencerPortAddress>&, int dir) const; }; }; /* namespace MIDI */ diff --git a/libs/midi++2/midi++/coremidi_midiport.h b/libs/midi++2/midi++/coremidi_midiport.h index 91eccea4a5..d5d3c23ede 100644 --- a/libs/midi++2/midi++/coremidi_midiport.h +++ b/libs/midi++2/midi++/coremidi_midiport.h @@ -22,6 +22,7 @@ #include <list> #include <string> +#include <vector> #include <fcntl.h> #include <unistd.h> @@ -32,45 +33,47 @@ namespace MIDI { -namespace PortRequest; + class CoreMidi_MidiPort:public Port { + public: + CoreMidi_MidiPort(const XMLNode& node); + virtual ~ CoreMidi_MidiPort(); -class CoreMidi_MidiPort:public Port -{ - public: - CoreMidi_MidiPort(PortRequest & req); - virtual ~ CoreMidi_MidiPort(); - - virtual int selectable() const { - return -1; - } - static std::string typestring; + virtual int selectable() const { + return -1; + } + + static int discover (std::vector<PortSet>&); + static std::string typestring; + + protected: + /* Direct I/O */ + int write (byte * msg, size_t msglen, timestamp_t timestamp); - protected: + int read (byte * buf, size_t max, timestamp_t timestamp) { + return 0; + } + + /* CoreMidi callback */ + static void read_proc(const MIDIPacketList * pktlist, + void *refCon, void *connRefCon); + std::string get_typestring () const { return typestring; } - protected: - /* Direct I/O */ - int write (byte *msg, size_t msglen, timestamp_t timestamp); - int read (byte *buf, size_t max, timestamp_t timestamp); - - /* CoreMidi callback */ - static void read_proc(const MIDIPacketList * pktlist, - void *refCon, void *connRefCon); - - private: - byte midi_buffer[1024]; - MIDIClientRef midi_client; - MIDIEndpointRef midi_destination; - MIDIEndpointRef midi_source; + private: + byte midi_buffer[1024]; + MIDIClientRef midi_client; + MIDIEndpointRef midi_destination; + MIDIEndpointRef midi_source; - int Open(PortRequest & req); - void Close(); - static MIDITimeStamp MIDIGetCurrentHostTime(); + int Open(const Port::Descriptor&); + void Close(); + static MIDITimeStamp MIDIGetCurrentHostTime(); - bool firstrecv; -}; + bool firstrecv; + + }; } // namespace MIDI diff --git a/libs/midi++2/midi++/factory.h b/libs/midi++2/midi++/factory.h index 9954ea72fe..f3402546e9 100644 --- a/libs/midi++2/midi++/factory.h +++ b/libs/midi++2/midi++/factory.h @@ -23,13 +23,12 @@ #include <string> #include <midi++/port.h> -#include <midi++/port_request.h> namespace MIDI { class PortFactory { public: - Port *create_port (PortRequest &req, void* data); + Port *create_port (const XMLNode&, void* data); static bool ignore_duplicate_devices (Port::Type); static int get_known_ports (std::vector<PortSet>&); diff --git a/libs/midi++2/midi++/fd_midiport.h b/libs/midi++2/midi++/fd_midiport.h index 34e2e27a1a..ec5a9f8af4 100644 --- a/libs/midi++2/midi++/fd_midiport.h +++ b/libs/midi++2/midi++/fd_midiport.h @@ -29,7 +29,6 @@ #include <unistd.h> #include <midi++/port.h> -#include <midi++/port_request.h> namespace MIDI { @@ -37,7 +36,7 @@ class FD_MidiPort : public Port { public: - FD_MidiPort (PortRequest &req, + FD_MidiPort (const XMLNode& node, const std::string &dirpath, const std::string &pattern); @@ -46,23 +45,14 @@ class FD_MidiPort : public Port } virtual int selectable() const; - static std::vector<std::string *> *list_devices (); - - static std::string typestring; - protected: - std::string get_typestring () const { - return typestring; - } + static std::vector<std::string *> *list_devices (); protected: int _fd; - virtual void open (PortRequest &req); + virtual void open (const Port::Descriptor&); - /* Direct I/O */ - - virtual int write (byte *msg, size_t msglen, - timestamp_t timestamp) { + virtual int write (byte *msg, size_t msglen, timestamp_t ignored) { int nwritten; if ((_mode & O_ACCMODE) == O_RDONLY) { @@ -89,8 +79,7 @@ class FD_MidiPort : public Port return nwritten; } - virtual int read (byte *buf, size_t max, - timestamp_t timestamp); + virtual int read (byte *buf, size_t max, timestamp_t ignored); private: static std::string *midi_dirpath; diff --git a/libs/midi++2/midi++/fifomidi.h b/libs/midi++2/midi++/fifomidi.h index ea644dde06..3439c27dcf 100644 --- a/libs/midi++2/midi++/fifomidi.h +++ b/libs/midi++2/midi++/fifomidi.h @@ -25,7 +25,6 @@ #include <unistd.h> #include <midi++/port.h> -#include <midi++/port_request.h> #include <midi++/fd_midiport.h> namespace MIDI { @@ -34,7 +33,7 @@ class FIFO_MidiPort : public MIDI::FD_MidiPort { public: - FIFO_MidiPort (PortRequest &req); + FIFO_MidiPort (const XMLNode&); ~FIFO_MidiPort () {}; static std::string typestring; @@ -45,7 +44,7 @@ class FIFO_MidiPort : public MIDI::FD_MidiPort } private: - void open (PortRequest &req); + void open (const Port::Descriptor&); }; } // namespace MIDI diff --git a/libs/midi++2/midi++/jack.h b/libs/midi++2/midi++/jack.h index 1f25609aac..845dd0c229 100644 --- a/libs/midi++2/midi++/jack.h +++ b/libs/midi++2/midi++/jack.h @@ -39,7 +39,7 @@ namespace MIDI class JACK_MidiPort : public Port { public: - JACK_MidiPort (PortRequest &req, jack_client_t* jack_client); + JACK_MidiPort (const XMLNode& node, jack_client_t* jack_client); virtual ~JACK_MidiPort (); /* No select(2)/poll(2)-based I/O */ @@ -49,6 +49,9 @@ public: static std::string typestring; + virtual XMLNode& get_state () const; + virtual void set_state (const XMLNode&); + protected: std::string get_typestring () const { return typestring; @@ -60,7 +63,7 @@ protected: int read(byte *buf, size_t max, timestamp_t timestamp); private: - int create_ports(PortRequest &req); + int create_ports(const XMLNode&); jack_client_t* _jack_client; jack_port_t* _jack_input_port; diff --git a/libs/midi++2/midi++/manager.h b/libs/midi++2/midi++/manager.h index eef52abe52..bb3bf9b999 100644 --- a/libs/midi++2/midi++/manager.h +++ b/libs/midi++2/midi++/manager.h @@ -21,6 +21,8 @@ #define __midi_manager_h__ #include <map> +#include <vector> + #include <string> #include <midi++/types.h> @@ -28,20 +30,18 @@ namespace MIDI { -/** Creates, stores, and manages system MIDI ports. - */ class Manager { public: ~Manager (); void set_api_data(void* data) { api_data = data; } - + /** Signal the start of an audio cycle. * This MUST be called before any reading/writing for this cycle. * Realtime safe. */ void cycle_start(nframes_t nframes); - + /** Signal the end of an audio cycle. * This signifies that the cycle began with @ref cycle_start has ended. * This MUST be called at the end of each cycle. @@ -49,13 +49,25 @@ class Manager { */ void cycle_end(); - Port *add_port (PortRequest &); + Port *add_port (const XMLNode& node); int remove_port (Port*); Port *port (std::string name); size_t nports () { return ports_by_device.size(); } + /* defaults for clients who are not picky */ + + Port *inputPort; + Port *outputPort; + channel_t inputChannelNumber; + channel_t outputChannelNumber; + + int set_input_port (std::string); + int set_output_port (std::string); + int set_input_channel (channel_t); + int set_output_channel (channel_t); + int foreach_port (int (*func)(const Port &, size_t n, void *), void *arg); @@ -70,7 +82,7 @@ class Manager { return theManager; } - static int parse_port_request (std::string str, Port::Type type); + int get_known_ports (std::vector<PortSet>&); private: /* This is a SINGLETON pattern */ @@ -81,7 +93,7 @@ class Manager { PortMap ports_by_device; /* canonical */ PortMap ports_by_tag; /* may contain duplicate Ports */ - void *api_data; + void* api_data; void close_ports (); }; diff --git a/libs/midi++2/midi++/nullmidi.h b/libs/midi++2/midi++/nullmidi.h index 6ed94db71c..8f36e6aed8 100644 --- a/libs/midi++2/midi++/nullmidi.h +++ b/libs/midi++2/midi++/nullmidi.h @@ -24,7 +24,6 @@ #include <string> #include <midi++/port.h> -#include <midi++/port_request.h> namespace MIDI { diff --git a/libs/midi++2/midi++/port.h b/libs/midi++2/midi++/port.h index e4338cf952..dcae446c42 100644 --- a/libs/midi++2/midi++/port.h +++ b/libs/midi++2/midi++/port.h @@ -20,10 +20,11 @@ #define __libmidi_port_h__ #include <string> +#include <iostream> #include <sigc++/sigc++.h> +#include <pbd/xml++.h> -#include <pbd/selectable.h> #include <midi++/types.h> #include <midi++/parser.h> @@ -44,64 +45,82 @@ class Port : public sigc::trackable { FIFO }; - Port (PortRequest &); + + Port (const XMLNode&); virtual ~Port (); + virtual XMLNode& get_state () const; + virtual 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); - /* Only for use by MidiManager. Don't ever call this. */ virtual void cycle_end(); - /* Direct I/O */ - - /** Read a message from port. - * @param buf Raw MIDI message to send - * @param max Max size to write to @a buf - * @param timestamp Time stamp in frames of this message (relative to cycle start) - * @return number of bytes successfully written to \a buf - */ - virtual int read(byte *buf, size_t max, timestamp_t timestamp) = 0; - /** Write a message to port. * @param msg Raw MIDI message to send * @param msglen Size of @a msg * @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; + virtual int write (byte *msg, size_t msglen, timestamp_t timestamp) = 0; + + /** Read a message from port. + * @param buf Raw MIDI message to send + * @param max Max size to write to @a buf + * @param timestamp Time stamp in frames of this message (relative to cycle start) + * @return number of bytes successfully written to \a buf + */ + virtual int read (byte *buf, size_t max, timestamp_t timestamp) = 0; /** Write a message to port. * @return true on success. * FIXME: describe semantics here */ - bool midimsg (byte *msg, size_t len, timestamp_t timestamp) { + int midimsg (byte *msg, size_t len, timestamp_t timestamp) { 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. + */ - /** Slow down 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. */ + * @return File descriptor, or -1 if not selectable. + */ virtual int selectable() const = 0; + 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; } + Parser *input() { return input_parser; } + Parser *output() { return output_parser; } void iostat (int *written, int *read, const size_t **in_counts, @@ -121,14 +140,21 @@ class Port : public sigc::trackable { } } - bool clock (); - 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; } - size_t number () const { return _number; } + 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(); + }; protected: bool _ok; @@ -147,10 +173,21 @@ class Port : public sigc::trackable { Parser *output_parser; size_t slowdown; + virtual std::string get_typestring () const = 0; + private: static size_t nports; }; +struct PortSet { + PortSet (std::string str) : owner (str) { } + + std::string owner; + std::list<XMLNode> ports; +}; + +std::ostream & operator << ( std::ostream & os, const Port & port ); + } // namespace MIDI #endif // __libmidi_port_h__ diff --git a/libs/midi++2/midi++/port_request.h b/libs/midi++2/midi++/port_request.h deleted file mode 100644 index dfde87a63c..0000000000 --- a/libs/midi++2/midi++/port_request.h +++ /dev/null @@ -1,66 +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 __midi_port_request_h__ -#define __midi_port_request_h__ - -#include <string> - -namespace MIDI { - -struct PortRequest { - enum Status { - Unknown, - OK, - Busy, - NoSuchFile, - TypeUnsupported, - NotAllowed - }; - const char *devname; - const char *tagname; - int mode; - Port::Type type; - Status status; - - PortRequest () { - devname = 0; - tagname = 0; - mode = 0; - type = Port::Unknown; - status = Unknown; - } - - PortRequest (const std::string &xdev, - const std::string &xtag, - const std::string &xmode, - const std::string &xtype); -}; - -struct PortSet { - PortSet (std::string str) : owner (str) { } - - std::string owner; - std::list<PortRequest> ports; -}; - -} // namespace MIDI - -#endif // __midi_port_request_h__ - diff --git a/libs/midi++2/midifactory.cc b/libs/midi++2/midifactory.cc index 9d98d9f6a7..d893cc9f47 100644 --- a/libs/midi++2/midifactory.cc +++ b/libs/midi++2/midifactory.cc @@ -24,7 +24,6 @@ #include <midi++/types.h> #include <midi++/factory.h> -#include <midi++/nullmidi.h> #include <midi++/fifomidi.h> #ifdef WITH_JACK_MIDI @@ -33,7 +32,6 @@ std::string MIDI::JACK_MidiPort::typestring = "jack"; #endif // WITH_JACK_MIDI -std::string MIDI::Null_MidiPort::typestring = "null"; std::string MIDI::FIFO_MidiPort::typestring = "fifo"; #ifdef WITH_ALSA @@ -58,50 +56,44 @@ using namespace PBD; // FIXME: void* data pointer, filthy Port * -PortFactory::create_port (PortRequest &req, void* data) +PortFactory::create_port (const XMLNode& node, void* data) { + Port::Descriptor desc (node); Port *port; - switch (req.type) { + switch (desc.type) { #ifdef WITH_JACK_MIDI case Port::JACK_Midi: assert(data != NULL); - port = new JACK_MidiPort (req, (jack_client_t*)data); + 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 (req); + port = new ALSA_RawMidiPort (node); break; case Port::ALSA_Sequencer: - port = new ALSA_SequencerMidiPort (req); + port = new ALSA_SequencerMidiPort (node); break; #endif // WITH_ALSA #if WITH_COREMIDI case Port::CoreMidi_MidiPort: - port = new CoreMidi_MidiPort (req); + port = new CoreMidi_MidiPort (node); break; #endif // WITH_COREMIDI - case Port::Null: - port = new Null_MidiPort (req); - break; - case Port::FIFO: - port = new FIFO_MidiPort (req); + port = new FIFO_MidiPort (node); break; default: - req.status = PortRequest::TypeUnsupported; return 0; } - req.status = PortRequest::OK; - return port; } @@ -179,8 +171,6 @@ PortFactory::string_to_type (const string& xtype) } else if (strings_equal_ignore_case (xtype, CoreMidi_MidiPort::typestring)) { return Port::CoreMidi_MidiPort; #endif - } else if (strings_equal_ignore_case (xtype, Null_MidiPort::typestring)) { - return Port::Null; } else if (strings_equal_ignore_case (xtype, FIFO_MidiPort::typestring)) { return Port::FIFO; #ifdef WITH_JACK_MIDI diff --git a/libs/midi++2/midimanager.cc b/libs/midi++2/midimanager.cc index ee73bdad86..8a358c3183 100644 --- a/libs/midi++2/midimanager.cc +++ b/libs/midi++2/midimanager.cc @@ -27,21 +27,25 @@ #include <midi++/manager.h> #include <midi++/factory.h> #include <midi++/channel.h> -#include <midi++/port_request.h> using namespace std; using namespace MIDI; using namespace PBD; +/* XXX check for strdup leaks */ + Manager *Manager::theManager = 0; Manager::Manager () - : api_data(NULL) { + inputPort = 0; + outputPort = 0; + inputChannelNumber = 0; + outputChannelNumber = 0; + api_data = 0; } Manager::~Manager () - { PortMap::iterator i; @@ -58,27 +62,27 @@ Manager::~Manager () } Port * -Manager::add_port (PortRequest &req) - +Manager::add_port (const XMLNode& node) { + Port::Descriptor desc (node); PortFactory factory; Port *port; PortMap::iterator existing; pair<string, Port *> newpair; - if (!PortFactory::ignore_duplicate_devices (req.type)) { + if (!PortFactory::ignore_duplicate_devices (desc.type)) { - if ((existing = ports_by_device.find (req.devname)) != ports_by_device.end()) { + if ((existing = ports_by_device.find (desc.device)) != ports_by_device.end()) { port = (*existing).second; - if (port->mode() == req.mode) { + if (port->mode() == desc.mode) { /* Same mode - reuse the port, and just create a new tag entry. */ - newpair.first = req.tagname; + newpair.first = desc.tag; newpair.second = port; ports_by_tag.insert (newpair); @@ -91,10 +95,10 @@ Manager::add_port (PortRequest &req) operation. */ - if ((req.mode == O_RDWR && port->mode() != O_RDWR) || - (req.mode != O_RDWR && port->mode() == O_RDWR)) { + if ((desc.mode == O_RDWR && port->mode() != O_RDWR) || + (desc.mode != O_RDWR && port->mode() == O_RDWR)) { error << "MIDIManager: port tagged \"" - << req.tagname + << desc.tag << "\" cannot be opened duplex and non-duplex" << endmsg; return 0; @@ -103,7 +107,8 @@ Manager::add_port (PortRequest &req) /* modes must be different or complementary */ } } - port = factory.create_port (req, api_data); + + port = factory.create_port (node, api_data); if (port == 0) { return 0; @@ -122,6 +127,18 @@ Manager::add_port (PortRequest &req) newpair.second = port; ports_by_device.insert (newpair); + /* first port added becomes the default input + port. + */ + + if (inputPort == 0) { + inputPort = port; + } + + if (outputPort == 0) { + outputPort = port; + } + return port; } @@ -156,119 +173,88 @@ Manager::remove_port (Port* port) return 0; } -Port * -Manager::port (string name) +int +Manager::set_input_port (string tag) { PortMap::iterator res; + bool found = false; for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) { - if (name == (*res).first) { - return (*res).second; + if (tag == (*res).first) { + found = true; + break; } } + + if (!found) { + return -1; + } + + inputPort = (*res).second; return 0; } int -Manager::foreach_port (int (*func)(const Port &, size_t, void *), - void *arg) +Manager::set_output_port (string tag) { - PortMap::const_iterator i; - int retval; - int n; - - for (n = 0, i = ports_by_device.begin(); - i != ports_by_device.end(); i++, n++) { + PortMap::iterator res; + bool found = false; - if ((retval = func (*((*i).second), n, arg)) != 0) { - return retval; + for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) { + if (tag == (*res).first) { + found = true; + break; } } - - return 0; -} - -int -Manager::parse_port_request (string str, Port::Type type) -{ - PortRequest *req; - string::size_type colon; - string tag; - - if (str.length() == 0) { - error << "MIDI: missing port specification" << endmsg; + + if (!found) { return -1; } - /* Port specifications look like: + // XXX send a signal to say we're about to change output ports - devicename - devicename:tagname - devicename:tagname:mode + if (outputPort) { + for (channel_t chan = 0; chan < 16; chan++) { + outputPort->channel (chan)->all_notes_off (0); + } + } + outputPort = (*res).second; - where + // XXX send a signal to say we've changed output ports - "devicename" is the full path to the requested file - - "tagname" (optional) is the name used to refer to the - port. If not given, g_path_get_basename (devicename) - will be used. + return 0; +} - "mode" (optional) is either "r" or "w" or something else. - if it is "r", the port will be opened - read-only, if "w", the port will be opened - write-only. Any other value, or no mode - specification at all, will cause the port to - be opened for reading and writing. - */ - - req = new PortRequest; - colon = str.find_first_of (':'); +Port * +Manager::port (string name) +{ + PortMap::iterator res; - if (colon != string::npos) { - req->devname = strdup (str.substr (0, colon).c_str()); - } else { - req->devname = strdup (str.c_str()); + for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) { + if (name == (*res).first) { + return (*res).second; + } } - if (colon < str.length()) { - - tag = str.substr (colon+1); + return 0; +} - /* see if there is a mode specification in the tag part */ +int +Manager::foreach_port (int (*func)(const Port &, size_t, void *), + void *arg) +{ + PortMap::const_iterator i; + int retval; + int n; - colon = tag.find_first_of (':'); - - if (colon != string::npos) { - string modestr; - - req->tagname = strdup (tag.substr (0, colon).c_str()); - - modestr = tag.substr (colon+1); - if (modestr == "r") { - req->mode = O_RDONLY; - } else if (modestr == "w") { - req->mode = O_WRONLY; - } else { - req->mode = O_RDWR; - } + for (n = 0, i = ports_by_device.begin(); + i != ports_by_device.end(); i++, n++) { - } else { - req->tagname = strdup (tag.c_str()); - req->mode = O_RDWR; + if ((retval = func (*((*i).second), n, arg)) != 0) { + return retval; } - - } else { - req->tagname = g_path_get_basename (req->devname); - req->mode = O_RDWR; - } - - req->type = type; - - if (MIDI::Manager::instance()->add_port (*req) == 0) { - return -1; } return 0; @@ -277,16 +263,22 @@ Manager::parse_port_request (string str, Port::Type type) void Manager::cycle_start(nframes_t nframes) { - for (PortMap::iterator i = ports_by_device.begin(); - i != ports_by_device.end(); i++) - (*i).second->cycle_start(nframes); + for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) { + (*i).second->cycle_start (nframes); + } } void Manager::cycle_end() { - for (PortMap::iterator i = ports_by_device.begin(); - i != ports_by_device.end(); i++) - (*i).second->cycle_end(); + for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) { + (*i).second->cycle_end (); + } } + +int +Manager::get_known_ports (vector<PortSet>& ports) +{ + return PortFactory::get_known_ports (ports); +} diff --git a/libs/midi++2/midiport.cc b/libs/midi++2/midiport.cc index 7f31b909d3..2e3d36c19c 100644 --- a/libs/midi++2/midiport.cc +++ b/libs/midi++2/midiport.cc @@ -17,24 +17,29 @@ $Id$ */ - +#include <iostream> #include <cstdio> #include <fcntl.h> +#include <pbd/xml++.h> +#include <pbd/failed_constructor.h> + #include <midi++/types.h> #include <midi++/port.h> #include <midi++/channel.h> -#include <midi++/port_request.h> +#include <midi++/factory.h> -using namespace Select; using namespace MIDI; +using namespace std; size_t Port::nports = 0; -Port::Port (PortRequest &req) +Port::Port (const XMLNode& node) : _currently_in_cycle(false) , _nframes_this_cycle(0) { + Descriptor desc (node); + _ok = false; /* derived class must set to true if constructor succeeds. */ @@ -45,10 +50,9 @@ Port::Port (PortRequest &req) output_parser = 0; slowdown = 0; - _devname = req.devname; - _tagname = req.tagname; - _mode = req.mode; - _number = nports++; + _devname = desc.device; + _tagname = desc.tag; + _mode = desc.mode; if (_mode == O_RDONLY || _mode == O_RDWR) { input_parser = new Parser (*this); @@ -77,7 +81,6 @@ Port::Port (PortRequest &req) Port::~Port () - { for (int i = 0; i < 16; i++) { delete _channel[i]; @@ -113,3 +116,87 @@ Port::cycle_end () _nframes_this_cycle = 0; } +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()); + + return *node; +} + +void +Port::set_state (const XMLNode& node) +{ + // relax +} + +void +Port::gtk_read_callback (void *ptr, int fd, int cond) +{ + byte buf[64]; + + ((Port *)ptr)->read (buf, sizeof (buf), 0); +} + +void +Port::write_callback (byte *msg, unsigned int len, void *ptr) + +{ + ((Port *)ptr)->write (msg, len, 0); +} + +std::ostream & MIDI::operator << ( std::ostream & os, const MIDI::Port & port ) +{ + 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; +} + +Port::Descriptor::Descriptor (const XMLNode& node) +{ + 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; + } + + 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(); + } +} + diff --git a/libs/midi++2/miditrace.cc b/libs/midi++2/miditrace.cc index d7c65d9f29..fafe822f82 100644 --- a/libs/midi++2/miditrace.cc +++ b/libs/midi++2/miditrace.cc @@ -11,7 +11,6 @@ Transmitter fatal (Transmitter::Fatal); TextReceiver text_receiver ("mmctest"); #include "midi++/port.h" -#include "midi++/port_request.h" #include "midi++/manager.h" using namespace MIDI; diff --git a/libs/midi++2/mmctest.cc b/libs/midi++2/mmctest.cc index 36fbd61124..062f6e8d32 100644 --- a/libs/midi++2/mmctest.cc +++ b/libs/midi++2/mmctest.cc @@ -11,7 +11,6 @@ Transmitter fatal (Transmitter::Fatal); TextReceiver text_receiver ("mmctest"); #include "midi++/port.h" -#include "midi++/port_request.h" #include "midi++/manager.h" #include "midi++/mmc.h" diff --git a/libs/midi++2/port_request.cc b/libs/midi++2/port_request.cc deleted file mode 100644 index d209f02574..0000000000 --- a/libs/midi++2/port_request.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - Copyright (C) 2000 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 <fcntl.h> -#include <string.h> -#include <midi++/port.h> -#include <midi++/port_request.h> - -using namespace std; -using namespace MIDI; - -PortRequest::PortRequest (const string &xdev, - const string &xtag, - const string &xmode, - const string &xtype) - -{ - status = OK; - - devname = strdup (xdev.c_str()); - tagname = strdup (xtag.c_str()); - - if (xmode == "output" || - xmode == "out" || - xmode == "OUTPUT" || - xmode == "OUT") { - mode = O_WRONLY; - - } else if (xmode == "input" || - xmode == "in" || - xmode == "INPUT" || - xmode == "IN") { - mode = O_RDONLY; - - } else if (xmode == "duplex" || - xmode == "DUPLEX" || - xmode == "inout" || - xmode == "INOUT") { - mode = O_RDWR; - } else { - status = Unknown; - } - - if (xtype == "JACK" || - xtype == "jack") { - type = Port::JACK_Midi; - } else if (xtype == "ALSA/RAW" || - xtype == "alsa/raw") { - type = Port::ALSA_RawMidi; - } else if (xtype == "ALSA/SEQUENCER" || - xtype == "alsa/sequencer") { - type = Port::ALSA_Sequencer; - } else if (xtype == "COREMIDI" || - xtype == "coremidi") { - type = Port::CoreMidi_MidiPort; - } else if (xtype == "NULL" || - xtype == "null") { - type = Port::Null; - } else if (xtype == "FIFO" || - xtype == "fifo") { - type = Port::FIFO; - } else { - status = Unknown; - } -} - |