diff options
author | Ludvig Strigeus | 2002-04-13 18:34:11 +0000 |
---|---|---|
committer | Ludvig Strigeus | 2002-04-13 18:34:11 +0000 |
commit | 9f191ea9c5882f59cd23adbcbaa4a1c704909573 (patch) | |
tree | f2ddc0e916248a56c82418b8346569bafd6e915a | |
parent | 38628f3543cf16d23968f541e4a35c95c2e17f13 (diff) | |
download | scummvm-rg350-9f191ea9c5882f59cd23adbcbaa4a1c704909573.tar.gz scummvm-rg350-9f191ea9c5882f59cd23adbcbaa4a1c704909573.tar.bz2 scummvm-rg350-9f191ea9c5882f59cd23adbcbaa4a1c704909573.zip |
new midi driver API,
no more USE_ADLIB,
a couple of sdl graphics driver fixes.
svn-id: r3925
-rw-r--r-- | gameDetector.cpp | 114 | ||||
-rw-r--r-- | gameDetector.h | 9 | ||||
-rw-r--r-- | main.cpp | 10 | ||||
-rw-r--r-- | resource.cpp | 16 | ||||
-rw-r--r-- | scumm.h | 6 | ||||
-rw-r--r-- | scummvm.cpp | 20 | ||||
-rw-r--r-- | scummvm.dsp | 14 | ||||
-rw-r--r-- | sdl.cpp | 32 | ||||
-rw-r--r-- | simon/midi.cpp | 392 | ||||
-rw-r--r-- | simon/simon.cpp | 5 | ||||
-rw-r--r-- | simon/simon.h | 43 | ||||
-rw-r--r-- | sound.cpp | 2 | ||||
-rw-r--r-- | sound.h | 52 | ||||
-rw-r--r-- | sound/adlib.cpp | 14 | ||||
-rw-r--r-- | sound/gmidi.cpp | 412 | ||||
-rw-r--r-- | sound/gmidi.h | 106 | ||||
-rw-r--r-- | sound/imuse.cpp | 26 | ||||
-rw-r--r-- | sound/mididrv.cpp | 689 | ||||
-rw-r--r-- | system.h | 10 |
19 files changed, 1087 insertions, 885 deletions
diff --git a/gameDetector.cpp b/gameDetector.cpp index 4eb75b06de..36dfa72491 100644 --- a/gameDetector.cpp +++ b/gameDetector.cpp @@ -40,7 +40,7 @@ static const char USAGE_STRING[] = "\tt<num> - set music tempo. Suggested: 1F0000\n" "\tp<path> - look for game in <path>\n" "\tm<num> - set music volume to <num> (0-100)\n" - "\te<num> - set music engine. see readme.txt for details\n" + "\te<mode> - set music engine. see readme.txt for details\n" "\tr - emulate roland mt32 instruments\n" "\tf - fullscreen mode\n" "\tg<mode> - graphics mode. normal,2x,3x,2xsai,super2xsai,supereagle\n" @@ -118,9 +118,8 @@ void GameDetector::parseCommandLine(int argc, char **argv) break; } case 'e': - if (*(s + 1) == '\0') + if (!parseMusicDriver(s+1)) goto ShowHelpAndExit; - _midi_driver = atoi(s + 1); goto NextArg; case 'g': { int gfx_mode = parseGraphicsMode(s+1); @@ -151,7 +150,7 @@ void GameDetector::parseCommandLine(int argc, char **argv) } #else - _midi_driver = 4; + _midi_driver = 4; /* FIXME: don't use numerics */ _exe_name = *argv; _gameDataPath = (char *)malloc(strlen(_exe_name) + 3); sprintf(_gameDataPath, ":%s:", _exe_name); @@ -184,6 +183,45 @@ int GameDetector::parseGraphicsMode(const char *s) { return -1; } +bool GameDetector::parseMusicDriver(const char *s) { + struct MusicDrivers { + const char *name; + int id; + }; + + const struct MusicDrivers music_drivers[] = { + {"auto",MD_AUTO}, + {"null",MD_NULL}, + {"windows",MD_WINDOWS}, + {"timidity",MD_TIMIDITY}, + {"seq",MD_SEQ}, + {"qt",MD_QTMUSIC}, + {"amidi",MD_AMIDI}, + {"adlib",-1}, + }; + + const MusicDrivers *md = music_drivers; + int i; + + _use_adlib = false; + + for(i=0; i!=ARRAYSIZE(music_drivers); i++,md++) { + if (!scumm_stricmp(md->name, s)) { + /* FIXME: when adlib driver is in use, propagate that to + * the Scumm class, and let it create an AdlibSoundDriver + * instead of MidiSoundDriver */ + if (md->id == -1) { + _use_adlib = true; + } + _midi_driver = md->id; + return true; + } + } + + return false; +} + + struct VersionSettings { const char *filename; const char *gamename; @@ -223,27 +261,27 @@ static const VersionSettings version_settings[] = { /* Scumm version 5 */ {"loomcd", "Loom (256 color CD version)", GID_LOOM256, 5, 1, 42, - GF_SMALL_HEADER | GF_USE_KEY | GF_AUDIOTRACKS}, + GF_SMALL_HEADER | GF_USE_KEY | GF_AUDIOTRACKS | GF_ADLIB_DEFAULT}, {"monkey", "Monkey Island 1", GID_MONKEY, 5, 2, 2, GF_USE_KEY | GF_AUDIOTRACKS}, {"monkey1", "Monkey Island 1 (alt)", GID_MONKEY, 5, 2, 2, - GF_USE_KEY | GF_AUDIOTRACKS}, + GF_USE_KEY | GF_AUDIOTRACKS | GF_ADLIB_DEFAULT}, {"monkey2", "Monkey Island 2: LeChuck's revenge", GID_MONKEY2, 5, 2, 2, - GF_USE_KEY}, + GF_USE_KEY | GF_ADLIB_DEFAULT}, {"atlantis", "Indiana Jones 4 and the Fate of Atlantis", GID_INDY4, 5, 5, 0, - GF_USE_KEY}, + GF_USE_KEY | GF_ADLIB_DEFAULT}, {"playfate", "Indiana Jones 4 and the Fate of Atlantis (Demo)", GID_INDY4, - 5, 5, 0, GF_USE_KEY}, + 5, 5, 0, GF_USE_KEY | GF_ADLIB_DEFAULT}, /* Scumm Version 6 */ {"tentacle", "Day Of The Tentacle", GID_TENTACLE, 6, 4, 2, - GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY}, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_ADLIB_DEFAULT}, {"dottdemo", "Day Of The Tentacle (Demo)", GID_TENTACLE, 6, 3, 2, - GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY}, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_ADLIB_DEFAULT}, {"samnmax", "Sam & Max", GID_SAMNMAX, 6, 4, 2, - GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_DRAWOBJ_OTHER_ORDER}, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_DRAWOBJ_OTHER_ORDER | GF_ADLIB_DEFAULT}, {"snmdemo", "Sam & Max (Demo)", GID_SAMNMAX, 6, 3, 0, - GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY}, + GF_NEW_OPCODES | GF_AFTER_V6 | GF_USE_KEY | GF_ADLIB_DEFAULT}, /* Scumm Version 7 */ {"ft", "Full Throttle", GID_FT, 7, 3, 0, @@ -307,11 +345,7 @@ int GameDetector::detectMain(int argc, char **argv) _gameTempo = 0; _soundCardType = 3; -#ifdef WIN32 - _midi_driver = MIDI_WINDOWS; -#else - _midi_driver = MIDI_NULL; -#endif + _midi_driver = MD_AUTO; parseCommandLine(argc, argv); @@ -329,6 +363,13 @@ int GameDetector::detectMain(int argc, char **argv) _gameText = "Please choose a game"; } + /* Use the adlib sound driver if auto mode is selected, + * and the game is one of those that want adlib as + * default */ + if (_midi_driver == MD_AUTO && _features&GF_ADLIB_DEFAULT) { + _use_adlib = true; + } + if (!_gameDataPath) { warning("No path was provided. Assuming that data file are in the current directory"); _gameDataPath = (char *)malloc(sizeof(char) * 2); @@ -337,3 +378,40 @@ int GameDetector::detectMain(int argc, char **argv) return (0); } + +OSystem *GameDetector::createSystem() { + /* auto is to use SDL */ + switch(_gfx_driver) { + case GD_SDL: + case GD_AUTO: + return OSystem_SDL_create(_gfx_mode, _fullScreen); + case GD_WIN32: + /* not implemented yet */ + break; + + case GD_X: + /* not implemented yet */ + break; + } + + error("Invalid graphics driver"); + return NULL; +} + +MidiDriver *GameDetector::createMidi() { + int drv = _midi_driver; + +#ifdef WIN32 + /* MD_WINDOWS is default MidiDriver on windows targets */ + if (drv == MD_AUTO) drv = MD_WINDOWS; +#endif + + switch(drv) { + case MD_AUTO: + case MD_NULL: return MidiDriver_NULL_create(); + case MD_WINDOWS: return MidiDriver_WIN_create(); + } + + error("Invalid midi driver selected"); + return NULL; +}
\ No newline at end of file diff --git a/gameDetector.h b/gameDetector.h index ea7c9f709b..dc2d62b9f0 100644 --- a/gameDetector.h +++ b/gameDetector.h @@ -32,6 +32,8 @@ public: byte _gameId; bool _simon; + bool _use_adlib; + uint16 _debugMode; uint16 _noSubtitles; uint16 _bootParam; @@ -45,12 +47,17 @@ public: const char *_gameText; uint32 _features; + int _gfx_driver; int _gfx_mode; int _scummVersion; int _cdrom; int parseGraphicsMode(const char *s); - + bool parseMusicDriver(const char *s); + +public: + OSystem *createSystem(); + MidiDriver *createMidi(); }; @@ -8,8 +8,6 @@ GameDetector detector; Gui gui; Scumm *g_scumm; -SoundEngine sound; -SOUND_DRIVER_TYPE snd_driv; #if !defined(__APPLE__) @@ -55,7 +53,7 @@ int main(int argc, char *argv[]) if (detector.detectMain(argc, argv)) return (-1); - OSystem *system = OSystem_SDL_create(detector._gfx_mode, detector._fullScreen); + OSystem *system = detector.createSystem(); { char *s = detector.getGameName(); @@ -66,16 +64,16 @@ int main(int argc, char *argv[]) /* Simon the Sorcerer? */ if (detector._gameId >= GID_SIMON_FIRST && detector._gameId <= GID_SIMON_LAST) { /* Simon the Sorcerer. Completely different initialization */ + MidiDriver *midi = detector.createMidi(); + SimonState *simon = SimonState::create(); simon->_game = detector._gameId - GID_SIMON_FIRST; - simon->go(system); + simon->go(system, midi); } else { Scumm *scumm = Scumm::createFromDetector(&detector, system); g_scumm = scumm; - sound.initialize(scumm, &snd_driv); - /* bind to Gui */ scumm->_gui = &gui; gui.init(scumm); /* Reinit GUI after loading a game */ diff --git a/resource.cpp b/resource.cpp index d5b74443da..0cb921879b 100644 --- a/resource.cpp +++ b/resource.cpp @@ -566,21 +566,21 @@ int Scumm::readSoundResource(int type, int idx) size = fileReadDwordBE() + 8; pos += size; + pri = -1; + switch (tag) { -#ifdef USE_ADLIB case MKID('ADL '): - pri = 10; + if (_use_adlib) + pri = 10; break; -#else case MKID('ROL '): - pri = 1; + if (!_use_adlib) + pri = 1; break; case MKID('GMD '): - pri = 2; + if (!_use_adlib) + pri = 2; break; -#endif - default: - pri = -1; } if (pri > best_pri) { @@ -529,7 +529,8 @@ enum GameFeatures { GF_16COLOR = 256, GF_OLD256 = 512, GF_AUDIOTRACKS = 1024, - GF_NO_SCALLING = 2048 + GF_NO_SCALLING = 2048, + GF_ADLIB_DEFAULT = 4096, }; enum WhereIsObject { @@ -941,8 +942,9 @@ public: /* Should be in Sound class */ MixerChannel _mixer_channel[NUM_MIXER]; - int _gameTempo, _midi_driver; + int _gameTempo; byte _sfxMode; + bool _use_adlib; int16 _sound_volume_master, _sound_volume_music, _sound_volume_sfx; int _saveSound; void *_sfxFile; diff --git a/scummvm.cpp b/scummvm.cpp index e292b83588..adc6640630 100644 --- a/scummvm.cpp +++ b/scummvm.cpp @@ -1298,9 +1298,25 @@ Scumm *Scumm::createFromDetector(GameDetector *detector, OSystem *syst) scumm->_features = detector->_features; scumm->_soundCardType = detector->_soundCardType; scumm->_noSubtitles = detector->_noSubtitles; - scumm->_midi_driver = detector->_midi_driver; scumm->_cdrom = detector->_cdrom; + { + SoundDriver *sdriv; + SoundEngine *seng; + + scumm->_use_adlib = detector->_use_adlib; + + if (!detector->_use_adlib) { + MidiDriver *midi = detector->createMidi(); + sdriv = new MidiSoundDriver; + ((MidiSoundDriver*)sdriv)->midiSetDriver(midi); + } else { + sdriv = new AdlibSoundDriver; + } + seng = new SoundEngine; + seng->initialize(scumm, sdriv); + } + scumm->delta = 6; if (detector->_restore) { scumm->_saveLoadSlot = 0; @@ -1309,6 +1325,8 @@ Scumm *Scumm::createFromDetector(GameDetector *detector, OSystem *syst) } scumm->delta = 0; + + return scumm; } diff --git a/scummvm.dsp b/scummvm.dsp index 4339e34d57..42d7dba044 100644 --- a/scummvm.dsp +++ b/scummvm.dsp @@ -68,7 +68,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
-# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "./sound" /I "./" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "ALLOW_GDI" /D "BYPASS_COPY_PROT" /D "DUMP_SCRIPTS" /D "USE_ADLIB" /Yu"stdafx.h" /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "./sound" /I "./" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "ALLOW_GDI" /D "BYPASS_COPY_PROT" /D "DUMP_SCRIPTS" /Yu"stdafx.h" /FD /GZ /c
# SUBTRACT CPP /Fr
# ADD BASE RSC /l 0x41d /d "_DEBUG"
# ADD RSC /l 0x41d /d "_DEBUG"
@@ -133,8 +133,16 @@ SOURCE=.\sound\gmidi.cpp # End Source File
# Begin Source File
+SOURCE=.\sound\gmidi.h
+# End Source File
+# Begin Source File
+
SOURCE=.\sound\imuse.cpp
# End Source File
+# Begin Source File
+
+SOURCE=.\sound\mididrv.cpp
+# End Source File
# End Group
# Begin Group "v3"
@@ -480,10 +488,6 @@ SOURCE=.\gfx.h # End Source File
# Begin Source File
-SOURCE=.\sound\gmidi.h
-# End Source File
-# Begin Source File
-
SOURCE=.\gui.h
# End Source File
# Begin Source File
@@ -502,7 +502,6 @@ void OSystem_SDL::add_dirty_rgn_auto(const byte *buf) { if (!force_full) { uint x,y,w; uint32 *ck = dirty_checksums; - SDL_Rect *dr = dirty_rect_list; for(y=0; y!=SCREEN_HEIGHT/8; y++) { for(x=0; x!=SCREEN_WIDTH/8; x++,ck++) { @@ -515,21 +514,13 @@ void OSystem_SDL::add_dirty_rgn_auto(const byte *buf) { w++; } while (x+w != SCREEN_WIDTH/8 && ck[w] != ck[w+CKSUM_NUM]); - /* add this rect to the dirty list. */ - if(dr==&dirty_rect_list[NUM_DIRTY_RECT-1]) { - force_full=true; + add_dirty_rect(x*8, y*8, w*8, 8); + + if (force_full) goto get_out; - } - - dr->x = x*8; - dr->y = y*8; - dr->w = w*8; - dr->h = 1*8; - dr++; } } } - num_dirty_rects = dr - dirty_rect_list; } else { get_out:; /* Copy old checksums to new */ @@ -544,13 +535,9 @@ void OSystem_SDL::update_screen() { /* force a full redraw, accomplish that by adding one big rect to the dirty * rect list */ if (force_full) { - SDL_Rect *dr = dirty_rect_list; - dr->x = 0; - dr->y = 0; - dr->w = SCREEN_WIDTH; - dr->h = SCREEN_HEIGHT; - num_dirty_rects = 1; force_full = false; + num_dirty_rects = 0; + add_dirty_rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); } if (num_dirty_rects == 0 || sdl_hwscreen == NULL) @@ -807,14 +794,15 @@ void OSystem_SDL::hotswap_gfx_mode() { unload_gfx_mode(); load_gfx_mode(); - /* blit image */ - OSystem_SDL::copy_rect(bak_mem, 320, 0, 0, 320, 200); - free(bak_mem); + force_full = true; /* reset palette */ SDL_SetColors(sdl_screen, _cur_pal, 0, 256); - force_full = true; + /* blit image */ + OSystem_SDL::copy_rect(bak_mem, 320, 0, 0, 320, 200); + free(bak_mem); + OSystem_SDL::update_screen(); } diff --git a/simon/midi.cpp b/simon/midi.cpp index a98ccd0e54..13459208b1 100644 --- a/simon/midi.cpp +++ b/simon/midi.cpp @@ -23,11 +23,9 @@ #include "stdafx.h" #include "scummsys.h" #include "system.h" +#include "gmidi.h" #include "simon.h" -/* This is win32 only code at the moment */ -#ifdef WIN32 - void MidiPlayer::read_from_file(void *dst, uint size) { if (fread(dst, size, 1, _input) != 1) error("Midi read error"); @@ -135,10 +133,8 @@ void MidiPlayer::read_mthd(Song *s, bool old) { t->delay = track_read_gamma(t); } - } - void MidiPlayer::read_one_song(Song *s) { _midi_var10 = 0; @@ -190,81 +186,38 @@ byte MidiPlayer::track_read_byte(Track *t) { } void MidiPlayer::initialize() { -#ifdef WIN32 - uint i; - MyMidiHdr *mmh; - MIDIPROPTIMEDIV mptd; - uint x; - - if (_midi_stream_handle == NULL) { - _midi_device_id = 0; - check_error(midiStreamOpen(&_midi_stream_handle, &_midi_device_id, 1, - (uint32)midi_callback, (uint32)this, CALLBACK_FUNCTION)); - } - - for(i=0,mmh=_prepared_headers; i!=NumPreparedHeaders; i++,mmh++) { - mmh->hdr.dwBufferLength = 0x400; - mmh->hdr.lpData = (LPSTR)calloc(0x400,1); - if (mmh->hdr.lpData == NULL) - error("Out of memory for prepared header"); - } + int res; + int i; for(i=0; i!=16; i++) _midi_volume_table[i] = 100; - - mptd.cbStruct = sizeof(mptd); - mptd.dwTimeDiv = _midi_songs[0].ppqn; - - check_error(midiStreamProperty(_midi_stream_handle, (byte*)&mptd, - MIDIPROP_SET | MIDIPROP_TIMEDIV)); - _midi_5 = 0; - x = 1; - - for(i=0,mmh=_prepared_headers; i!=NumPreparedHeaders; i++,mmh++) { - - fill(x, mmh); - - mmh->hdr.dwBytesRecorded = mmh->b; - - if (!_midi_var9) { - check_error(midiOutPrepareHeader((HMIDIOUT)_midi_stream_handle, - &mmh->hdr, sizeof(mmh->hdr))); - } - - check_error(midiStreamOut(_midi_stream_handle, - &mmh->hdr, sizeof(mmh->hdr))); - x = 0; - } + _md->property(MidiDriver::PROP_TIMEDIV, _midi_songs[0].ppqn); + res = _md->open(MidiDriver::MO_STREAMING); + if (res != 0) + error("MidiPlayer::initializer, got %s", MidiDriver::get_error_name(res)); + _midi_var9 = true; -#endif } -int MidiPlayer::fill(uint x, MyMidiHdr *mmh) { - uint32 best,i; +int MidiPlayer::fill(MidiEvent *me, int num_event) { + uint32 best,j; Track *best_track,*t; bool did_reset; - - mmh->a = 0; - mmh->size = 0x200; - mmh->c = 0; - mmh->d = 0; - mmh->b = 0; + NoteRec midi_tmp_note_rec; + int i = 0; did_reset = false; - for(;;) { - if (mmh->size - mmh->b < 12) - return 1; - + for(i=0; i!=num_event;) { best_track = NULL; best = 0xFFFFFFFF; /* Locate which track that's next */ t = _midi_cur_song_ptr->tracks; - for(i=0; i!=_midi_cur_song_ptr->num_tracks; i++,t++) { + for(j=_midi_cur_song_ptr->num_tracks; j; j--,t++) { if (!(t->a&1)) { if (t->delay < best) { best = t->delay; @@ -276,278 +229,59 @@ int MidiPlayer::fill(uint x, MyMidiHdr *mmh) { if (best_track == NULL) { /* reset tracks if song ended? */ if (did_reset) { - return 0; + /* exit if song ended completely */ + return i; } did_reset = true; reset_tracks(); continue; } - read_next_note(best_track, &_midi_tmp_note_rec); -// if ((_midi_tmp_note_rec.cmd&0xF)==3) { -// printf("%4d: %2X %d\n", _midi_tmp_note_rec.delay, -// _midi_tmp_note_rec.cmd, _midi_tmp_note_rec.param_1); - fill_helper(&_midi_tmp_note_rec, mmh); -// } + read_next_note(best_track, &midi_tmp_note_rec); + if (fill_helper(&midi_tmp_note_rec, me + i)) + i++; - if (_midi_num_sysex) { - free(_midi_tmp_note_rec.sysex_data); - _midi_num_sysex--; - } + if (midi_tmp_note_rec.sysex_data) free(midi_tmp_note_rec.sysex_data); } -} - -int MidiPlayer::fill_helper(NoteRec *nr, MyMidiHdr *mmh) { -#ifdef WIN32 - byte *lpdata; - uint b; - - lpdata = (byte*)mmh->hdr.lpData + mmh->a + mmh->b; - - b = nr->delay - _midi_var10; - _midi_var10 = nr->delay; - - if (nr->cmd<0xF0) { - ((MIDIEVENT*)lpdata)->dwDeltaTime = b; - ((MIDIEVENT*)lpdata)->dwStreamID = 0; - ((MIDIEVENT*)lpdata)->dwEvent = nr->cmd | (nr->param_1<<8) | (nr->param_2<<16); - - if ((nr->cmd&0xF0) == 0xB0 && nr->param_1 == 7) { - _midi_volume_table[nr->cmd&0xF] = nr->param_2; - - nr->param_1 = 0x76; - - ((MIDIEVENT*)lpdata)->dwEvent = nr->cmd | - (nr->param_1<<8) | (nr->param_2<<16) | MEVT_F_CALLBACK; - } - - mmh->b += 12; - } else if (nr->cmd==0xF0 || nr->cmd==0xF7) { - } else if (nr->param_1 != 0x51) { - return -105; - } else { - ((MIDIEVENT*)lpdata)->dwDeltaTime = b; - ((MIDIEVENT*)lpdata)->dwStreamID = 0; - - _midi_tempo = nr->sysex_data[2] | - (nr->sysex_data[1]<<8) | (nr->sysex_data[0]<<16); - - ((MIDIEVENT*)lpdata)->dwEvent = _midi_tempo | (MEVT_TEMPO<<24); - _midi_var8 = (_midi_cur_song_ptr->ppqn*60000) / _midi_tempo; - - if(_midi_num_sysex) { - free(nr->sysex_data); - _midi_num_sysex--; - } - - mmh->b += 12; - } -#endif - return 0; + return i; } -#if 0 -int MidiPlayer::fill(uint x, MyMidiHdr *mmh) { - Track *t; - uint i; - uint32 best; - Track *best_track; - int result; - - mmh->b = 0; - - if (x&1) { - NoteRec *nr = &_midi_tmp_note_rec; - - _midi_var1 = 0; - nr->delay = 0; - nr->big_cmd = 0; - nr->cmd_length = 0; - nr->sysex_data = NULL; - - _midi_track_ptr = NULL; - _midi_tick_track_ptr = NULL; - } - - if (_midi_var1 & 1) { - if (_midi_var2 == 0) - error("MidiPlayer::fill: Return -103"); - reset_tracks(); - _midi_var1 = 0; - } else if (_midi_var1 & 2) { - error("MidiPlayer::fill: Return -102"); - } else if (_midi_var1 & 4) { - _midi_var1 ^= 4; - - if (_midi_tmp_note_rec.cmd==0xFF && _midi_tmp_note_rec.param_1==0x2F) { - if (_midi_num_sysex) { - free(_midi_tmp_note_rec.sysex_data); - _midi_num_sysex--; - } - } else { - result = fill_helper(&_midi_tmp_note_rec, mmh); - if (result==-104) { - _midi_var1 |= 4; - return 0; - } - } - } - - /* find_next_track_to_run */ - for(;;) { - best_track = NULL; - best = 0xFFFFFFFF; - - /* Locate which track that's next */ - t = _midi_cur_song_ptr->tracks; - for(i=0; i!=_midi_cur_song_ptr->num_tracks; i++,t++) { - if (!(t->a&1)) { - if (t->delay < best) { - best = t->delay; - best_track = t; - } - } - } - - if (best_track == NULL) { - _midi_var1 |= 1; - return 0; - } - - read_next_note(best_track, &_midi_tmp_note_rec); - - if (_midi_tmp_note_rec.cmd==0xFF && _midi_tmp_note_rec.param_1==0x2F) { - if (_midi_num_sysex) { - free(_midi_tmp_note_rec.sysex_data); - _midi_num_sysex--; - } - continue; - } - - result = fill_helper(&_midi_tmp_note_rec, mmh); - if (result==-104) { - _midi_var1 |= 4; - return 0; - } - } +int MidiPlayer::on_fill(void *param, MidiEvent *ev, int num) { + MidiPlayer *mp = (MidiPlayer*)param; + return mp->fill(ev, num); } -int MidiPlayer::fill_helper(NoteRec *nr, MyMidiHdr *mmh) { - byte *lpdata; - uint a,b; - - lpdata = (byte*)mmh->hdr.lpData + mmh->a + mmh->b; - - if (mmh->b == 0) { - mmh->c = _midi_var10; - } - - if (_midi_var10 - mmh->c > _midi_var8) { - if (mmh->d!=0) { - mmh->d = 0; - return -104; - } - mmh->d = 1; - } +bool MidiPlayer::fill_helper(NoteRec *nr, MidiEvent *me) { + uint b; - a = _midi_var10; b = nr->delay - _midi_var10; _midi_var10 = nr->delay; if (nr->cmd<0xF0) { - if (mmh->size - mmh->b < 12) - return -104; - - ((MIDIEVENT*)lpdata)->dwDeltaTime = b; - ((MIDIEVENT*)lpdata)->dwStreamID = 0; - ((MIDIEVENT*)lpdata)->dwEvent = nr->cmd | (nr->param_1<<8) | (nr->param_2<<16); + me->delta = b; + me->event = nr->cmd | (nr->param_1<<8) | (nr->param_2<<16); if ((nr->cmd&0xF0) == 0xB0 && nr->param_1 == 7) { _midi_volume_table[nr->cmd&0xF] = nr->param_2; - nr->param_1 = 0x76; - - ((MIDIEVENT*)lpdata)->dwEvent = nr->cmd | - (nr->param_1<<8) | (nr->param_2<<16) | MEVT_F_CALLBACK; - } - - mmh->b += 12; - } else if (nr->cmd==0xF0 || nr->cmd==0xF7) { - if(_midi_num_sysex) { - free(nr->sysex_data); - _midi_num_sysex--; + me->event = nr->cmd | (nr->param_1<<8) | (nr->param_2<<16)/* | MEVT_F_CALLBACK*/; } - } else if (nr->param_1 != 0x51) { - if(_midi_num_sysex) { - free(nr->sysex_data); - _midi_num_sysex--; - } - - return -105; - } else if (mmh->size - mmh->b < 12) { - if(_midi_num_sysex) { - free(nr->sysex_data); - _midi_num_sysex--; - } - return -104; - } else { - ((MIDIEVENT*)lpdata)->dwDeltaTime = b; - ((MIDIEVENT*)lpdata)->dwStreamID = 0; + return true; - _midi_tempo = nr->sysex_data[2] | - (nr->sysex_data[1]<<8) | (nr->sysex_data[0]<<16); - - ((MIDIEVENT*)lpdata)->dwEvent = _midi_tempo | (MEVT_TEMPO<<24); - - _midi_var8 = (_midi_cur_song_ptr->ppqn*60000) / _midi_tempo; - - if(_midi_num_sysex) { - free(nr->sysex_data); - _midi_num_sysex--; - } - - mmh->b += 12; } - - return 0; -} -#endif - -void MidiPlayer::add_finished_hdrs() { - uint i; - MyMidiHdr *mmh = _prepared_headers; - - for(i=0; i!=NumPreparedHeaders; i++,mmh++) { - if (!(mmh->hdr.dwFlags & MHDR_INQUEUE)) { - fill(0, mmh); - if (mmh->b == 0) - break; - mmh->hdr.dwBytesRecorded = mmh->b; - check_error(midiStreamOut(_midi_stream_handle, &mmh->hdr, sizeof(mmh->hdr))); - } + + if (nr->cmd==0xF0 || nr->cmd==0xF7 || nr->param_1 != 0x51) { + return false; } -} + + _midi_tempo = nr->sysex_data[2] | (nr->sysex_data[1]<<8) | (nr->sysex_data[0]<<16); + _midi_var8 = (_midi_cur_song_ptr->ppqn*60000) / _midi_tempo; -void CALLBACK MidiPlayer::midi_callback(HMIDIOUT hmo, UINT wMsg, - DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { + me->delta = b; + me->event = (MidiDriver::ME_TEMPO << 24) | _midi_tempo; - switch(wMsg) { - case MM_MOM_DONE:{ - MidiPlayer *mp = ((MidiPlayer*)dwInstance); - if (!mp->_shutting_down) - mp->add_finished_hdrs(); - break; - } - } -} - -void MidiPlayer::check_error(MMRESULT result) { - char buf[200]; - if (result != MMSYSERR_NOERROR) { - midiOutGetErrorText(result, buf, 200); - error("MM System Error '%s'", buf); - } + return true; } void MidiPlayer::reset_tracks() { @@ -628,7 +362,6 @@ void MidiPlayer::read_next_note(Track *t, NoteRec *nr) { error("read_next_note: out of memory"); for(i=0; i!=nr->cmd_length; i++) nr->sysex_data[i] = track_read_byte(t); - _midi_num_sysex++; } else if (cmd_byte==0xFF) { nr->cmd = cmd_byte; @@ -642,7 +375,6 @@ void MidiPlayer::read_next_note(Track *t, NoteRec *nr) { error("read_next_note: out of memory"); for(i=0; i!=nr->cmd_length; i++) nr->sysex_data[i] = track_read_byte(t); - _midi_num_sysex++; } if (nr->param_1==0x2F) t->a|=1; @@ -657,21 +389,8 @@ void MidiPlayer::read_next_note(Track *t, NoteRec *nr) { } void MidiPlayer::shutdown() { - - if (_midi_stream_handle != NULL) { - _shutting_down = true; - - check_error(midiStreamStop(_midi_stream_handle)); - check_error(midiOutReset((HMIDIOUT)_midi_stream_handle)); - - unload(); - unprepare(); - - check_error(midiStreamClose(_midi_stream_handle)); - _midi_stream_handle = NULL; - - _shutting_down = false; - } + _md->close(); + unload(); } void MidiPlayer::unload() { @@ -690,31 +409,14 @@ void MidiPlayer::unload() { } } -void MidiPlayer::unprepare() { - uint i; - MyMidiHdr *mmh = _prepared_headers; - - for(i=0; i!=NumPreparedHeaders; i++,mmh++) { - check_error(midiOutUnprepareHeader( - (HMIDIOUT)_midi_stream_handle, &mmh->hdr, sizeof(mmh->hdr))); - free(mmh->hdr.lpData); - mmh->hdr.lpData = NULL; - } - - _midi_var9 = false; -} - void MidiPlayer::play() { - check_error(midiStreamRestart(_midi_stream_handle)); + _md->pause(false); } -#else -/* Dummy midiplayer for unix */ -void MidiPlayer::shutdown() {} -void MidiPlayer::read_all_songs(FILE *in) {} -void MidiPlayer::read_all_songs_old(FILE *in) {} -void MidiPlayer::initialize() {} -void MidiPlayer::play() {} +void MidiPlayer::set_driver(MidiDriver *md) { + _md = md; + md->set_stream_callback(this, on_fill); +} + -#endif
\ No newline at end of file diff --git a/simon/simon.cpp b/simon/simon.cpp index 3d818137c4..52b82c4f16 100644 --- a/simon/simon.cpp +++ b/simon/simon.cpp @@ -7515,12 +7515,15 @@ void SimonState::realizePalette() { } -void SimonState::go(OSystem *syst) { +void SimonState::go(OSystem *syst, MidiDriver *driver) { _system = syst; if (!_dump_file) _dump_file = stdout; + /* Setup midi driver */ + midi.set_driver(driver); + /* allocate buffers */ sdl_buf_3 = (byte*)calloc(320*200,1); sdl_buf = (byte*)calloc(320*200,1); diff --git a/simon/simon.h b/simon/simon.h index a4ac6b55b6..ffaf9938e7 100644 --- a/simon/simon.h +++ b/simon/simon.h @@ -230,6 +230,8 @@ int GetAsyncKeyState(int key); #endif +class MidiDriver; +struct MidiEvent; class MidiPlayer { public: @@ -238,7 +240,8 @@ public: void initialize(); void shutdown(); void play(); - + void set_driver(MidiDriver *md); + private: struct Track { uint32 a; @@ -257,17 +260,7 @@ private: Track *tracks; }; - struct MyMidiHdr { - MIDIHDR hdr; - uint32 a; - uint32 size; - uint32 b; - uint32 c; - uint32 d; - }; - struct NoteRec { -#ifdef WIN32 uint32 delay; union { struct { @@ -279,18 +272,12 @@ private: }; uint cmd_length; byte *sysex_data; -#endif }; - enum { - NumPreparedHeaders = 2, - }; + MidiDriver *_md; FILE *_input; - HMIDISTRM _midi_stream_handle; - UINT _midi_device_id; - uint _midi_var10, _midi_5; bool _midi_var9; byte _midi_var1; @@ -299,8 +286,6 @@ private: uint _midi_var11; - uint _midi_num_sysex; - uint32 _midi_tempo; Track *_midi_tick_track_ptr; @@ -311,12 +296,9 @@ private: Song *_midi_cur_song_ptr; - NoteRec _midi_tmp_note_rec; - uint32 _midi_volume_table[16]; Song _midi_songs[8]; - MyMidiHdr _prepared_headers[NumPreparedHeaders]; void read_mthd(Song *s, bool old); @@ -329,22 +311,15 @@ private: static uint32 track_read_gamma(Track *t); static byte track_read_byte(Track *t); - static void check_error(MMRESULT result); - - int fill(uint x, MyMidiHdr *mmh); - int fill_helper(NoteRec *nr, MyMidiHdr *mmh); + int fill(MidiEvent *me, int num_event); + bool fill_helper(NoteRec *nr, MidiEvent *me); void reset_tracks(); void read_next_note(Track *t, NoteRec *nr); - static void CALLBACK midi_callback(HMIDIOUT hmo, UINT wMsg, - DWORD dwInstance, DWORD dwParam1, DWORD dwParam2); - - void unload(); - void unprepare(); - void add_finished_hdrs(); + static int on_fill(void *param, MidiEvent *ev, int num); }; @@ -975,7 +950,7 @@ public: void resfile_read(void *dst, uint32 offs, uint32 size); - void go(OSystem *syst); + void go(OSystem *syst, MidiDriver *driver); void openGameFile(); static int CDECL game_thread_proc(void *param); @@ -377,7 +377,6 @@ void Scumm::talkSound(uint32 a, uint32 b, int mode) void Scumm::setupSound() { SoundEngine *se = (SoundEngine *)_soundEngine; - SOUND_DRIVER_TYPE *driver = se->driver(); if (se) { se->setBase(res.address[rtSound]); if (se->get_music_volume() == 0) @@ -387,7 +386,6 @@ void Scumm::setupSound() _sound_volume_sfx = 100; _sound_volume_music = se->get_music_volume(); _sound_volume_master = (se->get_master_volume() / 127); - driver->midiSetDriver(_midi_driver); } _sfxFile = openSfxFile(); } @@ -91,12 +91,6 @@ struct Instrument; struct AdlibSoundDriver; struct MidiSoundDriver; -#if defined(USE_ADLIB) -#define SOUND_DRIVER_TYPE AdlibSoundDriver -#else -#define SOUND_DRIVER_TYPE MidiSoundDriver -#endif - struct Struct10 { byte active; int16 cur_val; @@ -148,7 +142,7 @@ struct Instrument { struct Part { int _slot; - SOUND_DRIVER_TYPE *_drv; + SoundDriver *_drv; Part *_next, *_prev; MidiChannel *_mc; Player *_player; @@ -378,6 +372,21 @@ struct SoundDriver { pcChorus = 128, pcAll = 255, }; + + virtual void on_timer() = 0; + virtual uint32 get_base_tempo() = 0; + virtual byte get_hardware_type() = 0; + virtual void init(SoundEngine *eng, OSystem *syst) = 0; + virtual void update_pris() = 0; + virtual void set_instrument(uint slot, byte *instr) = 0; + virtual void part_set_instrument(Part *part, Instrument *instr) = 0; + virtual void part_key_on(Part *part, byte note, byte velocity) = 0; + virtual void part_key_off(Part *part, byte note) = 0; + virtual void part_off(Part *part) = 0; + virtual void part_changed(Part *part,byte what) = 0; + virtual void part_set_param(Part *part, byte param, int value) = 0; + virtual int part_update_active(Part *part,uint16 *active) = 0; + virtual void generate_samples(int16 *buf, int len) = 0; }; struct AdlibSoundDriver : SoundDriver { @@ -426,8 +435,8 @@ public: void uninit(); void init(SoundEngine *eng, OSystem *syst); void update_pris() { } - void generate_samples(int16 *buf, int len); - void on_timer(); + void generate_samples(int16 *buf, int len); + void on_timer(); void set_instrument(uint slot, byte *instr); void part_set_instrument(Part *part, Instrument *instr); void part_key_on(Part *part, byte note, byte velocity); @@ -437,9 +446,19 @@ public: void part_off(Part *part); int part_update_active(Part *part,uint16 *active); void adjust_priorities() {} - void midiSetDriver(int devicetype) {;} + + uint32 get_base_tempo() { +#ifdef _WIN32_WCE + return 0x1F0000 * 2; // Sampled down to 11 kHz +#else //_WIN32_WCE + return 0x1924E0; +#endif //_WIN32_WCE + } + + byte get_hardware_type() { return 1; } }; +#if 0 struct MidiDriver { bool MidiInitialized; int DeviceType; @@ -462,6 +481,7 @@ struct MidiDriver { int connect_to_timidity(int port); int open_sequencer_device(); }; +#endif struct MidiSoundDriver : SoundDriver { SoundEngine *_se; @@ -477,7 +497,7 @@ struct MidiSoundDriver : SoundDriver { byte _midi_chorus_last[16]; int8 _midi_pan_last[16]; - MidiDriver _midi_driver; + MidiDriver *_md; void midiPitchBend(byte chan, int16 pitchbend); void midiVolume(byte chan, byte volume); void midiPedal(byte chan, bool pedal); @@ -507,21 +527,25 @@ public: void part_key_on(Part *part, byte note, byte velocity); void part_key_off(Part *part, byte note); void part_changed(Part *part,byte what); - void midiSetDriver(int devicetype); + void midiSetDriver(MidiDriver *driver); static int midi_driver_thread(void *param); + + uint32 get_base_tempo() { return 0x400000; } + byte get_hardware_type() { return 5; } }; struct SoundEngine { friend struct Player; private: - SOUND_DRIVER_TYPE *_driver; + SoundDriver *_driver; byte **_base_sounds; Scumm *_s; byte _locked; + byte _hardware_type; bool _paused; bool _active_volume_faders; @@ -613,7 +637,7 @@ public: int clear_queue(); void setBase(byte **base) { _base_sounds = base; } - SOUND_DRIVER_TYPE *driver() { return _driver; } + SoundDriver *driver() { return _driver; } bool _mt32emulate; }; diff --git a/sound/adlib.cpp b/sound/adlib.cpp index de550d3361..9700d99255 100644 --- a/sound/adlib.cpp +++ b/sound/adlib.cpp @@ -23,7 +23,6 @@ #include "scumm.h" #include "fmopl.h" -#if defined USE_ADLIB static byte lookup_table[64][32]; const byte volume_table[] = { @@ -643,7 +642,7 @@ void AdlibSoundDriver::mc_init_stuff(MidiChannelAdl *mc, Struct10 * s10, s11->s10->unk3 = 0; break; default: - s10->start_value = part->_drv->adlib_read_param(mc->_channel, s11->param); + s10->start_value = ((AdlibSoundDriver*)part->_drv)->adlib_read_param(mc->_channel, s11->param); } struct10_init(s10, ie); @@ -661,18 +660,18 @@ void AdlibSoundDriver::mc_inc_stuff(MidiChannelAdl *mc, Struct10 * s10, switch (s11->param) { case 0: mc->_vol_2 = s10->start_value + s11->modify_val; - part->_drv->adlib_set_param(mc->_channel, 0, + ((AdlibSoundDriver*)part->_drv)->adlib_set_param(mc->_channel, 0, volume_table[lookup_table[mc->_vol_2] [part->_vol_eff >> 2]]); break; case 13: mc->_vol_1 = s10->start_value + s11->modify_val; if (mc->_twochan) { - part->_drv->adlib_set_param(mc->_channel, 13, + ((AdlibSoundDriver*)part->_drv)->adlib_set_param(mc->_channel, 13, volume_table[lookup_table[mc->_vol_1] [part->_vol_eff >> 2]]); } else { - part->_drv->adlib_set_param(mc->_channel, 13, mc->_vol_1); + ((AdlibSoundDriver*)part->_drv)->adlib_set_param(mc->_channel, 13, mc->_vol_1); } break; case 30: @@ -682,14 +681,14 @@ void AdlibSoundDriver::mc_inc_stuff(MidiChannelAdl *mc, Struct10 * s10, s11->s10->unk3 = (char)s11->modify_val; break; default: - part->_drv->adlib_set_param(mc->_channel, s11->param, + ((AdlibSoundDriver*)part->_drv)->adlib_set_param(mc->_channel, s11->param, s10->start_value + s11->modify_val); break; } } if (code & 2 && s11->flag0x10) - part->_drv->adlib_key_onoff(mc->_channel); + ((AdlibSoundDriver*)part->_drv)->adlib_key_onoff(mc->_channel); } void AdlibSoundDriver::part_changed(Part *part, byte what) @@ -988,4 +987,3 @@ int AdlibSoundDriver::part_update_active(Part *part, uint16 *active) return count; } -#endif diff --git a/sound/gmidi.cpp b/sound/gmidi.cpp index 9fea3c0472..ecd4e560c1 100644 --- a/sound/gmidi.cpp +++ b/sound/gmidi.cpp @@ -19,393 +19,20 @@ * $Header$ */ -/* - * Timidity support by Lionel Ulmer <lionel.ulmer@free.fr> - * QuickTime support by Florent Boudet <flobo@ifrance.com> - * Raw output support by Michael Pearce - * MorphOS support by Ruediger Hanke - */ - -#ifdef __MORPHOS__ -#include <devices/timer.h> -#endif - - #include "stdafx.h" #include "scumm.h" #include "gmidi.h" -void MidiSoundDriver::midiSetDriver(int devicetype) -{ - _midi_driver.DeviceType = devicetype; - _midi_driver.midiInit(); -} - -void MidiDriver::midiInit() -{ - if (MidiInitialized != true) { - switch (DeviceType) { - case MIDI_NULL: - midiInitNull(); - break; - case MIDI_WINDOWS: - midiInitWindows(); - break; - case MIDI_TIMIDITY: - midiInitTimidity(); - break; - case MIDI_SEQ: - midiInitSeq(); - break; - case MIDI_QTMUSIC: - midiInitQuicktime(); - break; - case MIDI_AMIDI: - break; - default: - DeviceType = 0; - midiInitNull(); - break; - } - MidiInitialized = true; - } else { - error("Midi driver already initialized"); - } -} - -void MidiDriver::MidiOut(int b) -{ - if (MidiInitialized != true) - midiInit(); - - if (MidiInitialized == true) { - switch (DeviceType) { - case MIDI_NULL: - break; - case MIDI_WINDOWS: - MidiOutWindows(_mo, b); - break; - case MIDI_TIMIDITY: - case MIDI_SEQ: - MidiOutSeq(_mo, b); - break; - case MIDI_QTMUSIC: - MidiOutQuicktime(_mo, b); - break; - case MIDI_AMIDI: - MidiOutMorphOS(_mo, b); - break; - default: - error("Invalid midi device type "); - break; - } - } else { - warning("Trying to write midi data without the driver being initialized"); - } -} - -/*********** Windows */ -void MidiDriver::midiInitWindows() +void MidiSoundDriver::midiSetDriver(MidiDriver *driver) { -#ifdef WIN32 - if (midiOutOpen((HMIDIOUT *) & _mo, MIDI_MAPPER, NULL, NULL, 0) != - MMSYSERR_NOERROR) - error("midiOutOpen failed"); -#endif -} + _md = driver; -void MidiDriver::MidiOutWindows(void *a, int b) -{ -#ifdef WIN32 - midiOutShortMsg((HMIDIOUT) a, b); -#endif -} - -/*********** Raw midi support */ -void MidiDriver::midiInitSeq() -{ - int device = open_sequencer_device(); - _mo = (void *)device; + int result = _md->open(MidiDriver::MO_SIMPLE); + if (result) + error("MidiSoundDriver::error = %s", MidiDriver::get_error_name(result)); } -int MidiDriver::open_sequencer_device() -{ - int device = 0; -#if !defined(__APPLE__CW) // No getenv support on Apple Carbon - 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"); - } -#endif - return device; -} - -/*********** Timidity */ -int MidiDriver::connect_to_timidity(int port) -{ - int s = 0; -#if !defined(__APPLE__CW) && !defined(__MORPHOS__) // No socket support on Apple Carbon or Morphos - struct hostent *serverhost; - struct sockaddr_in sadd; - - 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 Timidity socket"); - - if (connect(s, (struct sockaddr *)&sadd, sizeof(struct sockaddr_in)) < 0) - error("Could not connect to Timidity server"); -#endif - return s; -} - -void MidiDriver::midiInitTimidity() -{ - 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); - - 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); - - s2 = connect_to_timidity(newport); - _mo = (void *)s2; -} - -void MidiDriver::MidiOutSeq(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; - } - write(s, buf, position); -} - -/* Quicktime music support */ -void MidiDriver::midiInitQuicktime() -{ -#ifdef __APPLE__CW - 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); -#endif -} - -void MidiDriver::MidiOutQuicktime(void *a, int b) -{ -#ifdef __APPLE__CW - 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; - } -#endif -} - -/*********** MorphOS */ -void MidiDriver::MidiOutMorphOS(void *a, int b) -{ -#ifdef __MORPHOS__ - if (ScummMidiRequest) { - ULONG midi_data = b; // you never know about an int's size ;-) - ScummMidiRequest->amr_Std.io_Command = CMD_WRITE; - ScummMidiRequest->amr_Std.io_Data = &midi_data; - ScummMidiRequest->amr_Std.io_Length = 4; - DoIO((struct IORequest *)ScummMidiRequest); - } -#endif -} - - - - - - - -void MidiDriver::midiInitNull() -{ - warning - ("Music not enabled - MIDI support selected with no MIDI driver available. Try Adlib"); -} - - - -/************************* Common midi code **********************/ +/****************** Common midi code (SCUMM specific) *****************/ void MidiSoundDriver::midiPitchBend(byte chan, int16 pitchbend) { uint16 tmp; @@ -413,8 +40,7 @@ void MidiSoundDriver::midiPitchBend(byte chan, int16 pitchbend) if (_midi_pitchbend_last[chan] != pitchbend) { _midi_pitchbend_last[chan] = pitchbend; tmp = (pitchbend << 2) + 0x2000; - _midi_driver. - MidiOut(((tmp >> 7) & 0x7F) << 16 | (tmp & 0x7F) << 8 | 0xE0 | chan); + _md->send(((tmp >> 7) & 0x7F) << 16 | (tmp & 0x7F) << 8 | 0xE0 | chan); } } @@ -422,14 +48,14 @@ void MidiSoundDriver::midiVolume(byte chan, byte volume) { if (_midi_volume_last[chan] != volume) { _midi_volume_last[chan] = volume; - _midi_driver.MidiOut(volume << 16 | 7 << 8 | 0xB0 | chan); + _md->send(volume << 16 | 7 << 8 | 0xB0 | chan); } } void MidiSoundDriver::midiPedal(byte chan, bool pedal) { if (_midi_pedal_last[chan] != pedal) { _midi_pedal_last[chan] = pedal; - _midi_driver.MidiOut(pedal << 16 | 64 << 8 | 0xB0 | chan); + _md->send(pedal << 16 | 64 << 8 | 0xB0 | chan); } } @@ -437,7 +63,7 @@ void MidiSoundDriver::midiModWheel(byte chan, byte modwheel) { if (_midi_modwheel_last[chan] != modwheel) { _midi_modwheel_last[chan] = modwheel; - _midi_driver.MidiOut(modwheel << 16 | 1 << 8 | 0xB0 | chan); + _md->send(modwheel << 16 | 1 << 8 | 0xB0 | chan); } } @@ -445,7 +71,7 @@ void MidiSoundDriver::midiEffectLevel(byte chan, byte level) { if (_midi_effectlevel_last[chan] != level) { _midi_effectlevel_last[chan] = level; - _midi_driver.MidiOut(level << 16 | 91 << 8 | 0xB0 | chan); + _md->send(level << 16 | 91 << 8 | 0xB0 | chan); } } @@ -453,13 +79,13 @@ void MidiSoundDriver::midiChorus(byte chan, byte chorus) { if (_midi_chorus_last[chan] != chorus) { _midi_chorus_last[chan] = chorus; - _midi_driver.MidiOut(chorus << 16 | 93 << 8 | 0xB0 | chan); + _md->send(chorus << 16 | 93 << 8 | 0xB0 | chan); } } void MidiSoundDriver::midiControl0(byte chan, byte value) { - _midi_driver.MidiOut(value << 16 | 0 << 8 | 0xB0 | chan); + _md->send(value << 16 | 0 << 8 | 0xB0 | chan); } void MidiSoundDriver::midiProgram(byte chan, byte program) @@ -468,7 +94,7 @@ void MidiSoundDriver::midiProgram(byte chan, byte program) if (_se->_mt32emulate) program = mt32_to_gmidi[program]; - _midi_driver.MidiOut(program << 8 | 0xC0 | chan); + _md->send(program << 8 | 0xC0 | chan); } } @@ -476,24 +102,24 @@ void MidiSoundDriver::midiPan(byte chan, int8 pan) { if (_midi_pan_last[chan] != pan) { _midi_pan_last[chan] = pan; - _midi_driver.MidiOut(((pan - 64) & 0x7F) << 16 | 10 << 8 | 0xB0 | chan); + _md->send(((pan - 64) & 0x7F) << 16 | 10 << 8 | 0xB0 | chan); } } void MidiSoundDriver::midiNoteOn(byte chan, byte note, byte velocity) { - _midi_driver.MidiOut(velocity << 16 | note << 8 | 0x90 | chan); + _md->send(velocity << 16 | note << 8 | 0x90 | chan); } void MidiSoundDriver::midiNoteOff(byte chan, byte note) { - _midi_driver.MidiOut(note << 8 | 0x80 | chan); + _md->send(note << 8 | 0x80 | chan); } void MidiSoundDriver::midiSilence(byte chan) { - _midi_driver.MidiOut((64 << 8) | 0xB0 | chan); - _midi_driver.MidiOut((123 << 8) | 0xB0 | chan); + _md->send((64 << 8) | 0xB0 | chan); + _md->send((123 << 8) | 0xB0 | chan); } diff --git a/sound/gmidi.h b/sound/gmidi.h index 9a63151a58..7e9d7e8db5 100644 --- a/sound/gmidi.h +++ b/sound/gmidi.h @@ -6,16 +6,108 @@ #define SPECIAL_CHANNEL 9 #define DEVICE_NUM 0 -/* Sound output type - MIDI */ +struct MidiEvent { + uint32 delta; + uint32 event; +}; + +/* Lowlevel Abstract Midi Driver Class */ +class MidiDriver { + +public: + /* called whenever the midi driver is in streaming mode, + * and more midi commands need to be generated + * return 0 to tell the mididriver that the end of stream was reached + */ + typedef int StreamCallback(void *param, MidiEvent *ev, int num); + + + /* open modes, pass one of those to open() */ + enum { + MO_SIMPLE = 1, + MO_STREAMING = 2, + }; + + /* Special events that can be inserted in a MidiEvent. + * event = (ME_xxx<<24) | <24-bit data associated with event> + */ + enum { + ME_NONE = 0, + ME_TEMPO = 1, + }; + + /* error codes returned by open. + * can be converted to a string with get_error_name() + */ + enum { + MERR_CANNOT_CONNECT = 1, + MERR_STREAMING_NOT_AVAILABLE = 2, + MERR_DEVICE_NOT_AVAILABLE = 3, + MERR_ALREADY_OPEN = 4, + }; + + enum { + PROP_TIMEDIV = 1, + }; + + + /* destroy the midi object */ + virtual void destroy() = 0; + + /* open the midi driver. + * returns 0 if successful. + * otherwise an error code. */ + virtual int open(int mode) = 0; + + /* close the midi driver */ + virtual void close() = 0; + + /* output a packed midi command to the midi stream + * valid only if mode is MO_SIMPLE + */ + virtual void send(uint32 b) = 0; + + /* set callback when more streams need to be generated. + * valid only when mode==MO_STREAMING + */ + virtual void set_stream_callback(void *param, StreamCallback *sc) = 0; + + /* Pause or resume streaming MIDI */ + virtual void pause(bool pause) = 0; + + + /* Get or set a property */ + virtual uint32 property(int prop, uint32 param) = 0; + + /* retrieve a string representation of an error code */ + static const char *get_error_name(int error_code); +}; + + + +/* driver types */ enum { - MIDI_NULL = 0, - MIDI_WINDOWS = 1, - MIDI_TIMIDITY = 2, - MIDI_SEQ = 3, - MIDI_QTMUSIC = 4, - MIDI_AMIDI = 5 + MD_AUTO = 0, + MD_NULL = 1, + MD_WINDOWS = 2, + MD_TIMIDITY = 3, + MD_SEQ = 4, + MD_QTMUSIC = 5, + MD_AMIDI = 6, }; + +/* Factory functions => no need to include the specific classes + * in this header => faster compile */ +MidiDriver *MidiDriver_NULL_create(); +MidiDriver *MidiDriver_WIN_create(); +MidiDriver *MidiDriver_TIMIDITY_create(); +MidiDriver *MidiDriver_SEQ_create(); +MidiDriver *MidiDriver_QT_create(); +MidiDriver *MidiDriver_AMIDI_create(); + + + /* Roland to General Midi patch table. Still needs much work. */ static const byte mt32_to_gmidi[128] = { 0, 1, 2, 4, 4, 5, 5, 3, 16, 17, 18, 18, 19, diff --git a/sound/imuse.cpp b/sound/imuse.cpp index 92e3333aae..b91b8a845c 100644 --- a/sound/imuse.cpp +++ b/sound/imuse.cpp @@ -27,18 +27,6 @@ int num_mix; #define TICKS_PER_BEAT 480 -#ifdef USE_ADLIB -#ifdef _WIN32_WCE -#define TEMPO_BASE 0x1F0000 * 2 // Sampled down to 11 kHz -#else -#define TEMPO_BASE 0x1924E0 -#endif -#define HARDWARE_TYPE 1 -#else -#define TEMPO_BASE 0x400000 -#define HARDWARE_TYPE 5 -#endif - #define SYSEX_ID 0x7D #define SPECIAL_CHANNEL 9 @@ -984,7 +972,9 @@ int SoundEngine::initialize(Scumm *scumm, SoundDriver * driver) scumm->_soundEngine = this; _s = scumm; - _driver = (SOUND_DRIVER_TYPE *) driver; + _driver = driver; + + _hardware_type = driver->get_hardware_type(); _master_volume = 127; if (_music_volume < 1) @@ -1160,7 +1150,7 @@ void Player::set_tempo(uint32 b) uint32 i, j; if (_se->_s->_gameTempo < 1000) - i = TEMPO_BASE; + i = _se->_driver->get_base_tempo(); else i = _se->_s->_gameTempo; @@ -1357,7 +1347,7 @@ void Player::parse_sysex(byte *p, uint len) switch (code = *p++) { case 16: /* set instrument in part */ a = *p++ & 0x0F; - if (HARDWARE_TYPE != *p++) + if (_se->_hardware_type != *p++) break; decode_sysex_bytes(p, buf, len - 3); part = get_part(a); @@ -1367,7 +1357,7 @@ void Player::parse_sysex(byte *p, uint len) case 17: /* set global instrument */ p++; - if (HARDWARE_TYPE != *p++) + if (_se->_hardware_type != *p++) break; a = *p++; decode_sysex_bytes(p, buf, len - 4); @@ -1376,7 +1366,7 @@ void Player::parse_sysex(byte *p, uint len) case 33: /* param adjust */ a = *p++ & 0x0F; - if (HARDWARE_TYPE != *p++) + if (_se->_hardware_type != *p++) break; decode_sysex_bytes(p, buf, len - 3); part = get_part(a); @@ -2400,7 +2390,7 @@ void Part::key_off(byte note) void Part::init(SoundDriver * driver) { - _drv = (SOUND_DRIVER_TYPE *) driver; + _drv = driver; _player = NULL; _next = NULL; _prev = NULL; diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp new file mode 100644 index 0000000000..7a881e7cb1 --- /dev/null +++ b/sound/mididrv.cpp @@ -0,0 +1,689 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + */ + +/* + * Timidity support by Lionel Ulmer <lionel.ulmer@free.fr> + * QuickTime support by Florent Boudet <flobo@ifrance.com> + * Raw output support by Michael Pearce + * MorphOS support by Ruediger Hanke + */ + +#ifdef __MORPHOS__ +#include <devices/timer.h> +#endif + + +#include "stdafx.h" +#include "scumm.h" +#include "gmidi.h" + + +#ifdef WIN32 + +/* Windows MIDI driver */ +class MidiDriver_WIN : public MidiDriver { +public: + void destroy(); + int open(int mode); + void close(); + void send(uint32 b); + void pause(bool pause); + void set_stream_callback(void *param, StreamCallback *sc); + +private: + struct MyMidiHdr { + MIDIHDR hdr; + }; + + enum { + NUM_PREPARED_HEADERS=2, + MIDI_EVENT_SIZE = 64, + BUFFER_SIZE = MIDI_EVENT_SIZE * 12, + }; + + StreamCallback *_stream_proc; + void *_stream_param; + int _mode; + + HMIDIOUT _mo; + HMIDISTRM _ms; + + MyMidiHdr *_prepared_headers; + + uint16 _time_div; + + void unprepare(); + void prepare(); + void check_error(MMRESULT result); + void fill_all(); + uint32 property(int prop, uint32 param); + + static void CALLBACK midi_callback(HMIDIOUT hmo, UINT wMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2); +}; + +void MidiDriver_WIN::set_stream_callback(void *param, StreamCallback *sc) { + _stream_param = param; + _stream_proc = sc; +} + +void MidiDriver_WIN::destroy() { + close(); + delete this; +} + +void CALLBACK MidiDriver_WIN::midi_callback(HMIDIOUT hmo, UINT wMsg, + DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { + + switch(wMsg) { + case MM_MOM_DONE:{ + MidiDriver_WIN *md = ((MidiDriver_WIN*)dwInstance); + if (md->_mode) + md->fill_all(); + break; + } + } +} + +int MidiDriver_WIN::open(int mode) { + if (_mode != 0) + return MERR_ALREADY_OPEN; + + _mode = mode; + + if (mode == MO_SIMPLE) { + MMRESULT res = midiOutOpen((HMIDIOUT *) &_mo, MIDI_MAPPER, NULL, NULL, 0); + if (res != MMSYSERR_NOERROR) + check_error(res); + } else { + /* streaming mode */ + MIDIPROPTIMEDIV mptd; + UINT _midi_device_id = 0; + + check_error(midiStreamOpen(&_ms, &_midi_device_id, 1, + (uint32)midi_callback, (uint32)this, CALLBACK_FUNCTION)); + + prepare(); + + mptd.cbStruct = sizeof(mptd); + mptd.dwTimeDiv = _time_div; + + check_error(midiStreamProperty(_ms, (byte*)&mptd, + MIDIPROP_SET | MIDIPROP_TIMEDIV)); + + fill_all(); + } + + return 0; +} + +void MidiDriver_WIN::fill_all() { + if (_stream_proc == NULL) { + error("MidiDriver_WIN::fill_all() called, but _stream_proc==NULL"); + } + + uint i; + MyMidiHdr *mmh = _prepared_headers; + MidiEvent my_evs[64]; + + for(i=0; i!=NUM_PREPARED_HEADERS; i++,mmh++) { + if (!(mmh->hdr.dwFlags & MHDR_INQUEUE)) { + int num = _stream_proc(_stream_param, my_evs, 64); + int i; + + /* end of stream? */ + if (num == 0) + break; + + MIDIEVENT *ev = (MIDIEVENT*)mmh->hdr.lpData; + MidiEvent *my_ev = my_evs; + + for(i=0; i!=num; i++,my_ev++) { + ev->dwStreamID = 0; + ev->dwDeltaTime = my_ev->delta; + + switch(my_ev->event>>24) { + case 0: + ev->dwEvent = my_ev->event; + break; + case ME_TEMPO: + /* change tempo event */ + ev->dwEvent = (MEVT_TEMPO<<24) | (my_ev->event&0xFFFFFF); + break; + default: + error("Invalid event type passed"); + } + + /* increase stream pointer by 12 bytes + * (need to be 12 bytes, and sizeof(MIDIEVENT) is 16) + */ + ev = (MIDIEVENT*)((byte*)ev + 12); + } + + mmh->hdr.dwBytesRecorded = num * 12; + check_error(midiStreamOut(_ms, &mmh->hdr, sizeof(mmh->hdr))); + } + } +} + +void MidiDriver_WIN::prepare() { + int i; + MyMidiHdr *mmh; + + _prepared_headers = (MyMidiHdr*)calloc(sizeof(MyMidiHdr), 2); + + for(i=0,mmh=_prepared_headers; i!=NUM_PREPARED_HEADERS; i++,mmh++) { + mmh->hdr.dwBufferLength = BUFFER_SIZE; + mmh->hdr.lpData = (LPSTR)calloc(BUFFER_SIZE,1); + + check_error(midiOutPrepareHeader( + (HMIDIOUT)_ms, &mmh->hdr, sizeof(mmh->hdr))); + } +} + +void MidiDriver_WIN::unprepare() { + uint i; + MyMidiHdr *mmh = _prepared_headers; + + for(i=0; i!=NUM_PREPARED_HEADERS; i++,mmh++) { + check_error(midiOutUnprepareHeader( + (HMIDIOUT)_ms, &mmh->hdr, sizeof(mmh->hdr))); + free(mmh->hdr.lpData); + mmh->hdr.lpData = NULL; + } + + free(_prepared_headers); +} + +void MidiDriver_WIN::close() { + int mode_was = _mode; + _mode = 0; + + switch(mode_was) { + case MO_SIMPLE: + check_error(midiOutClose(_mo)); + break; + case MO_STREAMING:; + check_error(midiStreamStop(_ms)); + check_error(midiOutReset((HMIDIOUT)_ms)); + unprepare(); + check_error(midiStreamClose(_ms)); + break; + } +} + +void MidiDriver_WIN::send(uint32 b) { + if (_mode != MO_SIMPLE) + error("MidiDriver_WIN:send called but driver is not in simple mode"); + check_error(midiOutShortMsg(_mo, b)); +} + +void MidiDriver_WIN::pause(bool pause) { + if (_mode == MO_STREAMING) { + if (pause) + check_error(midiStreamPause(_ms)); + else + check_error(midiStreamRestart(_ms)); + } +} + +void MidiDriver_WIN::check_error(MMRESULT result) { + char buf[200]; + if (result != MMSYSERR_NOERROR) { + midiOutGetErrorText(result, buf, 200); + error("MM System Error '%s'", buf); + } +} + +uint32 MidiDriver_WIN::property(int prop, uint32 param) { + switch(prop) { + + /* 16-bit time division according to standard midi specification */ + case PROP_TIMEDIV: + _time_div = (uint16)param; + return 1; + } + + return 0; +} + +MidiDriver *MidiDriver_WIN_create() { + return new MidiDriver_WIN(); +} + +#endif // WIN32 + + +/* NULL driver */ +class MidiDriver_NULL : public MidiDriver { +public: + void destroy(); + int open(int mode); + void close(); + void send(uint32 b); + void pause(bool pause); + void set_stream_callback(void *param, StreamCallback *sc); + uint32 property(int prop, uint32 param); +private: +}; + +int MidiDriver_NULL::open(int mode) { + warning("Music not enabled - MIDI support selected with no MIDI driver available. Try Adlib"); + return 0; +} +void MidiDriver_NULL::close() {} +void MidiDriver_NULL::destroy() {} +void MidiDriver_NULL::send(uint32 b) {} +void MidiDriver_NULL::pause(bool pause) {} +void MidiDriver_NULL::set_stream_callback(void *param, StreamCallback *sc) {} +uint32 MidiDriver_NULL::property(int prop, uint32 param) { return 0; } + +MidiDriver *MidiDriver_NULL_create() { + return new MidiDriver_NULL(); +} + + +/* retrieve a string representation of an error code */ +const char *MidiDriver::get_error_name(int error_code) { + static const char * const midi_errors[] = { + "No error", + "Cannot connect", + "Streaming not available", + "Device not available", + "Driver already open" + }; + + if ((uint)error_code >= ARRAYSIZE(midi_errors)) + return "Unknown Error"; + return midi_errors[error_code]; +} + + + + + + + + +#if 0 + + + + + +void MidiDriver::midiInit() +{ + if (MidiInitialized != true) { + switch (DeviceType) { + case MIDI_NULL: + midiInitNull(); + break; + case MIDI_WINDOWS: + midiInitWindows(); + break; + case MIDI_TIMIDITY: + midiInitTimidity(); + break; + case MIDI_SEQ: + midiInitSeq(); + break; + case MIDI_QTMUSIC: + midiInitQuicktime(); + break; + case MIDI_AMIDI: + break; + default: + DeviceType = 0; + midiInitNull(); + break; + } + MidiInitialized = true; + } else { + error("Midi driver already initialized"); + } +} + +void MidiDriver::MidiOut(int b) +{ + if (MidiInitialized != true) + midiInit(); + + if (MidiInitialized == true) { + switch (DeviceType) { + case MIDI_NULL: + break; + case MIDI_WINDOWS: + MidiOutWindows(_mo, b); + break; + case MIDI_TIMIDITY: + case MIDI_SEQ: + MidiOutSeq(_mo, b); + break; + case MIDI_QTMUSIC: + MidiOutQuicktime(_mo, b); + break; + case MIDI_AMIDI: + MidiOutMorphOS(_mo, b); + break; + default: + error("Invalid midi device type "); + break; + } + } else { + warning("Trying to write midi data without the driver being initialized"); + } +} + +/*********** Windows */ +void MidiDriver::midiInitWindows() +{ +#ifdef WIN32 + if (midiOutOpen((HMIDIOUT *) & _mo, MIDI_MAPPER, NULL, NULL, 0) != + MMSYSERR_NOERROR) + error("midiOutOpen failed"); +#endif +} + +void MidiDriver::MidiOutWindows(void *a, int b) +{ +#ifdef WIN32 + midiOutShortMsg((HMIDIOUT) a, b); +#endif +} + +/*********** Raw midi support */ +void MidiDriver::midiInitSeq() +{ + int device = open_sequencer_device(); + _mo = (void *)device; +} + +int MidiDriver::open_sequencer_device() +{ + int device = 0; +#if !defined(__APPLE__CW) // No getenv support on Apple Carbon + 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"); + } +#endif + return device; +} + +/*********** Timidity */ +int MidiDriver::connect_to_timidity(int port) +{ + int s = 0; +#if !defined(__APPLE__CW) && !defined(__MORPHOS__) // No socket support on Apple Carbon or Morphos + struct hostent *serverhost; + struct sockaddr_in sadd; + + 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 Timidity socket"); + + if (connect(s, (struct sockaddr *)&sadd, sizeof(struct sockaddr_in)) < 0) + error("Could not connect to Timidity server"); +#endif + return s; +} + +void MidiDriver::midiInitTimidity() +{ + 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); + + 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); + + s2 = connect_to_timidity(newport); + _mo = (void *)s2; +} + +void MidiDriver::MidiOutSeq(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; + } + write(s, buf, position); +} + +/* Quicktime music support */ +void MidiDriver::midiInitQuicktime() +{ +#ifdef __APPLE__CW + 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); +#endif +} + +void MidiDriver::MidiOutQuicktime(void *a, int b) +{ +#ifdef __APPLE__CW + 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; + } +#endif +} + +/*********** MorphOS */ +void MidiDriver::MidiOutMorphOS(void *a, int b) +{ +#ifdef __MORPHOS__ + if (ScummMidiRequest) { + ULONG midi_data = b; // you never know about an int's size ;-) + ScummMidiRequest->amr_Std.io_Command = CMD_WRITE; + ScummMidiRequest->amr_Std.io_Data = &midi_data; + ScummMidiRequest->amr_Std.io_Length = 4; + DoIO((struct IORequest *)ScummMidiRequest); + } +#endif +} + + + +void MidiDriver::midiInitNull() +{ + warning + ("Music not enabled - MIDI support selected with no MIDI driver available. Try Adlib"); +} +#endif
\ No newline at end of file @@ -113,3 +113,13 @@ enum { }; +/* Graphics drivers */ +enum { + GD_AUTO = 0, + GD_SDL = 1, + GD_WIN32 = 2, + GD_X = 3, +}; + + + |