Skip to content

Commit f4b7974

Browse files
committed
proportionally reduco volume after threshold
1 parent 35ae96e commit f4b7974

File tree

7 files changed

+79
-22
lines changed

7 files changed

+79
-22
lines changed

sources/include/cage-engine/scene.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ namespace cage
137137
struct CAGE_ENGINE_API ListenerComponent
138138
{
139139
uint32 maxSounds = 100;
140+
Real maxGainThreshold = Real::Infinity(); // all sounds will have proportionally reduced gain when the sum of effective gains reaches this threshold
140141
Real gain = 1; // linear amplitude multiplier
141142
};
142143
}

sources/include/cage-engine/soundsQueue.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace cage
1919
{
2020
public:
2121
uint32 maxActiveSounds = 100;
22+
Real maxGainThreshold = Real::Infinity(); // all sounds will have proportionally reduced gain when the sum of effective gains reaches this threshold
2223
Real gain = 1; // linear amplitude multiplier
2324

2425
void play(Holder<Sound> sound, const SoundEventConfig &cfg = {});

sources/include/cage-engine/soundsVoices.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ namespace cage
2727
public:
2828
Quat orientation;
2929
Vec3 position;
30-
uint32 maxActiveVoices = 100;
30+
uint32 maxActiveSounds = 100;
31+
Real maxGainThreshold = Real::Infinity(); // all sounds will have proportionally reduced gain when the sum of effective gains reaches this threshold
3132
Real gain = 1; // linear amplitude multiplier
3233

3334
Holder<Voice> newVoice();
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include <algorithm>
2+
#include <vector>
3+
4+
#include <cage-core/math.h>
5+
6+
namespace cage
7+
{
8+
namespace
9+
{
10+
template<class T>
11+
struct Dereferencer : private Immovable
12+
{
13+
T *data = nullptr;
14+
CAGE_FORCE_INLINE Dereferencer(T *d) : data(d) {}
15+
CAGE_FORCE_INLINE Dereferencer(T &d) : data(&d) {}
16+
CAGE_FORCE_INLINE T *operator->() const { return data; }
17+
};
18+
19+
template<class This, class K, class T = Dereferencer<std::remove_pointer_t<K>>>
20+
void updateEffectiveGains(const This *ths, std::vector<K> &active)
21+
{
22+
// sort by priority
23+
std::sort(active.begin(), active.end(), [](const T a, const T b) -> bool { return std::pair(a->priority, a->effectiveGain) > std::pair(b->priority, b->effectiveGain); });
24+
for (uint32 i = ths->maxActiveSounds; i < active.size(); i++)
25+
Dereferencer(active[i])->effectiveGain = 0;
26+
27+
/*
28+
{ // fade-out sounds close to limit
29+
const uint32 s = max(ths->maxActiveSounds * 70 / 100, 2u);
30+
const Real f = 1.0 / (ths->maxActiveSounds - s + 1);
31+
for (uint32 i = s; i < active.size(); i++)
32+
Dereferencer(active[i])->effectiveGain *= saturate(1 - (i - s + 1) * f);
33+
}
34+
*/
35+
36+
// total gain reduction
37+
if (ths->maxGainThreshold != Real::Infinity())
38+
{
39+
Real sum;
40+
for (T a : active)
41+
sum += a->effectiveGain;
42+
if (sum > ths->maxGainThreshold)
43+
{
44+
const Real f = sqrt(ths->maxGainThreshold / sum);
45+
for (T a : active)
46+
a->effectiveGain *= f;
47+
}
48+
}
49+
50+
// apply this gain
51+
for (T a : active)
52+
a->effectiveGain *= ths->gain;
53+
}
54+
}
55+
}

sources/libengine/sound/soundsQueue.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
#include <algorithm>
21
#include <atomic>
32
#include <variant>
4-
#include <vector>
53

64
#include <cage-core/assetsOnDemand.h>
75
#include <cage-core/audioChannelsConverter.h>
@@ -10,6 +8,8 @@
108
#include <cage-engine/sound.h>
119
#include <cage-engine/soundsQueue.h>
1210

11+
#include "effectiveGain.h"
12+
1313
namespace cage
1414
{
1515
namespace
@@ -107,14 +107,14 @@ namespace cage
107107
remaining.store(rem, std::memory_order_relaxed);
108108
}
109109

110-
// update effective gains
110+
if (active.empty())
111+
return;
112+
113+
// reset effective gains
111114
for (Event &a : active)
112-
a.effectiveGain = a.gain * this->gain;
115+
a.effectiveGain = a.gain;
113116

114-
// sort by priority
115-
std::sort(active.begin(), active.end(), [](const Event &a, const Event &b) -> bool { return std::pair(a.priority, a.effectiveGain) > std::pair(b.priority, b.effectiveGain); });
116-
for (uint32 i = maxActiveSounds; i < active.size(); i++)
117-
active[i].effectiveGain = 0;
117+
updateEffectiveGains(this, active);
118118
}
119119

120120
void processEvent(Event &v, const SoundCallbackData &data)
@@ -161,6 +161,7 @@ namespace cage
161161
{
162162
CAGE_ASSERT(data.buffer.size() == data.frames * data.channels);
163163
CAGE_ASSERT(gain.valid() && gain >= 0 && gain.finite());
164+
CAGE_ASSERT(maxGainThreshold.valid() && maxGainThreshold >= 0);
164165
detail::memset(data.buffer.data(), 0, data.buffer.size() * sizeof(float));
165166

166167
if (purging)

sources/libengine/sound/soundsVoices.cpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
#include <algorithm>
2-
#include <vector>
3-
41
#include <cage-core/audioChannelsConverter.h>
52
#include <cage-core/audioDirectionalConverter.h>
63
#include <cage-core/sampleRateConverter.h>
74
#include <cage-engine/sound.h>
85
#include <cage-engine/soundsVoices.h>
96

7+
#include "effectiveGain.h"
8+
109
namespace cage
1110
{
1211
namespace
@@ -21,7 +20,7 @@ namespace cage
2120

2221
VoiceImpl(VoicesMixerImpl *mixer);
2322
~VoiceImpl();
24-
void updateGain();
23+
void resetGain();
2524
};
2625

2726
class VoicesMixerImpl : public VoicesMixer
@@ -44,14 +43,11 @@ namespace cage
4443

4544
void updateVoices()
4645
{
47-
// update effective gains
46+
// reset effective gains
4847
for (VoiceImpl *v : voices)
49-
v->updateGain();
48+
v->resetGain();
5049

51-
// sort by priority
52-
std::sort(voices.begin(), voices.end(), [](const VoiceImpl *a, const VoiceImpl *b) -> bool { return std::pair(a->priority, a->effectiveGain) > std::pair(b->priority, b->effectiveGain); });
53-
for (uint32 i = maxActiveVoices; i < voices.size(); i++)
54-
voices[i]->effectiveGain = 0;
50+
updateEffectiveGains(this, voices);
5551
}
5652

5753
void processVoice(VoiceImpl &v, const SoundCallbackData &data)
@@ -148,6 +144,7 @@ namespace cage
148144
{
149145
CAGE_ASSERT(data.buffer.size() == data.frames * data.channels);
150146
CAGE_ASSERT(gain.valid() && gain >= 0 && gain.finite());
147+
CAGE_ASSERT(maxGainThreshold.valid() && maxGainThreshold >= 0);
151148
CAGE_ASSERT(position.valid() && orientation.valid());
152149
detail::memset(data.buffer.data(), 0, data.buffer.size() * sizeof(float));
153150

@@ -184,7 +181,7 @@ namespace cage
184181
}
185182
}
186183

187-
void VoiceImpl::updateGain()
184+
void VoiceImpl::resetGain()
188185
{
189186
Real att = 1;
190187
if (position.valid())
@@ -208,7 +205,7 @@ namespace cage
208205
}
209206
}
210207
CAGE_ASSERT(valid(att) && att >= 0 && att <= 1 + 1e-7);
211-
effectiveGain = gain * mixer->gain * att;
208+
effectiveGain = gain * att;
212209
CAGE_ASSERT(valid(effectiveGain) && effectiveGain >= 0 && effectiveGain.finite());
213210
}
214211
}

sources/libsimple/sound.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ namespace cage
170170
const Transform t = interpolate(e.transformHistory, e.transform, interFactor);
171171
l.mixer->orientation = t.orientation;
172172
l.mixer->position = t.position;
173-
l.mixer->maxActiveVoices = e.listener.maxSounds;
173+
l.mixer->maxActiveSounds = e.listener.maxSounds;
174+
l.mixer->maxGainThreshold = e.listener.maxGainThreshold;
174175
l.mixer->gain = e.listener.gain;
175176
}
176177

0 commit comments

Comments
 (0)