summaryrefslogtreecommitdiff
path: root/src/mem_audio.c
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2023-08-28 18:57:55 -0700
committerVito Caputo <vcaputo@pengaru.com>2023-11-14 01:20:48 -0800
commitb22df31feeb7e695faabecfd7cc6fdd24609b0e1 (patch)
treeb1c33983aec45ba17de58276d2c3696695e573dd /src/mem_audio.c
parent8245857f9f07043039affd7b92a740e002b1b81b (diff)
til: add preliminary audio backend
This is an early implementation of something resembling an audio backend for rototiller/libtil. The assumption for now is that everything will use signed 16-bit native-endian stereo output @ 44.1khz.
Diffstat (limited to 'src/mem_audio.c')
-rw-r--r--src/mem_audio.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/mem_audio.c b/src/mem_audio.c
new file mode 100644
index 0000000..b8d51df
--- /dev/null
+++ b/src/mem_audio.c
@@ -0,0 +1,143 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "til.h"
+#include "til_audio.h"
+#include "til_audio_context.h"
+#include "til_settings.h"
+#include "til_setup.h"
+
+/* "mem" audio backend */
+
+typedef struct mem_audio_setup_t {
+ til_setup_t til_setup;
+} mem_audio_setup_t;
+
+typedef struct mem_audio_t {
+ til_audio_context_t til_audio_context;
+
+ unsigned n_queued;
+ unsigned n_queued_start_ticks;
+ unsigned paused:1;
+} mem_audio_t;
+
+
+static int mem_audio_init(til_setup_t *setup, til_audio_context_t **res_context);
+static int mem_audio_queue(til_audio_context_t *context, int16_t *frames, int n_frames);;
+static unsigned mem_audio_n_queued(til_audio_context_t *context);
+static void mem_audio_drop(til_audio_context_t *context);
+static void mem_audio_pause(til_audio_context_t *context);
+static void mem_audio_unpause(til_audio_context_t *context);
+static int mem_audio_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup);
+
+
+til_audio_ops_t mem_audio_ops = {
+ .init = mem_audio_init,
+ .drop = mem_audio_drop,
+ .pause = mem_audio_pause,
+ .unpause = mem_audio_unpause,
+ .queue = mem_audio_queue,
+ .n_queued = mem_audio_n_queued,
+ .setup = mem_audio_setup,
+};
+
+
+/* this simulates an audio timer grinding through the queued frames when unpaused,
+ * returns the remaining n_queued (if any) for convenience, but it's also maintained
+ * at c->n_queued.
+ */
+static unsigned mem_refresh_n_queued(mem_audio_t *c)
+{
+ if (!c->paused && c->n_queued) {
+ unsigned now = til_ticks_now();
+ unsigned n_played = ((float)(now - c->n_queued_start_ticks) * 44.1f);
+
+ c->n_queued -= MIN(c->n_queued, n_played);
+ }
+
+ return c->n_queued;
+}
+
+
+static int mem_audio_init(til_setup_t *setup, til_audio_context_t **res_context)
+{
+ mem_audio_t *c;
+
+ assert(setup);
+ assert(res_context);
+
+ c = til_audio_context_new(&mem_audio_ops, sizeof(mem_audio_t), setup);
+ if (!c)
+ return -ENOMEM;
+
+ c->paused = 1;
+ *res_context = &c->til_audio_context;
+
+ return 0;
+}
+
+
+static void mem_audio_drop(til_audio_context_t *context)
+{
+ mem_audio_t *c = (mem_audio_t *)context;
+
+ c->n_queued = 0;
+}
+
+
+static void mem_audio_pause(til_audio_context_t *context)
+{
+ mem_audio_t *c = (mem_audio_t *)context;
+
+ if (!c->paused) {
+ mem_refresh_n_queued(c);
+ c->paused = 1;
+ }
+}
+
+
+static void mem_audio_unpause(til_audio_context_t *context)
+{
+ mem_audio_t *c = (mem_audio_t *)context;
+
+ if (c->paused) {
+ c->paused = 0;
+ c->n_queued_start_ticks = til_ticks_now();
+ }
+}
+
+
+static int mem_audio_queue(til_audio_context_t *context, int16_t *frames, int n_frames)
+{
+ mem_audio_t *c = (mem_audio_t *)context;
+
+ mem_refresh_n_queued(c);
+ c->n_queued += n_frames;
+
+ return 0;
+}
+
+
+static unsigned mem_audio_n_queued(til_audio_context_t *context)
+{
+ mem_audio_t *c = (mem_audio_t *)context;
+
+ return mem_refresh_n_queued(c);
+}
+
+
+static int mem_audio_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup)
+{
+ if (res_setup) {
+ mem_audio_setup_t *setup;
+
+ setup = til_setup_new(settings, sizeof(*setup), NULL, &mem_audio_ops);
+ if (!setup)
+ return -ENOMEM;
+
+ *res_setup = &setup->til_setup;
+ }
+
+ return 0;
+}
© All Rights Reserved