VAE - Virtual Audio Engine 1
Small Data Driven Audio Engine
vae.hpp
Go to the documentation of this file.
1/**
2 * @file vae.hpp
3 * @author Tobias Kozel (t.kozel@pm.me)
4 * @brief Contains all public API types for VAE
5 * @version 0.1
6 * @date 2021-11-27
7 *
8 * @copyright Copyright (c) 2021
9 *
10 */
11
12#ifndef _VAE_API
13#define _VAE_API
14
15// see https://semver.org/
16#define VAE_VERSION_MAJOR 0 //< for incompatible API changes
17#define VAE_VERSION_MINOR 0 //< for adding functionality in a backwards-compatible manner
18#define VAE_VERSION_PATCH 1 //< for backwards-compatible bug fixes
19
20/**
21 * @brief Contains generated Event ids using generate_bank_defines.py
22 * @details Header can be included and used for autocompletion when calling
23 * vae::EnginePimpl::fireGlobalEvent or vae::core::Engine::fireGlobalEvent
24 */
25namespace vaeb { }
26
27/**
28 * @brief Contains Typedefinitions and basic structures use by the public API and internally
29 * @details The types used internally like handles or static settings can be changed, but vae::EnginePimpl needs to be recompiled.
30 */
31namespace vae {
32 using Sample = float; ///< Default sample types used where ever possible, changing this means the engine needs to be recompiled, short and int isn't working, probably needs a few changes in the pipeline
33 using Size = unsigned int; ///< How the elements are addressed in the heapbuffer
34 using Time = double; ///< Time sotred in seconds
35
36 using SmallHandle = unsigned char;
37 using GenericHandle = unsigned short;
38 using LargeHandle = unsigned int;
39
41 using EventHandle = GenericHandle; ///< The handle used to address events within a bank
46
47 using GlobalEventHandle = LargeHandle; ///< Used to globally address events, holds space for BankHandle and EventHandle
50 /**
51 * @brief Since 0 is a valid handle, these are used to identify invalid ones.
52 * Seems a little odd but means they can be used to direcly address array elements.
53 */
60 constexpr ListenerHandle AllListeners = (~0) - 1; ///< Will address all listeners
64
65 static_assert(
66 (sizeof(BankHandle) + sizeof(EventHandle)) <= sizeof(GlobalEventHandle),
67 "BankHandle combined with EventHandle needs to fit in GlobalEventHandle"
68 );
69
70 /**
71 * @brief Return Types for most engine functions
72 */
73 enum class Result {
74 Success = 0, ///< :)
75 GenericFailure, ///< :(
76 BankFormatError, ///< Generic bank loading error
77 BankFormatIndexError, ///< A index is out of bounds
78 BankFormatDuplicateIndex, ///< A index is used muktiple times
79 FileOpenError, ///< File system could not load file
80 VoiceStarvation, ///< Could not play sound because of voice limit
81 BankFormatBadMixHirarchy, ///< A mixer can only write to mixers with lower ids than themselves (no recursion)
82 ElementNotFound, ///< Referenced data not found
83 ValidHandleRequired, ///< Handle provided wasn't valid but needs to be
84 TooManyRecords, ///< Can't fit all data in fixed size array
85 DeviceError, ///< Can't open audio device
86 DuplicateEmitter, ///< Trying to register emitter twice
87 InvalidBank, ///< Valid bank handle needed
88 InvalidEmitter ///< Emitter probably wasn't registered
89 };
90
91 enum class LogLevel {
92 Debug = 0,
93 Info,
94 Warn,
95 Error,
97 };
98
99 /**
100 * @brief Basic struct describing a audio device
101 */
102 struct DeviceInfo {
103 int id; ///< Negative values for invalid device.
104 unsigned int sampleRate = 0; ///< TODO not used?
105 char name[255]; ///< Device name reported from backend
106 char api[4]; ///< API abbreviation
107 unsigned int bufferSize = 0; ///< desired bufferSize
108 unsigned char channelsIn = 0;
109 unsigned char channelsOut = 0;
110 };
111
112 /**
113 * @brief Public vae Vector 3 type
114 */
115 struct Vector3 { float x, y, z; };
116
117 /**
118 * @brief Emitters have a position and direction vector
119 * @details The direction vector isn't used since source can only emit unidirectional
120 */
124 };
125
126 /**
127 * @brief Listener uses additional up vector.
128 * This is the default coordinate system orientation.
129 * @attention Technically the can be changed but the speaker placements in vae::StaticConfig::Speakers need to be changed accordingly.
130 * @see vae::StaticConfig::Speakers
131 * @see vae::core::HRTFLoader
132 */
134 Vector3 position = { 0.f, 0.f, 0.f };
135 Vector3 front = { 0.f, 0.f, -1.f }; ///< -z front
136 Vector3 up = { 0.f, 1.f, 0.f }; ///< Y up
137 };
138
139
140 /**
141 * @brief Struct containing relevant data passed
142 * to EventCallback provided in the EngineConfig.
143 */
145 void* context; ///< Can point to custom context data also provided when setting the callback, ! not context based on event!
146 BankHandle bank; ///< Which bank the event is from
147 EventHandle event; ///< Which event
148 EmitterHandle emitter; ///< Which emitter
149 };
150
151 using EventCallback = void(*)(const EventCallbackData*);
152
153 /**
154 * @brief Settings for the engine defined
155 * at EnginePimpl::init
156 */
158 /**
159 * @brief Path where the bank files are located, needs to end with a trailing /
160 */
161 const char* rootPath = "./";
162
163 /**
164 * @brief Samplerate requested from device.
165 * @details If it doesn't support it, a resampler is used.
166 * Most of the audio samples used should be in this rate.
167 */
169
170 /**
171 * @brief Each time a event of the type emit gets triggered
172 * Used to get information about ending sounds and similar
173 */
175
176 /**
177 * @brief Custom data that can be accached to the EventCallback
178 * to maintain context
179 */
180 void* eventCallbackContext = nullptr;
181
182 static constexpr Size _preAllocatedEmitters = 1 << 14;
183
184 /**
185 * @brief How many emitters to allocate upfront.
186 * @details Once this number is exceeded a reallocation will take place.
187 * This might cause a short audio dropout depending on the size.
188 * ! internal map allocates power of 2 sizes !
189 * This makes space for 16384 emitters.
190 * Having less emitters than amount of voices does't make too much sense
191 * since each voice will have one assigned.
192 * Unless one emitter triggers a lot of sounds.
193 */
195
196 /**
197 * @brief Hard limit on concurrent voices, can't be 0 or lower than hrtfVoices.
198 * @details Rendering 512 voices with filters and spatialization
199 * is probably pushing it for most situations and not even necessary.
200 * This is a few years old but AudioKinetic recommends something around a 100
201 * https://blog.audiokinetic.com/how-to-get-a-hold-on-your-voices-optimizing-for-cpu-part-1/
202 */
204
205 /**
206 * @brief Amount of HRTF panned voices audible at any given time.
207 * Eats into the budget above.
208 */
210
211 /**
212 * @brief Hard limit on virtal voices.
213 * @details Virtualized voices will be revived as soon as possible and
214 * retain their playback position.
215 */
217
218 /**
219 * @brief Size of the voice queue for finished voices which
220 * need to trigger other events on_end when updating the engine.
221 * Too low of a value can cause these events to be discarded.
222 */
224
225
226 /**
227 * @brief Buffer size that will be requested from device.
228 * @details Higher values increase latency but reduce chanes of
229 * crackles and other artefacts. Some audio backends need
230 * higher values to work properly.
231 * The actual buffer size might vary based on the device.
232 */
234
235 /**
236 * @brief Number of blocks/buffers to processed ahead.
237 * @details Increases latency but reduces chances of underruns
238 * since it's more forgiving to the scheduler.
239 */
241
242 /**
243 * @brief If this is true update() does not need to be called on the engine instance.
244 * @details This means events will be emitted more offen
245 * and if a lot of work is done in the EventCallback defined above,
246 * the audio thread will be blocked and underruns occur.
247 */
249
250 /**
251 * @brief If enabled, all processing and mixing will happen in the audio callback.
252 * @details This results in lower latency and one less thread running, but this
253 * isn't good practice apparently.
254 *
255 */
257 };
258
259 /**
260 * @brief Contains some fundamental Configuration needed at compile time
261 * Dynamic settings are contained in the EngineSettings struct above.
262 * @details Changes made here need recompilation
263 */
264 namespace StaticConfig {
265 /**
266 * @brief Maximum channel count used to pre allocate buffers
267 */
268 constexpr unsigned char MaxChannels = 2;
269
270 /**
271 * @brief Maximum block size
272 * @details Used to preallocate buffers for mixers and dsp.
273 * Higher values need more memory might play better with instruction caches
274 * but uses more memory.
275 */
276 constexpr Size MaxBlock = 512;
277
278 /**
279 * @brief How many Samples to prefetch for streaming sources
280 * @attention TODO no streaming for now might even be a runtime settings
281 */
282 constexpr Size StreamPrefetch = 1024 * 8;
283
284 /**
285 * @brief How many listeners can observe 3D voices
286 * @see vae::core::Listener::Listeners
287 */
288 constexpr Size MaxListeners = 4;
289
290 /**
291 * @brief How many effects a mixer channel can process
292 * @see vae::core::Mixer::effects
293 */
294 constexpr Size MaxMixerEffects = 4;
295
297
298 /**
299 * @brief How many chained events can fit in chain_events on the core::Event structure
300 * @see vae::core::Event::chained_events
301 */
302 constexpr Size MaxChainedEvents = 4;
303
304 /**
305 * @brief Minimum volume before sounds will skip rendering
306 */
307 constexpr Sample MinVolume = 0.01f;
308
309 /**
310 * @brief Placement of the speakers around the listener used for SPCAP panning
311 * @details Distance to the listener is not taken into account.
312 * The subwoofer has no placement.
313 */
314 namespace Speakers {
315 constexpr Vector3 center = { 0, 0, -1 }; ///< Used for mono and souround setups (except quadrophonic)
316
317 constexpr Vector3 left = { -1, 0, 0 }; ///< Used in 7.1 and Headphones
318 constexpr Vector3 right = { +1, 0, 0 }; ///< Used in 7.1 and Headphones
319
320 constexpr Vector3 frontLeft = { +1, 0, -1 }; ///< Stereo and suround setups
321 constexpr Vector3 frontRight = { +1, 0, -1 }; ///< Stereo and suround setups
322
323 constexpr Vector3 rearLeft = { +1, 0, +1 }; ///< Sourund setups
324 constexpr Vector3 rearRight = { +1, 0, +1 }; ///< Sourund setups
325 }
326 }
327} // namespace vae
328
329#endif // _VAE_API
constexpr Vector3 right
Used in 7.1 and Headphones.
Definition: vae.hpp:318
constexpr Vector3 rearLeft
Sourund setups.
Definition: vae.hpp:323
constexpr Vector3 rearRight
Sourund setups.
Definition: vae.hpp:324
constexpr Vector3 frontLeft
Stereo and suround setups.
Definition: vae.hpp:320
constexpr Vector3 center
Used for mono and souround setups (except quadrophonic)
Definition: vae.hpp:315
constexpr Vector3 frontRight
Stereo and suround setups.
Definition: vae.hpp:321
constexpr Vector3 left
Used in 7.1 and Headphones.
Definition: vae.hpp:317
constexpr Sample MinVolume
Minimum volume before sounds will skip rendering.
Definition: vae.hpp:307
constexpr Size MaxListeners
How many listeners can observe 3D voices.
Definition: vae.hpp:288
constexpr Size MaxBlock
Maximum block size.
Definition: vae.hpp:276
constexpr Size MaxChainedEvents
How many chained events can fit in chain_events on the core::Event structure.
Definition: vae.hpp:302
constexpr Size MaxEffectsParameter
Definition: vae.hpp:296
constexpr unsigned char MaxChannels
Maximum channel count used to pre allocate buffers.
Definition: vae.hpp:268
constexpr Size StreamPrefetch
How many Samples to prefetch for streaming sources.
Definition: vae.hpp:282
constexpr Size MaxMixerEffects
How many effects a mixer channel can process.
Definition: vae.hpp:294
Contains Typedefinitions and basic structures use by the public API and internally.
Definition: vae.hpp:31
constexpr ListenerHandle AllListeners
Will address all listeners.
Definition: vae.hpp:60
constexpr EmitterHandle InvalidEmitterHandle
Definition: vae.hpp:61
unsigned int Size
How the elements are addressed in the heapbuffer.
Definition: vae.hpp:33
unsigned char SmallHandle
Definition: vae.hpp:36
unsigned short GenericHandle
Definition: vae.hpp:37
float Sample
Default sample types used where ever possible, changing this means the engine needs to be recompiled,...
Definition: vae.hpp:32
SmallHandle MixerHandle
Definition: vae.hpp:44
constexpr GenericHandle InvalidHandle
Since 0 is a valid handle, these are used to identify invalid ones.
Definition: vae.hpp:54
constexpr SourceHandle InvalidSourceHandle
Definition: vae.hpp:56
LargeHandle GlobalParameterHandle
TODO.
Definition: vae.hpp:49
SmallHandle BankHandle
Definition: vae.hpp:40
double Time
Time sotred in seconds.
Definition: vae.hpp:34
SmallHandle ListenerHandle
Definition: vae.hpp:45
constexpr EventHandle InvalidEventHandle
Definition: vae.hpp:55
LargeHandle EmitterHandle
Definition: vae.hpp:43
unsigned int LargeHandle
Definition: vae.hpp:38
constexpr ListenerHandle InvalidListenerHandle
Definition: vae.hpp:59
GenericHandle EventHandle
The handle used to address events within a bank.
Definition: vae.hpp:41
Result
Return Types for most engine functions.
Definition: vae.hpp:73
@ FileOpenError
File system could not load file.
@ BankFormatError
Generic bank loading error.
@ TooManyRecords
Can't fit all data in fixed size array.
@ InvalidBank
Valid bank handle needed.
@ InvalidEmitter
Emitter probably wasn't registered.
@ VoiceStarvation
Could not play sound because of voice limit.
@ ValidHandleRequired
Handle provided wasn't valid but needs to be.
@ ElementNotFound
Referenced data not found.
@ GenericFailure
:(
@ BankFormatDuplicateIndex
A index is used muktiple times.
@ BankFormatBadMixHirarchy
A mixer can only write to mixers with lower ids than themselves (no recursion)
@ DuplicateEmitter
Trying to register emitter twice.
@ DeviceError
Can't open audio device.
@ BankFormatIndexError
A index is out of bounds.
constexpr BankHandle InvalidBankHandle
Definition: vae.hpp:57
constexpr GlobalEventHandle InvalidGlobalEventHandle
Definition: vae.hpp:63
LogLevel
Definition: vae.hpp:91
GenericHandle GlobalMixerHandle
TODO.
Definition: vae.hpp:48
GenericHandle SourceHandle
Definition: vae.hpp:42
void(*)(const EventCallbackData *) EventCallback
Definition: vae.hpp:151
constexpr MixerHandle InvalidMixerHandle
Definition: vae.hpp:58
LargeHandle GlobalEventHandle
Used to globally address events, holds space for BankHandle and EventHandle.
Definition: vae.hpp:47
Contains generated Event ids using generate_bank_defines.py.
Definition: vae_def.hpp:4
Basic struct describing a audio device.
Definition: vae.hpp:102
unsigned int sampleRate
TODO not used?
Definition: vae.hpp:104
unsigned char channelsIn
Definition: vae.hpp:108
unsigned int bufferSize
desired bufferSize
Definition: vae.hpp:107
unsigned char channelsOut
Definition: vae.hpp:109
char name[255]
Device name reported from backend.
Definition: vae.hpp:105
int id
Negative values for invalid device.
Definition: vae.hpp:103
char api[4]
API abbreviation.
Definition: vae.hpp:106
Settings for the engine defined at EnginePimpl::init.
Definition: vae.hpp:157
Size finishedVoiceQueueSize
Size of the voice queue for finished voices which need to trigger other events on_end when updating t...
Definition: vae.hpp:223
Size voices
Hard limit on concurrent voices, can't be 0 or lower than hrtfVoices.
Definition: vae.hpp:203
Size preferredBufferSize
Buffer size that will be requested from device.
Definition: vae.hpp:233
void * eventCallbackContext
Custom data that can be accached to the EventCallback to maintain context.
Definition: vae.hpp:180
const char * rootPath
Path where the bank files are located, needs to end with a trailing /.
Definition: vae.hpp:161
bool updateInAudioThread
If this is true update() does not need to be called on the engine instance.
Definition: vae.hpp:248
EventCallback eventCallback
Each time a event of the type emit gets triggered Used to get information about ending sounds and sim...
Definition: vae.hpp:174
Size hrtfVoices
Amount of HRTF panned voices audible at any given time.
Definition: vae.hpp:209
Size preAllocatedEmitters
How many emitters to allocate upfront.
Definition: vae.hpp:194
bool processInBufferSwitch
If enabled, all processing and mixing will happen in the audio callback.
Definition: vae.hpp:256
static constexpr Size _preAllocatedEmitters
Definition: vae.hpp:182
Size virtualVoices
Hard limit on virtal voices.
Definition: vae.hpp:216
Size internalSampleRate
Samplerate requested from device.
Definition: vae.hpp:168
Size bufferPeriods
Number of blocks/buffers to processed ahead.
Definition: vae.hpp:240
Struct containing relevant data passed to EventCallback provided in the EngineConfig.
Definition: vae.hpp:144
void * context
Can point to custom context data also provided when setting the callback, ! not context based on even...
Definition: vae.hpp:145
EmitterHandle emitter
Which emitter.
Definition: vae.hpp:148
EventHandle event
Which event.
Definition: vae.hpp:147
BankHandle bank
Which bank the event is from.
Definition: vae.hpp:146
Emitters have a position and direction vector.
Definition: vae.hpp:121
Listener uses additional up vector.
Definition: vae.hpp:133
Vector3 up
Y up.
Definition: vae.hpp:136
Vector3 front
-z front
Definition: vae.hpp:135
Public vae Vector 3 type.
Definition: vae.hpp:115
float y
Definition: vae.hpp:115
float z
Definition: vae.hpp:115
float x
Definition: vae.hpp:115