From b5aa521a75017a34b97a44fc1abae8afeb9f6da5 Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Sun, 13 May 2007 16:11:19 +0000 Subject: added basic support for sounds playback in Amiga versions (only tested with the demos) svn-id: r26837 --- engines/cine/anim.cpp | 13 ++++++ engines/cine/cine.cpp | 11 +++-- engines/cine/main_loop.cpp | 2 + engines/cine/script.cpp | 95 +++++++++++++++++++++++++++++++++++++------ engines/cine/script.h | 3 +- engines/cine/sound_driver.cpp | 71 +++++++++++++++++++++++++++++++- engines/cine/sound_driver.h | 49 +++++++++++++++++++--- 7 files changed, 221 insertions(+), 23 deletions(-) (limited to 'engines') diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index 1b452eefc8..a30c2bdff3 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -395,6 +395,18 @@ void loadSpl(const char *resourceName) { strcpy(animDataTable[entry].name, currentPartName); } +void loadSplAbs(const char *resourceName, uint16 idx) { + int16 foundFileIdx; + byte *dataPtr; + int16 entry; + + foundFileIdx = findFileInBundle(resourceName); + dataPtr = readBundleFile(foundFileIdx); + + entry = reserveFrame((uint16) partBuffer[foundFileIdx].unpackedSize, 1, 0, idx); + memcpy(animDataTable[entry].ptr1, dataPtr, partBuffer[foundFileIdx].unpackedSize); +} + void loadMsk(const char *resourceName) { int16 foundFileIdx; byte *dataPtr; @@ -877,6 +889,7 @@ void loadAbs(const char *resourceName, uint16 idx) { loadSeqAbs(resourceName, idx); return; } else if (strstr(resourceName, ".SPL")) { + loadSplAbs(resourceName, idx); return; } else if (strstr(resourceName, ".AMI")) { return; diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index 1a2ae7f53b..c6fde9cbba 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -95,10 +95,15 @@ int CineEngine::init() { _system->initSize(320, 200); _system->endGFXTransaction(); - if (g_cine->getGameType() == GType_FW) { - g_soundDriver = new AdlibSoundDriverINS(_mixer); + if (g_cine->getPlatform() == Common::kPlatformPC) { + if (g_cine->getGameType() == GType_FW) { + g_soundDriver = new AdlibSoundDriverINS(_mixer); + } else { + g_soundDriver = new AdlibSoundDriverADL(_mixer); + } } else { - g_soundDriver = new AdlibSoundDriverADL(_mixer); + // Paula chipset for Amiga and Atari versions + g_soundDriver = new PaulaSoundDriver(_mixer); } g_sfxPlayer = new SfxPlayer(g_soundDriver); g_saveFileMan = _saveFileMan; diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 7bf537b17c..33f25a43e4 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -32,6 +32,7 @@ #include "cine/sfx_player.h" #include "cine/various.h" #include "cine/bg_list.h" +#include "cine/sound_driver.h" namespace Cine { @@ -156,6 +157,7 @@ void manageEvents(int count) { if (i % 2) g_system->updateScreen(); g_system->delayMillis(10); + g_soundDriver->update(); manageEvents(0); } } diff --git a/engines/cine/script.cpp b/engines/cine/script.cpp index c0c1e82b10..bff7344bf7 100644 --- a/engines/cine/script.cpp +++ b/engines/cine/script.cpp @@ -356,9 +356,9 @@ void setupOpcodes() { NULL, NULL, NULL, - o1_playSample, + o2_playSample, /* 78 */ - o2_op78, + o2_playSampleAlt, o1_disableSystemMenu, o1_loadMask5, o1_unloadMask5, @@ -1702,16 +1702,31 @@ void o1_loadMusic() { void o1_playMusic() { debugC(5, kCineDebugScript, "Line: %d: playMusic()", _currentLine); + if (g_cine->getPlatform() == Common::kPlatformAmiga || + g_cine->getPlatform() == Common::kPlatformAtariST) { + warning("STUB: o1_playMusic"); + return; + } g_sfxPlayer->play(); } void o1_fadeOutMusic() { debugC(5, kCineDebugScript, "Line: %d: fadeOutMusic()", _currentLine); + if (g_cine->getPlatform() == Common::kPlatformAmiga || + g_cine->getPlatform() == Common::kPlatformAtariST) { + warning("STUB: o1_fadeOutMusic"); + return; + } g_sfxPlayer->fadeOut(); } void o1_stopSample() { debugC(5, kCineDebugScript, "Line: %d: stopSample()", _currentLine); + if (g_cine->getPlatform() == Common::kPlatformAmiga || + g_cine->getPlatform() == Common::kPlatformAtariST) { + warning("STUB: o1_stopSample"); + return; + } g_sfxPlayer->stop(); } @@ -1737,9 +1752,46 @@ void o1_op73() { getNextWord(); } +void o1_playSampleAmiga() { + int num = getNextByte(); + int channel = getNextByte(); + int freq = getNextWord(); + int repeat = getNextByte(); + int volume = getNextWord(); + int size = getNextWord(); + + if (size == 0xFFFF) { + size = animDataTable[num].width * animDataTable[num].height; + } + + if (channel < 10) { // || _currentOpcode == 0x78 + int channel1, channel2; + if (channel == 0) { + channel1 = 0; + channel2 = 1; + } else { + channel1 = 2; + channel2 = 3; + } + ((PaulaSoundDriver *)g_soundDriver)->queueSound(channel1, freq, animDataTable[num].ptr1, size, -1, volume, 63, repeat); + ((PaulaSoundDriver *)g_soundDriver)->queueSound(channel2, freq, animDataTable[num].ptr1, size, 1, volume, 0, repeat); + } else { + channel -= 10; + if (volume > 63) { + volume = 63; + } + ((PaulaSoundDriver *)g_soundDriver)->queueSound(channel, freq, animDataTable[num].ptr1, size, 0, 0, volume, repeat); + } +} + void o1_playSample() { debugC(5, kCineDebugScript, "Line: %d: playSample()", _currentLine); + if (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) { + o1_playSampleAmiga(); + return; + } + byte anim = getNextByte(); byte channel = getNextByte(); @@ -1749,12 +1801,6 @@ void o1_playSample() { int16 volume = getNextWord(); uint16 flag = getNextWord(); - if (g_cine->getPlatform() == Common::kPlatformAmiga || - g_cine->getPlatform() == Common::kPlatformAtariST) { - warning("STUB: o1_playSample"); - return; - } - if (volume > 63) volume = 63; if (volume < 0) @@ -1771,7 +1817,7 @@ void o1_playSample() { g_sfxPlayer->stop(); if (flag == 0xFFFF) { - g_soundDriver->playSound(animDataTable[anim].ptr1, channel, volume); + g_soundDriver->playSound(animDataTable[anim].ptr1, 0, channel, volume); } else { g_soundDriver->resetChannel(channel); } @@ -1809,12 +1855,37 @@ void o2_loadPart() { debugC(5, kCineDebugScript, "Line: %d: loadPart(\"%s\")", _currentLine, param); } -void o2_op78() { - warning("STUB: o2_op78()"); - // This is probably wrong, but preserve the old behaviour for now. +void o2_playSample() { + if (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) { + // no-op in these versions + _currentPosition += 9; + return; + } o1_playSample(); } +void o2_playSampleAlt() { + int num = getNextByte(); + int channel = getNextByte(); + int freq = getNextWord(); + getNextByte(); + getNextWord(); + int size = getNextWord(); + + if (size == 0xFFFF) { + size = animDataTable[num].width * animDataTable[num].height; + } + if (animDataTable[num].ptr1) { + if (g_cine->getPlatform() == Common::kPlatformPC) { + // if speaker output is enabled, play sound on it + // if it's another device, don't play anything + } else { + g_soundDriver->setChannelFrequency(channel, freq); + g_soundDriver->playSound(animDataTable[num].ptr1, size, channel, 63); + } + } +} + void o2_addSeqListElement() { byte param1 = getNextByte(); byte param2 = getNextByte(); diff --git a/engines/cine/script.h b/engines/cine/script.h index e777c1fb6f..91e403d701 100644 --- a/engines/cine/script.h +++ b/engines/cine/script.h @@ -146,7 +146,8 @@ void o1_unloadMask5(); void o2_loadPart(); void o2_addSeqListElement(); void o2_removeSeq(); -void o2_op78(); +void o2_playSample(); +void o2_playSampleAlt(); void o2_op81(); void o2_op82(); void o2_isSeqRunning(); diff --git a/engines/cine/sound_driver.cpp b/engines/cine/sound_driver.cpp index 5d1c71cef8..19d94e38a3 100644 --- a/engines/cine/sound_driver.cpp +++ b/engines/cine/sound_driver.cpp @@ -283,7 +283,7 @@ void AdlibSoundDriverINS::setChannelFrequency(int channel, int frequency) { } } -void AdlibSoundDriverINS::playSound(const byte *data, int channel, int volume) { +void AdlibSoundDriverINS::playSound(const byte *data, int size, int channel, int volume) { assert(channel < 4); _channelsVolumeTable[channel] = 127; resetChannel(channel); @@ -356,7 +356,7 @@ void AdlibSoundDriverADL::setChannelFrequency(int channel, int frequency) { } } -void AdlibSoundDriverADL::playSound(const byte *data, int channel, int volume) { +void AdlibSoundDriverADL::playSound(const byte *data, int size, int channel, int volume) { assert(channel < 4); _channelsVolumeTable[channel] = 127; setupInstrument(data, channel); @@ -429,4 +429,71 @@ const int AdlibSoundDriver::_voiceOperatorsTable[] = { const int AdlibSoundDriver::_voiceOperatorsTableCount = ARRAYSIZE(_voiceOperatorsTable); + +PaulaSoundDriver::PaulaSoundDriver(Audio::Mixer *mixer) + : _mixer(mixer) { + memset(_channelsFreqTable, 0, sizeof(_channelsFreqTable)); + memset(_soundsQueue, 0, sizeof(_soundsQueue)); +} + +void PaulaSoundDriver::setupChannel(int channel, const byte *data, int instrument, int volume) { +} + +void PaulaSoundDriver::setChannelFrequency(int channel, int frequency) { + assert(frequency > 0); + _channelsFreqTable[channel] = PAULA_FREQ / frequency; +} + +void PaulaSoundDriver::stopChannel(int channel) { + _mixer->stopHandle(_channelsTable[channel]); +} + +void PaulaSoundDriver::playSound(const byte *data, int size, int channel, int volume) { + stopChannel(channel); + size = MIN(size - SPL_HDR_SIZE, READ_BE_UINT16(data + 4)); + data += SPL_HDR_SIZE; + if (size > 0) { + _mixer->playRaw(Audio::Mixer::kSFXSoundType, &_channelsTable[channel], const_cast(data), size, _channelsFreqTable[channel], 0); + _mixer->setChannelVolume(_channelsTable[channel], volume * Audio::Mixer::kMaxChannelVolume / 63); + } +} + +void PaulaSoundDriver::stopSound() { + for (int i = 0; i < NUM_CHANNELS; ++i) { + _mixer->stopHandle(_channelsTable[i]); + } +} + +void PaulaSoundDriver::queueSound(int channel, int frequency, const uint8 *data, int size, int volumeStep, int stepCount, int volume, int repeat) { + SoundQueue *sq = &_soundsQueue[channel]; + sq->freq = frequency; + sq->data = data; + sq->size = size; + sq->volumeStep = volumeStep; + sq->stepCount = stepCount; + sq->step = stepCount; + sq->repeat = repeat != 0; + sq->volume = volume; +} + +void PaulaSoundDriver::update() { + // process volume slides and start sound playback + for (int i = 0; i < NUM_CHANNELS; ++i) { + SoundQueue *sq = &_soundsQueue[i]; + if (sq->data) { + if (sq->step) { + --sq->step; + continue; + } + sq->step = sq->stepCount; + sq->volume = CLIP(sq->volume + sq->volumeStep, 0, 63); + setChannelFrequency(i, sq->freq); + playSound(sq->data, sq->size, i, sq->volume); + if (!sq->repeat) { + sq->data = 0; + } + } + } +} + } // End of namespace Cine diff --git a/engines/cine/sound_driver.h b/engines/cine/sound_driver.h index c6fc571f89..6ca1fa8f5a 100644 --- a/engines/cine/sound_driver.h +++ b/engines/cine/sound_driver.h @@ -30,7 +30,7 @@ #include "sound/mixer.h" namespace Cine { - + class SoundDriver { public: typedef void (*UpdateCallback)(void *); @@ -40,9 +40,10 @@ public: virtual void setupChannel(int channel, const byte *data, int instrument, int volume) = 0; virtual void setChannelFrequency(int channel, int frequency) = 0; virtual void stopChannel(int channel) = 0; - virtual void playSound(const byte *data, int channel, int volume) = 0; + virtual void playSound(const byte *data, int size, int channel, int volume) = 0; virtual void stopSound() = 0; - virtual const char *getInstrumentExtension() const = 0; + virtual const char *getInstrumentExtension() const { return ""; } + virtual void update() {} void setUpdateCallback(UpdateCallback upCb, void *ref); void resetChannel(int channel); @@ -123,7 +124,7 @@ public: virtual const char *getInstrumentExtension() const { return ".INS"; } virtual void loadInstrument(const byte *data, AdlibSoundInstrument *asi); virtual void setChannelFrequency(int channel, int frequency); - virtual void playSound(const byte *data, int channel, int volume); + virtual void playSound(const byte *data, int size, int channel, int volume); }; // Operation Stealth adlib driver @@ -133,7 +134,45 @@ public: virtual const char *getInstrumentExtension() const { return ".ADL"; } virtual void loadInstrument(const byte *data, AdlibSoundInstrument *asi); virtual void setChannelFrequency(int channel, int frequency); - virtual void playSound(const byte *data, int channel, int volume); + virtual void playSound(const byte *data, int size, int channel, int volume); +}; + +class PaulaSoundDriver : public SoundDriver { +public: + PaulaSoundDriver(Audio::Mixer *mixer); + + virtual void setupChannel(int channel, const byte *data, int instrument, int volume); + virtual void setChannelFrequency(int channel, int frequency); + virtual void stopChannel(int channel); + virtual void playSound(const byte *data, int size, int channel, int volume); + virtual void stopSound(); + + // Future Wars specific + void queueSound(int channel, int frequency, const uint8 *data, int size, int volumeStep, int stepCount, int volume, int repeat); + virtual void update(); + + enum { + PAULA_FREQ = 7093789, + NUM_CHANNELS = 4, + SPL_HDR_SIZE = 22 + }; + + struct SoundQueue { + int freq; + const uint8 *data; + int size; + int volumeStep; + int stepCount; + int step; + bool repeat; + int volume; + }; + +private: + Audio::Mixer *_mixer; + Audio::SoundHandle _channelsTable[NUM_CHANNELS]; + uint _channelsFreqTable[NUM_CHANNELS]; + SoundQueue _soundsQueue[NUM_CHANNELS]; }; extern SoundDriver *g_soundDriver; // TEMP -- cgit v1.2.3