From bbd3f0dbb3f76417237882ae8dfe5acfab73b50b Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Tue, 27 Jul 2010 17:18:02 +0000 Subject: ALSA: Be more intelligent when picking MIDI port Often, a client has more than one available port. Pick the first one that isn't already in use. For instance, on my computer client 17 is the "Emu10k1 WaveTable", and it has four available ports. If, say, aplaymidi is already playing on port 17:0, ScummVM will use port 17:1 instead. Otherwise the two programs will mess up each others instruments and controller settings. Of course, in reality I doubt that anyone will run two different MIDI playing applications at once. svn-id: r51380 --- backends/midi/alsa.cpp | 76 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 25 deletions(-) (limited to 'backends') diff --git a/backends/midi/alsa.cpp b/backends/midi/alsa.cpp index 2b36cdc3cf..4f73d7384b 100644 --- a/backends/midi/alsa.cpp +++ b/backends/midi/alsa.cpp @@ -48,6 +48,17 @@ #define my_snd_seq_open(seqp) snd_seq_open(seqp, SND_SEQ_OPEN) #endif +#define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits)) + +static int check_permission(snd_seq_port_info_t *pinfo) +{ + if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE)) { + if (!(snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT)) + return 1; + } + return 0; +} + /* * parse address string */ @@ -109,7 +120,41 @@ int MidiDriver_ALSA::open() { } if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) { - // subscribe to MIDI port + // Subscribe to MIDI port. Prefer one that doesn't already have + // any connections, unless we've forced a port number already. + if (seq_port == -1) { + snd_seq_client_info_t *cinfo; + snd_seq_port_info_t *pinfo; + + snd_seq_client_info_alloca(&cinfo); + snd_seq_port_info_alloca(&pinfo); + + snd_seq_get_any_client_info(seq_handle, seq_client, cinfo); + + int first_port = -1; + int found_port = -1; + + snd_seq_port_info_set_client(pinfo, seq_client); + snd_seq_port_info_set_port(pinfo, -1); + while (found_port == -1 && snd_seq_query_next_port(seq_handle, pinfo) >= 0) { + if (check_permission(pinfo)) { + if (first_port == -1) + first_port = snd_seq_port_info_get_port(pinfo); + if (found_port == -1 && snd_seq_port_info_get_write_use(pinfo) == 0) + found_port = snd_seq_port_info_get_port(pinfo); + } + } + + if (found_port == -1) { + // Should we abort here? For now, use the first + // available port. + seq_port = first_port; + warning("MidiDriver_ALSA: All ports on client %d (%s) are already in use", seq_client, snd_seq_client_info_get_name(cinfo)); + } else { + seq_port = found_port; + } + } + if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) < 0) { error("Can't subscribe to MIDI port (%d:%d) see README for help", seq_client, seq_port); } @@ -217,23 +262,21 @@ void MidiDriver_ALSA::send_event(int do_flush) { class AlsaDevice { public: - AlsaDevice(Common::String name, MusicType mt, int client, int port); + AlsaDevice(Common::String name, MusicType mt, int client); Common::String getName(); MusicType getType(); int getClient(); - int getPort(); private: Common::String _name; MusicType _type; int _client; - int _port; }; typedef Common::List AlsaDevices; -AlsaDevice::AlsaDevice(Common::String name, MusicType mt, int client, int port) - : _name(name), _type(mt), _client(client), _port(port) { +AlsaDevice::AlsaDevice(Common::String name, MusicType mt, int client) + : _name(name), _type(mt), _client(client) { } Common::String AlsaDevice::getName() { @@ -248,10 +291,6 @@ int AlsaDevice::getClient() { return _client; } -int AlsaDevice::getPort() { - return _port; -} - class AlsaMusicPlugin : public MusicPluginObject { public: const char *getName() const { @@ -270,17 +309,6 @@ private: static int parse_addr(const char *arg, int *client, int *port); }; -#define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits)) - -static int check_permission(snd_seq_port_info_t *pinfo) -{ - if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE)) { - if (!(snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT)) - return 1; - } - return 0; -} - AlsaDevices AlsaMusicPlugin::getAlsaDevices() const { AlsaDevices devices; snd_seq_t *seq_handle; @@ -306,9 +334,7 @@ AlsaDevices AlsaMusicPlugin::getAlsaDevices() const { // TODO: Can we figure out the appropriate music type? MusicType type = MT_GM; int client = snd_seq_client_info_get_client(cinfo); - int port = snd_seq_port_info_get_port(pinfo); - - devices.push_back(AlsaDevice(name, type, client, port)); + devices.push_back(AlsaDevice(name, type, client)); } } } @@ -395,7 +421,7 @@ Common::Error AlsaMusicPlugin::createInstance(MidiDriver **mididriver, MidiDrive if (device.getCompleteId().equals(MidiDriver::getDeviceString(dev, MidiDriver::kDeviceId))) { found = true; seq_client = d->getClient(); - seq_port = d->getPort(); + seq_port = -1; break; } } -- cgit v1.2.3