From fc0e40db304aa489d4117299fcce1f80ba0b6379 Mon Sep 17 00:00:00 2001 From: johndoe123 Date: Sat, 22 Sep 2012 00:55:40 +0000 Subject: NEVERHOOD: Implement the actual audio code Sounds and music play now in some scenes (I didn't change the comments to code in all modules yet) - Fix calcHash to ignore non-alphanumeric characters, this fixes at least one animation glitch (when inserting tapes into the player) - Move SoundResource to sound.cpp --- engines/neverhood/entity.h | 1 + engines/neverhood/gamemodule.cpp | 6 +- engines/neverhood/klayman.cpp | 20 +- engines/neverhood/klayman.h | 2 +- engines/neverhood/module1000.cpp | 20 +- engines/neverhood/module1100.cpp | 45 ++-- engines/neverhood/module1200.cpp | 27 +-- engines/neverhood/module1300.cpp | 42 ++-- engines/neverhood/module1400.cpp | 40 ++-- engines/neverhood/navigationscene.h | 2 + engines/neverhood/neverhood.cpp | 4 + engines/neverhood/neverhood.h | 2 + engines/neverhood/resource.cpp | 44 +--- engines/neverhood/resource.h | 16 -- engines/neverhood/resourceman.cpp | 2 +- engines/neverhood/scene.cpp | 16 +- engines/neverhood/sound.cpp | 463 ++++++++++++++++++++++++++++++++---- engines/neverhood/sound.h | 120 ++++++++++ 18 files changed, 673 insertions(+), 199 deletions(-) diff --git a/engines/neverhood/entity.h b/engines/neverhood/entity.h index 9256c13ba8..22eb780024 100644 --- a/engines/neverhood/entity.h +++ b/engines/neverhood/entity.h @@ -27,6 +27,7 @@ #include "neverhood/neverhood.h" #include "neverhood/gamevars.h" #include "neverhood/graphics.h" +#include "neverhood/sound.h" namespace Neverhood { diff --git a/engines/neverhood/gamemodule.cpp b/engines/neverhood/gamemodule.cpp index e2494af453..7841e278c3 100644 --- a/engines/neverhood/gamemodule.cpp +++ b/engines/neverhood/gamemodule.cpp @@ -298,9 +298,9 @@ uint32 GameModule::handleMessage(int messageNum, const MessageParam ¶m, Enti void GameModule::startup() { // TODO: Displaying of error text probably not needed in ScummVM // createModule(1500, 0); // Logos and intro video //Real -#if 0 +#if 1 _vm->gameState().sceneNum = 0; - createModule(1200, -1); + createModule(1400, -1); #endif #if 0 _vm->gameState().sceneNum = 0; @@ -339,7 +339,7 @@ void GameModule::startup() { _vm->gameState().sceneNum = 8; createModule(2600, -1); #endif -#if 1 +#if 0 _vm->gameState().which = 0; _vm->gameState().sceneNum = 1; createModule(2700, -1); diff --git a/engines/neverhood/klayman.cpp b/engines/neverhood/klayman.cpp index ca30e3bccb..00008830e7 100644 --- a/engines/neverhood/klayman.cpp +++ b/engines/neverhood/klayman.cpp @@ -60,7 +60,7 @@ static const KlaymanIdleTableItem klaymanTable4[] = { Klayman::Klayman(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y, int surfacePriority, int objectPriority, NRectArray *clipRects) : AnimatedSprite(vm, objectPriority), _soundResource1(vm), _soundResource2(vm), _counterMax(0), _counter(0), _isMoveObjectRequested(false), _counter3Max(0), _isWalkingOpenDoorNotified(false), _counter1(0), - _counter2(0), /*_field118(0), */_status2(0), _acceptInput(true), _attachedSprite(NULL), _isWalking(false), + _tapesToInsert(0), /*_field118(0), */_status2(0), _acceptInput(true), _attachedSprite(NULL), _isWalking(false), _status3(1), _parentScene(parentScene), _isSneaking(false), _isLargeStep(false), _flagF6(false), _isLeverDown(false), _flagFA(false), _ladderStatus(0), _pathPoints(NULL), _resourceHandle(-1), _soundFlag(false) { @@ -2119,16 +2119,16 @@ void Klayman::cbLeverReleasedEvent() { void Klayman::stInsertDisk() { if (!stStartActionFromIdle(AnimationCallback(&Klayman::stInsertDisk))) { _status2 = 2; - _counter2 = 0; + _tapesToInsert = 0; for (uint32 i = 0; i < 20; i++) { if (getSubVar(0x02038314, i)) { setSubVar(0x02720344, i, 1); setSubVar(0x02038314, i, 0); - _counter2++; + _tapesToInsert++; } } - if (_counter2 == 0) { - gotoState(NULL); + if (_tapesToInsert == 0) { + GotoState(NULL); gotoNextStateExt(); } else { startAnimation(0xD8C8D100, 0, -1); @@ -2136,7 +2136,7 @@ void Klayman::stInsertDisk() { SetSpriteUpdate(&Klayman::spriteUpdate41F250); SetMessageHandler(&Klayman::hmInsertDisk); _acceptInput = false; - _counter2--; + _tapesToInsert--; } } } @@ -2145,12 +2145,12 @@ uint32 Klayman::hmInsertDisk(int messageNum, const MessageParam ¶m, Entity * switch (messageNum) { case 0x100D: if (param.asInteger() == 0x06040580) { - if (_counter2 == 0) { - // TODO: Calc calcHash value somewhere else + if (_tapesToInsert == 0) { + // TODO: Calc calcHash value somewhere else nextAnimationByHash(0xD8C8D100, calcHash("GoToStartLoop/Finish"), 0); } - } else if (_counter2 != 0 && param.asInteger() == calcHash("GoToStartLoop/Finish")) { - _counter2--; + } else if (_tapesToInsert != 0 && param.asInteger() == calcHash("GoToStartLoop/Finish")) { + _tapesToInsert--; startAnimationByHash(0xD8C8D100, 0x01084280, 0); } else if (param.asInteger() == 0x062A1510) { _soundResource1.play(0x41688704); diff --git a/engines/neverhood/klayman.h b/engines/neverhood/klayman.h index b752b1ecdb..cbf17a01f8 100644 --- a/engines/neverhood/klayman.h +++ b/engines/neverhood/klayman.h @@ -185,7 +185,7 @@ protected: int16 _counter, _counterMax; int16 _counter3, _counter3Max; int16 _counter1; - int16 _counter2; + int16 _tapesToInsert; bool _flagF6; bool _isLeverDown; bool _isWalkingOpenDoorNotified; diff --git a/engines/neverhood/module1000.cpp b/engines/neverhood/module1000.cpp index 1c30681401..2db598bb3e 100644 --- a/engines/neverhood/module1000.cpp +++ b/engines/neverhood/module1000.cpp @@ -31,8 +31,8 @@ Module1000::Module1000(NeverhoodEngine *vm, Module *parentModule, int which) _musicFileHash = getGlobalVar(0xD0A14D10) ? 0x81106480 : 0x00103144; - // TODO SoundMan_addMusic(0x03294419, 0x061880C6); - // TODO SoundMan_addMusic(0x03294419, _musicFileHash); + _vm->_soundMan->addMusic(0x03294419, 0x061880C6); + _vm->_soundMan->addMusic(0x03294419, _musicFileHash); if (which < 0) { createScene(_vm->gameState().sceneNum, -1); @@ -45,7 +45,7 @@ Module1000::Module1000(NeverhoodEngine *vm, Module *parentModule, int which) } Module1000::~Module1000() { - // TODO SoundMan_deleteMusicGroup(0x03294419); + _vm->_soundMan->deleteMusicGroup(0x03294419); } void Module1000::createScene(int sceneNum, int which) { @@ -53,24 +53,24 @@ void Module1000::createScene(int sceneNum, int which) { _vm->gameState().sceneNum = sceneNum; switch (_vm->gameState().sceneNum) { case 0: - // TODO SoundMan_startMusic(0x061880C6, 0, 0, 1); + _vm->_soundMan->startMusic(0x061880C6, 0, 0); _childObject = new Scene1001(_vm, this, which); break; case 1: - // TODO SoundMan_startMusic(0x061880C6, 0, 0, 1); + _vm->_soundMan->startMusic(0x061880C6, 0, 0); _childObject = new Scene1002(_vm, this, which); break; case 2: - // TODO SoundMan_startMusic(0x061880C6, 0, 0); + _vm->_soundMan->startMusic(0x061880C6, 0, 0); _childObject = new Class152(_vm, this, 0xC084110C, 0x41108C00); break; case 3: - // TODO SoundMan_stopMusic(0x061880C6, 0, 2); + _vm->_soundMan->stopMusic(0x061880C6, 0, 2); _childObject = new Scene1004(_vm, this, which); break; case 4: - // TODO SoundMan_stopMusic(0x061880C6, 0, 0); - // TODO SoundMan_startMusic(_musicFileHash, 0, 0, 1); + _vm->_soundMan->stopMusic(0x061880C6, 0, 0); + _vm->_soundMan->startMusic(_musicFileHash, 0, 0); _childObject = new Scene1005(_vm, this, which); break; } @@ -105,7 +105,7 @@ void Module1000::updateScene() { createScene(1, 2); break; case 4: - // TODO SoundMan_stopMusic(_musicFileHash, 0, 1); + _vm->_soundMan->stopMusic(_musicFileHash, 0, 1); createScene(3, 1); break; } diff --git a/engines/neverhood/module1100.cpp b/engines/neverhood/module1100.cpp index 8b73598e03..e948c2b045 100644 --- a/engines/neverhood/module1100.cpp +++ b/engines/neverhood/module1100.cpp @@ -22,6 +22,7 @@ #include "neverhood/module1100.h" #include "neverhood/gamemodule.h" +#include "neverhood/navigationscene.h" namespace Neverhood { @@ -36,16 +37,16 @@ Module1100::Module1100(NeverhoodEngine *vm, Module *parentModule, int which) createScene(9, 3); } - // TODO SoundMan_addSoundList(0x2C818, dword_4B85B0, true); + // TODO SoundMan_addSoundList(0x0002C818, dword_4B85B0, true); // TODO SoundMan_setSoundListParams(dword_4B85B0, true, 50, 600, 20, 250); - // TODO SoundMan_setSoundParams(0x74E01054, false, 100, 200, 10, 20); - // TODO SoundMan_setSoundVolume(0x74E01054, 60); - // TODO SoundMan_playTwoSounds(0x2C818, 0x41861371, 0x43A2507F); + _vm->_soundMan->setSoundParams(0x74E01054, false, 100, 200, 10, 20); + _vm->_soundMan->setSoundVolume(0x74E01054, 60); + _vm->_soundMan->playTwoSounds(0x0002C818, 0x41861371, 0x43A2507F, 0); } Module1100::~Module1100() { - // TODO SoundMan_deleteGroup(0x2C818); + _vm->_soundMan->deleteGroup(0x0002C818); } void Module1100::createScene(int sceneNum, int which) { @@ -86,11 +87,11 @@ void Module1100::createScene(int sceneNum, int which) { createSmackerScene(0x04180007, true, false, false); break; case 6: - // TODO SoundMan_deleteSoundGroup(0x2C818); + _vm->_soundMan->deleteSoundGroup(0x0002C818); createSmackerScene(kSmackerFileHashList06, true, true, false); break; case 7: - // TODO SoundMan_setSoundParams(0x74E01054, false, 0, 0, 0, 0); + _vm->_soundMan->setSoundParams(0x74E01054, false, 0, 0, 0, 0); createSmackerScene(kSmackerFileHashList07, true, true, false); break; case 8: @@ -98,7 +99,7 @@ void Module1100::createScene(int sceneNum, int which) { break; case 1002: _countdown = 40; - // TODO SoundMan_setTwoSoundsPlayFlag(true); + _vm->_soundMan->setTwoSoundsPlayFlag(true); createSmackerScene(0x00012211, true, true, false); break; } @@ -111,9 +112,9 @@ void Module1100::updateScene() { switch (_vm->gameState().sceneNum) { case 0: _countdown = 0; - // TODO SoundMan_playTwoSounds(0x2C818, 0x48498E46, 0x50399F64); - // TODO SoundMan_setSoundVolume(0x48498E46, 65); - // TODO SoundMan_setSoundVolume(0x50399F64, 65); + _vm->_soundMan->playTwoSounds(0x0002C818, 0x48498E46, 0x50399F64, 0); + _vm->_soundMan->setSoundVolume(0x48498E46, 65); + _vm->_soundMan->setSoundVolume(0x50399F64, 65); if (_moduleResult == 0) { createScene(1, 0); } else if (_moduleResult == 1) { @@ -121,7 +122,7 @@ void Module1100::updateScene() { } break; case 1: - // TODO SoundMan_playTwoSounds(0x2C818, 0x41861371, 0x43A2507F); + _vm->_soundMan->playTwoSounds(0x0002C818, 0x41861371, 0x43A2507F, 0); if (getGlobalVar(0x0C0288F4)) { if (_moduleResult == 0) { createScene(6, -1); @@ -137,7 +138,7 @@ void Module1100::updateScene() { } break; case 2: - // TODO SoundMan_setSoundParams(0x74E01054, false, 0, 0, 0, 0); + _vm->_soundMan->setSoundParams(0x74E01054, false, 0, 0, 0, 0); if (_navigationAreaType == 3) { createScene(7, -1); } else if (_moduleResult == 1) { @@ -161,6 +162,7 @@ void Module1100::updateScene() { } break; case 5: + _vm->_soundMan->setTwoSoundsPlayFlag(false); if (getGlobalVar(0x610210B7)) { createScene(3, 0); } else { @@ -168,9 +170,11 @@ void Module1100::updateScene() { } break; case 6: + _vm->_soundMan->setTwoSoundsPlayFlag(false); leaveModule(1); break; case 7: + _vm->_soundMan->setTwoSoundsPlayFlag(false); createScene(2, 2); break; case 8: @@ -181,8 +185,9 @@ void Module1100::updateScene() { } break; case 1002: + _vm->_soundMan->setTwoSoundsPlayFlag(false); _countdown = 0; - // TODO SoundMan_playTwoSounds(0x2C818, 0x48498E46, 0x50399F64, 0); + _vm->_soundMan->playTwoSounds(0x0002C818, 0x48498E46, 0x50399F64, 0); createScene(1, 1); break; } @@ -191,7 +196,7 @@ void Module1100::updateScene() { case 0: #if 0 // TODO if (navigationScene()->soundFlag1 && _countdown != 0 && (--_countdown == 0)) { - SoundMan_playTwoSounds(0x2C818, 0x48498E46, 0x50399F64); + SoundMan_playTwoSounds(0x0002C818, 0x48498E46, 0x50399F64); SoundMan_setSoundVolume(0x48498E46, 65); SoundMan_setSoundVolume(0x50399F64, 65); } @@ -200,21 +205,21 @@ void Module1100::updateScene() { case 1: #if 0 // TODO if (navigationScene()->soundFlag1 && _countdown != 0 && (--_countdown == 0)) { - SoundMan_playTwoSounds(0x2C818, 0x41861371, 0x43A2507F); + SoundMan_playTwoSounds(0x0002C818, 0x41861371, 0x43A2507F); } #endif break; case 2: - // TODO SoundMan_setSoundParams(0x74E01054, !navigationScene()->soundFlag1, 0, 0, 0, 0); + _vm->_soundMan->setSoundParams(0x74E01054, !navigationScene()->getSoundFlag1(), 0, 0, 0, 0); break; case 5: case 6: case 7: case 1002: if (_countdown != 0 && (--_countdown == 0)) { - // TODO SoundMan_playTwoSounds(0x2C818, 0x48498E46, 0x50399F64); - // TODO SoundMan_setSoundVolume(0x48498E46, 65); - // TODO SoundMan_setSoundVolume(0x50399F64, 65); + _vm->_soundMan->playTwoSounds(0x0002C818, 0x48498E46, 0x50399F64, 0); + _vm->_soundMan->setSoundVolume(0x48498E46, 65); + _vm->_soundMan->setSoundVolume(0x50399F64, 65); } break; } diff --git a/engines/neverhood/module1200.cpp b/engines/neverhood/module1200.cpp index 7599d7655d..33b791aa9b 100644 --- a/engines/neverhood/module1200.cpp +++ b/engines/neverhood/module1200.cpp @@ -39,12 +39,12 @@ Module1200::Module1200(NeverhoodEngine *vm, Module *parentModule, int which) createScene(0, 0); } - // TODO SoundMan_addMusic(0x00478311, 0x62222CAE); - // TODO SoundMan_startMusic(0x62222CAE, 0, 0, 1); + _vm->_soundMan->addMusic(0x00478311, 0x62222CAE); + _vm->_soundMan->startMusic(0x62222CAE, 0, 0); } Module1200::~Module1200() { - // TODO SoundMan_deleteMusicGroup(0x00478311); + _vm->_soundMan->deleteMusicGroup(0x00478311); } void Module1200::createScene(int sceneNum, int which) { @@ -58,7 +58,7 @@ void Module1200::createScene(int sceneNum, int which) { _childObject = new Scene1202(_vm, this, which); break; case 2: - // TODO SoundMan_stopMusic(0x62222CAE, 0, 0); + _vm->_soundMan->stopMusic(0x62222CAE, 0, 0); createSmackerScene(0x31890001, true, true, false); setGlobalVar(0x2A02C07B, 1); break; @@ -87,7 +87,7 @@ void Module1200::updateScene() { createScene(0, 1); break; case 2: - // TODO SoundMan_startMusic(0x62222CAE, 0, 0, 1); + _vm->_soundMan->startMusic(0x62222CAE, 0, 0); createScene(0, 3); break; } @@ -371,7 +371,7 @@ AsScene1201TntMan::AsScene1201TntMan(NeverhoodEngine *vm, Scene *parentScene, Sp } AsScene1201TntMan::~AsScene1201TntMan() { - // TODO SoundMan_deleteSoundGroup(0x01D00560); + _vm->_soundMan->deleteSoundGroup(0x01D00560); } uint32 AsScene1201TntMan::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -426,8 +426,8 @@ void AsScene1201TntMan::sub40CD60() { } void AsScene1201TntMan::sub40CD90() { - // TODO SoundMan_addSound(0x01D00560, 0x4B044624, true); - // TODO SoundMan_playSoundLooping(0x4B044624); + _vm->_soundMan->addSound(0x01D00560, 0x4B044624); + _vm->_soundMan->playSoundLooping(0x4B044624); _flag = true; startAnimation(0x85084190, 0, -1); SetMessageHandler(&AsScene1201TntMan::handleMessage); @@ -447,7 +447,7 @@ Class465::Class465(NeverhoodEngine *vm, Sprite *asTntMan) } Class465::~Class465() { - // TODO SoundMan_deleteSoundGroup(0x041080A4); + _vm->_soundMan->deleteSoundGroup(0x041080A4); } void Class465::update() { @@ -455,8 +455,8 @@ void Class465::update() { if (getGlobalVar(0x20A0C516)) { setVisible(true); SetUpdateHandler(&AnimatedSprite::update); - // TODO SoundMan_addSound(0x041080A4, 0x460A1050, true); - // TODO SoundMan_playSoundLooping(0x460A1050); + _vm->_soundMan->addSound(0x041080A4, 0x460A1050); + _vm->_soundMan->playSoundLooping(0x460A1050); } } @@ -1227,10 +1227,7 @@ bool Scene1202::isSolved() { } void Scene1202::doPaletteEffect() { -#if 0 // TODO - Palette2 *palette2 = (Palette2*)_palette; - palette2->startFadeToPalette(24); -#endif + // TODO } } // End of namespace Neverhood diff --git a/engines/neverhood/module1300.cpp b/engines/neverhood/module1300.cpp index b7c588f114..ee4dc7a42c 100644 --- a/engines/neverhood/module1300.cpp +++ b/engines/neverhood/module1300.cpp @@ -35,12 +35,12 @@ namespace Neverhood { Module1300::Module1300(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - // TODO SoundMan_addMusic(0x61C090, 0x203197); + _vm->_soundMan->addMusic(0x61C090, 0x203197); // TODO SoundMan_addSoundList(0x61C090, dword_4B2868, true); // TODO SoundMan_setSoundListParams(dword_4B2868, false, 50, 600, 20, 150); - // TODO SoundMan_playTwoSounds(0x61C090, 0x48498E46, 0x50399F64, 0); - // TODO SoundMan_setSoundVolume(0x48498E46, 70); - // TODO SoundMan_setSoundVolume(0x50399F64, 70); + _vm->_soundMan->playTwoSounds(0x61C090, 0x48498E46, 0x50399F64, 0); + _vm->_soundMan->setSoundVolume(0x48498E46, 70); + _vm->_soundMan->setSoundVolume(0x50399F64, 70); if (which < 0) { if (_vm->gameState().sceneNum >= 1 && _vm->gameState().sceneNum <= 17) @@ -94,7 +94,7 @@ Module1300::Module1300(NeverhoodEngine *vm, Module *parentModule, int which) } Module1300::~Module1300() { - // TODO SoundMan_deleteGroup(0x61C090); + _vm->_soundMan->deleteGroup(0x61C090); } void Module1300::createScene(int sceneNum, int which) { @@ -103,82 +103,82 @@ void Module1300::createScene(int sceneNum, int which) { switch (_vm->gameState().sceneNum) { case 1: // TODO SoundMan_setSoundListParams(dword_4B2868, false, 0, 0, 0, 0); - // TODO SoundMan_startMusic(0x203197, 0, 2, 1); + _vm->_soundMan->startMusic(0x203197, 0, 2); _childObject = new Scene1302(_vm, this, which); break; case 2: // TODO SoundMan_setSoundListParams(dword_4B2868, false, 0, 0, 0, 0); - // TODO SoundMan_stopMusic(0x203197, 0, 2); + _vm->_soundMan->stopMusic(0x203197, 0, 2); _childObject = new Scene1303(_vm, this, which); break; case 3: // TODO SoundMan_setSoundListParams(dword_4B2868, false, 0, 0, 0, 0); - // TODO SoundMan_stopMusic(0x203197, 0, 2); + _vm->_soundMan->stopMusic(0x203197, 0, 2); _childObject = new Scene1304(_vm, this, which); break; case 4: // TODO SoundMan_setSoundListParams(dword_4B2868, false, 0, 0, 0, 0); - // TODO SoundMan_startMusic(0x203197, 0, 2, 1); + _vm->_soundMan->startMusic(0x203197, 0, 2); _childObject = new Scene1305(_vm, this, which); break; case 5: // TODO SoundMan_setSoundListParams(dword_4B2868, false, 0, 0, 0, 0); - // TODO SoundMan_startMusic(0x203197, 0, 2, 1); + _vm->_soundMan->startMusic(0x203197, 0, 2); _childObject = new Scene1306(_vm, this, which); break; case 6: // TODO SoundMan_setSoundListParams(dword_4B2868, false, 0, 0, 0, 0); - // TODO SoundMan_startMusic(0x203197, 0, 2, 1); + _vm->_soundMan->startMusic(0x203197, 0, 2); _childObject = new Scene1307(_vm, this, which); break; case 7: // TODO SoundMan_setSoundListParams(dword_4B2868, false, 0, 0, 0, 0); - // TODO SoundMan_startMusic(0x203197, 0, 2, 1); + _vm->_soundMan->startMusic(0x203197, 0, 2); _childObject = new Scene1308(_vm, this, which); break; case 8: // TODO SoundMan_setSoundListParams(dword_4B2868, false, 0, 0, 0, 0); - // TODO SoundMan_stopMusic(0x203197, 0, 2); + _vm->_soundMan->stopMusic(0x203197, 0, 2); _childObject = new DiskplayerScene(_vm, this, 1); break; case 9: // TODO SoundMan_setSoundListParams(dword_4B2868, false, 0, 0, 0, 0); - // TODO SoundMan_stopMusic(0x203197, 0, 2); + _vm->_soundMan->stopMusic(0x203197, 0, 2); createSmackerScene(0x20082818, true, true, false); break; case 10: // TODO SoundMan_setSoundListParams(dword_4B2868, false, 0, 0, 0, 0); - // TODO SoundMan_stopMusic(0x203197, 0, 2); + _vm->_soundMan->stopMusic(0x203197, 0, 2); createSmackerScene(0x20082828, true, true, false); break; case 11: // TODO SoundMan_setSoundListParams(0xdword_4B2868, true, 0, 0, 0, 0); - // TODO SoundMan_stopMusic(0x203197, 0, 2); + _vm->_soundMan->stopMusic(0x203197, 0, 2); createNavigationScene(0x004B27A8, which); break; case 12: // TODO SoundMan_setSoundListParams(0xdword_4B2868, true, 0, 0, 0, 0); - // TODO SoundMan_stopMusic(0x203197, 0, 2); + _vm->_soundMan->stopMusic(0x203197, 0, 2); createNavigationScene(0x004B2718, which); break; case 13: // TODO SoundMan_setSoundListParams(0xdword_4B2868, true, 0, 0, 0, 0); - // TODO SoundMan_stopMusic(0x203197, 0, 2); + _vm->_soundMan->stopMusic(0x203197, 0, 2); createNavigationScene(0x004B27D8, which); break; case 14: // TODO SoundMan_setSoundListParams(0xdword_4B2868, true, 0, 0, 0, 0); - // TODO SoundMan_stopMusic(0x203197, 0, 2); + _vm->_soundMan->stopMusic(0x203197, 0, 2); createNavigationScene(0x004B2808, which); break; case 15: // TODO SoundMan_setSoundListParams(0xdword_4B2868, true, 0, 0, 0, 0); - // TODO SoundMan_stopMusic(0x203197, 0, 2); + _vm->_soundMan->stopMusic(0x203197, 0, 2); createNavigationScene(0x004B2838, which); break; case 16: // TODO SoundMan_setSoundListParams(dword_4B2868, false, 0, 0, 0, 0); - // TODO SoundMan_stopMusic(0x203197, 0, 2); + _vm->_soundMan->stopMusic(0x203197, 0, 2); _childObject = new Scene1317(_vm, this, which); break; case 17: diff --git a/engines/neverhood/module1400.cpp b/engines/neverhood/module1400.cpp index 370735695d..8d40c340ec 100644 --- a/engines/neverhood/module1400.cpp +++ b/engines/neverhood/module1400.cpp @@ -32,8 +32,8 @@ namespace Neverhood { Module1400::Module1400(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { - // TODO SoundMan_addMusic(0x00AD0012, 0x06333232); - // TODO SoundMan_addMusic(0x00AD0012, 0x624A220E); + _vm->_soundMan->addMusic(0x00AD0012, 0x06333232); + _vm->_soundMan->addMusic(0x00AD0012, 0x624A220E); if (which < 0) { createScene(_vm->gameState().sceneNum, -1); @@ -44,7 +44,7 @@ Module1400::Module1400(NeverhoodEngine *vm, Module *parentModule, int which) } Module1400::~Module1400() { - // TODO SoundMan_deleteMusicGroup(0x00AD0012); + _vm->_soundMan->deleteMusicGroup(0x00AD0012); } void Module1400::createScene(int sceneNum, int which) { @@ -52,33 +52,33 @@ void Module1400::createScene(int sceneNum, int which) { _vm->gameState().sceneNum = sceneNum; switch (_vm->gameState().sceneNum) { case 0: - // TODO SoundMan_startMusic(0x06333232, 0, 2, 1); + _vm->_soundMan->startMusic(0x06333232, 0, 2); _childObject = new Scene1401(_vm, this, which); break; case 1: - // TODO SoundMan_stopMusic(0x06333232, 0, 2); - // TODO SoundMan_stopMusic(0x624A220E, 0, 2); + _vm->_soundMan->stopMusic(0x06333232, 0, 2); + _vm->_soundMan->stopMusic(0x624A220E, 0, 2); _childObject = new Scene1402(_vm, this, which); break; case 2: - // TODO SoundMan_stopMusic(0x06333232, 0, 2); - // TODO SoundMan_startMusic(0x624A220E, 0, 2, 1); + _vm->_soundMan->stopMusic(0x06333232, 0, 2); + _vm->_soundMan->startMusic(0x624A220E, 0, 2); _childObject = new Scene1403(_vm, this, which); break; case 3: - // TODO SoundMan_startMusic(0x06333232, 0, 2, 1); + _vm->_soundMan->startMusic(0x06333232, 0, 2); _childObject = new Scene1404(_vm, this, which); break; case 4: - // TODO SoundMan_startMusic(0x06333232, 0, 2, 1); + _vm->_soundMan->startMusic(0x06333232, 0, 2); _childObject = new Scene1405(_vm, this, which); break; case 5: - // TODO SoundMan_stopMusic(0x06333232, 0, 2); + _vm->_soundMan->stopMusic(0x06333232, 0, 2); _childObject = new DiskplayerScene(_vm, this, 2); break; case 6: - // TODO SoundMan_stopMusic(0x06333232, 0, 2); + _vm->_soundMan->stopMusic(0x06333232, 0, 2); _childObject = new Scene1407(_vm, this, which); break; } @@ -148,7 +148,7 @@ Class525::Class525(NeverhoodEngine *vm) } Class525::~Class525() { - // TODO SoundMan_deleteSoundGroup(0x01104C08); + _vm->_soundMan->deleteSoundGroup(0x01104C08); } void Class525::update4662A0() { @@ -157,8 +157,8 @@ void Class525::update4662A0() { sub466460(); } if (_countdown2 != 0 && (--_countdown2 == 0)) { - // TODO SoundMan_addSound(0x01104C08, 0x4A116437, true); - // TODO SoundMan_playSoundLooping(0x4A116437); + _vm->_soundMan->addSound(0x01104C08, 0x4A116437); + _vm->_soundMan->playSoundLooping(0x4A116437); } } @@ -211,7 +211,7 @@ void Class525::sub466420() { } void Class525::sub466460() { - // TODO SoundMan_deleteSound(0x4A116437); + _vm->_soundMan->deleteSound(0x4A116437); _soundResource1.play(0x4A120435); startAnimation(0x4C210500, 0, -1); } @@ -406,7 +406,7 @@ Class489::Class489(NeverhoodEngine *vm, Scene *parentScene, Sprite *klayman, Spr } Class489::~Class489() { - // TODO SoundMan_deleteSoundGroup(0x05331081); + _vm->_soundMan->deleteSoundGroup(0x05331081); } uint32 Class489::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { @@ -616,8 +616,8 @@ void Class489::sub434EC0() { NextState(&Class489::sub434F40); setGlobalVar(0x12A10DB3, 1); _soundResource1.play(0xCC4A8456); - // TODO SoundMan_addSound(0x05331081, 0xCE428854, true); - // TODO SoundMan_playSoundLooping(0xCE428854); + _vm->_soundMan->addSound(0x05331081, 0xCE428854); + _vm->_soundMan->playSoundLooping(0xCE428854); } void Class489::sub434F40() { @@ -634,7 +634,7 @@ void Class489::sub434F80() { NextState(&Class489::sub434E90); setGlobalVar(0x12A10DB3, 0); _soundResource1.play(0xCC4A8456); - // TODO SoundMan_deleteSound(0xCE428854); + _vm->_soundMan->deleteSound(0xCE428854); } void Class489::sub434FF0() { diff --git a/engines/neverhood/navigationscene.h b/engines/neverhood/navigationscene.h index c37a7fc178..4397a4372b 100644 --- a/engines/neverhood/navigationscene.h +++ b/engines/neverhood/navigationscene.h @@ -34,6 +34,8 @@ public: NavigationScene(NeverhoodEngine *vm, Module *parentModule, uint32 navigationListId, int navigationIndex, const byte *itemsTypes); virtual ~NavigationScene(); int getNavigationAreaType(); + bool getSoundFlag1() const { return _soundFlag1; } + bool getSoundFlag2() const { return _soundFlag2; } protected: SmackerPlayer *_smackerPlayer; bool _smackerDone; diff --git a/engines/neverhood/neverhood.cpp b/engines/neverhood/neverhood.cpp index abd937497e..e5c07b5b8d 100644 --- a/engines/neverhood/neverhood.cpp +++ b/engines/neverhood/neverhood.cpp @@ -100,6 +100,7 @@ Common::Error NeverhoodEngine::run() { #if 1 _soundMan = new SoundMan(this); + _audioResourceMan = new AudioResourceMan(this); _collisionMan = new CollisionMan(this); _gameModule = new GameModule(this); @@ -139,6 +140,8 @@ Common::Error NeverhoodEngine::run() { //debug("millis %d", _system->getMillis()); _gameModule->handleUpdate(); _gameModule->draw(); + _soundMan->update(); + _audioResourceMan->update(); _screen->wait(); _screen->update(); @@ -149,6 +152,7 @@ Common::Error NeverhoodEngine::run() { delete _gameModule; delete _collisionMan; delete _soundMan; + delete _audioResourceMan; #endif diff --git a/engines/neverhood/neverhood.h b/engines/neverhood/neverhood.h index 13ea39986a..2aa84e5cb7 100644 --- a/engines/neverhood/neverhood.h +++ b/engines/neverhood/neverhood.h @@ -46,6 +46,7 @@ class GameVars; class ResourceMan; class Screen; class SoundMan; +class AudioResourceMan; class StaticData; struct NPoint; @@ -87,6 +88,7 @@ public: CollisionMan *_collisionMan; SoundMan *_soundMan; + AudioResourceMan *_audioResourceMan; public: diff --git a/engines/neverhood/resource.cpp b/engines/neverhood/resource.cpp index 7b0aa94b13..9bf6549ffe 100644 --- a/engines/neverhood/resource.cpp +++ b/engines/neverhood/resource.cpp @@ -640,44 +640,20 @@ DataResource::DRDirectoryItem *DataResource::findDRDirectoryItem(uint32 nameHash return NULL; } -// SoundResource -// ALL TODO - -SoundResource::SoundResource(NeverhoodEngine *vm) - : _vm(vm) { -} - -bool SoundResource::isPlaying() { - return false; -} - -void SoundResource::load(uint32 fileHash) { -} - -void SoundResource::unload() { -} - -void SoundResource::play(uint32 fileHash, bool looping) { -} - -void SoundResource::play() { -} - -void SoundResource::setVolume(int volume) { -} - uint32 calcHash(const char *value) { uint32 hash = 0, shiftValue = 0; while (*value != 0) { char ch = *value++; - if (ch >= 'a' && ch <= 'z') - ch -= 32; - else if (ch >= '0' && ch <= '9') - ch += 22; - shiftValue += ch - 64; - if (shiftValue >= 32) - shiftValue -= 32; - hash ^= 1 << shiftValue; + if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) { + if (ch >= 'a' && ch <= 'z') + ch -= 32; + else if (ch >= '0' && ch <= '9') + ch += 22; + shiftValue += ch - 64; + if (shiftValue >= 32) + shiftValue -= 32; + hash ^= 1 << shiftValue; + } } return hash; } diff --git a/engines/neverhood/resource.h b/engines/neverhood/resource.h index b0cd464e06..16782968f8 100644 --- a/engines/neverhood/resource.h +++ b/engines/neverhood/resource.h @@ -191,22 +191,6 @@ protected: DataResource::DRDirectoryItem *findDRDirectoryItem(uint32 nameHash, uint16 type); }; -// TODO: Dummy class atm - -class SoundResource { -public: - SoundResource(NeverhoodEngine *vm); - bool isPlaying(); - void load(uint32 fileHash); - void unload(); - void play(uint32 fileHash, bool looping = false); - void play(); - void stop() { /*DUMMY*/ } - void setVolume(int volume); -protected: - NeverhoodEngine *_vm; -}; - uint32 calcHash(const char *value); } // End of namespace Neverhood diff --git a/engines/neverhood/resourceman.cpp b/engines/neverhood/resourceman.cpp index 0538f58e87..c073e976a4 100644 --- a/engines/neverhood/resourceman.cpp +++ b/engines/neverhood/resourceman.cpp @@ -35,7 +35,7 @@ void ResourceMan::addArchive(const Common::String &filename) { uint archiveIndex = _archives.size(); archive->open(filename); _archives.push_back(archive); - debug("ResourceMan::addArchive(%s) %d files", filename.c_str(), archive->getCount()); + debug(3, "ResourceMan::addArchive(%s) %d files", filename.c_str(), archive->getCount()); _entries.reserve(_entries.size() + archive->getCount()); for (uint archiveEntryIndex = 0; archiveEntryIndex < archive->getCount(); archiveEntryIndex++) { BlbArchiveEntry *archiveEntry = archive->getEntry(archiveEntryIndex); diff --git a/engines/neverhood/scene.cpp b/engines/neverhood/scene.cpp index d189fad240..8520d6467d 100644 --- a/engines/neverhood/scene.cpp +++ b/engines/neverhood/scene.cpp @@ -375,7 +375,7 @@ uint32 Scene::smackerHandleMessage(int messageNum, const MessageParam ¶m, En } bool Scene::queryPositionSprite(int16 mouseX, int16 mouseY) { - debug("Scene::queryPositionSprite(%d, %d)", mouseX, mouseY); + //debug("Scene::queryPositionSprite(%d, %d)", mouseX, mouseY); for (uint i = 0; i < _vm->_collisionMan->getSpriteCount(); i++) { Sprite *sprite = _vm->_collisionMan->getSprite(i); if (sprite->hasMessageHandler() && sprite->isPointInside(mouseX, mouseY) && @@ -397,7 +397,7 @@ bool Scene::queryPositionRectList(int16 mouseX, int16 mouseY) { for (uint j = 0; j < rectList[i].subRects.size(); j++) { debug(2, " (%d, %d) ? (%d, %d, %d, %d)", mouseX, mouseY, rectList[i].subRects[j].rect.x1, rectList[i].subRects[j].rect.y1, rectList[i].subRects[j].rect.x2, rectList[i].subRects[j].rect.y2); if (rectList[i].subRects[j].rect.contains(mouseX, mouseY)) { - debug("Scene::queryPositionRectList() -> %08X", rectList[i].subRects[j].messageListId); + //debug("Scene::queryPositionRectList() -> %08X", rectList[i].subRects[j].messageListId); return setMessageList2(rectList[i].subRects[j].messageListId); } } @@ -416,7 +416,7 @@ void Scene::setMessageList(uint32 id, bool messageListFlag, bool systemCallbackF } void Scene::setMessageList(MessageList *messageList, bool messageListFlag, bool systemCallbackFlag) { - debug("Scene::setMessageList(%p)", (void*)messageList); + //debug("Scene::setMessageList(%p)", (void*)messageList); _messageList = messageList; _messageListCount = _messageList ? _messageList->size() : 0; _messageListIndex = 0; @@ -426,11 +426,13 @@ void Scene::setMessageList(MessageList *messageList, bool messageListFlag, bool _messageListStatus = 1; sendMessage(_klayman, 0x101C, 0); +#if 0 // DEBUG: Show message list for (uint i = 0; i < messageList->size(); i++) { debug("A: %02d: %04X, %08X", i, (*messageList)[i].messageNum, (*messageList)[i].messageValue); } debug("A: ================================================================"); +#endif } @@ -441,13 +443,15 @@ bool Scene::setMessageList2(uint32 id, bool messageListFlag, bool systemCallback bool Scene::setMessageList2(MessageList *messageList, bool messageListFlag, bool systemCallbackFlag) { bool result = false; - debug("Scene::setMessageList2(%p)", (void*)messageList); + //debug("Scene::setMessageList2(%p)", (void*)messageList); +#if 0 // DEBUG: Show message list for (uint i = 0; i < messageList->size(); i++) { debug("B: %02d: %04X, %08X", i, (*messageList)[i].messageNum, (*messageList)[i].messageValue); } debug("B: ================================================================"); +#endif if (_messageListStatus == 1) { if (messageList != _messageList2) { @@ -500,7 +504,7 @@ void Scene::runMessageList() { uint32 messageNum = (*_messageList)[_messageListIndex].messageNum; uint32 messageParam = (*_messageList)[_messageListIndex].messageValue; - debug("Scene::runMessageList() %04X, %08X", messageNum, messageParam); + //debug("Scene::runMessageList() %04X, %08X", messageNum, messageParam); _messageListIndex++; if (_messageListIndex == _messageListCount) { @@ -573,7 +577,7 @@ void Scene::clearRectList() { void Scene::loadHitRectList() { HitRectList *hitRectList = _dataResource.getHitRectList(); - debug("Scene::loadHitRectList() hitRectList = %p", (void*)hitRectList); + //debug("Scene::loadHitRectList() hitRectList = %p", (void*)hitRectList); if (hitRectList) { _hitRectList = *hitRectList; _vm->_collisionMan->setHitRects(&_hitRectList); diff --git a/engines/neverhood/sound.cpp b/engines/neverhood/sound.cpp index 91a23bfc7b..bd2f223998 100644 --- a/engines/neverhood/sound.cpp +++ b/engines/neverhood/sound.cpp @@ -20,36 +20,101 @@ * */ +#include "common/memstream.h" #include "graphics/palette.h" #include "neverhood/sound.h" +#include "neverhood/resourceman.h" namespace Neverhood { // TODO Put more stuff into the constructors/destructors of the item structs // TODO Some parts are quite bad here, but my priority is to get sound working at all +SoundResource::SoundResource(NeverhoodEngine *vm) + : _vm(vm), _soundIndex(-1) { +} + +SoundResource::~SoundResource() { + unload(); +} + +bool SoundResource::isPlaying() { + return _soundIndex >= 0 && + _vm->_audioResourceMan->isSoundPlaying(_soundIndex); +} + +void SoundResource::load(uint32 fileHash) { + unload(); + _soundIndex = _vm->_audioResourceMan->addSound(fileHash); + _vm->_audioResourceMan->loadSound(_soundIndex); +} + +void SoundResource::unload() { + if (_soundIndex >= 0) { + _vm->_audioResourceMan->removeSound(_soundIndex); + _soundIndex = -1; + } +} + +void SoundResource::play(uint32 fileHash) { + load(fileHash); + play(); +} + +void SoundResource::play() { + if (_soundIndex >= 0) + _vm->_audioResourceMan->playSound(_soundIndex, false); +} + +void SoundResource::stop() { + if (_soundIndex >= 0) + _vm->_audioResourceMan->stopSound(_soundIndex); +} + +void SoundResource::setVolume(int16 volume) { + if (_soundIndex >= 0) + _vm->_audioResourceMan->setSoundVolume(_soundIndex, volume); +} + +void SoundResource::setPan(int16 pan) { + if (_soundIndex >= 0) + _vm->_audioResourceMan->setSoundPan(_soundIndex, pan); +} + MusicResource::MusicResource(NeverhoodEngine *vm) - : _vm(vm) { + : _vm(vm), _musicIndex(-1) { } bool MusicResource::isPlaying() { - return false; + return _musicIndex >= 0 && + _vm->_audioResourceMan->isMusicPlaying(_musicIndex); } void MusicResource::load(uint32 fileHash) { - // TODO + unload(); + _musicIndex = _vm->_audioResourceMan->loadMusic(fileHash); } void MusicResource::unload() { - // TODO + if (_musicIndex >= 0) { + _vm->_audioResourceMan->unloadMusic(_musicIndex); + _musicIndex = -1; + } } void MusicResource::play(int16 fadeVolumeStep) { - // TODO + if (_musicIndex >= 0) + _vm->_audioResourceMan->playMusic(_musicIndex, fadeVolumeStep); } void MusicResource::stop(int16 fadeVolumeStep) { - // TODO + if (_musicIndex >= 0) + _vm->_audioResourceMan->stopMusic(_musicIndex, fadeVolumeStep); +} + +void MusicResource::setVolume(int16 volume) { + if (_musicIndex >= 0) + _vm->_audioResourceMan->setMusicVolume(_musicIndex, volume); } MusicItem::MusicItem() @@ -80,6 +145,8 @@ SoundItem::~SoundItem() { delete _soundResource; } +// SoundMan + SoundMan::SoundMan(NeverhoodEngine *vm) : _vm(vm), _soundIndex1(-1), _soundIndex2(-1), _soundIndex3(-1) { @@ -107,8 +174,8 @@ void SoundMan::deleteMusic(uint32 musicFileHash) { if (musicItem) { delete musicItem; for (uint i = 0; i < _musicItems.size(); ++i) - if (_musicItems[i]->_musicFileHash == musicFileHash) { - _musicItems.remove_at(i); + if (_musicItems[i] == musicItem) { + _musicItems[i] = NULL; break; } } @@ -149,8 +216,8 @@ void SoundMan::deleteSound(uint32 soundFileHash) { if (soundItem) { delete soundItem; for (uint i = 0; i < _soundItems.size(); ++i) - if (_soundItems[i]->_soundFileHash == soundFileHash) { - _soundItems.remove_at(i); + if (_soundItems[i] == soundItem) { + _soundItems[i] = NULL; break; } } @@ -213,35 +280,41 @@ void SoundMan::update() { for (uint i = 0; i < _soundItems.size(); ++i) { SoundItem *soundItem = _soundItems[i]; - if (soundItem->_playOnceAfterCountdown) { - if (soundItem->_currCountdown == 0) { - soundItem->_currCountdown = soundItem->_initialCountdown; - } else if (--soundItem->_currCountdown == 0) { - soundItem->_soundResource->play(); + if (soundItem) { + if (soundItem->_playOnceAfterCountdown) { + if (soundItem->_currCountdown == 0) { + soundItem->_currCountdown = soundItem->_initialCountdown; + } else if (--soundItem->_currCountdown == 0) { + soundItem->_soundResource->play(); + } + } else if (soundItem->_playOnceAfterRandomCountdown) { + if (soundItem->_currCountdown == 0) { + if (soundItem->_minCountdown > 0 && soundItem->_maxCountdown > 0 && soundItem->_minCountdown < soundItem->_maxCountdown) + soundItem->_currCountdown = _vm->_rnd->getRandomNumberRng(soundItem->_minCountdown, soundItem->_maxCountdown); + } else if (--soundItem->_currCountdown == 0) { + soundItem->_soundResource->play(); + } + } else if (soundItem->_playLooping && !soundItem->_soundResource->isPlaying()) { + soundItem->_soundResource->play(); // TODO Looping parameter? } - } else if (soundItem->_playOnceAfterRandomCountdown) { - if (soundItem->_currCountdown == 0) { - if (soundItem->_minCountdown > 0 && soundItem->_maxCountdown > 0 && soundItem->_minCountdown < soundItem->_maxCountdown) - soundItem->_currCountdown = _vm->_rnd->getRandomNumberRng(soundItem->_minCountdown, soundItem->_maxCountdown); - } else if (--soundItem->_currCountdown == 0) { - soundItem->_soundResource->play(); - } - } else if (soundItem->_playLooping && !soundItem->_soundResource->isPlaying()) { - soundItem->_soundResource->play(); // TODO Looping parameter? } } for (uint i = 0; i < _musicItems.size(); ++i) { MusicItem *musicItem = _musicItems[i]; - if (musicItem->_countdown) { - --musicItem->_countdown; - } else if (musicItem->_play && !musicItem->_musicResource->isPlaying()) { - musicItem->_musicResource->play(musicItem->_fadeVolumeStep); - musicItem->_fadeVolumeStep = 0; - } else if (musicItem->_stop) { - musicItem->_musicResource->stop(musicItem->_fadeVolumeStep); - musicItem->_fadeVolumeStep = 0; - musicItem->_stop = false; + if (musicItem) { + if (musicItem->_countdown) { + --musicItem->_countdown; + } else if (musicItem->_play && !musicItem->_musicResource->isPlaying()) { + debug("SoundMan: play music %08X (fade %d)", musicItem->_musicFileHash, musicItem->_fadeVolumeStep); + musicItem->_musicResource->play(musicItem->_fadeVolumeStep); + musicItem->_fadeVolumeStep = 0; + } else if (musicItem->_stop) { + debug("SoundMan: stop music %08X (fade %d)", musicItem->_musicFileHash, musicItem->_fadeVolumeStep); + musicItem->_musicResource->stop(musicItem->_fadeVolumeStep); + musicItem->_fadeVolumeStep = 0; + musicItem->_stop = false; + } } } @@ -253,11 +326,11 @@ void SoundMan::deleteGroup(uint32 nameHash) { } void SoundMan::deleteMusicGroup(uint32 nameHash) { - for (int index = _musicItems.size() - 1; index >= 0; --index) { + for (uint index = 0; index < _musicItems.size(); ++index) { MusicItem *musicItem = _musicItems[index]; - if (musicItem->_nameHash == nameHash) { + if (musicItem && musicItem->_nameHash == nameHash) { delete musicItem; - _musicItems.remove_at(index); + _musicItems[index] = NULL; } } } @@ -276,11 +349,11 @@ void SoundMan::deleteSoundGroup(uint32 nameHash) { _soundIndex2 = -1; } - for (int index = _soundItems.size() - 1; index >= 0; --index) { + for (uint index = 0; index < _soundItems.size(); ++index) { soundItem = _soundItems[index]; - if (soundItem->_nameHash == nameHash) { + if (soundItem && soundItem->_nameHash == nameHash) { delete soundItem; - _soundItems.remove_at(index); + _soundItems[index] = NULL; } } @@ -359,21 +432,327 @@ void SoundMan::setSoundThreePlayFlag(bool playOnceAfterCountdown) { MusicItem *SoundMan::getMusicItemByHash(uint32 musicFileHash) { for (uint i = 0; i < _musicItems.size(); ++i) - if (_musicItems[i]->_musicFileHash == musicFileHash) + if (_musicItems[i] && _musicItems[i]->_musicFileHash == musicFileHash) return _musicItems[i]; return NULL; } SoundItem *SoundMan::getSoundItemByHash(uint32 soundFileHash) { for (uint i = 0; i < _soundItems.size(); ++i) - if (_soundItems[i]->_soundFileHash == soundFileHash) + if (_soundItems[i] && _soundItems[i]->_soundFileHash == soundFileHash) return _soundItems[i]; return NULL; } +int16 SoundMan::addMusicItem(MusicItem *musicItem) { + return 0; // TODO +} + +int16 SoundMan::addSoundItem(SoundItem *soundItem) { + for (uint i = 0; i < _soundItems.size(); ++i) + if (!_soundItems[i]) { + _soundItems[i] = soundItem; + return i; + } + int16 soundIndex = _soundItems.size(); + _soundItems.push_back(soundItem); + return soundIndex; +} + void SoundMan::deleteSoundByIndex(int index) { delete _soundItems[index]; - _soundItems.remove_at(index); + _soundItems[index] = NULL; +} + +// NeverhoodAudioStream + +NeverhoodAudioStream::NeverhoodAudioStream(int rate, byte shiftValue, bool isLooping, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream) + : _rate(rate), _shiftValue(shiftValue), _isLooping(isLooping), _isStereo(false), _stream(stream, disposeStream), _endOfData(false), _buffer(0), + _isCompressed(_shiftValue != 0xFF), _prevValue(0) { + // Setup our buffer for readBuffer + _buffer = new byte[kSampleBufferLength * (_isCompressed ? 1 : 2)]; + assert(_buffer); +} + +NeverhoodAudioStream::~NeverhoodAudioStream() { + delete[] _buffer; +} + +int NeverhoodAudioStream::readBuffer(int16 *buffer, const int numSamples) { + int samplesLeft = numSamples; + + while (samplesLeft > 0 && !_endOfData) { + + const int maxSamples = MIN(kSampleBufferLength, samplesLeft); + const int bytesToRead = maxSamples * (_isCompressed ? 1 : 2); + int bytesRead = _stream->read(_buffer, bytesToRead); + int samplesRead = bytesRead / (_isCompressed ? 1 : 2); + + samplesLeft -= samplesRead; + + const byte *src = _buffer; + if (_isCompressed) { + while (samplesRead--) { + _prevValue += (int8)(*src++); + *buffer++ = _prevValue << _shiftValue; + } + } else { + memcpy(buffer, _buffer, bytesRead); + buffer += bytesRead; + } + + if (bytesRead < bytesToRead || _stream->pos() >= _stream->size() || _stream->err() || _stream->eos()) { + if (_isLooping) + _stream->seek(0); + else + _endOfData = true; + } + + } + + return numSamples - samplesLeft; +} + +AudioResourceMan::AudioResourceMan(NeverhoodEngine *vm) + : _vm(vm) { +} + +AudioResourceMan::~AudioResourceMan() { +} + +int16 AudioResourceMan::addSound(uint32 fileHash) { + AudioResourceManSoundItem *soundItem = new AudioResourceManSoundItem(); + soundItem->_resourceHandle = _vm->_res->useResource(fileHash); + soundItem->_fileHash = fileHash; + soundItem->_data = NULL; + soundItem->_isLoaded = false; + soundItem->_isPlaying = false; + soundItem->_volume = 100; + soundItem->_panning = 50; + + for (uint i = 0; i < _soundItems.size(); ++i) + if (!_soundItems[i]) { + _soundItems[i] = soundItem; + return i; + } + + int16 soundIndex = (int16)_soundItems.size(); + _soundItems.push_back(soundItem); + return soundIndex; +} + +void AudioResourceMan::removeSound(int16 soundIndex) { + AudioResourceManSoundItem *soundItem = _soundItems[soundIndex]; + if (soundItem->_data) { + _vm->_res->unloadResource(soundItem->_resourceHandle); + soundItem->_data = NULL; + } + if (soundItem->_resourceHandle != 1) { + _vm->_res->unuseResource(soundItem->_resourceHandle); + soundItem->_resourceHandle = -1; + } + if (_vm->_mixer->isSoundHandleActive(soundItem->_soundHandle)) + _vm->_mixer->stopHandle(soundItem->_soundHandle); + delete soundItem; + _soundItems[soundIndex] = NULL; +} + +void AudioResourceMan::loadSound(int16 soundIndex) { + AudioResourceManSoundItem *soundItem = _soundItems[soundIndex]; + if (!soundItem->_data) { + // TODO Check if it's a sound resource + soundItem->_data = _vm->_res->loadResource(soundItem->_resourceHandle); + } +} + +void AudioResourceMan::unloadSound(int16 soundIndex) { + AudioResourceManSoundItem *soundItem = _soundItems[soundIndex]; + if (soundItem->_data) { + _vm->_res->unloadResource(soundItem->_resourceHandle); + soundItem->_data = NULL; + } +} + +void AudioResourceMan::setSoundVolume(int16 soundIndex, int16 volume) { + AudioResourceManSoundItem *soundItem = _soundItems[soundIndex]; + soundItem->_volume = MIN(volume, 100); + if (soundItem->_isPlaying && _vm->_mixer->isSoundHandleActive(soundItem->_soundHandle)) + _vm->_mixer->setChannelVolume(soundItem->_soundHandle, VOLUME(soundItem->_volume)); +} + +void AudioResourceMan::setSoundPan(int16 soundIndex, int16 pan) { + AudioResourceManSoundItem *soundItem = _soundItems[soundIndex]; + soundItem->_panning = MIN(pan, 100); + if (soundItem->_isPlaying && _vm->_mixer->isSoundHandleActive(soundItem->_soundHandle)) + _vm->_mixer->setChannelVolume(soundItem->_soundHandle, PANNING(soundItem->_panning)); +} + +void AudioResourceMan::playSound(int16 soundIndex, bool looping) { + AudioResourceManSoundItem *soundItem = _soundItems[soundIndex]; + if (!soundItem->_data) + loadSound(soundIndex); + + uint32 soundSize = _vm->_res->getResourceSize(soundItem->_resourceHandle); + Common::MemoryReadStream *stream = new Common::MemoryReadStream(soundItem->_data, soundSize, DisposeAfterUse::NO); + byte *shiftValue = _vm->_res->getResourceExtData(soundItem->_resourceHandle); + NeverhoodAudioStream *audioStream = new NeverhoodAudioStream(22050, *shiftValue, false, DisposeAfterUse::YES, stream); + + _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &soundItem->_soundHandle, + audioStream, -1, VOLUME(soundItem->_volume), PANNING(soundItem->_panning)); + + debug("playing sound %08X", soundItem->_fileHash); + + soundItem->_isPlaying = true; + +} + +void AudioResourceMan::stopSound(int16 soundIndex) { + AudioResourceManSoundItem *soundItem = _soundItems[soundIndex]; + if (_vm->_mixer->isSoundHandleActive(soundItem->_soundHandle)) + _vm->_mixer->stopHandle(soundItem->_soundHandle); + soundItem->_isPlaying = false; +} + +bool AudioResourceMan::isSoundPlaying(int16 soundIndex) { + AudioResourceManSoundItem *soundItem = _soundItems[soundIndex]; + return soundItem->_isPlaying; +} + +int16 AudioResourceMan::loadMusic(uint32 fileHash) { + + AudioResourceManMusicItem *musicItem; + + for (uint i = 0; i < _musicItems.size(); ++i) { + musicItem = _musicItems[i]; + if (musicItem && musicItem->_fileHash == fileHash && musicItem->_remove) { + musicItem->_remove = false; + musicItem->_isFadingOut = false; + musicItem->_isFadingIn = true; + return i; + } + } + + musicItem = new AudioResourceManMusicItem(); + musicItem->_fileHash = fileHash; + musicItem->_isPlaying = false; + musicItem->_remove = false; + musicItem->_volume = 100; + musicItem->_panning = 50; + musicItem->_start = false; + musicItem->_isFadingIn = false; + musicItem->_isFadingOut = false; + + for (uint i = 0; i < _musicItems.size(); ++i) { + if (!_musicItems[i]) { + _musicItems[i] = musicItem; + return i; + } + } + + int16 musicIndex = _musicItems.size(); + _musicItems.push_back(musicItem); + return musicIndex; + +} + +void AudioResourceMan::unloadMusic(int16 musicIndex) { + AudioResourceManMusicItem *musicItem = _musicItems[musicIndex]; + if (musicItem->_isFadingOut) { + musicItem->_remove = true; + } else { + if (_vm->_mixer->isSoundHandleActive(musicItem->_soundHandle)) + _vm->_mixer->stopHandle(musicItem->_soundHandle); + musicItem->_isPlaying = false; + _musicItems[musicIndex] = NULL; + } +} + +void AudioResourceMan::setMusicVolume(int16 musicIndex, int16 volume) { + AudioResourceManMusicItem *musicItem = _musicItems[musicIndex]; + musicItem->_volume = MIN(volume, 100); + if (musicItem->_isPlaying && _vm->_mixer->isSoundHandleActive(musicItem->_soundHandle)) + _vm->_mixer->setChannelVolume(musicItem->_soundHandle, VOLUME(musicItem->_volume)); +} + +void AudioResourceMan::playMusic(int16 musicIndex, int16 fadeVolumeStep) { + AudioResourceManMusicItem *musicItem = _musicItems[musicIndex]; + if (!musicItem->_isPlaying) { + musicItem->_isFadingIn = false; + musicItem->_isFadingOut = false; + if (fadeVolumeStep != 0) { + musicItem->_isFadingIn = true; + musicItem->_fadeVolume = 0; + musicItem->_fadeVolumeStep = fadeVolumeStep; + } + musicItem->_start = true; + } +} + +void AudioResourceMan::stopMusic(int16 musicIndex, int16 fadeVolumeStep) { + AudioResourceManMusicItem *musicItem = _musicItems[musicIndex]; + if (_vm->_mixer->isSoundHandleActive(musicItem->_soundHandle)) { + if (fadeVolumeStep != 0) { + if (musicItem->_isFadingIn) + musicItem->_isFadingIn = false; + else + musicItem->_fadeVolume = musicItem->_volume; + musicItem->_isFadingOut = true; + musicItem->_fadeVolumeStep = fadeVolumeStep; + } else { + _vm->_mixer->stopHandle(musicItem->_soundHandle); + } + musicItem->_isPlaying = false; + } +} + +bool AudioResourceMan::isMusicPlaying(int16 musicIndex) { + AudioResourceManMusicItem *musicItem = _musicItems[musicIndex]; + return musicItem->_isPlaying; +} + +void AudioResourceMan::updateMusicItem(int16 musicIndex) { + AudioResourceManMusicItem *musicItem = _musicItems[musicIndex]; + + if (musicItem->_start && !_vm->_mixer->isSoundHandleActive(musicItem->_soundHandle)) { + Common::SeekableReadStream *stream = _vm->_res->createStream(musicItem->_fileHash); + byte *shiftValue = _vm->_res->getResourceExtDataByHash(musicItem->_fileHash); + NeverhoodAudioStream *audioStream = new NeverhoodAudioStream(22050, *shiftValue, true, DisposeAfterUse::YES, stream); + _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, &musicItem->_soundHandle, + audioStream, -1, VOLUME(musicItem->_isFadingIn ? musicItem->_fadeVolume : musicItem->_volume), + PANNING(musicItem->_panning)); + musicItem->_start = false; + musicItem->_isPlaying = true; + } + + if (_vm->_mixer->isSoundHandleActive(musicItem->_soundHandle)) { + if (musicItem->_isFadingIn) { + musicItem->_fadeVolume += musicItem->_fadeVolumeStep; + if (musicItem->_fadeVolume >= musicItem->_volume) { + musicItem->_fadeVolume = musicItem->_volume; + musicItem->_isFadingIn = false; + } + _vm->_mixer->setChannelVolume(musicItem->_soundHandle, VOLUME(musicItem->_fadeVolume)); + } + if (musicItem->_isFadingOut) { + musicItem->_fadeVolume -= musicItem->_fadeVolumeStep; + if (musicItem->_fadeVolume < 0) + musicItem->_fadeVolume = 0; + _vm->_mixer->setChannelVolume(musicItem->_soundHandle, VOLUME(musicItem->_fadeVolume)); + if (musicItem->_fadeVolume == 0) { + musicItem->_isFadingOut = false; + stopMusic(musicIndex, 0); + if (musicItem->_remove) + unloadMusic(musicIndex); + } + } + } + +} + +void AudioResourceMan::update() { + for (uint i = 0; i < _musicItems.size(); ++i) + if (_musicItems[i]) + updateMusicItem(i); } } // End of namespace Neverhood diff --git a/engines/neverhood/sound.h b/engines/neverhood/sound.h index 39bf7cd096..b724e898f0 100644 --- a/engines/neverhood/sound.h +++ b/engines/neverhood/sound.h @@ -23,6 +23,7 @@ #ifndef NEVERHOOD_SOUND_H #define NEVERHOOD_SOUND_H +#include "audio/audiostream.h" #include "common/array.h" #include "graphics/surface.h" #include "neverhood/neverhood.h" @@ -30,6 +31,29 @@ namespace Neverhood { +// Convert volume from percent to 0..255 +#define VOLUME(volume) (Audio::Mixer::kMaxChannelVolume / 100 * (volume)) + +// Convert panning from percent (50% equals center) to -127..0..+127 +#define PANNING(panning) (254 / 100 * (panning) - 127) + +class SoundResource { +public: + SoundResource(NeverhoodEngine *vm); + ~SoundResource(); + bool isPlaying(); + void load(uint32 fileHash); + void unload(); + void play(uint32 fileHash); + void play(); + void stop(); + void setVolume(int16 volume); + void setPan(int16 pan); +protected: + NeverhoodEngine *_vm; + int16 _soundIndex; +}; + class MusicResource { public: MusicResource(NeverhoodEngine *vm); @@ -38,8 +62,10 @@ public: void unload(); void play(int16 fadeVolumeStep); void stop(int16 fadeVolumeStep); + void setVolume(int16 volume); protected: NeverhoodEngine *_vm; + int16 _musicIndex; }; struct MusicItem { @@ -72,6 +98,8 @@ struct SoundItem { ~SoundItem(); }; +// TODO Give this a better name + class SoundMan { public: SoundMan(NeverhoodEngine *vm); @@ -122,10 +150,102 @@ protected: MusicItem *getMusicItemByHash(uint32 musicFileHash); SoundItem *getSoundItemByHash(uint32 soundFileHash); + int16 addMusicItem(MusicItem *musicItem); + int16 addSoundItem(SoundItem *soundItem); void deleteSoundByIndex(int index); }; +class NeverhoodAudioStream : public Audio::AudioStream { +public: + NeverhoodAudioStream(int rate, byte shiftValue, bool isLooping, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream); + ~NeverhoodAudioStream(); + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return _isStereo; } + bool endOfData() const { return _endOfData; } + int getRate() const { return _rate; } +private: + const int _rate; + const bool _isLooping; + const bool _isStereo; + const byte _shiftValue; + const bool _isCompressed; + int16 _prevValue; + Common::DisposablePtr _stream; + bool _endOfData; + byte *_buffer; + enum { + kSampleBufferLength = 2048 + }; + int fillBuffer(int maxSamples); +}; + +// TODO Rename these + +struct AudioResourceManSoundItem { + uint32 _fileHash; + int _resourceHandle; + byte *_data; + bool _isLoaded; + bool _isPlaying; + int16 _volume; + int16 _panning; + Audio::SoundHandle _soundHandle; +}; + +struct AudioResourceManMusicItem { + uint32 _fileHash; + // streamIndex dw + // needCreate db + bool _isPlaying; + bool _remove; + int16 _volume; + int16 _panning; + bool _start; + bool _isFadingIn; + bool _isFadingOut; + int16 _fadeVolume; + int16 _fadeVolumeStep; + Audio::SoundHandle _soundHandle; + // status dw + // updateCounter dd +}; + +class AudioResourceMan { +public: + AudioResourceMan(NeverhoodEngine *vm); + ~AudioResourceMan(); + + int16 addSound(uint32 fileHash); + void removeSound(int16 soundIndex); + void loadSound(int16 soundIndex); + void unloadSound(int16 soundIndex); + void setSoundVolume(int16 soundIndex, int16 volume); + void setSoundPan(int16 soundIndex, int16 pan); + void playSound(int16 soundIndex, bool looping); + void stopSound(int16 soundIndex); + bool isSoundPlaying(int16 soundIndex); + + int16 loadMusic(uint32 fileHash); + void unloadMusic(int16 musicIndex); + void setMusicVolume(int16 musicIndex, int16 volume); + void playMusic(int16 musicIndex, int16 fadeVolumeStep); + void stopMusic(int16 musicIndex, int16 fadeVolumeStep); + bool isMusicPlaying(int16 musicIndex); + void updateMusicItem(int16 musicIndex); + + void update(); + +protected: + NeverhoodEngine *_vm; + + Common::Array _musicItems; + Common::Array _soundItems; + + int16 addSoundItem(AudioResourceManSoundItem *soundItem); + +}; + } // End of namespace Neverhood #endif /* NEVERHOOD_SOUND_H */ -- cgit v1.2.3