auto-re-connect ALSA seq ports at startup, if they were connected; may break OS X compilation till tomorrow morning (US Eastern TZ)

git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2489 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2007-09-27 04:20:31 +00:00
parent 0fe9b63100
commit e79a7e8ff9
28 changed files with 326 additions and 399 deletions

View file

@ -712,12 +712,15 @@ OptionEditor::add_midi_port ()
smod = "duplex"; smod = "duplex";
} }
MIDI::PortRequest req (X_("ardour"),
dialog.port_name.get_text(),
smod,
MIDI::PortFactory::default_port_type());
if (MIDI::Manager::instance()->add_port (req) != 0) { XMLNode node (X_("MIDI-port"));
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) {
redisplay_midi_ports (); redisplay_midi_ports ();
} }
} }

View file

@ -42,17 +42,7 @@ class Configuration : public Stateful
Configuration(); Configuration();
virtual ~Configuration(); virtual ~Configuration();
struct MidiPortDescriptor { std::map<std::string,XMLNode> midi_ports;
std::string tag;
std::string device;
std::string type;
std::string mode;
MidiPortDescriptor (const XMLNode&);
XMLNode& get_state();
};
std::map<std::string,MidiPortDescriptor *> midi_ports;
void map_parameters (sigc::slot<void,const char*> theSlot); void map_parameters (sigc::slot<void,const char*> theSlot);

View file

@ -217,10 +217,12 @@ Configuration::set_state (const XMLNode& root)
if (node->name() == "MIDI-port") { if (node->name() == "MIDI-port") {
try { try {
pair<string,MidiPortDescriptor*> newpair; MIDI::Port::Descriptor desc (*node);
newpair.second = new MidiPortDescriptor (*node); map<string,XMLNode>::iterator x;
newpair.first = newpair.second->tag; if ((x = midi_ports.find (desc.tag)) != midi_ports.end()) {
midi_ports.insert (newpair); midi_ports.erase (x);
}
midi_ports.insert (pair<string,XMLNode>(desc.tag,*node));
} }
catch (failed_constructor& err) { catch (failed_constructor& err) {
@ -263,52 +265,6 @@ Configuration::set_variables (const XMLNode& node, ConfigVariableBase::Owner own
} }
Configuration::MidiPortDescriptor::MidiPortDescriptor (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 = prop->value();
have_type = true;
}
if ((prop = node.property ("mode")) != 0) {
mode = prop->value();
have_mode = true;
}
if (!have_tag || !have_device || !have_type || !have_mode) {
throw failed_constructor();
}
}
XMLNode&
Configuration::MidiPortDescriptor::get_state()
{
XMLNode* root = new XMLNode("MIDI-port");
root->add_property("tag", tag);
root->add_property("device", device);
root->add_property("type", type);
root->add_property("mode", mode);
return *root;
}
void void
Configuration::map_parameters (sigc::slot<void,const char*> theSlot) Configuration::map_parameters (sigc::slot<void,const char*> theSlot)
{ {

View file

@ -32,6 +32,8 @@
#include <xmmintrin.h> #include <xmmintrin.h>
#endif #endif
#include <glibmm/fileutils.h>
#include <lrdf.h> #include <lrdf.h>
#include <pbd/error.h> #include <pbd/error.h>
@ -40,7 +42,6 @@
#include <pbd/fpu.h> #include <pbd/fpu.h>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/port_request.h>
#include <midi++/manager.h> #include <midi++/manager.h>
#include <midi++/mmc.h> #include <midi++/mmc.h>
@ -110,29 +111,13 @@ setup_osc ()
static int static int
setup_midi () setup_midi ()
{ {
std::map<string,Configuration::MidiPortDescriptor*>::iterator i;
if (Config->midi_ports.size() == 0) { if (Config->midi_ports.size() == 0) {
warning << _("no MIDI ports specified: no MMC or MTC control possible") << endmsg; warning << _("no MIDI ports specified: no MMC or MTC control possible") << endmsg;
return 0; return 0;
} }
for (i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) { for (std::map<string,XMLNode>::iterator i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) {
Configuration::MidiPortDescriptor* port_descriptor; MIDI::Manager::instance()->add_port (i->second);
port_descriptor = (*i).second;
MIDI::PortRequest request (port_descriptor->device,
port_descriptor->tag,
port_descriptor->mode,
port_descriptor->type);
if (request.status != MIDI::PortRequest::OK) {
error << string_compose(_("MIDI port specifications for \"%1\" are not understandable."), port_descriptor->tag) << endmsg;
continue;
}
MIDI::Manager::instance()->add_port (request);
} }
MIDI::Port* first; MIDI::Port* first;
@ -144,8 +129,6 @@ setup_midi ()
/* More than one port, so try using specific names for each port */ /* More than one port, so try using specific names for each port */
map<string,Configuration::MidiPortDescriptor *>::iterator i;
if (Config->get_mmc_port_name() != N_("default")) { if (Config->get_mmc_port_name() != N_("default")) {
default_mmc_port = MIDI::Manager::instance()->port (Config->get_mmc_port_name()); default_mmc_port = MIDI::Manager::instance()->port (Config->get_mmc_port_name());
} }
@ -443,7 +426,7 @@ find_file (string name, string dir, string subdir = "")
for (vector<string>::iterator i = split_path.begin(); i != split_path.end(); ++i) { for (vector<string>::iterator i = split_path.begin(); i != split_path.end(); ++i) {
path = *i; path = *i;
path += "/" + name; path += "/" + name;
if (access (path.c_str(), R_OK) == 0) { if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
// cerr << "Using file " << path << " found in ARDOUR_PATH." << endl; // cerr << "Using file " << path << " found in ARDOUR_PATH." << endl;
return path; return path;
} }

View file

@ -33,6 +33,7 @@
#include <pbd/error.h> #include <pbd/error.h>
#include <pbd/pathscanner.h> #include <pbd/pathscanner.h>
#include <pbd/xml++.h> #include <pbd/xml++.h>
#include <pbd/stacktrace.h>
#include <ardour/ardour.h> #include <ardour/ardour.h>
#include <ardour/session.h> #include <ardour/session.h>

View file

@ -23,7 +23,6 @@ midiparser.cc
midiport.cc midiport.cc
mmc.cc mmc.cc
mtc.cc mtc.cc
port_request.cc
version.cc version.cc
""") """)

View file

@ -23,10 +23,12 @@
#include <pbd/failed_constructor.h> #include <pbd/failed_constructor.h>
#include <pbd/error.h> #include <pbd/error.h>
#include <pbd/xml++.h>
#include <midi++/types.h> #include <midi++/types.h>
#include <midi++/alsa_sequencer.h> #include <midi++/alsa_sequencer.h>
#include <midi++/port_request.h>
#include "i18n.h"
//#define DOTRACE 1 //#define DOTRACE 1
@ -44,31 +46,31 @@ using namespace PBD;
snd_seq_t* ALSA_SequencerMidiPort::seq = 0; snd_seq_t* ALSA_SequencerMidiPort::seq = 0;
ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (PortRequest &req) ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (const XMLNode& node)
: Port (req) : Port (node)
, decoder (0) , decoder (0)
, encoder (0) , encoder (0)
, port_id (-1) , port_id (-1)
{ {
TR_FN(); TR_FN();
int err; int err;
Descriptor desc (node);
if (!seq && init_client (req.devname) < 0) { if (!seq && init_client (desc.device) < 0) {
_ok = false; _ok = false;
} else { } 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 (1024, &decoder)) && // Length taken from ARDOUR::Session::midi_read ()
0 <= (err = snd_midi_event_new (64, &encoder))) { // Length taken from ARDOUR::Session::mmc_buffer 0 <= (err = snd_midi_event_new (64, &encoder))) { // Length taken from ARDOUR::Session::mmc_buffer
snd_midi_event_init (decoder); snd_midi_event_init (decoder);
snd_midi_event_init (encoder); snd_midi_event_init (encoder);
_ok = true; _ok = true;
req.status = PortRequest::OK;
} else {
req.status = PortRequest::Unknown;
} }
} }
set_state (node);
} }
ALSA_SequencerMidiPort::~ALSA_SequencerMidiPort () ALSA_SequencerMidiPort::~ALSA_SequencerMidiPort ()
@ -160,17 +162,17 @@ ALSA_SequencerMidiPort::read (byte *buf, size_t max)
} }
int int
ALSA_SequencerMidiPort::CreatePorts (PortRequest &req) ALSA_SequencerMidiPort::create_ports (const Port::Descriptor& desc)
{ {
int err; int err;
unsigned int caps = 0; 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; 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; caps |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ;
if (0 <= (err = snd_seq_create_simple_port (seq, req.tagname, caps, if (0 <= (err = snd_seq_create_simple_port (seq, desc.tag.c_str(), caps,
(SND_SEQ_PORT_TYPE_MIDI_GENERIC| (SND_SEQ_PORT_TYPE_MIDI_GENERIC|
SND_SEQ_PORT_TYPE_SOFTWARE| SND_SEQ_PORT_TYPE_SOFTWARE|
SND_SEQ_PORT_TYPE_APPLICATION)))) { SND_SEQ_PORT_TYPE_APPLICATION)))) {
@ -271,7 +273,13 @@ ALSA_SequencerMidiPort::discover (vector<PortSet>& ports)
} }
} }
ports.back().ports.push_back (PortRequest (client, port, mode, "alsa/sequencer")); 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; ++n;
} }
} }
@ -279,3 +287,139 @@ ALSA_SequencerMidiPort::discover (vector<PortSet>& ports)
return 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;
}
}
}

View file

@ -23,7 +23,6 @@
#include <midi++/coremidi_midiport.h> #include <midi++/coremidi_midiport.h>
#include <midi++/types.h> #include <midi++/types.h>
#include <midi++/port_request.h>
#include <mach/mach_time.h> #include <mach/mach_time.h>
#include <pbd/pthread_utils.h> #include <pbd/pthread_utils.h>
@ -36,15 +35,15 @@ MIDITimeStamp CoreMidi_MidiPort::MIDIGetCurrentHostTime()
return mach_absolute_time(); 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; firstrecv = true;
int err; int err;
if (0 == (err = Open(req))) { if (0 == (err = Open(desc))) {
_ok = true; _ok = true;
req.status = PortRequest::OK; }
} else
req.status = PortRequest::Unknown;
} }
CoreMidi_MidiPort::~CoreMidi_MidiPort () {Close();} CoreMidi_MidiPort::~CoreMidi_MidiPort () {Close();}
@ -77,13 +76,13 @@ int CoreMidi_MidiPort::write (byte *msg, size_t msglen)
} }
} }
int CoreMidi_MidiPort::Open (PortRequest &req) int CoreMidi_MidiPort::Open (const Descriptor& desc)
{ {
OSStatus err; OSStatus err;
CFStringRef coutputStr; CFStringRef coutputStr;
string str; string str;
coutputStr = CFStringCreateWithCString(0, req.devname, CFStringGetSystemEncoding()); coutputStr = CFStringCreateWithCString(0, desc.device.c_str(), CFStringGetSystemEncoding());
err = MIDIClientCreate(coutputStr, 0, 0, &midi_client); err = MIDIClientCreate(coutputStr, 0, 0, &midi_client);
CFRelease(coutputStr); CFRelease(coutputStr);
if (!midi_client) { if (!midi_client) {
@ -91,7 +90,7 @@ int CoreMidi_MidiPort::Open (PortRequest &req)
goto error; goto error;
} }
str = req.tagname + string("_in"); str = desc.tag + string("_in");
coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding()); coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
err = MIDIDestinationCreate(midi_client, coutputStr, read_proc, this, &midi_destination); err = MIDIDestinationCreate(midi_client, coutputStr, read_proc, this, &midi_destination);
CFRelease(coutputStr); CFRelease(coutputStr);
@ -100,7 +99,7 @@ int CoreMidi_MidiPort::Open (PortRequest &req)
goto error; goto error;
} }
str = req.tagname + string("_out"); str = desc.tag + string("_out");
coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding()); coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
err = MIDISourceCreate(midi_client, coutputStr, &midi_source); err = MIDISourceCreate(midi_client, coutputStr, &midi_source);
CFRelease(coutputStr); CFRelease(coutputStr);

View file

@ -34,40 +34,38 @@ using namespace PBD;
string *FD_MidiPort::midi_dirpath = 0; string *FD_MidiPort::midi_dirpath = 0;
string *FD_MidiPort::midi_filename_pattern = 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 &dirpath,
const string &pattern) const string &pattern)
: Port (req) : Port (node)
{ {
open (req); Descriptor desc (node);
open (desc);
if (_fd < 0) { if (_fd < 0) {
switch (errno) { switch (errno) {
case EBUSY: case EBUSY:
error << "MIDI: port device in use" << endmsg; error << "MIDI: port device in use" << endmsg;
req.status = PortRequest::Busy;
break; break;
case ENOENT: case ENOENT:
error << "MIDI: no such port device" << endmsg; error << "MIDI: no such port device" << endmsg;
req.status = PortRequest::NoSuchFile;
break; break;
case EACCES: case EACCES:
error << "MIDI: access to port denied" << endmsg; error << "MIDI: access to port denied" << endmsg;
req.status = PortRequest::NotAllowed;
break; break;
default: default:
req.status = PortRequest::Unknown; break;
} }
} else { } else {
_ok = true; _ok = true;
req.status = PortRequest::OK;
if (midi_dirpath == 0) { if (midi_dirpath == 0) {
midi_dirpath = new string (dirpath); midi_dirpath = new string (dirpath);
midi_filename_pattern = new string (pattern); midi_filename_pattern = new string (pattern);
} }
if (req.mode & O_NONBLOCK == 0) { if (desc.mode & O_NONBLOCK == 0) {
/* we unconditionally set O_NONBLOCK during /* we unconditionally set O_NONBLOCK during
open, but the request didn't ask for it, open, but the request didn't ask for it,
so remove it. so remove it.
@ -80,11 +78,11 @@ FD_MidiPort::FD_MidiPort (PortRequest &req,
} }
void void
FD_MidiPort::open (PortRequest &req) FD_MidiPort::open (const Descriptor& desc)
{ {
int mode = req.mode | O_NONBLOCK; int mode = desc.mode | O_NONBLOCK;
_fd = ::open (req.devname, mode); _fd = ::open (desc.device.c_str(), mode);
} }
vector<string *> * vector<string *> *

View file

@ -26,19 +26,19 @@
using namespace MIDI; using namespace MIDI;
FIFO_MidiPort::FIFO_MidiPort (PortRequest &req) FIFO_MidiPort::FIFO_MidiPort (const XMLNode& node)
: FD_MidiPort (req, ".", "midi") : FD_MidiPort (node, ".", "midi")
{ {
} }
void 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 /* This is a placeholder for the fun-and-games I think we will
need to do with FIFO's. need to do with FIFO's.
*/ */
_fd = ::open (req.devname, req.mode|O_NDELAY); _fd = ::open (desc.device.c_str(), desc.mode|O_NDELAY);
} }

View file

@ -34,8 +34,8 @@ class ALSA_RawMidiPort : public MIDI::FD_MidiPort
{ {
public: public:
ALSA_RawMidiPort (MIDI::PortRequest &req) ALSA_RawMidiPort (const XMLNode& node)
: FD_MidiPort (req, "/dev/snd", "midi") {} : FD_MidiPort (node, "/dev/snd", "midi") {}
virtual ~ALSA_RawMidiPort () {} virtual ~ALSA_RawMidiPort () {}
static std::string typestring; static std::string typestring;

View file

@ -27,7 +27,6 @@
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/port_request.h>
namespace MIDI { namespace MIDI {
@ -35,7 +34,7 @@ class ALSA_SequencerMidiPort : public Port
{ {
public: public:
ALSA_SequencerMidiPort (PortRequest &req); ALSA_SequencerMidiPort (const XMLNode&);
virtual ~ALSA_SequencerMidiPort (); virtual ~ALSA_SequencerMidiPort ();
/* select(2)/poll(2)-based I/O */ /* select(2)/poll(2)-based I/O */
@ -45,6 +44,9 @@ class ALSA_SequencerMidiPort : public Port
static int discover (std::vector<PortSet>&); static int discover (std::vector<PortSet>&);
static std::string typestring; static std::string typestring;
XMLNode& get_state() const;
void set_state (const XMLNode&);
protected: protected:
/* Direct I/O */ /* Direct I/O */
@ -60,10 +62,13 @@ class ALSA_SequencerMidiPort : public Port
int port_id; int port_id;
snd_seq_event_t SEv; snd_seq_event_t SEv;
int CreatePorts(PortRequest &req); int create_ports (const Port::Descriptor&);
static int init_client (std::string name); static int init_client (std::string name);
static snd_seq_t* seq; static snd_seq_t* seq;
typedef std::pair<int,int> SequencerPortAddress;
void get_connections (std::vector<SequencerPortAddress>&, int dir) const;
}; };
}; /* namespace MIDI */ }; /* namespace MIDI */

View file

@ -28,7 +28,6 @@
#include <unistd.h> #include <unistd.h>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/port_request.h>
#include <CoreMIDI/CoreMIDI.h> #include <CoreMIDI/CoreMIDI.h>
@ -36,7 +35,7 @@ namespace MIDI {
class CoreMidi_MidiPort:public Port { class CoreMidi_MidiPort:public Port {
public: public:
CoreMidi_MidiPort(PortRequest & req); CoreMidi_MidiPort(const XMLNode& node);
virtual ~ CoreMidi_MidiPort(); virtual ~ CoreMidi_MidiPort();
virtual int selectable() const { virtual int selectable() const {
@ -68,7 +67,7 @@ namespace MIDI {
MIDIEndpointRef midi_destination; MIDIEndpointRef midi_destination;
MIDIEndpointRef midi_source; MIDIEndpointRef midi_source;
int Open(PortRequest & req); int Open(const Port::Descriptor&);
void Close(); void Close();
static MIDITimeStamp MIDIGetCurrentHostTime(); static MIDITimeStamp MIDIGetCurrentHostTime();

View file

@ -23,13 +23,12 @@
#include <string> #include <string>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/port_request.h>
namespace MIDI { namespace MIDI {
class PortFactory { class PortFactory {
public: public:
Port *create_port (PortRequest &req); Port *create_port (const XMLNode&);
static bool ignore_duplicate_devices (Port::Type); static bool ignore_duplicate_devices (Port::Type);
static int get_known_ports (std::vector<PortSet>&); static int get_known_ports (std::vector<PortSet>&);

View file

@ -29,7 +29,6 @@
#include <unistd.h> #include <unistd.h>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/port_request.h>
namespace MIDI { namespace MIDI {
@ -37,7 +36,7 @@ class FD_MidiPort : public Port
{ {
public: public:
FD_MidiPort (PortRequest &req, FD_MidiPort (const XMLNode& node,
const std::string &dirpath, const std::string &dirpath,
const std::string &pattern); const std::string &pattern);
@ -51,7 +50,7 @@ class FD_MidiPort : public Port
protected: protected:
int _fd; int _fd;
virtual void open (PortRequest &req); virtual void open (const Port::Descriptor&);
virtual int write (byte *msg, size_t msglen) { virtual int write (byte *msg, size_t msglen) {
int nwritten; int nwritten;

View file

@ -25,7 +25,6 @@
#include <unistd.h> #include <unistd.h>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/port_request.h>
#include <midi++/fd_midiport.h> #include <midi++/fd_midiport.h>
namespace MIDI { namespace MIDI {
@ -34,7 +33,7 @@ class FIFO_MidiPort : public MIDI::FD_MidiPort
{ {
public: public:
FIFO_MidiPort (PortRequest &req); FIFO_MidiPort (const XMLNode&);
~FIFO_MidiPort () {}; ~FIFO_MidiPort () {};
static std::string typestring; static std::string typestring;
@ -45,7 +44,7 @@ class FIFO_MidiPort : public MIDI::FD_MidiPort
} }
private: private:
void open (PortRequest &req); void open (const Port::Descriptor&);
}; };
} // namespace MIDI } // namespace MIDI

View file

@ -27,7 +27,6 @@
#include <midi++/types.h> #include <midi++/types.h>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/port_request.h>
namespace MIDI { namespace MIDI {
@ -35,7 +34,7 @@ class Manager {
public: public:
~Manager (); ~Manager ();
Port *add_port (PortRequest &); Port *add_port (const XMLNode& node);
int remove_port (Port*); int remove_port (Port*);
Port *port (std::string name); Port *port (std::string name);
@ -68,8 +67,6 @@ class Manager {
return theManager; return theManager;
} }
static int parse_port_request (std::string str, Port::Type type);
int get_known_ports (std::vector<PortSet>&); int get_known_ports (std::vector<PortSet>&);
private: private:

View file

@ -24,7 +24,6 @@
#include <string> #include <string>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/port_request.h>
namespace MIDI { namespace MIDI {
@ -32,8 +31,8 @@ class Null_MidiPort : public Port
{ {
public: public:
Null_MidiPort (PortRequest &req) Null_MidiPort (const XMLNode& node)
: Port (req) { : Port (node) {
/* reset devname and tagname */ /* reset devname and tagname */

View file

@ -23,12 +23,11 @@
#include <iostream> #include <iostream>
#include <sigc++/sigc++.h> #include <sigc++/sigc++.h>
#include <pbd/xml++.h>
#include <midi++/types.h> #include <midi++/types.h>
#include <midi++/parser.h> #include <midi++/parser.h>
class XMLNode;
namespace MIDI { namespace MIDI {
class Channel; class Channel;
@ -46,10 +45,11 @@ class Port : public sigc::trackable {
}; };
Port (PortRequest &); Port (const XMLNode&);
virtual ~Port (); virtual ~Port ();
virtual XMLNode& get_state () const; virtual XMLNode& get_state () const;
virtual void set_state (const XMLNode&);
/* Direct I/O */ /* Direct I/O */
@ -124,6 +124,16 @@ class Port : public sigc::trackable {
int mode () const { return _mode; } int mode () const { return _mode; }
bool ok () const { return _ok; } 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: protected:
bool _ok; bool _ok;
Type _type; Type _type;
@ -144,6 +154,13 @@ class Port : public sigc::trackable {
static size_t nports; 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 ); std::ostream & operator << ( std::ostream & os, const Port & port );
} // namespace MIDI } // namespace MIDI

View file

@ -1,67 +0,0 @@
/*
Copyright (C) 1999-2007 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 __midi_port_request_h__
#define __midi_port_request_h__
#include <list>
#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__

View file

@ -52,43 +52,40 @@ using namespace MIDI;
using namespace PBD; using namespace PBD;
Port * Port *
PortFactory::create_port (PortRequest &req) PortFactory::create_port (const XMLNode& node)
{ {
Port::Descriptor desc (node);
Port *port; Port *port;
switch (req.type) { switch (desc.type) {
#ifdef WITH_ALSA #ifdef WITH_ALSA
case Port::ALSA_RawMidi: case Port::ALSA_RawMidi:
port = new ALSA_RawMidiPort (req); port = new ALSA_RawMidiPort (node);
break; break;
case Port::ALSA_Sequencer: case Port::ALSA_Sequencer:
port = new ALSA_SequencerMidiPort (req); port = new ALSA_SequencerMidiPort (node);
break; break;
#endif // WITH_ALSA #endif // WITH_ALSA
#if WITH_COREMIDI #if WITH_COREMIDI
case Port::CoreMidi_MidiPort: case Port::CoreMidi_MidiPort:
port = new CoreMidi_MidiPort (req); port = new CoreMidi_MidiPort (node);
break; break;
#endif // WITH_COREMIDI #endif // WITH_COREMIDI
case Port::Null: case Port::Null:
port = new Null_MidiPort (req); port = new Null_MidiPort (node);
break; break;
case Port::FIFO: case Port::FIFO:
port = new FIFO_MidiPort (req); port = new FIFO_MidiPort (node);
break; break;
default: default:
req.status = PortRequest::TypeUnsupported;
return 0; return 0;
} }
req.status = PortRequest::OK;
return port; return port;
} }

View file

@ -27,7 +27,6 @@
#include <midi++/manager.h> #include <midi++/manager.h>
#include <midi++/factory.h> #include <midi++/factory.h>
#include <midi++/channel.h> #include <midi++/channel.h>
#include <midi++/port_request.h>
using namespace std; using namespace std;
using namespace MIDI; using namespace MIDI;
@ -64,27 +63,27 @@ Manager::~Manager ()
} }
Port * Port *
Manager::add_port (PortRequest &req) Manager::add_port (const XMLNode& node)
{ {
Port::Descriptor desc (node);
PortFactory factory; PortFactory factory;
Port *port; Port *port;
PortMap::iterator existing; PortMap::iterator existing;
pair<string, Port *> newpair; 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; port = (*existing).second;
if (port->mode() == req.mode) { if (port->mode() == desc.mode) {
/* Same mode - reuse the port, and just /* Same mode - reuse the port, and just
create a new tag entry. create a new tag entry.
*/ */
newpair.first = req.tagname; newpair.first = desc.tag;
newpair.second = port; newpair.second = port;
ports_by_tag.insert (newpair); ports_by_tag.insert (newpair);
@ -97,10 +96,10 @@ Manager::add_port (PortRequest &req)
operation. operation.
*/ */
if ((req.mode == O_RDWR && port->mode() != O_RDWR) || if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
(req.mode != O_RDWR && port->mode() == O_RDWR)) { (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
error << "MIDIManager: port tagged \"" error << "MIDIManager: port tagged \""
<< req.tagname << desc.tag
<< "\" cannot be opened duplex and non-duplex" << "\" cannot be opened duplex and non-duplex"
<< endmsg; << endmsg;
return 0; return 0;
@ -110,7 +109,7 @@ Manager::add_port (PortRequest &req)
} }
} }
port = factory.create_port (req); port = factory.create_port (node);
if (port == 0) { if (port == 0) {
return 0; return 0;
@ -262,90 +261,6 @@ Manager::foreach_port (int (*func)(const Port &, size_t, void *),
return 0; 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;
return -1;
}
/* Port specifications look like:
devicename
devicename:tagname
devicename:tagname:mode
where
"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.
"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 (':');
if (colon != string::npos) {
req->devname = strdup (str.substr (0, colon).c_str());
} else {
req->devname = strdup (str.c_str());
}
if (colon < str.length()) {
tag = str.substr (colon+1);
/* see if there is a mode specification in the tag part */
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;
}
} else {
req->tagname = strdup (tag.c_str());
req->mode = O_RDWR;
}
} else {
// check when tagname is freed
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;
}
int int
Manager::get_known_ports (vector<PortSet>& ports) Manager::get_known_ports (vector<PortSet>& ports)

View file

@ -17,26 +17,27 @@
$Id$ $Id$
*/ */
#include <iostream>
#include <cstdio> #include <cstdio>
#include <fcntl.h> #include <fcntl.h>
#include <pbd/xml++.h> #include <pbd/xml++.h>
#include <pbd/failed_constructor.h>
#include <midi++/types.h> #include <midi++/types.h>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/channel.h> #include <midi++/channel.h>
#include <midi++/port_request.h>
#include <midi++/factory.h> #include <midi++/factory.h>
//using namespace Select;
using namespace MIDI; using namespace MIDI;
using namespace std;
size_t Port::nports = 0; size_t Port::nports = 0;
Port::Port (PortRequest &req) Port::Port (const XMLNode& node)
{ {
Descriptor desc (node);
_ok = false; /* derived class must set to true if constructor _ok = false; /* derived class must set to true if constructor
succeeds. succeeds.
*/ */
@ -47,9 +48,9 @@ Port::Port (PortRequest &req)
output_parser = 0; output_parser = 0;
slowdown = 0; slowdown = 0;
_devname = req.devname; _devname = desc.device;
_tagname = req.tagname; _tagname = desc.tag;
_mode = req.mode; _mode = desc.mode;
if (_mode == O_RDONLY || _mode == O_RDWR) { if (_mode == O_RDONLY || _mode == O_RDWR) {
input_parser = new Parser (*this); input_parser = new Parser (*this);
@ -97,6 +98,12 @@ Port::get_state () const
return *node; return *node;
} }
void
Port::set_state (const XMLNode& node)
{
// relax
}
int int
Port::clock () Port::clock ()
@ -163,3 +170,36 @@ std::ostream & MIDI::operator << ( std::ostream & os, const MIDI::Port & port )
return 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();
}
}

View file

@ -11,7 +11,6 @@ Transmitter fatal (Transmitter::Fatal);
TextReceiver text_receiver ("mmctest"); TextReceiver text_receiver ("mmctest");
#include "midi++/port.h" #include "midi++/port.h"
#include "midi++/port_request.h"
#include "midi++/manager.h" #include "midi++/manager.h"
using namespace MIDI; using namespace MIDI;

View file

@ -11,7 +11,6 @@ Transmitter fatal (Transmitter::Fatal);
TextReceiver text_receiver ("mmctest"); TextReceiver text_receiver ("mmctest");
#include "midi++/port.h" #include "midi++/port.h"
#include "midi++/port_request.h"
#include "midi++/manager.h" #include "midi++/manager.h"
#include "midi++/mmc.h" #include "midi++/mmc.h"

View file

@ -1,41 +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 <midi++/port.h>
#include <midi++/port_request.h>
#include <midi++/factory.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());
mode = PortFactory::string_to_mode (xmode);
type = PortFactory::string_to_type (xtype);
}

View file

@ -24,7 +24,6 @@
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/manager.h> #include <midi++/manager.h>
#include <midi++/port_request.h>
#include <ardour/route.h> #include <ardour/route.h>
#include <ardour/session.h> #include <ardour/session.h>

View file

@ -9,7 +9,6 @@
#include <midi++/types.h> #include <midi++/types.h>
#include <midi++/port.h> #include <midi++/port.h>
#include <midi++/manager.h> #include <midi++/manager.h>
#include <midi++/port_request.h>
#include "i18n.h" #include "i18n.h"
#include <unistd.h> #include <unistd.h>