aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudvig Strigeus2002-04-13 18:34:11 +0000
committerLudvig Strigeus2002-04-13 18:34:11 +0000
commit9f191ea9c5882f59cd23adbcbaa4a1c704909573 (patch)
treef2ddc0e916248a56c82418b8346569bafd6e915a
parent38628f3543cf16d23968f541e4a35c95c2e17f13 (diff)
downloadscummvm-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.cpp114
-rw-r--r--gameDetector.h9
-rw-r--r--main.cpp10
-rw-r--r--resource.cpp16
-rw-r--r--scumm.h6
-rw-r--r--scummvm.cpp20
-rw-r--r--scummvm.dsp14
-rw-r--r--sdl.cpp32
-rw-r--r--simon/midi.cpp392
-rw-r--r--simon/simon.cpp5
-rw-r--r--simon/simon.h43
-rw-r--r--sound.cpp2
-rw-r--r--sound.h52
-rw-r--r--sound/adlib.cpp14
-rw-r--r--sound/gmidi.cpp412
-rw-r--r--sound/gmidi.h106
-rw-r--r--sound/imuse.cpp26
-rw-r--r--sound/mididrv.cpp689
-rw-r--r--system.h10
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();
};
diff --git a/main.cpp b/main.cpp
index 54320aac08..aafcf2f666 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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) {
diff --git a/scumm.h b/scumm.h
index 2268fb41c3..9debfb5763 100644
--- a/scumm.h
+++ b/scumm.h
@@ -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
diff --git a/sdl.cpp b/sdl.cpp
index a77042d27c..0b1e28a351 100644
--- a/sdl.cpp
+++ b/sdl.cpp
@@ -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);
diff --git a/sound.cpp b/sound.cpp
index 75aa4a187e..22c14dbad2 100644
--- a/sound.cpp
+++ b/sound.cpp
@@ -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();
}
diff --git a/sound.h b/sound.h
index bdcd850559..2d4ba7b7e8 100644
--- a/sound.h
+++ b/sound.h
@@ -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
diff --git a/system.h b/system.h
index 07a234b768..b2afb8eb19 100644
--- a/system.h
+++ b/system.h
@@ -113,3 +113,13 @@ enum {
};
+/* Graphics drivers */
+enum {
+ GD_AUTO = 0,
+ GD_SDL = 1,
+ GD_WIN32 = 2,
+ GD_X = 3,
+};
+
+
+