aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Noble2002-05-16 06:46:50 +0000
committerNicolas Noble2002-05-16 06:46:50 +0000
commit5edf1e6d7f9ca5ce8fa4e6ded69adff61c60ab50 (patch)
treecb82f69a3dfa64011f81e85333b5a303261d3c00
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
-rw-r--r--Makefile36
-rw-r--r--gameDetector.cpp4
-rw-r--r--readme.txt48
-rw-r--r--sound/mididrv.cpp200
-rw-r--r--sound/mididrv.h4
5 files changed, 283 insertions, 9 deletions
diff --git a/Makefile b/Makefile
index de431fe47d..bb75ac6a2f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,38 @@
# $Header$
-CC = g++
-CFLAGS = -g -O -Wall -Wstrict-prototypes -Wuninitialized -Wno-long-long -Wno-multichar
-DEFINES = -DUNIX
+CC = g++
+CFLAGS = -g -O -Wall -Wstrict-prototypes -Wuninitialized -Wno-long-long -Wno-multichar
+DEFINES = -DUNIX
LDFLAGS :=
INCLUDES:= `sdl-config --cflags` -I./ -I./sound
-CPPFLAGS= $(DEFINES) $(INCLUDES)
+LIBS = -lncurses
+
+# Uncomment this to activate the MAD lib for compressed sound files
+# DEFINES += -DCOMPRESSED_SOUND_FILE
+# LIBS += -lmad
+
+# Uncomment this to activate the ALSA lib for midi
+# DEFINES += -DUSE_ALSA
+# LIBS += -lasound
+
-# Add -lmad for -DCOMPRESSED_SOUND_FILE
-LIBS = `sdl-config --libs` -lncurses
+# Now, please choose a graphical output system between SDL and X11.
+# Beware, only define one of them, otherwise the compilation will blow up.
-OBJS = sdl.o
+# Comment this if you want to disable SDL output
+OBJS = sdl.o
+INCLUDE += `sdl-config --cflags`
+LIBS += `sdl-config --libs`
+
+# Uncomment this if you rather want X11 output
+# OBJS = x11.o
+# DEFINES += -DUNIX_X11
+# LDFLAGS := -L/usr/X11R6/lib -L/usr/local/lib
+# INCLUDES+= -I/usr/X11R6/include
+# LIBS += -lpthread
+
+
+CPPFLAGS= $(DEFINES) $(INCLUDES)
include Makefile.common
diff --git a/gameDetector.cpp b/gameDetector.cpp
index 06ed0757f8..f378b511be 100644
--- a/gameDetector.cpp
+++ b/gameDetector.cpp
@@ -320,6 +320,7 @@ bool GameDetector::parseMusicDriver(const char *s) {
{"core",MD_COREAUDIO},
{"amidi",MD_AMIDI},
{"midiemu",MD_MIDIEMU},
+ {"alsa", MD_ALSA},
{"adlib",-1},
};
@@ -608,6 +609,9 @@ MidiDriver *GameDetector::createMidi() {
#if defined(__APPLE__)
case MD_COREAUDIO: return MidiDriver_CORE_create();
#endif
+#if defined(UNIX) && defined(USE_ALSA)
+ case MD_ALSA: return MidiDriver_ALSA_create();
+#endif
}
error("Invalid midi driver selected");
diff --git a/readme.txt b/readme.txt
index 3ce3d0685c..514febd4ad 100644
--- a/readme.txt
+++ b/readme.txt
@@ -320,6 +320,7 @@ depending on your operating system and configuration.
-eqt - Quicktime sound, for Macintosh users.
-ecore - CoreAudio sound, for MacOS X users.
-eamidi - Uses the MorphOS MIDI system, for MorphOS users
+ -ealsa - Output using ALSA sequencer device. See below.
-enull - Null output. Don't play any music.
@@ -330,6 +331,7 @@ as sampled waves. This is the default mode for most games, and offers the
best compatability between machines and games. However, Sam and Max does not
include Adlib emulation.
+
Playing sound with MIDI emulation:
----------------------------------
Until recently, some games (particually Sam and Max) were only able to run
@@ -341,12 +343,14 @@ and is the default for Sam and Max on UNIX platforms. -HOWEVER-, it is still
very buggy and the emulation is not perfect. If you are capable of using
native midi, we recommend using one of the MIDI modes below.
+
Playing sound with Native MIDI:
-------------------------------
Use the appropriate -e<mode> command line option from the list above to
select your preferred MIDI device. For example, if you wish to use the
Windows MIDI driver, use the -ewindows option.
+
Playing sound with Sequencer MIDI: [UNIX ONLY]
----------------------------------
If your soundcard driver supports a sequencer, you may set the environment
@@ -360,6 +364,48 @@ performance and quality than Adlib or MIDI emulation. However, for those
systems where sequencer support does not work, you can always fall back on
either of those methods.
+
+Playing sound with ALSA sequencer: [UNIX ONLY]
+----------------------------------
+If you have installed the ALSA driver with the sequencer support, then
+set the environment variable "SCUMMVM_PORT" to your sequencer port - eg 65:0
+
+Here is a little howto on how to use the ALSA sequencer with your soundcard.
+In all cases, to have a list of all the sequencer ports you have, try the
+command "aconnect -o -l". On my system it gives me the output:
+client 64: 'External MIDI 0' [type=kernel]
+ 0 'MIDI 0-0 '
+client 65: 'Emu10k1 WaveTable' [type=kernel]
+ 0 'Emu10k1 Port 0 '
+ 1 'Emu10k1 Port 1 '
+ 2 'Emu10k1 Port 2 '
+ 3 'Emu10k1 Port 3 '
+client 128: 'Client-128' [type=user]
+ 0 'TiMidity port 0 '
+ 1 'TiMidity port 1 '
+
+It means the external MIDI output of my sound card is located on the
+port 64:0, that I've got four WaveTable MIDI outputs in 65:0, 65:1, 65:2
+and 65:3, and that I've got two TiMidity ports, located at 128:0 and 128:1.
+
+If you have a FM-chip on your card, like the SB16, then you have to load
+the soundfonts using the sbiload software. Example:
+ sbiload -p 65:0 /etc/std.o3 /etc/drums.o3
+
+If you have a WaveTable capable sound card, you have to load a sbk or sf2
+soundfont using the sfxload software. If you manage to do so, please mail
+me since I managed to get it working only once, and never again.
+
+If you don't have a MIDI capable soundcard, or if you want to take
+advantage of your TiMidity samples, then you can ask TiMidity to become an
+alsa sequencer output. Here is a quick way to do so:
+ timidity -iAqqq -B2,8 -Os1S -s 44100 &
+
+Then the TiMidity port will be visible from the 'aconnect -o -l' list. You
+should launch it beeing as root, since it will try to set up some real time
+priority.
+
+
Using MP3 files for CD audio:
-----------------------------
Use LAME or some other mp3 encoder to rip the cd audio tracks to files. Name
@@ -456,7 +502,7 @@ Credits:
Daniel Schepler - Final MI1 CD music support
Tim 'realmz' - Initial MI1 CD music support
Jonathan 'khalek' - Expert weaver in the Loom
- Nicolas Noble - Config file support
+ Nicolas Noble - Config file and ALSA support
Pawel Kolodziejski - Added missing Dig SMUSH codecs
Felix Jakschitsc - His hard work on Zak256
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 */
+
diff --git a/sound/mididrv.h b/sound/mididrv.h
index a24ee458ce..977308afe8 100644
--- a/sound/mididrv.h
+++ b/sound/mididrv.h
@@ -106,7 +106,8 @@ enum {
MD_QTMUSIC = 5,
MD_AMIDI = 6,
MD_COREAUDIO = 7,
- MD_MIDIEMU = 8
+ MD_MIDIEMU = 8,
+ MD_ALSA = 9,
};
@@ -120,3 +121,4 @@ extern MidiDriver *MidiDriver_QT_create();
extern MidiDriver *MidiDriver_CORE_create();
extern MidiDriver *MidiDriver_AMIDI_create();
extern MidiDriver *MidiDriver_MIDIEMU_create();
+extern MidiDriver *MidiDriver_ALSA_create();