From 0727bfcaf2bd48bf501a7fa95515c400a1996902 Mon Sep 17 00:00:00 2001 From: Bryan Jurish Date: Thu, 2 Feb 2006 12:49:19 +0000 Subject: initial cvs import svn path=/trunk/externals/moocow/; revision=4536 --- flite/flite.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 flite/flite.c (limited to 'flite/flite.c') diff --git a/flite/flite.c b/flite/flite.c new file mode 100644 index 0000000..9493a38 --- /dev/null +++ b/flite/flite.c @@ -0,0 +1,264 @@ +/* -*- Mode: C -*- */ +/*=============================================================================*\ + * File: flite.c + * Author: Bryan Jurish + * Description: speech synthesis for PD + * + * PD interface to 'flite' C libraries. + * + *=============================================================================*/ + + +#include + +/* black magic */ +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +/*-------------------------------------------------------------------- + * DEBUG + *--------------------------------------------------------------------*/ +//#define FLITE_DEBUG 1 +//#undef FLITE_DEBUG + + +/*-------------------------------------------------------------------- + * Globals + *--------------------------------------------------------------------*/ +extern cst_voice *PDFLITE_REGISTER_VOICE(); +static cst_voice *voice; + +#define DEFAULT_BUFSIZE 256 +#define DEFAULT_BUFSTEP 256 + +/*===================================================================== + * Structures and Types + *=====================================================================*/ + +static char *flite_description = + "flite: Text-to-Speech external v%s by Bryan Jurish"; +//static char *flite_acknowledge = "flite: based on code by "; +//static char *flite_version = "flite: PD external v%s by Bryan Jurish"; + + + +/*--------------------------------------------------------------------- + * flite + *---------------------------------------------------------------------*/ +static t_class *flite_class; +typedef struct _flite +{ + t_object x_obj; /* black magic (probably inheritance-related) */ + t_symbol *x_arrayname; /* arrayname (from '_tabwrite' code in $PD_SRC/d_array.c) */ + char *textbuf; /* text buffer (hack) */ + int bufsize; /* text buffer size */ +} t_flite; + + +/*-------------------------------------------------------------------- + * flite_synth : synthesize current text-buffer + *--------------------------------------------------------------------*/ +void flite_synth(t_flite *x) { + cst_wave *wave; + int i,vecsize; + t_garray *a; + t_float *vec; + +# ifdef FLITE_DEBUG + post("flite: got message 'synth'"); +# endif + + // -- sanity checks + if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) + error("flite: no such array '%s'", x->x_arrayname->s_name); + if (!x->textbuf) { + error("flite: attempt to synthesize empty text-buffer!"); + return; + } + +# ifdef FLITE_DEBUG + post("flite: flite_text_to_wave()"); +# endif + wave = flite_text_to_wave(x->textbuf,voice); + + if (!wave) { + error("flite: synthesis failed for text '%s'", x->textbuf); + return; + } + + // -- resample +# ifdef FLITE_DEBUG + post("flite: cst_wave_resample()"); +# endif + cst_wave_resample(wave,sys_getsr()); + + // -- resize & write to our array +# ifdef FLITE_DEBUG + post("flite: garray_resize(%d)", wave->num_samples); +# endif + + garray_resize(a, wave->num_samples); + if (!garray_getfloatarray(a, &vecsize, &vec)) + error("flite: bad template for write to array '%s'", x->x_arrayname->s_name); + +# ifdef FLITE_DEBUG + post("flite: ->write to garray loop<-"); +# endif + for (i = 0; i < wave->num_samples; i++) { + *vec++ = wave->samples[i]/32767.0; + } + + // -- outlet synth-done-bang + outlet_bang(x->x_obj.ob_outlet); + + // -- cleanup + delete_wave(wave); + + // -- redraw + garray_redraw(a); +} + +/*-------------------------------------------------------------------- + * flite_text : set text-buffer + *--------------------------------------------------------------------*/ +void flite_text(t_flite *x, t_symbol *s, int argc, t_atom *argv) { + int i, alen, buffered; + t_symbol *asym; + + // -- allocate initial text-buffer if required + if (x->textbuf == NULL) { + x->bufsize = DEFAULT_BUFSIZE; + x->textbuf = getbytes(x->bufsize); + } + if (x->textbuf == NULL) { + error("flite: allocation failed for text buffer"); + x->bufsize = 0; + return; + } + + // -- convert args to strings + buffered = 0; + for (i = 0; i < argc; i++) { + asym = atom_gensym(argv); + alen = 1+strlen(asym->s_name); + + // -- reallocate if necessary + while (buffered + alen > x->bufsize) { + x->textbuf = resizebytes(x->textbuf,x->bufsize,x->bufsize+DEFAULT_BUFSTEP); + x->bufsize = x->bufsize+DEFAULT_BUFSTEP; + if (x->textbuf == NULL) { + error("flite: allocation failed for text buffer"); + x->bufsize = 0; + return; + } + } + + // -- append arg-string to text-buf + if (i == 0) { + strcpy(x->textbuf+buffered, asym->s_name); + buffered += alen-1; + } else { + *(x->textbuf+buffered) = ' '; + strcpy(x->textbuf+buffered+1, asym->s_name); + buffered += alen; + } + + // -- increment/decrement + argv++; + } + +#ifdef FLITE_DEBUG + post("flite_debug: got text='%s'", x->textbuf); +#endif +} + + +/*-------------------------------------------------------------------- + * flite_list : parse & synthesize text in one swell foop + *--------------------------------------------------------------------*/ +void flite_list(t_flite *x, t_symbol *s, int argc, t_atom *argv) { + flite_text(x,s,argc,argv); + flite_synth(x); +} + + +/*-------------------------------------------------------------------- + * flite_set : set arrayname + *--------------------------------------------------------------------*/ +static void flite_set(t_flite *x, t_symbol *ary) { +#ifdef FLITE_DEBUG + post("flite_set: called with arg='%s'", ary->s_name); +#endif + x->x_arrayname = ary; +} + + +/*-------------------------------------------------------------------- + * constructor / destructor + *--------------------------------------------------------------------*/ +static void *flite_new(t_symbol *ary) +{ + t_flite *x; + + x = (t_flite *)pd_new(flite_class); + + // set initial arrayname + x->x_arrayname = ary; + + // init textbuf + x->textbuf = NULL; + x->bufsize = 0; + + // create bang-on-done outlet + outlet_new(&x->x_obj, &s_bang); + + return (void *)x; +} + +static void flite_free(t_flite *x) { + if (x->bufsize && x->textbuf != NULL) { + freebytes(x->textbuf, x->bufsize); + x->bufsize = 0; + } +} + +/*-------------------------------------------------------------------- + * setup + *--------------------------------------------------------------------*/ +void flite_setup(void) { + post(""); + post(flite_description, PACKAGE_VERSION); + post(""); + + // --- setup synth + flite_init(); + voice = PDFLITE_REGISTER_VOICE(); + + // --- register class + flite_class = class_new(gensym("flite"), + (t_newmethod)flite_new, // newmethod + (t_method)flite_free, // freemethod + sizeof(t_flite), // size + CLASS_DEFAULT, // flags + A_DEFSYM, // arg1: table-name + 0); + + // --- class methods + class_addlist(flite_class, flite_list); + class_addmethod(flite_class, (t_method)flite_set, gensym("set"), A_DEFSYM, 0); + class_addmethod(flite_class, (t_method)flite_text, gensym("text"), A_GIMME, 0); + class_addmethod(flite_class, (t_method)flite_synth, gensym("synth"), 0); + + // --- help patch + class_sethelpsymbol(flite_class, gensym("flite-help.pd")); +} -- cgit v1.2.1