#define PKE_AUDIO_IMPL_PIPEWIRE #include "asset-manager.hpp" #include "audio-impl-pw.hpp" #include "audio.hpp" #include "pk.h" struct pke_audio_master pke_audio_mstr{}; void pke_audio_init() { pke_audio_mstr.master_volume = 1.f; pke_audio_mstr.channel_count = 2; pke_audio_mstr.bkt_transient = pk_mem_bucket_create("pke_audio", PK_MEM_DEFAULT_BUCKET_SIZE, PK_MEMBUCKET_FLAG_TRANSIENT); for (uint8_t i = 0; i < pke_audio_mstr.channel_count; ++i) { pke_audio_mstr.source_volumes[i] = 1.f; } #ifdef PKE_AUDIO_IMPL_PIPEWIRE pke_audio_pw_init(); #endif } void pke_audio_teardown() { #ifdef PKE_AUDIO_IMPL_PIPEWIRE pke_audio_pw_teardown(); #endif pk_mem_bucket_destroy(pke_audio_mstr.bkt_transient); } void pke_audio_tick(double delta) { (void)delta; #ifdef PKE_AUDIO_IMPL_PIPEWIRE if (pke_audio_pw.is_needing_output_remapped == true) { pke_audio_pw_remap_outputs(); } #endif } float pke_audio_get_volume(pke_audio_source source) { return pke_audio_mstr.source_volumes[static_cast(source)]; } void pke_audio_set_volume(pke_audio_source source, float volume) { pke_audio_mstr.source_volumes[static_cast(source)] = volume; } bool pke_audio_playing_objects_find_first_by_key(void *user_data, void *arr_data) { std::tuple &tup = *reinterpret_cast*>(user_data); pke_audio_obj &audio_obj = *reinterpret_cast(arr_data); return std::get<0>(tup) == audio_obj.handle && std::get<1>(tup) == audio_obj.source; } void pke_audio_play(AssetHandle handle, pke_audio_source audio_source, glm::vec3 position_source, pke_audio_flags flags) { // TODO validation: audio length (does it fit in uint32_t), etc // TODO rethink threading: first-pass only mutex std::tuple tup {handle, audio_source}; pke_audio_mstr.mtx_buffer.lock(); uint32_t idx = pk_arr_find_first_index(&pke_audio_mstr.playing_objects, &tup, pke_audio_playing_objects_find_first_by_key); pke_audio_obj *aobj = NULL; if (idx == uint32_t(-1)) { AM_Get(handle); // keep the asset in memory, freed when play_count hits 0 pk_arr_append_t(&pke_audio_mstr.playing_objects, {}); aobj = &pke_audio_mstr.playing_objects[pke_audio_mstr.playing_objects.next-1]; memset(aobj, 0, sizeof(pke_audio_obj)); aobj->handle = handle; aobj->source = audio_source; aobj->play_count = 1; idx = 0; } else { aobj = &pke_audio_mstr.playing_objects[idx]; idx = aobj->play_count; aobj->play_count += 1; } aobj->position_source[idx] = position_source; aobj->flags[idx] = flags; aobj->play_heads[idx] = 0; pke_audio_mstr.mtx_buffer.unlock(); } void pke_audio_stop_all() { // TODO fade-out instead of hard-cut? Maybe that should be a separate function. uint32_t i; pke_audio_mstr.mtx_buffer.lock(); for (i = 0; i < pke_audio_mstr.playing_objects.next; ++i) { AM_Release(pke_audio_mstr.playing_objects[i].handle); } pk_arr_clear(&pke_audio_mstr.playing_objects); pke_audio_mstr.mtx_buffer.unlock(); }