@@ -7,7 +7,7 @@ namespace SoundFX {
7
7
bool
8
8
Sound3DUtil::InitializeOpenAL () {
9
9
if (!InitializeSharedContext ()) {
10
- spdlog::error (" OpenAL could not be initialized." );
10
+ spdlog::critical (" OpenAL could not be initialized." );
11
11
return false ;
12
12
}
13
13
return true ;
@@ -33,7 +33,7 @@ namespace SoundFX {
33
33
Sound3DUtil::InitializeDevice () {
34
34
ALCdevice *device = alcOpenDevice (nullptr );
35
35
if (!device) {
36
- spdlog::error (" Failed to open OpenAL device." );
36
+ spdlog::critical (" Failed to open OpenAL device." );
37
37
}
38
38
return device;
39
39
}
@@ -44,9 +44,15 @@ namespace SoundFX {
44
44
return nullptr ;
45
45
}
46
46
47
- ALCcontext *context = alcCreateContext (device, nullptr );
47
+ const ALCint attributes[] = {ALC_MONO_SOURCES,
48
+ 4000 , // Maximum number of mono sources
49
+ ALC_STEREO_SOURCES,
50
+ 4000 , // Maximum number of stereo sources
51
+ 0 };
52
+
53
+ ALCcontext *context = alcCreateContext (device, attributes);
48
54
if (!context || alcMakeContextCurrent (context) == ALC_FALSE) {
49
- spdlog::error (" Failed to create or set OpenAL context." );
55
+ spdlog::critical (" Failed to create or set OpenAL context." );
50
56
alcDestroyContext (context);
51
57
alcCloseDevice (device);
52
58
return nullptr ;
@@ -81,7 +87,12 @@ namespace SoundFX {
81
87
}
82
88
83
89
std::vector<short > samples (fileInfo.frames * fileInfo.channels );
84
- sf_read_short (sndFile, samples.data (), static_cast <sf_count_t >(samples.size ()));
90
+ if (sf_read_short (sndFile, samples.data (), static_cast <sf_count_t >(samples.size ()))
91
+ < samples.size ()) {
92
+ spdlog::error (" Failed to read audio samples from file: {}" , filePath);
93
+ sf_close (sndFile);
94
+ return 0 ;
95
+ }
85
96
sf_close (sndFile);
86
97
87
98
ALuint buffer;
@@ -92,6 +103,11 @@ namespace SoundFX {
92
103
samples.data (),
93
104
static_cast <ALsizei>(samples.size () * sizeof (short )),
94
105
fileInfo.samplerate );
106
+ if (alGetError () != AL_NO_ERROR) {
107
+ spdlog::error (" Failed to fill OpenAL buffer with audio data." );
108
+ alDeleteBuffers (1 , &buffer);
109
+ return 0 ;
110
+ }
95
111
96
112
{
97
113
std::lock_guard lock (bufferCacheMutex);
@@ -139,14 +155,23 @@ namespace SoundFX {
139
155
140
156
ALuint source;
141
157
alGenSources (1 , &source);
158
+ if (alGetError () != AL_NO_ERROR) {
159
+ spdlog::error (" Failed to generate OpenAL source." );
160
+ return 0 ;
161
+ }
162
+
142
163
alSourcei (source, AL_BUFFER, static_cast <ALint>(buffer));
143
164
alSourcef (source, AL_REFERENCE_DISTANCE, referenceDistance);
144
165
alSourcef (source, AL_MAX_DISTANCE, maxDistance);
145
166
alSourcef (source, AL_ROLLOFF_FACTOR, rolloffFactor);
146
- alSourcef (source, AL_GAIN, gain);
147
167
alSourcef (source, AL_MIN_GAIN, minGain);
148
168
149
169
alSourcePlay (source);
170
+ if (alGetError () != AL_NO_ERROR) {
171
+ spdlog::error (" Failed to play OpenAL source." );
172
+ alDeleteSources (1 , &source);
173
+ return 0 ;
174
+ }
150
175
151
176
std::thread ([source, worldSourcePos, maxDistance, gain] {
152
177
ALint state = AL_PLAYING;
@@ -170,7 +195,15 @@ namespace SoundFX {
170
195
const float distance = relativeSourcePos.Length ();
171
196
float volume = 1 .0f - distance / maxDistance;
172
197
volume = std::clamp (volume, 0 .0f , 1 .0f );
173
- alSourcef (source, AL_GAIN, volume * gain);
198
+
199
+ const float ingameVolume = GetIngameVolumeFactor ();
200
+ const float finalVolume = volume * gain * ingameVolume;
201
+
202
+ float currentGain;
203
+ alGetSourcef (source, AL_GAIN, ¤tGain);
204
+ if (std::abs (currentGain - finalVolume) > 0 .01f ) {
205
+ alSourcef (source, AL_GAIN, finalVolume);
206
+ }
174
207
175
208
const RE::NiPoint3 forwardVector = GetForwardVector (player->Get3D ());
176
209
constexpr RE::NiPoint3 upVector = {0 .0f , 0 .0f , 1 .0f };
@@ -191,10 +224,13 @@ namespace SoundFX {
191
224
}
192
225
193
226
alGetSourcei (source, AL_SOURCE_STATE, &state);
194
- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
227
+ std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
195
228
}
196
229
197
230
alDeleteSources (1 , &source);
231
+ if (alGetError () != AL_NO_ERROR) {
232
+ spdlog::critical (" Failed to delete OpenAL source: {}" , source);
233
+ }
198
234
}).detach ();
199
235
200
236
return source;
@@ -218,4 +254,18 @@ namespace SoundFX {
218
254
}
219
255
}
220
256
257
+ float
258
+ Sound3DUtil::GetIngameVolumeFactor () {
259
+ if (auto *settings = RE::INIPrefSettingCollection::GetSingleton ()) {
260
+ if (const auto *volumeSetting = settings->GetSetting (" fAudioMasterVolume:AudioMenu" )) {
261
+ const float newVolume = volumeSetting->data .f ;
262
+ constexpr float epsilon = 0 .0001f ;
263
+ if (std::abs (newVolume - cachedVolume.load ()) > epsilon) {
264
+ cachedVolume.store (newVolume);
265
+ }
266
+ return cachedVolume.load ();
267
+ }
268
+ }
269
+ return 1 .0f ;
270
+ }
221
271
}
0 commit comments