summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/xas/drone.h88
-rw-r--r--src/Makefile4
-rw-r--r--src/drone.c240
3 files changed, 330 insertions, 2 deletions
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 <sys/time.h>
+
+#include <xas/spatial.h>
+#include <xas/seq.h>
+
+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 <stdlib.h>
+#include <string.h>
+
+#include <xas/vox.h>
+#include <xas/drone.h>
+
+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; i<speech_line_count; i++) {
+ if (record_speech_sample(drone->bank,
+ 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;
+}