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
|
#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<pke_audio_source_T>(source)];
}
void pke_audio_set_volume(pke_audio_source source, float volume) {
pke_audio_mstr.source_volumes[static_cast<pke_audio_source_T>(source)] = volume;
}
bool pke_audio_playing_objects_find_first_by_key(void *user_data, void *arr_data) {
std::tuple<AssetHandle, pke_audio_source> &tup = *reinterpret_cast<std::tuple<AssetHandle, pke_audio_source>*>(user_data);
pke_audio_obj &audio_obj = *reinterpret_cast<pke_audio_obj*>(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<AssetHandle, pke_audio_source> 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();
}
|