aboutsummaryrefslogtreecommitdiff
path: root/backends/midi/alsa.cpp
diff options
context:
space:
mode:
authorTorbjörn Andersson2010-07-19 07:47:11 +0000
committerTorbjörn Andersson2010-07-19 07:47:11 +0000
commitabae29a2dccfc132505687e70c220beb2f56defe (patch)
treeacbca7b1b7e4d28791209ee3834c103865412d98 /backends/midi/alsa.cpp
parent9cb23c8a7bcda26196e78af3e28da67db6b987ea (diff)
downloadscummvm-rg350-abae29a2dccfc132505687e70c220beb2f56defe.tar.gz
scummvm-rg350-abae29a2dccfc132505687e70c220beb2f56defe.tar.bz2
scummvm-rg350-abae29a2dccfc132505687e70c220beb2f56defe.zip
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
Diffstat (limited to 'backends/midi/alsa.cpp')
-rw-r--r--backends/midi/alsa.cpp253
1 files changed, 182 insertions, 71 deletions
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<AlsaDevice> 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<bool> 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