VAE - Virtual Audio Engine 1
Small Data Driven Audio Engine
vae::core::VoiceManger Class Reference

There is only one voice pool and VAE and it's managed here. More...

#include <vae_voice_manager.hpp>

Collaboration diagram for vae::core::VoiceManger:

Public Member Functions

Result init (const EngineConfig &config)
 
HeapBuffer< Voice > & all ()
 
HeapBuffer< Voice > & finished ()
 
Size getActiveVoiceCount () const
 
template<class Func >
void forEachVoice (const Func &&func)
 Callback provided to iterate voices, needs to return a bool to indicate when a voice needs to be stopped. More...
 
template<class Func >
void forEachFinishedVoice (const Func &&func)
 
VoicePangetVoicePan (Size index)
 
VoiceFiltergetVoiceFilter (Size index)
 
Result play (Event &event, const BankHandle bank, const Sample gain, const EmitterHandle emitter, const ListenerHandle listener, const MixerHandle mixer)
 
Result makeVirtual (Voice &v)
 makes provided voice virtual More...
 
Result stop (Voice &v)
 Stops a voice. More...
 
template<typename T >
Result stop (T handle, T Voice::*member, const EmitterHandle emitter=InvalidEmitterHandle)
 Stop voice based on a member value and optionally an emitter. More...
 
template<typename T >
void setVoiceProperty (EmitterHandle emitter, T Voice::*member, const T &value)
 
template<typename T >
void setVoiceProperty (EmitterHandle emitter, T VoiceFilter::*member, const T &value)
 

Private Attributes

HeapBuffer< VoicemFinishedVoiceQueue
 voices that finished playing are queued here More...
 
HeapBuffer< VoicemVoices
 Currently playing voice are here. More...
 
HeapBuffer< VoicemVirtualVoices
 
HeapBuffer< VoicePanmVoicePans
 Interpolation data for the panning algorithm or manual panning data. More...
 
HeapBuffer< VoiceFiltermVoiceFiltered
 Data needed for filtering is here. More...
 
Size mActiveVoices = 0
 Number of currently playing voices. More...
 
Size mInactiveVoices = 0
 Number of currenly virtual voices. More...
 
Size mActiveHRTFVoices = 0
 Number of ative hrtf voices. More...
 
Size mHRTFVoiceCount = 0
 Number of voices reserved for hrtf. More...
 
Size mHighestVoice = 0
 TODO bad. More...
 
Size mFinishedPending = 0
 Voices in mFinishedVoiceQueue. More...
 
Size mHighestFinishedVoice = 0
 TODO bad as well. More...
 
Size mStarvedVoices = 0
 Voices which could not play since no other voice could be killed and are lost forever. More...
 
Size mStoppedQueueOverflow = 0
 Voice which did not fit mFinishedVoiceQueue and could not triggered chained events. More...
 

Detailed Description

There is only one voice pool and VAE and it's managed here.

This class handles starting and stopping voices as well as virtualization

Definition at line 34 of file vae_voice_manager.hpp.

Member Function Documentation

◆ all()

HeapBuffer< Voice > & vae::core::VoiceManger::all ( )
inline

Definition at line 62 of file vae_voice_manager.hpp.

62 {
63 return mVoices;
64 }
HeapBuffer< Voice > mVoices
Currently playing voice are here.

◆ finished()

HeapBuffer< Voice > & vae::core::VoiceManger::finished ( )
inline

Definition at line 66 of file vae_voice_manager.hpp.

66 {
68 }
HeapBuffer< Voice > mFinishedVoiceQueue
voices that finished playing are queued here
Here is the caller graph for this function:

◆ forEachFinishedVoice()

template<class Func >
void vae::core::VoiceManger::forEachFinishedVoice ( const Func &&  func)
inline

Definition at line 96 of file vae_voice_manager.hpp.

96 {
97 VAE_PROFILER_SCOPE_NAMED("Foreach Finished Voice")
98 for (Size i = 0; i <= mHighestFinishedVoice; i++) {
99 auto& v = mFinishedVoiceQueue[i];
100 if (v.source == InvalidSourceHandle) { continue; }
101 if (!func(v)) { continue; };
103 v.source = InvalidSourceHandle; // now the finished voice is handled
104 }
109 }
Size mHighestFinishedVoice
TODO bad as well.
Size mActiveHRTFVoices
Number of ative hrtf voices.
Size mActiveVoices
Number of currently playing voices.
Size mFinishedPending
Voices in mFinishedVoiceQueue.
Size mInactiveVoices
Number of currenly virtual voices.
const char *const voiceHRTFCount
const char *const voiceCount
Definition: vae_profiler.hpp:7
const char *const voiceVirtualCount
Definition: vae_profiler.hpp:9
const char *const voiceFinishedCount
Definition: vae_profiler.hpp:8
unsigned int Size
How the elements are addressed in the heapbuffer.
Definition: vae.hpp:33
constexpr SourceHandle InvalidSourceHandle
Definition: vae.hpp:56
#define VAE_PROFILER_SCOPE_NAMED(name)
Profiles a scope and names it.
#define VAE_PROFILER_PLOT(name, value)
Records a value.
Here is the caller graph for this function:

◆ forEachVoice()

template<class Func >
void vae::core::VoiceManger::forEachVoice ( const Func &&  func)
inline

Callback provided to iterate voices, needs to return a bool to indicate when a voice needs to be stopped.

Template Parameters
Func
Parameters
func

Definition at line 81 of file vae_voice_manager.hpp.

81 {
82 VAE_PROFILER_SCOPE_NAMED("Foreach Voice")
83 for (Size index = 0; index <= mHighestVoice; index++) {
84 auto& i = mVoices[index];
85 if (i.source == InvalidSourceHandle) { continue; }
86 if (!func(i, index)) {
87 stop(i); // stop the voice if callback returns false
88 }
89 }
93 }
Result stop(Voice &v)
Stops a voice.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getActiveVoiceCount()

Size vae::core::VoiceManger::getActiveVoiceCount ( ) const
inline

Definition at line 70 of file vae_voice_manager.hpp.

70 {
71 return mActiveVoices;
72 }
Here is the caller graph for this function:

◆ getVoiceFilter()

VoiceFilter & vae::core::VoiceManger::getVoiceFilter ( Size  index)
inline

Definition at line 115 of file vae_voice_manager.hpp.

115 {
116 return mVoiceFiltered[index];
117 }
HeapBuffer< VoiceFilter > mVoiceFiltered
Data needed for filtering is here.

◆ getVoicePan()

VoicePan & vae::core::VoiceManger::getVoicePan ( Size  index)
inline

Definition at line 111 of file vae_voice_manager.hpp.

111 {
112 return mVoicePans[index];
113 }
HeapBuffer< VoicePan > mVoicePans
Interpolation data for the panning algorithm or manual panning data.
Here is the caller graph for this function:

◆ init()

Result vae::core::VoiceManger::init ( const EngineConfig config)
inline

Definition at line 51 of file vae_voice_manager.hpp.

51 {
52 VAE_PROFILER_SCOPE_NAMED("Voicemanager Init")
53 mVoices.resize(config.voices);
54 mFinishedVoiceQueue.resize(config.finishedVoiceQueueSize);
55 mVoicePans.resize(config.voices);
56 mVoiceFiltered.resize(config.voices);
57 mVirtualVoices.resize(config.virtualVoices);
58 mHRTFVoiceCount = config.hrtfVoices;
59 return Result::Success;
60 }
Size mHRTFVoiceCount
Number of voices reserved for hrtf.
HeapBuffer< Voice > mVirtualVoices
Result
Return Types for most engine functions.
Definition: vae.hpp:73

◆ makeVirtual()

Result vae::core::VoiceManger::makeVirtual ( Voice v)
inline

makes provided voice virtual

Parameters
v
Returns
Result

Definition at line 244 of file vae_voice_manager.hpp.

244 {
246 for (Size i = 0; i < mVirtualVoices.size(); i++) {
247 auto& slot = mVirtualVoices[i];
248 if (slot.source != InvalidSourceHandle) { continue; }
249 slot = v;
250 v.source = InvalidSourceHandle;
252 if (slot.HRTF) {
254 } else {
256 }
260
261 VAE_DEBUG_VOICES("Virtualized voice from event %i:%i\tactive: %i\tincative: %i",
262 v.event, v.bank, mActiveVoices, mInactiveVoices
263 )
264 return Result::Success;
265 }
267 }
@ GenericFailure
:(
#define VAE_DEBUG_VOICES(msg,...)
Definition: vae_logger.hpp:90
#define VAE_PROFILER_SCOPE()
Profiles a scope.
Here is the caller graph for this function:

◆ play()

Result vae::core::VoiceManger::play ( Event event,
const BankHandle  bank,
const Sample  gain,
const EmitterHandle  emitter,
const ListenerHandle  listener,
const MixerHandle  mixer 
)
inline
Parameters
event
bank
emitter
mixer
Returns
Result

Definition at line 128 of file vae_voice_manager.hpp.

132 {
134
135 Size searchStartIndex;
136 Size searchEndIndex;
137 bool starved;
138
139 if (event.HRTF) {
140 searchStartIndex = 0;
141 searchEndIndex = mHRTFVoiceCount;
143 } else {
144 searchStartIndex = mHRTFVoiceCount;
145 searchEndIndex = (Size) mVoices.size();
146 starved = mActiveVoices == (mVoices.size() - mHRTFVoiceCount);
147 }
148
149 // No voices left, find one to virtualize
150 if(starved) {
151 VAE_PROFILER_SCOPE_NAMED("Search killable Voice")
152 Size potentialVirtual = ~0;
153 Sample lowestGain = 10;
154 for (Size i = searchStartIndex; i < searchEndIndex; i++) {
155 auto& v = mVoices[i];
156 if (v.critical) { continue; } // Don't kill important voices
157
158 if (!v.audible) {
159 if (makeVirtual(v) == Result::Success) {
160 searchStartIndex = i;
161 break;
162 }
163 }
164
165 if (v.gain <= lowestGain) {
166 lowestGain = v.gain;
167 potentialVirtual = i;
168 }
169 }
170
171 if (potentialVirtual < searchEndIndex) {
172 makeVirtual(mVoices[potentialVirtual]);
173 searchStartIndex = potentialVirtual;
174 }
175 }
176
177 // Find a free voice
178 for (Size i = searchStartIndex; i < searchEndIndex; i++) {
179 VAE_PROFILER_SCOPE_NAMED("Search Free Voice")
180 auto& v = mVoices[i];
181 if(v.source == InvalidSourceHandle) {
182 v = { }; // re init object resets time and so on
183 v.source = event.source;
184 v.event = event.id;
185 v.listener = listener;
186
187 // find out if voice should trigger events on end
188 // if not killing the voice is easier so this gets a flag
189 v.chainedEvents = v.chainedEvents || (event.on_end != InvalidEventHandle);
190
191 if (mixer != InvalidMixerHandle && !event.force_mixer) {
192 // Only use the mixer provided if it's valid
193 // and the event allows overriding it
194 v.mixer = mixer;
195 } else {
196 // Otherwise use the mixer from the event
197 v.mixer = event.mixer;
198 }
199
200 v.gain = event.gain * gain;
201 v.loop = event.loop;
202 v.attenuate = event.attenuate;
203 // v.filtered = true; // todo provide way to init the filter settings
204 if (v.filtered) {
205 mVoiceFiltered[i] = { };
206 }
207
208 v.emitter = emitter;
209 v.spatialized = event.spatial;
210 mVoicePans[i] = { }; // Always clear this since non spatial use this for manual panning
211 v.HRTF = event.HRTF;
212 v.bank = bank;
213 if (v.HRTF) {
215 } else {
217 }
222 VAE_DEBUG_VOICES("Started voice slot %i from event %i:%i\tactive: %i",
223 i, event.id, bank, mActiveVoices
224 )
225 return Result::Success;
226 }
227 }
228
229 mHighestVoice = (Size) mVoices.size() - 1;
230
233
234 VAE_DEBUG_VOICES("Voice starvation. Can't start voice from event %i:%i", event.id, bank)
235
237 }
Size mStarvedVoices
Voices which could not play since no other voice could be killed and are lost forever.
Result makeVirtual(Voice &v)
makes provided voice virtual
T max(const T &v1, const T &v2)
Definition: TMath.hpp:21
const char *const starvedVoiceCount
float Sample
Default sample types used where ever possible, changing this means the engine needs to be recompiled,...
Definition: vae.hpp:32
constexpr EventHandle InvalidEventHandle
Definition: vae.hpp:55
@ VoiceStarvation
Could not play sound because of voice limit.
constexpr MixerHandle InvalidMixerHandle
Definition: vae.hpp:58
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setVoiceProperty() [1/2]

template<typename T >
void vae::core::VoiceManger::setVoiceProperty ( EmitterHandle  emitter,
T Voice::*  member,
const T &  value 
)
inline

Definition at line 393 of file vae_voice_manager.hpp.

393 {
395 for (auto& v : mVoices) {
396 if(v.emitter == emitter) {
397 (&v)->*member = value;
398 }
399 }
400 }
Here is the caller graph for this function:

◆ setVoiceProperty() [2/2]

template<typename T >
void vae::core::VoiceManger::setVoiceProperty ( EmitterHandle  emitter,
T VoiceFilter::*  member,
const T &  value 
)
inline

Definition at line 403 of file vae_voice_manager.hpp.

403 {
405 for (Size i = 0; i < mVoices.size(); i++) {
406 auto& v = mVoices[i];
407 if(v.emitter == emitter) {
408 (&mVoiceFiltered[i])->*member = value;
409 v.filtered = true;
410 }
411 }
412 }

◆ stop() [1/2]

template<typename T >
Result vae::core::VoiceManger::stop ( handle,
T Voice::*  member,
const EmitterHandle  emitter = InvalidEmitterHandle 
)
inline

Stop voice based on a member value and optionally an emitter.

Can kill multiple voices if they match. Alco affects virtual voices

Template Parameters
THandle type like MixerHandle
Parameters
handleHandle to use to look for voice
memberPointer to member variable of Voice
emitterOptional emitter which also needs to match if provided
Returns
Result Alsoways a success

Definition at line 371 of file vae_voice_manager.hpp.

371 {
373 // Kill all the virtual voices first
374 for (auto& v : mVirtualVoices) {
375 if (v.source == InvalidSourceHandle) { continue; }
376 // only consider active voices
377 if ((&v)->*member != handle) { continue; }
378 // If we got an emitter it has to match too
379 if (emitter != InvalidEmitterHandle && v.emitter == emitter) { continue; }
380 v.source = InvalidSourceHandle;
381 }
382
383 for (auto& v : mVoices) {
384 if (v.source == InvalidSourceHandle) { continue; }
385 if ((&v)->*member != handle) { continue; }
386 if (emitter != InvalidEmitterHandle && v.emitter == emitter) { continue; }
387 stop(v);
388 }
389 return Result::Success;
390 }
constexpr EmitterHandle InvalidEmitterHandle
Definition: vae.hpp:61
Here is the call graph for this function:

◆ stop() [2/2]

Result vae::core::VoiceManger::stop ( Voice v)
inline

Stops a voice.

Mostly used internally since other stop function provide better usage also revives virtual voices

Parameters
vVoice to stop
Returns
Result

If the event triggers something on_end it needs to be added to the finishedVoiceQueue array in the voice manager. The update() function on the engine will handle it

Definition at line 276 of file vae_voice_manager.hpp.

276 {
278 if (v.source == InvalidSourceHandle) { return Result::Success; }
279
280 if (!v.chainedEvents) {
281 if (0 < mInactiveVoices) {
282 // If we have inactive voices, revive one
283 for (Size i = 0; i < mVirtualVoices.size(); i++) {
284 auto virt = mVirtualVoices[i];
285 if (virt.source == InvalidSourceHandle) { continue; }
286 if (virt.HRTF == v.HRTF) {
287 virt.started = false; // marks filter buffers for clearing
288 v = virt;
289 virt.source = InvalidSourceHandle;
291 VAE_DEBUG_VOICES("Revived voice from event %i:%i\tactive: %i\tincative: %i",
292 v.event, v.bank, mActiveVoices, mInactiveVoices
293 )
297 return Result::Success;
298 }
299 }
300 }
301 v.source = InvalidSourceHandle; // Mark voice as free
302 if (v.HRTF) {
304 } else {
306 }
310 return Result::Success;
311 }
312
313 /**
314 * If the event triggers something on_end
315 * it needs to be added to the finishedVoiceQueue
316 * array in the voice manager.
317 * The update() function on the engine will handle it
318 */
319
320 // TODO VAE PERF
321 bool finished = false;
322 for (Size i = 0; i < mFinishedVoiceQueue.size(); i++) {
323 auto& f = mFinishedVoiceQueue[i];
324 if (f.source == InvalidSourceHandle) {
326 finished = true;
327 f = v;
328 // // This is set last since it marks the
329 // // finished voice for other threads
330 // f.source = v.source;
331 VAE_DEBUG_VOICES("Stopped voice from event %i:%i\tactive: %i",
332 f.event, f.bank, mActiveVoices
333 )
334 break;
335 }
336 }
337 if (v.HRTF) {
339 } else {
341 }
342 v.source = InvalidSourceHandle; // Mark voice as free
343
344 if (!finished) {
346 // Failed to find a free spot in finished voices array
347 // Event will be discarded
348 VAE_DEBUG_VOICES("finishedVoiceQueue is full. Stop Event %i in bank %i discarded", v.event, v.bank)
351 } else {
353 }
358 return Result::Success;
359 }
HeapBuffer< Voice > & finished()
Size mStoppedQueueOverflow
Voice which did not fit mFinishedVoiceQueue and could not triggered chained events.
else() add_library(tklb STATIC $
const char *const stoppedVoiceOverflow
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ mActiveHRTFVoices

Size vae::core::VoiceManger::mActiveHRTFVoices = 0
private

Number of ative hrtf voices.

Definition at line 43 of file vae_voice_manager.hpp.

◆ mActiveVoices

Size vae::core::VoiceManger::mActiveVoices = 0
private

Number of currently playing voices.

Definition at line 41 of file vae_voice_manager.hpp.

◆ mFinishedPending

Size vae::core::VoiceManger::mFinishedPending = 0
private

Voices in mFinishedVoiceQueue.

Definition at line 46 of file vae_voice_manager.hpp.

◆ mFinishedVoiceQueue

HeapBuffer<Voice> vae::core::VoiceManger::mFinishedVoiceQueue
private

voices that finished playing are queued here

Definition at line 35 of file vae_voice_manager.hpp.

◆ mHighestFinishedVoice

Size vae::core::VoiceManger::mHighestFinishedVoice = 0
private

TODO bad as well.

Definition at line 47 of file vae_voice_manager.hpp.

◆ mHighestVoice

Size vae::core::VoiceManger::mHighestVoice = 0
private

TODO bad.

Definition at line 45 of file vae_voice_manager.hpp.

◆ mHRTFVoiceCount

Size vae::core::VoiceManger::mHRTFVoiceCount = 0
private

Number of voices reserved for hrtf.

Definition at line 44 of file vae_voice_manager.hpp.

◆ mInactiveVoices

Size vae::core::VoiceManger::mInactiveVoices = 0
private

Number of currenly virtual voices.

Definition at line 42 of file vae_voice_manager.hpp.

◆ mStarvedVoices

Size vae::core::VoiceManger::mStarvedVoices = 0
private

Voices which could not play since no other voice could be killed and are lost forever.

Definition at line 48 of file vae_voice_manager.hpp.

◆ mStoppedQueueOverflow

Size vae::core::VoiceManger::mStoppedQueueOverflow = 0
private

Voice which did not fit mFinishedVoiceQueue and could not triggered chained events.

Definition at line 49 of file vae_voice_manager.hpp.

◆ mVirtualVoices

HeapBuffer<Voice> vae::core::VoiceManger::mVirtualVoices
private

Definition at line 37 of file vae_voice_manager.hpp.

◆ mVoiceFiltered

HeapBuffer<VoiceFilter> vae::core::VoiceManger::mVoiceFiltered
private

Data needed for filtering is here.

Definition at line 39 of file vae_voice_manager.hpp.

◆ mVoicePans

HeapBuffer<VoicePan> vae::core::VoiceManger::mVoicePans
private

Interpolation data for the panning algorithm or manual panning data.

Definition at line 38 of file vae_voice_manager.hpp.

◆ mVoices

HeapBuffer<Voice> vae::core::VoiceManger::mVoices
private

Currently playing voice are here.

Definition at line 36 of file vae_voice_manager.hpp.


The documentation for this class was generated from the following file: