From 945f3ba330620e429bb70cb71d8dc0b9521d8b1d Mon Sep 17 00:00:00 2001 From: XANTRONIX Development Date: Thu, 10 Mar 2022 00:41:49 -0500 Subject: Initial commit of src/drone.c --- include/xas/drone.h | 88 +++++++++++++++++++ src/Makefile | 4 +- src/drone.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 include/xas/drone.h create mode 100644 src/drone.c diff --git a/include/xas/drone.h b/include/xas/drone.h new file mode 100644 index 0000000..d77834c --- /dev/null +++ b/include/xas/drone.h @@ -0,0 +1,88 @@ +#ifndef _XAS_DRONE_H +#define _XAS_DRONE_H + +#include + +#include +#include + +enum xas_drone_chamber_event_type { + XAS_DRONE_CHAMBER_EVENT_NONE, + XAS_DRONE_CHAMBER_EVENT_SYNTH, + XAS_DRONE_CHAMBER_EVENT_DRONE_SPEECH +}; + +typedef struct _xas_drone xas_drone; + +struct _xas_drone { + xas_bank *bank; + xas_spatial_scene *scene; + xas_spatial_object *obj; + float speech_speed; + + const char **speech_lines; + + xas_drone *next; +}; + +typedef struct _xas_drone_chamber_interval { + struct timeval duration; + + size_t freq_l, + freq_r; + + enum xas_synth_type type_l, + type_r; +} xas_drone_chamber_interval; + +typedef struct _xas_drone_chamber_speech { + size_t drone_index, + speech_line; +} xas_drone_chamber_speech; + +typedef struct _xas_drone_chamber_event { + enum xas_drone_chamber_event_type type; + + union { + xas_drone_chamber_interval interval; + xas_drone_chamber_speech speech; + }; +} xas_drone_chamber_event; + +typedef struct _xas_drone_chamber { + xas_spatial_scene *scene; + xas_drone **drones; + size_t drone_count; + + xas_spatial_object *synth_l, + *synth_r; +} xas_drone_chamber; + +xas_drone *xas_drone_new(xas_spatial_scene *scene, + xas_spatial_coord position, + float speech_speed, + size_t speech_sample_count, + size_t speech_line_count, + const char **speech_lines); + +void xas_drone_destroy(xas_drone *drone); + +xas_spatial_object *xas_drone_get_spatial_object(xas_drone *drone); + +xas_drone_chamber *xas_drone_chamber_new(xas_spatial_scene *scene, + xas_spatial_coord location, + size_t drone_count); + +void xas_drone_chamber_destroy(xas_drone_chamber *chamber); + +void xas_drone_chamber_insert_drone(xas_drone_chamber *chamber, + xas_drone *drone, + size_t index); + +int xas_drone_chamber_event_seq(xas_drone_chamber *chamber, + xas_drone_chamber_event *ev, + xas_seq *seq, + int advance, + struct timeval *now); + +#endif /* _XAS_DRONE_H */ diff --git a/src/Makefile b/src/Makefile index 099c3ee..c4609c8 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 seq.h + spatial.h seq.h drone.h OBJS = audio.o riff.o mixer.o object.o synth.o vox.o bank.o \ - spatial.o seq.o + spatial.o seq.o drone.o VERSION_MAJOR = 0 VERSION_MINOR = 0.1 diff --git a/src/drone.c b/src/drone.c new file mode 100644 index 0000000..19fccba --- /dev/null +++ b/src/drone.c @@ -0,0 +1,240 @@ +#include +#include + +#include +#include + +static size_t DEFAULT_BUFFER_SIZE = 735; + +static int record_speech_sample(xas_bank *bank, + size_t entry_index, + float speed, + const char *text) { + xas_vox *vox; + xas_audio_stream *source; + + if ((vox = xas_vox_new(bank->format, + DEFAULT_BUFFER_SIZE, + "/usr/bin/text2wave")) == NULL) { + goto error_vox_new; + } + + if ((source = xas_vox_stream_new(vox)) == NULL) { + goto error_vox_stream_new; + } + + xas_vox_set_voice(vox, "voice_cmu_us_slt_cg"); + xas_vox_set_parameter_float(vox, "Duration_Stretch", speed); + xas_vox_say(vox, text); + xas_vox_generate(vox); + + if (xas_bank_record(bank, source, entry_index, bank->entry_size) < 0) { + goto error_bank_record; + } + + xas_audio_stream_destroy(source); + xas_vox_destroy(vox); + + return 0; + +error_bank_record: + xas_audio_stream_destroy(source); + +error_vox_stream_new: + xas_vox_destroy(vox); + +error_vox_new: + return -1; +} + +xas_drone *xas_drone_new(xas_spatial_scene *scene, + xas_spatial_coord position, + float speech_speed, + size_t speech_sample_count, + size_t speech_line_count, + const char **speech_lines) { + xas_drone *drone; + + size_t i; + + if ((drone = malloc(sizeof(*drone))) == NULL) { + goto error_malloc_drone; + } + + if ((drone->bank = xas_bank_new(scene->format, + speech_sample_count, + speech_line_count)) == NULL) { + goto error_bank_new; + } + + for (i=0; ibank, + i, + speech_speed, + speech_lines[i]) < 0) { + goto error_record_speech_sample; + } + } + + if ((drone->obj = xas_spatial_scene_add_bank_player(scene, + position, + drone->bank)) == NULL) { + goto error_spatial_scene_add_bank_player; + } + + return drone; + +error_spatial_scene_add_bank_player: +error_record_speech_sample: + xas_bank_destroy(drone->bank); + +error_bank_new: + free(drone); + +error_malloc_drone: + return NULL; +} + +void xas_drone_destroy(xas_drone *drone) { + xas_bank_destroy(drone->bank); + + free(drone); +} + +xas_spatial_object *xas_drone_get_spatial_object(xas_drone *drone) { + return drone->obj; +} + +xas_drone_chamber *xas_drone_chamber_new(xas_spatial_scene *scene, + xas_spatial_coord location, + size_t drone_count) { + xas_drone_chamber *chamber; + + size_t total = drone_count * sizeof(xas_drone *); + + if ((chamber = malloc(sizeof(*chamber))) == NULL) { + goto error_malloc_chamber; + } + + if ((chamber->drones = malloc(total)) == NULL) { + goto error_malloc_chamber_drones; + } + + if ((chamber->synth_l = xas_spatial_scene_add_synth(scene, + (xas_spatial_coord){ + location.x - 5.0, + location.y, + location.z + }, + XAS_SYNTH_SINE)) == NULL) { + goto error_spatial_scene_add_synth; + } + + if ((chamber->synth_r = xas_spatial_scene_add_synth(scene, + (xas_spatial_coord){ + location.x + 5.0, + location.y, + location.z + }, + XAS_SYNTH_SINE)) == NULL) { + goto error_spatial_scene_add_synth; + } + + chamber->drone_count = drone_count; + + memset(chamber->drones, '\0', total); + + return chamber; + +error_spatial_scene_add_synth: +error_malloc_chamber_drones: + free(chamber); + +error_malloc_chamber: + return NULL; +} + +void xas_drone_chamber_destroy(xas_drone_chamber *chamber) { + free(chamber); +} + +void xas_drone_chamber_insert_drone(xas_drone_chamber *chamber, + xas_drone *drone, + size_t index) { + chamber->drones[index] = drone; +} + +int xas_drone_chamber_event_seq(xas_drone_chamber *chamber, + xas_drone_chamber_event *ev, + xas_seq *seq, + int advance, + struct timeval *now) { + struct timeval tmp = *now; + + switch (ev->type) { + case XAS_DRONE_CHAMBER_EVENT_NONE: + return 0; + + case XAS_DRONE_CHAMBER_EVENT_SYNTH: + if (xas_seq_add_set_frequency(seq, + chamber->synth_l, + *now, + ev->interval.freq_l) < 0) { + goto error_seq_add; + } + + if (xas_seq_add_set_synth_type(seq, + chamber->synth_l, + *now, + ev->interval.type_l) < 0) { + goto error_seq_add; + } + + if (xas_seq_add_set_frequency(seq, + chamber->synth_r, + *now, + ev->interval.freq_r) < 0) { + goto error_seq_add; + } + + if (xas_seq_add_set_synth_type(seq, + chamber->synth_r, + *now, + ev->interval.type_r) < 0) { + goto error_seq_add; + } + + if (advance) { + timeradd(&tmp, &ev->interval.duration, now); + } + + break; + + case XAS_DRONE_CHAMBER_EVENT_DRONE_SPEECH: + struct timeval duration, + delay = { 0, 5000000 }; + + xas_drone *drone = chamber->drones[ev->speech.drone_index]; + size_t slot = ev->speech.speech_line; + + xas_bank_entry_duration(drone->bank, slot, &duration); + + if (xas_seq_add_event_on(seq, + drone->obj, + *now) < 0) { + goto error_seq_add; + } + + if (advance) { + timeradd(now, &delay, &tmp); + timeradd(&tmp, &duration, now); + } + + break; + } + + return 0; + +error_seq_add: + return -1; +} -- cgit v1.2.3