aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scummvm.cpp14
-rw-r--r--sound.h14
-rw-r--r--sound/gmidi.cpp384
3 files changed, 285 insertions, 127 deletions
diff --git a/scummvm.cpp b/scummvm.cpp
index 56eada213a..3bf16c96ee 100644
--- a/scummvm.cpp
+++ b/scummvm.cpp
@@ -415,10 +415,11 @@ int Scumm::scummLoop(int delta) {
"\td - enable debug output\n" \
"\tn - no subtitles for speech\n" \
"\tb<num> - start in room <num>\n" \
- "\tt<num> - Set music tempo. Suggested: 1F0000\n" \
- "\ts<num> - Set scale factor to <num> (1, 2, or 3 - 2 by default)\n" \
+ "\tt<num> - set music tempo. Suggested: 1F0000\n" \
+ "\ts<num> - set scale factor to <num> (1, 2, or 3 - 2 by default)\n" \
"\tp<path> - look for game in <path>\n" \
- "\tm<num> - Set music volume to <num> (0-100)\n" \
+ "\tm<num> - set music volume to <num> (0-100)\n" \
+ "\tr - emulate roland mt32 instruments\n" \
"\tf - fullscreen mode\n" \
"\tg - graphics mode. 1 for 2xSai anti-aliasing\n"
@@ -492,6 +493,13 @@ void Scumm::parseCommandLine(int argc, char **argv) {
se->set_music_volume(atoi(s+1));
goto NextArg;
}
+ case 'r': {
+ SoundEngine *se = (SoundEngine*)_soundEngine;
+
+ if (se)
+ se->_mt32emulate = true;
+ break;
+ }
case 'g':
if (*(s+1) == '\0')
goto ShowHelpAndExit;
diff --git a/sound.h b/sound.h
index 6b8a278828..fc8de23820 100644
--- a/sound.h
+++ b/sound.h
@@ -17,6 +17,12 @@
*
* Change Log:
* $Log$
+ * Revision 1.5 2002/03/14 06:06:49 ender
+ * Added some new midi drivers - QuickTime Music and RawMidi.
+ * -DUSE_RAWMIDI and -DUSE_QTMUSIC respectivly.
+ *
+ * I assume these will compile - if not file a bug/patch. Also added a "-r" commandline parameter to turn on MT32 emulation... the patch conversion set isn't quite right, still..
+ *
* Revision 1.4 2002/03/05 23:37:31 ender
* Adding music volume control.
*
@@ -395,12 +401,11 @@ public:
int part_update_active(Part *part,uint16 *active);
void adjust_priorities() {}
- bool wave_based() { return true; }
+ bool wave_based() { return true; }
};
struct MidiSoundDriver : SoundDriver {
- void *_mo;
- bool _mt32emulate;
+ void *_mo;
SoundEngine *_se;
MidiChannelGM _midi_channels[9];
@@ -459,7 +464,7 @@ private:
bool _paused;
bool _active_volume_faders;
- bool _initialized;
+ bool _initialized;
byte _volume_fader_counter;
uint _queue_end, _queue_pos, _queue_sound;
@@ -548,6 +553,7 @@ public:
void setBase(byte **base) { _base_sounds = base; }
SOUND_DRIVER_TYPE *driver() { return _driver; }
+ bool _mt32emulate;
};
diff --git a/sound/gmidi.cpp b/sound/gmidi.cpp
index ea56ee615e..d66ee465a4 100644
--- a/sound/gmidi.cpp
+++ b/sound/gmidi.cpp
@@ -20,147 +20,292 @@
/*
* Timidity support by Lionel Ulmer <lionel.ulmer@free.fr>
+ * QuickTime support by Florent Boudet <flobo@ifrance.com>
+ * Raw output support by Michael Pearce
*/
#include "stdafx.h"
-
-#if !defined USE_ADLIB
-
#include "scumm.h"
#include "sound.h"
-
-#ifdef USE_TIMIDITY
-#include <sys/time.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Copy-pasted from Timidity */
-#define SEQ_MIDIPUTC 5
-
-#endif /* USE_TIMIDITY */
-
-
-#define SPECIAL_CHANNEL 9
+#include "gmidi.h"
#if defined(WIN32)
+ /* Windows sequencer support */
+ void MidiSoundDriver::midiInit() {
+ if (midiOutOpen((HMIDIOUT*)&_mo, MIDI_MAPPER, NULL, NULL, 0) != MMSYSERR_NOERROR)
+ error("midiOutOpen failed");
+ }
+ #define MIDI_OUT(a,b) midiOutShortMsg((HMIDIOUT)(a), (b))
+
+#elif defined(USE_RAWMIDI)
+ /* Raw midi support - dump to /dev/midi0 or something */
+ static int open_rawmidi_device() {
+ int device;
+ char *device_name = getenv("SCUMMVM_MIDI");
+ if (device_name != NULL) {
+ device = (open((device_name), O_RDWR, 0));
+ } else {
+ warning("You need to set-up the SCUMMVM_MIDI environment variable properly (see readme.txt) ");
+ }
+ if ((device_name == NULL) || (device < 0)) {
+ if (device_name == NULL)
+ warning("Opening /dev/null (no music will be heard) ");
+ else
+ warning("Cannot open rawmidi device %s - using /dev/null (no music will be heard) ", device_name);
+ device = (open(("/dev/null"), O_RDWR, 0));
+ if (device < 0)
+ error("Cannot open /dev/null to dump midi output");
+ }
+ return device;
+ }
-void MidiSoundDriver::midiInit() {
- if (midiOutOpen((HMIDIOUT*)&_mo, MIDI_MAPPER, NULL, NULL, 0) != MMSYSERR_NOERROR)
- error("midiOutOpen failed");
-}
+void SoundEngine::midiInit() {
+ int device;
+ device = open_rawmidi_device();
+ _mo = (void *) device;
+ }
-#define MIDI_OUT(a,b) midiOutShortMsg((HMIDIOUT)(a), (b))
+ static inline void MIDI_OUT(void *a, int b) {
+ int device = (int) a;
+ unsigned char buf[256];
+ int position = 0;
+
+ switch (b & 0xF0) {
+ case 0x80:
+ case 0x90:
+ case 0xA0:
+ case 0xB0:
+ case 0xE0:
+ buf[position++] = b;
+ buf[position++] = (b >> 8) & 0x7F;
+ buf[position++] = (b >> 16) & 0x7F;
+ break;
+ case 0xC0:
+ case 0xD0:
+ buf[position++] = b;
+ buf[position++] = (b >> 8) & 0x7F;
+ break;
+ default:
+ fprintf(stderr, "Unknown : %08x\n", b);
+ break;
+ }
+ write(device, buf, position);
+ }
#elif defined(USE_TIMIDITY)
-
-static int connect_to_timidity(int port)
-{
- struct hostent *serverhost;
- struct sockaddr_in sadd;
- int s;
+ /* Timidity server support */
+ static int connect_to_timidity(int port) {
+ struct hostent *serverhost;
+ struct sockaddr_in sadd;
+ int s;
- serverhost = gethostbyname("localhost");
- if (serverhost == NULL)
- error("Could not resolve host");
- sadd.sin_family = serverhost->h_addrtype;
- sadd.sin_port = htons(port);
- memcpy(&(sadd.sin_addr), serverhost->h_addr_list[0], serverhost->h_length);
+ serverhost = gethostbyname("localhost");
+ if (serverhost == NULL)
+ error("Could not resolve Timidity host ('localhost')");
+
+ sadd.sin_family = serverhost->h_addrtype;
+ sadd.sin_port = htons(port);
+ memcpy(&(sadd.sin_addr), serverhost->h_addr_list[0], serverhost->h_length);
- s = socket(AF_INET,SOCK_STREAM,0);
- if (s < 0)
- error("Could not open socket");
- if (connect(s, (struct sockaddr *) &sadd, sizeof(struct sockaddr_in)) < 0)
- error("Could not connect to server");
+ s = socket(AF_INET,SOCK_STREAM,0);
+ if (s < 0)
+ error("Could not open Timidity socket");
- return s;
-}
-
-void MidiSoundDriver::midiInit() {
- int s, s2;
- int len;
- int dummy, newport;
- char buf[256];
-
- s = connect_to_timidity(7777);
- len = read(s, buf, 256);
- buf[len] = '\0';
- printf("%s", buf);
-
- sprintf(buf, "SETBUF %f %f\n", 0.1, 0.15);
- write(s, buf, strlen(buf));
- len = read(s, buf, 256);
- buf[len] = '\0';
- printf("%s", buf);
+ if (connect(s, (struct sockaddr *) &sadd, sizeof(struct sockaddr_in)) < 0)
+ error("Could not connect to Timidity server");
- sprintf(buf, "OPEN lsb\n");
- write(s, buf, strlen(buf));
- len = read(s, buf, 256);
- buf[len] = '\0';
- printf("%s", buf);
-
- sscanf(buf, "%d %d", &dummy, &newport);
- printf(" => port = %d\n", newport);
+ return s;
+ }
+
+ void MidiSoundDriver::midiInit() {
+ int s, s2;
+ int len;
+ int dummy, newport;
+ char buf[256];
+
+ s = connect_to_timidity(7777);
+ len = read(s, buf, 256);
+ buf[len] = '\0';
+ printf("%s", buf);
+
+ sprintf(buf, "SETBUF %f %f\n", 0.1, 0.15);
+ write(s, buf, strlen(buf));
+ len = read(s, buf, 256); // buf[len] = '\0'; printf("%s", buf);
- s2 = connect_to_timidity(newport);
- _mo = (void *) s2;
-}
+ sprintf(buf, "OPEN lsb\n");
+ write(s, buf, strlen(buf));
+ len = read(s, buf, 256); // buf[len] = '\0'; printf("%s", buf);
-#define DEVICE_NUM 0
+ sscanf(buf, "%d %d", &dummy, &newport);
+ printf(" => port = %d\n", newport);
+
+ s2 = connect_to_timidity(newport);
+ _mo = (void *) s2;
+ }
-static inline void MIDI_OUT(void *a, int b) {
- int s = (int) a;
- unsigned char buf[256];
- int position = 0;
+ static inline void MIDI_OUT(void *a, int b) {
+ int s = (int) a;
+ unsigned char buf[256];
+ int position = 0;
- switch (b & 0xF0) {
- case 0x80:
- case 0x90:
- case 0xA0:
- case 0xB0:
- case 0xE0:
- buf[position++] = SEQ_MIDIPUTC;
- buf[position++] = b;
- buf[position++] = DEVICE_NUM;
- buf[position++] = 0;
- buf[position++] = SEQ_MIDIPUTC;
- buf[position++] = (b >> 8) & 0x7F;
- buf[position++] = DEVICE_NUM;
- buf[position++] = 0;
- buf[position++] = SEQ_MIDIPUTC;
- buf[position++] = (b >> 16) & 0x7F;
- buf[position++] = DEVICE_NUM;
- buf[position++] = 0;
- break;
- case 0xC0:
- case 0xD0:
- buf[position++] = SEQ_MIDIPUTC;
- buf[position++] = b;
- buf[position++] = DEVICE_NUM;
- buf[position++] = 0;
- buf[position++] = SEQ_MIDIPUTC;
- buf[position++] = (b >> 8) & 0x7F;
- buf[position++] = DEVICE_NUM;
- buf[position++] = 0;
- break;
- default:
- fprintf(stderr, "Unknown : %08x\n", b);
- break;
+ switch (b & 0xF0) {
+ case 0x80:
+ case 0x90:
+ case 0xA0:
+ case 0xB0:
+ case 0xE0:
+ buf[position++] = SEQ_MIDIPUTC;
+ buf[position++] = b;
+ buf[position++] = DEVICE_NUM;
+ buf[position++] = 0;
+ buf[position++] = SEQ_MIDIPUTC;
+ buf[position++] = (b >> 8) & 0x7F;
+ buf[position++] = DEVICE_NUM;
+ buf[position++] = 0;
+ buf[position++] = SEQ_MIDIPUTC;
+ buf[position++] = (b >> 16) & 0x7F;
+ buf[position++] = DEVICE_NUM;
+ buf[position++] = 0;
+ break;
+ case 0xC0:
+ case 0xD0:
+ buf[position++] = SEQ_MIDIPUTC;
+ buf[position++] = b;
+ buf[position++] = DEVICE_NUM;
+ buf[position++] = 0;
+ buf[position++] = SEQ_MIDIPUTC;
+ buf[position++] = (b >> 8) & 0x7F;
+ buf[position++] = DEVICE_NUM;
+ buf[position++] = 0;
+ break;
+ default:
+ fprintf(stderr, "Unknown : %08x\n", b);
+ break;
+ }
+ write(s, buf, position);
}
- write(s, buf, position);
-}
-#else
-#define MIDI_OUT(a,b)
-void MidiSoundDriver::midiInit() { }
+#elif defined(USE_QTMUSIC)
+ /* Quicktime music support */
+ void MidiSoundDriver::midiInit() {
+ ComponentResult qtErr = noErr;
+ qtNoteAllocator = NULL;
+
+ for (int i = 0 ; i < 15 ; i++)
+ qtNoteChannel[i] = NULL;
+
+ qtNoteAllocator = OpenDefaultComponent(kNoteAllocatorComponentType, 0);
+ if (qtNoteAllocator == NULL)
+ goto bail;
+
+ simpleNoteRequest.info.flags = 0;
+ *(short *)(&simpleNoteRequest.info.polyphony) = EndianS16_NtoB(15); // simultaneous tones
+ *(Fixed *)(&simpleNoteRequest.info.typicalPolyphony) = EndianU32_NtoB(0x00010000);
+
+ qtErr = NAStuffToneDescription(qtNoteAllocator, 1, &simpleNoteRequest.tone);
+ if (qtErr != noErr)
+ goto bail;
+
+ for (int i = 0 ; i < 15 ; i++) {
+ qtErr = NANewNoteChannel(qtNoteAllocator, &simpleNoteRequest, &(qtNoteChannel[i]));
+ if ((qtErr != noErr) || (qtNoteChannel == NULL))
+ goto bail;
+ }
+ return;
+
+ bail:
+ fprintf(stderr, "Init QT failed %x %x %d\n", qtNoteAllocator, qtNoteChannel, qtErr);
+ for (int i = 0 ; i < 15 ; i++) {
+ if (qtNoteChannel[i] != NULL)
+ NADisposeNoteChannel(qtNoteAllocator, qtNoteChannel[i]);
+ }
+
+ if (qtNoteAllocator != NULL)
+ CloseComponent(qtNoteAllocator);
+ }
+
+ static inline void MIDI_OUT(void *a, int b) {
+ MusicMIDIPacket midPacket;
+ unsigned char *midiCmd = midPacket.data;
+ midPacket.length = 3;
+ midiCmd[3] = (b & 0xFF000000)>>24;
+ midiCmd[2] = (b & 0x00FF0000)>>16;
+ midiCmd[1] = (b & 0x0000FF00)>>8;
+ midiCmd[0] = b;
+
+ unsigned char chanID = midiCmd[0] & 0x0F;
+ switch (midiCmd[0] & 0xF0) {
+ case 0x80: // Note off
+ NAPlayNote(qtNoteAllocator, qtNoteChannel[chanID], midiCmd[1], 0);
+ break;
+
+ case 0x90: // Note on
+ NAPlayNote(qtNoteAllocator, qtNoteChannel[chanID], midiCmd[1], midiCmd[2]);
+ break;
+
+ case 0xB0: // Effect
+ switch (midiCmd[1]) {
+ case 0x01: // Modulation
+ NASetController(qtNoteAllocator, qtNoteChannel[chanID], kControllerModulationWheel, midiCmd[2]<<8);
+ break;
+
+ case 0x07: // Volume
+ NASetController(qtNoteAllocator, qtNoteChannel[chanID], kControllerVolume, midiCmd[2]*300);
+ break;
+
+ case 0x0A: // Pan
+ NASetController(qtNoteAllocator, qtNoteChannel[chanID], kControllerPan, (midiCmd[2]<<1)+0xFF);
+ break;
+
+ case 0x40: // Sustain on/off
+ NASetController(qtNoteAllocator, qtNoteChannel[chanID], kControllerSustain, midiCmd[2]);
+ break;
+
+ case 0x5b: // ext effect depth
+ NASetController(qtNoteAllocator, qtNoteChannel[chanID], kControllerReverb, midiCmd[2]<<8);
+ break;
+
+ case 0x5d: // chorus depth
+ NASetController(qtNoteAllocator, qtNoteChannel[chanID], kControllerChorus, midiCmd[2]<<8);
+ break;
+
+ case 0x7b: // mode message all notes off
+ for (int i = 0 ; i < 128 ; i++)
+ NAPlayNote(qtNoteAllocator, qtNoteChannel[chanID], i, 0);
+ break;
+
+ default:
+ fprintf(stderr, "Unknown MIDI effect: %08x\n", b);
+ break;
+ }
+ break;
+
+ case 0xC0: // Program change
+ NASetInstrumentNumber(qtNoteAllocator, qtNoteChannel[chanID], midiCmd[1]);
+ break;
+
+ case 0xE0: { // Pitch bend
+ long theBend = ((((long)midiCmd[1] + (long)(midiCmd[2] << 8)))-0x4000)/4;
+ NASetController(qtNoteAllocator, qtNoteChannel[chanID], kControllerPitchBend, theBend);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "Unknown Command: %08x\n", b);
+ NASendMIDI(qtNoteAllocator, qtNoteChannel[chanID], &midPacket);
+ break;
+ }
+ }
+#elif
+
+ /* Null output driver */
+ #define MIDI_OUT(a,b)
+ void MidiSoundDriver::midiInit() {warning("Music not enabled - MIDI support selected with no MIDI driver available. Try Adlib";}
#endif
+
+/************************* Common midi code **********************/
void MidiSoundDriver::midiPitchBend(byte chan, int16 pitchbend) {
uint16 tmp;
@@ -224,8 +369,9 @@ static const byte mt32_to_gmidi[128] = {
void MidiSoundDriver::midiProgram(byte chan, byte program) {
- if (_mt32emulate)
+ if (_se->_mt32emulate)
program=mt32_to_gmidi[program];
+
MIDI_OUT(_mo, program<<8 | 0xC0 | chan);
}
@@ -410,5 +556,3 @@ void MidiSoundDriver::part_off(Part *part) {
midiSilence(mc->_chan);
}
}
-
-#endif