Skip to content

Commit

Permalink
CAEPedSpeechAudioEntity + Fixes (#749)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pirulax authored Sep 30, 2024
1 parent 5cd7142 commit c91981e
Show file tree
Hide file tree
Showing 103 changed files with 13,312 additions and 8,284 deletions.
1 change: 0 additions & 1 deletion source/StdInc.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ namespace fs = std::filesystem;
#include "game_sa\Enums\eClothesTexturePart.h"
#include "game_sa\Enums\eCrimeType.h"
#include "game_sa\Enums\eDecisionMakerEvents.h"
#include "game_sa\Enums\eEmergencyPedVoices.h"
#include "game_sa\Enums\eEntityStatus.h"
#include "game_sa\Enums\eEntityType.h"
#include "game_sa\Enums\eEventType.h"
Expand Down
12 changes: 12 additions & 0 deletions source/extensions/WEnum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,15 @@ using WEnumU32 = WEnum<E, std::uint32_t>;
template<typename E>
using WEnumS32 = WEnum<E, std::int32_t>;
};

#define NOTSA_WENUM_DEFS_FOR(_e) \
using _e##S8 = notsa::WEnumS8<_e>; \
using _e##S16 = notsa::WEnumS16<_e>; \
using _e##S32 = notsa::WEnumS32<_e>;

//! Use unary operator + instead of ugly `static_cast` for enum (class) for casting to underlaying type
template <typename T>
requires std::is_enum_v<T>
inline constexpr auto operator+(T e) noexcept {
return static_cast<std::underlying_type_t<T>>(e);
}
17 changes: 17 additions & 0 deletions source/extensions/ci_string.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "KeyGen.h"
#include <string>
#include <string_view>

Expand Down Expand Up @@ -32,3 +33,19 @@ struct ci_char_traits : public std::char_traits<char> {
using ci_string = std::basic_string<char, details::ci_char_traits>;
using ci_string_view = std::basic_string_view<char, details::ci_char_traits>;
}; // namespace notsa

namespace std {
template<>
struct hash<notsa::ci_string> {
std::size_t operator()(const notsa::ci_string& s) const noexcept {
return CKeyGen::GetUppercaseKey(s.data(), s.data() + s.size());
}
};

template<>
struct hash<notsa::ci_string_view> {
std::size_t operator()(const notsa::ci_string_view& s) const noexcept {
return CKeyGen::GetUppercaseKey(s.data(), s.data() + s.size());
}
};
}
55 changes: 23 additions & 32 deletions source/game_sa/Audio/AEAudioEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ void CAEAudioEnvironment::InjectHooks() {
RH_ScopedInstall(GetDistanceAttenuation, 0x4D7F20);
RH_ScopedInstall(GetDirectionalMikeAttenuation, 0x4D7F60);
RH_ScopedInstall(GetReverbEnvironmentAndDepth, 0x4D8010);
RH_ScopedOverloadedInstall(GetPositionRelativeToCamera, "vec", 0x4D80B0, void(*)(CVector*, const CVector*));
RH_ScopedOverloadedInstall(GetPositionRelativeToCamera, "placeable", 0x4D8340, void(*)(CVector*, CPlaceable*));
RH_ScopedOverloadedInstall(GetPositionRelativeToCamera, "vec", 0x4D80B0, CVector(*)(const CVector&));
RH_ScopedOverloadedInstall(GetPositionRelativeToCamera, "placeable", 0x4D8340, CVector(*)(CPlaceable*));
}

// 0x4D7E40
Expand Down Expand Up @@ -95,38 +95,29 @@ void CAEAudioEnvironment::GetReverbEnvironmentAndDepth(int8* reverbEnv, int32* d
}

// 0x4D80B0
void CAEAudioEnvironment::GetPositionRelativeToCamera(CVector* vecOut, const CVector* vecPos) {
static const float fFirstPersonMult = 2.0F;
if (!vecPos)
return;

const auto camMode = CCamera::GetActiveCamera().m_nMode;
if (camMode == eCamMode::MODE_SNIPER || camMode == eCamMode::MODE_ROCKETLAUNCHER || camMode == eCamMode::MODE_1STPERSON) {
const auto& tempMat = TheCamera.m_mCameraMatrix;
const auto& vecCamPos = TheCamera.GetPosition();
const auto vecOffset = *vecPos - (vecCamPos - tempMat.GetForward() * fFirstPersonMult);

vecOut->x = -DotProduct(vecOffset, tempMat.GetRight());
vecOut->y = DotProduct(vecOffset, tempMat.GetForward());
vecOut->z = DotProduct(vecOffset, tempMat.GetUp());
return;
CVector CAEAudioEnvironment::GetPositionRelativeToCamera(const CVector& pt) {
const auto& camMat = TheCamera.m_mCameraMatrix;
const auto Calculate = [&](CVector offset) {
const auto posOS = pt - TheCamera.GetPosition() + offset;
return camMat.InverseTransformVector(CVector{-posOS.x, posOS.y, posOS.z});
};
switch (CCamera::GetActiveCamera().m_nMode) {
case eCamMode::MODE_SNIPER:
case eCamMode::MODE_ROCKETLAUNCHER:
case eCamMode::MODE_1STPERSON: {
return Calculate(-camMat.GetForward() * 2.f);
}
default: {
const auto* player = FindPlayerPed();
const auto camDist = player
? std::clamp(CVector::Dist(camMat.GetPosition(), player->GetPosition()), 0.0F, 0.5F)
: 0.f;
return Calculate(camMat.GetForward() * camDist);
}
}

auto fMult = 0.0F;
auto* player = FindPlayerPed();
if (player)
fMult = std::clamp(DistanceBetweenPoints(TheCamera.GetPosition(), player->GetPosition()), 0.0F, 0.5F);

const auto& tempMat = TheCamera.m_mCameraMatrix;
const auto& vecCamPos = TheCamera.GetPosition();
const auto vecOffset = *vecPos - (vecCamPos + tempMat.GetForward() * fMult);

vecOut->x = -DotProduct(vecOffset, tempMat.GetRight());
vecOut->y = DotProduct(vecOffset, tempMat.GetForward());
vecOut->z = DotProduct(vecOffset, tempMat.GetUp());
}

// 0x4D8340
void CAEAudioEnvironment::GetPositionRelativeToCamera(CVector* vecOut, CPlaceable* placeable) {
return CAEAudioEnvironment::GetPositionRelativeToCamera(vecOut, &placeable->GetPosition());
CVector CAEAudioEnvironment::GetPositionRelativeToCamera(CPlaceable* placeable) {
return CAEAudioEnvironment::GetPositionRelativeToCamera(placeable->GetPosition());
}
4 changes: 2 additions & 2 deletions source/game_sa/Audio/AEAudioEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class CAEAudioEnvironment {
static float GetDistanceAttenuation(float dist);
static float GetDirectionalMikeAttenuation(const CVector& soundDir);
static void GetReverbEnvironmentAndDepth(int8* reverbEnv, int32* depth);
static void GetPositionRelativeToCamera(CVector* vecOut, const CVector* vecPos);
static void GetPositionRelativeToCamera(CVector* vecOut, CPlaceable* placeable);
static CVector GetPositionRelativeToCamera(const CVector& pos);
static CVector GetPositionRelativeToCamera(CPlaceable* placeable);
};

static constexpr int32 NUM_AUDIO_ENVIRONMENTS = 68;
Expand Down
82 changes: 47 additions & 35 deletions source/game_sa/Audio/AEAudioUtility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,46 @@
uint64& CAEAudioUtility::startTimeMs = *reinterpret_cast<uint64*>(0xb610f8);
float (&CAEAudioUtility::m_sfLogLookup)[50][2] = *reinterpret_cast<float (*)[50][2]>(0xb61100);

// NOTE: Not sure about the size.
static inline auto& gScriptBanksLookup = *reinterpret_cast<std::array<int32, 628>*>(0x8ABC70);
// NOTE: For me all values were 0... The below values should be the correct ones:
static constexpr std::array<eSoundBank, AE_SCRIPT_BANK_LAST - AE_SCRIPT_BANK_FIRST> gScriptBanksLookup = {
SND_BANK_SCRIPT_VIDEO_POKER,
SND_BANK_SCRIPT_SHOOTING_RANGE,
SND_BANK_SCRIPT_POOL_MINIGAME,
SND_BANK_SCRIPT_NULL,
SND_BANK_SCRIPT_KEYPAD,
SND_BANK_SCRIPT_NULL,
SND_BANK_SCRIPT_GOGO,
SND_BANK_SCRIPT_DUALITY,
SND_BANK_SCRIPT_NULL,
SND_BANK_SCRIPT_BLACK_PROJECT,
SND_BANK_SCRIPT_BEE,
SND_BANK_SCRIPT_BASKETBALL,
SND_BANK_SCRIPT_MEAT_BUSINESS,
SND_BANK_SCRIPT_ROULETTE,
SND_BANK_SCRIPT_BANDIT,
SND_BANK_SCRIPT_NULL,
SND_BANK_SCRIPT_NULL,
SND_BANK_SCRIPT_OGLOC,
SND_BANK_SCRIPT_CARGO_PLANE,
SND_BANK_SCRIPT_DA_NANG,
SND_BANK_SCRIPT_GYM,
SND_BANK_SCRIPT_OTB,
SND_BANK_SCRIPT_STINGER,
SND_BANK_SCRIPT_UNCLE_SAM,
SND_BANK_SCRIPT_VERTICAL_BIRD,
SND_BANK_SCRIPT_MECHANIC,
SND_BANK_SCRIPT_CAT2_BANK,
SND_BANK_SCRIPT_AIR_HORN,
SND_BANK_SCRIPT_RESTAURANT,
SND_BANK_SCRIPT_TEMPEST
};

void CAEAudioUtility::InjectHooks() {
RH_ScopedClass(CAEAudioUtility);
RH_ScopedCategory("Audio");

RH_ScopedOverloadedInstall(GetRandomNumberInRange, "int", 0x4d9c10, int32(*)(const int32, const int32));
RH_ScopedOverloadedInstall(GetRandomNumberInRange, "float", 0x4d9c50, float(*)(float, float));
RH_ScopedOverloadedInstall(GetRandomNumberInRange<int32>, "int", 0x4d9c10, int32(*)(int32, int32));
RH_ScopedOverloadedInstall(GetRandomNumberInRange<float>, "float", 0x4d9c50, float(*)(float, float));
RH_ScopedInstall(ResolveProbability, 0x4d9c80);
RH_ScopedInstall(GetPiecewiseLinear, 0x4d9d90);
RH_ScopedInstall(AudioLog10, 0x4d9e50);
Expand All @@ -28,18 +59,6 @@ void CAEAudioUtility::InjectHooks() {
RH_ScopedInstall(StaticInitialise, 0x5b97f0);
}

// 0x4d9c10
int32 CAEAudioUtility::GetRandomNumberInRange(const int32 min, const int32 max) {
// This and CGeneral differs in that this function returns a number [min, max + 1], while
// the other [min, max]. To solve this we do `max + 1`
return CGeneral::GetRandomNumberInRange(min, max + 1);
}

// 0x4d9c50
float CAEAudioUtility::GetRandomNumberInRange(float a, float b) {
return CGeneral::GetRandomNumberInRange(a, b);
}

// 0x4d9c80
bool CAEAudioUtility::ResolveProbability(float p) {
return p >= 1.0f || CGeneral::RandomBool(100.0f * p);
Expand Down Expand Up @@ -107,28 +126,21 @@ void CAEAudioUtility::StaticInitialise() {
}

// 0x4D9CC0
bool CAEAudioUtility::GetBankAndSoundFromScriptSlotAudioEvent(int32& slot, int32& outBank, int32& outSound, int32 a4) {
if (slot < 1800)
bool CAEAudioUtility::GetBankAndSoundFromScriptSlotAudioEvent(const eAudioEvents& scriptID, eSoundBankS32& outBankID, int32& outSoundID, int32 slot) {
if (scriptID < AE_SCRIPT_BANK_FIRST) {
return false;

if (slot < 2000) {
outBank = gScriptBanksLookup[slot - 1800];
return true;
}

if (slot == 0xFFFF) { // (uint16)-1
outBank = 291;

if (a4 > 3)
outSound = 0;
else
outSound = 2 * (a4 % 2);

return true;
if (scriptID < AE_SCRIPT_SLOT_FIRST) {
outBankID = gScriptBanksLookup[scriptID - AE_SCRIPT_BANK_FIRST];
} else if (scriptID == AE_SCRIPT_SLOT_USE_CUSTOM) {
outBankID = SND_BANK_SCRIPT_NULL;
outSoundID = slot > 3
? 0
: 2 * (slot % 2);
} else {
outSoundID = (slot - 2'000) % 200;
outBankID = (eSoundBank)(SND_BANK_SCRIPT_FIRST + outSoundID); //SND_BANK_SCRIPT_FIRST + static_cast<int32>(std::floor(float(slot - AE_SCRIPT_SLOT_FIRST) / 200.0f));
}

outBank = static_cast<int32>(std::floor(float(slot - 2000) / 200.0f)) + 147;
outSound = (slot - 2000) % 200;
return true;
}

Expand Down
19 changes: 16 additions & 3 deletions source/game_sa/Audio/AEAudioUtility.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
#pragma once
#include "eRadioID.h"
#include <General.h>

class CVehicle;

class CAEAudioUtility {
public:
static void StaticInitialise();

static int32 GetRandomNumberInRange(const int32 min, const int32 max);
static float GetRandomNumberInRange(float a, float b);
/*!
* @brief This and CGeneral differs in that this function returns a number [min, max + 1], while
* @brief the other [min, max]. To solve this we do `max + 1`
*/
template<std::integral T>
static T GetRandomNumberInRange(T min, T max) {
return CGeneral::GetRandomNumberInRange<T>(min, max + 1);
}

template<typename T>
requires std::is_floating_point_v<T>
static T GetRandomNumberInRange(T min, T max) {
return CGeneral::GetRandomNumberInRange<T>(min, max);
}

static CVehicle* FindVehicleOfPlayer();
static bool ResolveProbability(float prob);
Expand All @@ -17,7 +30,7 @@ class CAEAudioUtility {
static uint32 ConvertFromBytesToMS(uint32 lengthInBytes, uint32 frequency, uint16 frequencyMult);
static uint32 ConvertFromMSToBytes(uint32 a, uint32 frequency, uint16 frequencyMult);

static bool GetBankAndSoundFromScriptSlotAudioEvent(int32& slot, int32& outBank, int32& outSound, int32 a4);
static bool GetBankAndSoundFromScriptSlotAudioEvent(const eAudioEvents& ae, eSoundBankS32& outBankID, int32& outSoundID, int32 slot);
static float GetPiecewiseLinear(float x, int16 dataCount, float (*data)[2]);
static uint64 GetCurrentTimeInMS();

Expand Down
36 changes: 17 additions & 19 deletions source/game_sa/Audio/AESound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void CAESound::InjectHooks() {
RH_ScopedInstall(StopSound, 0x4EF1C0);
RH_ScopedInstall(SetIndividualEnvironment, 0x4EF2B0);
RH_ScopedInstall(UpdatePlayTime, 0x4EF2E0);
RH_ScopedOverloadedInstall(GetRelativePosition, "OG", 0x4EF350, void(CAESound::*)(CVector&) const);
RH_ScopedInstall(GetRelativePosition, 0x4EF350);
RH_ScopedInstall(CalculateFrequency, 0x4EF390);
RH_ScopedInstall(UpdateFrequency, 0x4EF3E0);
RH_ScopedInstall(GetRelativePlaybackFrequencyWithDoppler, 0x4EF400);
Expand Down Expand Up @@ -193,11 +193,10 @@ void CAESound::UpdatePlayTime(int16 soundLength, int16 loopStartTime, int16 play
}

// 0x4EF350
void CAESound::GetRelativePosition(CVector& out) const {
if (!GetFrontEnd()) {
CAEAudioEnvironment::GetPositionRelativeToCamera(&out, &m_vecCurrPosn);
}
out = m_vecCurrPosn;
CVector CAESound::GetRelativePosition() const {
return GetFrontEnd()
? m_vecCurrPosn
: CAEAudioEnvironment::GetPositionRelativeToCamera(m_vecCurrPosn);
}

// 0x4EF390
Expand All @@ -215,14 +214,14 @@ void CAESound::UpdateFrequency() {
}

// 0x4EF400
float CAESound::GetRelativePlaybackFrequencyWithDoppler() {
float CAESound::GetRelativePlaybackFrequencyWithDoppler() const {
return GetFrontEnd()
? m_fFrequency
: m_fFrequency * CAEAudioEnvironment::GetDopplerRelativeFrequency(m_fPrevCamDist, m_fCurrCamDist, m_nPrevTimeUpdate, m_nCurrTimeUpdate, m_fTimeScale);
}

// 0x4EF440
float CAESound::GetSlowMoFrequencyScalingFactor() {
float CAESound::GetSlowMoFrequencyScalingFactor() const {
return GetUnpausable() || !CTimer::GetIsSlowMotionActive() || CCamera::GetActiveCamera().m_nMode == eCamMode::MODE_CAMERA
? 1.f
: fSlowMoFrequencyScalingFactor;
Expand Down Expand Up @@ -255,29 +254,29 @@ void CAESound::StopSoundAndForget() {
}

// 0x4EF880
void CAESound::SetPosition(CVector vecPos) {
void CAESound::SetPosition(CVector pos) {
if (!m_nLastFrameUpdate) {
m_vecPrevPosn = vecPos;
m_vecCurrPosn = vecPos;
m_vecPrevPosn = pos;
m_vecCurrPosn = pos;

auto const fCamDist = DistanceBetweenPoints(vecPos, TheCamera.GetPosition());
auto const fCamDist = DistanceBetweenPoints(pos, TheCamera.GetPosition());
m_fCurrCamDist = fCamDist;
m_fPrevCamDist = fCamDist;

m_nLastFrameUpdate = CTimer::GetFrameCounter();
m_nCurrTimeUpdate = CTimer::GetTimeInMS();
m_nPrevTimeUpdate = CTimer::GetTimeInMS();
} else if (m_nLastFrameUpdate == CTimer::GetFrameCounter()) {
m_vecCurrPosn = vecPos;
m_fCurrCamDist = DistanceBetweenPoints(vecPos, TheCamera.GetPosition());
m_vecCurrPosn = pos;
m_fCurrCamDist = DistanceBetweenPoints(pos, TheCamera.GetPosition());
m_nCurrTimeUpdate = CTimer::GetTimeInMS();
} else {
m_vecPrevPosn = m_vecCurrPosn;
m_fPrevCamDist = m_fCurrCamDist;
m_nPrevTimeUpdate = m_nCurrTimeUpdate;

m_vecCurrPosn = vecPos;
m_fCurrCamDist = DistanceBetweenPoints(vecPos, TheCamera.GetPosition());
m_vecCurrPosn = pos;
m_fCurrCamDist = DistanceBetweenPoints(pos, TheCamera.GetPosition());
m_nCurrTimeUpdate = CTimer::GetTimeInMS();
m_nLastFrameUpdate = CTimer::GetFrameCounter();
}
Expand All @@ -288,9 +287,8 @@ void CAESound::CalculateVolume() {
if (GetFrontEnd())
m_fFinalVolume = m_fVolume - m_fSoundHeadRoom;
else {
CVector relativePos;
CAEAudioEnvironment::GetPositionRelativeToCamera(&relativePos, &m_vecCurrPosn);
const auto fDist = relativePos.Magnitude() / m_fSoundDistance;
const auto relativePos = CAEAudioEnvironment::GetPositionRelativeToCamera(m_vecCurrPosn);
const auto fDist = CAEAudioEnvironment::GetPositionRelativeToCamera(m_vecCurrPosn).Magnitude() / m_fSoundDistance;
const auto fAttenuation = CAEAudioEnvironment::GetDistanceAttenuation(fDist);
m_fFinalVolume = CAEAudioEnvironment::GetDirectionalMikeAttenuation(relativePos) + fAttenuation + m_fVolume - m_fSoundHeadRoom;
}
Expand Down
7 changes: 3 additions & 4 deletions source/game_sa/Audio/AESound.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,11 @@ class CAESound {
bool GetForcedFront() const { return m_bForcedFront; }
void SetIndividualEnvironment(uint16 envFlag, uint16 bEnabled); // pass eSoundEnvironment as envFlag
void UpdatePlayTime(int16 soundLength, int16 loopStartTime, int16 playProgress);
void GetRelativePosition(CVector& out) const;
CVector GetRelativePosition() const { CVector out; GetRelativePosition(out); return out; } // NOTSA
CVector GetRelativePosition() const;
void CalculateFrequency();
void UpdateFrequency();
float GetRelativePlaybackFrequencyWithDoppler();
float GetSlowMoFrequencyScalingFactor();
float GetRelativePlaybackFrequencyWithDoppler() const;
float GetSlowMoFrequencyScalingFactor() const;
void NewVPSLentry();
void RegisterWithPhysicalEntity(CEntity* entity);
void StopSoundAndForget();
Expand Down
Loading

0 comments on commit c91981e

Please sign in to comment.