diff --git a/TR5Main/Game/Lara/lara.cpp b/TR5Main/Game/Lara/lara.cpp index 5bde3cde3..99a250e3e 100644 --- a/TR5Main/Game/Lara/lara.cpp +++ b/TR5Main/Game/Lara/lara.cpp @@ -1249,9 +1249,9 @@ void AnimateLara(ITEM_INFO* item) } flags = cmd[1] & 0xC000; - if (flags == SFX_LANDANDWATER || - (flags == SFX_LANDONLY && (Lara.waterSurfaceDist >= 0 || Lara.waterSurfaceDist == NO_HEIGHT)) || - (flags == SFX_WATERONLY && Lara.waterSurfaceDist < 0 && Lara.waterSurfaceDist != NO_HEIGHT && !(g_Level.Rooms[LaraItem->roomNumber].flags & ENV_FLAG_SWAMP))) + if ( flags == (int)SOUND_PLAYCONDITION::LandAndWater || + (flags == (int)SOUND_PLAYCONDITION::Land && (Lara.waterSurfaceDist >= 0 || Lara.waterSurfaceDist == NO_HEIGHT)) || + (flags == (int)SOUND_PLAYCONDITION::Water && Lara.waterSurfaceDist < 0 && Lara.waterSurfaceDist != NO_HEIGHT && !(g_Level.Rooms[LaraItem->roomNumber].flags & ENV_FLAG_SWAMP))) { SoundEffect(cmd[1] & 0x3FFF, &item->pos, 2); } diff --git a/TR5Main/Game/animation.cpp b/TR5Main/Game/animation.cpp index ef8e83472..abc7cd863 100644 --- a/TR5Main/Game/animation.cpp +++ b/TR5Main/Game/animation.cpp @@ -122,12 +122,12 @@ void AnimateItem(ITEM_INFO* item) } else if (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_WATER) { - if (!flags || flags == SFX_WATERONLY && (g_Level.Rooms[Camera.pos.roomNumber].flags & ENV_FLAG_WATER || Objects[item->objectNumber].intelligent)) + if (!flags || flags == (int)SOUND_PLAYCONDITION::Water && (g_Level.Rooms[Camera.pos.roomNumber].flags & ENV_FLAG_WATER || Objects[item->objectNumber].intelligent)) { SoundEffect(cmd[1] & 0x3FFF, &item->pos, 2); } } - else if (!flags || flags == SFX_LANDONLY && !(g_Level.Rooms[Camera.pos.roomNumber].flags & ENV_FLAG_WATER)) + else if (!flags || flags == (int)SOUND_PLAYCONDITION::Land && !(g_Level.Rooms[Camera.pos.roomNumber].flags & ENV_FLAG_WATER)) { SoundEffect(cmd[1] & 0x3FFF, &item->pos, 2); } diff --git a/TR5Main/Game/control/control.cpp b/TR5Main/Game/control/control.cpp index 8226fbc19..bd1a1b7a5 100644 --- a/TR5Main/Game/control/control.cpp +++ b/TR5Main/Game/control/control.cpp @@ -143,7 +143,7 @@ GAME_STATUS ControlPhase(int numFrames, int demoMode) { if (TrInput & IN_SAVE && LaraItem->hitPoints > 0 && g_Inventory.Get_invMode() != IM_SAVE) { - Sound_Stop(); + StopAllSounds(); g_Inventory.Set_invMode(IM_SAVE); @@ -152,7 +152,7 @@ GAME_STATUS ControlPhase(int numFrames, int demoMode) } else if (TrInput & IN_LOAD && g_Inventory.Get_invMode() != IM_LOAD) { - Sound_Stop(); + StopAllSounds(); g_Inventory.Set_invMode(IM_LOAD); @@ -161,7 +161,7 @@ GAME_STATUS ControlPhase(int numFrames, int demoMode) } else if (TrInput & IN_PAUSE && g_Inventory.Get_invMode() != IM_PAUSE && LaraItem->hitPoints > 0) { - Sound_Stop(); + StopAllSounds(); g_Renderer.DumpGameScene(); g_Inventory.Set_invMode(IM_PAUSE); g_Inventory.Set_pause_menu_to_display(pause_main_menu); @@ -170,7 +170,7 @@ GAME_STATUS ControlPhase(int numFrames, int demoMode) else if ((DbInput & IN_DESELECT || g_Inventory.Get_enterInventory() != NO_ITEM) && LaraItem->hitPoints > 0) { // Stop all sounds - Sound_Stop(); + StopAllSounds(); if (g_Inventory.S_CallInventory2(1)) return GAME_STATUS::GAME_STATUS_LOAD_GAME; @@ -473,7 +473,7 @@ GAME_STATUS DoTitle(int index) InitialiseFXArray(true); InitialisePickupDisplay(); InitialiseCamera(); - Sound_Stop(); + StopAllSounds(); // Run the level script GameScriptLevel* level = g_GameFlow->Levels[index]; @@ -506,7 +506,7 @@ GAME_STATUS DoTitle(int index) UseSpotCam = true; // Play background music - PlaySoundTrack("083_horus", SOUND_TRACK_BGM); + PlaySoundTrack(83); // Initialise ponytails InitialiseHair(); @@ -581,7 +581,7 @@ GAME_STATUS DoLevel(int index, std::string ambient, bool loadFromSavegame) InitialiseFXArray(true); InitialisePickupDisplay(); InitialiseCamera(); - Sound_Stop(); + StopAllSounds(); // Run the level script GameScriptLevel* level = g_GameFlow->Levels[index]; @@ -596,6 +596,9 @@ GAME_STATUS DoLevel(int index, std::string ambient, bool loadFromSavegame) }); } + // Play default background music + PlaySoundTrack(ambient, SOUNDTRACK_PLAYTYPE::BGM); + // Restore the game? if (loadFromSavegame) { @@ -636,9 +639,6 @@ GAME_STATUS DoLevel(int index, std::string ambient, bool loadFromSavegame) // Initialise flyby cameras InitSpotCamSequences(); - // Play background music - PlaySoundTrack(ambient, SOUND_TRACK_BGM); - // Initialise ponytails InitialiseHair(); @@ -673,7 +673,7 @@ GAME_STATUS DoLevel(int index, std::string ambient, bool loadFromSavegame) g_GameScript->OnEnd(); g_GameScript->FreeLevelScripts(); // Here is the only way for exiting from the loop - Sound_Stop(); + StopAllSounds(); StopSoundTracks(); return result; @@ -980,4 +980,7 @@ void CleanUp() DisableDripParticles(); DisableBubbles(); DisableDebris(); + + // Clear soundtrack masks + ClearSoundTrackMasks(); } \ No newline at end of file diff --git a/TR5Main/Game/flipeffect.cpp b/TR5Main/Game/flipeffect.cpp index 0128664de..5062b6822 100644 --- a/TR5Main/Game/flipeffect.cpp +++ b/TR5Main/Game/flipeffect.cpp @@ -116,7 +116,7 @@ void AddFootprint(ITEM_INFO* item) return; PHD_VECTOR position; - if (FXType == SFX_LANDONLY) + if (FXType == (int)SOUND_PLAYCONDITION::Land) GetLaraJointPosition(&position, LM_LFOOT); else GetLaraJointPosition(&position, LM_RFOOT); diff --git a/TR5Main/Game/savegame.cpp b/TR5Main/Game/savegame.cpp index 7ddd69226..eca921102 100644 --- a/TR5Main/Game/savegame.cpp +++ b/TR5Main/Game/savegame.cpp @@ -10,6 +10,7 @@ #include "sound/sound.h" #include "level.h" #include "setup.h" +#include "sound.h" #include "flipeffect.h" #include "tr5_rats_emitter.h" #include "tr5_bats_emitter.h" @@ -416,7 +417,7 @@ bool SaveGame::Save(int slot) serializedItems.push_back(serializedItemOffset); } - auto ambientTrackOffset = fbb.CreateString(CurrentLoopedSoundTrack); + auto ambientTrackOffset = fbb.CreateString(GetSoundTrackNameAndPosition(SOUNDTRACK_PLAYTYPE::BGM).first); auto serializedItemsOffset = fbb.CreateVector(serializedItems); // Flipmaps @@ -724,7 +725,8 @@ bool SaveGame::Load(int slot) FlipStatus = s->flip_status(); //FlipTimer = s->flip_timer(); - CurrentLoopedSoundTrack = s->ambient_track()->str(); + // TODO: Save and restore playhead, and also oneshot track too! + PlaySoundTrack(s->ambient_track()->str(), SOUNDTRACK_PLAYTYPE::BGM); // Static objects for (int i = 0; i < s->static_meshes()->size(); i++) diff --git a/TR5Main/Objects/TR4/Vehicles/jeep.cpp b/TR5Main/Objects/TR4/Vehicles/jeep.cpp index 38c96c17e..b7b134a30 100644 --- a/TR5Main/Objects/TR4/Vehicles/jeep.cpp +++ b/TR5Main/Objects/TR4/Vehicles/jeep.cpp @@ -409,7 +409,6 @@ static int JeepCheckGetOff() LaraItem->pos.zRot = 0; Lara.Vehicle = NO_ITEM; Lara.gunStatus = LG_NO_ARMS; - CurrentLoopedSoundTrack = 110; return false; } } @@ -1561,8 +1560,6 @@ void JeepCollision(short itemNumber, ITEM_INFO* l, COLL_INFO* coll) jeep->unknown2 = 0; item->flags |= 0x20; - - CurrentLoopedSoundTrack = 98; } else ObjectCollision(itemNumber, l, coll); diff --git a/TR5Main/Objects/TR5/Object/tr5_teleporter.cpp b/TR5Main/Objects/TR5/Object/tr5_teleporter.cpp index 99beb3662..9fb14c006 100644 --- a/TR5Main/Objects/TR5/Object/tr5_teleporter.cpp +++ b/TR5Main/Objects/TR5/Object/tr5_teleporter.cpp @@ -177,11 +177,7 @@ void ControlTeleporter(short itemNumber) if (item->triggerFlags == 666) { - if (item->itemFlags[0] == 15) - { - //PlaySoundTrack("xa12_z_10", SOUND_TRACK_ONESHOT); - } - else if (item->itemFlags[0] == 70) + if (item->itemFlags[0] == 70) { SoundEffect(SFX_TR5_LIFT_HIT_FLOOR1, 0, 0); SoundEffect(SFX_TR5_LIFT_HIT_FLOOR2, 0, 0); diff --git a/TR5Main/Renderer/Render11Helper.cpp b/TR5Main/Renderer/Render11Helper.cpp index 20f7b9359..6e8a7f28f 100644 --- a/TR5Main/Renderer/Render11Helper.cpp +++ b/TR5Main/Renderer/Render11Helper.cpp @@ -598,7 +598,6 @@ namespace TEN::Renderer continue; adapter.DisplayModes.push_back(newMode); - logD("W: ", newMode.Width,"H: ", newMode.Height," ", newMode.RefreshRate, "Hz"); } m_adapters.push_back(adapter); diff --git a/TR5Main/Renderer/Utils.cpp b/TR5Main/Renderer/Utils.cpp index c1cf5b28d..a38b22d77 100644 --- a/TR5Main/Renderer/Utils.cpp +++ b/TR5Main/Renderer/Utils.cpp @@ -20,7 +20,6 @@ namespace TEN::Renderer::Utils { ComPtr compileVertexShader(ID3D11Device* device, const std::wstring& fileName, const std::string& function, const std::string& model, const D3D_SHADER_MACRO * defines, ComPtr& bytecode) { ComPtr errors; - logD("Compiling vertex shader"); throwIfFailed(D3DCompileFromFile(fileName.c_str(), defines, D3D_COMPILE_STANDARD_FILE_INCLUDE, function.c_str(), model.c_str(), GetShaderFlags(), 0, bytecode.GetAddressOf(),errors.GetAddressOf())); ComPtr shader; throwIfFailed(device->CreateVertexShader(bytecode->GetBufferPointer(), bytecode->GetBufferSize(), nullptr, shader.GetAddressOf())); @@ -33,7 +32,6 @@ namespace TEN::Renderer::Utils { } ComPtr compilePixelShader(ID3D11Device* device, const wstring& fileName, const string& function, const string& model, const D3D_SHADER_MACRO* defines, ComPtr& bytecode) { ComPtr errors; - logD("Compiling pixel shader"); UINT flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR | D3DCOMPILE_SKIP_OPTIMIZATION; throwIfFailed(D3DCompileFromFile(fileName.c_str(), defines, D3D_COMPILE_STANDARD_FILE_INCLUDE, function.c_str(), model.c_str(), GetShaderFlags(), 0, bytecode.GetAddressOf(), errors.GetAddressOf())); ComPtr shader; diff --git a/TR5Main/Scripting/GameFlowScript.cpp b/TR5Main/Scripting/GameFlowScript.cpp index e4eead174..e9b567255 100644 --- a/TR5Main/Scripting/GameFlowScript.cpp +++ b/TR5Main/Scripting/GameFlowScript.cpp @@ -172,12 +172,14 @@ void GameFlow::SetGameFarView(byte val) void GameFlow::SetAudioTracks(sol::as_table_t>&& src) { std::vector tracks = std::move(src); + SoundTracks.clear(); + for (auto t : tracks) { - AudioTrack track; + SoundTrackInfo track; track.Name = t.trackName; track.Mask = 0; - track.looped = t.looped; - SoundTracks.insert_or_assign(track.Name, track); + track.Mode = t.looped ? SOUNDTRACK_PLAYTYPE::BGM : SOUNDTRACK_PLAYTYPE::OneShot; + SoundTracks.push_back(track); } } @@ -233,8 +235,6 @@ bool GameFlow::DoGameflow() // First we need to fill some legacy variables in PCTomb5.exe GameScriptLevel* level = Levels[CurrentLevel]; - CurrentLoopedSoundTrack = level->AmbientTrack; - GAME_STATUS status; if (CurrentLevel == 0) @@ -263,7 +263,7 @@ bool GameFlow::DoGameflow() } } - status = DoLevel(CurrentLevel, CurrentLoopedSoundTrack, loadFromSavegame); + status = DoLevel(CurrentLevel, level->AmbientTrack, loadFromSavegame); loadFromSavegame = false; } diff --git a/TR5Main/Scripting/GameLogicScript.cpp b/TR5Main/Scripting/GameLogicScript.cpp index 35e33742e..1a6f595dc 100644 --- a/TR5Main/Scripting/GameLogicScript.cpp +++ b/TR5Main/Scripting/GameLogicScript.cpp @@ -30,7 +30,8 @@ Functions and callbacks for level-specific logic scripts. static void PlayAudioTrack(std::string const & trackName, sol::optional looped) { - PlaySoundTrack(trackName, looped.value_or(SOUND_TRACK_ONESHOT)); + auto mode = looped.value_or(false) ? SOUNDTRACK_PLAYTYPE::OneShot : SOUNDTRACK_PLAYTYPE::BGM; + PlaySoundTrack(trackName, mode); } static void PlaySoundEffect(int id, GameScriptPosition p, int flags) @@ -54,7 +55,7 @@ static void PlaySoundEffect(int id, int flags) static void SetAmbientTrack(std::string const & trackName) { - PlaySoundTrack(trackName, SOUND_TRACK_BGM); + PlaySoundTrack(trackName, SOUNDTRACK_PLAYTYPE::BGM); } static int FindRoomNumber(GameScriptPosition pos) @@ -516,8 +517,8 @@ void AddOneSecret() { if (Savegame.Level.Secrets >= 255) return; - Savegame.Level.Secrets++; - PlaySoundTrack(TRACK_FOUND_SECRET, SOUND_TRACK_ONESHOT); + Savegame.Level.Secrets++; + PlaySecretTrack(); } /* diff --git a/TR5Main/Sound/sound.cpp b/TR5Main/Sound/sound.cpp index 9eb322e8c..43aee2f63 100644 --- a/TR5Main/Sound/sound.cpp +++ b/TR5Main/Sound/sound.cpp @@ -9,17 +9,13 @@ #include "configuration.h" #include "level.h" -using std::vector; -using std::unordered_map; -using std::string; - HSTREAM BASS_3D_Mixdown; -HFX BASS_FXHandler[NUM_SOUND_FILTERS]; -SoundTrackSlot BASS_Soundtrack[NUM_SOUND_TRACK_TYPES]; +HFX BASS_FXHandler[(int)SOUND_FILTER::Count]; +SoundTrackSlot BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::Count]; HSAMPLE SamplePointer[SOUND_MAX_SAMPLES]; SoundEffectSlot SoundSlot[SOUND_MAX_CHANNELS]; -const BASS_BFX_FREEVERB BASS_ReverbTypes[NUM_REVERB_TYPES] = // Reverb presets +const BASS_BFX_FREEVERB BASS_ReverbTypes[(int)REVERB_TYPE::Count] = // Reverb presets { // Dry Mix | Wet Mix | Size | Damp | Width | Mode | Channel { 1.0f, 0.20f, 0.05f, 0.90f, 0.7f, 0, -1 }, // 0 = Outside @@ -29,8 +25,8 @@ const BASS_BFX_FREEVERB BASS_ReverbTypes[NUM_REVERB_TYPES] = // Reverb preset { 1.0f, 0.25f, 0.90f, 1.00f, 1.0f, 0, -1 } // 4 = Pipe }; -unordered_map SoundTracks; -std::string CurrentLoopedSoundTrack; +std::map SoundTrackMap; +std::vector SoundTracks; static int GlobalMusicVolume; static int GlobalFXVolume; @@ -40,13 +36,13 @@ void SetVolumeMusic(int vol) GlobalMusicVolume = vol; float fVol = static_cast(vol) / 100.0f; - if (BASS_ChannelIsActive(BASS_Soundtrack[SOUND_TRACK_BGM].channel)) + if (BASS_ChannelIsActive(BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::BGM].Channel)) { - BASS_ChannelSetAttribute(BASS_Soundtrack[SOUND_TRACK_BGM].channel, BASS_ATTRIB_VOL, fVol); + BASS_ChannelSetAttribute(BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::BGM].Channel, BASS_ATTRIB_VOL, fVol); } - if (BASS_ChannelIsActive(BASS_Soundtrack[SOUND_TRACK_ONESHOT].channel)) + if (BASS_ChannelIsActive(BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::OneShot].Channel)) { - BASS_ChannelSetAttribute(BASS_Soundtrack[SOUND_TRACK_ONESHOT].channel, BASS_ATTRIB_VOL, fVol); + BASS_ChannelSetAttribute(BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::OneShot].Channel, BASS_ATTRIB_VOL, fVol); } } @@ -55,7 +51,7 @@ void SetVolumeFX(int vol) GlobalFXVolume = vol; } -bool Sound_LoadSample(char *pointer, int compSize, int uncompSize, int index) +bool LoadSample(char *pointer, int compSize, int uncompSize, int index) { if (index >= SOUND_MAX_SAMPLES) { @@ -156,18 +152,18 @@ long SoundEffect(int effectID, PHD_3DPOS* position, int env_flags, float pitchMu // We set it to -2 afterwards to prevent further debug message firings. if (sampleIndex == -1) { - logE("Non present effect %d \n", effectID); + logE("Non present effect ", effectID); g_Level.SoundMap[effectID] = -2; return 0; } else if (sampleIndex == -2) return 0; - SAMPLE_INFO *sampleInfo = &g_Level.SoundDetails[sampleIndex]; + SampleInfo* sampleInfo = &g_Level.SoundDetails[sampleIndex]; - if (sampleInfo->number < 0) + if (sampleInfo->Number < 0) { - logD("No valid samples count for effect %d", sampleIndex); + logD("No valid samples count for effect ", sampleIndex); return 0; } @@ -175,7 +171,7 @@ long SoundEffect(int effectID, PHD_3DPOS* position, int env_flags, float pitchMu DWORD sampleFlags = SOUND_SAMPLE_FLAGS; // Effect's chance to play. - if ((sampleInfo->randomness) && ((GetRandomControl() & 127) > sampleInfo->randomness)) + if ((sampleInfo->Randomness) && ((GetRandomControl() & 127) > sampleInfo->Randomness)) return 0; // Apply 3D attrib only to sound with position property @@ -183,19 +179,19 @@ long SoundEffect(int effectID, PHD_3DPOS* position, int env_flags, float pitchMu sampleFlags |= BASS_SAMPLE_3D; // Set & randomize volume (if needed) - float gain = (static_cast(sampleInfo->volume) / 255.0f) * gainMultiplier; - if ((sampleInfo->flags & SOUND_FLAG_RND_GAIN)) + float gain = (static_cast(sampleInfo->Volume) / 255.0f) * gainMultiplier; + if ((sampleInfo->Flags & SOUND_FLAG_RND_GAIN)) gain -= (static_cast(GetRandomControl()) / static_cast(RAND_MAX))* SOUND_MAX_GAIN_CHANGE; // Set and randomize pitch and additionally multiply by provided value (for vehicles etc) - float pitch = (1.0f + static_cast(sampleInfo->pitch) / 127.0f) * pitchMultiplier; + float pitch = (1.0f + static_cast(sampleInfo->Pitch) / 127.0f) * pitchMultiplier; // Randomize pitch (if needed) - if ((sampleInfo->flags & SOUND_FLAG_RND_PITCH)) + if ((sampleInfo->Flags & SOUND_FLAG_RND_PITCH)) pitch += ((static_cast(GetRandomControl()) / static_cast(RAND_MAX)) - 0.5f)* SOUND_MAX_PITCH_CHANGE * 2.0f; // Calculate sound radius and distance to sound - float radius = (float)(sampleInfo->radius) * 1024.0f; + float radius = (float)(sampleInfo->Radius) * 1024.0f; float distance = Sound_DistanceToListener(position); // Don't play sound if it's too far from listener's position. @@ -209,23 +205,23 @@ long SoundEffect(int effectID, PHD_3DPOS* position, int env_flags, float pitchMu int existingChannel = Sound_EffectIsPlaying(effectID, position); // Select behaviour based on effect playback type (bytes 0-1 of flags field) - int playType = sampleInfo->flags & 3; + auto playType = (SOUND_PLAYTYPE)(sampleInfo->Flags & 3); switch (playType) { - case SOUND_NORMAL: + case SOUND_PLAYTYPE::Normal: break; - case SOUND_WAIT: + case SOUND_PLAYTYPE::Wait: if (existingChannel != -1) // Don't play until stopped return 0; break; - case SOUND_RESTART: + case SOUND_PLAYTYPE::Restart: if (existingChannel != -1) // Stop existing and continue Sound_FreeSlot(existingChannel, SOUND_XFADETIME_CUTSOUND); break; - case SOUND_LOOPED: + case SOUND_PLAYTYPE::Looped: if (existingChannel != -1) // Just update parameters and return, if already playing { Sound_UpdateEffectPosition(existingChannel, position); @@ -238,11 +234,11 @@ long SoundEffect(int effectID, PHD_3DPOS* position, int env_flags, float pitchMu // Randomly select arbitrary sample from the list, if more than one is present int sampleToPlay = 0; - int numSamples = (sampleInfo->flags >> 2) & 15; + int numSamples = (sampleInfo->Flags >> 2) & 15; if (numSamples == 1) - sampleToPlay = sampleInfo->number; + sampleToPlay = sampleInfo->Number; else - sampleToPlay = sampleInfo->number + (int)((GetRandomControl() * numSamples) >> 15); + sampleToPlay = sampleInfo->Number + (int)((GetRandomControl() * numSamples) >> 15); // Get free channel to play sample int freeSlot = Sound_GetFreeSlot(); @@ -259,17 +255,17 @@ long SoundEffect(int effectID, PHD_3DPOS* position, int env_flags, float pitchMu return 0; // Finally ready to play sound, assign it to sound slot. - SoundSlot[freeSlot].state = SOUND_STATE_IDLE; - SoundSlot[freeSlot].effectID = effectID; - SoundSlot[freeSlot].channel = channel; - SoundSlot[freeSlot].gain = gain; - SoundSlot[freeSlot].origin = position ? Vector3(position->xPos, position->yPos, position->zPos) : SOUND_OMNIPRESENT_ORIGIN; + SoundSlot[freeSlot].State = SOUND_STATE::Idle; + SoundSlot[freeSlot].EffectID = effectID; + SoundSlot[freeSlot].Channel = channel; + SoundSlot[freeSlot].Gain = gain; + SoundSlot[freeSlot].Origin = position ? Vector3(position->xPos, position->yPos, position->zPos) : SOUND_OMNIPRESENT_ORIGIN; if (Sound_CheckBASSError("Applying pitch/gain attribs on channel %x, sample %d", false, channel, sampleToPlay)) return 0; // Set looped flag, if necessary - if (playType == SOUND_LOOPED) + if (playType == SOUND_PLAYTYPE::Looped) BASS_ChannelFlags(channel, BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // Play channel @@ -292,58 +288,50 @@ long SoundEffect(int effectID, PHD_3DPOS* position, int env_flags, float pitchMu void StopSoundEffect(short effectID) { for (int i = 0; i < SOUND_MAX_CHANNELS; i++) - if (SoundSlot[i].effectID == effectID && SoundSlot[i].channel != NULL && BASS_ChannelIsActive(SoundSlot[i].channel) == BASS_ACTIVE_PLAYING) + if (SoundSlot[i].EffectID == effectID && SoundSlot[i].Channel != NULL && BASS_ChannelIsActive(SoundSlot[i].Channel) == BASS_ACTIVE_PLAYING) Sound_FreeSlot(i, SOUND_XFADETIME_CUTSOUND); } -void Sound_Stop() +void StopAllSounds() { for (int i = 0; i < SOUND_MAX_CHANNELS; i++) - if (SoundSlot[i].channel != NULL && BASS_ChannelIsActive(SoundSlot[i].channel)) - BASS_ChannelStop(SoundSlot[i].channel); + if (SoundSlot[i].Channel != NULL && BASS_ChannelIsActive(SoundSlot[i].Channel)) + BASS_ChannelStop(SoundSlot[i].Channel); ZeroMemory(SoundSlot, (sizeof(SoundEffectSlot) * SOUND_MAX_CHANNELS)); } -void Sound_FreeSamples() +void FreeSamples() { - Sound_Stop(); + StopAllSounds(); for (int i = 0; i < SOUND_MAX_SAMPLES; i++) Sound_FreeSample(i); } -void PlaySoundTrack(short track, short flags) -{ - PlaySoundTrack(track, flags, SOUND_TRACK_ONESHOT); -} - -void PlaySoundTrack(std::string track, unsigned int mode) +void PlaySoundTrack(std::string track, SOUNDTRACK_PLAYTYPE mode, QWORD position) { bool crossfade = false; - DWORD crossfadeTime; + DWORD crossfadeTime = 0; DWORD flags = BASS_STREAM_AUTOFREE | BASS_SAMPLE_FLOAT | BASS_ASYNCFILE; - mode = (mode >= NUM_SOUND_TRACK_TYPES) ? SOUND_TRACK_BGM : mode; - - bool channelActive = BASS_ChannelIsActive(BASS_Soundtrack[mode].channel); - if (channelActive && BASS_Soundtrack[mode].track.compare(track) == 0) + bool channelActive = BASS_ChannelIsActive(BASS_Soundtrack[(int)mode].Channel); + if (channelActive && BASS_Soundtrack[(int)mode].Track.compare(track) == 0) return; switch (mode) { - case SOUND_TRACK_ONESHOT: - crossfadeTime = SOUND_XFADETIME_ONESHOT; - break; + case SOUNDTRACK_PLAYTYPE::OneShot: + crossfadeTime = SOUND_XFADETIME_ONESHOT; + break; - case SOUND_TRACK_BGM: - crossfade = true; - crossfadeTime = channelActive ? SOUND_XFADETIME_BGM : SOUND_XFADETIME_BGM_START; - flags |= BASS_SAMPLE_LOOP; - CurrentLoopedSoundTrack = track; - break; + case SOUNDTRACK_PLAYTYPE::BGM: + crossfade = true; + crossfadeTime = channelActive ? SOUND_XFADETIME_BGM : SOUND_XFADETIME_BGM_START; + flags |= BASS_SAMPLE_LOOP; + break; } - if(channelActive) - BASS_ChannelSlideAttribute(BASS_Soundtrack[mode].channel, BASS_ATTRIB_VOL, -1.0f, crossfadeTime); + if (channelActive) + BASS_ChannelSlideAttribute(BASS_Soundtrack[(int)mode].Channel, BASS_ATTRIB_VOL, -1.0f, crossfadeTime); static char fullTrackName[1024]; char const* name = track.c_str(); @@ -371,10 +359,10 @@ void PlaySoundTrack(std::string track, unsigned int mode) // Damp BGM track in case one-shot track is about to play. - if (mode == SOUND_TRACK_ONESHOT) + if (mode == SOUNDTRACK_PLAYTYPE::OneShot) { - if (BASS_ChannelIsActive(BASS_Soundtrack[SOUND_TRACK_BGM].channel)) - BASS_ChannelSlideAttribute(BASS_Soundtrack[SOUND_TRACK_BGM].channel, BASS_ATTRIB_VOL, masterVolume * SOUND_BGM_DAMP_COEFFICIENT, SOUND_XFADETIME_BGM_START); + if (BASS_ChannelIsActive(BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::BGM].Channel)) + BASS_ChannelSlideAttribute(BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::BGM].Channel, BASS_ATTRIB_VOL, masterVolume * SOUND_BGM_DAMP_COEFFICIENT, SOUND_XFADETIME_BGM_START); BASS_ChannelSetSync(stream, BASS_SYNC_FREE | BASS_SYNC_ONETIME | BASS_SYNC_MIXTIME, 0, Sound_FinishOneshotTrack, NULL); } @@ -388,62 +376,95 @@ void PlaySoundTrack(std::string track, unsigned int mode) BASS_ChannelSlideAttribute(stream, BASS_ATTRIB_VOL, masterVolume, crossfadeTime); // Shuffle... - QWORD newPos = BASS_ChannelGetLength(stream, BASS_POS_BYTE) * (static_cast(GetRandomControl()) / static_cast(RAND_MAX)); - BASS_ChannelSetPosition(stream, newPos, BASS_POS_BYTE); + // Only activates if no custom position is passed as argument. + if (!position) + { + QWORD newPos = BASS_ChannelGetLength(stream, BASS_POS_BYTE) * (static_cast(GetRandomControl()) / static_cast(RAND_MAX)); + BASS_ChannelSetPosition(stream, newPos, BASS_POS_BYTE); + } } else BASS_ChannelSetAttribute(stream, BASS_ATTRIB_VOL, masterVolume); BASS_ChannelPlay(stream, false); + // Try to restore position, if specified. + if (position && (BASS_ChannelGetLength(stream, BASS_POS_BYTE) > position)) + BASS_ChannelSetPosition(stream, position, BASS_POS_BYTE); + if (Sound_CheckBASSError("Playing soundtrack %s", false, fullTrackName)) return; - BASS_Soundtrack[mode].channel = stream; - BASS_Soundtrack[mode].track = track; + BASS_Soundtrack[(int)mode].Channel = stream; + BASS_Soundtrack[(int)mode].Track = track; } -void PlaySoundTrack(std::string track, DWORD mask, DWORD unknown) +void PlaySoundTrack(std::string track, short mask) +{ + // If track name was included in script, play it as registered track and take mask into account. + // Otherwise, play it once without registering anywhere. + + if (SoundTrackMap.count(track)) + PlaySoundTrack(SoundTrackMap[track], mask); + else + PlaySoundTrack(track, SOUNDTRACK_PLAYTYPE::OneShot); +} + +void PlaySoundTrack(int index, short mask) { // Check and modify soundtrack map mask, if needed. // If existing mask is unmodified (same activation mask setup), track won't play. - if (!SoundTracks[track].looped) + + if (!(SoundTracks[index].Mode == SOUNDTRACK_PLAYTYPE::BGM)) { - byte filteredMask = (mask >> 8) & 0x3F; - if ((SoundTracks[track].Mask & filteredMask) == filteredMask) + short filteredMask = (mask >> 8) & 0x3F; + if ((SoundTracks[index].Mask & filteredMask) == filteredMask) return; // Mask is the same, don't play it. - SoundTracks[track].Mask |= filteredMask; + SoundTracks[index].Mask |= filteredMask; } - PlaySoundTrack(track, SoundTracks[track].looped); -} - -void PlaySoundTrack(int index, DWORD mask, DWORD unknown) -{ - std::pair& track = *std::next(SoundTracks.begin(), index); - PlaySoundTrack(track.first, mask, unknown); + PlaySoundTrack(SoundTracks[index].Name, SoundTracks[index].Mode); } void StopSoundTracks() { // Do quick fadeouts. - BASS_ChannelSlideAttribute(BASS_Soundtrack[SOUND_TRACK_ONESHOT].channel, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, -1.0f, SOUND_XFADETIME_ONESHOT); - BASS_ChannelSlideAttribute(BASS_Soundtrack[SOUND_TRACK_BGM].channel, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, -1.0f, SOUND_XFADETIME_ONESHOT); + BASS_ChannelSlideAttribute(BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::OneShot].Channel, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, -1.0f, SOUND_XFADETIME_ONESHOT); + BASS_ChannelSlideAttribute(BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::BGM].Channel, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, -1.0f, SOUND_XFADETIME_ONESHOT); - BASS_Soundtrack[SOUND_TRACK_ONESHOT].track = ""; - BASS_Soundtrack[SOUND_TRACK_ONESHOT].channel = NULL; - BASS_Soundtrack[SOUND_TRACK_BGM].track = ""; - BASS_Soundtrack[SOUND_TRACK_BGM].channel = NULL; + BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::OneShot].Track = ""; + BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::OneShot].Channel = NULL; + BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::BGM].Track = ""; + BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::BGM].Channel = NULL; +} + +void ClearSoundTrackMasks() +{ + for (auto& track : SoundTracks) { track.Mask = 0; } +} + +// Returns specified soundtrack type's stem name and playhead position. +// To be used with savegames. To restore soundtrack, use PlaySoundtrack function with playhead position passed as 3rd argument. + +std::pair GetSoundTrackNameAndPosition(SOUNDTRACK_PLAYTYPE type) +{ + auto track = BASS_Soundtrack[(int)type]; + + if (track.Track.empty() || !BASS_ChannelIsActive(track.Channel)) + return std::pair(); + + std::filesystem::path path = track.Track; + return std::pair(path.stem().string(), BASS_ChannelGetPosition(track.Channel, BASS_POS_BYTE)); } static void CALLBACK Sound_FinishOneshotTrack(HSYNC handle, DWORD channel, DWORD data, void* userData) { - if (BASS_ChannelIsActive(BASS_Soundtrack[SOUND_TRACK_BGM].channel)) - BASS_ChannelSlideAttribute(BASS_Soundtrack[SOUND_TRACK_BGM].channel, BASS_ATTRIB_VOL, (float)GlobalMusicVolume / 100.0f, SOUND_XFADETIME_BGM_START); + if (BASS_ChannelIsActive(BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::BGM].Channel)) + BASS_ChannelSlideAttribute(BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::BGM].Channel, BASS_ATTRIB_VOL, (float)GlobalMusicVolume / 100.0f, SOUND_XFADETIME_BGM_START); - BASS_Soundtrack[SOUND_TRACK_ONESHOT].track = ""; - BASS_Soundtrack[SOUND_TRACK_ONESHOT].channel = NULL; + BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::OneShot].Track = ""; + BASS_Soundtrack[(int)SOUNDTRACK_PLAYTYPE::OneShot].Channel = NULL; } void Sound_FreeSample(int index) @@ -462,7 +483,7 @@ int Sound_GetFreeSlot() { for (int i = 0; i < SOUND_MAX_CHANNELS; i++) { - if (SoundSlot[i].channel == NULL || !BASS_ChannelIsActive(SoundSlot[i].channel)) + if (SoundSlot[i].Channel == NULL || !BASS_ChannelIsActive(SoundSlot[i].Channel)) return i; } @@ -473,7 +494,7 @@ int Sound_GetFreeSlot() for (int i = 0; i < SOUND_MAX_CHANNELS; i++) { - float distance = Vector3(SoundSlot[i].origin - Vector3(Camera.mikePos.x, Camera.mikePos.y, Camera.mikePos.z)).Length(); + float distance = Vector3(SoundSlot[i].Origin - Vector3(Camera.mikePos.x, Camera.mikePos.y, Camera.mikePos.z)).Length(); if (distance > minDistance) { minDistance = distance; @@ -494,28 +515,28 @@ int Sound_EffectIsPlaying(int effectID, PHD_3DPOS *position) { for (int i = 0; i < SOUND_MAX_CHANNELS; i++) { - if (SoundSlot[i].effectID == effectID) + if (SoundSlot[i].EffectID == effectID) { - if (SoundSlot[i].channel == NULL) // Free channel + if (SoundSlot[i].Channel == NULL) // Free channel continue; - if (BASS_ChannelIsActive(SoundSlot[i].channel)) + if (BASS_ChannelIsActive(SoundSlot[i].Channel)) { // Only check position on 3D samples. 2D samples stop immediately. BASS_CHANNELINFO info; - BASS_ChannelGetInfo(SoundSlot[i].channel, &info); + BASS_ChannelGetInfo(SoundSlot[i].Channel, &info); if (!(info.flags & BASS_SAMPLE_3D) || !position) return i; // Check if effect origin is equal OR in nearest possible hearing range. Vector3 origin = Vector3(position->xPos, position->yPos, position->zPos); - if (Vector3::Distance(origin, SoundSlot[i].origin) < SOUND_MAXVOL_RADIUS) + if (Vector3::Distance(origin, SoundSlot[i].Origin) < SOUND_MAXVOL_RADIUS) return i; } else - SoundSlot[i].channel = NULL; // WTF, let's clean this up + SoundSlot[i].Channel = NULL; // WTF, let's clean this up } } return -1; @@ -550,13 +571,13 @@ void Sound_FreeSlot(int index, unsigned int fadeout) return; if (fadeout > 0) - BASS_ChannelSlideAttribute(SoundSlot[index].channel, BASS_ATTRIB_VOL, -1.0f, fadeout); + BASS_ChannelSlideAttribute(SoundSlot[index].Channel, BASS_ATTRIB_VOL, -1.0f, fadeout); else - BASS_ChannelStop(SoundSlot[index].channel); + BASS_ChannelStop(SoundSlot[index].Channel); - SoundSlot[index].channel = NULL; - SoundSlot[index].state = SOUND_STATE_IDLE; - SoundSlot[index].effectID = -1; + SoundSlot[index].Channel = NULL; + SoundSlot[index].State = SOUND_STATE::Idle; + SoundSlot[index].EffectID = -1; } // Update sound position in a level. @@ -569,23 +590,23 @@ bool Sound_UpdateEffectPosition(int index, PHD_3DPOS *position, bool force) if (position) { BASS_CHANNELINFO info; - BASS_ChannelGetInfo(SoundSlot[index].channel, &info); + BASS_ChannelGetInfo(SoundSlot[index].Channel, &info); if (info.flags & BASS_SAMPLE_3D) { - SoundSlot[index].origin.x = position->xPos; - SoundSlot[index].origin.y = position->yPos; - SoundSlot[index].origin.z = position->zPos; + SoundSlot[index].Origin.x = position->xPos; + SoundSlot[index].Origin.y = position->yPos; + SoundSlot[index].Origin.z = position->zPos; auto pos = BASS_3DVECTOR(position->xPos, position->yPos, position->zPos); auto rot = BASS_3DVECTOR(position->xRot, position->yRot, position->zRot); - BASS_ChannelSet3DPosition(SoundSlot[index].channel, &pos, &rot, NULL); + BASS_ChannelSet3DPosition(SoundSlot[index].Channel, &pos, &rot, NULL); BASS_Apply3D(); } } // Reset activity flag, important for looped samples - if (BASS_ChannelIsActive(SoundSlot[index].channel)) - SoundSlot[index].state = SOUND_STATE_IDLE; + if (BASS_ChannelIsActive(SoundSlot[index].Channel)) + SoundSlot[index].State = SOUND_STATE::Idle; return true; } @@ -596,8 +617,8 @@ bool Sound_UpdateEffectAttributes(int index, float pitch, float gain) if (index > SOUND_MAX_CHANNELS || index < 0) return false; - BASS_ChannelSetAttribute(SoundSlot[index].channel, BASS_ATTRIB_FREQ, 22050.0f * pitch); - BASS_ChannelSetAttribute(SoundSlot[index].channel, BASS_ATTRIB_VOL, gain); + BASS_ChannelSetAttribute(SoundSlot[index].Channel, BASS_ATTRIB_FREQ, 22050.0f * pitch); + BASS_ChannelSetAttribute(SoundSlot[index].Channel, BASS_ATTRIB_VOL, gain); return true; } @@ -614,34 +635,34 @@ void Sound_UpdateScene() if (currentReverb == -1 || g_Level.Rooms[Camera.pos.roomNumber].reverbType != currentReverb) { currentReverb = g_Level.Rooms[Camera.pos.roomNumber].reverbType; - if (currentReverb < NUM_REVERB_TYPES) - BASS_FXSetParameters(BASS_FXHandler[SOUND_FILTER_REVERB], &BASS_ReverbTypes[currentReverb]); + if (currentReverb < (int)REVERB_TYPE::Count) + BASS_FXSetParameters(BASS_FXHandler[(int)SOUND_FILTER::Reverb], &BASS_ReverbTypes[currentReverb]); } for (int i = 0; i < SOUND_MAX_CHANNELS; i++) { - if ((SoundSlot[i].channel != NULL) && (BASS_ChannelIsActive(SoundSlot[i].channel) == BASS_ACTIVE_PLAYING)) + if ((SoundSlot[i].Channel != NULL) && (BASS_ChannelIsActive(SoundSlot[i].Channel) == BASS_ACTIVE_PLAYING)) { - SAMPLE_INFO *sampleInfo = &g_Level.SoundDetails[g_Level.SoundMap[SoundSlot[i].effectID]]; + SampleInfo* sampleInfo = &g_Level.SoundDetails[g_Level.SoundMap[SoundSlot[i].EffectID]]; // Stop and clean up sounds which were in ending state in previous frame. // In case sound is looping, make it ending unless they are re-fired in next frame. - if (SoundSlot[i].state == SOUND_STATE_ENDING) + if (SoundSlot[i].State == SOUND_STATE::Ending) { - SoundSlot[i].state = SOUND_STATE_ENDED; + SoundSlot[i].State = SOUND_STATE::Ended; Sound_FreeSlot(i, SOUND_XFADETIME_CUTSOUND); continue; } - else if (sampleInfo->flags & 3 == SOUND_LOOPED) - SoundSlot[i].state = SOUND_STATE_ENDING; + else if ((SOUND_PLAYTYPE)(sampleInfo->Flags & 3) == SOUND_PLAYTYPE::Looped) + SoundSlot[i].State = SOUND_STATE::Ending; // Calculate attenuation and clean up sounds which are out of listener range (only for 3D sounds). - if (SoundSlot[i].origin != SOUND_OMNIPRESENT_ORIGIN) + if (SoundSlot[i].Origin != SOUND_OMNIPRESENT_ORIGIN) { - float radius = (float)(sampleInfo->radius) * 1024.0f; - float distance = Sound_DistanceToListener(SoundSlot[i].origin); + float radius = (float)(sampleInfo->Radius) * 1024.0f; + float distance = Sound_DistanceToListener(SoundSlot[i].Origin); if (distance > radius) { @@ -649,7 +670,7 @@ void Sound_UpdateScene() continue; } else - BASS_ChannelSetAttribute(SoundSlot[i].channel, BASS_ATTRIB_VOL, Sound_Attenuate(SoundSlot[i].gain, distance, radius)); + BASS_ChannelSetAttribute(SoundSlot[i].Channel, BASS_ATTRIB_VOL, Sound_Attenuate(SoundSlot[i].Gain, distance, radius)); } } } @@ -711,20 +732,20 @@ void Sound_Init() return; // Initialize channels and tracks array - ZeroMemory(BASS_Soundtrack, (sizeof(HSTREAM) * NUM_SOUND_TRACK_TYPES)); + ZeroMemory(BASS_Soundtrack, (sizeof(HSTREAM) * (int)SOUNDTRACK_PLAYTYPE::Count)); ZeroMemory(SoundSlot, (sizeof(SoundEffectSlot) * SOUND_MAX_CHANNELS)); // Attach reverb effect to 3D channel - BASS_FXHandler[SOUND_FILTER_REVERB] = BASS_ChannelSetFX(BASS_3D_Mixdown, BASS_FX_BFX_FREEVERB, 0); - BASS_FXSetParameters(BASS_FXHandler[SOUND_FILTER_REVERB], &BASS_ReverbTypes[RVB_OUTSIDE]); + BASS_FXHandler[(int)SOUND_FILTER::Reverb] = BASS_ChannelSetFX(BASS_3D_Mixdown, BASS_FX_BFX_FREEVERB, 0); + BASS_FXSetParameters(BASS_FXHandler[(int)SOUND_FILTER::Reverb], &BASS_ReverbTypes[(int)REVERB_TYPE::Outside]); if (Sound_CheckBASSError("Attaching environmental FX", true)) return; // Apply slight compression to 3D channel - BASS_FXHandler[SOUND_FILTER_COMPRESSOR] = BASS_ChannelSetFX(BASS_3D_Mixdown, BASS_FX_BFX_COMPRESSOR2, 1); + BASS_FXHandler[(int)SOUND_FILTER::Compressor] = BASS_ChannelSetFX(BASS_3D_Mixdown, BASS_FX_BFX_COMPRESSOR2, 1); auto comp = BASS_BFX_COMPRESSOR2{ 4.0f, -18.0f, 1.5f, 10.0f, 100.0f, -1 }; - BASS_FXSetParameters(BASS_FXHandler[SOUND_FILTER_COMPRESSOR], &comp); + BASS_FXSetParameters(BASS_FXHandler[(int)SOUND_FILTER::Compressor], &comp); if (Sound_CheckBASSError("Attaching compressor", true)) return; @@ -762,6 +783,11 @@ void SayNo() SoundEffect(SFX_TR4_LARA_NO, NULL, SFX_ALWAYS); } +void PlaySecretTrack() +{ + PlaySoundTrack(SoundTracks.size()); +} + int GetShatterSound(int shatterID) { auto fxID = StaticObjects[shatterID].shatterSound; diff --git a/TR5Main/Sound/sound.h b/TR5Main/Sound/sound.h index ba5bedd50..6b46549a7 100644 --- a/TR5Main/Sound/sound.h +++ b/TR5Main/Sound/sound.h @@ -1,16 +1,10 @@ #pragma once + #include #include #include "control/control.h" #include "sound_effects.h" -enum SFX_TYPES -{ - SFX_LANDANDWATER = 0, - SFX_LANDONLY = (1 << 14), - SFX_WATERONLY = (2 << 14) -}; - #define SFX_ALWAYS 2 #define SOUND_BASS_UNITS 1.0f / 1024.0f // TR->BASS distance unit coefficient @@ -35,102 +29,108 @@ enum SFX_TYPES #define SOUND_XFADETIME_HIJACKSOUND 50 #define SOUND_BGM_DAMP_COEFFICIENT 0.6f -#define TRACK_FOUND_SECRET "073_Secret" #define TRACKS_PREFIX "Audio\\%s.%s" +enum class SOUNDTRACK_PLAYTYPE +{ + OneShot, + BGM, + Count +}; + +enum class SOUND_PLAYCONDITION +{ + LandAndWater = 0, + Land = (1 << 14), + Water = (2 << 14) +}; + +enum class SOUND_PLAYTYPE +{ + Normal, + Wait, + Restart, + Looped +}; + +enum class REVERB_TYPE +{ + Outside, // 0x00 no reverberation + Small, // 0x01 little reverberation + Medium, // 0x02 + Large, // 0x03 + Pipe, // 0x04 highest reverberation, almost never used + Count +}; + +enum class SOUND_STATE +{ + Idle, + Ending, + Ended +}; + +enum class SOUND_FILTER +{ + Reverb, + Compressor, + Lowpass, + Count +}; + struct SoundEffectSlot { - short state; - short effectID; - float gain; - HCHANNEL channel; - Vector3 origin; + SOUND_STATE State; + short EffectID; + float Gain; + HCHANNEL Channel; + Vector3 Origin; }; struct SoundTrackSlot { - HSTREAM channel; - std::string track; + HSTREAM Channel; + std::string Track; }; -enum sound_track_types +struct SampleInfo { - SOUND_TRACK_ONESHOT, - SOUND_TRACK_BGM, - - NUM_SOUND_TRACK_TYPES + short Number; + byte Volume; + byte Radius; + byte Randomness; + signed char Pitch; + short Flags; }; -enum sound_filters -{ - SOUND_FILTER_REVERB, - SOUND_FILTER_COMPRESSOR, - SOUND_FILTER_LOWPASS, - - NUM_SOUND_FILTERS -}; - -enum sound_states -{ - SOUND_STATE_IDLE, - SOUND_STATE_ENDING, - SOUND_STATE_ENDED -}; - -enum sound_flags -{ - SOUND_NORMAL, - SOUND_WAIT, - SOUND_RESTART, - SOUND_LOOPED -}; - -enum reverb_type -{ - RVB_OUTSIDE, // 0x00 no reverberation - RVB_SMALL_ROOM, // 0x01 little reverberation - RVB_MEDIUM_ROOM, // 0x02 - RVB_LARGE_ROOM, // 0x03 - RVB_PIPE, // 0x04 highest reverberation, almost never used - - NUM_REVERB_TYPES -}; - -struct SAMPLE_INFO -{ - short number; - byte volume; - byte radius; - byte randomness; - signed char pitch; - short flags; -}; - -struct AudioTrack +struct SoundTrackInfo { std::string Name; - byte Mask; - bool looped; + SOUNDTRACK_PLAYTYPE Mode; + short Mask; }; -extern std::unordered_map SoundTracks; -extern std::string CurrentLoopedSoundTrack; +extern std::map SoundTrackMap; +extern std::vector SoundTracks; long SoundEffect(int effectID, PHD_3DPOS* position, int env_flags, float pitchMultiplier = 1.0f, float gainMultiplier = 1.0f); void StopSoundEffect(short effectID); -bool Sound_LoadSample(char *buffer, int compSize, int uncompSize, int currentIndex); -void Sound_FreeSamples(); -void Sound_Stop(); +bool LoadSample(char *buffer, int compSize, int uncompSize, int currentIndex); +void FreeSamples(); +void StopAllSounds(); -void PlaySoundTrack(short track, short flags); -void PlaySoundTrack(std::string trackName, unsigned int mode); -void PlaySoundTrack(std::string trackName, DWORD mask, DWORD unknown); -void PlaySoundTrack(int index, DWORD mask, DWORD unknown); +void PlaySoundTrack(std::string trackName, SOUNDTRACK_PLAYTYPE mode, QWORD position = 0); +void PlaySoundTrack(std::string trackName, short mask = 0); +void PlaySoundTrack(int index, short mask = 0); void StopSoundTracks(); +void ClearSoundTrackMasks(); +void PlaySecretTrack(); void SayNo(); void PlaySoundSources(); int GetShatterSound(int shatterID); +std::pair GetSoundTrackNameAndPosition(SOUNDTRACK_PLAYTYPE type); + static void CALLBACK Sound_FinishOneshotTrack(HSYNC handle, DWORD channel, DWORD data, void* userData); void SetVolumeMusic(int vol); diff --git a/TR5Main/Specific/level.cpp b/TR5Main/Specific/level.cpp index 6768e50d8..0b0901715 100644 --- a/TR5Main/Specific/level.cpp +++ b/TR5Main/Specific/level.cpp @@ -1112,7 +1112,7 @@ void LoadSamples() if (numSamplesInfos) { g_Level.SoundDetails.resize(numSamplesInfos); - ReadBytes(g_Level.SoundDetails.data(), numSamplesInfos * sizeof(SAMPLE_INFO)); + ReadBytes(g_Level.SoundDetails.data(), numSamplesInfos * sizeof(SampleInfo)); int numSamples = ReadInt32(); if (numSamples <= 0) @@ -1127,7 +1127,7 @@ void LoadSamples() uncompressedSize = ReadInt32(); compressedSize = ReadInt32(); ReadBytes(buffer, compressedSize); - Sound_LoadSample(buffer, compressedSize, uncompressedSize, i); + LoadSample(buffer, compressedSize, uncompressedSize, i); } free(buffer); @@ -1179,8 +1179,8 @@ int LoadLevelFile(int levelIndex) { logD("Loading level file..."); - Sound_Stop(); - Sound_FreeSamples(); + StopAllSounds(); + FreeSamples(); if (!g_FirstLevel) FreeLevel(); g_FirstLevel = false; diff --git a/TR5Main/Specific/level.h b/TR5Main/Specific/level.h index 7fe05ae2e..b57ca8bbc 100644 --- a/TR5Main/Specific/level.h +++ b/TR5Main/Specific/level.h @@ -15,7 +15,7 @@ struct ChunkId; struct LEB128; -struct SAMPLE_INFO; +struct SampleInfo; struct BOX_INFO; struct OVERLAP; @@ -142,7 +142,7 @@ struct LEVEL std::vector Overlaps; std::vector Zones[MAX_ZONES][2]; std::vector SoundMap; - std::vector SoundDetails; + std::vector SoundDetails; std::vector AnimatedTexturesSequences; int NumItems; int NumSpritesSequences;