From 52206f118933effa8ab8a7b465c76d97e985428f Mon Sep 17 00:00:00 2001 From: Alex Bevilacqua Date: Sun, 20 Sep 2009 21:10:43 +0000 Subject: [PATCH] ASYLUM: NEW SOUND SUBSYSTEM! This is still sort of WIP though because it's not a "true" implementation (direct from disassembly). It also doesn't really do anything with the new ambient sound queue, but the functionality's there for when we make more progress on the AmbientSoundItem initializations. Also started to re-write updateBarriers(). The original is there as updateBarriers2() for the time being. git-svn-id: http://asylumengine.googlecode.com/svn/trunk@362 0bfb4aae-4ea4-11de-8d8d-752d95cf3e3c --- engines/asylum/actionlist.cpp | 12 +- engines/asylum/asylum.cpp | 24 ++-- engines/asylum/asylum.h | 17 +++ engines/asylum/blowuppuzzle.cpp | 24 ++-- engines/asylum/blowuppuzzle.h | 1 + engines/asylum/menu.cpp | 15 ++- engines/asylum/respack.cpp | 2 +- engines/asylum/respack.h | 3 + engines/asylum/scene.cpp | 130 +++++++++++++++++- engines/asylum/scene.h | 2 +- engines/asylum/sound.cpp | 228 ++++++++++++++++++++++++++++++-- engines/asylum/sound.h | 61 ++++++--- engines/asylum/worldstats.cpp | 18 +++ engines/asylum/worldstats.h | 3 +- 14 files changed, 471 insertions(+), 69 deletions(-) diff --git a/engines/asylum/actionlist.cpp b/engines/asylum/actionlist.cpp index 747dfcc4b8b..a19bc67e908 100644 --- a/engines/asylum/actionlist.cpp +++ b/engines/asylum/actionlist.cpp @@ -611,10 +611,8 @@ int kEnableBarriers(ActionCommand *cmd, Scene *scn) { uint32 v59 = cmd->param2; if (!scn->actions()->getScript()->counter && scn->getSceneIndex() != 13 && sndIdx != 0) { - ResourcePack *sfx = new ResourcePack(18); - scn->vm()->sound()->playSfx(sfx, ((unsigned int)(sndIdx != 0) & 5) + 0x80120001); - delete sfx; - //scn->vm()->sound()->playSfx(scn->getSpeechPack(),sndIdx + 86); + scn->vm()->sound()->playSound(((sndIdx != 0) & 5) + 0x80120001, + false, scn->vm()->soundVolume(), 0); } if (scn->actions()->getScript()->counter >= 3 * v59 - 1) { @@ -805,7 +803,7 @@ int kPlayMovie(ActionCommand *cmd, Scene *scn) { int kStopAllBarriersSounds(ActionCommand *cmd, Scene *scn) { // TODO: do this for all barriers that have sfx playing - scn->vm()->sound()->stopSfx(); + scn->vm()->sound()->stopAllSounds(); return -1; } @@ -934,9 +932,9 @@ int kPlaySpeech(ActionCommand *cmd, Scene *scn) { if ((int)sndIdx >= 0) { if (sndIdx >= 259) { sndIdx -= 9; - scn->vm()->sound()->playSfx(scn->getSpeechPack(), sndIdx - 0x7FFD0000); + scn->vm()->sound()->playSpeech(sndIdx - 0x7FFD0000); } else { - scn->vm()->sound()->playSfx(scn->getSpeechPack(), sndIdx); + scn->vm()->sound()->playSpeech(sndIdx); } } else debugC(kDebugLevelScripts, diff --git a/engines/asylum/asylum.cpp b/engines/asylum/asylum.cpp index d9af080da60..08bf9bcf51f 100644 --- a/engines/asylum/asylum.cpp +++ b/engines/asylum/asylum.cpp @@ -54,6 +54,10 @@ AsylumEngine::AsylumEngine(OSystem *system, Common::Language language) g_eventRec.registerRandomSource(_rnd, "asylum"); memset(_gameFlags, 0, 1512); + + // initialize default configuration + _ambientVolume = 0; + _soundVolume = 0; } AsylumEngine::~AsylumEngine() { @@ -149,22 +153,18 @@ void AsylumEngine::waitForTimer(int msec_delay) { void AsylumEngine::playIntro() { _video->playVideo(1, kSubtitlesOn); + if (_scene->worldstats()->musicCurrentResId != 0xFFFFFD66) - _sound->playMusic(_scene->getMusicPack(), - _scene->worldstats()->musicCurrentResId); + _sound->playMusic(_scene->worldstats()->musicCurrentResId); _screen->clearScreen(); setGameFlag(4); setGameFlag(12); - ResourcePack *introRes = new ResourcePack(18); - - _sound->playSfx(introRes, 7); - - _introPlaying = true; - - delete introRes; + // Play the intro sound sample (the screen is blacked out, you hear + // an alarm sounding and men talking about. + _sound->playSound(0x8012007, false, _soundVolume, 0); } void AsylumEngine::checkForEvent(bool doUpdate) { // k_sub_40AE30 (0040AE30) @@ -178,7 +178,7 @@ void AsylumEngine::checkForEvent(bool doUpdate) { // k_sub_40AE30 (0040AE30) // by moving the logic to the event loop and checking whether a flag is // set to determine if control should be returned to the engine. if (_introPlaying) { - if (!_sound->isSfxActive()) { + if (!_sound->isPlaying(0x8012007)) { _introPlaying = false; // TODO Since we've currently only got one sfx handle to play with in @@ -258,7 +258,7 @@ void AsylumEngine::processDelayedEvents() { int videoIdx = _scene->actions()->delayedVideoIndex; if (videoIdx >= 0) { _sound->stopMusic(); - _sound->stopSfx(); + _sound->stopAllSounds(); _video->playVideo(videoIdx, kSubtitlesOn); _scene->actions()->delayedVideoIndex = -1; @@ -272,7 +272,7 @@ void AsylumEngine::processDelayedEvents() { int sceneIdx = _scene->actions()->delayedSceneIndex; if (sceneIdx >=0 && !_scene->actions()->processing) { _sound->stopMusic(); - _sound->stopSfx(); + _sound->stopAllSounds(); if (_scene) delete _scene; diff --git a/engines/asylum/asylum.h b/engines/asylum/asylum.h index 0bd6894603a..00f75069faf 100644 --- a/engines/asylum/asylum.h +++ b/engines/asylum/asylum.h @@ -39,6 +39,17 @@ namespace Asylum { +// XXX +// I'm not sure if system endian-ness would have any +// effect byte order of the data files, but I guess +// it won't hurt to keep this here until we can test +// on a big-endian system +#ifndef SCUMM_BIG_ENDIAN +#define LOBYTE(word) (word & 0xFF) +#else +#define LOBYTE(word) ((word >> 24) & 0xFF) +#endif + class Console; class Scene; class MainMenu; @@ -83,6 +94,9 @@ public: Screen* screen() { return _screen; } Scene* scene() { return _scene; } + int ambientVolume() { return _ambientVolume; } + int soundVolume() { return _soundVolume; } + private: void checkForEvent(bool doUpdate); void waitForTimer(int msec_delay); @@ -93,6 +107,9 @@ private: Common::Language _language; Common::RandomSource _rnd; + int _ambientVolume; + int _soundVolume; + bool _introPlaying; Console *_console; diff --git a/engines/asylum/blowuppuzzle.cpp b/engines/asylum/blowuppuzzle.cpp index 18669b7ea05..4611067a248 100644 --- a/engines/asylum/blowuppuzzle.cpp +++ b/engines/asylum/blowuppuzzle.cpp @@ -111,6 +111,12 @@ void BlowUpPuzzleVCR::handleEvent(Common::Event *event, bool doUpdate) { update(); } +void BlowUpPuzzle::playSound(uint resourceId) { + ResourceEntry *resource = _scene->getResourcePack()->getResource(resourceId); + int volume = _scene->vm()->soundVolume(); + _scene->vm()->sound()->playSound(resource, false, volume, 0); +} + int BlowUpPuzzleVCR::inPolyRegion(int x, int y, int polyIdx) { return x >= BlowUpPuzzleVCRPolies[polyIdx].left && x <= BlowUpPuzzleVCRPolies[polyIdx].right && y >= BlowUpPuzzleVCRPolies[polyIdx].top && y <= BlowUpPuzzleVCRPolies[polyIdx].bottom; @@ -318,13 +324,13 @@ int BlowUpPuzzleVCR::setJackOnHole(int jackType, JackState plugged) { if(_jacksState[jackType-1] == kOnHand) { _jacksState[jackType-1] = plugged; _holesState[plugged-1] = jackType; // set jack on red - _scene->vm()->sound()->playSfx(_scene->getResourcePack(), _scene->worldstats()->grResId[44]); + playSound(_scene->worldstats()->grResId[44]); } } else if(jackType == 0) { jackType = _holesState[plugged-1]; _jacksState[jackType-1] = kOnHand; _holesState[plugged-1] = 0; - _scene->vm()->sound()->playSfx(_scene->getResourcePack(), _scene->worldstats()->grResId[43]); + playSound(_scene->worldstats()->grResId[43]); return 0; } return 1; @@ -500,7 +506,7 @@ void BlowUpPuzzleVCR::handleMouseDown() { if (_cursor->x() >= (uint32)BlowUpPuzzleVCRPolies[kBlackJack].left && _cursor->x() <= (uint32)BlowUpPuzzleVCRPolies[kYellowJack].right && _cursor->y() >= (uint32)BlowUpPuzzleVCRPolies[kBlackJack].top && _cursor->y() <= (uint32)BlowUpPuzzleVCRPolies[kYellowJack].bottom) { _jacksState[jackType-1] = kOnTable; - _scene->vm()->sound()->playSfx(_scene->getResourcePack(), _scene->worldstats()->grResId[50]); + playSound(_scene->worldstats()->grResId[50]); _cursor->show(); } return; @@ -517,7 +523,7 @@ void BlowUpPuzzleVCR::handleMouseDown() { // TODO: VCR button regions if (inPolyRegion(_cursor->x(), _cursor->y(), kRewindButton)) { - _scene->vm()->sound()->playSfx(_scene->getResourcePack(), _scene->worldstats()->grResId[39]); + playSound(_scene->worldstats()->grResId[39]); if(!_buttonsState[kRewind]) { _buttonsState[kRewind] = kDownON; return; @@ -527,7 +533,7 @@ void BlowUpPuzzleVCR::handleMouseDown() { return; } } else if (inPolyRegion(_cursor->x(), _cursor->y(), kPlayButton)) { - _scene->vm()->sound()->playSfx(_scene->getResourcePack(), _scene->worldstats()->grResId[39]); + playSound(_scene->worldstats()->grResId[39]); if(!_buttonsState[kPlay]) { _buttonsState[kPlay] = kDownON; return; @@ -537,7 +543,7 @@ void BlowUpPuzzleVCR::handleMouseDown() { return; } } else if (inPolyRegion(_cursor->x(), _cursor->y(), kStopButton)) { - _scene->vm()->sound()->playSfx(_scene->getResourcePack(), _scene->worldstats()->grResId[39]); + playSound(_scene->worldstats()->grResId[39]); if(_buttonsState[kStop]) { if(_buttonsState[kStop] == kON) { _buttonsState[kStop] = kDownOFF; @@ -548,7 +554,7 @@ void BlowUpPuzzleVCR::handleMouseDown() { return; } } else if (inPolyRegion(_cursor->x(), _cursor->y(), kPowerButton)) { - _scene->vm()->sound()->playSfx(_scene->getResourcePack(), _scene->worldstats()->grResId[39]); + playSound(_scene->worldstats()->grResId[39]); if(!_buttonsState[kPower] && _holesState[kPluggedOnBlack-1] == kBlack+1 && _holesState[kPluggedOnRed-1] && _holesState[kPluggedOnYellow-1]) { _buttonsState[kPower] = kDownON; @@ -564,7 +570,7 @@ void BlowUpPuzzleVCR::handleMouseUp() { if(_buttonsState[kPower] == kDownON) { // TODO: check if next sound is already playing - _scene->vm()->sound()->playSfx(_scene->getResourcePack(), _scene->worldstats()->grResId[47]); + playSound(_scene->worldstats()->grResId[47]); _buttonsState[kPower] = kON; _buttonsState[kStop] = kON; _buttonsState[kPlay] = kON; @@ -579,7 +585,7 @@ void BlowUpPuzzleVCR::handleMouseUp() { if(_buttonsState[kRewind] == kDownOFF) { _buttonsState[kRewind] = kON; - _scene->vm()->sound()->playSfx(_scene->getResourcePack(), _scene->worldstats()->grResId[46]); + playSound(_scene->worldstats()->grResId[46]); } else if(_buttonsState[kRewind] == kDownON) { _buttonsState[kRewind] = kOFF; } diff --git a/engines/asylum/blowuppuzzle.h b/engines/asylum/blowuppuzzle.h index ada5988d751..01a100c18a5 100644 --- a/engines/asylum/blowuppuzzle.h +++ b/engines/asylum/blowuppuzzle.h @@ -66,6 +66,7 @@ protected: GraphicResource *_bgResource; virtual void update() {}; + void playSound(uint resourceId); }; // end of class BlowUpPuzzle diff --git a/engines/asylum/menu.cpp b/engines/asylum/menu.cpp index f71364ecefc..f085322d2f3 100644 --- a/engines/asylum/menu.cpp +++ b/engines/asylum/menu.cpp @@ -82,7 +82,12 @@ void MainMenu::openMenu() { _vm->screen()->setPalette(_resPack, 17); // Copy the bright background to the back buffer GraphicFrame *bg = _bgResource->getFrame(1); - _vm->screen()->copyToBackBuffer((byte *)bg->surface.pixels, bg->surface.w, 0, 0, bg->surface.w, bg->surface.h); + _vm->screen()->copyToBackBuffer((byte *)bg->surface.pixels, + bg->surface.w, + 0, + 0, + bg->surface.w, + bg->surface.h); // Set mouse cursor _cursor->load(2); @@ -90,7 +95,7 @@ void MainMenu::openMenu() { // Stop all sounds _vm->sound()->stopMusic(); - _vm->sound()->stopSfx(); + _vm->sound()->stopSound(); // Start playing music _vm->sound()->playMusic(_resPack, 39); @@ -105,7 +110,7 @@ void MainMenu::closeMenu() { _vm->scene()->activate(); // Stop menu sounds and menu music - _vm->sound()->stopSfx(); + _vm->sound()->stopSound(); _vm->sound()->stopMusic(); } @@ -284,8 +289,8 @@ void MainMenu::updateMainMenu() { _text->drawResTextCentered(MenuIconFixedXpos[iconNum], iconFrame->y + 50, _text->getResTextWidth(iconNum + 1309), iconNum + 1309); // Play creepy voice - if (!_vm->sound()->isSfxActive() && _activeIcon != _previousActiveIcon) { - _vm->sound()->playSfx(_resPack, iconNum + 44); + if (_activeIcon != _previousActiveIcon) { + _vm->sound()->playSound(_resPack, iconNum + 44, _vm->soundVolume()); _previousActiveIcon = _activeIcon; } diff --git a/engines/asylum/respack.cpp b/engines/asylum/respack.cpp index 8fc540900cf..52e234d890e 100644 --- a/engines/asylum/respack.cpp +++ b/engines/asylum/respack.cpp @@ -72,7 +72,7 @@ void ResourcePack::init(const char *resourceFile) { } ResourceEntry *ResourcePack::getResource(uint32 resourceId) { - uint16 index = resourceId & 0xFFFF; + uint16 index = RESIDX(resourceId); if (!_resources[index].data) { // Load the requested resource if it's not loaded already _packFile.seek(_resources[index].offset, SEEK_SET); diff --git a/engines/asylum/respack.h b/engines/asylum/respack.h index 97c0c160662..c7cabcdc5cd 100644 --- a/engines/asylum/respack.h +++ b/engines/asylum/respack.h @@ -31,6 +31,9 @@ namespace Asylum { +#define RESID(id) ((id >> 16) & 0x7FFF) +#define RESIDX(id) (id & 0XFFFF) + struct ResourceEntry { byte *data; uint32 size; diff --git a/engines/asylum/scene.cpp b/engines/asylum/scene.cpp index 1aa2490464a..f9998385130 100644 --- a/engines/asylum/scene.cpp +++ b/engines/asylum/scene.cpp @@ -69,7 +69,6 @@ Scene::Scene(uint8 sceneIdx, AsylumEngine *vm): _vm(vm) { _text = new Text(_vm->screen()); _resPack = new ResourcePack(sceneIdx); - _speechPack = new ResourcePack(3); // FIXME are all scene speech packs the same? // FIXME // Is there EVER more than one actor enabled for a scene? I can't @@ -139,6 +138,12 @@ Scene::Scene(uint8 sceneIdx, AsylumEngine *vm): _vm(vm) { } } + // XXX + // This is a hack for the moment to test out + // the new sound queuing functionality + for (uint i = 0; i < _ws->numAmbientSound; i++) + _vm->sound()->addToSoundBuffer(_ws->ambientSounds[i].resId); + // TODO: init action list } @@ -150,7 +155,6 @@ Scene::~Scene() { delete _cursor; delete _bgResource; delete _musPack; - delete _speechPack; delete _resPack; delete _text; delete _blowUp; @@ -267,7 +271,7 @@ int Scene::updateScene() { // Barriers startTick = _vm->_system->getMillis(); - updateBarriers(); + updateBarriers2(); debugC(kDebugLevelScene, "UpdateBarriers Time: %d", _vm->_system->getMillis() - startTick); // Ambient Sounds @@ -528,7 +532,38 @@ void Scene::updateActor(uint32 actorIdx) { } } +// XXX WIP void Scene::updateBarriers() { + int v1, v0, v32, v33, v34, tickVal, tickVal05, tickVal06; + v1 = v0 = v32 = v33 = v34 = tickVal = tickVal05 = tickVal06 = 0; + + uint32 start, v2, v31; + bool done = false; + //if (_ws->barriers.size() > 0); + + v2 = _ws->barriers[0].tickCount2; + for (uint32 idx = 0; idx < _ws->numBarriers; idx++) { + Barrier *b = &_ws->barriers[idx]; + start = _vm->_system->getMillis(); + + if (v2 - 32 != 4) + done = true; + + if (!done && !_ws->checkBarrierFlagsCondition(idx)) { + v31 = _vm->_system->getMillis(); + } + + /* + * TODO + */ + + v2 += 426; + v1 = 0; + done = false; + } +} + +void Scene::updateBarriers2() { Screen *screen = _vm->screen(); uint barriersCount = _ws->barriers.size(); @@ -669,6 +704,95 @@ void Scene::updateBarriers() { } void Scene::updateAmbientSounds() { + // if (cfgGameQualityValue > 3) + + int v2 = 1; + int v15, v11, v10, v16; + + int panning, volume; + + for (uint32 i = 0; i < _ws->numAmbientSound; i++) { + AmbientSoundItem *snd = &_ws->ambientSounds[i]; + for (uint32 f = 0; f < 6; f++) { + uint gameFlag = snd->flagNum[f]; + if (gameFlag >= 0) { + if (_vm->isGameFlagNotSet(gameFlag)) { + v2 = 0; + break; + } + } else { + if (_vm->isGameFlagSet(-gameFlag)) { + // XXX Looks like this just jumps back to + // the top of the loop, so not sure if this + // is somehow important + } + } + } + if (v2) { + if (_vm->sound()->isPlaying(snd->resId)) { + if (snd->field_0) { + ; // TODO volume calculation + } + } else { + if (snd->field_0) { + ; // TODO calculate panning at point + } else { + panning = 0; + } + + if (snd->field_0 == 0) { + volume = -(snd->field_C ^ 2); + } else { + ; // TODO calculate volume increase + } + + if (LOBYTE(snd->flags) & 2) { + if (rand() % 10000 < 10) { + if (snd->field_0) { + _vm->sound()->playSound(_resPack, snd->resId, false, _vm->ambientVolume() + volume, panning); + } else { + v15 = rand() % 500; + v11 = v15 * ((((rand() % 100 >= 50) - 1) & 2) - 1) + volume; + v10 = v11; + if ( v11 <= -10000 ) + v10 = -10000; + if ( v10 >= 0 ) + v11 = 0; + else + if ( v11 <= -10000 ) + v11 = -10000; + v16 = rand(); + _vm->sound()->playSound(_resPack, snd->resId, false, v11, v16 % 20001 - 10000); + } + } else { + if (LOBYTE(snd->flags) & 4) { + /* + if ( (unsigned int)*ambientPanningArray < getTickCount() ) + { + if ( v1->field_14 >= 0 ) + v12 = 60000 * v1->field_14 + getTickCount(); + else + v12 = getTickCount() - 1000 * v1->field_14; + *ambientPanningArray = v12; + playSound(v7, 0, v9, panning); + } + */ + } else { + if (LOBYTE(snd->flags) & 8) { + /* + if ( !*(ambientPanningArray - 15) ) + { + playSound(v7, 0, v9, panning); + *(ambientPanningArray - 15) = 1; + } + */ + } + } + } + } + } + } + } } void Scene::updateMusic() { diff --git a/engines/asylum/scene.h b/engines/asylum/scene.h index d62548f2dc6..fb415716a1c 100644 --- a/engines/asylum/scene.h +++ b/engines/asylum/scene.h @@ -69,7 +69,6 @@ public: Cursor* getCursor() { return _cursor; } ResourcePack* getResourcePack() { return _resPack; } ResourcePack* getMusicPack() { return _musPack; } - ResourcePack* getSpeechPack() { return _speechPack; } GraphicResource* getGraphicResource(uint32 entry) { return new GraphicResource(_resPack, entry); } BlowUpPuzzle* getBlowUpPuzzle() { return _blowUp; } @@ -110,6 +109,7 @@ private: void updateMouse(); void updateActor(uint32 actorIdx); void updateBarriers(); + void updateBarriers2(); // XXX Alexandre's version void updateAmbientSounds(); void updateMusic(); void updateAdjustScreen(); diff --git a/engines/asylum/sound.cpp b/engines/asylum/sound.cpp index 677e3169467..7327a94aa66 100644 --- a/engines/asylum/sound.cpp +++ b/engines/asylum/sound.cpp @@ -24,32 +24,240 @@ */ #include "asylum/sound.h" +#include "asylum/asylum.h" #include "common/stream.h" +#include "sound/audiostream.h" +#include "sound/adpcm.h" #include "sound/wave.h" namespace Asylum { Sound::Sound(Audio::Mixer *mixer) : _mixer(mixer) { + _speechPack = new ResourcePack(3); + _soundPack = new ResourcePack(18); } Sound::~Sound() { + delete _speechPack; + delete _soundPack; + + clearSoundBuffer(); } -void Sound::playSfx(byte *data, uint32 size) { - Common::MemoryReadStream *mem = new Common::MemoryReadStream(data, size); +// from engines/agos/sound.cpp +void convertVolume(int &vol) { + // DirectSound was orginally used, which specifies volume + // and panning differently than ScummVM does, using a logarithmic scale + // rather than a linear one. + // + // Volume is a value between -10,000 and 0. + // + // In both cases, the -10,000 represents -100 dB. When panning, only + // one speaker's volume is affected - just like in ScummVM - with + // negative values affecting the left speaker, and positive values + // affecting the right speaker. Thus -10,000 means the left speaker is + // silent. - // Now create the audio stream and play it (it's just a regular WAVE file) - Audio::AudioStream *sfx = Audio::makeWAVStream(mem, true); - _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, sfx); + int v = CLIP(vol, -10000, 0); + if (v) { + vol = (int)((double)Audio::Mixer::kMaxChannelVolume * pow(10.0, (double)v / 2000.0) + 0.5); + } else { + vol = Audio::Mixer::kMaxChannelVolume; + } } -void Sound::playMusic(byte *data, uint32 size) { - Common::MemoryReadStream *mem = new Common::MemoryReadStream(data, size); +// from engines/agos/sound.cpp +void convertPan(int &pan) { + // DirectSound was orginally used, which specifies volume + // and panning differently than ScummVM does, using a logarithmic scale + // rather than a linear one. + // + // Panning is a value between -10,000 and 10,000. + // + // In both cases, the -10,000 represents -100 dB. When panning, only + // one speaker's volume is affected - just like in ScummVM - with + // negative values affecting the left speaker, and positive values + // affecting the right speaker. Thus -10,000 means the left speaker is + // silent. - // Now create the audio stream and play it (it's just a regular WAVE file) - Audio::AudioStream *mus = Audio::makeWAVStream(mem, true); - _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, mus); + int p = CLIP(pan, -10000, 10000); + if (p < 0) { + pan = (int)(255.0 * pow(10.0, (double)p / 2000.0) + 127.5); + } else if (p > 0) { + pan = (int)(255.0 * pow(10.0, (double)p / -2000.0) - 127.5); + } else { + pan = 0; + } +} + +int Sound::getBufferPosition(uint32 resId) { + int pos = -1; + + for (uint i = 0; i < _soundBuffer.size(); i++) { + if (resId == _soundBuffer[i].resId) { + pos = i; + break; + } + } + + return pos; +} + +bool Sound::addToSoundBuffer(uint resId) { + int exists = getBufferPosition(resId); + + if (exists >= 0) { + SoundBufferItem sound; + sound.resId = resId; + _soundBuffer.push_back(sound); + } + + return (exists < 0) ? true : false; +} + +void Sound::clearSoundBuffer() { + _soundBuffer.clear(); +} + +bool Sound::isPlaying(uint resId) { + int pos = getBufferPosition(resId); + + if (pos < 0) { + warning("isPlaying: resId %d not currently bufferred", resId); + } else { + SoundBufferItem snd = _soundBuffer[pos]; + if (_mixer->isSoundHandleActive(snd.handle)) { + return true; + } + } + + return false; +} + +void Sound::playSound(ResourcePack *pack, uint resId, int volume, bool looping, int panning, bool overwrite) { + ResourceEntry *resource = pack->getResource(resId); + if (_mixer->isSoundHandleActive(_soundHandle)) { + if (overwrite) { + _mixer->stopHandle(_soundHandle); + playSound(resource, looping, volume, panning); + } + // if the current handle isn't active, play the sound + playSound(resource, looping, volume, panning); + } + +} + +void Sound::playSound(ResourceEntry *resource, bool looping, int volume, int panning) { + playSoundData(&_soundHandle, resource->data, resource->size, looping, volume, panning); +} + +void Sound::playSound(ResourcePack *pack, uint resId, bool looping, int volume, int panning) { + int pos = getBufferPosition(resId); + + if (pos < 0) { + warning("isPlaying: resId %d not currently bufferred", resId); + } else { + SoundBufferItem snd = _soundBuffer[pos]; + if (_mixer->isSoundHandleActive(snd.handle)) { + debugC(kDebugLevelSound, "playSound: handle for resId %d already active", resId); + } else { + ResourceEntry *ent = _soundPack->getResource(resId); + playSoundData(&snd.handle, ent->data, ent->size, looping, volume, panning); + } + } + +} + +void Sound::playSound(uint resId, bool looping, int volume, int panning, bool fromBuffer) { + if (fromBuffer) { + playSound(_soundPack, resId, looping, volume, panning); + } else { + if (_mixer->isSoundHandleActive(_soundHandle)) { + debugC(kDebugLevelSound, "playSound: temporary sound handle is active"); + } else { + ResourceEntry *ent = _soundPack->getResource(resId); + playSound(ent, looping, volume, panning); + } + } +} + +void Sound::stopSound() { + if (_mixer->isSoundHandleActive(_soundHandle)) + _mixer->stopHandle(_soundHandle); +} + +void Sound::stopSound(uint resId) { + int pos = getBufferPosition(resId); + + if (pos < 0) { + warning("isPlaying: resId %d not currently bufferred", resId); + } else { + _mixer->stopHandle(_soundBuffer[pos].handle); + } +} + +void Sound::stopAllSounds() { + _mixer->stopHandle(_soundHandle); + + for (uint i = 0; i < _soundBuffer.size(); i++) + _mixer->stopHandle(_soundBuffer[i].handle); +} + +void Sound::playSpeech(uint resId) { + ResourceEntry *ent = _speechPack->getResource(resId); + + _mixer->stopHandle(_speechHandle); + playSoundData(&_speechHandle, ent->data, ent->size, false, 0, 0); +} + +void Sound::playMusic(uint resId) { + stopMusic(); + + // TODO Play music :P +} + +void Sound::playMusic(ResourcePack *pack, uint resId) { + stopMusic(); + + ResourceEntry *resource = pack->getResource(resId); + playSoundData(&_musicHandle, resource->data, resource->size, true, 0, 0); +} + +void Sound::stopMusic() { + _mixer->stopHandle(_musicHandle); +} + +// from engines/agos/sound.cpp +void Sound::playSoundData(Audio::SoundHandle *handle, byte *soundData, uint soundDataLength, bool loop, int vol, int pan) { + byte *buffer, flags; + uint16 compType; + int blockAlign, rate; + + // TODO: Use makeWAVStream() in future, when makeADPCMStream() allows sound looping + int size = soundDataLength; + Common::MemoryReadStream stream(soundData, size); + if (!Audio::loadWAVFromStream(stream, size, rate, flags, &compType, &blockAlign)) + error("playSound: Not valid WAV data"); + + convertVolume(vol); + convertPan(pan); + + if (loop == true) + flags |= Audio::Mixer::FLAG_LOOP; + + if (compType == 2) { + Audio::AudioStream *sndStream = Audio::makeADPCMStream(&stream, false, size, Audio::kADPCMMS, rate, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1, blockAlign); + buffer = (byte *)malloc(size * 4); + size = sndStream->readBuffer((int16*)buffer, size * 2); + size *= 2; // 16bits. + delete sndStream; + } else { + buffer = (byte *)malloc(size); + memcpy(buffer, soundData + stream.pos(), size); + } + + _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer, size, rate, flags | Audio::Mixer::FLAG_AUTOFREE, -1, vol, pan); } } // end of namespace Asylum diff --git a/engines/asylum/sound.h b/engines/asylum/sound.h index ab73ff7f830..768390ff936 100644 --- a/engines/asylum/sound.h +++ b/engines/asylum/sound.h @@ -27,6 +27,7 @@ #define ASYLUM_SOUND_H_ #include "sound/mixer.h" + #include "asylum/respack.h" namespace Asylum { @@ -62,35 +63,55 @@ typedef struct AmbientSoundItem { } AmbientSoundItem; +typedef struct SoundBufferItem { + uint32 resId; + Audio::SoundHandle handle; + uint32 unknown; +} SoundBufferItem; + class Sound { public: Sound(Audio::Mixer *mixer); ~Sound(); - void playSfx(byte *data, uint32 size); - void playSfx(ResourcePack *resPack, uint32 resourceId) { - ResourceEntry *resEntry = resPack->getResource(resourceId); - playSfx(resEntry->data, resEntry->size); - } - bool isSfxActive() { return _mixer->isSoundHandleActive(_sfxHandle); } - void pauseSfx() { _mixer->pauseHandle(_sfxHandle, true); } - void resumeSfx() { _mixer->pauseHandle(_sfxHandle, false); } - void stopSfx() { _mixer->stopHandle(_sfxHandle); } + bool addToSoundBuffer(uint resId); + void clearSoundBuffer(); - void playMusic(byte *data, uint32 size); - void playMusic(ResourcePack *resPack, uint32 resourceId) { - ResourceEntry *resEntry = resPack->getResource(resourceId); - playMusic(resEntry->data, resEntry->size); - } - bool isMusicActive() { return _mixer->isSoundHandleActive(_musicHandle); } - void pauseMusic() { _mixer->pauseHandle(_musicHandle, true); } - void resumeMusic() { _mixer->pauseHandle(_musicHandle, false); } - void stopMusic() { _mixer->stopHandle(_musicHandle); } + /** + * Play a sound resource from the supplied resource pack. + * + * @param overwrite determine if _soundHandle should be overwritten if still active + */ + void playSound(ResourcePack *pack, uint resId, int volume, bool looping = false, int panning = 0, bool overwrite = false); + void playSound(ResourcePack *pack, uint resId, bool looping, int volume, int panning); + void playSound(ResourceEntry *resource, bool looping, int volume, int panning); + void playSound(uint resId, bool looping, int volume, int panning, bool fromBuffer = false); + void stopSound(uint resId); + void stopSound(); + void stopAllSounds(); + + void playSpeech(uint resId); + + void playMusic(ResourcePack *pack, uint resId); + void playMusic(uint resId); + void stopMusic(); + + bool isPlaying(uint resId); private: - Audio::SoundHandle _sfxHandle; - Audio::SoundHandle _musicHandle; Audio::Mixer *_mixer; + + Audio::SoundHandle _speechHandle; + Audio::SoundHandle _musicHandle; + Audio::SoundHandle _soundHandle; + + ResourcePack *_speechPack; + ResourcePack *_soundPack; + + Common::Array _soundBuffer; + + int getBufferPosition(uint32 resId); + void playSoundData(Audio::SoundHandle *handle, byte *soundData, uint32 soundDataLength, bool loop = false, int vol = 0, int pan = 0); }; } // end of namespace Asylum diff --git a/engines/asylum/worldstats.cpp b/engines/asylum/worldstats.cpp index e4aac738084..bfc1133480e 100644 --- a/engines/asylum/worldstats.cpp +++ b/engines/asylum/worldstats.cpp @@ -98,6 +98,24 @@ bool WorldStats::isBarrierVisible(uint32 idx) { return false; } +bool WorldStats::checkBarrierFlagsCondition(uint32 idx) { + Barrier *b = getBarrierByIndex(idx); + bool result; + + if (LOBYTE(b->flags) & 1) { + for (int i = 0; i < 10; i++) { + result = _scene->vm()->isGameFlagSet(b->gameFlags[i]); + if (result) + return result; + } + result = true; + } else { + result = false; + } + + return result; +} + // FIXME: load necessary World Stats content void WorldStats::load(Common::SeekableReadStream *stream) { size = stream->readUint32LE(); diff --git a/engines/asylum/worldstats.h b/engines/asylum/worldstats.h index de040be381c..76d2baf866e 100644 --- a/engines/asylum/worldstats.h +++ b/engines/asylum/worldstats.h @@ -154,7 +154,8 @@ public: bool isBarrierOnScreen(uint32 idx); bool isBarrierVisible(uint32 idx); - + // TODO this needs a better name + bool checkBarrierFlagsCondition(uint32 idx); private: Scene *_scene;