aboutsummaryrefslogtreecommitdiff
path: root/backends/midi/alsa.cpp
diff options
context:
space:
mode:
authorMatthew Hoops2011-05-03 17:17:27 -0400
committerMatthew Hoops2011-05-03 17:25:41 -0400
commit9cb600099f4c29298707787cafad2741a1cd6686 (patch)
treefb1930fa56b611317831d66442cba19b18d2e57a /backends/midi/alsa.cpp
parent3b2283daf850605ca897002afbafe44489c35473 (diff)
parent95a6098f672191dc0792bd4f9bfa18706bbe8e3a (diff)
downloadscummvm-rg350-9cb600099f4c29298707787cafad2741a1cd6686.tar.gz
scummvm-rg350-9cb600099f4c29298707787cafad2741a1cd6686.tar.bz2
scummvm-rg350-9cb600099f4c29298707787cafad2741a1cd6686.zip
Merge remote branch 'upstream/master' into pegasus
Diffstat (limited to 'backends/midi/alsa.cpp')
-rw-r--r--backends/midi/alsa.cpp55
1 files changed, 39 insertions, 16 deletions
diff --git a/backends/midi/alsa.cpp b/backends/midi/alsa.cpp
index 953b088958..5110734a18 100644
--- a/backends/midi/alsa.cpp
+++ b/backends/midi/alsa.cpp
@@ -30,6 +30,8 @@
#if defined(USE_ALSA)
#include "common/config-manager.h"
+#include "common/error.h"
+#include "common/textconsole.h"
#include "common/util.h"
#include "audio/musicplugin.h"
#include "audio/mpu401.h"
@@ -44,7 +46,7 @@
#if SND_LIB_MAJOR >= 1 || SND_LIB_MINOR >= 6
#define snd_seq_flush_output(x) snd_seq_drain_output(x)
-#define snd_seq_set_client_group(x,name) /*nop */
+#define snd_seq_set_client_group(x,name) /*nop */
#define my_snd_seq_open(seqp) snd_seq_open(seqp, "hw", SND_SEQ_OPEN_DUPLEX, 0)
#else
/* SND_SEQ_OPEN_OUT causes oops on early version of ALSA */
@@ -53,9 +55,8 @@
#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)) {
+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;
}
@@ -68,10 +69,11 @@ static int check_permission(snd_seq_port_info_t *pinfo)
#define ADDR_DELIM ".:"
-class MidiDriver_ALSA:public MidiDriver_MPU401 {
+class MidiDriver_ALSA : public MidiDriver_MPU401 {
public:
MidiDriver_ALSA(int client, int port);
int open();
+ bool isOpen() const { return _isOpen; }
void close();
void send(uint32 b);
void sysEx(const byte *msg, uint16 length);
@@ -83,11 +85,12 @@ private:
snd_seq_t *seq_handle;
int seq_client, seq_port;
int my_client, my_port;
+ // The volume controller value of the first MIDI channel
+ int8 _channel0Volume;
};
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)
-{
+ : _isOpen(false), seq_handle(0), seq_client(client), seq_port(port), my_client(0), my_port(0), _channel0Volume(127) {
memset(&ev, 0, sizeof(ev));
}
@@ -114,7 +117,7 @@ int MidiDriver_ALSA::open() {
// with those capabilities.
my_port = snd_seq_create_simple_port(seq_handle, "SCUMMVM port 0", 0,
- SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
+ SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
if (my_port < 0) {
snd_seq_close(seq_handle);
@@ -208,24 +211,41 @@ void MidiDriver_ALSA::send(uint32 b) {
case 0xB0:
/* is it this simple ? Wow... */
snd_seq_ev_set_controller(&ev, chanID, midiCmd[1], midiCmd[2]);
+
+ // We save the volume of the first MIDI channel here to utilize it in
+ // our workaround for broken USB-MIDI cables.
+ if (chanID == 0 && midiCmd[1] == 0x07)
+ _channel0Volume = midiCmd[2];
+
send_event(1);
break;
case 0xC0:
snd_seq_ev_set_pgmchange(&ev, chanID, midiCmd[1]);
send_event(0);
+
+ // Send a volume change command to work around a firmware bug in common
+ // USB-MIDI cables. If the first MIDI command in a USB packet is a
+ // Cx or Dx command, the second command in the packet is dropped
+ // somewhere.
+ send(0x07B0 | (_channel0Volume << 16));
break;
case 0xD0:
snd_seq_ev_set_chanpress(&ev, chanID, midiCmd[1]);
send_event(1);
+
+ // Send a volume change command to work around a firmware bug in common
+ // USB-MIDI cables. If the first MIDI command in a USB packet is a
+ // Cx or Dx command, the second command in the packet is dropped
+ // somewhere.
+ send(0x07B0 | (_channel0Volume << 16));
break;
- case 0xE0:{
- // long theBend = ((((long)midiCmd[1] + (long)(midiCmd[2] << 7))) - 0x2000) / 4;
- // snd_seq_ev_set_pitchbend(&ev, chanID, theBend);
- long theBend = ((long)midiCmd[1] + (long)(midiCmd[2] << 7)) - 0x2000;
- snd_seq_ev_set_pitchbend(&ev, chanID, theBend);
- send_event(1);
- }
- break;
+ case 0xE0: {
+ // long theBend = ((((long)midiCmd[1] + (long)(midiCmd[2] << 7))) - 0x2000) / 4;
+ // snd_seq_ev_set_pitchbend(&ev, chanID, theBend);
+ long theBend = ((long)midiCmd[1] + (long)(midiCmd[2] << 7)) - 0x2000;
+ snd_seq_ev_set_pitchbend(&ev, chanID, theBend);
+ send_event(1);
+ } break;
default:
warning("Unknown MIDI Command: %08x", (int)b);
@@ -280,6 +300,9 @@ typedef Common::List<AlsaDevice> AlsaDevices;
AlsaDevice::AlsaDevice(Common::String name, MusicType mt, int client)
: _name(name), _type(mt), _client(client) {
+ // Make sure we do not get any trailing spaces to avoid problems when
+ // storing the name in the configuration file.
+ _name.trim();
}
Common::String AlsaDevice::getName() {