forked from KhronosGroup/Vulkan-Tutorial
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathaudio_system.h
More file actions
410 lines (349 loc) · 12.5 KB
/
audio_system.h
File metadata and controls
410 lines (349 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <queue>
#include <vulkan/vulkan_raii.hpp>
#include <vulkan/vk_platform.h>
#include <stdexcept>
/**
* @brief Class representing an audio source.
*/
class AudioSource {
public:
/**
* @brief Default constructor.
*/
AudioSource() = default;
/**
* @brief Destructor for proper cleanup.
*/
virtual ~AudioSource() = default;
/**
* @brief Play the audio source.
*/
virtual void Play() = 0;
/**
* @brief Pause the audio source.
*/
virtual void Pause() = 0;
/**
* @brief Stop the audio source.
*/
virtual void Stop() = 0;
/**
* @brief Set the volume of the audio source.
* @param volume The volume (0.0f to 1.0f).
*/
virtual void SetVolume(float volume) = 0;
/**
* @brief Set whether the audio source should loop.
* @param loop Whether to loop.
*/
virtual void SetLoop(bool loop) = 0;
/**
* @brief Set the position of the audio source in 3D space.
* @param x The x-coordinate.
* @param y The y-coordinate.
* @param z The z-coordinate.
*/
virtual void SetPosition(float x, float y, float z) = 0;
/**
* @brief Set the velocity of the audio source in 3D space.
* @param x The x-component.
* @param y The y-component.
* @param z The z-component.
*/
virtual void SetVelocity(float x, float y, float z) = 0;
/**
* @brief Check if the audio source is playing.
* @return True if playing, false otherwise.
*/
virtual bool IsPlaying() const = 0;
};
// Forward declarations
class Renderer;
class Engine;
/**
* @brief Interface for audio output devices.
*/
class AudioOutputDevice {
public:
/**
* @brief Default constructor.
*/
AudioOutputDevice() = default;
/**
* @brief Virtual destructor for proper cleanup.
*/
virtual ~AudioOutputDevice() = default;
/**
* @brief Initialize the audio output device.
* @param sampleRate The sample rate (e.g., 44100).
* @param channels The number of channels (typically 2 for stereo).
* @param bufferSize The buffer size in samples.
* @return True if initialization was successful, false otherwise.
*/
virtual bool Initialize(uint32_t sampleRate, uint32_t channels, uint32_t bufferSize) = 0;
/**
* @brief Start audio playback.
* @return True if successful, false otherwise.
*/
virtual bool Start() = 0;
/**
* @brief Stop audio playback.
* @return True if successful, false otherwise.
*/
virtual bool Stop() = 0;
/**
* @brief Write audio data to the output device.
* @param data Pointer to the audio data (interleaved stereo float samples).
* @param sampleCount Number of samples per channel to write.
* @return True if successful, false otherwise.
*/
virtual bool WriteAudio(const float* data, uint32_t sampleCount) = 0;
/**
* @brief Check if the device is currently playing.
* @return True if playing, false otherwise.
*/
virtual bool IsPlaying() const = 0;
/**
* @brief Get the current playback position in samples.
* @return Current position in samples.
*/
virtual uint32_t GetPosition() const = 0;
};
/**
* @brief Class for managing audio.
*/
class AudioSystem {
public:
/**
* @brief Default constructor.
*/
AudioSystem() = default;
// Constructor-based initialization to replace separate Initialize() calls
AudioSystem(Engine* engine, Renderer* renderer) {
if (!Initialize(engine, renderer)) {
throw std::runtime_error("AudioSystem: initialization failed");
}
}
/**
* @brief Flush audio output: clears pending processing and device buffers so playback restarts cleanly.
*/
void FlushOutput();
/**
* @brief Destructor for proper cleanup.
*/
~AudioSystem();
/**
* @brief Initialize the audio system.
* @param engine Pointer to the engine for accessing active camera.
* @param renderer Pointer to the renderer for compute shader support.
* @return True if initialization was successful, false otherwise.
*/
bool Initialize(Engine* engine, Renderer* renderer = nullptr);
/**
* @brief Update the audio system.
* @param deltaTime The time elapsed since the last update.
*/
void Update(std::chrono::milliseconds deltaTime);
/**
* @brief Load an audio file.
* @param filename The path to the audio file.
* @param name The name to assign to the audio.
* @return True if loading was successful, false otherwise.
*/
bool LoadAudio(const std::string& filename, const std::string& name);
/**
* @brief Create an audio source.
* @param name The name of the audio to use.
* @return Pointer to the created audio source, or nullptr if creation failed.
*/
AudioSource* CreateAudioSource(const std::string& name);
/**
* @brief Create a sine wave ping audio source for debugging.
* @param name The name to assign to the debug audio source.
* @return Pointer to the created audio source, or nullptr if creation failed.
*/
AudioSource* CreateDebugPingSource(const std::string& name);
/**
* @brief Set the listener position in 3D space.
* @param x The x-coordinate.
* @param y The y-coordinate.
* @param z The z-coordinate.
*/
void SetListenerPosition(float x, float y, float z);
/**
* @brief Set the listener orientation in 3D space.
* @param forwardX The x-component of the forward vector.
* @param forwardY The y-component of the forward vector.
* @param forwardZ The z-component of the forward vector.
* @param upX The x-component of the up vector.
* @param upY The y-component of the up vector.
* @param upZ The z-component of the up vector.
*/
void SetListenerOrientation(float forwardX, float forwardY, float forwardZ,
float upX, float upY, float upZ);
/**
* @brief Set the listener velocity in 3D space.
* @param x The x-component.
* @param y The y-component.
* @param z The z-component.
*/
void SetListenerVelocity(float x, float y, float z);
/**
* @brief Set the master volume.
* @param volume The volume (0.0f to 1.0f).
*/
void SetMasterVolume(float volume);
/**
* @brief Enable HRTF (Head-Related Transfer Function) processing.
* @param enable Whether to enable HRTF processing.
*/
void EnableHRTF(bool enable);
/**
* @brief Check if HRTF processing is enabled.
* @return True if HRTF processing is enabled, false otherwise.
*/
bool IsHRTFEnabled() const;
/**
* @brief Set whether to force CPU-only HRTF processing.
* @param cpuOnly Whether to force CPU-only processing (true) or allow Vulkan shader processing (false).
*/
void SetHRTFCPUOnly(bool cpuOnly);
/**
* @brief Check if HRTF processing is set to CPU-only mode.
* @return True if CPU-only mode is enabled, false if Vulkan shader processing is allowed.
*/
bool IsHRTFCPUOnly() const;
/**
* @brief Load HRTF data from a file.
* @param filename The path to the HRTF data file.
* @return True if loading was successful, false otherwise.
*/
bool LoadHRTFData(const std::string& filename);
/**
* @brief Process audio data with HRTF.
* @param inputBuffer The input audio buffer.
* @param outputBuffer The output audio buffer.
* @param sampleCount The number of samples to process.
* @param sourcePosition The position of the sound source.
* @return True if processing was successful, false otherwise.
*/
bool ProcessHRTF(const float* inputBuffer, float* outputBuffer, uint32_t sampleCount, const float* sourcePosition);
/**
* @brief Generate a sine wave ping for debugging purposes.
* @param buffer The output buffer to fill with ping audio data.
* @param sampleCount The number of samples to generate.
* @param playbackPosition The current playback position for timing.
*/
static void GenerateSineWavePing(float* buffer, uint32_t sampleCount, uint32_t playbackPosition);
private:
// Loaded audio data
std::unordered_map<std::string, std::vector<uint8_t>> audioData;
// Audio sources
std::vector<std::unique_ptr<AudioSource>> sources;
// Listener properties
float listenerPosition[3] = {0.0f, 0.0f, 0.0f};
float listenerOrientation[6] = {0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f};
float listenerVelocity[3] = {0.0f, 0.0f, 0.0f};
// Master volume
float masterVolume = 1.0f;
// Whether the audio system is initialized
bool initialized = false;
// HRTF processing
bool hrtfEnabled = false;
bool hrtfCPUOnly = false;
std::vector<float> hrtfData;
uint32_t hrtfSize = 0;
uint32_t numHrtfPositions = 0;
// Renderer for compute shader support
Renderer* renderer = nullptr;
// Engine reference for accessing active camera
Engine* engine = nullptr;
// Audio output device for sending processed audio to speakers
std::unique_ptr<AudioOutputDevice> outputDevice = nullptr;
// Threading infrastructure for background audio processing
std::thread audioThread;
std::mutex audioMutex;
std::condition_variable audioCondition;
std::atomic<bool> audioThreadRunning{false};
std::atomic<bool> audioThreadShouldStop{false};
// Audio processing task queue
struct AudioTask {
std::vector<float> inputBuffer;
std::vector<float> outputBuffer;
float sourcePosition[3];
uint32_t sampleCount; // total frames in input/output (may include history)
uint32_t actualSamplesProcessed; // frames to write this tick (new part)
uint32_t trimFront; // frames to skip from output front (history length)
AudioOutputDevice* outputDevice;
float masterVolume;
};
// Set up HRTF parameters
struct HRTFParams {
float sourcePosition[3];
float listenerPosition[3];
float listenerOrientation[6]; // Forward (3) and up (3) vectors
uint32_t sampleCount;
uint32_t hrtfSize;
uint32_t numHrtfPositions;
float padding; // For alignment
} params;
std::queue<std::shared_ptr<AudioTask>> audioTaskQueue;
std::mutex taskQueueMutex;
// Vulkan resources for HRTF processing
vk::raii::Buffer inputBuffer = nullptr;
vk::raii::DeviceMemory inputBufferMemory = nullptr;
vk::raii::Buffer outputBuffer = nullptr;
vk::raii::DeviceMemory outputBufferMemory = nullptr;
vk::raii::Buffer hrtfBuffer = nullptr;
vk::raii::DeviceMemory hrtfBufferMemory = nullptr;
vk::raii::Buffer paramsBuffer = nullptr;
vk::raii::DeviceMemory paramsBufferMemory = nullptr;
// Persistent memory mapping for UBO to avoid repeated map/unmap operations
void* persistentParamsMemory = nullptr;
uint32_t currentSampleCount = 0; // Track current buffer size to avoid unnecessary recreation
/**
* @brief Create buffers for HRTF processing.
* @param sampleCount The number of samples to process.
* @return True if creation was successful, false otherwise.
*/
bool createHRTFBuffers(uint32_t sampleCount);
/**
* @brief Clean up HRTF buffers.
*/
void cleanupHRTFBuffers();
/**
* @brief Start the background audio processing thread.
*/
void startAudioThread();
/**
* @brief Stop the background audio processing thread.
*/
void stopAudioThread();
/**
* @brief Main loop for the background audio processing thread.
*/
void audioThreadLoop();
/**
* @brief Process an audio task in the background thread.
* @param task The audio task to process.
*/
void processAudioTask(const std::shared_ptr<AudioTask>& task);
/**
* @brief Submit an audio processing task to the background thread.
* @param inputBuffer The input audio buffer.
* @param sampleCount The number of samples to process.
* @param sourcePosition The position of the sound source.
* @param actualSamplesProcessed The number of samples actually processed.
* @return True if the task was submitted successfully, false otherwise.
*/
bool submitAudioTask(const float* inputBuffer, uint32_t sampleCount, const float* sourcePosition, uint32_t actualSamplesProcessed, uint32_t trimFront);
};