From abbfb09a64e4d9188cb9ef17733693d43e9a51ce Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 24 Aug 2021 14:58:41 +0300 Subject: [PATCH] Audio enhancements: * redo high fps fix * make releasing vehicle sounds attach to entities * fix bug with reusing audio entity that is still being used * use time scale to modify sound speed --- src/audio/AudioLogic.cpp | 15 ++- src/audio/AudioManager.cpp | 186 ++++++++++++++++++++++++++++--------- src/audio/AudioManager.h | 7 ++ src/audio/PolRadio.cpp | 4 + src/core/config.h | 3 +- 5 files changed, 166 insertions(+), 49 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 47c5546b..163a34e7 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -2321,7 +2321,11 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams& params, CVehicle* veh freq = GearFreqAdj[CurrentPretendGear] + freqModifier + 22050; if (engineSoundType == SFX_BANK_TRUCK) freq /= 2; +#ifdef USE_TIME_SCALE_FOR_AUDIO + SampleManager.SetChannelFrequency(nChannel, freq * CTimer::GetTimeScale()); +#else SampleManager.SetChannelFrequency(nChannel, freq); +#endif if (!channelUsed) { #ifdef AUDIO_REVERB SampleManager.SetChannelReverbFlag(nChannel, m_bDynamicAcousticModelingStatus != FALSE); @@ -7870,7 +7874,7 @@ cPedComments::Process() AudioManager.m_sQueueSample.m_nEmittingVolume = MAX_VOLUME; #endif // FIX_BUGS #endif // EXTERNAL_3D_SOUND -#ifdef ATTACH_PED_COMMENTS_TO_ENTITIES +#ifdef ATTACH_RELEASING_SOUNDS_TO_ENTITIES // let's disable doppler because if sounds funny as the sound moves // originally position of ped comment doesn't change so this has no effect anyway AudioManager.m_sQueueSample.m_fSpeedMultiplier = 0.0f; @@ -7891,16 +7895,19 @@ cPedComments::Process() if((sampleIndex >= SFX_POLICE_BOAT_1 && sampleIndex <= SFX_POLICE_BOAT_23) || (sampleIndex >= SFX_POLICE_HELI_1 && sampleIndex <= SFX_POLICE_HELI_20)) AudioManager.m_sQueueSample.m_MaxDistance = 400.0f; - #ifndef ATTACH_PED_COMMENTS_TO_ENTITIES + #ifndef ATTACH_RELEASING_SOUNDS_TO_ENTITIES else if (sampleIndex >= SFX_PLAYER_ANGRY_BUSTED_1 && sampleIndex <= SFX_PLAYER_ON_FIRE_16) { // check if player sfx AudioManager.m_sQueueSample.m_bIs2D = TRUE; AudioManager.m_sQueueSample.m_nPan = 63; } - #endif // ATTACH_PED_COMMENTS_TO_ENTITIES + #endif // ATTACH_RELEASING_SOUNDS_TO_ENTITIES #endif // FIX_BUGS AudioManager.m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(AudioManager.m_sQueueSample.m_nSampleIndex) + AudioManager.RandomDisplacement(750); - if(CTimer::GetIsSlowMotionActive()) AudioManager.m_sQueueSample.m_nFrequency /= 2; +#ifndef USE_TIME_SCALE_FOR_AUDIO + if (CTimer::GetIsSlowMotionActive()) + AudioManager.m_sQueueSample.m_nFrequency >>= 1; +#endif m_asPedComments[m_nActiveBank][m_nIndexMap[m_nActiveBank][0]].m_nProcess = -1; prevSamples[counter++] = sampleIndex; if(counter == 10) counter = 0; diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index f92e15fc..e46bc07e 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -135,8 +135,47 @@ cAudioManager::CreateEntity(eAudioType type, void *entity) return AEHANDLE_ERROR_NOENTITY; if (type >= TOTAL_AUDIO_TYPES) return AEHANDLE_ERROR_BADAUDIOTYPE; + +#ifdef FIX_BUGS + // since sound could still play after entity deletion let's make sure we don't override one that is in use + // find all the free entity IDs that are being used by queued samples + int32 stillUsedEntities[NUM_CHANNELS_GENERIC * NUM_SOUNDS_SAMPLES_BANKS]; + uint32 stillUsedEntitiesCount = 0; + + for (uint8 i = 0; i < NUM_SOUNDS_SAMPLES_BANKS; i++) + for (uint8 j = 0; j < m_SampleRequestQueuesStatus[i]; j++) { + tSound &sound = m_asSamples[i][m_abSampleQueueIndexTable[i][j]]; + if (sound.m_nEntityIndex < 0) continue; + if (!m_asAudioEntities[sound.m_nEntityIndex].m_bIsUsed) { + bool found = false; + for (uint8 k = 0; k < stillUsedEntitiesCount; k++) { + if (stillUsedEntities[k] == sound.m_nEntityIndex) { + found = true; + break; + } + } + if (!found) + stillUsedEntities[stillUsedEntitiesCount++] = sound.m_nEntityIndex; + } + } +#endif + for (uint32 i = 0; i < ARRAY_SIZE(m_asAudioEntities); i++) { if (!m_asAudioEntities[i].m_bIsUsed) { +#ifdef FIX_BUGS + // skip if ID is still used by queued sample + bool skip = false; + for (uint8 j = 0; j < stillUsedEntitiesCount; j++) { + if (stillUsedEntities[j] == i) { + //debug("audio entity %i still used, skipping\n", i); + skip = true; + break; + } + } + if (skip) + continue; +#endif + m_asAudioEntities[i].m_bIsUsed = TRUE; m_asAudioEntities[i].m_bStatus = FALSE; m_asAudioEntities[i].m_nType = type; @@ -936,39 +975,92 @@ cAudioManager::AddReleasingSounds() if(sample.m_nCounter <= 255 || sample.m_nReflectionDelay == 0) // check if not delayed reflection #endif { +#ifdef ATTACH_RELEASING_SOUNDS_TO_ENTITIES + if (sample.m_nCounter <= 255 && !sample.m_bIs2D) { // check if not reflection and is a 3D sound + CEntity* entity = (CEntity*)GetEntityPointer(sample.m_nEntityIndex); + if (entity && m_asAudioEntities[sample.m_nEntityIndex].m_nType == AUDIOTYPE_PHYSICAL) { + sample.m_vecPos = entity->GetPosition(); + float oldDistance = sample.m_fDistance; + sample.m_fDistance = Sqrt(GetDistanceSquared(sample.m_vecPos)); + if (sample.m_nSampleIndex >= SAMPLEBANK_PED_START && sample.m_nSampleIndex <= SAMPLEBANK_PED_END) { // check if it's ped comment + uint8 vol; + if (CWorld::GetIsLineOfSightClear(TheCamera.GetPosition(), sample.m_vecPos, true, false, false, false, false, false)) + vol = MAX_VOLUME; + else + vol = 31; +#ifdef EXTERNAL_3D_SOUND + sample.m_nEmittingVolume = vol; +#endif + sample.m_nVolume = ComputeVolume(vol, sample.m_MaxDistance, sample.m_fDistance); + } else { + // calculate new volume with changed distance + float volumeDiff = sq((sample.m_MaxDistance - sample.m_fDistance) / (sample.m_MaxDistance - oldDistance)); + if (volumeDiff > 0.0f) { + uint8 newVolume = volumeDiff * sample.m_nVolume; + if (sample.m_nVolumeChange > 0) + sample.m_nVolumeChange = volumeDiff * sample.m_nVolumeChange; +#if defined(FIX_BUGS) && defined(EXTERNAL_3D_SOUND) + if (sample.m_nEmittingVolumeChange > 0) + sample.m_nEmittingVolumeChange = volumeDiff * sample.m_nEmittingVolumeChange; +#endif + sample.m_nVolume = Min(127, newVolume); + } + } + if (sample.m_nVolume == 0) + sample.m_nFramesToPlay = 0; + } + } +#endif +#ifdef FIX_BUGS + if (sample.m_nFramesToPlay <= 0) + continue; + if (sample.m_nLoopCount == 0) { + if (sample.m_nVolumeChange == -1) { + sample.m_nVolumeChange = sample.m_nVolume / sample.m_nFramesToPlay; + if (sample.m_nVolumeChange <= 0) + sample.m_nVolumeChange = 1; +#ifdef EXTERNAL_3D_SOUND + sample.m_nEmittingVolumeChange = sample.m_nEmittingVolume / sample.m_nFramesToPlay; + if (sample.m_nEmittingVolumeChange <= 0) + sample.m_nEmittingVolumeChange = 1; +#endif + } + if (sample.m_nVolume <= sample.m_nVolumeChange * CTimer::GetTimeStepFix()) { + sample.m_nFramesToPlay = 0; + continue; + } + sample.m_nVolume -= sample.m_nVolumeChange * CTimer::GetTimeStepFix(); +#ifdef EXTERNAL_3D_SOUND + if (sample.m_nEmittingVolume <= sample.m_nEmittingVolumeChange * CTimer::GetTimeStepFix()) { + sample.m_nFramesToPlay = 0; + continue; + } + sample.m_nEmittingVolume -= sample.m_nEmittingVolumeChange * CTimer::GetTimeStepFix(); +#endif + } + sample.m_nFramesToPlay -= CTimer::GetTimeStepFix(); + if (sample.m_nFramesToPlay < 0) + sample.m_nFramesToPlay = 0; +#else if (sample.m_nFramesToPlay == 0) continue; if (sample.m_nLoopCount == 0) { if (sample.m_nVolumeChange == -1) { -#if defined(FIX_BUGS) && defined(EXTERNAL_3D_SOUND) - sample.m_nVolumeChange = sample.m_nEmittingVolume / sample.m_nFramesToPlay; -#else sample.m_nVolumeChange = sample.m_nVolume / sample.m_nFramesToPlay; -#endif if (sample.m_nVolumeChange <= 0) sample.m_nVolumeChange = 1; } -#if defined(FIX_BUGS) && defined(EXTERNAL_3D_SOUND) - if (sample.m_nEmittingVolume <= sample.m_nVolumeChange) { -#else if (sample.m_nVolume <= sample.m_nVolumeChange) { -#endif sample.m_nFramesToPlay = 0; continue; } -#if defined(FIX_BUGS) && defined(EXTERNAL_3D_SOUND) - sample.m_nEmittingVolume -= sample.m_nVolumeChange; -#else sample.m_nVolume -= sample.m_nVolumeChange; -#endif } -#ifdef FIX_BUGS - if(CTimer::GetLogicalFramesPassed() != 0) + sample.m_nFramesToPlay--; #endif - --sample.m_nFramesToPlay; if (m_bReduceReleasingPriority) { if (sample.m_nPriority < 20) - ++sample.m_nPriority; + sample.m_nPriority++; } sample.m_bStatic = FALSE; } @@ -1002,6 +1094,16 @@ cAudioManager::ProcessActiveQueues() bool8 isPhoneCall; uint8 channelOffset = 0; +#ifdef EXTERNAL_3D_SOUND + #define WORKING_VOLUME_FIELD m_nEmittingVolume +#else + #define WORKING_VOLUME_FIELD m_nVolume +#endif + +#ifdef USE_TIME_SCALE_FOR_AUDIO + float timeScale = m_nUserPause ? 1.0f : CTimer::GetTimeScale(); +#endif + for (int32 i = 0; i < m_nActiveSamples; i++) { m_asSamples[m_nActiveSampleQueue][i].m_bIsBeingPlayed = FALSE; m_asActiveSamples[i].m_bIsBeingPlayed = FALSE; @@ -1034,12 +1136,12 @@ cAudioManager::ProcessActiveQueues() sample.m_nVolumeChange = -1; if (!sample.m_bStatic) { if (sample.m_bIs2D) { -#ifdef EXTERNAL_3D_SOUND - emittingVol = m_bDoubleVolume ? 2 * Min(63, sample.m_nEmittingVolume) : sample.m_nEmittingVolume; + emittingVol = m_bDoubleVolume ? 2 * Min(63, sample.WORKING_VOLUME_FIELD) : sample.WORKING_VOLUME_FIELD; +#ifdef USE_TIME_SCALE_FOR_AUDIO + SampleManager.SetChannelFrequency(j, sample.m_nFrequency * timeScale); #else - emittingVol = m_bDoubleVolume ? 2 * Min(63, sample.m_nVolume) : sample.m_nVolume; -#endif SampleManager.SetChannelFrequency(j, sample.m_nFrequency); +#endif #ifdef EXTERNAL_3D_SOUND SampleManager.SetChannelEmittingVolume(j, emittingVol); #else @@ -1047,24 +1149,6 @@ cAudioManager::ProcessActiveQueues() SampleManager.SetChannelVolume(j, emittingVol); #endif } else { -#ifdef ATTACH_PED_COMMENTS_TO_ENTITIES - if (sample.m_nCounter <= 255 && sample.m_nSampleIndex >= SAMPLEBANK_PED_START && sample.m_nSampleIndex <= SAMPLEBANK_PED_END) { - CEntity* entity = (CEntity*)GetEntityPointer(sample.m_nEntityIndex); - if (entity && m_asAudioEntities[sample.m_nEntityIndex].m_nType == AUDIOTYPE_PHYSICAL) { - sample.m_vecPos = entity->GetPosition(); - sample.m_fDistance = Sqrt(GetDistanceSquared(sample.m_vecPos)); - uint8 vol; - if (CWorld::GetIsLineOfSightClear(TheCamera.GetPosition(), sample.m_vecPos, true, false, false, false, false, false)) - vol = MAX_VOLUME; - else - vol = 31; -#ifdef EXTERNAL_3D_SOUND - sample.m_nEmittingVolume = vol; -#endif - sample.m_nVolume = ComputeVolume(vol, sample.m_MaxDistance, sample.m_fDistance); - } - } -#endif position2 = sample.m_fDistance; position1 = m_asActiveSamples[j].m_fDistance; m_asActiveSamples[j].m_fDistance = sample.m_fDistance; @@ -1072,7 +1156,11 @@ cAudioManager::ProcessActiveQueues() if (sample.m_nFrequency != m_asActiveSamples[j].m_nFrequency) { uint32 freq = Clamp2((int32)sample.m_nFrequency, (int32)m_asActiveSamples[j].m_nFrequency, 6000); m_asActiveSamples[j].m_nFrequency = freq; +#ifdef USE_TIME_SCALE_FOR_AUDIO + SampleManager.SetChannelFrequency(j, freq * timeScale); +#else SampleManager.SetChannelFrequency(j, freq); +#endif } #ifdef EXTERNAL_3D_SOUND if (sample.m_nEmittingVolume != m_asActiveSamples[j].m_nEmittingVolume) { @@ -1160,18 +1248,18 @@ cAudioManager::ProcessActiveQueues() m_asActiveSamples[j].m_nPan = ComputePan(m_asActiveSamples[j].m_fDistance, &position); #endif } -#ifdef EXTERNAL_3D_SOUND - emittingVol = m_bDoubleVolume ? 2 * Min(63, m_asActiveSamples[j].m_nEmittingVolume) : m_asActiveSamples[j].m_nEmittingVolume; -#else - emittingVol = m_bDoubleVolume ? 2 * Min(63, m_asActiveSamples[j].m_nVolume) : m_asActiveSamples[j].m_nVolume; -#endif + emittingVol = m_bDoubleVolume ? 2 * Min(63, m_asActiveSamples[j].WORKING_VOLUME_FIELD) : m_asActiveSamples[j].WORKING_VOLUME_FIELD; #ifdef GTA_PS2 { SampleManager.InitialiseChannel(k, m_asActiveSamples[k].m_nSampleIndex, m_asActiveSamples[k].m_nBankIndex); #else if (SampleManager.InitialiseChannel(k, m_asActiveSamples[k].m_nSampleIndex, m_asActiveSamples[k].m_nBankIndex)) { #endif +#ifdef USE_TIME_SCALE_FOR_AUDIO + SampleManager.SetChannelFrequency(k, m_asActiveSamples[k].m_nFrequency * timeScale); +#else SampleManager.SetChannelFrequency(k, m_asActiveSamples[k].m_nFrequency); +#endif isPhoneCall = FALSE; for (int32 l = 0; l < MISSION_AUDIO_SLOTS; l++) { if (m_bIsMissionAudioPhoneCall[l]) { @@ -1194,8 +1282,8 @@ cAudioManager::ProcessActiveQueues() #endif #ifndef GTA_PS2 SampleManager.SetChannelLoopPoints(k, m_asActiveSamples[k].m_nLoopStart, m_asActiveSamples[k].m_nLoopEnd); - SampleManager.SetChannelLoopCount(k, m_asActiveSamples[k].m_nLoopCount); #endif + SampleManager.SetChannelLoopCount(k, m_asActiveSamples[k].m_nLoopCount); #if !defined(GTA_PS2) || defined(AUDIO_REVERB) SampleManager.SetChannelReverbFlag(k, m_asActiveSamples[k].m_bReverb); #endif @@ -1232,10 +1320,20 @@ cAudioManager::ProcessActiveQueues() } } } + #ifdef GTA_PS2 m_nChannelOffset += channelOffset; #endif m_nChannelOffset %= m_nActiveSamples; + +#ifdef USE_TIME_SCALE_FOR_AUDIO + for (uint8 i = 0; i < m_nActiveSamples; i++) { + if (m_asActiveSamples[i].m_nSampleIndex != NO_SAMPLE && m_asActiveSamples[i].m_bIsBeingPlayed) + SampleManager.SetChannelFrequency(i, m_asActiveSamples[i].m_nFrequency * timeScale); + } +#endif + +#undef WORKING_VOLUME_FIELD } void diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 821732df..8708fecd 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -44,14 +44,21 @@ public: // 63 = L 100% R 100% // 127 = L 0% R 100% uint8 m_nFrontRearPan; // Used on PS2 for surround panning +#ifndef FIX_BUGS uint32 m_nFramesToPlay; // Number of frames the sound would be played (if it stops being queued). // This one is being set by queued sample for looping sounds, otherwise calculated inside AudioManager +#else + float m_nFramesToPlay; // Made into float for high fps fix +#endif // all fields below are internal to AudioManager calculations and aren't set by queued sample bool8 m_bIsBeingPlayed; // Set to TRUE when the sound was added or changed on current frame to avoid it being overwritten bool8 m_bIsPlayingFinished; // Not sure about the name. Set to TRUE when sampman channel becomes free uint32 m_nFinalPriority; // Actual value used to compare priority, calculated using volume and m_nPriority. Lesser value means higher priority int8 m_nVolumeChange; // How much m_nVolume should reduce per each frame. +#if defined(FIX_BUGS) && defined(EXTERNAL_3D_SOUND) + int8 m_nEmittingVolumeChange; // same as above but for m_nEmittingVolume +#endif }; VALIDATE_SIZE(tSound, 96); diff --git a/src/audio/PolRadio.cpp b/src/audio/PolRadio.cpp index da09eeb9..49b8368c 100644 --- a/src/audio/PolRadio.cpp +++ b/src/audio/PolRadio.cpp @@ -236,7 +236,11 @@ cAudioManager::ServicePoliceRadioChannel(uint8 wantedLevel) default: freq = SampleManager.GetSampleBaseFrequency(sample); break; } PoliceChannelFreq = freq; +#ifdef USE_TIME_SCALE_FOR_AUDIO + SampleManager.SetChannelFrequency(CHANNEL_POLICE_RADIO, freq * CTimer::GetTimeScale()); +#else SampleManager.SetChannelFrequency(CHANNEL_POLICE_RADIO, freq); +#endif SampleManager.SetChannelVolume(CHANNEL_POLICE_RADIO, 100); SampleManager.SetChannelPan(CHANNEL_POLICE_RADIO, 63); #ifndef GTA_PS2 diff --git a/src/core/config.h b/src/core/config.h index cb9deb7f..55232f06 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -449,7 +449,8 @@ static_assert(false, "SUPPORT_XBOX_SCRIPT and SUPPORT_MOBILE_SCRIPT are mutually //#define AUDIO_OAL_USE_SNDFILE // use libsndfile to decode WAVs instead of our internal decoder #define AUDIO_OAL_USE_MPG123 // use mpg123 to support mp3 files #define PAUSE_RADIO_IN_FRONTEND // pause radio when game is paused -#define ATTACH_PED_COMMENTS_TO_ENTITIES // ped comments coordinates would update following ped entity +#define ATTACH_RELEASING_SOUNDS_TO_ENTITIES // ped comments coordinates would update following ped entity +#define USE_TIME_SCALE_FOR_AUDIO // slow down/speed up sounds according to the speed of the game #define MULTITHREADED_AUDIO // for streams. requires C++11 or later #ifdef AUDIO_OPUS