From dbca48aa1cd1b4a984a5b0791a064bfb3d088f70 Mon Sep 17 00:00:00 2001 From: James Brown Date: Thu, 14 Mar 2002 06:06:49 +0000 Subject: 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.. svn-id: r3741 --- scummvm.cpp | 14 ++- sound.h | 14 ++- sound/gmidi.cpp | 384 ++++++++++++++++++++++++++++++++++++++------------------ 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 - start in room \n" \ - "\tt - Set music tempo. Suggested: 1F0000\n" \ - "\ts - Set scale factor to (1, 2, or 3 - 2 by default)\n" \ + "\tt - set music tempo. Suggested: 1F0000\n" \ + "\ts - set scale factor to (1, 2, or 3 - 2 by default)\n" \ "\tp - look for game in \n" \ - "\tm - Set music volume to (0-100)\n" \ + "\tm - set music volume to (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 + * QuickTime support by Florent Boudet + * Raw output support by Michael Pearce */ #include "stdafx.h" - -#if !defined USE_ADLIB - #include "scumm.h" #include "sound.h" - -#ifdef USE_TIMIDITY -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* 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 -- cgit v1.2.3