aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/kyra/kyra.cpp28
-rw-r--r--engines/kyra/kyra.h4
-rw-r--r--engines/kyra/module.mk1
-rw-r--r--engines/kyra/sound.cpp169
-rw-r--r--engines/kyra/sound.h97
-rw-r--r--engines/kyra/sound_adlib.cpp1908
-rw-r--r--engines/kyra/staticres.cpp24
7 files changed, 2101 insertions, 130 deletions
diff --git a/engines/kyra/kyra.cpp b/engines/kyra/kyra.cpp
index a54bdc0a5b..d9aba16213 100644
--- a/engines/kyra/kyra.cpp
+++ b/engines/kyra/kyra.cpp
@@ -326,19 +326,27 @@ int KyraEngine::init(GameDetector &detector) {
// for now we prefer MIDI-to-Adlib conversion over native midi
int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB/* | MDT_PREFER_MIDI*/);
- bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
- MidiDriver *driver = MidiDriver::createMidi(midiDriver);
if (midiDriver == MD_ADLIB) {
- // In this case we should play the Adlib tracks, but for now
- // the automagic MIDI-to-Adlib conversion will do.
- } else if (native_mt32) {
- driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
- }
+ _sound = new SoundAdlibPC(_mixer, this);
+ assert(_sound);
+ } else {
+ bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
+
+ MidiDriver *driver = MidiDriver::createMidi(midiDriver);
+ assert(driver);
+ if (native_mt32) {
+ driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+ }
- _sound = new SoundPC(driver, _mixer, this);
- assert(_sound);
- static_cast<SoundPC*>(_sound)->hasNativeMT32(native_mt32);
+ SoundMidiPC *soundMidiPc = new SoundMidiPC(driver, _mixer, this);
+ _sound = soundMidiPc;
+ assert(_sound);
+ soundMidiPc->hasNativeMT32(native_mt32);
+ }
+ if (!_sound->init()) {
+ error("Couldn't init sound");
+ }
_sound->setVolume(255);
_saveFileMan = _system->getSavefileManager();
diff --git a/engines/kyra/kyra.h b/engines/kyra/kyra.h
index 9953a61544..d65849348c 100644
--- a/engines/kyra/kyra.h
+++ b/engines/kyra/kyra.h
@@ -938,8 +938,8 @@ protected:
Timer _timers[34];
uint32 _timerNextRun;
- static const char *_xmidiFiles[];
- static const int _xmidiFilesCount;
+ static const char *_musicFiles[];
+ static const int _musicFilesCount;
static const int8 _charXPosTable[];
static const int8 _addXPosTable[];
diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk
index d19e5f13e7..0866413fe8 100644
--- a/engines/kyra/module.mk
+++ b/engines/kyra/module.mk
@@ -8,6 +8,7 @@ MODULE_OBJS := \
script.o \
seqplayer.o \
sound.o \
+ sound_adlib.o \
staticres.o \
sprites.o \
wsamovie.o \
diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp
index 564174306a..d8cb070aed 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -35,8 +35,58 @@
namespace Kyra {
-SoundPC::SoundPC(MidiDriver *driver, Audio::Mixer *mixer, KyraEngine *engine) : Sound() {
- _engine = engine;
+Sound::Sound(KyraEngine *engine, Audio::Mixer *mixer)
+ : _engine(engine), _mixer(mixer), _currentVocFile(0), _vocHandle(), _compressHandle() {
+}
+
+Sound::~Sound() {
+}
+
+void Sound::voicePlay(const char *file) {
+ uint32 fileSize = 0;
+ byte *fileData = 0;
+ bool found = false;
+ char filenamebuffer[25];
+
+ for (int i = 0; _supportedCodes[i].fileext; ++i) {
+ strcpy(filenamebuffer, file);
+ strcat(filenamebuffer, _supportedCodes[i].fileext);
+
+ _engine->resource()->fileHandle(filenamebuffer, &fileSize, _compressHandle);
+ if (!_compressHandle.isOpen())
+ continue;
+
+ _currentVocFile = _supportedCodes[i].streamFunc(&_compressHandle, fileSize);
+ found = true;
+ break;
+ }
+
+ if (!found) {
+ strcpy(filenamebuffer, file);
+ strcat(filenamebuffer, ".VOC");
+
+ fileData = _engine->resource()->fileData(filenamebuffer, &fileSize);
+ if (!fileData)
+ return;
+
+ Common::MemoryReadStream vocStream(fileData, fileSize);
+ _mixer->stopHandle(_vocHandle);
+ _currentVocFile = makeVOCStream(vocStream);
+ }
+
+ if (_currentVocFile)
+ _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_vocHandle, _currentVocFile);
+ delete [] fileData;
+ fileSize = 0;
+}
+
+bool Sound::voiceIsPlaying() {
+ return _mixer->isSoundHandleActive(_vocHandle);
+}
+
+#pragma mark -
+
+SoundMidiPC::SoundMidiPC(MidiDriver *driver, Audio::Mixer *mixer, KyraEngine *engine) : Sound(engine, mixer) {
_driver = driver;
_passThrough = false;
_eventFromMusic = false;
@@ -58,17 +108,14 @@ SoundPC::SoundPC(MidiDriver *driver, Audio::Mixer *mixer, KyraEngine *engine) :
if (ret != MERR_ALREADY_OPEN && ret != 0) {
error("couldn't open midi driver");
}
-
- _currentVocFile = 0;
- _mixer = mixer;
}
-SoundPC::~SoundPC() {
+SoundMidiPC::~SoundMidiPC() {
_driver->setTimerCallback(NULL, NULL);
close();
}
-void SoundPC::setVolume(int volume) {
+void SoundMidiPC::setVolume(int volume) {
if (volume < 0)
volume = 0;
else if (volume > 255)
@@ -89,7 +136,7 @@ void SoundPC::setVolume(int volume) {
}
}
-int SoundPC::open() {
+int SoundMidiPC::open() {
// Don't ever call open without first setting the output driver!
if (!_driver)
return 255;
@@ -102,13 +149,13 @@ int SoundPC::open() {
return 0;
}
-void SoundPC::close() {
+void SoundMidiPC::close() {
if (_driver)
_driver->close();
_driver = 0;
}
-void SoundPC::send(uint32 b) {
+void SoundMidiPC::send(uint32 b) {
if (_passThrough) {
if ((b & 0xFFF0) == 0x007BB0)
return;
@@ -152,7 +199,7 @@ void SoundPC::send(uint32 b) {
_channel[_virChannel[channel]]->send(b);
}
-void SoundPC::metaEvent(byte type, byte *data, uint16 length) {
+void SoundMidiPC::metaEvent(byte type, byte *data, uint16 length) {
switch (type) {
case 0x2F: // End of Track
if (_eventFromMusic) {
@@ -173,19 +220,22 @@ void SoundPC::metaEvent(byte type, byte *data, uint16 length) {
}
}
-void SoundPC::playMusic(const char *file) {
+void SoundMidiPC::playMusic(const char *file) {
+ char filename[25];
+ sprintf(filename, "%s.XMI", file);
+
uint32 size;
- uint8 *data = (_engine->resource())->fileData(file, &size);
+ uint8 *data = (_engine->resource())->fileData(filename, &size);
if (!data) {
- warning("couldn't load '%s'", file);
+ warning("couldn't load '%s'", filename);
return;
}
playMusic(data, size);
}
-void SoundPC::playMusic(uint8 *data, uint32 size) {
+void SoundMidiPC::playMusic(uint8 *data, uint32 size) {
stopMusic();
_parserSource = data;
@@ -205,19 +255,22 @@ void SoundPC::playMusic(uint8 *data, uint32 size) {
_parser->property(MidiParser::mpAutoLoop, false);
}
-void SoundPC::loadSoundEffectFile(const char *file) {
+void SoundMidiPC::loadSoundEffectFile(const char *file) {
+ char filename[25];
+ sprintf(filename, "%s.XMI", file);
+
uint32 size;
- uint8 *data = (_engine->resource())->fileData(file, &size);
+ uint8 *data = (_engine->resource())->fileData(filename, &size);
if (!data) {
- warning("couldn't load '%s'", file);
+ warning("couldn't load '%s'", filename);
return;
}
loadSoundEffectFile(data, size);
}
-void SoundPC::loadSoundEffectFile(uint8 *data, uint32 size) {
+void SoundMidiPC::loadSoundEffectFile(uint8 *data, uint32 size) {
stopSoundEffect();
_soundEffectSource = data;
@@ -237,7 +290,7 @@ void SoundPC::loadSoundEffectFile(uint8 *data, uint32 size) {
_soundEffect->property(MidiParser::mpAutoLoop, false);
}
-void SoundPC::stopMusic() {
+void SoundMidiPC::stopMusic() {
_isLooping = false;
_isPlaying = false;
if (_parser) {
@@ -253,7 +306,7 @@ void SoundPC::stopMusic() {
}
}
-void SoundPC::stopSoundEffect() {
+void SoundMidiPC::stopSoundEffect() {
_sfxIsPlaying = false;
if (_soundEffect) {
_soundEffect->unloadMusic();
@@ -264,8 +317,8 @@ void SoundPC::stopSoundEffect() {
}
}
-void SoundPC::onTimer(void *refCon) {
- SoundPC *music = (SoundPC *)refCon;
+void SoundMidiPC::onTimer(void *refCon) {
+ SoundMidiPC *music = (SoundMidiPC *)refCon;
// this should be set to the fadeToBlack value
static const uint32 musicFadeTime = 2 * 1000;
@@ -307,7 +360,7 @@ void SoundPC::onTimer(void *refCon) {
}
}
-void SoundPC::playTrack(uint8 track, bool loop) {
+void SoundMidiPC::playTrack(uint8 track, bool loop) {
if (_parser) {
_isPlaying = true;
_isLooping = loop;
@@ -318,7 +371,7 @@ void SoundPC::playTrack(uint8 track, bool loop) {
}
}
-void SoundPC::playSoundEffect(uint8 track) {
+void SoundMidiPC::playSoundEffect(uint8 track) {
if (_soundEffect) {
_sfxIsPlaying = true;
_soundEffect->setTrack(track);
@@ -327,70 +380,30 @@ void SoundPC::playSoundEffect(uint8 track) {
}
}
-void SoundPC::beginFadeOut() {
+void SoundMidiPC::beginFadeOut() {
// this should be something like fade out...
_fadeMusicOut = true;
_fadeStartTime = _engine->_system->getMillis();
}
-void SoundPC::voicePlay(const char *file) {
- uint32 fileSize = 0;
- byte *fileData = 0;
- bool found = false;
- char filenamebuffer[25];
-
- for (int i = 0; _supportedCodes[i].fileext; ++i) {
- strcpy(filenamebuffer, file);
- strcat(filenamebuffer, _supportedCodes[i].fileext);
-
- _engine->resource()->fileHandle(filenamebuffer, &fileSize, _compressHandle);
- if (!_compressHandle.isOpen())
- continue;
-
- _currentVocFile = _supportedCodes[i].streamFunc(&_compressHandle, fileSize);
- found = true;
- break;
- }
-
- if (!found) {
- strcpy(filenamebuffer, file);
- strcat(filenamebuffer, ".VOC");
-
- fileData = _engine->resource()->fileData(filenamebuffer, &fileSize);
- if (!fileData)
- return;
-
- Common::MemoryReadStream vocStream(fileData, fileSize);
- _mixer->stopHandle(_vocHandle);
- _currentVocFile = makeVOCStream(vocStream);
- }
-
- if (_currentVocFile)
- _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_vocHandle, _currentVocFile);
- delete [] fileData;
- fileSize = 0;
-}
-
-bool SoundPC::voiceIsPlaying() {
- return _mixer->isSoundHandleActive(_vocHandle);
-}
+#pragma mark -
void KyraEngine::snd_playTheme(int file, int track) {
- debugC(9, kDebugLevelMain, "KyraEngine::snd_playTheme(%d)", file);
- assert(file < _xmidiFilesCount);
+ debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_playTheme(%d)", file);
+ assert(file < _musicFilesCount);
_curMusicTheme = _newMusicTheme = file;
- _sound->playMusic(_xmidiFiles[file]);
+ _sound->playMusic(_musicFiles[file]);
_sound->playTrack(track, false);
}
void KyraEngine::snd_setSoundEffectFile(int file) {
- debugC(9, kDebugLevelMain, "KyraEngine::snd_setSoundEffectFile(%d)", file);
- assert(file < _xmidiFilesCount);
- _sound->loadSoundEffectFile(_xmidiFiles[file]);
+ debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_setSoundEffectFile(%d)", file);
+ assert(file < _musicFilesCount);
+ _sound->loadSoundEffectFile(_musicFiles[file]);
}
void KyraEngine::snd_playSoundEffect(int track) {
- debugC(9, kDebugLevelMain, "KyraEngine::snd_playSoundEffect(%d)", track);
+ debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_playSoundEffect(%d)", track);
if (track == 49) {
snd_playWanderScoreViaMap(56, 1);
} else {
@@ -399,7 +412,7 @@ void KyraEngine::snd_playSoundEffect(int track) {
}
void KyraEngine::snd_playWanderScoreViaMap(int command, int restart) {
- debugC(9, kDebugLevelMain, "KyraEngine::snd_playWanderScoreViaMap(%d, %d)", command, restart);
+ debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_playWanderScoreViaMap(%d, %d)", command, restart);
static const int8 soundTable[] = {
-1, 0, -1, 1, 0, 3, 0, 2,
0, 4, 1, 2, 1, 3, 1, 4,
@@ -441,7 +454,7 @@ void KyraEngine::snd_playWanderScoreViaMap(int command, int restart) {
}
void KyraEngine::snd_playVoiceFile(int id) {
- debugC(9, kDebugLevelMain, "KyraEngine::snd_playVoiceFile(%d)", id);
+ debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_playVoiceFile(%d)", id);
char vocFile[9];
assert(id >= 0 && id < 9999);
sprintf(vocFile, "%03d", id);
@@ -449,7 +462,7 @@ void KyraEngine::snd_playVoiceFile(int id) {
}
void KyraEngine::snd_voiceWaitForFinish(bool ingame) {
- debugC(9, kDebugLevelMain, "KyraEngine::snd_voiceWaitForFinish(%d)", ingame);
+ debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_voiceWaitForFinish(%d)", ingame);
while (_sound->voiceIsPlaying() && !_skipFlag) {
if (ingame) {
delay(10, true);
@@ -461,7 +474,7 @@ void KyraEngine::snd_voiceWaitForFinish(bool ingame) {
// static res
-const SoundPC::SpeechCodecs SoundPC::_supportedCodes[] = {
+const Sound::SpeechCodecs Sound::_supportedCodes[] = {
#ifdef USE_MAD
{ ".VO3", makeMP3Stream },
#endif // USE_MAD
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index f63283d129..21b99d8056 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -41,14 +41,15 @@ namespace Kyra {
class Sound {
public:
- Sound() {}
- virtual ~Sound() {}
+ Sound(KyraEngine *engine, Audio::Mixer *mixer);
+ virtual ~Sound();
+
+ virtual bool init() = 0;
virtual void setVolume(int volume) = 0;
virtual int getVolume() = 0;
virtual void playMusic(const char *file) = 0;
- virtual void playMusic(uint8 *data, uint32 size) = 0;
virtual void stopMusic() = 0;
virtual void playTrack(uint8 track, bool looping = true) = 0;
@@ -56,7 +57,6 @@ public:
virtual void startTrack() = 0;
virtual void loadSoundEffectFile(const char *file) = 0;
- virtual void loadSoundEffectFile(uint8 *data, uint32 size) = 0;
virtual void stopSoundEffect() = 0;
virtual void playSoundEffect(uint8 track) = 0;
@@ -64,16 +64,74 @@ public:
virtual void beginFadeOut() = 0;
virtual bool fadeOut() = 0;
- virtual void voicePlay(const char *file) = 0;
- virtual void voiceUnload() = 0;
- virtual bool voiceIsPlaying() = 0;
+ void voicePlay(const char *file);
+ void voiceUnload() {}
+ bool voiceIsPlaying();
+
+protected:
+ KyraEngine *_engine;
+ Audio::Mixer *_mixer;
+
+private:
+ AudioStream *_currentVocFile;
+ Audio::SoundHandle _vocHandle;
+ Common::File _compressHandle;
+
+ struct SpeechCodecs {
+ const char *fileext;
+ AudioStream *(*streamFunc)(Common::File*, uint32);
+ };
+
+ static const SpeechCodecs _supportedCodes[];
+};
+
+class AdlibDriver;
+
+class SoundAdlibPC : public Sound {
+public:
+ SoundAdlibPC(Audio::Mixer *mixer, KyraEngine *engine);
+ ~SoundAdlibPC();
+
+ bool init();
+
+ void setVolume(int volume);
+ int getVolume();
+
+ void playMusic(const char *file);
+ void stopMusic();
+
+ void playTrack(uint8 track, bool looping);
+ void haltTrack();
+ void startTrack();
+
+ void loadSoundEffectFile(const char *file);
+ void stopSoundEffect();
+
+ void playSoundEffect(uint8 track);
+
+ void beginFadeOut();
+ bool fadeOut();
+private:
+ void loadSoundFile(const char *file);
+
+ AdlibDriver *_driver;
+
+ uint8 _trackEntries[120];
+ uint8 *_soundDataPtr;
+ int _sfxPlayingSound;
+ Common::String _soundFileLoaded;
+
+ uint8 _sfxSecondByteOfSong;
+ uint8 _sfxFourthByteOfSong;
};
-class SoundPC : public MidiDriver, public Sound {
+class SoundMidiPC : public MidiDriver, public Sound {
public:
- SoundPC(MidiDriver *driver, Audio::Mixer *mixer, KyraEngine *engine);
- ~SoundPC();
+ SoundMidiPC(MidiDriver *driver, Audio::Mixer *mixer, KyraEngine *engine);
+ ~SoundMidiPC();
+
+ bool init() { return true; }
void setVolume(int volume);
int getVolume() { return _volume; }
@@ -98,10 +156,6 @@ public:
void beginFadeOut();
bool fadeOut() { return _fadeMusicOut; }
-
- void voicePlay(const char *file);
- void voiceUnload() {};
- bool voiceIsPlaying();
//MidiDriver interface implementation
int open();
@@ -116,7 +170,7 @@ public:
MidiChannel *allocateChannel() { return 0; }
MidiChannel *getPercussionChannel() { return 0; }
-protected:
+private:
static void onTimer(void *data);
@@ -137,19 +191,6 @@ protected:
byte *_parserSource;
MidiParser *_soundEffect;
byte *_soundEffectSource;
- KyraEngine *_engine;
-
- Audio::Mixer *_mixer;
- AudioStream *_currentVocFile;
- Audio::SoundHandle _vocHandle;
- Common::File _compressHandle;
-
- struct SpeechCodecs {
- const char *fileext;
- AudioStream *(*streamFunc)(Common::File*, uint32);
- };
-
- static const SpeechCodecs _supportedCodes[];
};
} // end of namespace Kyra
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
new file mode 100644
index 0000000000..f1171ef16f
--- /dev/null
+++ b/engines/kyra/sound_adlib.cpp
@@ -0,0 +1,1908 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/system.h"
+#include "common/mutex.h"
+#include "common/timer.h"
+#include "kyra/resource.h"
+#include "kyra/sound.h"
+
+#include "sound/mixer.h"
+#include "sound/fmopl.h"
+#include "sound/audiostream.h"
+
+// TODO:
+// - check how the sounds are stopped (doesn't work atm whyever)
+// - implement music pausing + stop and fadeing
+// - check why the sfx sounds strange sometimes
+// - implement stateCallback1_1
+
+namespace Kyra {
+
+class AdlibDriver : public AudioStream {
+public:
+ AdlibDriver(Audio::Mixer *mixer);
+ ~AdlibDriver();
+
+ int callback(int opcode, ...);
+ void callback();
+
+ // AudioStream API
+ int readBuffer(int16 *buffer, const int numSamples) {
+ memset(buffer, 0, sizeof(int16)*numSamples);
+ lock();
+ YM3812UpdateOne(_adlib, buffer, numSamples);
+ unlock();
+ return numSamples;
+ }
+
+ bool isStereo() const { return false; }
+ bool endOfData() const { return false; }
+ int getRate() const { return 22050; }
+
+private:
+ struct OpcodeEntry {
+ typedef int (AdlibDriver::*DriverOpcode)(va_list &list);
+ DriverOpcode function;
+ const char *name;
+ };
+
+ static const OpcodeEntry _opcodeList[];
+ static const int _opcodesEntries;
+
+ int snd_ret0x100(va_list &list);
+ int snd_ret0x1983(va_list &list);
+ int snd_initDriver(va_list &list);
+ int snd_deinitDriver(va_list &list);
+ int snd_setSoundData(va_list &list);
+ int snd_unkOpcode1(va_list &list);
+ int snd_startSong(va_list &list);
+ int snd_unkOpcode2(va_list &list);
+ int snd_unkOpcode3(va_list &list);
+ int snd_readByte(va_list &list);
+ int snd_writeByte(va_list &list);
+ int snd_setUnk5(va_list &list);
+ int snd_unkOpcode4(va_list &list);
+ int snd_dummy(va_list &list);
+ int snd_getNullvar4(va_list &list);
+ int snd_setNullvar3(va_list &list);
+ int snd_setFlag(va_list &list);
+ int snd_clearFlag(va_list &list);
+
+ struct OutputState {
+ uint8 unk27;
+ uint8 *dataptr;
+ uint8 unk5;
+ uint8 unk9;
+ uint8 unk10;
+ int8 unk2;
+ uint8 dataptrStackPos;
+ uint8 *dataptrStack[4];
+ uint8 unk14;
+ uint8 unk29;
+ int8 unk31;
+ uint16 unk30;
+ uint16 unk37;
+ uint8 unk33;
+ uint8 unk34;
+ uint8 unk35;
+ uint8 unk36;
+ uint8 unk32;
+ uint8 unk41;
+ uint8 unk38;
+ uint8 unk26;
+ uint8 unk7;
+ uint8 unk15;
+ int8 unk1;
+ int8 unk4;
+ uint8 unk17;
+ uint8 unkOutputValue1;
+ typedef void (AdlibDriver::*Callback)(OutputState&);
+ Callback callback1;
+ Callback callback2;
+ uint8 unk12;
+ uint8 unk24;
+ uint8 unk25;
+ uint8 unk28;
+ uint8 unk23;
+ uint8 unk39;
+ uint8 unk40;
+ uint8 unk3;
+ uint8 unk11;
+ uint8 unk19;
+ uint8 unk18;
+ uint8 unk20;
+ uint8 unk21;
+ uint8 unk22;
+ uint16 offset;
+ uint8 unk6;
+ uint8 unk13;
+ int8 unk16;
+ };
+
+ void stateCallback1_1(OutputState &state);
+ void stateCallback1_2(OutputState &state);
+ void stateCallback2_1(OutputState& state);
+
+ void resetAdlibState();
+ void output0x388(uint16 word);
+ void waitLoops(int count);
+ void initTable(OutputState &table);
+ void unkOutput1(OutputState &table);
+ void unkOutput2(uint8 num);
+
+ uint16 updateUnk6Value();
+ void update1(uint8 unk1, OutputState &state);
+
+ void updateAndOutput1(uint8 unk1, OutputState &state);
+ void updateAndOutput2(uint8 unk1, uint8 *dataptr, OutputState &state);
+ void updateAndOutput3(OutputState &state);
+
+ void output1(OutputState &state);
+
+ uint8 calculateLowByte1(OutputState &state);
+ uint8 calculateLowByte2(OutputState &state);
+
+ uint16 checkValue(int16 val) {
+ if (val < 0)
+ val = 0;
+ if (val > 0x3F)
+ val = 0x3F;
+ return val;
+ }
+
+ void callbackOutput();
+ void callbackProcess();
+
+ struct ParserOpcode {
+ typedef int (AdlibDriver::*POpcode)(uint8 *&dataptr, OutputState &state, uint8 value);
+ POpcode function;
+ const char *name;
+ };
+ static const ParserOpcode _parserOpcodeTable[];
+ static const int _parserOpcodeTableSize;
+
+ int updateCallback1(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback2(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback3(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback4(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback5(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallbackPushDataPtr(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallbackPopDataPtr(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback8(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback9(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback10(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback11(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback12(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback13(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback14(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback15(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback16(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback17(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback18(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback19(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback20(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback21(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback22(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback23(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback24(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback25(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback26(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback27(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback28(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback29(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback30(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback31(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback32(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback33(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback34(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback35(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback36(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback37(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback38(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback39(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback40(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback41(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback42(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback43(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback44(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback45(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback46(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback47(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback48(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback49(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback50(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback51(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback52(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback53(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback54(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback55(uint8 *&dataptr, OutputState &state, uint8 value);
+ int updateCallback56(uint8 *&dataptr, OutputState &state, uint8 value);
+private:
+ int _lastProcessed;
+ uint8 _flagTrigger;
+ int _curTable;
+ uint8 _unk4;
+ uint8 _unk5;
+ int _soundsPlaying;
+
+ uint16 _unk6;
+ uint8 _continueFlag;
+
+ uint8 _unkValue1;
+ uint8 _unkValue2;
+ uint8 _unkValue3;
+ uint8 _unkValue4;
+ uint8 _unkValue5;
+ uint8 _unkValue6;
+ uint8 _unkValue7;
+ uint8 _unkValue8;
+ uint8 _unkValue9;
+ uint8 _unkValue10;
+ uint8 _unkValue11;
+ uint8 _unkValue12;
+ uint8 _unkValue13;
+ uint8 _unkValue14;
+ uint8 _unkValue15;
+ uint8 _unkValue16;
+ uint8 _unkValue17;
+ uint8 _unkValue18;
+ uint8 _unkValue19;
+ uint8 _unkValue20;
+
+ int _flags;
+ FM_OPL *_adlib;
+
+ uint8 *_soundData;
+
+ uint8 _soundIdTable[0x10];
+ OutputState _outputTables[10];
+
+ uint8 _unkOutputByte2;
+ uint8 _unkOutputByte1;
+ uint8 _unkTableByte1;
+
+ const uint8 *_tablePtr1;
+ const uint8 *_tablePtr2;
+
+ static const uint8 _outputTable[];
+ static const uint16 _unkTable[];
+ static const uint8 *_unkTable2[];
+ static const uint8 _unkTable2_1[];
+ static const uint8 _unkTable2_2[];
+ static const uint8 _unkTable2_3[];
+ static const uint8 _unkTables[][32];
+
+ Common::Mutex _mutex;
+ Audio::Mixer *_mixer;
+
+ void lock() { _mutex.lock(); }
+ void unlock() { _mutex.unlock(); }
+};
+
+void AdlibTimerCall(void *refCon) {
+ AdlibDriver *driver = (AdlibDriver*)refCon;
+ driver->callback();
+}
+
+AdlibDriver::AdlibDriver(Audio::Mixer *mixer) {
+ _mixer = mixer;
+
+ _flags = 0;
+ // TODO: use mixer sample rate
+ _adlib = makeAdlibOPL(22050);
+ assert(_adlib);
+
+ memset(_outputTables, 0, sizeof(_outputTables));
+ _soundData = 0;
+
+ _unkOutputByte2 = _unkOutputByte1 = 0;
+
+ _lastProcessed = _flagTrigger = _curTable = _unk4 = 0;
+ _unk6 = 0x1234;
+ _continueFlag = 0;
+
+ _unkTableByte1 = 0;
+
+ _unkValue3 = 0xFF;
+ _unkValue1 = _unkValue2 = _unkValue4 = _unkValue5 = 0;
+ _unkValue6 = _unkValue7 = _unkValue8 = _unkValue9 = _unkValue10 = 0;
+ _unkValue11 = _unkValue12 = _unkValue13 = _unkValue14 = _unkValue15 =
+ _unkValue16 = _unkValue17 = _unkValue18 = _unkValue19 = _unkValue20 = 0;
+
+ _tablePtr1 = _tablePtr2 = 0;
+
+ _mixer->setupPremix(this);
+
+ // the interval should be around 13000 to 20000
+ Common::g_timer->installTimerProc(&AdlibTimerCall, 15000, this);
+}
+
+AdlibDriver::~AdlibDriver() {
+ Common::g_timer->removeTimerProc(&AdlibTimerCall);
+ _mixer->setupPremix(0);
+ OPLDestroy(_adlib);
+ _adlib = 0;
+}
+
+int AdlibDriver::callback(int opcode, ...) {
+ lock();
+ if (opcode >= _opcodesEntries || opcode < 0) {
+ warning("AdlibDriver: calling unknown opcode '%d'", opcode);
+ return 0;
+ }
+
+ debugC(9, kDebugLevelSound, "Calling opcode '%s' (%d)", _opcodeList[opcode].name, opcode);
+
+ va_list args;
+ va_start(args, opcode);
+ int returnValue = (this->*(_opcodeList[opcode].function))(args);
+ va_end(args);
+ unlock();
+ return returnValue;
+}
+
+// Opcodes
+
+int AdlibDriver::snd_ret0x100(va_list &list) {
+ return 0x100;
+}
+
+int AdlibDriver::snd_ret0x1983(va_list &list) {
+ return 0x1983;
+}
+
+int AdlibDriver::snd_initDriver(va_list &list) {
+ _lastProcessed = _soundsPlaying = 0;
+ resetAdlibState();
+ return 0;
+}
+
+int AdlibDriver::snd_deinitDriver(va_list &list) {
+ resetAdlibState();
+ return 0;
+}
+
+int AdlibDriver::snd_setSoundData(va_list &list) {
+ if (_soundData) {
+ delete [] _soundData;
+ _soundData = 0;
+ }
+ _soundData = va_arg(list, uint8*);
+ return 0;
+}
+
+int AdlibDriver::snd_unkOpcode1(va_list &list) {
+ warning("unimplemented snd_unkOpcode1");
+ return 0;
+}
+
+int AdlibDriver::snd_startSong(va_list &list) {
+ int songId = va_arg(list, int);
+ _flags |= 8;
+ uint16 offset = READ_LE_UINT16(&_soundData[songId << 1]);
+ uint8 firstByte = *(_soundData + offset);
+
+ if ((songId << 1) != 0) {
+ if (firstByte == 9) {
+ if (_flags & 2)
+ return 0;
+ } else {
+ if (_flags & 1)
+ return 0;
+ }
+ }
+
+ _soundIdTable[_soundsPlaying] = songId;
+ ++_soundsPlaying;
+ _soundsPlaying &= 0x0F;
+
+ return 0;
+}
+
+int AdlibDriver::snd_unkOpcode2(va_list &list) {
+ warning("unimplemented snd_unkOpcode2");
+ return 0;
+}
+
+int AdlibDriver::snd_unkOpcode3(va_list &list) {
+ int value = va_arg(list, int);
+ int loop = value;
+ if (value < 0) {
+ value = 0;
+ loop = 9;
+ }
+ loop -= value;
+ ++loop;
+
+ while (loop--) {
+ _curTable = value;
+ OutputState &table = _outputTables[_curTable];
+ table.unk2 = 0;
+ table.dataptr = 0;
+ if (value != 9) {
+ unkOutput1(table);
+ }
+ ++value;
+ }
+
+ return 0;
+}
+
+int AdlibDriver::snd_readByte(va_list &list) {
+ uint8 *ptr = _soundData + READ_LE_UINT16(&_soundData[va_arg(list, int) << 1]) + va_arg(list, int);
+ return *ptr;
+}
+
+int AdlibDriver::snd_writeByte(va_list &list) {
+ uint8 *ptr = _soundData + READ_LE_UINT16(&_soundData[va_arg(list, int) << 1]) + va_arg(list, int);
+ uint8 oldValue = *ptr;
+ *ptr = (uint8)va_arg(list, int);
+ return oldValue;
+}
+
+int AdlibDriver::snd_setUnk5(va_list &list) {
+ warning("unimplemented snd_setUnk5");
+ return 0;
+}
+
+int AdlibDriver::snd_unkOpcode4(va_list &list) {
+ warning("unimplemented snd_unkOpcode4");
+ return 0;
+}
+
+int AdlibDriver::snd_dummy(va_list &list) {
+ return 0;
+}
+
+int AdlibDriver::snd_getNullvar4(va_list &list) {
+ warning("unimplemented snd_getNullvar4");
+ return 0;
+}
+
+int AdlibDriver::snd_setNullvar3(va_list &list) {
+ warning("unimplemented snd_setNullvar3");
+ return 0;
+}
+
+int AdlibDriver::snd_setFlag(va_list &list) {
+ int oldFlags = _flags;
+ _flags |= va_arg(list, int);
+ return oldFlags;
+}
+
+int AdlibDriver::snd_clearFlag(va_list &list) {
+ int oldFlags = _flags;
+ _flags &= ~(va_arg(list, int));
+ return oldFlags;
+}
+
+// timer callback
+
+void AdlibDriver::callback() {
+ lock();
+ //--_flagTrigger;
+ //if ((int8)_flagTrigger < 0)
+ _flags &= 0xFFF7;
+ callbackOutput();
+ callbackProcess();
+
+ _unkValue3 += _unkTableByte1;
+ if ((int8)_unkValue3 < 0) {
+ if (!(--_unkValue2)) {
+ _unkValue2 = _unkValue1;
+ ++_unkValue4;
+ }
+ }
+ unlock();
+}
+
+void AdlibDriver::callbackOutput() {
+ while (_lastProcessed != _soundsPlaying) {
+ uint8 *ptr = _soundData;
+
+ ptr += READ_LE_UINT16(&ptr[_soundIdTable[_lastProcessed] << 1]);
+ uint8 index = *ptr++; // set nullvar
+
+ OutputState &table = _outputTables[index];
+
+ int8 unk2 = *ptr++;
+ if (unk2 >= table.unk2) {
+ initTable(table);
+ table.unk2 = unk2;
+ table.dataptr = ptr;
+ table.unk1 = -1;
+ table.unk4 = -1;
+ table.unk5 = 1;
+ if (index != 9) {
+ unkOutput2(index);
+ }
+ }
+
+ ++_lastProcessed;
+ _lastProcessed &= 0x0F;
+ }
+}
+
+void AdlibDriver::callbackProcess() {
+ _curTable = 9;
+ for (_curTable = 9; _curTable >= 0; --_curTable) {
+ if (!_outputTables[_curTable].dataptr) {
+ continue;
+ }
+
+ OutputState &table = _outputTables[_curTable];
+ _unkOutputByte1 = _outputTable[_curTable];
+
+ if (table.unk6) {
+ table.unk1 = _unkTableByte1;
+ }
+
+ table.unk4 += table.unk1;
+ if (table.unk4 < 0) {
+ if (--table.unk5) {
+ if (table.unk5 == table.unk7)
+ unkOutput1(table);
+ if (table.unk5 == table.unk3 && _curTable != 9)
+ unkOutput1(table);
+ } else {
+ int8 opcode = 0;
+ while (1 && table.dataptr) {
+ uint16 command = READ_LE_UINT16(table.dataptr);
+ table.dataptr += 2;
+ if (command & 0x0080) {
+ opcode = command & 0x7F;
+ if (opcode > 0x4A)
+ opcode = 0x4A;
+ //debug("'%s' (%d) (%d)", _parserOpcodeTable[opcode].name, opcode, _curTable);
+ opcode = (this->*(_parserOpcodeTable[opcode].function))(table.dataptr, table, (command & 0xFF00) >> 8);
+ --opcode;
+ if (opcode >= 0)
+ break;
+ continue;
+ } else {
+ opcode = 0;
+ updateAndOutput1(command & 0xFF, table);
+ updateAndOutput3(table);
+ update1((command & 0xFF00) >> 8, table);
+ if (!_continueFlag)
+ continue;
+ break;
+ }
+ }
+ if (opcode)
+ continue;
+ }
+ }
+
+ if (table.callback1)
+ (this->*(table.callback1))(table);
+ if (table.callback2)
+ (this->*(table.callback2))(table);
+ }
+}
+
+//
+
+void AdlibDriver::resetAdlibState() {
+ _unk6 = 0x1234;
+ output0x388(0x120);
+ output0x388(0x800);
+ output0x388(0xBD00);
+ int loop = 10;
+ while (loop--) {
+ if (loop != 9) {
+ output0x388(((_outputTable[loop] + 0x40) << 8) | 0x3F);
+ output0x388(((_outputTable[loop] + 0x43) << 8) | 0x3F);
+ }
+ initTable(_outputTables[loop]);
+ }
+}
+
+void AdlibDriver::output0x388(uint16 word) {
+ OPLWrite(_adlib, 0x388, (word >> 8) & 0xFF);
+ waitLoops(4);
+ OPLWrite(_adlib, 0x389, word & 0xFF);
+ waitLoops(23);
+}
+
+void AdlibDriver::waitLoops(int count) {
+ while (count--) {
+ OPLRead(_adlib, 0x388);
+ }
+}
+
+void AdlibDriver::initTable(OutputState &table) {
+ uint8 unk27BackUp = table.unk27;
+
+ memset(&table, 0, sizeof(OutputState));
+
+ table.unk27 = unk27BackUp;
+
+ table.unk1 = -1;
+ table.unk2 = 0;
+ // normally here are nullfuncs but we set 0 for now
+ table.callback1 = 0;
+ table.callback2 = 0;
+ table.unk3 = 0x01;
+}
+
+void AdlibDriver::unkOutput1(OutputState &table) {
+ if (_curTable == 9)
+ return;
+ if (_unk4 && _curTable >= 6)
+ return;
+ uint16 output = (_curTable + 0xB0) << 8;
+ table.unkOutputValue1 &= 0xDF;
+ output |= table.unkOutputValue1;
+ output0x388(output);
+}
+
+void AdlibDriver::unkOutput2(uint8 num) {
+ if (_unk4)
+ if (num >= 6)
+ return;
+
+ uint8 value = _outputTable[num];
+ output0x388(((value + 0x60) << 8) | 0xFF);
+ output0x388(((value + 0x63) << 8) | 0xFF);
+ output0x388(((value + 0x80) << 8) | 0xFF);
+ output0x388(((value + 0x83) << 8) | 0xFF);
+
+ output0x388(((num + 0xB0) << 8) | 0x00);
+ output0x388(((num + 0xB0) << 8) | 0x20);
+}
+
+uint16 AdlibDriver::updateUnk6Value() {
+ _unk6 += 0x9248;
+ uint16 lowBits = _unk6 & 7;
+ _unk6 >>= 3;
+ _unk6 |= lowBits << 12;
+ return _unk6;
+}
+
+void AdlibDriver::update1(uint8 unk1, OutputState &state) {
+ _continueFlag = unk1;
+ if (state.unk11) {
+ state.unk5 = (updateUnk6Value() & 0xFF) + (unk1 & state.unk11);
+ return;
+ }
+ uint8 value = unk1;
+ if (state.unk12) {
+ uint8 value2 = value;
+ uint8 add = value >> 3;
+ int loops = state.unk12;
+ while (loops--) {
+ value2 += add;
+ }
+ state.unk7 = value2;
+ }
+ state.unk5 = value;
+}
+
+void AdlibDriver::updateAndOutput1(uint8 unk1, OutputState &state) {
+ state.unk13 = unk1;
+ uint8 unk2 = unk1 & 0xF0;
+ unk2 += state.unk10;
+ unk1 &= 0x0F;
+ unk1 += state.unk14;
+
+ if ((int8)unk1 >= 0x0C) {
+ unk1 -= 0x0C;
+ unk2 += 0x10;
+ } else if ((int8)unk1 < 0) {
+ unk1 += 0x0C;
+ unk2 -= 0x10;
+ }
+
+ uint16 value = _unkTable[unk1] + state.unk15;
+
+ unk2 >>= 2;
+ unk2 &= 0x1C;
+ unk2 |= (value & 0xFF00) >> 8;
+ value = (value & 0xFF) | (unk2 << 8);
+
+ if (state.unk16 != 0) {
+ if (state.unk16 >= 0) {
+ const uint8 *table = _unkTables[(state.unk13 & 0x0F) + 2];
+ value += table[state.unk16];
+ } else {
+ const uint8 *table = _unkTables[state.unk13 & 0x0F];
+ value -= table[(state.unk16 ^ 0xFF) + 1];
+ }
+ }
+
+ state.unkOutputValue1 = (state.unkOutputValue1 & 0x20) | ((value & 0xFF00) >> 8);
+ state.unk17 = value & 0xFF;
+
+ output0x388(((0xA0 + _curTable) << 8) | state.unk17);
+ output0x388(((0xB0 + _curTable) << 8) | state.unkOutputValue1);
+}
+
+void AdlibDriver::updateAndOutput2(uint8 unk1, uint8 *dataptr, OutputState &state) {
+ output0x388(((0x20 + unk1) << 8) | *dataptr++);
+ output0x388(((0x23 + unk1) << 8) | *dataptr++);
+
+ uint8 temp = *dataptr++;
+ output0x388(((0xC0 + _curTable) << 8) | temp);
+ state.unk23 = temp & 1;
+
+ output0x388(((0xE0 + unk1) << 8) | *dataptr++);
+ output0x388(((0xE3 + unk1) << 8) | *dataptr++);
+
+ state.unk24 = *dataptr++;
+ output0x388(((0x40 + unk1) << 8) | calculateLowByte1(state));
+
+ state.unk25 = *dataptr++;
+ output0x388(((0x43 + unk1) << 8) | calculateLowByte2(state));
+
+ output0x388(((0x60 + unk1) << 8) | *dataptr++);
+ output0x388(((0x63 + unk1) << 8) | *dataptr++);
+
+ output0x388(((0x80 + unk1) << 8) | *dataptr++);
+ output0x388(((0x83 + unk1) << 8) | *dataptr++);
+}
+
+void AdlibDriver::updateAndOutput3(OutputState &state) {
+ state.unkOutputValue1 |= 0x20;
+ output0x388(((0xB0 + _curTable) << 8) | state.unkOutputValue1);
+ int8 shift = 9 - state.unk33;
+ uint16 temp = state.unk17 | (state.unkOutputValue1 << 8);
+ state.unk37 = ((temp & 0x3FF) >> shift) & 0xFF;
+ state.unk38 = state.unk36;
+}
+
+void AdlibDriver::output1(OutputState &state) {
+ uint8 lowByte = calculateLowByte2(state);
+ output0x388(((0x43 + _outputTable[_curTable]) << 8) | lowByte);
+ if (state.unk23) {
+ lowByte = calculateLowByte1(state);
+ output0x388(((0x40 + _outputTable[_curTable]) << 8) | lowByte);
+ }
+}
+
+void AdlibDriver::stateCallback1_1(OutputState &state) {
+ state.unk31 += state.unk29;
+ if ((int8)state.unk31 < 0)
+ return;
+ warning("stateCallback1_1 unimplemented");
+}
+
+void AdlibDriver::stateCallback1_2(OutputState &state) {
+ if (state.unk38) {
+ --state.unk38;
+ return;
+ }
+
+ state.unk41 += state.unk32;
+ if ((int8)state.unk41 < 0) {
+ uint16 temp2 = state.unk37;
+ if (!(--state.unk34)) {
+ temp2 ^= 0xFFFF;
+ ++temp2;
+ state.unk37 = temp2;
+ state.unk34 = state.unk35;
+ }
+
+ uint16 temp3 = state.unk17 | (state.unkOutputValue1 << 8);
+ temp2 += temp3 & 0x3FF;
+ state.unk17 = temp2 & 0xFF;
+
+ state.unkOutputValue1 = (state.unkOutputValue1 & 0xFC) | (temp3 >> 8);
+
+ output0x388(((0xA0 + _curTable) << 8) | state.unkOutputValue1);
+ output0x388(((0xB0 + _curTable) << 8) | state.unkOutputValue1);
+ }
+}
+
+void AdlibDriver::stateCallback2_1(OutputState &state) {
+ state.unk18 += state.unk19;
+ if ((int8)state.unk18 < 0) {
+ if ((--state.unk21) & 0x80) {
+ state.unk21 = state.unk20;
+ }
+ uint16 value = (state.unk22 + _unkOutputByte1) << 8;
+ value |= (_soundData/*state.dataptr:segment*/ + state.offset)[state.unk21];
+ output0x388(value);
+ }
+}
+
+uint8 AdlibDriver::calculateLowByte1(OutputState &state) {
+ int8 value = state.unk24 & 0x3F;
+ if (state.unk23) {
+ value += state.unk26;
+ value += state.unk27;
+ value += state.unk28;
+ }
+
+ if (value > 0x3F) {
+ if (value < 0)
+ value = 0;
+ else
+ value = 0x3F;
+ }
+
+ return value | (state.unk24 & 0xC0);
+}
+
+uint8 AdlibDriver::calculateLowByte2(OutputState &state) {
+ int8 value = state.unk25 & 0x3F;
+ value += state.unk26;
+ value += state.unk27;
+ value += state.unk28;
+
+ if (value > 0x3F) {
+ if (value < 0)
+ value = 0;
+ else
+ value = 0x3F;
+ }
+
+ return value | (state.unk25 & 0xC0);
+}
+
+// parser opcodes
+
+int AdlibDriver::updateCallback1(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk9 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback2(uint8 *&dataptr, OutputState &state, uint8 value) {
+ ++dataptr;
+ if (--state.unk9) {
+ --dataptr;
+ --dataptr;
+ uint16 add = READ_LE_UINT16(dataptr);
+ dataptr += 2;
+ dataptr += add;
+ }
+ return 0;
+}
+
+int AdlibDriver::updateCallback3(uint8 *&dataptr, OutputState &state, uint8 value) {
+ if (value >= 0xFF)
+ return 0;
+
+ uint16 add = value << 1;
+ uint8 *ptr = _soundData + READ_LE_UINT16(_soundData + add);
+ uint8 table = *ptr++;
+ OutputState &state2 = _outputTables[table];
+ int8 temp = *((int8*)ptr); ++ptr;
+ if (temp >= (int8)state2.unk2) {
+ _flagTrigger = 1;
+ _flags |= 8;
+ initTable(state2);
+ state2.unk2 = temp;
+ state2.dataptr = ptr;
+ state2.unk1 = -1;
+ state2.unk4 = -1;
+ state2.unk5 = 1;
+ unkOutput2(table);
+ }
+ return 0;
+}
+
+int AdlibDriver::updateCallback4(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk3 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback5(uint8 *&dataptr, OutputState &state, uint8 value) {
+ --dataptr;
+ uint16 add = READ_LE_UINT16(dataptr); dataptr += 2;
+ dataptr += add;
+ return 0;
+}
+
+int AdlibDriver::updateCallbackPushDataPtr(uint8 *&dataptr, OutputState &state, uint8 value) {
+ --dataptr;
+ uint16 add = READ_LE_UINT16(dataptr); dataptr += 2;
+ state.dataptrStack[state.dataptrStackPos++] = dataptr;
+ dataptr += add;
+ return 0;
+}
+
+int AdlibDriver::updateCallbackPopDataPtr(uint8 *&dataptr, OutputState &state, uint8 value) {
+ dataptr = state.dataptrStack[--state.dataptrStackPos];
+ return 0;
+}
+
+int AdlibDriver::updateCallback8(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk10 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback9(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk2 = 0;
+ if (_curTable != 9) {
+ unkOutput1(state);
+ }
+ dataptr = 0;
+ return 2;
+}
+
+int AdlibDriver::updateCallback10(uint8 *&dataptr, OutputState &state, uint8 value) {
+ update1(value, state);
+ unkOutput1(state);
+ return (_continueFlag != 0);
+}
+
+int AdlibDriver::updateCallback11(uint8 *&dataptr, OutputState &state, uint8 value) {
+ output0x388(*dataptr++);
+ return 0;
+}
+
+int AdlibDriver::updateCallback12(uint8 *&dataptr, OutputState &state, uint8 value) {
+ updateAndOutput1(value, state);
+ value = *dataptr++;
+ update1(value, state);
+ return (_continueFlag != 0);
+}
+
+int AdlibDriver::updateCallback13(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk14 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback14(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk18 = value;
+ state.unk19 = value;
+ state.unk20 = state.unk21 = *dataptr++;
+ state.unk22 = *dataptr++;
+ state.offset = READ_LE_UINT16(dataptr); dataptr += 2;
+ state.callback2 = &AdlibDriver::stateCallback2_1;
+ return 0;
+}
+
+int AdlibDriver::updateCallback15(uint8 *&dataptr, OutputState &state, uint8 value) {
+ OutputState &state2 = _outputTables[_curTable];
+ state2.unk5 = 0;
+ state2.unk2 = 0;
+ state2.dataptr = 0;
+ return 0;
+}
+
+int AdlibDriver::updateCallback16(uint8 *&dataptr, OutputState &state, uint8 value) {
+ uint8 *ptr = _soundData;
+ ptr += READ_LE_UINT16(&_soundData[value << 1]);
+ OutputState &state2 = _outputTables[*ptr];
+ if (!state2.dataptr) {
+ return 0;
+ }
+ dataptr -= 2;
+ return 2;
+}
+
+int AdlibDriver::updateCallback17(uint8 *&dataptr, OutputState &state, uint8 value) {
+ uint8 *ptr = _soundData;
+ ptr += READ_LE_UINT16(_soundData + value * 2 + 0x1F4);
+ updateAndOutput2(_unkOutputByte1, ptr, state);
+ return 0;
+}
+
+int AdlibDriver::updateCallback18(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk29 = value;
+ state.unk30 = READ_BE_UINT16(dataptr); dataptr += 2;
+ state.callback1 = &AdlibDriver::stateCallback1_1;
+ state.unk31 = -1;
+ return 0;
+}
+
+int AdlibDriver::updateCallback19(uint8 *&dataptr, OutputState &state, uint8 value) {
+ --dataptr;
+ state.callback1 = 0;
+ state.unk30 = 0;
+ return 0;
+}
+
+int AdlibDriver::updateCallback20(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk15 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback21(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk32 = value;
+ state.unk33 = *dataptr++;
+ uint8 temp = *dataptr++;
+ state.unk34 = temp + 1;
+ state.unk35 = temp << 1;
+ state.unk36 = *dataptr++;
+ state.callback1 = &AdlibDriver::stateCallback1_2;
+ return 0;
+}
+
+int AdlibDriver::updateCallback22(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk2 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback23(uint8 *&dataptr, OutputState &state, uint8 value) {
+ value >>= 1;
+ _unkValue1 = _unkValue2 = value;
+ _unkValue3 = 0xFF;
+ _unkValue4 = _unkValue5 = 0;
+ return 0;
+}
+
+int AdlibDriver::updateCallback24(uint8 *&dataptr, OutputState &state, uint8 value) {
+ if (_unkValue5) {
+ if (_unkValue4 & value) {
+ _unkValue5 = 0;
+ return 0;
+ }
+ }
+
+ if (!(value & _unkValue4)) {
+ ++_unkValue5;
+ }
+
+ dataptr -= 2;
+ state.unk5 = 1;
+ return 2;
+}
+
+int AdlibDriver::updateCallback25(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk26 = value;
+ output1(state);
+ return 0;
+}
+
+int AdlibDriver::updateCallback26(uint8 *&dataptr, OutputState &state, uint8 value) {
+ update1(value, state);
+ return (_continueFlag != 0);
+}
+
+int AdlibDriver::updateCallback27(uint8 *&dataptr, OutputState &state, uint8 value) {
+ update1(value, state);
+ updateAndOutput3(state);
+ return (_continueFlag != 0);
+}
+
+int AdlibDriver::updateCallback28(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk12 = value & 7;
+ return 0;
+}
+
+int AdlibDriver::updateCallback29(uint8 *&dataptr, OutputState &state, uint8 value) {
+ _unkTableByte1 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback30(uint8 *&dataptr, OutputState &state, uint8 value) {
+ --dataptr;
+ state.callback2 = 0;
+ return 0;
+}
+
+int AdlibDriver::updateCallback31(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk1 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback32(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk28 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback33(uint8 *&dataptr, OutputState &state, uint8 value) {
+ int tableBackup = _curTable;
+
+ _curTable = value;
+ OutputState &state2 = _outputTables[value];
+ state2.unk27 = *dataptr++;
+ output1(state2);
+
+ _curTable = tableBackup;
+ return 0;
+}
+
+int AdlibDriver::updateCallback34(uint8 *&dataptr, OutputState &state, uint8 value) {
+ int tableBackup = _curTable;
+
+ _curTable = value;
+ OutputState &state2 = _outputTables[value];
+ state2.unk27 += *dataptr++;
+ output1(state2);
+
+ _curTable = tableBackup;
+ return 0;
+}
+
+int AdlibDriver::updateCallback35(uint8 *&dataptr, OutputState &state, uint8 value) {
+ value &= 1;
+ value <<= 7;
+ _unkOutputByte2 = (_unkOutputByte2 & 0x7F) | value;
+ output0x388(0xBD00 | _unkOutputByte2);
+ return 0;
+}
+
+int AdlibDriver::updateCallback36(uint8 *&dataptr, OutputState &state, uint8 value) {
+ value &= 1;
+ value <<= 6;
+ _unkOutputByte2 = (_unkOutputByte2 & 0xBF) | value;
+ output0x388(0xBD00 | _unkOutputByte2);
+ return 0;
+}
+
+int AdlibDriver::updateCallback37(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk26 += value;
+ output1(state);
+ return 0;
+}
+
+int AdlibDriver::updateCallback38(uint8 *&dataptr, OutputState &state, uint8 value) {
+ int tableBackUp = _curTable;
+
+ _curTable = value;
+ OutputState &state2 = _outputTables[value];
+ state2.unk5 = state2.unk2 = 0;
+ state2.dataptr = 0;
+ state2.unk27 = 0;
+
+ if (value != 9) {
+ uint8 outValue = _outputTable[value];
+ output0x388((0xC0 + _curTable) << 8);
+ output0x388(((0x43 + outValue) << 8) | 0x3F);
+ output0x388(((0x83 + outValue) << 8) | 0xFF);
+ output0x388((0xB0 + _curTable) << 8);
+ }
+
+ _curTable = tableBackUp;
+ return 0;
+}
+
+int AdlibDriver::updateCallback39(uint8 *&dataptr, OutputState &state, uint8 value) {
+ uint16 unk = *dataptr++;
+ unk |= value << 8;
+ unk &= updateUnk6Value();
+
+ uint16 unk2 = ((state.unkOutputValue1 & 0x1F) << 8) | state.unk17;
+ unk2 += unk;
+ unk2 |= ((state.unkOutputValue1 & 0x20) << 8);
+
+ output0x388(((0xA0 + _curTable) << 8) | (unk2 & 0xFF));
+ output0x388(((0xB0 + _curTable) << 8) | ((unk2 & 0xFF00) >> 8));
+
+ return 0;
+}
+
+int AdlibDriver::updateCallback40(uint8 *&dataptr, OutputState &state, uint8 value) {
+ --dataptr;
+ state.callback1 = 0;
+ return 0;
+}
+
+int AdlibDriver::updateCallback41(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk16 = value;
+ int8 unk1 = 0, unk2 = 0;
+
+ unk1 = state.unk13 & 0xF0;
+ unk1 += state.unk10;
+
+ unk2 = state.unk13 & 0x0F;
+ unk2 += state.unk14;
+
+ if (unk2 >= 12) {
+ unk2 -= 12;
+ unk1 += 16;
+ } else if (unk2 < 0) {
+ unk2 += 12;
+ unk1 -= 16;
+ }
+
+ uint16 unk3 = _unkTable[unk2] + state.unk15;
+ unk1 >>= 1; unk1 &= 0x1C;
+ unk2 |= (unk3 >> 8);
+
+ uint16 unk4 = (unk2 << 8) | (unk3 & 0xFF);
+ if (state.unk16 >= 0) {
+ const uint8 *ptr = _unkTables[(state.unk13 & 0x0F) + 2];
+ unk4 += ptr[state.unk16];
+ } else {
+ const uint8 *ptr = _unkTables[state.unk13 & 0x0F];
+ unk4 += ptr[(state.unk16 ^ 0xFF) + 1];
+ }
+
+ unk2 = unk4 >> 8;
+ unk1 = unk4 & 0xFF;
+
+ state.unkOutputValue1 = unk2 | (state.unkOutputValue1 & 0x20);
+ state.unk17 = unk1;
+
+ output0x388(((0xA0 + _curTable) << 8) | unk1);
+ output0x388(((0xB0 + _curTable) << 8) | state.unkOutputValue1);
+
+ return 0;
+}
+
+int AdlibDriver::updateCallback42(uint8 *&dataptr, OutputState &state, uint8 value) {
+ --dataptr;
+ state.unk1 = _unkTableByte1;
+ return 0;
+}
+
+int AdlibDriver::updateCallback43(uint8 *&dataptr, OutputState &state, uint8 value) {
+ --dataptr;
+ return 0;
+}
+
+int AdlibDriver::updateCallback44(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk11 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback45(uint8 *&dataptr, OutputState &state, uint8 value) {
+ if (value & 0x80) {
+ value += state.unk1;
+ if ((int8)value >= (int8)state.unk1)
+ value = 1;
+ } else {
+ value += state.unk1;
+ if ((int8)value < 0)
+ value = (uint8)-1;
+ }
+ state.unk1 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback46(uint8 *&dataptr, OutputState &state, uint8 value) {
+ uint8 entry = *dataptr++;
+ _tablePtr1 = _unkTable2[entry++];
+ _tablePtr2 = _unkTable2[entry];
+ if (value == 2) {
+ output0x388(0xA000 | _tablePtr2[0]);
+ }
+ return 0;
+}
+
+int AdlibDriver::updateCallback47(uint8 *&dataptr, OutputState &state, uint8 value) {
+ --dataptr;
+ return 0;
+}
+
+int AdlibDriver::updateCallback48(uint8 *&dataptr, OutputState &state, uint8 value) {
+ int tableBackUp = _curTable;
+ int outputByteBackUp = _unkOutputByte1;
+
+ uint8 entry = value * 2;
+
+ uint8 *ptr = _soundData;
+ _curTable = 6;
+ _unkOutputByte1 = _outputTable[6];
+
+ ptr += READ_LE_UINT16(_soundData + entry + 0x1F4);
+
+ _unkValue6 = *(ptr + 6);
+ updateAndOutput2(_unkOutputByte1, ptr, state);
+
+ entry = *ptr++ * 2;
+
+ ptr = _soundData;
+ _curTable = 7;
+ _unkOutputByte1 = _outputTable[7];
+
+ _unkValue7 = entry = *(ptr + 5);
+ _unkValue8 = entry = *(ptr + 6);
+ updateAndOutput2(_unkOutputByte1, ptr, state);
+
+ entry = *ptr++ * 2;
+
+ ptr = _soundData;
+ _curTable = 8;
+ _unkOutputByte1 = _outputTable[8];
+
+ _unkValue9 = entry = *(ptr + 5);
+ _unkValue10 = entry = *(ptr + 6);
+ updateAndOutput2(_unkOutputByte1, ptr, state);
+
+ _outputTables[6].unkOutputValue1 = *ptr++ & 0x2F;
+ output0x388(0xB600 | _outputTables[6].unkOutputValue1);
+ output0x388(0xA600 | *ptr++);
+
+ _outputTables[7].unkOutputValue1 = *ptr++ & 0x2F;
+ output0x388(0xB700 | _outputTables[7].unkOutputValue1);
+ output0x388(0xA700 | *ptr++);
+
+ _outputTables[8].unkOutputValue1 = *ptr++ & 0x2F;
+ output0x388(0xB800 | _outputTables[8].unkOutputValue1);
+ output0x388(0xA800 | *ptr++);
+
+ _unk4 = 0x20;
+
+ _unkOutputByte1 = outputByteBackUp;
+ _curTable = tableBackUp;
+ return 0;
+}
+
+int AdlibDriver::updateCallback49(uint8 *&dataptr, OutputState &state, uint8 value) {
+ OPLWrite(_adlib, 0x388, (value << 8) | 0xBD);
+ waitLoops(4);
+
+ OPLWrite(_adlib, 0x389, 0xBD00 | (((value & 0x1F) ^ 0xFF) & _unk4) | 0x20);
+ waitLoops(23);
+
+ value |= _unk4;
+ _unk4 = value;
+
+ value |= _unkOutputByte2;
+ value |= 0x20;
+ OPLWrite(_adlib, 0x389, 0xBD00 | value);
+ waitLoops(23);
+
+ return 0;
+}
+
+int AdlibDriver::updateCallback50(uint8 *&dataptr, OutputState &state, uint8 value) {
+ --dataptr;
+ _unk4 = 0;
+ output0x388(0xBD00 | (value & _unkOutputByte2));
+ return 0;
+}
+
+int AdlibDriver::updateCallback51(uint8 *&dataptr, OutputState &state, uint8 value) {
+ uint16 temp = (value << 8) | *dataptr++;
+
+ if (value & 1) {
+ uint8 val = temp & 0xFF;
+ _unkValue12 = val;
+ val += _unkValue7;
+ val += _unkValue11;
+ val += _unkValue12;
+ output0x388(0x5100 | checkValue(val));
+ }
+
+ if (value & 2) {
+ uint8 val = temp & 0xFF;
+ _unkValue14 = val;
+ val += _unkValue10;
+ val += _unkValue13;
+ val += _unkValue14;
+ output0x388(0x5500 | checkValue(val));
+ }
+
+ if (value & 4) {
+ uint8 val = temp & 0xFF;
+ _unkValue15 = val;
+ val += _unkValue9;
+ val += _unkValue16;
+ val += _unkValue15;
+ output0x388(0x5200 | checkValue(val));
+ }
+
+ if (value & 8) {
+ uint8 val = temp & 0xFF;
+ _unkValue18 = val;
+ val += _unkValue8;
+ val += _unkValue17;
+ val += _unkValue18;
+ output0x388(0x5400 | checkValue(val));
+ }
+
+ if (value & 16) {
+ uint8 val = temp & 0xFF;
+ _unkValue20 = val;
+ val += _unkValue6;
+ val += _unkValue19;
+ val += _unkValue20;
+ output0x388(0x5300 | checkValue(val));
+ }
+
+ return 0;
+}
+
+int AdlibDriver::updateCallback52(uint8 *&dataptr, OutputState &state, uint8 value) {
+ uint16 temp = (value << 8) | *dataptr++;
+
+ if (value & 1) {
+ uint8 val = temp & 0xFF;
+ val += _unkValue7;
+ val += _unkValue11;
+ val += _unkValue12;
+ output0x388(0x5100 | checkValue(val));
+ }
+
+ if (value & 2) {
+ uint8 val = temp & 0xFF;
+ val += _unkValue10;
+ val += _unkValue13;
+ val += _unkValue14;
+ output0x388(0x5500 | checkValue(val));
+ }
+
+ if (value & 4) {
+ uint8 val = temp & 0xFF;
+ val += _unkValue9;
+ val += _unkValue16;
+ val += _unkValue15;
+ output0x388(0x5200 | checkValue(val));
+ }
+
+ if (value & 8) {
+ uint8 val = temp & 0xFF;
+ val += _unkValue8;
+ val += _unkValue17;
+ val += _unkValue18;
+ output0x388(0x5400 | checkValue(val));
+ }
+
+ if (value & 16) {
+ uint8 val = temp & 0xFF;
+ val += _unkValue6;
+ val += _unkValue19;
+ val += _unkValue20;
+ output0x388(0x5300 | checkValue(val));
+ }
+
+ return 0;
+}
+
+int AdlibDriver::updateCallback53(uint8 *&dataptr, OutputState &state, uint8 value) {
+ uint16 temp = (value << 8) | *dataptr++;
+
+ if (value & 1) {
+ uint8 val = temp & 0xFF;
+ _unkValue11 = val;
+ val += _unkValue7;
+ val += _unkValue12;
+ output0x388(0x5100 | checkValue(val));
+ }
+
+ if (value & 2) {
+ uint8 val = temp & 0xFF;
+ _unkValue13 = val;
+ val += _unkValue10;
+ val += _unkValue14;
+ output0x388(0x5500 | checkValue(val));
+ }
+
+ if (value & 4) {
+ uint8 val = temp & 0xFF;
+ _unkValue16 = val;
+ val += _unkValue9;
+ val += _unkValue15;
+ output0x388(0x5200 | checkValue(val));
+ }
+
+ if (value & 8) {
+ uint8 val = temp & 0xFF;
+ _unkValue17 = val;
+ val += _unkValue8;
+ val += _unkValue18;
+ output0x388(0x5400 | checkValue(val));
+ }
+
+ if (value & 16) {
+ uint8 val = temp & 0xFF;
+ _unkValue19 = val;
+ val += _unkValue6;
+ val += _unkValue20;
+ output0x388(0x5300 | checkValue(val));
+ }
+
+ return 0;
+}
+
+int AdlibDriver::updateCallback54(uint8 *&dataptr, OutputState &state, uint8 value) {
+ _unk5 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback55(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk6 = value;
+ return 0;
+}
+
+int AdlibDriver::updateCallback56(uint8 *&dataptr, OutputState &state, uint8 value) {
+ state.unk39 = value;
+ state.unk40 = *dataptr++;
+ return 0;
+}
+
+// static res
+
+#define COMMAND(x) { &AdlibDriver::x, #x }
+const AdlibDriver::OpcodeEntry AdlibDriver::_opcodeList[] = {
+ COMMAND(snd_ret0x100),
+ COMMAND(snd_ret0x1983),
+ COMMAND(snd_initDriver),
+ COMMAND(snd_deinitDriver),
+ COMMAND(snd_setSoundData),
+ COMMAND(snd_unkOpcode1),
+ COMMAND(snd_startSong),
+ COMMAND(snd_unkOpcode2),
+ COMMAND(snd_unkOpcode3),
+ COMMAND(snd_readByte),
+ COMMAND(snd_writeByte),
+ COMMAND(snd_setUnk5),
+ COMMAND(snd_unkOpcode4),
+ COMMAND(snd_dummy),
+ COMMAND(snd_getNullvar4),
+ COMMAND(snd_setNullvar3),
+ COMMAND(snd_setFlag),
+ COMMAND(snd_clearFlag)
+};
+
+const AdlibDriver::ParserOpcode AdlibDriver::_parserOpcodeTable[] = {
+ COMMAND(updateCallback1),
+ COMMAND(updateCallback2),
+ COMMAND(updateCallback3),
+ COMMAND(updateCallback4),
+ COMMAND(updateCallback5),
+ COMMAND(updateCallbackPushDataPtr),
+ COMMAND(updateCallbackPopDataPtr),
+ COMMAND(updateCallback8),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback10),
+ COMMAND(updateCallback11),
+ COMMAND(updateCallback12),
+ COMMAND(updateCallback13),
+ COMMAND(updateCallback14),
+ COMMAND(updateCallback15),
+ COMMAND(updateCallback16),
+ COMMAND(updateCallback17),
+ COMMAND(updateCallback18),
+ COMMAND(updateCallback19),
+ COMMAND(updateCallback20),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback21),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback22),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback23),
+ COMMAND(updateCallback24),
+ COMMAND(updateCallback25),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback26),
+ COMMAND(updateCallback27),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback28),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback29),
+ COMMAND(updateCallback30),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback31),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback32),
+ COMMAND(updateCallback33),
+ COMMAND(updateCallback34),
+ COMMAND(updateCallback35),
+ COMMAND(updateCallback36),
+ COMMAND(updateCallback37),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback38),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback39),
+ COMMAND(updateCallback40),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback41),
+ COMMAND(updateCallback42),
+ COMMAND(updateCallback43),
+ COMMAND(updateCallback44),
+ COMMAND(updateCallback45),
+ COMMAND(updateCallback9),
+ COMMAND(updateCallback46),
+ COMMAND(updateCallback47),
+ COMMAND(updateCallback48),
+ COMMAND(updateCallback49),
+ COMMAND(updateCallback50),
+ COMMAND(updateCallback51),
+ COMMAND(updateCallback52),
+ COMMAND(updateCallback53),
+ COMMAND(updateCallback54),
+ COMMAND(updateCallback55),
+ COMMAND(updateCallback56),
+ COMMAND(updateCallback9)
+};
+#undef COMMAND
+
+const int AdlibDriver::_opcodesEntries = ARRAYSIZE(AdlibDriver::_opcodeList);
+const int AdlibDriver::_parserOpcodeTableSize = ARRAYSIZE(AdlibDriver::_parserOpcodeTable);
+
+const uint8 AdlibDriver::_outputTable[] = {
+ 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11,
+ 0x12
+};
+
+const uint16 AdlibDriver::_unkTable[] = {
+ 0x0134, 0x0147, 0x015A, 0x016F, 0x0184, 0x019C, 0x01B4, 0x01CE, 0x01E9,
+ 0x0207, 0x0225, 0x0246
+};
+
+const uint8 *AdlibDriver::_unkTable2[] = {
+ AdlibDriver::_unkTable2_1,
+ AdlibDriver::_unkTable2_2,
+ AdlibDriver::_unkTable2_1,
+ AdlibDriver::_unkTable2_2,
+ AdlibDriver::_unkTable2_3,
+ AdlibDriver::_unkTable2_2
+};
+
+const uint8 AdlibDriver::_unkTable2_1[] = {
+ 0x50, 0x50, 0x4F, 0x4F, 0x4E, 0x4E, 0x4D, 0x4D,
+ 0x4C, 0x4C, 0x4B, 0x4B, 0x4A, 0x4A, 0x49, 0x49,
+ 0x48, 0x48, 0x47, 0x47, 0x46, 0x46, 0x45, 0x45,
+ 0x44, 0x44, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41,
+ 0x40, 0x40, 0x3F, 0x3F, 0x3E, 0x3E, 0x3D, 0x3D,
+ 0x3C, 0x3C, 0x3B, 0x3B, 0x3A, 0x3A, 0x39, 0x39,
+ 0x38, 0x38, 0x37, 0x37, 0x36, 0x36, 0x35, 0x35,
+ 0x34, 0x34, 0x33, 0x33, 0x32, 0x32, 0x31, 0x31,
+ 0x30, 0x30, 0x2F, 0x2F, 0x2E, 0x2E, 0x2D, 0x2D,
+ 0x2C, 0x2C, 0x2B, 0x2B, 0x2A, 0x2A, 0x29, 0x29,
+ 0x28, 0x28, 0x27, 0x27, 0x26, 0x26, 0x25, 0x25,
+ 0x24, 0x24, 0x23, 0x23, 0x22, 0x22, 0x21, 0x21,
+ 0x20, 0x20, 0x1F, 0x1F, 0x1E, 0x1E, 0x1D, 0x1D,
+ 0x1C, 0x1C, 0x1B, 0x1B, 0x1A, 0x1A, 0x19, 0x19,
+ 0x18, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15,
+ 0x14, 0x14, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11,
+ 0x10, 0x10
+};
+
+// no don't ask me WHY this table exsits!
+const uint8 AdlibDriver::_unkTable2_2[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x6F,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F
+};
+
+const uint8 AdlibDriver::_unkTable2_3[] = {
+ 0x40, 0x40, 0x40, 0x3F, 0x3F, 0x3F, 0x3E, 0x3E,
+ 0x3E, 0x3D, 0x3D, 0x3D, 0x3C, 0x3C, 0x3C, 0x3B,
+ 0x3B, 0x3B, 0x3A, 0x3A, 0x3A, 0x39, 0x39, 0x39,
+ 0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, 0x36,
+ 0x36, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x33,
+ 0x33, 0x33, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31,
+ 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2E, 0x2E,
+ 0x2E, 0x2D, 0x2D, 0x2D, 0x2C, 0x2C, 0x2C, 0x2B,
+ 0x2B, 0x2B, 0x2A, 0x2A, 0x2A, 0x29, 0x29, 0x29,
+ 0x28, 0x28, 0x28, 0x27, 0x27, 0x27, 0x26, 0x26,
+ 0x26, 0x25, 0x25, 0x25, 0x24, 0x24, 0x24, 0x23,
+ 0x23, 0x23, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21,
+ 0x20, 0x20, 0x20, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E,
+ 0x1E, 0x1D, 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1B,
+ 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x19,
+ 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x16, 0x16,
+ 0x16, 0x15
+};
+
+// TODO: format this
+const uint8 AdlibDriver::_unkTables[][32] = {
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x19,
+ 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21 },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x09,
+ 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11,
+ 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x1A,
+ 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x22, 0x24 },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x09,
+ 0x0A, 0x0C, 0x0D, 0x0E, 0x0F, 0x11, 0x12, 0x13,
+ 0x14, 0x15, 0x16, 0x17, 0x19, 0x1A, 0x1C, 0x1D,
+ 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26 },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x0A,
+ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x11, 0x12, 0x13,
+ 0x14, 0x15, 0x16, 0x17, 0x18, 0x1A, 0x1C, 0x1D,
+ 0x1E, 0x1F, 0x20, 0x21, 0x23, 0x25, 0x27, 0x28 },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x0A,
+ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x11, 0x13, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1B, 0x1D, 0x1F, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x28, 0x2A },
+ { 0x00, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1B, 0x1D, 0x1F, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x28, 0x2A },
+ { 0x00, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1B, 0x1D, 0x1F, 0x20,
+ 0x21, 0x22, 0x23, 0x25, 0x27, 0x29, 0x2B, 0x2D },
+ { 0x00, 0x01, 0x02, 0x03, 0x05, 0x07, 0x09, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x15,
+ 0x16, 0x17, 0x18, 0x1A, 0x1C, 0x1E, 0x21, 0x24,
+ 0x25, 0x26, 0x27, 0x29, 0x2B, 0x2D, 0x2F, 0x30 },
+ { 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x15, 0x18,
+ 0x19, 0x1A, 0x1C, 0x1D, 0x1F, 0x21, 0x23, 0x25,
+ 0x26, 0x27, 0x29, 0x2B, 0x2D, 0x2F, 0x30, 0x32 },
+ { 0x00, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x14, 0x17, 0x1A,
+ 0x19, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x25, 0x28,
+ 0x29, 0x2A, 0x2B, 0x2D, 0x2F, 0x31, 0x33, 0x35 },
+ { 0x00, 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0E,
+ 0x0F, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1B,
+ 0x1C, 0x1D, 0x1E, 0x20, 0x22, 0x24, 0x26, 0x29,
+ 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x39 },
+ { 0x00, 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0E,
+ 0x0F, 0x10, 0x12, 0x14, 0x16, 0x19, 0x1B, 0x1E,
+ 0x1F, 0x21, 0x23, 0x25, 0x27, 0x29, 0x2B, 0x2D,
+ 0x2E, 0x2F, 0x31, 0x32, 0x34, 0x36, 0x39, 0x3C },
+ { 0x00, 0x01, 0x03, 0x05, 0x07, 0x0A, 0x0C, 0x0F,
+ 0x10, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1E,
+ 0x1F, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2B, 0x2E,
+ 0x2F, 0x30, 0x32, 0x34, 0x36, 0x39, 0x3C, 0x3F },
+ { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0B, 0x0D, 0x10,
+ 0x11, 0x12, 0x14, 0x16, 0x18, 0x1B, 0x1E, 0x21,
+ 0x22, 0x23, 0x25, 0x27, 0x29, 0x2C, 0x2F, 0x32,
+ 0x33, 0x34, 0x36, 0x38, 0x3B, 0x34, 0x41, 0x44 },
+ { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0B, 0x0D, 0x11,
+ 0x12, 0x13, 0x15, 0x17, 0x1A, 0x1D, 0x20, 0x23,
+ 0x24, 0x25, 0x27, 0x29, 0x2C, 0x2F, 0x32, 0x35,
+ 0x36, 0x37, 0x39, 0x3B, 0x3E, 0x41, 0x44, 0x47 }
+};
+
+#pragma mark -
+
+SoundAdlibPC::SoundAdlibPC(Audio::Mixer *mixer, KyraEngine *engine)
+ : Sound(engine, mixer), _driver(0), _trackEntries(), _soundDataPtr(0) {
+ memset(_trackEntries, 0, sizeof(_trackEntries));
+ _driver = new AdlibDriver(mixer);
+ assert(_driver);
+
+ _sfxPlayingSound = -1;
+ _soundFileLoaded = "";
+}
+
+SoundAdlibPC::~SoundAdlibPC() {
+ delete [] _soundDataPtr;
+ delete _driver;
+}
+
+bool SoundAdlibPC::init() {
+ _driver->callback(2);
+ _driver->callback(16, int(4));
+ return true;
+}
+
+void SoundAdlibPC::setVolume(int volume) {
+}
+
+int SoundAdlibPC::getVolume() {
+ return 0;
+}
+
+void SoundAdlibPC::playMusic(const char *file) {
+ loadSoundFile(file);
+}
+
+void SoundAdlibPC::stopMusic() {
+ playSoundEffect(0);
+}
+
+void SoundAdlibPC::playTrack(uint8 track, bool looping) {
+ // snd_stopSound();
+ // snd_unk1();
+ playSoundEffect(track);
+}
+
+void SoundAdlibPC::haltTrack() {
+}
+
+void SoundAdlibPC::startTrack() {
+}
+
+void SoundAdlibPC::loadSoundEffectFile(const char *file) {
+ loadSoundFile(file);
+}
+
+void SoundAdlibPC::stopSoundEffect() {
+}
+
+void SoundAdlibPC::playSoundEffect(uint8 track) {
+ uint8 soundId = _trackEntries[track];
+ if ((int8)soundId == -1 || !_soundDataPtr)
+ return;
+ soundId &= 0xFF;
+ while ((_driver->callback(16, 0) & 8)) {
+ _engine->delay(10);
+ }
+ if (_sfxPlayingSound != -1) {
+ _driver->callback(10, _sfxPlayingSound, int(1), int(_sfxSecondByteOfSong));
+ _driver->callback(10, _sfxPlayingSound, int(3), int(_sfxFourthByteOfSong));
+ _sfxPlayingSound = -1;
+ }
+
+ int firstByteOfSong = _driver->callback(9, soundId, int(0));
+
+ if (firstByteOfSong != 9) {
+ _sfxPlayingSound = soundId;
+ _sfxSecondByteOfSong = _driver->callback(9, soundId, int(1));
+ _sfxFourthByteOfSong = _driver->callback(9, soundId, int(3));
+
+ int newVal = ((((-_sfxFourthByteOfSong) + 63) * 0xFF) >> 8) & 0xFF;
+ newVal = -newVal + 63;
+ _driver->callback(10, soundId, int(3), newVal);
+ newVal = ((_sfxSecondByteOfSong * 0xFF) >> 8) & 0xFF;
+ _driver->callback(10, soundId, int(1), newVal);
+ }
+
+ _driver->callback(6, soundId);
+}
+
+void SoundAdlibPC::beginFadeOut() {
+}
+
+bool SoundAdlibPC::fadeOut() {
+ return false;
+}
+
+void SoundAdlibPC::loadSoundFile(const char *file) {
+ if (_soundFileLoaded == file)
+ return;
+
+ uint8 *file_data = 0; uint32 file_size = 0;
+
+ char filename[25];
+ sprintf(filename, "%s.ADL", file);
+
+ file_data = _engine->resource()->fileData(filename, &file_size);
+ if (!file_data) {
+ warning("Couldn't find music file: '%s'", filename);
+ return;
+ }
+
+ // snd_stopSound();
+ // snd_unk1();
+
+ _driver->callback(8, int(-1));
+ _soundDataPtr = 0;
+
+ uint8 *p = file_data;
+ memcpy(_trackEntries, p, 120*sizeof(uint8));
+ p += 120;
+
+ int soundDataSize = file_size - 120;
+
+ _soundDataPtr = new uint8[soundDataSize];
+ assert(_soundDataPtr);
+
+ memcpy(_soundDataPtr, p, soundDataSize*sizeof(uint8));
+
+ delete [] file_data;
+ file_data = p = 0;
+ file_size = 0;
+
+ _driver->callback(4, _soundDataPtr);
+
+ _soundFileLoaded = file;
+}
+
+} // end of namespace Kyra
+
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 90cb5350aa..a6d1e7920b 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -814,20 +814,20 @@ KyraEngine::OpcodeProc KyraEngine::_opcodeTable[] = {
const int KyraEngine::_opcodeTableSize = ARRAYSIZE(_opcodeTable);
-const char *KyraEngine::_xmidiFiles[] = {
- "INTRO.XMI",
- "KYRA1A.XMI",
- "KYRA1B.XMI",
- "KYRA2A.XMI",
- "KYRA3A.XMI",
- "KYRA4A.XMI",
- "KYRA4B.XMI",
- "KYRA5A.XMI",
- "KYRA5B.XMI",
- "KYRAMISC.XMI"
+const char *KyraEngine::_musicFiles[] = {
+ "INTRO",
+ "KYRA1A",
+ "KYRA1B",
+ "KYRA2A",
+ "KYRA3A",
+ "KYRA4A",
+ "KYRA4B",
+ "KYRA5A",
+ "KYRA5B",
+ "KYRAMISC"
};
-const int KyraEngine::_xmidiFilesCount = ARRAYSIZE(_xmidiFiles);
+const int KyraEngine::_musicFilesCount = ARRAYSIZE(_musicFiles);
const int8 KyraEngine::_charXPosTable[] = {
0, 4, 4, 4, 0, -4, -4, -4