summaryrefslogtreecommitdiff
path: root/src/audio-impl-pw.cpp
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-07-11 11:41:21 -0400
committerJonathan Bradley <jcb@pikum.xyz>2025-07-11 11:41:21 -0400
commitf88ca0bc946bae086e02eacdc6c129f00e2e07e3 (patch)
treeeb8975ec505315e7f53a15ded32fb0cfd6b57731 /src/audio-impl-pw.cpp
parent1fd2b900a5f97379e80adc411d3763f9ba811570 (diff)
pke: audio: fx boilerplate, low-pass spatial
Diffstat (limited to 'src/audio-impl-pw.cpp')
-rw-r--r--src/audio-impl-pw.cpp70
1 files changed, 52 insertions, 18 deletions
diff --git a/src/audio-impl-pw.cpp b/src/audio-impl-pw.cpp
index 4f5f4cf..92acd8d 100644
--- a/src/audio-impl-pw.cpp
+++ b/src/audio-impl-pw.cpp
@@ -1,8 +1,10 @@
#include "audio-impl-pw.hpp"
+#include "audio-impl-shared.hpp"
#include "asset-manager.hpp"
#include "audio-types.hpp"
#include "game-settings.hpp"
+#include "math-helpers.hpp"
#include "pipewire/keys.h"
#include "pipewire/thread-loop.h"
#include "pk.h"
@@ -276,13 +278,16 @@ void on_pipewire_process(void *user_data) {
int stride;
uint8_t pc, pc2;
uint32_t i, ii, c;
- uint64_t n_frames, i_frame;
+ int64_t n_frames, i_frame;
float *dst;
float val, vol, vol2;
float *spatial_volumes = nullptr;
glm::vec3 listener_origin;
glm::vec3 audio_dir = glm::vec3(0);
glm::vec3 *spatial_normals = nullptr;
+ pke_audio_fx_params_reverb *params_reverb;
+ pke_audio_fx_params_delay *params_delay;
+ pke_audio_fx_params_low_pass_filter *params_low_pass_filter;
pk_mem_bucket_reset(pke_audio_mstr.bkt_transient);
if ((b = pw_stream_dequeue_buffer(pke_audio_pw.stream)) == NULL) {
@@ -296,14 +301,11 @@ void on_pipewire_process(void *user_data) {
return;
}
- stride = sizeof(float) * pke_audio_mstr.channel_count;
- n_frames = buf->datas[0].maxsize / stride;
- if (b->requested) {
- n_frames = PK_MIN(b->requested, n_frames);
- }
-
- spatial_volumes = pk_new<float>(pke_audio_mstr.channel_count, pke_audio_mstr.bkt_transient);
- spatial_normals = pk_new<glm::vec3>(pke_audio_mstr.channel_count, pke_audio_mstr.bkt_transient);
+ spatial_volumes = pk_new<float>(pke_audio_mstr.channel_count, pke_audio_mstr.bkt_transient);
+ spatial_normals = pk_new<glm::vec3>(pke_audio_mstr.channel_count, pke_audio_mstr.bkt_transient);
+ params_reverb = pk_new<pke_audio_fx_params_reverb>(pke_audio_mstr.channel_count, pke_audio_mstr.bkt_transient);
+ params_delay = pk_new<pke_audio_fx_params_delay>(pke_audio_mstr.channel_count, pke_audio_mstr.bkt_transient);
+ params_low_pass_filter = pk_new<pke_audio_fx_params_low_pass_filter>(pke_audio_mstr.channel_count, pke_audio_mstr.bkt_transient);
// calculate spatial_normals
// TODO maybe don't use UBO
@@ -314,11 +316,19 @@ void on_pipewire_process(void *user_data) {
switch (c) {
case 0:
// left-speaker
- spatial_normals[c] = glm::normalize(glm::vec3(-1.f, 0.f, 1.f));
+ if (pke_audio_mstr.channel_count > 2) {
+ spatial_normals[c] = glm::normalize(glm::vec3(-1.f, 0.f, 1.f));
+ } else {
+ spatial_normals[c] = glm::normalize(glm::vec3(-1.f, 0.f, 0.f));
+ }
break;
case 1:
// right
- spatial_normals[c] = glm::normalize(glm::vec3( 1.f, 0.f, 1.f));
+ if (pke_audio_mstr.channel_count > 2) {
+ spatial_normals[c] = glm::normalize(glm::vec3( 1.f, 0.f, 1.f));
+ } else {
+ spatial_normals[c] = glm::normalize(glm::vec3( 1.f, 0.f, 0.f));
+ }
break;
case 2:
// center
@@ -350,10 +360,23 @@ void on_pipewire_process(void *user_data) {
}
pke_audio_mstr.mtx_buffer.lock();
+
+ stride = sizeof(float) * pke_audio_mstr.channel_count;
+
+ n_frames = buf->datas[0].maxsize / stride;
+ if (b->requested) {
+ n_frames = PK_MIN((int64_t)b->requested, n_frames);
+ }
+ // fprintf(stdout, "[pw] frame count: %li, requested: %lu\n", n_frames, b->requested);
+
buf->datas[0].chunk->offset = 0;
buf->datas[0].chunk->stride = stride;
buf->datas[0].chunk->size = n_frames * stride;
+ if (buf->datas[0].chunk->size == 0) {
+ goto audio_done;
+ }
+
for (i = 0; i < pke_audio_mstr.playing_objects.next; ++i) {
pke_audio_obj *aobj = &pke_audio_mstr.playing_objects[i];
const Asset *a = AM_Get(aobj->handle);
@@ -381,11 +404,19 @@ void on_pipewire_process(void *user_data) {
break;
}
}
- if (audio_dir != glm::vec3(0)) {
- float dot_dir = glm::dot(spatial_normals[c], audio_dir);
+ float dot_dir = glm::dot(spatial_normals[c], audio_dir);
+ if (!glm::isnan(dot_dir) && dot_dir < 0.0) {
// fprintf(stderr, "[pw] dot: %f\n", dot_dir);
- spatial_volumes[c] = glm::clamp(dot_dir, 0.f, 1.f);
+
+ // 20k max, 500 min
+ params_low_pass_filter[c].cutoff_freq = log_interp(500.f, 20000.f, abs(dot_dir));
+ } else {
+ params_low_pass_filter[c].cutoff_freq = 0.f;
}
+ params_reverb[c].reverb_strength = 0.f; // TODO
+ params_delay[c].delay_frames = 0; // TODO
+ // spatial_volumes[c] = glm::clamp(dot_dir, 0.f, 1.f);
+ spatial_volumes[c] = lerp(0.f, 1.f, dot_dir + 0.85f);
if (isnan(spatial_volumes[c]) || spatial_volumes[c] == 0.0f) {
/*
@@ -430,14 +461,11 @@ void on_pipewire_process(void *user_data) {
vol2 *= (spatial_volumes[c] * distance_volume);
}
if (vol2 <= 0.0) {
- // fprintf(stderr, "[pw] vol2 is <= 0.0\n");
+ // fprintf(stderr, "[pw] chan: %i vol2 is <= 0.0\n", c);
dst += 1;
continue;
}
- val = ((float*)a->ptr)[aobj->play_heads[pc]];
-
- // vol2 = PK_CLAMP(vol2, 0.0, 0.5);
/*
if (isnan(vol2)) {
fprintf(stderr, "[pw] vol2 is NaN\n");
@@ -446,6 +474,11 @@ void on_pipewire_process(void *user_data) {
fprintf(stderr, "[pw] vol2 is 0, %f, %f, %f\n", pke_audio_mstr.master_volume, pke_audio_mstr.source_volumes[c], spatial_volumes[c]);
}
*/
+
+ // val = ((float*)a->ptr)[aobj->play_heads[pc]]; // val is read inside fx_low_pass_filter
+ val = pke_audio_fx_low_pass_filter((float*)a->ptr, a->size / sizeof(float), (uint32_t)aobj->play_heads[pc], &params_low_pass_filter[pc]);
+ val += pke_audio_fx_reverb((float*)a->ptr, a->size / sizeof(float), (uint32_t)aobj->play_heads[pc], &params_reverb[pc]);
+ val += pke_audio_fx_delay((float*)a->ptr, a->size / sizeof(float), (uint32_t)aobj->play_heads[pc], &params_delay[pc]);
*dst += val * vol2;
/*
if (isnan(*dst)) {
@@ -481,6 +514,7 @@ void on_pipewire_process(void *user_data) {
memset(dst, 0, sizeof(float) * n_frames * pke_audio_mstr.channel_count);
}
+audio_done:
pw_stream_queue_buffer(pke_audio_pw.stream, b);
pke_audio_mstr.mtx_buffer.unlock();
return;