@@ -49,8 +49,6 @@ namespace Audio {
4949 static sourceRecord_t* sources = nullptr ;
5050 static CONSTEXPR int nSources = 128 ; // TODO see what's the limit for OpenAL soft
5151
52- sourceRecord_t* GetSource (int priority);
53-
5452 static bool initialized = false ;
5553
5654 void InitSounds () {
@@ -116,44 +114,55 @@ namespace Audio {
116114 }
117115 }
118116
119- void AddSound (std::shared_ptr<Emitter> emitter, std::shared_ptr<Sound> sound, int priority) {
120- if (not initialized) {
121- return ;
122- }
117+ static Cvar::Range<Cvar::Cvar<int >> a_clientSoundPriorityMaxDistance ( " a_clientSoundPriorityMaxDistance" ,
118+ " Sounds emitted by players/bots within this distance (in qu) will have higher priority than other sounds"
119+ " (multiplier: a_clientSoundPriorityMultiplier)" , Cvar::NONE, 32 * 32 , 0 , BIT( 16 ) );
123120
124- sourceRecord_t* source = GetSource (priority);
121+ static Cvar::Range<Cvar::Cvar<float >> a_clientSoundPriorityMultiplier ( " a_clientSoundPriorityMultiplier" ,
122+ " Sounds emitted by players/bots within a_clientSoundPriorityMaxDistance"
123+ " will use this value as their priority multiplier" ,
124+ Cvar::NONE, 2 .0f , 0 .0f , 1024 .0f );
125125
126- if (source) {
127- // Make the source forget if it was a "static" or a "streaming" source.
128- source->source .ResetBuffer ();
129- sound->emitter = emitter;
130- sound->AcquireSource (source->source );
131- source->usingSound = sound;
132- source->priority = priority;
133- source->active = true ;
126+ static float GetAdjustedVolumeForPosition ( const Vec3& origin, const Vec3& src, const bool isClient ) {
127+ vec3_t v0 { origin.Data ()[0 ], origin.Data ()[1 ], origin.Data ()[2 ] };
128+ vec3_t v1 { src.Data ()[0 ], src.Data ()[1 ], src.Data ()[2 ] };
134129
135- sound->FinishSetup ();
136- sound->Play ();
130+ float totalPriority = VectorDistanceSquared ( v0, v1 );
131+
132+ const float distanceThreshold = a_clientSoundPriorityMaxDistance.Get ();
133+ if ( isClient && totalPriority < distanceThreshold * distanceThreshold ) {
134+ totalPriority *= 1 .0f / a_clientSoundPriorityMultiplier.Get ();
137135 }
136+
137+ return 1 .0f / totalPriority;
138138 }
139139
140140 // Finds a inactive or low-priority source to play a new sound.
141- sourceRecord_t* GetSource (int priority) {
142- // TODO make a better heuristic? (take into account the distance / the volume /... ?)
141+ static sourceRecord_t* GetSource ( const Vec3& position, int priority, const float currentGain ) {
143142 int best = -1 ;
144- int bestPriority = priority;
145143
146- // Gets the minimum sound by comparing activity first then priority
144+ const Vec3& playerPos = entities[playerClientNum].position ;
145+
146+ // Sound volume is inversely proportional to distance to the source
147+ const float adjustedVolume = Q_rsqrt_fast ( currentGain )
148+ * GetAdjustedVolumeForPosition ( playerPos, position, priority == CLIENT );
149+
150+ // Gets the minimum sound by comparing activity first, then the adjusted volume
147151 for (int i = 0 ; i < nSources; i++) {
148152 sourceRecord_t& source = sources[i];
149153
150154 if (not source.active ) {
151155 return &source;
152156 }
153157
154- if (source.priority < bestPriority || (best < 0 && source.priority <= priority)) {
158+ const Vec3& sourcePos = source.usingSound ->emitter ->GetPosition ();
159+
160+ // Sound volume is inversely proportional to distance to the source
161+ const float adjustedSourceVolume = Q_rsqrt_fast ( source.usingSound ->currentGain )
162+ * GetAdjustedVolumeForPosition ( playerPos, sourcePos, source.priority == CLIENT );
163+
164+ if ( adjustedVolume > adjustedSourceVolume ) {
155165 best = i;
156- bestPriority = source.priority ;
157166 continue ;
158167 }
159168 }
@@ -171,6 +180,30 @@ namespace Audio {
171180 }
172181 }
173182
183+ void AddSound ( std::shared_ptr<Emitter> emitter, std::shared_ptr<Sound> sound, int priority ) {
184+ if ( not initialized ) {
185+ return ;
186+ }
187+
188+ const Vec3& position = emitter->GetPosition ();
189+ const float currentGain = sound->positionalGain * sound->soundGain
190+ * SliderToAmplitude ( sound->volumeModifier ->Get () );
191+ sourceRecord_t* source = GetSource ( position, priority, currentGain );
192+
193+ if ( source ) {
194+ // Make the source forget if it was a "static" or a "streaming" source.
195+ source->source .ResetBuffer ();
196+ sound->emitter = emitter;
197+ sound->AcquireSource ( source->source );
198+ source->usingSound = sound;
199+ source->priority = priority;
200+ source->active = true ;
201+
202+ sound->FinishSetup ();
203+ sound->Play ();
204+ }
205+ }
206+
174207 // Implementation of Sound
175208
176209 Sound::Sound () : positionalGain(1 .0f ), soundGain(1 .0f ), currentGain(1 .0f ),
0 commit comments