diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index 6df4c052..9e86aef0 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -91,9 +91,153 @@ enum eVehicleModel cAudioManager &AudioManager = *(cAudioManager *)0x880FC0; constexpr int totalAudioEntitiesSlots = 200; +constexpr int maxVolume = 127; char &g_nMissionAudioPlayingStatus = *(char *)0x60ED88; +void +cAudioManager::AddSampleToRequestedQueue() +{ + int32 calculatedVolume; + tActiveSample *sample; + int32 unknown1; + uint8 unknown2; + bool bReflections; + + if(m_sQueueSample.m_nSampleIndex < TOTAL_AUDIO_SAMPLES) { + calculatedVolume = m_sQueueSample.field_16 * (maxVolume - m_sQueueSample.m_bVolume); + unknown2 = m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; + if(unknown2 >= m_bActiveSamples) { + unknown1 = 27 * m_bActiveSampleQueue; + unknown2 = *(&m_asSamples[53].field_91 + m_bActiveSamples + unknown1); + if(m_asSamples[unknown1 + unknown2].calculatedVolume <= calculatedVolume) + return; + } else { + ++m_bSampleRequestQueuesStatus[m_bActiveSampleQueue]; + } + m_sQueueSample.calculatedVolume = calculatedVolume; + m_sQueueSample.m_bLoopEnded = 0; + if(m_sQueueSample.m_bIsDistant) { + m_sQueueSample.m_bRequireReflection = 0; + m_sQueueSample.m_bLoopsRemaining = 0; + } + if(m_bDynamicAcousticModelingStatus && m_sQueueSample.m_nLoopCount) { + bReflections = m_sQueueSample.m_bRequireReflection; + } else { + bReflections = false; + m_sQueueSample.m_bLoopsRemaining = 0; + } + m_sQueueSample.m_bRequireReflection = 0; + + if(!m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bReverbFlag = 0; + + sample = &m_asSamples[27 * m_bActiveSampleQueue + unknown2]; + sample->m_nEntityIndex = m_sQueueSample.m_nEntityIndex; + sample->field_4 = m_sQueueSample.field_4; + sample->m_nSampleIndex = m_sQueueSample.m_nSampleIndex; + sample->m_bBankIndex = m_sQueueSample.m_bBankIndex; + sample->m_bIsDistant = m_sQueueSample.m_bIsDistant; + sample->field_16 = m_sQueueSample.field_16; + sample->m_nFrequency = m_sQueueSample.m_nFrequency; + sample->m_bVolume = m_sQueueSample.m_bVolume; + sample->m_fDistance = m_sQueueSample.m_fDistance; + sample->m_nLoopCount = m_sQueueSample.m_nLoopCount; + sample->m_nLoopStart = m_sQueueSample.m_nLoopStart; + sample->m_nLoopEnd = m_sQueueSample.m_nLoopEnd; + sample->m_bEmittingVolume = m_sQueueSample.m_bEmittingVolume; + sample->field_48 = m_sQueueSample.field_48; + sample->m_fSoundIntensity = m_sQueueSample.m_fSoundIntensity; + sample->field_56 = m_sQueueSample.field_56; + sample->m_vecPos = m_sQueueSample.m_vecPos; + sample->m_bReverbFlag = m_sQueueSample.m_bReverbFlag; + sample->m_bLoopsRemaining = m_sQueueSample.m_bLoopsRemaining; + sample->m_bRequireReflection = m_sQueueSample.m_bRequireReflection; + sample->m_bOffset = m_sQueueSample.m_bOffset; + sample->field_76 = m_sQueueSample.field_76; + sample->m_bIsProcessed = m_sQueueSample.m_bIsProcessed; + sample->m_bLoopEnded = m_sQueueSample.m_bLoopEnded; + sample->calculatedVolume = m_sQueueSample.calculatedVolume; + sample->field_88 = m_sQueueSample.field_88; + + AddDetailsToRequestedOrderList(unknown2); + if(bReflections) AddReflectionsToRequestedQueue(); + } +} + +void +cAudioManager::AddDetailsToRequestedOrderList(uint8 sample) +{ + int32 offset; + uint32 i = 0; + if(sample != 0) { + for(; i < sample; i++) { + offset = 27 * m_bActiveSampleQueue; + if(m_asSamples[offset + m_abSampleQueueIndexTable[i + offset]] + .calculatedVolume > m_asSamples[offset + sample].calculatedVolume) + break; + } + if(i < sample) { + memmove(&m_abSampleQueueIndexTable[offset + 1 + i], + &m_abSampleQueueIndexTable[offset + i], m_bActiveSamples - i - 1); + } + } + m_abSampleQueueIndexTable[27 * m_bActiveSampleQueue + i] = sample; +} + +void +cAudioManager::AddReflectionsToRequestedQueue() +{ + float reflectionDistance; + int32 noise; + uint8 emittingVolume = emittingVolume = + (m_sQueueSample.m_bVolume >> 1) + (m_sQueueSample.m_bVolume >> 3); + + for(uint32 i = 0; i < 5u; i++) { + reflectionDistance = m_afReflectionsDistances[i]; + if(reflectionDistance > 0.0f && reflectionDistance < 100.f && + reflectionDistance < m_sQueueSample.m_fSoundIntensity) { + m_sQueueSample.m_bLoopsRemaining = (reflectionDistance * 0.38873f); // @todo assert value + if(m_sQueueSample.m_bLoopsRemaining > 5u) { + m_sQueueSample.m_fDistance = m_afReflectionsDistances[i]; + m_sQueueSample.m_bEmittingVolume = emittingVolume; + m_sQueueSample.m_bVolume = + ComputeVolume(emittingVolume, m_sQueueSample.m_fSoundIntensity, + m_sQueueSample.m_fDistance); + if(m_sQueueSample.m_bVolume > emittingVolume >> 4) { + m_sQueueSample.field_4 += ((i + 1) << 8); + if(m_sQueueSample.m_nLoopCount) { + noise = RandomDisplacement( + m_sQueueSample.m_nFrequency >> 5); + if(noise <= 0) + m_sQueueSample.m_nFrequency += noise; + else + m_sQueueSample.m_nFrequency -= noise; + } + m_sQueueSample.field_16 += 20; + m_sQueueSample.m_vecPos.x = m_avecReflectionsPos[i].x; + m_sQueueSample.m_vecPos.y = m_avecReflectionsPos[i].y; + m_sQueueSample.m_vecPos.z = m_avecReflectionsPos[i].z; + AddSampleToRequestedQueue(); + } + } + } + } +} + +uint32 +cAudioManager::ComputeVolume(int emittingVolume, float soundIntensity, float distance) +{ + float newSoundIntensity; + if(soundIntensity <= 0.0f) return 0; + if((soundIntensity * 0.2f) <= distance) { + newSoundIntensity = soundIntensity * 0.2f; + emittingVolume = + sq((soundIntensity - distance) / (soundIntensity - newSoundIntensity)) * + emittingVolume; + } + return emittingVolume; +} + void cAudioManager::Initialise() { @@ -409,7 +553,7 @@ cAudioManager::ResetPoliceRadio() void cAudioManager::InterrogateAudioEntities() { - for(uint32 i = 0; i < m_nAudioEntitiesTotal; i++) { + for(int32 i = 0; i < m_nAudioEntitiesTotal; i++) { ProcessEntity(m_anAudioEntityIndices[i]); m_asAudioEntities[m_anAudioEntityIndices[i]].field_24 = 0; } @@ -418,7 +562,7 @@ cAudioManager::InterrogateAudioEntities() void cAudioManager::ClearRequestedQueue() { - for(uint32 i = 0; i < m_bActiveSamples; i++) { + for(int32 i = 0; i < m_bActiveSamples; i++) { m_abSampleQueueIndexTable[i + 27 * m_bActiveSampleQueue] = m_bActiveSamples; } m_bSampleRequestQueuesStatus[m_bActiveSampleQueue] = 0; @@ -432,14 +576,14 @@ cAudioManager::ClearRequestedQueue() bool cAudioManager::UsesReverseWarning(int32 model) { - return model == LINERUN || fabs(model - FIRETRUK) <= 1 || model == BUS || + return model == LINERUN || model == FIRETRUK || model == TRASH || model == BUS || model == COACH; // fix } bool cAudioManager::HasAirBrakes(int32 model) { - return model == LINERUN || fabs(model - FIRETRUK) <= 1 || model == BUS || + return model == LINERUN || model == FIRETRUK || model == TRASH || model == BUS || model == COACH; // fix } @@ -594,7 +738,7 @@ cAudioManager::DestroyEntity(int32 id) if(m_bIsInitialised && id >= 0 && id < totalAudioEntitiesSlots && m_asAudioEntities[id].m_bIsUsed) { m_asAudioEntities[id].m_bIsUsed = 0; - for(uint32 i = 0; i < m_nAudioEntitiesTotal; ++i) { + for(int32 i = 0; i < m_nAudioEntitiesTotal; ++i) { if(id == m_anAudioEntityIndices[i]) { if(i < totalAudioEntitiesSlots - 1) memmove(&m_anAudioEntityIndices[i], @@ -2816,6 +2960,11 @@ cAudioManager::Service() } STARTPATCHES +InjectHook(0x57B070, &cAudioManager::AddSampleToRequestedQueue, PATCH_JUMP); +InjectHook(0x57B210, &cAudioManager::AddDetailsToRequestedOrderList, PATCH_JUMP); +InjectHook(0x57B300, &cAudioManager::AddReflectionsToRequestedQueue, PATCH_JUMP); +InjectHook(0x57ABB0, &cAudioManager::ComputeVolume, PATCH_JUMP); + InjectHook(0x57A0E0, &cAudioManager::Initialise, PATCH_JUMP); InjectHook(0x569420, &cAudioManager::PostInitialiseGameSpecificSetup, PATCH_JUMP); //InjectHook(0x57EAC0, &cAudioManager::InitialisePoliceRadioZones, PATCH_JUMP); diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 9796c1c8..7a2dc9c5 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -44,7 +44,7 @@ public: char m_bLoopEnded; char field_82; char field_83; - int field_84; + int calculatedVolume; char field_88; char field_89; char field_90; @@ -218,15 +218,20 @@ public: char field_19195; int m_nTimeOfRecentCrime; + void AddSampleToRequestedQueue(); + + void AddDetailsToRequestedOrderList(uint8 sample); + void AddReflectionsToRequestedQueue(); + + uint32 ComputeVolume(int emittingVolume, float soundIntensity, float distance); + void Initialise(); void PostInitialiseGameSpecificSetup(); - void InitialisePoliceRadioZones(); // @todo + void InitialisePoliceRadioZones(); // @todo void ResetAudioLogicTimers(int32 timer); // @todo void Terminate(); - // done - char GetMissionScriptPoliceAudioPlayingStatus(); bool GetMissionAudioLoadingStatus(); @@ -270,7 +275,7 @@ public: void InterrogateAudioEntities(); void ClearRequestedQueue(); -// void AgeCrimes(); + // void AgeCrimes(); //todo bool UsesReverseWarning(int32 model); bool HasAirBrakes(int32 model); @@ -283,7 +288,7 @@ public: void ProcessPlane(void *); // todo void ClearMissionAudio(); -// void ProcessReverb(); + // void ProcessReverb(); // todo bool IsMissionAudioSampleFinished();