From 7b8375ee2026d42b5444f8ae0e7b98e272e87d69 Mon Sep 17 00:00:00 2001 From: XANTRONIX Development Date: Sun, 13 Mar 2022 17:16:26 -0400 Subject: Refactor drone speech modules Changes: * Implement xas_drone_vox type to wrap a xas_vox and audio stream object in one, and save rendered speech to a drone's audio bank * Implement xas_drone_speech_import() as a convenience wrapper to xas_drone_vox methods --- src/drone.c | 220 +++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 159 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/drone.c b/src/drone.c index dc8c084..e4a0cb7 100644 --- a/src/drone.c +++ b/src/drone.c @@ -1,91 +1,37 @@ #include #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) { + size_t bank_entry_size, + size_t bank_entry_count) { 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) { + bank_entry_size, + bank_entry_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; } + drone->scene = scene; + return drone; error_spatial_scene_add_bank_player: -error_record_speech_sample: xas_bank_destroy(drone->bank); error_bank_new: @@ -105,6 +51,158 @@ xas_spatial_object *xas_drone_get_spatial_object(xas_drone *drone) { return drone->obj; } +int xas_drone_speech_import(xas_drone *drone, + const char *voice, + float speed, + size_t speech_sample_first, + size_t speech_sample_count, + const char **speech_lines) { + xas_drone_vox *vox; + size_t i, o; + + if (speech_sample_first + speech_sample_count - 1 >= drone->bank->entry_count) { + errno = EINVAL; + + goto error_invalid; + } + + if ((vox = xas_drone_vox_new(drone)) == NULL) { + goto error_vox_new; + } + + if (voice) { + xas_drone_vox_set_voice(vox, voice); + } + + xas_drone_vox_set_speed(vox, speed); + + for (i=0, o=speech_sample_first; iobj) < 0) { + goto error_vox_stop_obj; + } + } + + xas_drone_vox_destroy(vox); + + return 0; + +error_vox_stop_obj: +error_vox_save: +error_vox_say: +error_vox_new: +error_invalid: + return -1; +} + +xas_drone_vox *xas_drone_vox_new(xas_drone *drone) { + xas_drone_vox *vox; + + if ((vox = malloc(sizeof(*vox))) == NULL) { + goto error_malloc_vox; + } + + if ((vox->obj = xas_vox_new(drone->scene->format, + XAS_DRONE_VOX_BUFFER_SIZE, + XAS_DRONE_VOX_TEXT2WAVE_PATH)) == NULL) { + goto error_vox_new; + } + + if ((vox->source = xas_vox_stream_new(vox->obj)) == NULL) { + goto error_vox_stream_new; + } + + vox->drone = drone; + vox->voice = XAS_DRONE_VOX_DEFAULT_VOICE; + vox->speed = XAS_DRONE_VOX_DEFAULT_SPEED; + + return vox; + +error_vox_stream_new: + xas_vox_destroy(vox->obj); + +error_vox_new: + free(vox); + +error_malloc_vox: + return NULL; +} + +void xas_drone_vox_destroy(xas_drone_vox *vox) { + xas_audio_stream_destroy(vox->source); + xas_vox_destroy(vox->obj); + free(vox); +} + +void xas_drone_vox_set_voice(xas_drone_vox *vox, const char *voice) { + vox->voice = voice; +} + +void xas_drone_vox_set_speed(xas_drone_vox *vox, float speed) { + vox->speed = speed; +} + +int xas_drone_vox_say(xas_drone_vox *vox, const char *text) { + return xas_vox_say(vox->obj, text); +} + +int xas_drone_vox_vsayf(xas_drone_vox *vox, + const char *format, + va_list args) { + return xas_vox_vsayf(vox->obj, format, args); +} + +int xas_drone_vox_sayf(xas_drone_vox *vox, const char *format, ...) { + int ret; + va_list args; + + va_start(args, format); + + ret = xas_vox_vsayf(vox->obj, format, args); + + va_end(args); + + return ret; +} + +int xas_drone_vox_save(xas_drone_vox *vox, size_t sample_index) { + if (vox->voice && xas_vox_set_voice(vox->obj, vox->voice) < 0) { + goto error_vox_set_voice; + } + + if (xas_vox_set_parameter_float(vox->obj, + "Duration_Stretch", + 1.0f / vox->speed) < 0) { + goto error_vox_set_parameter_float; + } + + if (xas_vox_generate(vox->obj) < 0) { + goto error_vox_generate; + } + + if (xas_bank_record(vox->drone->bank, + vox->source, + sample_index, + vox->drone->bank->entry_size) < 0) { + goto error_bank_record; + } + + return 0; + +error_bank_record: +error_vox_generate: +error_vox_set_parameter_float: +error_vox_set_voice: + return -1; +} + xas_drone_chamber *xas_drone_chamber_new(xas_spatial_scene *scene, xas_spatial_coord location, size_t drone_count) { -- cgit v1.2.3