-
Notifications
You must be signed in to change notification settings - Fork 32
/
AudioTweaks.cpp
171 lines (139 loc) · 6.55 KB
/
AudioTweaks.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <iostream>
#include "dllmain.h"
#include "Patches.h"
#include "Game.h"
#include "Settings.h"
#include "AudioTweaks.h"
void(__cdecl* Snd_set_system_vol)(char flg, int16_t vol);
void __cdecl Snd_set_system_vol_Hook(char flg, int16_t vol)
{
Snd_set_system_vol(flg, vol);
re4t::AudioTweaks::UpdateVolume();
}
void* g_mwply = nullptr;
void(__cdecl* mwPlySetOutVol)(void* mwply, int vol);
void __cdecl mwPlySetOutVol_Hook(void* mwply, int vol)
{
g_mwply = mwply;
// volume of 0 would cause divide by zero (which doesn't crash, but does make volume extremely loud)
// -960 seems to be minimum volume allowed by Criware, so we'll set to that (not completely sure if it's muted or not though)
int new_vol = -960;
if (re4t::cfg->iVolumeCutscene > 0)
new_vol = int(float(vol) / ((re4t::cfg->iVolumeCutscene / 100.0f) * (re4t::cfg->iVolumeMaster / 100.0f)));
mwPlySetOutVol(mwply, new_vol);
}
SND_STR* str_work = nullptr; // 0x127B6B8 in 1.1.0
void(__cdecl* Snd_str_work_calc_ax_vol)(SND_STR* str); // 0x979E70 in 1.1.0
void(__cdecl* SYNSetMasterVolume)(uint32_t a1, uint16_t a2, float a3); // 0x97AB90 in 1.1.0, GC vers names it SYNSetMasterVolume, likely different name on PC
SND_SEQ* (__cdecl* Snd_search_seq_work_seq_no)(int seq_no); // 0x978070 in 1.1.0, guessed name
void(__cdecl* Snd_seq_work_calc_ax_vol)(SND_SEQ* a1); // 0x978150 in 1.1.0
void re4t::AudioTweaks::UpdateVolume()
{
if (!Snd_ctrl_work)
return;
// shift value left by 8, as done by Snd_set_system_vol
const float vol_max = 127;
Snd_ctrl_work->vol_str_bgm_48 = Snd_ctrl_work->vol_iss_bgm_44 = (int16_t(vol_max * (re4t::cfg->iVolumeBGM / 100.0f) * (re4t::cfg->iVolumeMaster / 100.0f)) << 8);
Snd_ctrl_work->vol_iss_se_46 = (int16_t(vol_max * (re4t::cfg->iVolumeSE / 100.0f) * (re4t::cfg->iVolumeMaster / 100.0f)) << 8);
Snd_ctrl_work->vol_str_se_4A = (int16_t(vol_max * (re4t::cfg->iVolumeCutscene / 100.0f) * (re4t::cfg->iVolumeMaster / 100.0f)) << 8); // str_se seems to mostly get used by cutscenes / merchant dialogue
if (g_mwply && (
FlagIsSet(GlobalPtr()->flags_STATUS_0_501C, uint32_t(Flags_STATUS::STA_MOVIE_ON)) ||
FlagIsSet(GlobalPtr()->flags_STATUS_0_501C, uint32_t(Flags_STATUS::STA_MOVIE2_ON))))
{
mwPlySetOutVol_Hook(g_mwply, -100); // -100 comes from cSofdec::startApp, hook will adjust it for us
}
// Update volume of any playing str sounds
for (int i = 0; i < 4; i++)
{
SND_STR* cur_str = &str_work[i];
if (cur_str->field_C != 1)
continue;
// Use Snd_str_work_calc_ax_vol to update volume of the SND_STR
Snd_str_work_calc_ax_vol(cur_str);
// Use SYNSetMasterVolume to update XAudio volume of the sound
SYNSetMasterVolume(cur_str->sound_idx_0, cur_str->str_type_50 /* gets truncated to uint16 for some reason? */, float(cur_str->vol_decibels_3C));
}
// Update volume of any playing seq sounds
for (int i = 0; i < 8; i++)
{
SND_SEQ* cur_seq = Snd_search_seq_work_seq_no(i);
if ((cur_seq->status_flags_4C & 0x10) == 0)
continue;
// Update volume of the seq with our updated values
Snd_seq_work_calc_ax_vol(cur_seq);
// Use SYNSetMasterVolume to update XAudio volume of the sound
SYNSetMasterVolume(cur_seq->sound_idx_0, cur_seq->field_14, float(cur_seq->vol_decibels_64));
}
}
uint32_t __cdecl knife_r3_fire10_SndCall_Hook(uint16_t blk, uint16_t call_no, Vec* pos, uint8_t id, uint32_t flag, cModel* pMod)
{
if (re4t::cfg->bRestoreGCSoundEffects)
call_no = 85; // use original GC sound effect
return bio4::SndCall(blk, call_no, pos, id, flag, pMod);
}
void re4t::init::AudioTweaks()
{
// Hook Snd_set_system_vol so we can override volume values with our own after game updates them
auto pattern = hook::pattern("B8 10 00 00 00 0F B6 55 ? 52 50 E8 ? ? ? ? 83 C4");
ReadCall(injector::GetBranchDestination(pattern.count(1).get(0).get<uint32_t>(0xB)).as_int(), Snd_set_system_vol);
InjectHook(injector::GetBranchDestination(pattern.count(1).get(0).get<uint32_t>(0xB)).as_int(), Snd_set_system_vol_Hook);
// Hook mwPlySetOutVol so we can override FMV volume, and store mwply handle to allow updating volume during runtime
pattern = hook::pattern("6A 9C 56 E8 ? ? ? ?");
ReadCall(pattern.count(1).get(0).get<uint32_t>(3), mwPlySetOutVol);
InjectHook(pattern.count(1).get(0).get<uint32_t>(3), mwPlySetOutVol_Hook, PATCH_CALL);
// Fetch addr of SND_STR structs
pattern = hook::pattern("6B C0 5C 05 ? ? ? ? 5D C3");
str_work = *pattern.count(2).get(0).get<SND_STR*>(4);
// Find Snd_str_work_calc_ax_vol so we can update volume of SND_STR correctly
pattern = hook::pattern("8A 46 4C A8 01 74 ? A8 04 75 ? 56 E8 ? ? ? ? 83 C4 04");
ReadCall(pattern.count(1).get(0).get<uint32_t>(0xC), Snd_str_work_calc_ax_vol);
// Find SYNSetMasterVolume so we can tell XAudio to update volume
pattern = hook::pattern("D9 1C ? 52 50 E8 ? ? ? ? 8B 07 83 C4 ? 5F");
ReadCall(pattern.count(1).get(0).get<uint32_t>(0x5), SYNSetMasterVolume);
// Find Snd_search_seq_work_seq_no
pattern = hook::pattern("56 E8 ? ? ? ? 83 C4 ? 66 83 78 4C 00 74");
ReadCall(pattern.count(1).get(0).get<uint32_t>(0x1), Snd_search_seq_work_seq_no);
// Find Snd_seq_work_calc_ax_vol
pattern = hook::pattern("F6 46 56 01 74 ? 56 E8 ? ? ? ? DB 46 64");
ReadCall(pattern.count(1).get(0).get<uint32_t>(0x7), Snd_seq_work_calc_ax_vol);
// Hook SndCall call inside knife_r3_fire10 to allow restoring original GC knife sound effect
pattern = hook::pattern("83 C0 ? 50 6A 03 6A 01 E8");
InjectHook(pattern.count(1).get(0).get<uint32_t>(8), knife_r3_fire10_SndCall_Hook, PATCH_CALL);
// Silence armored Ashley
{
auto pattern = hook::pattern("83 C4 ? 80 BA ? ? ? ? 02 75 ? 83 FF ? 77 ? 0F B6 87 ? ? ? ? FF 24 85 ? ? ? ? BE");
struct ClankClanklHook
{
void operator()(injector::reg_pack& regs)
{
int AshleyCostumeID = int(GlobalPtr()->subCostume_4FCB);
// Mimic what CMP does, since we're overwriting it.
if (AshleyCostumeID > 2)
{
// Clear both flags
regs.ef &= ~(1 << regs.zero_flag);
regs.ef &= ~(1 << regs.carry_flag);
}
else if (AshleyCostumeID < 2)
{
// ZF = 0, CF = 1
regs.ef &= ~(1 << regs.zero_flag);
regs.ef |= (1 << regs.carry_flag);
}
else if (AshleyCostumeID == 2)
{
// ZF = 1, CF = 0
regs.ef |= (1 << regs.zero_flag);
regs.ef &= ~(1 << regs.carry_flag);
}
if (re4t::cfg->bSilenceArmoredAshley)
{
// Make the game think Ashley isn't using the clanky costume
regs.ef &= ~(1 << regs.zero_flag);
regs.ef |= (1 << regs.carry_flag);
}
}
}; injector::MakeInline<ClankClanklHook>(pattern.count(1).get(0).get<uint32_t>(3), pattern.count(1).get(0).get<uint32_t>(10));
spd::log()->info("SilenceArmoredAshley applied");
}
}