VAE - Virtual Audio Engine 1
Small Data Driven Audio Engine
vae_spatial_manager.hpp
Go to the documentation of this file.
1#ifndef _VAE_SPATIAL_MANAGER
2#define _VAE_SPATIAL_MANAGER
3
4
5
9#include "./vae_util.hpp"
10#include "./vae_types.hpp"
12
13#define VAE_NO_EXCEPT
14#ifdef VAE_NO_EXCEPT
15 #define TSL_NO_EXCEPTIONS
16#endif
17
18
19#ifdef VAE_NO_SIMD
20 #define ROBIN_HOOD_DISABLE_INTRINSICS
21#endif
22
23// TODO get rid of this since it relies on <functional> and <memory> which pull in <stdio.h>
24#include "../../external/headeronly/robin_hood.h"
25
26namespace vae { namespace core {
27
29
30 // We do a little bit of templating
31 template <typename key, class T> using Map =
32 robin_hood::unordered_map<key, T>;
33 // TODO for power of 2 sizes other maps might be faster and need the same amount of ram
34 Map<EmitterHandle, Emitter> mEmitters; // All emitters across banks
35
36 Listeners mListeners; // All Listeners
37 public:
38 Result init(Size emitterCount) {
39 VAE_PROFILER_SCOPE_NAMED("Spatial Init")
40 mEmitters.reserve(emitterCount);
41 return Result::Success;
42 }
43
47 if (mEmitters.contains(e)) {
48 VAE_INFO("Trying to add duplicate emitter %u", e)
50 }
51 Emitter emitter;
52 emitter.bank = InvalidBankHandle;
53 emitter.event = InvalidEventHandle;
54 // TODO VAE_DEBUG when allocation happens and also lock audio thread
55 mEmitters.insert({e, emitter});
57 return Result::Success;
58 }
59
62 EmitterHandle ret = rand();
63 while (hasEmitter(ret)) {
64 ret = rand();
65 }
66 auto result = addEmitter(ret);
67 return result == Result::Success ? ret : InvalidEmitterHandle;
68 }
69
71 BankHandle bank, EventHandle event, float maxDist,
72 const LocationDirection& locDir, Sample spread
73 ) {
75 auto handle = createEmitter();
76 auto& e = mEmitters[handle];
77 e.position = { locDir.position.x, locDir.position.y, locDir.position.z };
78 e.spread = spread;
79 e.maxDist = maxDist;
80 e.bank = bank;
81 e.event = event;
82 return handle;
83 }
84
87 auto res = mEmitters.erase(e);
88 if (res == 1) {
90 return Result::Success;
91 }
93 }
94
97 return mEmitters[e];
98 }
99
102 return mEmitters.contains(e);
103 }
104
105 void compact() {
107 // mEmitters.compact();
108 }
109
111 EmitterHandle emitter, const LocationDirection& locDir,
112 Sample spread
113 ) {
115 if (!hasEmitter(emitter)) {
116 VAE_DEBUG("Accessed invalid emitter %i", emitter)
118 }
119 auto& e = getEmitter(emitter);
120 e.position = { locDir.position.x, locDir.position.y, locDir.position.z };
121 e.spread = spread;
122 return Result::Success;
123 }
124
126 return mListeners;
127 }
128
129 template <class Func>
130 Result forListeners(ListenerHandle handle, const Func&& func) {
132 if (handle == AllListeners) {
133 for(ListenerHandle index = 0; index < StaticConfig::MaxListeners; index++) {
134 auto& i = mListeners[index];
135 if (i.id == InvalidListenerHandle) { continue; }
136 Result result = func(i);
137 if (result != Result::Success) {
138 return result;
139 }
140 }
141 return Result::Success;
142 }
143 return func(mListeners[handle]);
144 }
145
148 for (ListenerHandle index = 0; index < StaticConfig::MaxListeners; index++) {
149 auto& i = mListeners[index];
150 if (i.id == InvalidListenerHandle) {
151 i.id = index;
152 i.position = { 0.f, 0.f, 0.f };
153 i.front = { 0.f, 0.f, -1.f };
154 i.up = { 0.f, 1.f, 0.f };
155 return index;
156 }
157 }
158 VAE_ERROR("Exeeded maxim amount of listeners define in StaticConfig::MaxListeners")
160 }
161
163 ListenerHandle listener,
164 const LocationOrientation& locOr
165 ) {
167 if (StaticConfig::MaxListeners <= listener) {
168 VAE_WARN("Accessed invalid listener %i", listener)
170 }
171 auto& l = mListeners[listener];
172 if (l.id == InvalidBankHandle) {
174 }
175 l.position = { locOr.position.x, locOr.position.y, locOr.position.z };
176 l.front = { locOr.front.x, locOr.front.y, locOr.front.z };
177 l.up = { locOr.up.x, locOr.up.y, locOr.up.z };
178 return Result::Success;
179 }
180
183 if (StaticConfig::MaxListeners <= listener) {
184 VAE_WARN("Accessed invalid listener %i", listener)
186 }
187 mListeners[listener].id = InvalidListenerHandle;
188 return Result::Success;
189 }
190
191 template <class Callback>
192 void update(VoiceManger& manager, Callback callback) {
193 VAE_PROFILER_SCOPE_NAMED("Spatial Update")
194
195 // TODO perf maybe swap loops
196 // This triggers nearby auto emitters
198 for (auto& emitter : mEmitters) {
199 auto& e = emitter.second;
200 // TODO seperate auto emitter somehow
201 if (e.bank == InvalidBankHandle) { continue; } // means it wants to auto emit
202 if (e.autoplaying) { continue; }
203 // only trigger sounds which haven't been auto triggered
204 const auto distance = glm::distance(l.position, e.position);
205 if (distance < e.maxDist) {
206 mEmitters[emitter.first].autoplaying = true;
207 callback(e.event, e.bank, emitter.first);
208 }
209 }
210 return Result::Success;
211 });
212 }
213 };
214
216
217} } // vae::core
218
219#endif // _VAE_SPATIAL_MANAGER
Result addEmitter(EmitterHandle e)
Result setListener(ListenerHandle listener, const LocationOrientation &locOr)
EmitterHandle createAutoEmitter(BankHandle bank, EventHandle event, float maxDist, const LocationDirection &locDir, Sample spread)
bool hasEmitter(EmitterHandle e)
robin_hood::unordered_map< key, T > Map
Result removeListener(ListenerHandle listener)
Result setEmitter(EmitterHandle emitter, const LocationDirection &locDir, Sample spread)
Result removeEmitter(EmitterHandle e)
Result forListeners(ListenerHandle handle, const Func &&func)
Map< EmitterHandle, Emitter > mEmitters
void update(VoiceManger &manager, Callback callback)
Emitter & getEmitter(EmitterHandle e)
Result init(Size emitterCount)
There is only one voice pool and VAE and it's managed here.
constexpr Size MaxListeners
How many listeners can observe 3D voices.
Definition: vae.hpp:288
const char *const emitters
constexpr int _VAE_SIZE_SPATIAL_MANAGER
Listener[StaticConfig::MaxListeners] Listeners
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
float Sample
Default sample types used where ever possible, changing this means the engine needs to be recompiled,...
Definition: vae.hpp:32
SmallHandle BankHandle
Definition: vae.hpp:40
SmallHandle ListenerHandle
Definition: vae.hpp:45
constexpr EventHandle InvalidEventHandle
Definition: vae.hpp:55
LargeHandle EmitterHandle
Definition: vae.hpp:43
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
@ ValidHandleRequired
Handle provided wasn't valid but needs to be.
@ ElementNotFound
Referenced data not found.
@ DuplicateEmitter
Trying to register emitter twice.
constexpr BankHandle InvalidBankHandle
Definition: vae.hpp:57
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
float y
Definition: vae.hpp:115
float z
Definition: vae.hpp:115
float x
Definition: vae.hpp:115
Allows placement of a Sound in 3D.
Definition: vae_emitter.hpp:10
BankHandle bank
Needed to identify event.
Definition: vae_emitter.hpp:15
EventHandle event
Will be triggerd.
Definition: vae_emitter.hpp:14
#define VAE_ERROR(msg,...)
Definition: vae_logger.hpp:80
#define VAE_WARN(msg,...)
Definition: vae_logger.hpp:85
#define VAE_INFO(msg,...)
Definition: vae_logger.hpp:84
#define VAE_DEBUG(msg,...)
Definition: vae_logger.hpp:83
#define VAE_PROFILER_SCOPE_NAMED(name)
Profiles a scope and names it.
#define VAE_PROFILER_SCOPE()
Profiles a scope.
#define VAE_PROFILER_PLOT(name, value)
Records a value.
Internal types used across VAE.
#define VAE_ASSERT(condition)
Definition: vae_util.hpp:11
Holds all voices and starts/stops them.