diff options
Diffstat (limited to 'engines/cine')
-rw-r--r-- | engines/cine/cine.cpp | 19 | ||||
-rw-r--r-- | engines/cine/main_loop.cpp | 13 | ||||
-rw-r--r-- | engines/cine/resource.cpp | 94 | ||||
-rw-r--r-- | engines/cine/resource.h | 10 | ||||
-rw-r--r-- | engines/cine/script.cpp | 31 | ||||
-rw-r--r-- | engines/cine/sfx_player.cpp | 318 | ||||
-rw-r--r-- | engines/cine/sfx_player.h | 65 | ||||
-rw-r--r-- | engines/cine/sound_driver.cpp | 667 | ||||
-rw-r--r-- | engines/cine/sound_driver.h | 151 | ||||
-rw-r--r-- | engines/cine/various.cpp | 6 |
10 files changed, 744 insertions, 630 deletions
diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index 8ec2a86c96..426ccc4a18 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -46,8 +46,8 @@ namespace Cine { -Audio::Mixer * cine_g_mixer; -AdlibMusic *g_cine_adlib; +SoundDriver *g_soundDriver; +SfxPlayer *g_sfxPlayer; static void initialize(); @@ -131,7 +131,6 @@ CineEngine::CineEngine(GameDetector *detector, OSystem *syst) : Engine(syst) { warning("Sound initialization failed."); } - cine_g_mixer = _mixer; _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); @@ -163,7 +162,12 @@ int CineEngine::init(GameDetector &detector) { _system->initSize(320, 200); _system->endGFXTransaction(); - g_cine_adlib = new AdlibMusic(_mixer); + if (gameType == GID_FW) { + g_soundDriver = new AdlibSoundDriverINS(_mixer); + } else { + g_soundDriver = new AdlibSoundDriverADL(_mixer); + } + g_sfxPlayer = new SfxPlayer(g_soundDriver); initialize(); @@ -178,8 +182,8 @@ int CineEngine::go() { if (gameType == Cine::GID_FW) snd_clearBasesonEntries(); - delete g_cine_adlib; - + delete g_soundDriver; + delete g_sfxPlayer; return 0; } @@ -196,7 +200,8 @@ static void initialize() { partBuffer = (PartBuffer *)malloc(255 * sizeof(PartBuffer)); loadTextData("texte.dat", textDataPtr); - snd_loadBasesonEntries("BASESON.SND"); + if (gameType == Cine::GID_FW) + snd_loadBasesonEntries("BASESON.SND"); for (i = 0; i < NUM_MAX_OBJECT; i++) { objectTable[i].part = 0; diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index ef7d186a20..5197ea5362 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -28,6 +28,7 @@ #include "cine/main_loop.h" #include "cine/object.h" +#include "cine/sfx_player.h" #include "cine/various.h" namespace Cine { @@ -142,17 +143,15 @@ void mainLoop(int bootScriptIdx) { strcpy(currentCtName, ""); strcpy(currentPartName, ""); - stopSample(); + g_sfxPlayer->stop(); do { mainLoopSub3(); di = executePlayerInput(); - if (var18 != 0) { - if (var18 >= 100 || var19) { - stopSample(); - } - } +// if (g_sfxPlayer->_fadeOutCounter != 0 && g_sfxPlayer->_fadeOutCounter < 100) { +// g_sfxPlayer->stop(); +// } processSeqList(); executeList1(); @@ -232,7 +231,7 @@ void mainLoop(int bootScriptIdx) { } while (!exitEngine && !quitFlag && var21 != 7); hideMouse(); - stopSample(); + g_sfxPlayer->stop(); closeEngine3(); unloadAllMasks(); freePrcLinkedList(); diff --git a/engines/cine/resource.cpp b/engines/cine/resource.cpp index dbed696a29..c2835fc7e9 100644 --- a/engines/cine/resource.cpp +++ b/engines/cine/resource.cpp @@ -22,11 +22,105 @@ * */ +#include "common/file.h" + +#include "cine/cine.h" #include "cine/resource.h" +#include "cine/unpack.h" +#include "cine/various.h" namespace Cine { void checkDataDisk(int16 param) { } +/* FW specific */ +static Common::File *snd_baseSndFile = NULL; +static uint16 snd_numBasesonEntries = 0; +static BasesonEntry *snd_basesonEntries = NULL; + +int snd_loadBasesonEntries(const char *fileName) { + int i; + + snd_baseSndFile = new Common::File(); + snd_baseSndFile->open(fileName); + if (!snd_baseSndFile->isOpen()) + return -1; + + snd_numBasesonEntries = snd_baseSndFile->readUint16BE(); + snd_baseSndFile->readUint16BE(); /* entry_size */ + snd_basesonEntries = (BasesonEntry *)malloc(snd_numBasesonEntries * sizeof(BasesonEntry)); + if (snd_basesonEntries) { + for (i = 0; i < snd_numBasesonEntries; ++i) { + BasesonEntry *be = &snd_basesonEntries[i]; + snd_baseSndFile->read(be->name, 14); + be->offset = snd_baseSndFile->readUint32BE(); + be->size = snd_baseSndFile->readUint32BE(); + be->unpackedSize = snd_baseSndFile->readUint32BE(); + snd_baseSndFile->readUint32BE(); /* unused */ + } + } + return 0; +} + +void snd_clearBasesonEntries() { + snd_baseSndFile->close(); + delete snd_baseSndFile; + free(snd_basesonEntries); + snd_basesonEntries = NULL; + snd_numBasesonEntries = 0; +} + +static int snd_findBasesonEntry(const char *entryName) { + int i; + char *p; + char basesonEntryName[20]; + + assert(strlen(entryName) < 20); + strcpy(basesonEntryName, entryName); + for (p = basesonEntryName; *p; ++p) { + if (*p >= 'a' && *p <= 'z') + *p += 'A' - 'a'; + } + + for (i = 0; i < snd_numBasesonEntries; ++i) { + if (strcmp(snd_basesonEntries[i].name, basesonEntryName) == 0) + return i; + } + return -1; +} + +uint8 *snd_loadBasesonEntry(const char *entryName) { + int entryNum; + uint8 *entryData = NULL; + + if (gameType == Cine::GID_OS) { + entryNum = findFileInBundle((const char *)entryName); + if (entryNum != -1) + entryData = readBundleFile(entryNum); + } else { + entryNum = snd_findBasesonEntry(entryName); + if (entryNum != -1 && entryNum < snd_numBasesonEntries) { + const BasesonEntry *be = &snd_basesonEntries[entryNum]; + entryData = (uint8 *)malloc(be->unpackedSize); + if (entryData) { + if (be->unpackedSize > be->size) { + uint8 *tempData = (uint8 *)malloc(be->size); + if (tempData) { + snd_baseSndFile->seek(be->offset, SEEK_SET); + snd_baseSndFile->read(tempData, be->size); + delphineUnpack(entryData, tempData, be->size); + free(tempData); + } + } else { + snd_baseSndFile->seek(be->offset, SEEK_SET); + snd_baseSndFile->read(entryData, be->size); + } + } + } + } + + return entryData; +} + } // End of namespace Cine diff --git a/engines/cine/resource.h b/engines/cine/resource.h index 84cec3faed..a77ac7ef94 100644 --- a/engines/cine/resource.h +++ b/engines/cine/resource.h @@ -30,7 +30,17 @@ namespace Cine { +struct BasesonEntry { + char name[14]; + uint32 offset; + uint32 size; + uint32 unpackedSize; +}; + void checkDataDisk(int16 param); +extern int snd_loadBasesonEntries(const char *fileName); +extern void snd_clearBasesonEntries(); +extern uint8 *snd_loadBasesonEntry(const char *entryName); } // End of namespace Cine diff --git a/engines/cine/script.cpp b/engines/cine/script.cpp index 628876ece7..2bd8318d86 100644 --- a/engines/cine/script.cpp +++ b/engines/cine/script.cpp @@ -1784,27 +1784,26 @@ void executeScript(prcLinkedListStruct *scriptElement, uint16 params) { case 0x6D: { DEBUG_SCRIPT(currentLine, "loadMusic(%s)", currentScriptPtr + currentPosition); - snd_loadSong((char *)(currentScriptPtr + currentPosition)); - - currentPosition += strlen((char *)(currentScriptPtr + currentPosition)) + 1; + g_sfxPlayer->load((const char *)(currentScriptPtr + currentPosition)); + currentPosition += strlen((const char *)(currentScriptPtr + currentPosition)) + 1; break; } case 0x6E: { DEBUG_SCRIPT(currentLine, "playMusic()"); - snd_playSong(); + g_sfxPlayer->play(); break; } case 0x6F: { DEBUG_SCRIPT(currentLine, "fadeOutMusic()"); - snd_fadeOutSong(); + g_sfxPlayer->fadeOut(); break; } case 0x70: { DEBUG_SCRIPT(currentLine, "stopSample()"); - snd_stopSong(); + g_sfxPlayer->stop(); break; } case 0x77: @@ -1840,16 +1839,20 @@ void executeScript(prcLinkedListStruct *scriptElement, uint16 params) { volume = 63; if (animDataTable[anim].ptr1) { - if (channel >= 10) + if (channel >= 10) { channel -= 10; - if (volume < 50) + } + if (volume < 50) { volume = 50; - if (snd_songIsPlaying) - snd_stopSong(); - if (flag == 0xFFFF) - (*snd_driver.playSound)(animDataTable[anim].ptr1, channel, volume); - else - snd_resetChannel(channel); + } + + g_sfxPlayer->stop(); + + if (flag == 0xFFFF) { + g_soundDriver->playSound(animDataTable[anim].ptr1, channel, volume); + } else { + g_soundDriver->resetChannel(channel); + } } break; } diff --git a/engines/cine/sfx_player.cpp b/engines/cine/sfx_player.cpp index cc4eee495a..ef2b6d5553 100644 --- a/engines/cine/sfx_player.cpp +++ b/engines/cine/sfx_player.cpp @@ -24,7 +24,6 @@ #include "common/stdafx.h" #include "common/system.h" -#include "common/file.h" #include "cine/cine.h" #include "cine/sfx_player.h" @@ -34,242 +33,161 @@ namespace Cine { -uint16 snd_eventsDelay; -int snd_songIsPlaying = 0; -uint8 snd_nullInstrument[] = { 0, 0 }; -SfxState snd_sfxState; - -static uint8 snd_mute = 0; -static char snd_songFileName[30]; - -/* LVDT specific */ -static Common::File *snd_baseSndFile = NULL; -static uint16 snd_numBasesonEntries = 0; -static BasesonEntry *snd_basesonEntries = NULL; - -int snd_loadBasesonEntries(const char *fileName) { - int i; - - snd_baseSndFile = new Common::File(); - snd_baseSndFile->open(fileName); - if (!snd_baseSndFile->isOpen()) - return -1; - - snd_numBasesonEntries = snd_baseSndFile->readUint16BE(); - snd_baseSndFile->readUint16BE(); /* entry_size */ - snd_basesonEntries = (BasesonEntry *)malloc(snd_numBasesonEntries * sizeof(BasesonEntry)); - if (snd_basesonEntries) { - for (i = 0; i < snd_numBasesonEntries; ++i) { - BasesonEntry *be = &snd_basesonEntries[i]; - snd_baseSndFile->read(be->name, 14); - be->offset = snd_baseSndFile->readUint32BE(); - be->size = snd_baseSndFile->readUint32BE(); - be->unpackedSize = snd_baseSndFile->readUint32BE(); - snd_baseSndFile->readUint32BE(); /* unused */ - } - } - return 0; +SfxPlayer::SfxPlayer(SoundDriver *driver) + : _playing(false), _driver(driver) { + memset(_instrumentsData, 0, sizeof(_instrumentsData)); + _sfxData = NULL; + _fadeOutCounter = 0; + _driver->setUpdateCallback(updateCallback, this); } -void snd_clearBasesonEntries() { - snd_baseSndFile->close(); - delete snd_baseSndFile; - free(snd_basesonEntries); - snd_basesonEntries = NULL; - snd_numBasesonEntries = 0; +SfxPlayer::~SfxPlayer() { + _driver->setUpdateCallback(NULL, NULL); + if (_playing) { + stop(); + } } -static int snd_findBasesonEntry(const char *entryName) { - int i; - char *p; - char basesonEntryName[20]; - - assert(strlen(entryName) < 20); - strcpy(basesonEntryName, entryName); - for (p = basesonEntryName; *p; ++p) { - if (*p >= 'a' && *p <= 'z') - *p += 'A' - 'a'; +bool SfxPlayer::load(const char *song) { + debug(9, "SfxPlayer::load('%s')", song); + + /* stop (w/ fade out) the previous song */ + while (_fadeOutCounter != 0 && _fadeOutCounter < 100) { + g_system->delayMillis(50); } + _fadeOutCounter = 0; - for (i = 0; i < snd_numBasesonEntries; ++i) { - if (strcmp(snd_basesonEntries[i].name, basesonEntryName) == 0) - return i; + if (_playing) { + stop(); } - return -1; -} -static uint8 *snd_loadBasesonEntry(const char *entryName) { - int entryNum; - uint8 *entryData = NULL; + /* like the original PC version, skip introduction song (file doesn't exist) */ + if (gameType == Cine::GID_OS && strncmp(song, "INTRO", 5) == 0) { + return 0; + } + + _sfxData = snd_loadBasesonEntry(song); + if (!_sfxData) { + warning("Unable to load soundfx module '%s'", song); + return 0; + } - if (gameType == Cine::GID_OS) { - entryNum = findFileInBundle((const char *)entryName); - if (entryNum != -1) - entryData = readBundleFile(entryNum); - } else { - entryNum = snd_findBasesonEntry(entryName); - if (entryNum != -1 && entryNum < snd_numBasesonEntries) { - const BasesonEntry *be = &snd_basesonEntries[entryNum]; - entryData = (uint8 *)malloc(be->unpackedSize); - if (entryData) { - if (be->unpackedSize > be->size) { - uint8 *tempData = (uint8 *)malloc(be->size); - if (tempData) { - snd_baseSndFile->seek(be->offset, SEEK_SET); - snd_baseSndFile->read(tempData, be->size); - delphineUnpack(entryData, tempData, be->size); - free(tempData); - } - } else { - snd_baseSndFile->seek(be->offset, SEEK_SET); - snd_baseSndFile->read(entryData, be->size); - } + for (int i = 0; i < NUM_INSTRUMENTS; ++i) { + _instrumentsData[i] = NULL; + + char instrument[13]; + memcpy(instrument, _sfxData + 20 + i * 30, 12); + instrument[12] = '\0'; + + if (strlen(instrument) != 0) { + char *dot = strrchr(instrument, '.'); + if (dot) { + *dot = '\0'; + } + strcat(instrument, _driver->getInstrumentExtension()); + _instrumentsData[i] = snd_loadBasesonEntry(instrument); + if (!_instrumentsData[i]) { + warning("Unable to load soundfx instrument '%s'", instrument); } } } - - return entryData; + return 1; } -void snd_stopSong() { - int i; - - snd_songFileName[0] = '\0'; - snd_songIsPlaying = 0; - snd_fadeOutCounter = 0; - - for (i = 0; i < 4; ++i) - (*snd_driver.stopChannel) (i); - - snd_adlibDriverStopSong(); - snd_freeSong(); +void SfxPlayer::play() { + debug(9, "SfxPlayer::play()"); + if (_sfxData) { + for (int i = 0; i < NUM_CHANNELS; ++i) { + _instrumentsChannelTable[i] = -1; + } + _currentPos = 0; + _currentOrder = 0; + _numOrders = _sfxData[470]; + _eventsDelay = (252 - _sfxData[471]) * 50 / 1060; + _updateTicksCounter = 0; + _playing = true; + } } -void snd_freeSong() { - int i; - - for (i = 0; i < 15; ++i) { - if (snd_sfxState.instruments[i] != snd_nullInstrument) - free(snd_sfxState.instruments[i]); +void SfxPlayer::stop() { + _fadeOutCounter = 0; + _playing = false; + for (int i = 0; i < NUM_CHANNELS; ++i) { + _driver->stopChannel(i); } - free(snd_sfxState.songData); - memset(&snd_sfxState, 0, sizeof(snd_sfxState)); + _driver->stopSound(); + unload(); } -int snd_loadSong(const char *songName) { - int i; - - while (snd_fadeOutCounter != 0 && snd_fadeOutCounter < 100) - g_system->delayMillis(40); - - snd_fadeOutCounter = 0; - - if (snd_songIsPlaying) - snd_stopSong(); - - if ((gameType == Cine::GID_OS) && (strncmp(songName, "INTRO", 5) == 0)) - return 0; - - strcpy(snd_songFileName, songName); - if (gameType == Cine::GID_OS) - strcat(snd_songFileName, ".IST"); - - snd_sfxState.songData = snd_loadBasesonEntry(songName); - if (!snd_sfxState.songData) - return 0; - - for (i = 0; i < 15; ++i) { - char instrumentName[13]; - memcpy(instrumentName, snd_sfxState.songData + 20 + i * 30, 12); - instrumentName[12] = '\0'; - - snd_sfxState.instruments[i] = snd_nullInstrument; - if (strlen(instrumentName) != 0) { - char *dot = strrchr(instrumentName, '.'); - if (dot) - *dot = '\0'; - - if (gameType == Cine::GID_OS) - strcat(instrumentName, ".ADL"); - else - strcat(instrumentName, ".INS"); - - snd_sfxState.instruments[i] = - snd_loadBasesonEntry(instrumentName); - } +void SfxPlayer::fadeOut() { + if (_playing) { + _fadeOutCounter = 1; + _playing = false; } - return 1; } -void snd_fadeOutSong() { - if (snd_songIsPlaying) { - snd_songFileName[0] = '\0'; - snd_songIsPlaying = 0; - snd_fadeOutCounter = 1; - } +void SfxPlayer::updateCallback(void *ref) { + ((SfxPlayer *)ref)->update(); } -void snd_playSong() { - if (strlen(snd_songFileName) != 0) { - snd_sfxState.currentInstrumentChannel[0] = -1; - snd_sfxState.currentInstrumentChannel[1] = -1; - snd_sfxState.currentInstrumentChannel[2] = -1; - snd_sfxState.currentInstrumentChannel[3] = -1; - snd_sfxState.currentOrder = 0; - snd_sfxState.currentPos = 0; - snd_sfxState.numOrders = snd_sfxState.songData[470]; - snd_eventsDelay = (252 - snd_sfxState.songData[471]) * 25 * 2 / 1060; - snd_songTicksCounter = 0; - snd_songIsPlaying = 1; +void SfxPlayer::update() { + if (_playing || (_fadeOutCounter != 0 && _fadeOutCounter < 100)) { + ++_updateTicksCounter; + if (_updateTicksCounter > _eventsDelay) { + handleEvents(); + _updateTicksCounter = 0; + } } } -void snd_handleEvents() { - int i; - const uint8 *patternData = snd_sfxState.songData + 600; - const uint8 *orderTable = snd_sfxState.songData + 472; - uint16 patternNum = orderTable[snd_sfxState.currentOrder] * 1024; +void SfxPlayer::handleEvents() { + const uint8 *patternData = _sfxData + 600; + const uint8 *orderTable = _sfxData + 472; + uint16 patternNum = orderTable[_currentOrder] * 1024; - for (i = 0; i < 4; ++i) { - snd_handlePattern(i, patternData + patternNum + snd_sfxState.currentPos); + for (int i = 0; i < 4; ++i) { + handlePattern(i, patternData + patternNum + _currentPos); patternData += 4; } - if (snd_fadeOutCounter != 0 && snd_fadeOutCounter < 100) - snd_fadeOutCounter += 4; - - snd_sfxState.currentPos += 16; - if (snd_sfxState.currentPos >= 1024) { - snd_sfxState.currentPos = 0; - ++snd_sfxState.currentOrder; - if (snd_sfxState.currentOrder == snd_sfxState.numOrders) - snd_sfxState.currentOrder = 0; + if (_fadeOutCounter != 0 && _fadeOutCounter < 100) { + _fadeOutCounter += 2; } + _currentPos += 16; + if (_currentPos >= 1024) { + _currentPos = 0; + ++_currentOrder; + if (_currentOrder == _numOrders) { + _currentOrder = 0; + } + } + debug(7, "_currentOrder=%d/%d _currentPos=%d", _currentOrder, _numOrders, _currentPos); } -void snd_handlePattern(int channelNum, const uint8 *patternData) { - uint16 instrNum = patternData[2] >> 4; - snd_adlibInstrumentsTable[channelNum] = snd_nullInstrument; - if (instrNum != 0) { - if (snd_sfxState.currentInstrumentChannel[channelNum] != instrNum) { - snd_sfxState.currentInstrumentChannel[channelNum] = instrNum; - (*snd_driver.setupChannel) (channelNum, snd_sfxState.instruments[instrNum - 1], instrNum - 1); - } else if (snd_fadeOutCounter != 0) { - instrNum = snd_sfxState.currentInstrumentChannel[channelNum]; - if (instrNum != 0) - (*snd_driver.setupChannel)(channelNum, snd_sfxState.instruments[instrNum - 1], instrNum - 1); +void SfxPlayer::handlePattern(int channel, const uint8 *patternData) { + int instrument = patternData[2] >> 4; + if (instrument != 0) { + --instrument; + if (_instrumentsChannelTable[channel] != instrument || _fadeOutCounter != 0) { + _instrumentsChannelTable[channel] = instrument; + const int volume = _sfxData[instrument] - _fadeOutCounter; + _driver->setupChannel(channel, _instrumentsData[instrument], instrument, volume); } - snd_adlibInstrumentsTable[channelNum] = snd_sfxState.instruments[instrNum - 1]; } - if (snd_mute != 0) - (*snd_driver.stopChannel)(channelNum); - else { - int16 freq = (int16)READ_BE_UINT16(patternData); - if (freq > 0) { - (*snd_driver.stopChannel)(channelNum); - (*snd_driver.setChannelFrequency)(channelNum, freq); - } + int16 freq = (int16)READ_BE_UINT16(patternData); + if (freq > 0) { + _driver->stopChannel(channel); + _driver->setChannelFrequency(channel, freq); + } +} + +void SfxPlayer::unload() { + for (int i = 0; i < NUM_INSTRUMENTS; ++i) { + free(_instrumentsData[i]); + _instrumentsData[i] = NULL; } + free(_sfxData); + _sfxData = NULL; } } // End of namespace Cine diff --git a/engines/cine/sfx_player.h b/engines/cine/sfx_player.h index b082f5391a..1b40df06d8 100644 --- a/engines/cine/sfx_player.h +++ b/engines/cine/sfx_player.h @@ -27,36 +27,47 @@ namespace Cine { -struct BasesonEntry { - char name[14]; - uint32 offset; - uint32 size; - uint32 unpackedSize; -}; +class SoundDriver; + +class SfxPlayer { +public: + + enum { + NUM_INSTRUMENTS = 15, + NUM_CHANNELS = 4 + }; + + SfxPlayer(SoundDriver *driver); + ~SfxPlayer(); + + bool load(const char *song); + void play(); + void stop(); + void fadeOut(); + + static void updateCallback(void *ref); + +private: + + void update(); + void handleEvents(); + void handlePattern(int channel, const uint8 *patternData); + void unload(); -struct SfxState { - uint8 *songData; - int currentInstrumentChannel[4]; - uint8 *instruments[15]; - int currentOrder; - int currentPos; - int numOrders; + bool _playing; + int _currentPos; + int _currentOrder; + int _numOrders; + int _eventsDelay; + int _fadeOutCounter; + int _updateTicksCounter; + int _instrumentsChannelTable[NUM_CHANNELS]; + uint8 *_sfxData; + uint8 *_instrumentsData[NUM_INSTRUMENTS]; + SoundDriver *_driver; }; -extern uint16 snd_eventsDelay; -extern int snd_songIsPlaying; -extern uint8 snd_nullInstrument[]; -extern SfxState snd_sfxState; - -extern int snd_loadBasesonEntries(const char *fileName); -extern void snd_clearBasesonEntries(); -extern void snd_stopSong(); -extern void snd_freeSong(); -extern int snd_loadSong(const char *songName); -extern void snd_fadeOutSong(); -extern void snd_playSong(); -extern void snd_handleEvents(); -extern void snd_handlePattern(int channelNum, const uint8 *patternData); +extern SfxPlayer *g_sfxPlayer; // TEMP } // End of namespace Cine diff --git a/engines/cine/sound_driver.cpp b/engines/cine/sound_driver.cpp index ecf3f83061..872d6c1742 100644 --- a/engines/cine/sound_driver.cpp +++ b/engines/cine/sound_driver.cpp @@ -23,383 +23,412 @@ */ #include "cine/cine.h" -#include "cine/sfx_player.h" #include "cine/sound_driver.h" #include "sound/mixer.h" -#include "sound/fmopl.h" namespace Cine { -extern AdlibMusic *g_cine_adlib; - -uint8 snd_useAdlib = 0; -uint16 snd_fadeOutCounter = 0; -uint16 snd_songTicksCounter = 0; -uint8 *snd_adlibInstrumentsTable[4]; -SoundDriver snd_driver; - -static uint8 snd_adlibVibrato = 0; -static int16 snd_adlibChannelVolume[4]; - -static const uint16 snd_adlibFreqTable[] = { - 0x0157, 0x016C, 0x0181, 0x0198, 0x01B1, 0x01CB, 0x01E6, 0x0203, - 0x0222, 0x0243, 0x0266, 0x028A -}; +void SoundDriver::setUpdateCallback(UpdateCallback upCb, void *ref) { + _upCb = upCb; + _upRef = ref; +} -static const uint8 snd_adlibOpTable[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x08, 0x09, 0x0A, - 0x0B, 0x0C, 0x0D, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 -}; +void SoundDriver::findNote(int freq, int *note, int *oct) const { + *note = _noteTableCount - 1; + for (int i = 0; i < _noteTableCount; ++i) { + if (_noteTable[i] <= freq) { + *note = i; + break; + } + } + *oct = *note / 12; +} -static const uint8 snd_adlibNoteTable[] = { - 0x00, 0x03, 0x01, 0x04, 0x02, 0x05, 0x06, 0x09, 0x07, - 0x0A, 0x08, 0x0B, 0x0C, 0x0F, 0x10, 0x10, 0x0E, 0x0E, - 0x11, 0x11, 0x0D, 0x0D, 0x00, 0x00 -}; +void SoundDriver::resetChannel(int channel) { + stopChannel(channel); + stopSound(); +} -static const int16 snd_adlibNoteFreqTable[] = { - 0x0EEE, 0x0E17, 0x0D4D, 0x0C8C, 0x0BD9, 0x0B2F, 0x0A8E, 0x09F7, - 0x0967, 0x08E0, 0x0861, 0x07E8, 0x0777, 0x070B, 0x06A6, 0x0647, - 0x05EC, 0x0597, 0x0547, 0x04FB, 0x04B3, 0x0470, 0x0430, 0x03F4, - 0x03BB, 0x0385, 0x0353, 0x0323, 0x02F6, 0x02CB, 0x02A3, 0x027D, - 0x0259, 0x0238, 0x0218, 0x01FA, 0x01DD, 0x01C2, 0x01A9, 0x0191, - 0x017B, 0x0165, 0x0151, 0x013E, 0x012C, 0x011C, 0x010C, 0x00FD, - 0x00EE, 0x00E1, 0x00D4, 0x00C8, 0x00BD, 0x00B2, 0x00A8, 0x009F, - 0x0096, 0x008E, 0x0086, 0x007E, 0x0077, 0x0070, 0x006A, 0x0064, - 0x005E, 0x0059, 0x0054, 0x004F, 0x004B, 0x0047, 0x0043, 0x003F, - 0x003B, 0x0038, 0x0035, 0x0032, 0x002F, 0x002C, 0x002A, 0x0027, - 0x0025, 0x0023, 0x0021, 0x001F, 0x001D, 0x001C, 0x001A, 0x0019, - 0x0017, 0x0016, 0x0015, 0x0013, 0x0012, 0x0011, 0x0010, 0x000F -}; +AdlibSoundDriver::AdlibSoundDriver(Audio::Mixer *mixer) + : _mixer(mixer) { + _sampleRate = _mixer->getOutputRate(); + _opl = makeAdlibOPL(_sampleRate); + memset(_channelsVolumeTable, 0, sizeof(_channelsVolumeTable)); + memset(_instrumentsTable, 0, sizeof(_instrumentsTable)); + initCard(); + _mixer->setupPremix(this); +} -static void snd_adlibWriteData(int port, int value) { - OPLWriteReg(g_cine_adlib->getOPL(), port, value); +AdlibSoundDriver::~AdlibSoundDriver() { + _mixer->setupPremix(NULL); } -static void snd_adlibDriverSetupInstrument(const uint8 *instrumentData, int channelNum) { - int16 tmp; +void AdlibSoundDriver::setupChannel(int channel, const uint8 *data, int instrument, int volume) { + assert(channel < 4); + if (data) { + if (volume > 80) { + volume = 80; + } else if (volume < 0) { + volume = 0; + } + volume += volume / 4; + if (volume > 127) { + volume = 127; + } + _channelsVolumeTable[channel] = volume; + setupInstrument(data, channel); + } +} - uint8 waveSelect1 = instrumentData[54] & 3; /* var2 */ - uint8 waveSelect2 = instrumentData[56] & 3; /* var1 */ +void AdlibSoundDriver::stopChannel(int channel) { + assert(channel < 4); + AdlibSoundInstrument *ins = &_instrumentsTable[channel]; + if (ins) { + if (ins->mode != 0 && ins->channel == 6) { + channel = 6; + } + if (ins->mode == 0 || ins->channel == 6) { + OPLWriteReg(_opl, 0xB0 | channel, 0); + } + if (ins->mode != 0) { + _vibrato &= (1 << (10 - ins->channel)) ^ 0xFF; + OPLWriteReg(_opl, 0xBD, _vibrato); + } + } +} - uint8 fl = *instrumentData++; /* varB */ - uint8 ch = *instrumentData++; /* var4 */ +void AdlibSoundDriver::stopSound() { + int i; + for (i = 0; i < 18; ++i) { + OPLWriteReg(_opl, 0x40 | _operatorsTable[i], 63); + } + for (i = 0; i < 9; ++i) { + OPLWriteReg(_opl, 0xB0 | i, 0); + } + OPLWriteReg(_opl, 0xBD, 0); +} - uint8 adlibOp1, adlibOp2; /* _di, varA */ +int AdlibSoundDriver::readBuffer(int16 *buffer, const int numSamples) { + update(buffer, numSamples / 2); + // convert mono to stereo + for (int i = numSamples / 2 - 1; i >= 0; i--) { + buffer[2 * i] = buffer[2 * i + 1] = buffer[i]; + } + return numSamples; +} - if (fl != 0) { - adlibOp1 = snd_adlibOpTable[snd_adlibNoteTable[ch * 2 + 0]]; - adlibOp2 = snd_adlibOpTable[snd_adlibNoteTable[ch * 2 + 1]]; - } else { - adlibOp1 = snd_adlibOpTable[snd_adlibNoteTable[channelNum * 2 + 0]]; - adlibOp2 = snd_adlibOpTable[snd_adlibNoteTable[channelNum * 2 + 1]]; - } - - if (fl == 0 || ch == 6) { - // vibrato - tmp = 0; - if (READ_LE_UINT16(instrumentData + 18) != 0) - tmp |= 0x80; - if (READ_LE_UINT16(instrumentData + 20) != 0) - tmp |= 0x40; - if (READ_LE_UINT16(instrumentData + 10) != 0) - tmp |= 0x20; - if (READ_LE_UINT16(instrumentData + 22) != 0) - tmp |= 0x10; - tmp |= (READ_LE_UINT16(instrumentData + 2) & 0xF); - snd_adlibWriteData(ADLIB_REG_AM_VIBRATO_EG_KS + adlibOp1, tmp); - - // key scaling - tmp = 0x3F - (READ_LE_UINT16(instrumentData + 16) & 0x3F); - tmp = snd_adlibChannelVolume[channelNum] * tmp; - tmp += tmp + 0x7F; - tmp = 0x3F - (tmp / 0xFE); - if (READ_LE_UINT16(instrumentData + 24) != 0) - tmp = READ_LE_UINT16(instrumentData + 16) & 0x3F; - tmp |= READ_LE_UINT16(instrumentData) << 6; - snd_adlibWriteData(ADLIB_REG_KEY_SCALING_OPERATOR_OUTPUT + adlibOp1, tmp); - - // attack/decay rates - tmp = (READ_LE_UINT16(instrumentData + 6) << 4) | (READ_LE_UINT16(instrumentData + 12) & 0xF); - snd_adlibWriteData(ADLIB_REG_ATTACK_RATE_DECAY_RATE + adlibOp1, tmp); - - // sustain/release rates - tmp = (READ_LE_UINT16(instrumentData + 8) << 4) | (READ_LE_UINT16(instrumentData + 14) & 0xF); - snd_adlibWriteData(ADLIB_REG_SUSTAIN_LEVEL_RELEASE_RATE_0 + adlibOp1, tmp); - - if (fl != 0) { - tmp = READ_LE_UINT16(instrumentData + 4) * 2; - if (READ_LE_UINT16(instrumentData + 24) == 0) - tmp |= 1; - - snd_adlibWriteData(ADLIB_REG_FEEDBACK_STRENGTH_CONNECTION_TYPE + ch, tmp); - } else { - tmp = READ_LE_UINT16(instrumentData + 4) * 2; - if (READ_LE_UINT16(instrumentData + 24) == 0) - tmp |= 1; +void AdlibSoundDriver::initCard() { + _vibrato = 0x20; + OPLWriteReg(_opl, 0xBD, _vibrato); + OPLWriteReg(_opl, 0x08, 0x40); + + int i; + for (i = 0; i < 18; ++i) { + OPLWriteReg(_opl, 0x40 | _operatorsTable[i], 0); + } + for (i = 0; i < 9; ++i) { + OPLWriteReg(_opl, 0xB0 | i, 0); + } + for (i = 0; i < 9; ++i) { + OPLWriteReg(_opl, 0xC0 | i, 0); + } + for (i = 0; i < 18; ++i) { + OPLWriteReg(_opl, 0x60 | _operatorsTable[i], 0); + } + for (i = 0; i < 18; ++i) { + OPLWriteReg(_opl, 0x80 | _operatorsTable[i], 0); + } + for (i = 0; i < 18; ++i) { + OPLWriteReg(_opl, 0x20 | _operatorsTable[i], 0); + } + for (i = 0; i < 18; ++i) { + OPLWriteReg(_opl, 0xE0 | _operatorsTable[i], 0); + } - snd_adlibWriteData(ADLIB_REG_FEEDBACK_STRENGTH_CONNECTION_TYPE + channelNum, tmp); - } - snd_adlibWriteData(ADLIB_REG_WAVE_SELECT + adlibOp1, waveSelect1); - instrumentData += 26; - } - - // vibrato - tmp = 0; - if (READ_LE_UINT16(instrumentData + 18) != 0) - tmp |= 0x80; - if (READ_LE_UINT16(instrumentData + 20) != 0) - tmp |= 0x40; - if (READ_LE_UINT16(instrumentData + 10) != 0) - tmp |= 0x20; - if (READ_LE_UINT16(instrumentData + 22) != 0) - tmp |= 0x10; - tmp |= (READ_LE_UINT16(instrumentData + 2) & 0xF); - snd_adlibWriteData(ADLIB_REG_AM_VIBRATO_EG_KS + adlibOp2, tmp); - - // key scaling - tmp = 0x3F - (READ_LE_UINT16(instrumentData + 16) & 0x3F); - tmp = snd_adlibChannelVolume[channelNum] * tmp; - tmp += tmp + 0x7F; - tmp = 0x3F - (tmp / 0xFE); - tmp |= READ_LE_UINT16(instrumentData) << 6; - snd_adlibWriteData(ADLIB_REG_KEY_SCALING_OPERATOR_OUTPUT + adlibOp2, tmp); - - // attack/decay rates */ - tmp =(READ_LE_UINT16(instrumentData + 6) << 4) | (READ_LE_UINT16(instrumentData + 12) & 0xF); - snd_adlibWriteData(ADLIB_REG_ATTACK_RATE_DECAY_RATE + adlibOp2, tmp); - - // sustain/release rates */ - tmp = (READ_LE_UINT16(instrumentData + 8) << 4) | (READ_LE_UINT16(instrumentData + 14) & 0xF); - snd_adlibWriteData(ADLIB_REG_SUSTAIN_LEVEL_RELEASE_RATE_0 + adlibOp2, tmp); - snd_adlibWriteData(ADLIB_REG_WAVE_SELECT + adlibOp2, waveSelect2); + OPLWriteReg(_opl, 1, 0x20); + OPLWriteReg(_opl, 1, 0); } -static void snd_adlibInterrupt(void *param, int16 *buf, int len) { - int16 *origData = buf; - uint origLen = len; +void AdlibSoundDriver::update(int16 *buf, int len) { static int samplesLeft = 0; - while (len != 0) { - int count; - if (samplesLeft == 0) { - if (snd_songIsPlaying || (snd_fadeOutCounter != 0 && snd_fadeOutCounter < 100)) { - ++snd_songTicksCounter; - if (snd_songTicksCounter > snd_eventsDelay) { - snd_handleEvents(); - snd_songTicksCounter = 0; - } - } - samplesLeft = g_cine_adlib->getRate() / 50; - } - count = samplesLeft; - if (count > len) + int count = samplesLeft; + if (count > len) { count = len; - - YM3812UpdateOne(g_cine_adlib->getOPL(), buf, count); - + } samplesLeft -= count; len -= count; + YM3812UpdateOne(_opl, buf, count); + if (samplesLeft == 0) { + if (_upCb) { + (*_upCb)(_upRef); + } + samplesLeft = _sampleRate / 50; + } buf += count; } - - // Convert mono data to stereo - for (int i = (origLen - 1); i >= 0; i--) { - origData[2 * i] = origData[2 * i + 1] = origData[i]; - } } -static void snd_adlibDriverSetupChannel(int channelNum, const uint8 *data, int instrumentNum) { - int16 vol = snd_sfxState.songData[instrumentNum]; - if (vol != 0 && vol < 0x50) - vol = 0x50; - - vol -= snd_fadeOutCounter; - if (vol < 0) - vol = 0; - - vol += vol / 4; - if (vol > 0x7F) - vol = 0x7F; +void AdlibSoundDriver::setupInstrument(const uint8 *data, int channel) { + assert(channel < 4); + AdlibSoundInstrument *ins = &_instrumentsTable[channel]; + loadInstrument(data, ins); - snd_adlibChannelVolume[channelNum] = vol; - snd_adlibDriverSetupInstrument(data, channelNum); -} - -static void snd_getAdlibFrequency(int frequency, int *adlibFreq) { - int i; + int mod, car, tmp; + const AdlibRegisterSoundInstrument *reg; - *adlibFreq = 95; - for (i = 0; i < 96; ++i) { - if (snd_adlibNoteFreqTable[i] <= frequency) { - *adlibFreq = i; - break; + if (ins->mode != 0) { + mod = _operatorsTable[_voiceOperatorsTable[2 * ins->channel + 0]]; + car = _operatorsTable[_voiceOperatorsTable[2 * ins->channel + 1]]; + } else { + mod = _operatorsTable[_voiceOperatorsTable[2 * channel + 0]]; + car = _operatorsTable[_voiceOperatorsTable[2 * channel + 1]]; + } + + if (ins->mode == 0 || ins->channel == 6) { + reg = &ins->regMod; + OPLWriteReg(_opl, 0x20 | mod, reg->vibrato); + if (reg->freqMod) { + tmp = reg->outputLevel & 0x3F; + } else { + tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel]; + tmp = 63 - (2 * tmp + 127) / (2 * 127); } + OPLWriteReg(_opl, 0x40 | mod, tmp | (reg->keyScaling << 6)); + OPLWriteReg(_opl, 0x60 | mod, reg->attackDecay); + OPLWriteReg(_opl, 0x80 | mod, reg->sustainRelease); + if (ins->mode != 0) { + OPLWriteReg(_opl, 0xC0 | ins->channel, reg->feedbackStrength); + } else { + OPLWriteReg(_opl, 0xC0 | channel, reg->feedbackStrength); + } + OPLWriteReg(_opl, 0xE0 | mod, ins->waveSelectMod); } -} - -static void snd_adlibDriverSetChannelFrequency(int channelNum, int frequency) { - const uint8 *instr = snd_adlibInstrumentsTable[channelNum]; - uint8 fl = *instr++; // var2 - uint8 ch = *instr++; // var1 - - if (fl != 0 && ch == 6) - channelNum = 6; - if (fl == 0 || channelNum == 6) { - uint16 freqLow, freqHigh; // var8 - int adlibFreq; - - snd_getAdlibFrequency(frequency, &adlibFreq); - if (channelNum == 6) - adlibFreq %= 12; - - freqLow = snd_adlibFreqTable[adlibFreq % 12]; - snd_adlibWriteData(ADLIB_REG_FREQUENCY_0 + channelNum, freqLow); - freqHigh = ((adlibFreq / 12) << 2) | ((freqLow & 0x300) >> 8); - if (fl == 0) - freqHigh |= 0x20; + reg = &ins->regCar; + OPLWriteReg(_opl, 0x20 | car, reg->vibrato); + tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel]; + tmp = 63 - (2 * tmp + 127) / (2 * 127); + OPLWriteReg(_opl, 0x40 | car, tmp | (reg->keyScaling << 6)); + OPLWriteReg(_opl, 0x60 | car, reg->attackDecay); + OPLWriteReg(_opl, 0x80 | car, reg->sustainRelease); + OPLWriteReg(_opl, 0xE0 | car, ins->waveSelectCar); +} - snd_adlibWriteData(ADLIB_REG_KEY_ON_OCTAVE_FREQUENCY_0 + channelNum, freqHigh); +void AdlibSoundDriver::loadRegisterInstrument(const uint8 *data, AdlibRegisterSoundInstrument *reg) { + reg->vibrato = 0; + if (READ_LE_UINT16(data + 18)) { // amplitude vibrato + reg->vibrato |= 0x80; + } + if (READ_LE_UINT16(data + 20)) { // frequency vibrato + reg->vibrato |= 0x40; } - if (fl != 0) { - snd_adlibVibrato |= 1 << (10 - ch); - snd_adlibWriteData(ADLIB_REG_AM_VIBRATO_RHYTHM, snd_adlibVibrato); + if (READ_LE_UINT16(data + 10)) { // sustaining sound + reg->vibrato |= 0x20; } + if (READ_LE_UINT16(data + 22)) { // envelope scaling + reg->vibrato |= 0x10; + } + reg->vibrato |= READ_LE_UINT16(data + 2) & 0xF; // frequency multiplier + + reg->attackDecay = READ_LE_UINT16(data + 6) << 4; // attack rate + reg->attackDecay |= READ_LE_UINT16(data + 12) & 0xF; // decay rate + + reg->sustainRelease = READ_LE_UINT16(data + 8) << 4; // sustain level + reg->sustainRelease |= READ_LE_UINT16(data + 14) & 0xF; // release rate + + reg->feedbackStrength = READ_LE_UINT16(data + 4) << 1; // feedback + if (READ_LE_UINT16(data + 24) == 0) { // frequency modulation + reg->feedbackStrength |= 1; + } + + reg->keyScaling = READ_LE_UINT16(data); + reg->outputLevel = READ_LE_UINT16(data + 16); + reg->freqMod = READ_LE_UINT16(data + 24); } -static void snd_adlibDriverStopChannel(int channelNum) { - const uint8 *instr = snd_adlibInstrumentsTable[channelNum]; - uint8 fl = *instr++; // var2 - uint8 ch = *instr++; // var1 - - if (fl != 0 && ch == 6) - channelNum = 6; - - if (fl == 0 || channelNum == 6) - snd_adlibWriteData(ADLIB_REG_KEY_ON_OCTAVE_FREQUENCY_0 + channelNum, 0); +void AdlibSoundDriverINS::loadInstrument(const uint8 *data, AdlibSoundInstrument *asi) { + asi->mode = *data++; + asi->channel = *data++; + loadRegisterInstrument(data, &asi->regMod); data += 26; + loadRegisterInstrument(data, &asi->regCar); data += 26; + asi->waveSelectMod = data[0] & 3; data += 2; + asi->waveSelectCar = data[0] & 3; data += 2; + asi->amDepth = data[0]; data += 2; +} - if (fl != 0) { - snd_adlibVibrato &= (1 << (10 - ch)) ^ 0xFF; - snd_adlibWriteData(ADLIB_REG_AM_VIBRATO_RHYTHM, snd_adlibVibrato); +void AdlibSoundDriverINS::setChannelFrequency(int channel, int frequency) { + assert(channel < 4); + AdlibSoundInstrument *ins = &_instrumentsTable[channel]; + if (ins) { + if (ins->mode != 0 && ins->channel == 6) { + channel = 6; + } + if (ins->mode == 0 || ins->channel == 6) { + int freq, note, oct; + findNote(frequency, ¬e, &oct); + if (channel == 6) { + note %= 12; + } + freq = _freqTable[note % 12]; + OPLWriteReg(_opl, 0xA0 | channel, freq); + freq = ((note / 12) << 2) | ((freq & 0x300) >> 8); + if (ins->mode == 0) { + freq |= 0x20; + } + OPLWriteReg(_opl, 0xB0 | channel, freq); + } + if (ins->mode != 0) { + _vibrato |= 1 << (10 - ins->channel); + OPLWriteReg(_opl, 0xBD, _vibrato); + } } } -static void snd_adlibDriverPlaySound(uint8 * data, int channelNum, int volume) { -// if (_snd_mute) return; - uint8 fl, ch; // var2, var1 - - assert(channelNum < 4); - data += 257; - snd_adlibInstrumentsTable[channelNum] = data; - snd_resetChannel(channelNum); - snd_adlibChannelVolume[channelNum] = 0x7F; - snd_adlibDriverSetupInstrument(data, channelNum); - fl = *data++; - ch = *data++; - - if (fl != 0 && ch == 6) - channelNum = 6; - - if (fl == 0 || channelNum == 6) { - uint16 freqLow, freqHigh; - freqLow = snd_adlibFreqTable[0]; - snd_adlibWriteData(ADLIB_REG_FREQUENCY_0 + channelNum, freqLow); - freqHigh = 4 | ((freqLow & 0x300) >> 8); - if (fl == 0) - freqHigh |= 0x20; - - snd_adlibWriteData(ADLIB_REG_KEY_ON_OCTAVE_FREQUENCY_0 + channelNum, freqHigh); +void AdlibSoundDriverINS::playSound(const uint8 *data, int channel, int volume) { + assert(channel < 4); + _channelsVolumeTable[channel] = 127; + resetChannel(channel); + setupInstrument(data + 257, channel); + AdlibSoundInstrument *ins = &_instrumentsTable[channel]; + if (ins->mode != 0 && ins->channel == 6) { + channel = 6; + } + if (ins->mode == 0 || channel == 6) { + int freq = _freqTable[0]; + OPLWriteReg(_opl, 0xA0 | channel, freq); + freq = 4 | ((freq & 0x300) >> 8); + if (ins->mode == 0) { + freq |= 0x20; + } + OPLWriteReg(_opl, 0xB0 | channel, freq); } - if (fl != 0) { - snd_adlibVibrato = 1 << (10 - ch); - snd_adlibWriteData(ADLIB_REG_AM_VIBRATO_RHYTHM, snd_adlibVibrato); + if (ins->mode != 0) { + _vibrato = 1 << (10 - ins->channel); + OPLWriteReg(_opl, 0xBD, _vibrato); } } -static SoundDriver snd_adlibDriver = { - &snd_adlibDriverSetupChannel, - &snd_adlibDriverSetChannelFrequency, - &snd_adlibDriverStopChannel, - &snd_adlibDriverPlaySound -}; - -void snd_adlibDriverStopSong() { - int i; - - for (i = 0; i < 18; ++i) - snd_adlibWriteData(ADLIB_REG_KEY_SCALING_OPERATOR_OUTPUT + snd_adlibOpTable[i], 0x3F); +void AdlibSoundDriverADL::loadInstrument(const uint8 *data, AdlibSoundInstrument *asi) { + asi->mode = *data++; + asi->channel = *data++; + asi->waveSelectMod = *data++ & 3; + asi->waveSelectCar = *data++ & 3; + asi->amDepth = *data++; + ++data; + loadRegisterInstrument(data, &asi->regMod); data += 26; + loadRegisterInstrument(data, &asi->regCar); data += 26; +} - for (i = 0; i < 9; ++i) - snd_adlibWriteData(ADLIB_REG_KEY_ON_OCTAVE_FREQUENCY_0 + i, 0); +void AdlibSoundDriverADL::setChannelFrequency(int channel, int frequency) { + assert(channel < 4); + AdlibSoundInstrument *ins = &_instrumentsTable[channel]; + if (ins) { + if (ins->mode != 0) { + channel = ins->channel; + if (channel == 9) { + channel = 8; + } else if (channel == 10) { + channel = 7; + } + } + int freq, note, oct; + findNote(frequency, ¬e, &oct); + + note += oct * 12; + if (ins->amDepth) { + note = ins->amDepth; + } + if (note < 0) { + note = 0; + } - snd_adlibWriteData(ADLIB_REG_AM_VIBRATO_RHYTHM, 0); + freq = _freqTable[note % 12]; + OPLWriteReg(_opl, 0xA0 | channel, freq); + freq = ((note / 12) << 2) | ((freq & 0x300) >> 8); + if (ins->mode == 0) { + freq |= 0x20; + } + OPLWriteReg(_opl, 0xB0 | channel, freq); + if (ins->mode != 0) { + _vibrato = 1 << (10 - channel); + OPLWriteReg(_opl, 0xBD, _vibrato); + } + } } -void snd_resetChannel(int channelNum) { - (*snd_driver.stopChannel) (channelNum); - if (snd_useAdlib) - snd_adlibDriverStopSong(); +void AdlibSoundDriverADL::playSound(const uint8 *data, int channel, int volume) { + assert(channel < 4); + _channelsVolumeTable[channel] = 127; + setupInstrument(data, channel); + AdlibSoundInstrument *ins = &_instrumentsTable[channel]; + if (ins->mode != 0 && ins->channel == 6) { + OPLWriteReg(_opl, 0xB0 | channel, 0); + } + if (ins->mode != 0) { + _vibrato = (1 << (10 - ins->channel)) ^ 0xFF; + OPLWriteReg(_opl, 0xBD, _vibrato); + } + if (ins->mode != 0) { + channel = ins->channel; + if (channel == 9) { + channel = 8; + } else if (channel == 10) { + channel = 7; + } + } + uint16 note = 48; + if (ins->amDepth) { + note = ins->amDepth; + } + int freq = _freqTable[note % 12]; + OPLWriteReg(_opl, 0xA0 | channel, freq); + freq = ((note / 12) << 2) | ((freq & 0x300) >> 8); + if (ins->mode == 0) { + freq |= 0x20; + } + OPLWriteReg(_opl, 0xB0 | channel, freq); + if (ins->mode != 0) { + _vibrato = 1 << (10 - channel); + OPLWriteReg(_opl, 0xBD, _vibrato); + } } -AdlibMusic::AdlibMusic(Audio::Mixer *pMixer) { - _mixer = pMixer; - _sampleRate = pMixer->getOutputRate(); - g_cine_adlib = this; - _opl = makeAdlibOPL(_sampleRate); - - snd_adlibVibrato = 0x20; - snd_adlibWriteData(ADLIB_REG_AM_VIBRATO_RHYTHM, snd_adlibVibrato); - snd_adlibWriteData(0x08, 0x40); - - int i; - - for (i = 0; i < 18; ++i) - snd_adlibWriteData(ADLIB_REG_KEY_SCALING_OPERATOR_OUTPUT + snd_adlibOpTable[i], 0); - - for (i = 0; i < 9; ++i) - snd_adlibWriteData(ADLIB_REG_KEY_ON_OCTAVE_FREQUENCY_0 + i, 0); - - for (i = 0; i < 9; ++i) - snd_adlibWriteData(ADLIB_REG_FEEDBACK_STRENGTH_CONNECTION_TYPE + i, 0); - - for (i = 0; i < 18; ++i) - snd_adlibWriteData(ADLIB_REG_ATTACK_RATE_DECAY_RATE + snd_adlibOpTable[i], 0); - - for (i = 0; i < 18; ++i) - snd_adlibWriteData(ADLIB_REG_SUSTAIN_LEVEL_RELEASE_RATE_0 + snd_adlibOpTable[i], 0); - - for (i = 0; i < 18; ++i) - snd_adlibWriteData(ADLIB_REG_AM_VIBRATO_EG_KS + snd_adlibOpTable[i], 0); - - for (i = 0; i < 18; ++i) - snd_adlibWriteData(ADLIB_REG_WAVE_SELECT + snd_adlibOpTable[i], - 0); +const int SoundDriver::_noteTable[] = { + 0xEEE, 0xE17, 0xD4D, 0xC8C, 0xBD9, 0xB2F, 0xA8E, 0x9F7, + 0x967, 0x8E0, 0x861, 0x7E8, 0x777, 0x70B, 0x6A6, 0x647, + 0x5EC, 0x597, 0x547, 0x4FB, 0x4B3, 0x470, 0x430, 0x3F4, + 0x3BB, 0x385, 0x353, 0x323, 0x2F6, 0x2CB, 0x2A3, 0x27D, + 0x259, 0x238, 0x218, 0x1FA, 0x1DD, 0x1C2, 0x1A9, 0x191, + 0x17B, 0x165, 0x151, 0x13E, 0x12C, 0x11C, 0x10C, 0x0FD, + 0x0EE, 0x0E1, 0x0D4, 0x0C8, 0x0BD, 0x0B2, 0x0A8, 0x09F, + 0x096, 0x08E, 0x086, 0x07E, 0x077, 0x070, 0x06A, 0x064, + 0x05E, 0x059, 0x054, 0x04F, 0x04B, 0x047, 0x043, 0x03F, + 0x03B, 0x038, 0x035, 0x032, 0x02F, 0x02C, 0x02A, 0x027, + 0x025, 0x023, 0x021, 0x01F, 0x01D, 0x01C, 0x01A, 0x019, + 0x017, 0x016, 0x015, 0x013, 0x012, 0x011, 0x010, 0x00F +}; - snd_adlibWriteData(1, 0x20); - snd_adlibWriteData(1, 0); +const int SoundDriver::_noteTableCount = ARRAYSIZE(_noteTable); - for (i = 0; i < 4; ++i) - snd_adlibInstrumentsTable[i] = snd_nullInstrument; +const int AdlibSoundDriver::_freqTable[] = { + 0x157, 0x16C, 0x181, 0x198, 0x1B1, 0x1CB, + 0x1E6, 0x203, 0x222, 0x243, 0x266, 0x28A +}; - snd_useAdlib = 1; - snd_driver = snd_adlibDriver; +const int AdlibSoundDriver::_freqTableCount = ARRAYSIZE(_freqTable); - _mixer->setupPremix(this); -} +const int AdlibSoundDriver::_operatorsTable[] = { + 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21 +}; -void AdlibMusic::premixerCall(int16 *data, uint len) { - snd_adlibInterrupt(NULL, data, len); -} +const int AdlibSoundDriver::_operatorsTableCount = ARRAYSIZE(_operatorsTable); -void AdlibMusic::setVolume(uint8 volume) { - for (int i = 0; i < 4; ++i) - snd_adlibChannelVolume[i] = volume | 128; -} +const int AdlibSoundDriver::_voiceOperatorsTable[] = { + 0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 16, 16, 14, 14, 17, 17, 13, 13 +}; -AdlibMusic::~AdlibMusic(void) { - _mixer->setupPremix(NULL); -} +const int AdlibSoundDriver::_voiceOperatorsTableCount = ARRAYSIZE(_voiceOperatorsTable); } // End of namespace Cine diff --git a/engines/cine/sound_driver.h b/engines/cine/sound_driver.h index 1dbc59ff85..a87673836e 100644 --- a/engines/cine/sound_driver.h +++ b/engines/cine/sound_driver.h @@ -22,8 +22,8 @@ * */ -#ifndef CINE_SNDDRIVER_H_ -#define CINE_SNDDRIVER_H_ +#ifndef CINE_SOUNDDRIVER_H_ +#define CINE_SOUNDDRIVER_H_ #include "sound/audiostream.h" #include "sound/fmopl.h" @@ -33,62 +33,111 @@ namespace Audio { } namespace Cine { - -#define ADLIB_REG_TIMER_1_DATA 2 -#define ADLIB_REG_TIMER_CONTROL_FLAGS 4 -#define ADLIB_REG_AM_VIBRATO_EG_KS 0x20 -#define ADLIB_REG_KEY_SCALING_OPERATOR_OUTPUT 0x40 -#define ADLIB_REG_ATTACK_RATE_DECAY_RATE 0x60 -#define ADLIB_REG_SUSTAIN_LEVEL_RELEASE_RATE_0 0x80 -#define ADLIB_REG_FREQUENCY_0 0xA0 -#define ADLIB_REG_KEY_ON_OCTAVE_FREQUENCY_0 0xB0 -#define ADLIB_REG_AM_VIBRATO_RHYTHM 0xBD -#define ADLIB_REG_FEEDBACK_STRENGTH_CONNECTION_TYPE 0xC0 -#define ADLIB_REG_WAVE_SELECT 0xE0 - -struct SoundDriver { - void (*setupChannel) (int channelNum, const uint8 * data, int instrumentNum); - void (*setChannelFrequency) (int channelNum, int frequency); - void (*stopChannel) (int channelNum); - void (*playSound) (uint8 * data, int channelNum, int volume); + +class SoundDriver { +public: + typedef void (*UpdateCallback)(void *); + + virtual void setupChannel(int channel, const uint8 *data, int instrument, int volume) = 0; + virtual void setChannelFrequency(int channel, int frequency) = 0; + virtual void stopChannel(int channel) = 0; + virtual void playSound(const uint8 *data, int channel, int volume) = 0; + virtual void stopSound() = 0; + virtual const char *getInstrumentExtension() const = 0; + + void setUpdateCallback(UpdateCallback upCb, void *ref); + void resetChannel(int channel); + void findNote(int freq, int *note, int *oct) const; + +protected: + UpdateCallback _upCb; + void *_upRef; + + static const int _noteTable[]; + static const int _noteTableCount; }; -extern uint16 snd_fadeOutCounter, snd_songTicksCounter; -extern uint8 *snd_adlibInstrumentsTable[4]; -extern SoundDriver snd_driver; - -extern void snd_adlibDriverInit(); -extern void snd_adlibDriverExit(); -extern void snd_adlibDriverStopSong(); -extern void snd_resetChannel(int channelNum); +struct AdlibRegisterSoundInstrument { + uint16 vibrato; + uint16 attackDecay; + uint16 sustainRelease; + uint16 feedbackStrength; + uint16 keyScaling; + uint16 outputLevel; + uint16 freqMod; +}; -class AdlibMusic : public AudioStream { +struct AdlibSoundInstrument { + uint8 mode; + uint8 channel; + AdlibRegisterSoundInstrument regMod; + AdlibRegisterSoundInstrument regCar; + uint8 waveSelectMod; + uint8 waveSelectCar; + uint8 amDepth; +}; + +class AdlibSoundDriver : public SoundDriver, AudioStream { public: - AdlibMusic(Audio::Mixer * pMixer); - ~AdlibMusic(void); - virtual void setVolume(uint8 volume); - - FM_OPL *getOPL() { - return _opl; - } - - // AudioStream API - int readBuffer(int16 *buffer, const int numSamples) { - premixerCall(buffer, numSamples / 2); - return numSamples; - } - bool isStereo() const { return true; } - bool endOfData() const { return false; } - int getRate() const { return _sampleRate; } - -private: + AdlibSoundDriver(Audio::Mixer *mixer); + virtual ~AdlibSoundDriver(); + + // SoundDriver interface + virtual void setupChannel(int channel, const uint8 *data, int instrument, int volume); + virtual void stopChannel(int channel); + virtual void stopSound(); + + // AudioStream interface + virtual int readBuffer(int16 *buffer, const int numSamples); + virtual bool isStereo() const { return true; } + virtual bool endOfData() const { return false; } + virtual int getRate() const { return _sampleRate; } + + void initCard(); + void update(int16 *buf, int len); + void setupInstrument(const uint8 *data, int channel); + void loadRegisterInstrument(const uint8 *data, AdlibRegisterSoundInstrument *reg); + virtual void loadInstrument(const uint8 *data, AdlibSoundInstrument *asi) = 0; + +protected: FM_OPL *_opl; - Audio::Mixer * _mixer; - uint32 _sampleRate; + int _sampleRate; + Audio::Mixer *_mixer; + + uint8 _vibrato; + int _channelsVolumeTable[4]; + AdlibSoundInstrument _instrumentsTable[4]; + + static const int _freqTable[]; + static const int _freqTableCount; + static const int _operatorsTable[]; + static const int _operatorsTableCount; + static const int _voiceOperatorsTable[]; + static const int _voiceOperatorsTableCount; +}; - void premixerCall(int16 *buf, uint len); +// Future Wars adlib driver +class AdlibSoundDriverINS : public AdlibSoundDriver { +public: + AdlibSoundDriverINS(Audio::Mixer *mixer) : AdlibSoundDriver(mixer) {} + virtual const char *getInstrumentExtension() const { return ".INS"; } + virtual void loadInstrument(const uint8 *data, AdlibSoundInstrument *asi); + virtual void setChannelFrequency(int channel, int frequency); + virtual void playSound(const uint8 *data, int channel, int volume); }; +// Operation Stealth adlib driver +class AdlibSoundDriverADL : public AdlibSoundDriver { +public: + AdlibSoundDriverADL(Audio::Mixer *mixer) : AdlibSoundDriver(mixer) {} + virtual const char *getInstrumentExtension() const { return ".ADL"; } + virtual void loadInstrument(const uint8 *data, AdlibSoundInstrument *asi); + virtual void setChannelFrequency(int channel, int frequency); + virtual void playSound(const uint8 *data, int channel, int volume); +}; + +extern SoundDriver *g_soundDriver; // TEMP + } // End of namespace Cine -#endif /* CINE_SNDDRIVER_H_ */ +#endif /* CINE_SOUNDDRIVER_H_ */ diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 061eec33c7..1251661679 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -153,10 +153,6 @@ commandeType defaultActionCommand[] = { selectedObjStruct currentSelectedObject; -void stopSample(void) { - snd_stopSong(); -} - void mainLoopSub3(void) { } @@ -475,7 +471,7 @@ int16 makeLoad(char *saveName) { return -1; } - stopSample(); + g_sfxPlayer->stop(); closeEngine3(); unloadAllMasks(); freePrcLinkedList(); |