6#include <brenta/drivers/miniaudio.hpp>
7#include <brenta/logger.hpp>
15std::expected<void, std::string> MiniaudioDriver::initialize()
18 result = ma_engine_init(NULL, &this->engine);
19 if (result != MA_SUCCESS)
21 ERROR(
"Miniaudio: error initializing miniaudio driver: {}",
22 ma_result_description(result));
23 return std::unexpected(
"Initializing miniaudio driver");
26 for (
int i = 0; i < BRENTA_NUM_STREAMS; ++i)
28 this->stream_pool[i].in_use =
false;
29 this->stream_pool[i].generation = -1;
30 this->stream_pool[i].sound_index = -1;
33 INFO(
"Miniaudio: driver initialized");
37std::expected<void, std::string> MiniaudioDriver::terminate()
39 ma_engine_uninit(&this->engine);
42 for (
int i = 0; i < BRENTA_NUM_STREAMS; ++i)
44 auto& slot = this->stream_pool[i];
47 ma_sound_uninit(&slot.handle);
48 ma_audio_buffer_uninit(&slot.local_buffer);
54 for (
auto& asset : this->sound_assets)
58 ma_audio_buffer_uninit(&asset.buffer);
63 this->sound_assets.clear();
65 INFO(
"Miniaudio: driver terminated safely");
73std::optional<MiniaudioDriver::MiniaudioStream> MiniaudioDriver::create_stream()
75 MiniaudioStream stream_handle;
76 ma_result res = ma_sound_init_ex(&this->engine, NULL, &stream_handle);
77 if (res != MA_SUCCESS)
79 ERROR(
"Miniaudio: error creating audio stream");
87MiniaudioDriver::request_stream(
const SoundAsset& sound)
89 for (
int i = 0; i < BRENTA_NUM_STREAMS; ++i)
91 if (!this->stream_pool[i].in_use)
93 auto& slot = this->stream_pool[i];
94 auto& asset = this->sound_assets[sound.get_id()];
100 ma_uint32 sampleRate;
101 ma_data_source_get_data_format(&asset.buffer, &format, &channels, &sampleRate, NULL, 0);
103 ma_uint64 frameCount;
104 ma_data_source_get_length_in_pcm_frames(&asset.buffer, &frameCount);
106 void* pData =
const_cast<void*
>(asset.buffer.ref.pData);
109 ma_audio_buffer_config config =
110 ma_audio_buffer_config_init(format,
115 config.sampleRate = sampleRate;
117 ma_result res = ma_audio_buffer_init(&config, &slot.local_buffer);
118 if (res != MA_SUCCESS)
120 ma_audio_buffer_uninit(&slot.local_buffer);
121 ERROR(
"Miniaudio: Failed to create local buffer in sound {}",
127 res = ma_sound_init_from_data_source(&this->engine,
132 if (res != MA_SUCCESS)
134 ma_audio_buffer_uninit(&slot.local_buffer);
135 ERROR(
"Miniaudio: Failed to bind sound {} to stream {}",
140 DEBUG(
"Miniaudio: Binded sound {} to stream {}",
144 this->stream_pool[i].in_use =
true;
145 this->stream_pool[i].sound_index = sound.get_id();
146 this->stream_pool[i].generation = asset.generation;
153void MiniaudioDriver::release_stream(Stream stream)
155 auto& slot = this->stream_pool[stream];
160 ma_sound_stop(&slot.handle);
161 ma_sound_uninit(&slot.handle);
162 ma_audio_buffer_uninit(&slot.local_buffer);
165 slot.sound_index = -1;
168 DEBUG(
"Miniaudio: unbinded stream {}", stream);
171std::optional<SoundAsset>
172MiniaudioDriver::load(
const std::filesystem::path& path)
177 for (
unsigned int i = 0; i < this->sound_assets.size(); ++i)
179 if (!this->sound_assets[i].in_use)
188 slot_index = sound_assets.size();
189 this->sound_assets.emplace_back();
192 auto& sound_slot = this->sound_assets[slot_index];
194 ma_decoder tmp_decoder;
196 ma_decoder_init_file(path.string().c_str(),
199 if (res != MA_SUCCESS)
201 ERROR(
"Miniaudio: error loading sound decoder from path {}",
206 ma_uint64 total_frames;
207 ma_decoder_get_length_in_pcm_frames(&tmp_decoder, &total_frames);
209 size_t bufferSize = total_frames * tmp_decoder.outputChannels
210 * ma_get_bytes_per_sample(tmp_decoder.outputFormat);
211 void* pRawData = malloc(bufferSize);
213 ma_uint64 frames_read;
214 ma_decoder_read_pcm_frames(&tmp_decoder, pRawData, total_frames, &frames_read);
216 ma_audio_buffer_config config =
217 ma_audio_buffer_config_init(tmp_decoder.outputFormat,
218 tmp_decoder.outputChannels,
223 ma_audio_buffer_init_copy(&config, &sound_slot.buffer);
224 if (res != MA_SUCCESS)
226 ERROR(
"Miniaudio: error loading sound buffer from path {}",
232 ma_decoder_uninit(&tmp_decoder);
234 sound_slot.in_use =
true;
235 sound_slot.generation++;
237 INFO(
"Miniaudio: loaded sound {} from {}",
238 slot_index, path.string());
243void MiniaudioDriver::unload(
const SoundAsset& sound)
245 auto id = sound.get_id();
247 if (id < 0 || !this->sound_assets[
id].in_use)
250 auto& asset_slot = this->sound_assets[id];
253 for (
int i = 0; i < BRENTA_NUM_STREAMS; ++i)
255 auto& stream = this->stream_pool[i];
257 if (stream.in_use && stream.sound_index ==
id)
259 this->release_stream(i);
260 DEBUG(
"Miniaudio: Force-released stream {} because asset {} was unloaded", i,
id);
264 ma_audio_buffer_uninit(&asset_slot.buffer);
266 asset_slot.in_use =
false;
267 asset_slot.generation++;
271void MiniaudioDriver::play(Stream stream)
273 auto& stream_slot = this->stream_pool[stream];
274 if (!stream_slot.in_use)
276 ERROR(
"Miniaudio: play: cannot use stream {}", stream);
279 if (stream_slot.generation
280 != this->sound_assets[stream_slot.sound_index].generation)
282 ERROR(
"Miniaudio: play: stream {} does not match driver's stream", stream);
286 ma_sound_start(&stream_slot.handle);
288 INFO(
"Miniaudio: started playing on stream {}", stream);
292void MiniaudioDriver::stop(Stream stream)
294 auto& stream_slot = this->stream_pool[stream];
295 if (!stream_slot.in_use)
297 ERROR(
"Miniaudio: stop: cannot use stream {}", stream);
300 if (stream_slot.generation
301 != this->sound_assets[stream_slot.sound_index].generation)
303 ERROR(
"Miniaudio: stop: stream {} does not match driver's stream", stream);
307 ma_sound_stop(&stream_slot.handle);
309 INFO(
"Miniaudio: stopped stream {}", stream);
313void MiniaudioDriver::set_volume(Stream stream,
float volume)
315 auto& stream_slot = this->stream_pool[stream];
316 if (!stream_slot.in_use)
318 ERROR(
"Miniaudio: stop: cannot use stream {}", stream);
321 if (stream_slot.generation
322 != this->sound_assets[stream_slot.sound_index].generation)
324 ERROR(
"Miniaudio: stop: stream {} does not match driver's stream", stream);
328 ma_sound_set_volume(&stream_slot.handle, volume);
330 INFO(
"Miniaudio: volume for stream {} set to {}", stream, volume);