From 4be4c6eca7e6eea0aea35aa069b2614000b777f7 Mon Sep 17 00:00:00 2001 From: XANTRONIX Development Date: Mon, 28 Feb 2022 13:15:26 -0500 Subject: Initial stab at script playback --- src/script.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 127 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/script.c b/src/script.c index 8c58f7f..b983577 100644 --- a/src/script.c +++ b/src/script.c @@ -1,6 +1,9 @@ #include #include +#include +#include +#include #include xas_script *xas_script_new(xas_spatial_scene *scene, size_t buffer_size) { @@ -10,13 +13,9 @@ xas_script *xas_script_new(xas_spatial_scene *scene, size_t buffer_size) { goto error_malloc_script; } - script->scene = scene; - script->first = NULL; - - timerclear(&script->timestamp); - - script->buffer_size = buffer_size; - script->current_index = 0; + script->scene = scene; + script->first = NULL; + script->buffer_size = buffer_size; return script; @@ -78,6 +77,7 @@ int xas_script_add_event_off(xas_script *script, } ev->type = XAS_SCRIPT_EVENT_OFF; + ev->objtype = XAS_SCRIPT_OBJECT_ANY; ev->object = object; ev->timestamp = timestamp; ev->next = NULL; @@ -100,6 +100,7 @@ int xas_script_add_event_on(xas_script *script, } ev->type = XAS_SCRIPT_EVENT_ON; + ev->objtype = XAS_SCRIPT_OBJECT_ANY; ev->object = object; ev->timestamp = timestamp; ev->next = NULL; @@ -112,7 +113,7 @@ error_malloc_ev: return -1; } -int xas_script_add_position_set(xas_script *script, +int xas_script_add_set_position(xas_script *script, xas_spatial_object *object, struct timeval timestamp, xas_spatial_coord point) { @@ -123,6 +124,7 @@ int xas_script_add_position_set(xas_script *script, } ev->type = XAS_SCRIPT_EVENT_SET_POSITION; + ev->objtype = XAS_SCRIPT_OBJECT_ANY; ev->object = object; ev->timestamp = timestamp; ev->point = point; @@ -136,7 +138,7 @@ error_malloc_ev: return -1; } -int xas_script_add_gain_set(xas_script *script, +int xas_script_add_set_gain(xas_script *script, xas_spatial_object *object, struct timeval timestamp, float gain) { @@ -147,6 +149,7 @@ int xas_script_add_gain_set(xas_script *script, } ev->type = XAS_SCRIPT_EVENT_ON; + ev->objtype = XAS_SCRIPT_OBJECT_ANY; ev->object = object; ev->timestamp = timestamp; ev->gain = gain; @@ -160,7 +163,7 @@ error_malloc_ev: return -1; } -int xas_script_add_bank_set(xas_script *script, +int xas_script_add_set_bank(xas_script *script, xas_spatial_object *object, struct timeval timestamp, size_t index) { @@ -171,6 +174,7 @@ int xas_script_add_bank_set(xas_script *script, } ev->type = XAS_SCRIPT_EVENT_SET_BANK_INDEX; + ev->objtype = XAS_SCRIPT_OBJECT_BANK_PLAYER; ev->object = object; ev->timestamp = timestamp; ev->next = NULL; @@ -184,7 +188,7 @@ error_malloc_ev: return -1; } -int xas_script_add_frequency_set(xas_script *script, +int xas_script_add_set_frequency(xas_script *script, xas_spatial_object *object, struct timeval timestamp, size_t frequency) { @@ -195,6 +199,7 @@ int xas_script_add_frequency_set(xas_script *script, } ev->type = XAS_SCRIPT_EVENT_SET_FREQUENCY; + ev->objtype = XAS_SCRIPT_OBJECT_SYNTH; ev->object = object; ev->timestamp = timestamp; ev->next = NULL; @@ -208,4 +213,114 @@ error_malloc_ev: return -1; } -int xas_script_play(xas_script *script, xas_audio_stream *sink); +static inline void timerupdate(struct timeval *tv, + suseconds_t interval, + size_t frame) { + struct timeval zero = { 0, 0 }, + timer = { 0, frame * interval }; + + timeradd(&zero, &timer, tv); +} + +static int event_trigger(xas_spatial_scene *scene, xas_script_event *ev) { + switch (ev->type) { + case XAS_SCRIPT_EVENT_OFF: + return xas_spatial_object_stop(ev->object); + + case XAS_SCRIPT_EVENT_ON: + return xas_spatial_object_start(ev->object); + + case XAS_SCRIPT_EVENT_SET_POSITION: + xas_spatial_scene_position_object(scene, + ev->object, + ev->point); + + break; + + case XAS_SCRIPT_EVENT_SET_GAIN: + xas_object_set_gain(ev->object->ctx, ev->gain); + + break; + + case XAS_SCRIPT_EVENT_SET_FREQUENCY: + if (ev->objtype != XAS_SCRIPT_OBJECT_SYNTH) { + goto error_invalid_event; + } + + xas_synth_set_frequency(ev->object->ctx, ev->frequency); + + break; + + case XAS_SCRIPT_EVENT_SET_BANK_INDEX: + if (ev->objtype != XAS_SCRIPT_OBJECT_BANK_PLAYER) { + goto error_invalid_event; + } + + xas_bank_player_set_entry(ev->object->ctx, ev->gain); + + break; + } + + return 0; + +error_invalid_event: + return -1; +} + +int xas_script_play(xas_script *script, xas_audio_stream *sink) { + xas_script_event *ev = script->first; + xas_audio_stream *source; + + size_t frame = 0, + sample_rate = script->scene->format.sample_rate, + buffer_size = script->buffer_size; + + suseconds_t interval = 1000000 / (sample_rate / buffer_size); + + int16_t *samples; + + if ((source = xas_spatial_scene_new_stream(script->scene, + script->buffer_size)) == NULL) { + goto error_spatial_scene_new_stream; + } + + while (ev) { + xas_script_event *next = ev->next; + struct timeval tv; + + ssize_t readlen; + + timerupdate(&tv, interval, frame); + + if (timercmp(&ev->timestamp, &tv, >)) { + if (event_trigger(script->scene, ev) < 0) { + goto error_event_trigger; + } + + ev = next; + } + + if ((readlen = xas_audio_stream_read(source, + (void **)&samples, + buffer_size)) < 0) { + goto error_audio_stream_io; + } else if (readlen == 0) { + break; + } + + if (xas_audio_stream_write(sink, samples, readlen) < 0) { + goto error_audio_stream_io; + } + + frame++; + } + + return frame * buffer_size; + +error_audio_stream_io: +error_event_trigger: + xas_audio_stream_destroy(source); + +error_spatial_scene_new_stream: + return -1; +} -- cgit v1.2.3