From 48a0cd1377d2216f79468322c2b7c956d216674c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9l=C3=A8ne=20Corbineau?= Date: Thu, 16 Jan 2025 23:35:35 +0100 Subject: [PATCH] Basic whitenoise generator --- pw_plugin/Makefile | 2 +- pw_plugin/main.c | 12 ------ pw_plugin/main.cc | 92 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 13 deletions(-) delete mode 100644 pw_plugin/main.c create mode 100644 pw_plugin/main.cc diff --git a/pw_plugin/Makefile b/pw_plugin/Makefile index 9e010c2..3207131 100644 --- a/pw_plugin/Makefile +++ b/pw_plugin/Makefile @@ -2,4 +2,4 @@ build: main.out main.out: main.o - $(CC) $(LDFLAGS) $^ -o $@ + $(CXX) $(LDFLAGS) $^ -o $@ diff --git a/pw_plugin/main.c b/pw_plugin/main.c deleted file mode 100644 index 60f5de2..0000000 --- a/pw_plugin/main.c +++ /dev/null @@ -1,12 +0,0 @@ -#include - -int main(int argc, char *argv[]) -{ - pw_init(&argc, &argv); - - fprintf(stdout, "Compiled with libpipewire %s\n" - "Linked with libpipewire %s\n", - pw_get_headers_version(), - pw_get_library_version()); - return 0; -} diff --git a/pw_plugin/main.cc b/pw_plugin/main.cc new file mode 100644 index 0000000..dbf2369 --- /dev/null +++ b/pw_plugin/main.cc @@ -0,0 +1,92 @@ +#include +#include +#include "pipewire/pipewire.h" +#include "spa/param/audio/format-utils.h" + +struct local_data { + pw_main_loop* loop; + pw_stream* stream; + + std::mt19937 gen; + std::normal_distribution nd{0, 0.3}; +}; + +void on_process(local_data* ld) { + pw_buffer *b; + spa_buffer *buf; + if((b = pw_stream_dequeue_buffer(ld->stream)) == NULL) { + pw_log_warn("No buffers left!"); + return; + } + + buf = b->buffer; + + float* dst; + if((dst = (float*)buf->datas[0].data) == NULL) { + return; + } + + int n_frames = buf->datas[0].maxsize / sizeof(float); + if(b->requested) { + n_frames = SPA_MIN(b->requested, n_frames); + } + + for(int i = 0; i < n_frames; ++i) { + *dst++ = ld->nd(ld->gen); + } + + buf->datas[0].chunk->offset = 0; + buf->datas[0].chunk->stride = sizeof(float); + buf->datas[0].chunk->size = n_frames * sizeof(float); + + pw_stream_queue_buffer(ld->stream, b); +} + +const struct pw_stream_events stream_events { + PW_VERSION_STREAM_EVENTS, + .process = (void(*)(void*))on_process, +}; + +int main(int argc, char** argv) { + // We do NOT seed the MT engine -> the time series will be predictable! + local_data bookkeep{nullptr,nullptr,}; + + pw_init(&argc, &argv); + bookkeep.loop = pw_main_loop_new(NULL); + + bookkeep.stream = pw_stream_new_simple( + pw_main_loop_get_loop(bookkeep.loop), + "audio-src", + pw_properties_new( + PW_KEY_MEDIA_TYPE, "Audio", + PW_KEY_MEDIA_CATEGORY, "Playback", + PW_KEY_MEDIA_ROLE, "Test", + NULL), + &stream_events, + &bookkeep); + + const spa_pod* params[1]; + uint8_t buffer[1024]; + spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); + + auto audio_info = SPA_AUDIO_INFO_RAW_INIT( + .format = SPA_AUDIO_FORMAT_F32_LE, + .rate = 44100, + .channels = 1,); + + params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat,&audio_info); + + pw_stream_connect(bookkeep.stream, + PW_DIRECTION_OUTPUT, + PW_ID_ANY, + (pw_stream_flags)(PW_STREAM_FLAG_AUTOCONNECT | + PW_STREAM_FLAG_MAP_BUFFERS | + PW_STREAM_FLAG_RT_PROCESS), + params, 1); + + pw_main_loop_run(bookkeep.loop); + + pw_stream_destroy(bookkeep.stream); + pw_main_loop_destroy(bookkeep.loop); + return 0; +}