diff options
-rw-r--r-- | Makefile | 36 | ||||
-rw-r--r-- | gameDetector.cpp | 4 | ||||
-rw-r--r-- | readme.txt | 48 | ||||
-rw-r--r-- | sound/mididrv.cpp | 200 | ||||
-rw-r--r-- | sound/mididrv.h | 4 |
5 files changed, 283 insertions, 9 deletions
@@ -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(); |