summaryrefslogtreecommitdiff
path: root/src/audio.cpp
blob: 194c01c6b2e899bd631cd085abf5157c598da0ac (plain)
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();
}