From ea5c729f69a9c6c2fb88caa48e37f6f548532b9b Mon Sep 17 00:00:00 2001 From: XANTRONIX Development Date: Tue, 1 Mar 2022 23:43:57 -0500 Subject: good cats renaming stuff,,, --- examples/Makefile | 2 +- examples/script.c | 125 ------------------ examples/seq.c | 140 ++++++++++++++++++++ include/xas/script.h | 95 -------------- include/xas/seq.h | 95 ++++++++++++++ src/Makefile | 4 +- src/script.c | 361 --------------------------------------------------- src/seq.c | 361 +++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 599 insertions(+), 584 deletions(-) delete mode 100644 examples/script.c create mode 100644 examples/seq.c delete mode 100644 include/xas/script.h create mode 100644 include/xas/seq.h delete mode 100644 src/script.c create mode 100644 src/seq.c diff --git a/examples/Makefile b/examples/Makefile index b167416..756fa89 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -8,7 +8,7 @@ LIBNAME = xas CFLAGS += -I$(INCLUDE_PATH) LDFLAGS += -L../src -l$(LIBNAME) -lm -EXAMPLES = test open say spatial script +EXAMPLES = test open say spatial seq all: $(EXAMPLES) diff --git a/examples/script.c b/examples/script.c deleted file mode 100644 index f9faccc..0000000 --- a/examples/script.c +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static void usage(int argc, char **argv, const char *message, ...) { - va_list args; - - va_start(args, message); - - if (message) { - vfprintf(stderr, message, args); - fputc('\n', stderr); - } - - va_end(args); - - fprintf(stderr, "usage: %s output.wav\n", argv[0]); - - exit(EX_USAGE); -} - -int main(int argc, char **argv) { - xas_spatial_scene *scene; - xas_script *script; - - xas_spatial_object *synth_l, - *synth_r, - *voice; - - xas_audio_stream *output, - *wave; - - xas_audio_format format = { - .channels = XAS_AUDIO_STEREO, - .sample_size = XAS_AUDIO_PCM_16_BIT, - .sample_rate = 44100 - }; - - size_t buffer_size = 735; - - xas_spatial_coord speakers[2] = { - { -0.09, 0.0, 0.0 }, - { 0.09, 0.0, 0.0 } - }; - - if (argc != 2) { - usage(argc, argv, "No output file provided"); - } - - if ((wave = xas_riff_new_file(argv[1], - format, - O_WRONLY | O_CREAT | O_TRUNC)) == NULL) { - goto error_riff_new_file; - } - - if ((scene = xas_spatial_scene_new(format, - speakers[0], - speakers[1])) == NULL) { - goto error_spatial_scene_new; - } - - if ((script = xas_script_new(scene, buffer_size)) == NULL) { - goto error_script_new; - } - - if ((voice = xas_spatial_scene_add_vox(scene, - (xas_spatial_coord){ 0.0, 0.0, -20.0 }, - "/usr/bin/text2wave")) == NULL) { - goto error_spatial_scene_add_vox; - } - - if ((synth_l = xas_spatial_scene_add_synth(scene, - (xas_spatial_coord){ -20.0, 0.0, 0.0 }, - XAS_SYNTH_SINE)) == NULL) { - goto error_spatial_scene_add_synth_l; - } - - if ((synth_r = xas_spatial_scene_add_synth(scene, - (xas_spatial_coord){ 20.0, 0.0, 0.0 }, - XAS_SYNTH_SINE)) == NULL) { - goto error_spatial_scene_add_synth_r; - } - - if ((output = xas_spatial_scene_stream_new(scene, - buffer_size)) == NULL) { - goto error_spatial_scene_stream_new; - } - - xas_vox_set_parameter_float(voice->ctx, "Duration_Stretch", 1.3); - - xas_script_add_set_frequency(script, synth_l, (struct timeval){ 0, 0 }, 220); - xas_script_add_event_on( script, synth_l, (struct timeval){ 0, 0 }); - xas_script_add_event_off(script, synth_l, (struct timeval){ 60, 0 }); - - xas_script_destroy(script); - xas_spatial_scene_destroy(scene); - xas_audio_stream_destroy(wave); - - return EX_OK; - -error_spatial_scene_stream_new: -error_spatial_scene_add_synth_r: -error_spatial_scene_add_synth_l: -error_spatial_scene_add_vox: - xas_script_destroy(script); - -error_script_new: - xas_spatial_scene_destroy(scene); - -error_spatial_scene_new: - xas_audio_stream_destroy(wave); - -error_riff_new_file: - return EX_OSERR; -} diff --git a/examples/seq.c b/examples/seq.c new file mode 100644 index 0000000..3c0293a --- /dev/null +++ b/examples/seq.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static void usage(int argc, char **argv, const char *message, ...) { + va_list args; + + va_start(args, message); + + if (message) { + vfprintf(stderr, message, args); + fputc('\n', stderr); + } + + va_end(args); + + fprintf(stderr, "usage: %s output.wav\n", argv[0]); + + exit(EX_USAGE); +} + +int main(int argc, char **argv) { + xas_spatial_scene *scene; + xas_seq *seq; + + xas_spatial_object *synth_l, + *synth_r, + *voice; + + xas_audio_stream *output, + *wave; + + xas_audio_format format = { + .channels = XAS_AUDIO_STEREO, + .sample_size = XAS_AUDIO_PCM_16_BIT, + .sample_rate = 44100 + }; + + size_t buffer_size = 735; + + xas_spatial_coord speakers[2] = { + { -0.09, 0.0, 0.0 }, + { 0.09, 0.0, 0.0 } + }; + + if (argc != 2) { + usage(argc, argv, "No output file provided"); + } + + if ((wave = xas_riff_new_file(argv[1], + format, + O_WRONLY | O_CREAT | O_TRUNC)) == NULL) { + goto error_riff_new_file; + } + + if ((scene = xas_spatial_scene_new(format, + speakers[0], + speakers[1])) == NULL) { + goto error_spatial_scene_new; + } + + if ((seq = xas_seq_new(scene, buffer_size)) == NULL) { + goto error_seq_new; + } + + if ((voice = xas_spatial_scene_add_vox(scene, + (xas_spatial_coord){ 0.0, 0.0, -20.0 }, + "/usr/bin/text2wave")) == NULL) { + goto error_spatial_scene_add_vox; + } + + if ((synth_l = xas_spatial_scene_add_synth(scene, + (xas_spatial_coord){ -20.0, 0.0, 0.0 }, + XAS_SYNTH_SINE)) == NULL) { + goto error_spatial_scene_add_synth_l; + } + + if ((synth_r = xas_spatial_scene_add_synth(scene, + (xas_spatial_coord){ 20.0, 0.0, 0.0 }, + XAS_SYNTH_SINE)) == NULL) { + goto error_spatial_scene_add_synth_r; + } + + if ((output = xas_spatial_scene_stream_new(scene, + buffer_size)) == NULL) { + goto error_spatial_scene_stream_new; + } + + xas_vox_set_parameter_float(voice->ctx, "Duration_Stretch", 1.3); + + xas_seq_add_set_frequency(seq, synth_l, (struct timeval){ 0, 0 }, 220); + xas_seq_add_set_frequency(seq, synth_r, (struct timeval){ 0, 0 }, 420); + xas_seq_add_event_on( seq, synth_l, (struct timeval){ 0, 0 }); + xas_seq_add_event_on( seq, synth_r, (struct timeval){ 0, 0 }); + + xas_seq_add_set_position(seq, + synth_l, + (struct timeval){ 15, 0 }, + (xas_spatial_coord){ -10.0, 0.0, 0.0 }); + + xas_seq_add_phrase(seq, + voice, + (struct timeval){ 10, 0 }, + "I will eat your soul."); + + xas_seq_add_event_off(seq, synth_l, (struct timeval){ 60, 0 }); + + xas_seq_play(seq, wave); + + xas_seq_destroy(seq); + xas_spatial_scene_destroy(scene); + xas_audio_stream_destroy(wave); + + return EX_OK; + +error_spatial_scene_stream_new: +error_spatial_scene_add_synth_r: +error_spatial_scene_add_synth_l: +error_spatial_scene_add_vox: + xas_seq_destroy(seq); + +error_seq_new: + xas_spatial_scene_destroy(scene); + +error_spatial_scene_new: + xas_audio_stream_destroy(wave); + +error_riff_new_file: + return EX_OSERR; +} diff --git a/include/xas/script.h b/include/xas/script.h deleted file mode 100644 index ff07b49..0000000 --- a/include/xas/script.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef _XAS_SCRIPT_H -#define _XAS_SCRIPT_H - -#include -#include - -#include -#include - -enum xas_script_event_type { - XAS_SCRIPT_EVENT_OFF, - XAS_SCRIPT_EVENT_ON, - XAS_SCRIPT_EVENT_SET_POSITION, - XAS_SCRIPT_EVENT_SET_GAIN, - XAS_SCRIPT_EVENT_SET_FREQUENCY, - XAS_SCRIPT_EVENT_SET_BANK_INDEX, - XAS_SCRIPT_EVENT_SPEECH -}; - -enum xas_script_object_type { - XAS_SCRIPT_OBJECT_ANY, - XAS_SCRIPT_OBJECT_SYNTH, - XAS_SCRIPT_OBJECT_VOX, - XAS_SCRIPT_OBJECT_BANK_PLAYER -}; - -typedef struct _xas_script_event xas_script_event; - -struct _xas_script_event { - enum xas_script_event_type type; - enum xas_script_object_type objtype; - - xas_spatial_object *object; - - struct timeval timestamp; - - union { - float gain; - xas_spatial_coord point; - size_t index; - size_t frequency; - const char *phrase; - }; - - xas_script_event *next; -}; - -typedef struct _xas_script { - xas_spatial_scene *scene; - - xas_script_event *first; - - size_t buffer_size; -} xas_script; - -xas_script *xas_script_new(xas_spatial_scene *scene, size_t buffer_size); - -void xas_script_destroy(xas_script *script); - -int xas_script_add_event_off(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp); - -int xas_script_add_event_on(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp); - -int xas_script_add_set_position(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp, - xas_spatial_coord point); - -int xas_script_add_set_gain(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp, - float gain); - -int xas_script_add_set_bank(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp, - size_t index); - -int xas_script_add_set_frequency(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp, - size_t frequency); - -int xas_script_add_phrase(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp, - const char *phrase); - -int xas_script_play(xas_script *script, xas_audio_stream *sink); - -#endif /* _XAS_SCRIPT_H */ diff --git a/include/xas/seq.h b/include/xas/seq.h new file mode 100644 index 0000000..74b198f --- /dev/null +++ b/include/xas/seq.h @@ -0,0 +1,95 @@ +#ifndef _XAS_SEQ_H +#define _XAS_SEQ_H + +#include +#include + +#include +#include + +enum xas_seq_event_type { + XAS_SEQ_EVENT_OFF, + XAS_SEQ_EVENT_ON, + XAS_SEQ_EVENT_SET_POSITION, + XAS_SEQ_EVENT_SET_GAIN, + XAS_SEQ_EVENT_SET_FREQUENCY, + XAS_SEQ_EVENT_SET_BANK_INDEX, + XAS_SEQ_EVENT_SPEECH +}; + +enum xas_seq_object_type { + XAS_SEQ_OBJECT_ANY, + XAS_SEQ_OBJECT_SYNTH, + XAS_SEQ_OBJECT_VOX, + XAS_SEQ_OBJECT_BANK_PLAYER +}; + +typedef struct _xas_seq_event xas_seq_event; + +struct _xas_seq_event { + enum xas_seq_event_type type; + enum xas_seq_object_type objtype; + + xas_spatial_object *object; + + struct timeval timestamp; + + union { + float gain; + xas_spatial_coord point; + size_t index; + size_t frequency; + const char *phrase; + }; + + xas_seq_event *next; +}; + +typedef struct _xas_seq { + xas_spatial_scene *scene; + + xas_seq_event *first; + + size_t buffer_size; +} xas_seq; + +xas_seq *xas_seq_new(xas_spatial_scene *scene, size_t buffer_size); + +void xas_seq_destroy(xas_seq *seq); + +int xas_seq_add_event_off(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp); + +int xas_seq_add_event_on(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp); + +int xas_seq_add_set_position(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp, + xas_spatial_coord point); + +int xas_seq_add_set_gain(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp, + float gain); + +int xas_seq_add_set_bank(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp, + size_t index); + +int xas_seq_add_set_frequency(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp, + size_t frequency); + +int xas_seq_add_phrase(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp, + const char *phrase); + +int xas_seq_play(xas_seq *seq, xas_audio_stream *sink); + +#endif /* _XAS_SEQ_H */ diff --git a/src/Makefile b/src/Makefile index ce60d40..099c3ee 100644 --- a/src/Makefile +++ b/src/Makefile @@ -8,10 +8,10 @@ CFLAGS += -I$(INCLUDE_PATH) LDFLAGS += HEADERS = audio.h riff.h mixer.h object.h synth.h vox.h bank.h \ - spatial.h script.h + spatial.h seq.h OBJS = audio.o riff.o mixer.o object.o synth.o vox.o bank.o \ - spatial.o script.o + spatial.o seq.o VERSION_MAJOR = 0 VERSION_MINOR = 0.1 diff --git a/src/script.c b/src/script.c deleted file mode 100644 index 4bd69b1..0000000 --- a/src/script.c +++ /dev/null @@ -1,361 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include - -xas_script *xas_script_new(xas_spatial_scene *scene, size_t buffer_size) { - xas_script *script; - - if ((script = malloc(sizeof(*script))) == NULL) { - goto error_malloc_script; - } - - script->scene = scene; - script->first = NULL; - script->buffer_size = buffer_size; - - return script; - -error_malloc_script: - return NULL; -} - -void xas_script_destroy(xas_script *script) { - xas_script_event *event = script->first; - - while (event) { - xas_script_event *next = event->next; - - free(event); - - event = next; - } - - free(script); -} - -static void add_event(xas_script *script, xas_script_event *ev) { - xas_script_event *current = script->first; - - if (script->first == NULL) { - script->first = ev; - - return; - } - - while (current) { - xas_script_event *next = current->next; - - if (next == NULL) { - current->next = ev; - - return; - } - - if (timercmp(&ev->timestamp, ¤t->timestamp, >=) - && timercmp(&ev->timestamp, &next->timestamp, <)) { - current->next = ev; - ev->next = next; - - return; - } - - current = next; - } -} - -int xas_script_add_event_off(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp) { - xas_script_event *ev; - - if ((ev = malloc(sizeof(*ev))) == NULL) { - goto error_malloc_ev; - } - - ev->type = XAS_SCRIPT_EVENT_OFF; - ev->objtype = XAS_SCRIPT_OBJECT_ANY; - ev->object = object; - ev->timestamp = timestamp; - ev->next = NULL; - - add_event(script, ev); - - return 0; - -error_malloc_ev: - return -1; -} - -int xas_script_add_event_on(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp) { - xas_script_event *ev; - - if ((ev = malloc(sizeof(*ev))) == NULL) { - goto error_malloc_ev; - } - - ev->type = XAS_SCRIPT_EVENT_ON; - ev->objtype = XAS_SCRIPT_OBJECT_ANY; - ev->object = object; - ev->timestamp = timestamp; - ev->next = NULL; - - add_event(script, ev); - - return 0; - -error_malloc_ev: - return -1; -} - -int xas_script_add_set_position(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp, - xas_spatial_coord point) { - xas_script_event *ev; - - if ((ev = malloc(sizeof(*ev))) == NULL) { - goto error_malloc_ev; - } - - ev->type = XAS_SCRIPT_EVENT_SET_POSITION; - ev->objtype = XAS_SCRIPT_OBJECT_ANY; - ev->object = object; - ev->timestamp = timestamp; - ev->point = point; - ev->next = NULL; - - add_event(script, ev); - - return 0; - -error_malloc_ev: - return -1; -} - -int xas_script_add_set_gain(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp, - float gain) { - xas_script_event *ev; - - if ((ev = malloc(sizeof(*ev))) == NULL) { - goto error_malloc_ev; - } - - ev->type = XAS_SCRIPT_EVENT_ON; - ev->objtype = XAS_SCRIPT_OBJECT_ANY; - ev->object = object; - ev->timestamp = timestamp; - ev->gain = gain; - ev->next = NULL; - - add_event(script, ev); - - return 0; - -error_malloc_ev: - return -1; -} - -int xas_script_add_set_bank(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp, - size_t index) { - xas_script_event *ev; - - if ((ev = malloc(sizeof(*ev))) == NULL) { - goto error_malloc_ev; - } - - ev->type = XAS_SCRIPT_EVENT_SET_BANK_INDEX; - ev->objtype = XAS_SCRIPT_OBJECT_BANK_PLAYER; - ev->object = object; - ev->timestamp = timestamp; - ev->next = NULL; - ev->index = index; - - add_event(script, ev); - - return 0; - -error_malloc_ev: - return -1; -} - -int xas_script_add_set_frequency(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp, - size_t frequency) { - xas_script_event *ev; - - if ((ev = malloc(sizeof(*ev))) == NULL) { - goto error_malloc_ev; - } - - ev->type = XAS_SCRIPT_EVENT_SET_FREQUENCY; - ev->objtype = XAS_SCRIPT_OBJECT_SYNTH; - ev->object = object; - ev->timestamp = timestamp; - ev->next = NULL; - ev->frequency = frequency; - - add_event(script, ev); - - return 0; - -error_malloc_ev: - return -1; -} - -int xas_script_add_phrase(xas_script *script, - xas_spatial_object *object, - struct timeval timestamp, - const char *phrase) { - xas_script_event *ev; - - if ((ev = malloc(sizeof(*ev))) == NULL) { - goto error_malloc_ev; - } - - ev->type = XAS_SCRIPT_EVENT_SPEECH; - ev->objtype = XAS_SCRIPT_OBJECT_VOX; - ev->object = object; - ev->timestamp = timestamp; - ev->next = NULL; - ev->phrase = phrase; - - add_event(script, ev); - - return 0; - -error_malloc_ev: - return -1; -} - -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; - - case XAS_SCRIPT_EVENT_SPEECH: - if (ev->objtype != XAS_SCRIPT_OBJECT_VOX) { - goto error_invalid_event; - } - - xas_vox_say(ev->object->ctx, ev->phrase); - xas_vox_generate(ev->object->ctx); - - break; - } - - return 0; - -error_invalid_event: - return -1; -} - -static inline void timerupdate(struct timeval *tv, - suseconds_t interval, - size_t frame) { - suseconds_t usec = frame * interval; - - tv->tv_sec = usec / 1000000; - tv->tv_usec = usec % 1000000; -} - -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_stream_new(script->scene, - script->buffer_size)) == NULL) { - goto error_spatial_scene_stream_new; - } - - while (ev) { - struct timeval tv; - - ssize_t readlen; - - timerupdate(&tv, interval, frame); - - while (ev && !timercmp(&tv, &ev->timestamp, <)) { - if (event_trigger(script->scene, ev) < 0) { - goto error_event_trigger; - } - - ev = 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_stream_new: - return -1; -} diff --git a/src/seq.c b/src/seq.c new file mode 100644 index 0000000..64b3544 --- /dev/null +++ b/src/seq.c @@ -0,0 +1,361 @@ +#include +#include + +#include +#include +#include +#include +#include + +xas_seq *xas_seq_new(xas_spatial_scene *scene, size_t buffer_size) { + xas_seq *seq; + + if ((seq = malloc(sizeof(*seq))) == NULL) { + goto error_malloc_seq; + } + + seq->scene = scene; + seq->first = NULL; + seq->buffer_size = buffer_size; + + return seq; + +error_malloc_seq: + return NULL; +} + +void xas_seq_destroy(xas_seq *seq) { + xas_seq_event *event = seq->first; + + while (event) { + xas_seq_event *next = event->next; + + free(event); + + event = next; + } + + free(seq); +} + +static void add_event(xas_seq *seq, xas_seq_event *ev) { + xas_seq_event *current = seq->first; + + if (seq->first == NULL) { + seq->first = ev; + + return; + } + + while (current) { + xas_seq_event *next = current->next; + + if (next == NULL) { + current->next = ev; + + return; + } + + if (timercmp(&ev->timestamp, ¤t->timestamp, >=) + && timercmp(&ev->timestamp, &next->timestamp, <)) { + current->next = ev; + ev->next = next; + + return; + } + + current = next; + } +} + +int xas_seq_add_event_off(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp) { + xas_seq_event *ev; + + if ((ev = malloc(sizeof(*ev))) == NULL) { + goto error_malloc_ev; + } + + ev->type = XAS_SEQ_EVENT_OFF; + ev->objtype = XAS_SEQ_OBJECT_ANY; + ev->object = object; + ev->timestamp = timestamp; + ev->next = NULL; + + add_event(seq, ev); + + return 0; + +error_malloc_ev: + return -1; +} + +int xas_seq_add_event_on(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp) { + xas_seq_event *ev; + + if ((ev = malloc(sizeof(*ev))) == NULL) { + goto error_malloc_ev; + } + + ev->type = XAS_SEQ_EVENT_ON; + ev->objtype = XAS_SEQ_OBJECT_ANY; + ev->object = object; + ev->timestamp = timestamp; + ev->next = NULL; + + add_event(seq, ev); + + return 0; + +error_malloc_ev: + return -1; +} + +int xas_seq_add_set_position(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp, + xas_spatial_coord point) { + xas_seq_event *ev; + + if ((ev = malloc(sizeof(*ev))) == NULL) { + goto error_malloc_ev; + } + + ev->type = XAS_SEQ_EVENT_SET_POSITION; + ev->objtype = XAS_SEQ_OBJECT_ANY; + ev->object = object; + ev->timestamp = timestamp; + ev->point = point; + ev->next = NULL; + + add_event(seq, ev); + + return 0; + +error_malloc_ev: + return -1; +} + +int xas_seq_add_set_gain(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp, + float gain) { + xas_seq_event *ev; + + if ((ev = malloc(sizeof(*ev))) == NULL) { + goto error_malloc_ev; + } + + ev->type = XAS_SEQ_EVENT_ON; + ev->objtype = XAS_SEQ_OBJECT_ANY; + ev->object = object; + ev->timestamp = timestamp; + ev->gain = gain; + ev->next = NULL; + + add_event(seq, ev); + + return 0; + +error_malloc_ev: + return -1; +} + +int xas_seq_add_set_bank(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp, + size_t index) { + xas_seq_event *ev; + + if ((ev = malloc(sizeof(*ev))) == NULL) { + goto error_malloc_ev; + } + + ev->type = XAS_SEQ_EVENT_SET_BANK_INDEX; + ev->objtype = XAS_SEQ_OBJECT_BANK_PLAYER; + ev->object = object; + ev->timestamp = timestamp; + ev->next = NULL; + ev->index = index; + + add_event(seq, ev); + + return 0; + +error_malloc_ev: + return -1; +} + +int xas_seq_add_set_frequency(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp, + size_t frequency) { + xas_seq_event *ev; + + if ((ev = malloc(sizeof(*ev))) == NULL) { + goto error_malloc_ev; + } + + ev->type = XAS_SEQ_EVENT_SET_FREQUENCY; + ev->objtype = XAS_SEQ_OBJECT_SYNTH; + ev->object = object; + ev->timestamp = timestamp; + ev->next = NULL; + ev->frequency = frequency; + + add_event(seq, ev); + + return 0; + +error_malloc_ev: + return -1; +} + +int xas_seq_add_phrase(xas_seq *seq, + xas_spatial_object *object, + struct timeval timestamp, + const char *phrase) { + xas_seq_event *ev; + + if ((ev = malloc(sizeof(*ev))) == NULL) { + goto error_malloc_ev; + } + + ev->type = XAS_SEQ_EVENT_SPEECH; + ev->objtype = XAS_SEQ_OBJECT_VOX; + ev->object = object; + ev->timestamp = timestamp; + ev->next = NULL; + ev->phrase = phrase; + + add_event(seq, ev); + + return 0; + +error_malloc_ev: + return -1; +} + +static int event_trigger(xas_spatial_scene *scene, xas_seq_event *ev) { + switch (ev->type) { + case XAS_SEQ_EVENT_OFF: + return xas_spatial_object_stop(ev->object); + + case XAS_SEQ_EVENT_ON: + return xas_spatial_object_start(ev->object); + + case XAS_SEQ_EVENT_SET_POSITION: + xas_spatial_scene_position_object(scene, + ev->object, + ev->point); + + break; + + case XAS_SEQ_EVENT_SET_GAIN: + xas_object_set_gain(ev->object->ctx, ev->gain); + + break; + + case XAS_SEQ_EVENT_SET_FREQUENCY: + if (ev->objtype != XAS_SEQ_OBJECT_SYNTH) { + goto error_invalid_event; + } + + xas_synth_set_frequency(ev->object->ctx, ev->frequency); + + break; + + case XAS_SEQ_EVENT_SET_BANK_INDEX: + if (ev->objtype != XAS_SEQ_OBJECT_BANK_PLAYER) { + goto error_invalid_event; + } + + xas_bank_player_set_entry(ev->object->ctx, ev->gain); + + break; + + case XAS_SEQ_EVENT_SPEECH: + if (ev->objtype != XAS_SEQ_OBJECT_VOX) { + goto error_invalid_event; + } + + xas_vox_say(ev->object->ctx, ev->phrase); + xas_vox_generate(ev->object->ctx); + + break; + } + + return 0; + +error_invalid_event: + return -1; +} + +static inline void timerupdate(struct timeval *tv, + suseconds_t interval, + size_t frame) { + suseconds_t usec = frame * interval; + + tv->tv_sec = usec / 1000000; + tv->tv_usec = usec % 1000000; +} + +int xas_seq_play(xas_seq *seq, xas_audio_stream *sink) { + xas_seq_event *ev = seq->first; + xas_audio_stream *source; + + size_t frame = 0, + sample_rate = seq->scene->format.sample_rate, + buffer_size = seq->buffer_size; + + suseconds_t interval = 1000000 / (sample_rate / buffer_size); + + int16_t *samples; + + if ((source = xas_spatial_scene_stream_new(seq->scene, + seq->buffer_size)) == NULL) { + goto error_spatial_scene_stream_new; + } + + while (ev) { + struct timeval tv; + + ssize_t readlen; + + timerupdate(&tv, interval, frame); + + while (ev && !timercmp(&tv, &ev->timestamp, <)) { + if (event_trigger(seq->scene, ev) < 0) { + goto error_event_trigger; + } + + ev = 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_stream_new: + return -1; +} -- cgit v1.2.3