From abae29a2dccfc132505687e70c220beb2f56defe Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Mon, 19 Jul 2010 07:47:11 +0000 Subject: ALSA: Get ALSA port settings from the new device config settings. This is also an attempt to make the transition from the old settings to the new ones a little less rough, by trying to put something sensible into the first device, which is what's used by default. Currently it prefers 17:x and 65:x since they're the old defaults, followed by 128:x since that's probably TiMidity. The old SCUMMVM_PORT environment variable still overrides any config settings. I haven't made up my mind whether or not that's a good idea, but at least it prints a warning message. TODO: The old 'alsa_port' setting is not handled. It should probably be used to set sensible defaults for the new settings, but I'm not sure where this should be done. TODO: The documentation will need to be updated, once everything is working the way it should. svn-id: r51019 --- backends/midi/alsa.cpp | 253 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 182 insertions(+), 71 deletions(-) (limited to 'backends/midi/alsa.cpp') diff --git a/backends/midi/alsa.cpp b/backends/midi/alsa.cpp index a3f4b149d1..076655bfed 100644 --- a/backends/midi/alsa.cpp +++ b/backends/midi/alsa.cpp @@ -56,7 +56,7 @@ class MidiDriver_ALSA:public MidiDriver_MPU401 { public: - MidiDriver_ALSA(); + MidiDriver_ALSA(int client, int port); int open(); void close(); void send(uint32 b); @@ -69,34 +69,19 @@ private: snd_seq_t *seq_handle; int seq_client, seq_port; int my_client, my_port; - static int parse_addr(const char *arg, int *client, int *port); }; -MidiDriver_ALSA::MidiDriver_ALSA() - : _isOpen(false), seq_handle(0), seq_client(0), seq_port(0), my_client(0), my_port(0) +MidiDriver_ALSA::MidiDriver_ALSA(int client, int port) + : _isOpen(false), seq_handle(0), seq_client(client), seq_port(port), my_client(0), my_port(0) { memset(&ev, 0, sizeof(ev)); } int MidiDriver_ALSA::open() { - const char *var = NULL; - if (_isOpen) return MERR_ALREADY_OPEN; _isOpen = true; - var = getenv("SCUMMVM_PORT"); - if (!var && ConfMan.hasKey("alsa_port")) { - var = ConfMan.get("alsa_port").c_str(); - } - - if (var) { - if (parse_addr(var, &seq_client, &seq_port) < 0) { - error("Invalid port %s", var); - return -1; - } - } - if (my_snd_seq_open(&seq_handle) < 0) { error("Can't open sequencer"); return -1; @@ -118,29 +103,11 @@ int MidiDriver_ALSA::open() { return -1; } - if (var) { - if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) { - // subscribe to MIDI 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); - } - } - } else { - int defaultPorts[] = { - 65, 0, - 17, 0 - }; - int i; - - for (i = 0; i < ARRAYSIZE(defaultPorts); i += 2) { - seq_client = defaultPorts[i]; - seq_port = defaultPorts[i + 1]; - if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) >= 0) - break; + if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) { + // subscribe to MIDI 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); } - - if (i >= ARRAYSIZE(defaultPorts)) - error("Can't subscribe to MIDI port (65:0) or (17:0)"); } printf("Connected to Alsa sequencer client [%d:%d]\n", seq_client, seq_port); @@ -230,24 +197,6 @@ void MidiDriver_ALSA::sysEx(const byte *msg, uint16 length) { send_event(1); } -int MidiDriver_ALSA::parse_addr(const char *arg, int *client, int *port) { - const char *p; - - if (isdigit(*arg)) { - if ((p = strpbrk(arg, ADDR_DELIM)) == NULL) - return -1; - *client = atoi(arg); - *port = atoi(p + 1); - } else { - if (*arg == 's' || *arg == 'S') { - *client = SND_SEQ_ADDRESS_SUBSCRIBERS; - *port = 0; - } else - return -1; - } - return 0; -} - void MidiDriver_ALSA::send_event(int do_flush) { snd_seq_ev_set_direct(&ev); snd_seq_ev_set_source(&ev, my_port); @@ -261,6 +210,43 @@ void MidiDriver_ALSA::send_event(int do_flush) { // Plugin interface +class AlsaDevice { +public: + AlsaDevice(Common::String name, MusicType mt, int client, int port); + 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) { +} + +Common::String AlsaDevice::getName() { + return _name; +} + +MusicType AlsaDevice::getType() { + return _type; +} + +int AlsaDevice::getClient() { + return _client; +} + +int AlsaDevice::getPort() { + return _port; +} + class AlsaMusicPlugin : public MusicPluginObject { public: const char *getName() const { @@ -271,8 +257,12 @@ public: return "alsa"; } + AlsaDevices getAlsaDevices() const; MusicDevices getDevices() const; Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const; + +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)) @@ -286,11 +276,10 @@ static int check_permission(snd_seq_port_info_t *pinfo) return 0; } -MusicDevices AlsaMusicPlugin::getDevices() const { - MusicDevices devices; - - snd_seq_t *seq; - if (my_snd_seq_open(&seq) < 0) +AlsaDevices AlsaMusicPlugin::getAlsaDevices() const { + AlsaDevices devices; + snd_seq_t *seq_handle; + if (my_snd_seq_open(&seq_handle) < 0) return devices; // can't open sequencer snd_seq_client_info_t *cinfo; @@ -298,32 +287,154 @@ MusicDevices AlsaMusicPlugin::getDevices() const { snd_seq_port_info_t *pinfo; snd_seq_port_info_alloca(&pinfo); snd_seq_client_info_set_client(cinfo, -1); - while (snd_seq_query_next_client(seq, cinfo) >= 0) { + while (snd_seq_query_next_client(seq_handle, cinfo) >= 0) { bool found_valid_port = false; /* reset query info */ snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); snd_seq_port_info_set_port(pinfo, -1); - while (!found_valid_port && snd_seq_query_next_port(seq, pinfo) >= 0) { + while (!found_valid_port && snd_seq_query_next_port(seq_handle, pinfo) >= 0) { if (check_permission(pinfo)) { found_valid_port = true; - // TODO: Return a different music type depending on the configuration - devices.push_back(MusicDevice(this, snd_seq_client_info_get_name(cinfo), MT_GM)); - //snd_seq_client_info_get_client(cinfo) : snd_seq_port_info_get_port(pinfo) + + const char *name = snd_seq_client_info_get_name(cinfo); + // 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)); } } } - snd_seq_close(seq); + snd_seq_close(seq_handle); return devices; } -Common::Error AlsaMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { - *mididriver = new MidiDriver_ALSA(); +MusicDevices AlsaMusicPlugin::getDevices() const { + MusicDevices devices; + Common::Array used; + AlsaDevices::iterator d; + int i; + + AlsaDevices alsaDevices = getAlsaDevices(); + + for (i = 0, d = alsaDevices.begin(); d != alsaDevices.end(); ++i, ++d) { + used.push_back(false); + } + + // Since the default behaviour is to use the first device in the list, + // try to put something sensible there. We used to have 17:0 and 65:0 + // as defaults. + + for (i = 0, d = alsaDevices.begin(); d != alsaDevices.end(); ++i, ++d) { + int client = d->getClient(); + if (client == 17 || client == 65) { + devices.push_back(MusicDevice(this, d->getName(), d->getType())); + used[i] = true; + } + } + + // 128:0 is probably TiMidity, or something like that, so that's + // probably a good second choice. + + for (i = 0, d = alsaDevices.begin(); d != alsaDevices.end(); ++i, ++d) { + if (d->getClient() == 128) { + devices.push_back(MusicDevice(this, d->getName(), d->getType())); + used[i] = true; + } + } + + // Add the remaining devices in the order they were found. + + for (i = 0, d = alsaDevices.begin(); d != alsaDevices.end(); ++i, ++d) { + + if (!used[i]) { + devices.push_back(MusicDevice(this, d->getName(), d->getType())); + } + } + + return devices; +} + +Common::Error AlsaMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle dev) const { + bool found = false; + int seq_client, seq_port; + + const char *var = NULL; + + // TODO: Upgrade from old alsa_port setting. This probably isn't the + // right place to do that, though. + + if (ConfMan.hasKey("alsa_port")) { + warning("AlsaMusicPlugin: Found old 'alsa_port' setting, which will be ignored"); + } + + // The SCUMMVM_PORT environment variable can still be used to override + // any config setting. + + var = getenv("SCUMMVM_PORT"); + if (var) { + warning("AlsaMusicPlugin: SCUMMVM_PORT environment variable overrides config settings"); + if (parse_addr(var, &seq_client, &seq_port) >= 0) { + found = true; + } else { + warning("AlsaMusicPlugin: Invalid port %s, using config settings instead", var); + } + } + + // Try to match the setting to an available ALSA device. + + if (!found && dev) { + AlsaDevices alsaDevices = getAlsaDevices(); + + for (AlsaDevices::iterator d = alsaDevices.begin(); d != alsaDevices.end(); ++d) { + MusicDevice device(this, d->getName(), d->getType()); + + if (device.getCompleteId().equals(MidiDriver::getDeviceString(dev, MidiDriver::kDeviceId))) { + found = true; + seq_client = d->getClient(); + seq_port = d->getPort(); + break; + } + } + } + + // Still nothing? Try a sensible default. + + if (!found) { + // TODO: What's a sensible default anyway? And exactly when do + // we get to this case? + + warning("AlsaMusicPlugin: Using 17:0 as default ALSA port"); + seq_client = 17; + seq_port = 0; + } + + *mididriver = new MidiDriver_ALSA(seq_client, seq_port); return Common::kNoError; } +int AlsaMusicPlugin::parse_addr(const char *arg, int *client, int *port) { + const char *p; + + if (isdigit(*arg)) { + if ((p = strpbrk(arg, ADDR_DELIM)) == NULL) + return -1; + *client = atoi(arg); + *port = atoi(p + 1); + } else { + if (*arg == 's' || *arg == 'S') { + *client = SND_SEQ_ADDRESS_SUBSCRIBERS; + *port = 0; + } else + return -1; + } + return 0; +} + //#if PLUGIN_ENABLED_DYNAMIC(ALSA) //REGISTER_PLUGIN_DYNAMIC(ALSA, PLUGIN_TYPE_MUSIC, AlsaMusicPlugin); //#else -- cgit v1.2.3