aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorGregory Montoir2006-03-09 22:37:19 +0000
committerGregory Montoir2006-03-09 22:37:19 +0000
commit2cf5859404fe91e19c2d18d57c1955d314c5da06 (patch)
treecea410cf373e690ba2c94fd68bf3c390af5c023f /engines
parentf0106cd59c90d22799bb1517575a2d92a9027abe (diff)
downloadscummvm-rg350-2cf5859404fe91e19c2d18d57c1955d314c5da06.tar.gz
scummvm-rg350-2cf5859404fe91e19c2d18d57c1955d314c5da06.tar.bz2
scummvm-rg350-2cf5859404fe91e19c2d18d57c1955d314c5da06.zip
oo'ified sound code and added basic support for OS adlib music.
svn-id: r21186
Diffstat (limited to 'engines')
-rw-r--r--engines/cine/cine.cpp19
-rw-r--r--engines/cine/main_loop.cpp13
-rw-r--r--engines/cine/resource.cpp94
-rw-r--r--engines/cine/resource.h10
-rw-r--r--engines/cine/script.cpp31
-rw-r--r--engines/cine/sfx_player.cpp318
-rw-r--r--engines/cine/sfx_player.h65
-rw-r--r--engines/cine/sound_driver.cpp667
-rw-r--r--engines/cine/sound_driver.h151
-rw-r--r--engines/cine/various.cpp6
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, &note, &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, &note, &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();