aboutsummaryrefslogtreecommitdiff
path: root/sound/mididrv.cpp
diff options
context:
space:
mode:
authorNicolas Noble2002-05-16 06:46:50 +0000
committerNicolas Noble2002-05-16 06:46:50 +0000
commit5edf1e6d7f9ca5ce8fa4e6ded69adff61c60ab50 (patch)
treecb82f69a3dfa64011f81e85333b5a303261d3c00 /sound/mididrv.cpp
parent4f24f91f8c47d2f91233cc41057c808aa3f0df9f (diff)
downloadscummvm-rg350-5edf1e6d7f9ca5ce8fa4e6ded69adff61c60ab50.tar.gz
scummvm-rg350-5edf1e6d7f9ca5ce8fa4e6ded69adff61c60ab50.tar.bz2
scummvm-rg350-5edf1e6d7f9ca5ce8fa4e6ded69adff61c60ab50.zip
Added an ALSA sequencer support. Updated readme.txt to explain it, and
Makefile to allow the user to enable it. I also reorganised the Makefile a bit, since there is now one more optionnal library. BBrox, I also merged your Makefile.x11 in it, just take a look at it! svn-id: r4341
Diffstat (limited to 'sound/mididrv.cpp')
-rw-r--r--sound/mididrv.cpp200
1 files changed, 200 insertions, 0 deletions
diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp
index 0dc14f9558..4dfda237e6 100644
--- a/sound/mididrv.cpp
+++ b/sound/mididrv.cpp
@@ -1444,6 +1444,205 @@ void MidiDriver_MIDIEMU::midi_fm_endnote(int voice) {
}
+#if defined(UNIX) && defined(USE_ALSA)
+
+#include <alsa/asoundlib.h>
+
+/*
+ * ALSA sequencer driver
+ * Mostly cut'n'pasted from Virtual Tiny Keyboard (vkeybd) by Takashi Iwai
+ * (you really rox, you know?)
+ */
+
+#if 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 my_snd_seq_open(seqp) snd_seq_open(seqp, "hw", SND_SEQ_OPEN_OUTPUT, 0)
+#else
+/* SND_SEQ_OPEN_OUT causes oops on early version of ALSA */
+#define my_snd_seq_open(seqp) snd_seq_open(seqp, SND_SEQ_OPEN)
+#endif
+
+/*
+ * parse address string
+ */
+
+#define ADDR_DELIM ".:"
+
+static int parse_addr(char *arg, int *client, int *port)
+{
+ 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;
+}
+
+class MidiDriver_ALSA : public MidiDriver {
+public:
+ MidiDriver_ALSA();
+ int open(int mode);
+ void close();
+ void send(uint32 b);
+ void pause(bool pause);
+ void set_stream_callback(void *param, StreamCallback *sc);
+
+private:
+ void send_event(int do_flush);
+ snd_seq_event_t ev;
+ StreamCallback *_stream_proc;
+ void *_stream_param;
+ int _mode;
+ snd_seq_t *seq_handle;
+ int seq_client, seq_port;
+ int my_client, my_port;
+};
+
+MidiDriver_ALSA::MidiDriver_ALSA() {
+ printf("Driver: ALSA\n");
+}
+
+void MidiDriver_ALSA::send_event(int do_flush)
+{
+ snd_seq_ev_set_direct(&ev);
+ snd_seq_ev_set_source(&ev, my_port);
+ snd_seq_ev_set_dest(&ev, seq_client, seq_port);
+
+ snd_seq_event_output(seq_handle, &ev);
+ if (do_flush)
+ snd_seq_flush_output(seq_handle);
+}
+
+int MidiDriver_ALSA::open(int mode) {
+ char * var;
+ unsigned int caps;
+
+ if (_mode != 0)
+ return MERR_ALREADY_OPEN;
+ _mode=mode;
+ if (mode!=MO_SIMPLE) return MERR_STREAMING_NOT_AVAILABLE;
+
+ if (!(var = getenv("SCUMMVM_PORT"))) {
+ error("You have to define the environnement variable SCUMMVM_PORT");
+ return -1;
+ }
+
+ if (parse_addr(var, &seq_client, &seq_port) < 0) {
+ error("Invalid port %s", var);
+ return -1;
+ }
+
+ if (my_snd_seq_open(&seq_handle)) {
+ error("Can't open sequencer");
+ return -1;
+ }
+
+ my_client = snd_seq_client_id(seq_handle);
+ snd_seq_set_client_name(seq_handle, "SCUMMVM");
+ snd_seq_set_client_group(seq_handle, "input");
+
+ caps = SND_SEQ_PORT_CAP_READ;
+ if (seq_client == SND_SEQ_ADDRESS_SUBSCRIBERS)
+ caps = ~SND_SEQ_PORT_CAP_SUBS_READ;
+ my_port = snd_seq_create_simple_port(seq_handle, "SCUMMVM", caps, SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
+ if (my_port < 0) {
+ snd_seq_close(seq_handle);
+ error("Can't create port");
+ return -1;
+ }
+
+ 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) {
+ snd_seq_close(seq_handle);
+ error("Can't subscribe to MIDI port (%d:%d)", seq_client, seq_port);
+ return -1;
+ }
+ }
+
+ printf("ALSA client initialised [%d:%d]\n", my_client, my_port);
+
+ return 0;
+}
+
+void MidiDriver_ALSA::close() {
+ _mode = 0;
+ snd_seq_close(seq_handle);
+}
+
+
+void MidiDriver_ALSA::send(uint32 b)
+{
+ unsigned int midiCmd[4];
+ ev.type = SND_SEQ_EVENT_OSS;
+ ev.data.raw8.d[0] = b;
+
+ midiCmd[3] = (b & 0xFF000000) >> 24;
+ midiCmd[2] = (b & 0x00FF0000) >> 16;
+ midiCmd[1] = (b & 0x0000FF00) >> 8;
+ midiCmd[0] = (b & 0x000000FF);
+
+ unsigned char chanID = midiCmd[0] & 0x0F;
+ switch (midiCmd[0] & 0xF0) {
+ case 0x80:
+ snd_seq_ev_set_noteoff(&ev, chanID, midiCmd[1], midiCmd[2]);
+ send_event(1);
+ break;
+ case 0x90:
+ snd_seq_ev_set_noteon(&ev, chanID, midiCmd[1], midiCmd[2]);
+ send_event(1);
+ break;
+
+ case 0xB0: // Effect
+ snd_seq_ev_set_controller(&ev, chanID, midiCmd[1], midiCmd[2]);
+ send_event(1);
+ break;
+ case 0xC0:
+ snd_seq_ev_set_pgmchange(&ev, chanID, midiCmd[1]);
+ send_event(0);
+ break;
+
+ case 0xE0:{ // Pitch bend
+ long theBend =
+ ((((long)midiCmd[1] + (long)(midiCmd[2] << 8))) - 0x4000) / 4;
+ snd_seq_ev_set_pitchbend(&ev, chanID, theBend);
+ send_event(1);
+ }
+ break;
+
+ default:
+ error("Unknown Command: %08x\n", (int)b);
+ break;
+ }
+}
+
+void MidiDriver_ALSA::pause(bool pause) {
+ if (_mode == MO_STREAMING) {
+ }
+}
+
+void MidiDriver_ALSA::set_stream_callback(void *param, StreamCallback *sc) {
+ _stream_param = param;
+ _stream_proc = sc;
+}
+
+MidiDriver *MidiDriver_ALSA_create() {
+ return new MidiDriver_ALSA();
+}
+
+#endif
+
+
#if 0
/* Old code for timidity support, maybe somebody can rewrite this for the
@@ -1503,3 +1702,4 @@ void MidiDriver::midiInitTimidity()
#endif /* 0 */
+