0003-pico2wave-Convert-text-to-.wav-using-svox-text-to-sp.patch (15439B)
1 From 8bec80dccc9f4fe147a500486813f4e89a0d56d8 Mon Sep 17 00:00:00 2001 2 From: Mathieu Parent <math.parent@gmail.com> 3 Date: Sun, 25 Oct 2009 15:19:01 +0100 4 Subject: [PATCH 3/7] pico2wave: Convert text to .wav using svox text-to-speech system. 5 6 --- 7 pico/.gitignore | 1 + 8 pico/Makefile.am | 7 + 9 pico/bin/pico2wave.c | 341 ++++++++++++++++++++++++++++++++++++++++++++++++++ 10 pico/configure.in | 3 + 11 4 files changed, 352 insertions(+), 0 deletions(-) 12 create mode 100644 pico/bin/pico2wave.c 13 14 diff --git a/pico/.gitignore b/pico/.gitignore 15 index 4235569..a110298 100644 16 --- a/pico/.gitignore 17 +++ b/pico/.gitignore 18 @@ -29,4 +29,5 @@ libtool 19 *.lo 20 .libs 21 libttspico.la 22 +pico2wave 23 24 diff --git a/pico/Makefile.am b/pico/Makefile.am 25 index 6d8a10c..0d9472d 100644 26 --- a/pico/Makefile.am 27 +++ b/pico/Makefile.am 28 @@ -34,3 +34,10 @@ libttspico_la_SOURCES = \ 29 lib/picotrns.c \ 30 lib/picowa.c 31 32 +bin_PROGRAMS = pico2wave 33 +pico2wave_SOURCES = \ 34 + bin/pico2wave.c 35 +pico2wave_LDADD = \ 36 + libttspico.la -lm -lpopt 37 +pico2wave_CFLAGS = -Wall -I lib 38 + 39 diff --git a/pico/bin/pico2wave.c b/pico/bin/pico2wave.c 40 new file mode 100644 41 index 0000000..0c035a7 42 --- /dev/null 43 +++ b/pico/bin/pico2wave.c 44 @@ -0,0 +1,341 @@ 45 +/* pico2wave.c 46 + 47 + * Copyright (C) 2009 Mathieu Parent <math.parent@gmail.com> 48 + * 49 + * Licensed under the Apache License, Version 2.0 (the "License"); 50 + * you may not use this file except in compliance with the License. 51 + * You may obtain a copy of the License at 52 + * 53 + * http://www.apache.org/licenses/LICENSE-2.0 54 + * 55 + * Unless required by applicable law or agreed to in writing, software 56 + * distributed under the License is distributed on an "AS IS" BASIS, 57 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 58 + * See the License for the specific language governing permissions and 59 + * limitations under the License. 60 + * 61 + * Convert text to .wav using svox text-to-speech system. 62 + * 63 + */ 64 + 65 + 66 +#include <popt.h> 67 +#include <stdio.h> 68 +#include <stdlib.h> 69 +#include <string.h> 70 + 71 +#include <picoapi.h> 72 +#include <picoapid.h> 73 +#include <picoos.h> 74 + 75 + 76 +/* adaptation layer defines */ 77 +#define PICO_MEM_SIZE 2500000 78 +#define DummyLen 100000000 79 + 80 +/* string constants */ 81 +#define MAX_OUTBUF_SIZE 128 82 +const char * PICO_LINGWARE_PATH = "./lang/"; 83 +const char * PICO_VOICE_NAME = "PicoVoice"; 84 + 85 +/* supported voices 86 + Pico does not separately specify the voice and locale. */ 87 +const char * picoSupportedLangIso3[] = { "eng", "eng", "deu", "spa", "fra", "ita" }; 88 +const char * picoSupportedCountryIso3[] = { "USA", "GBR", "DEU", "ESP", "FRA", "ITA" }; 89 +const char * picoSupportedLang[] = { "en-US", "en-GB", "de-DE", "es-ES", "fr-FR", "it-IT" }; 90 +const char * picoInternalLang[] = { "en-US", "en-GB", "de-DE", "es-ES", "fr-FR", "it-IT" }; 91 +const char * picoInternalTaLingware[] = { "en-US_ta.bin", "en-GB_ta.bin", "de-DE_ta.bin", "es-ES_ta.bin", "fr-FR_ta.bin", "it-IT_ta.bin" }; 92 +const char * picoInternalSgLingware[] = { "en-US_lh0_sg.bin", "en-GB_kh0_sg.bin", "de-DE_gl0_sg.bin", "es-ES_zl0_sg.bin", "fr-FR_nk0_sg.bin", "it-IT_cm0_sg.bin" }; 93 +const char * picoInternalUtppLingware[] = { "en-US_utpp.bin", "en-GB_utpp.bin", "de-DE_utpp.bin", "es-ES_utpp.bin", "fr-FR_utpp.bin", "it-IT_utpp.bin" }; 94 +const int picoNumSupportedVocs = 6; 95 + 96 +/* adapation layer global variables */ 97 +void * picoMemArea = NULL; 98 +pico_System picoSystem = NULL; 99 +pico_Resource picoTaResource = NULL; 100 +pico_Resource picoSgResource = NULL; 101 +pico_Resource picoUtppResource = NULL; 102 +pico_Engine picoEngine = NULL; 103 +pico_Char * picoTaFileName = NULL; 104 +pico_Char * picoSgFileName = NULL; 105 +pico_Char * picoUtppFileName = NULL; 106 +pico_Char * picoTaResourceName = NULL; 107 +pico_Char * picoSgResourceName = NULL; 108 +pico_Char * picoUtppResourceName = NULL; 109 +int picoSynthAbort = 0; 110 + 111 + 112 +int main(int argc, const char *argv[]) { 113 + char * wavefile = NULL; 114 + char * lang = "en-US"; 115 + int langIndex = -1, langIndexTmp = -1; 116 + char * text; 117 + int8_t * buffer; 118 + size_t bufferSize = 256; 119 + 120 + /* Parsing options */ 121 + poptContext optCon; /* context for parsing command-line options */ 122 + int opt; /* used for argument parsing */ 123 + 124 + struct poptOption optionsTable[] = { 125 + { "wave", 'w', POPT_ARG_STRING, &wavefile, 0, 126 + "Write output to this WAV file (extension SHOULD be .wav)", "filename.wav" }, 127 + { "lang", 'l', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &lang, 0, 128 + "Language", "lang" }, 129 + POPT_AUTOHELP 130 + POPT_TABLEEND 131 + }; 132 + optCon = poptGetContext(NULL, argc, argv, optionsTable, POPT_CONTEXT_POSIXMEHARDER); 133 + poptSetOtherOptionHelp(optCon, "<words>"); 134 + 135 + /* Reporting about invalid extra options */ 136 + while ((opt = poptGetNextOpt(optCon)) != -1) { 137 + switch (opt) { 138 + default: 139 + fprintf(stderr, "Invalid option %s: %s\n", 140 + poptBadOption(optCon, 0), poptStrerror(opt)); 141 + poptPrintHelp(optCon, stderr, 0); 142 + exit(1); 143 + } 144 + } 145 + 146 + /* Mandatory option: --wave */ 147 + if(!wavefile) { 148 + fprintf(stderr, "Mandatory option: %s\n\n", 149 + "--wave=filename.wav"); 150 + poptPrintHelp(optCon, stderr, 0); 151 + exit(1); 152 + } 153 + /* option: --lang */ 154 + for(langIndexTmp =0; langIndexTmp<picoNumSupportedVocs; langIndexTmp++) { 155 + if(!strcmp(picoSupportedLang[langIndexTmp], lang)) { 156 + langIndex = langIndexTmp; 157 + break; 158 + } 159 + } 160 + if(langIndex == -1) { 161 + fprintf(stderr, "Unknown language: %s\nValid languages:\n", 162 + lang); 163 + for(langIndexTmp =0; langIndexTmp<picoNumSupportedVocs; langIndexTmp++) { 164 + fprintf(stderr, "%s\n", picoSupportedLang[langIndexTmp]); 165 + } 166 + lang = "en-US"; 167 + fprintf(stderr, "\n"); 168 + poptPrintHelp(optCon, stderr, 0); 169 + exit(1); 170 + } 171 + 172 + /* Remaining argument is <words> */ 173 + const char **extra_argv; 174 + extra_argv = poptGetArgs(optCon); 175 + if(extra_argv) { 176 + text = (char *) &(*extra_argv)[0]; 177 + } else { 178 + //TODO: stdin not supported yet. 179 + fprintf(stderr, "Missing argument: %s\n\n", 180 + "<words>"); 181 + poptPrintHelp(optCon, stderr, 0); 182 + exit(1); 183 + } 184 + 185 + poptFreeContext(optCon); 186 + 187 + buffer = malloc( bufferSize ); 188 + 189 + int ret, getstatus; 190 + pico_Char * inp = NULL; 191 + pico_Char * local_text = NULL; 192 + short outbuf[MAX_OUTBUF_SIZE/2]; 193 + pico_Int16 bytes_sent, bytes_recv, text_remaining, out_data_type; 194 + pico_Retstring outMessage; 195 + 196 + picoSynthAbort = 0; 197 + 198 + picoMemArea = malloc( PICO_MEM_SIZE ); 199 + if((ret = pico_initialize( picoMemArea, PICO_MEM_SIZE, &picoSystem ))) { 200 + pico_getSystemStatusMessage(picoSystem, ret, outMessage); 201 + fprintf(stderr, "Cannot initialize pico (%i): %s\n", ret, outMessage); 202 + goto terminate; 203 + } 204 + 205 + /* Load the text analysis Lingware resource file. */ 206 + picoTaFileName = (pico_Char *) malloc( PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE ); 207 + strcpy((char *) picoTaFileName, PICO_LINGWARE_PATH); 208 + strcat((char *) picoTaFileName, (const char *) picoInternalTaLingware[langIndex]); 209 + if((ret = pico_loadResource( picoSystem, picoTaFileName, &picoTaResource ))) { 210 + pico_getSystemStatusMessage(picoSystem, ret, outMessage); 211 + fprintf(stderr, "Cannot load text analysis resource file (%i): %s\n", ret, outMessage); 212 + goto unloadTaResource; 213 + } 214 + 215 + /* Load the signal generation Lingware resource file. */ 216 + picoSgFileName = (pico_Char *) malloc( PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE ); 217 + strcpy((char *) picoSgFileName, PICO_LINGWARE_PATH); 218 + strcat((char *) picoSgFileName, (const char *) picoInternalSgLingware[langIndex]); 219 + if((ret = pico_loadResource( picoSystem, picoSgFileName, &picoSgResource ))) { 220 + pico_getSystemStatusMessage(picoSystem, ret, outMessage); 221 + fprintf(stderr, "Cannot load signal generation Lingware resource file (%i): %s\n", ret, outMessage); 222 + goto unloadSgResource; 223 + } 224 + 225 + /* Load the utpp Lingware resource file if exists - NOTE: this file is optional 226 + and is currently not used. Loading is only attempted for future compatibility. 227 + If this file is not present the loading will still succeed. // 228 + picoUtppFileName = (pico_Char *) malloc( PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE ); 229 + strcpy((char *) picoUtppFileName, PICO_LINGWARE_PATH); 230 + strcat((char *) picoUtppFileName, (const char *) picoInternalUtppLingware[langIndex]); 231 + ret = pico_loadResource( picoSystem, picoUtppFileName, &picoUtppResource ); 232 + pico_getSystemStatusMessage(picoSystem, ret, outMessage); 233 + printf("pico_loadResource: %i: %s\n", ret, outMessage); 234 + */ 235 + 236 + /* Get the text analysis resource name. */ 237 + picoTaResourceName = (pico_Char *) malloc( PICO_MAX_RESOURCE_NAME_SIZE ); 238 + if((ret = pico_getResourceName( picoSystem, picoTaResource, (char *) picoTaResourceName ))) { 239 + pico_getSystemStatusMessage(picoSystem, ret, outMessage); 240 + fprintf(stderr, "Cannot get the text analysis resource name (%i): %s\n", ret, outMessage); 241 + goto unloadUtppResource; 242 + } 243 + 244 + /* Get the signal generation resource name. */ 245 + picoSgResourceName = (pico_Char *) malloc( PICO_MAX_RESOURCE_NAME_SIZE ); 246 + if((ret = pico_getResourceName( picoSystem, picoSgResource, (char *) picoSgResourceName ))) { 247 + pico_getSystemStatusMessage(picoSystem, ret, outMessage); 248 + fprintf(stderr, "Cannot get the signal generation resource name (%i): %s\n", ret, outMessage); 249 + goto unloadUtppResource; 250 + } 251 + 252 + 253 + /* Create a voice definition. */ 254 + if((ret = pico_createVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME ))) { 255 + pico_getSystemStatusMessage(picoSystem, ret, outMessage); 256 + fprintf(stderr, "Cannot create voice definition (%i): %s\n", ret, outMessage); 257 + goto unloadUtppResource; 258 + } 259 + 260 + /* Add the text analysis resource to the voice. */ 261 + if((ret = pico_addResourceToVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME, picoTaResourceName ))) { 262 + pico_getSystemStatusMessage(picoSystem, ret, outMessage); 263 + fprintf(stderr, "Cannot add the text analysis resource to the voice (%i): %s\n", ret, outMessage); 264 + goto unloadUtppResource; 265 + } 266 + 267 + /* Add the signal generation resource to the voice. */ 268 + if((ret = pico_addResourceToVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME, picoSgResourceName ))) { 269 + pico_getSystemStatusMessage(picoSystem, ret, outMessage); 270 + fprintf(stderr, "Cannot add the signal generation resource to the voice (%i): %s\n", ret, outMessage); 271 + goto unloadUtppResource; 272 + } 273 + 274 + /* Create a new Pico engine. */ 275 + if((ret = pico_newEngine( picoSystem, (const pico_Char *) PICO_VOICE_NAME, &picoEngine ))) { 276 + pico_getSystemStatusMessage(picoSystem, ret, outMessage); 277 + fprintf(stderr, "Cannot create a new pico engine (%i): %s\n", ret, outMessage); 278 + goto disposeEngine; 279 + } 280 + 281 + local_text = (pico_Char *) text ; 282 + text_remaining = strlen((const char *) local_text) + 1; 283 + 284 + inp = (pico_Char *) local_text; 285 + 286 + size_t bufused = 0; 287 + 288 + picoos_Common common = (picoos_Common) pico_sysGetCommon(picoSystem); 289 + 290 + picoos_SDFile sdOutFile = NULL; 291 + 292 + picoos_bool done = TRUE; 293 + if(TRUE != (done = picoos_sdfOpenOut(common, &sdOutFile, 294 + (picoos_char *) wavefile, SAMPLE_FREQ_16KHZ, PICOOS_ENC_LIN))) 295 + { 296 + fprintf(stderr, "Cannot open output wave file\n"); 297 + ret = 1; 298 + goto disposeEngine; 299 + } 300 + 301 + /* synthesis loop */ 302 + while (text_remaining) { 303 + /* Feed the text into the engine. */ 304 + if((ret = pico_putTextUtf8( picoEngine, inp, text_remaining, &bytes_sent ))) { 305 + pico_getSystemStatusMessage(picoSystem, ret, outMessage); 306 + fprintf(stderr, "Cannot put Text (%i): %s\n", ret, outMessage); 307 + goto disposeEngine; 308 + } 309 + 310 + text_remaining -= bytes_sent; 311 + inp += bytes_sent; 312 + 313 + do { 314 + if (picoSynthAbort) { 315 + goto disposeEngine; 316 + } 317 + /* Retrieve the samples and add them to the buffer. */ 318 + getstatus = pico_getData( picoEngine, (void *) outbuf, 319 + MAX_OUTBUF_SIZE, &bytes_recv, &out_data_type ); 320 + if((getstatus !=PICO_STEP_BUSY) && (getstatus !=PICO_STEP_IDLE)){ 321 + pico_getSystemStatusMessage(picoSystem, getstatus, outMessage); 322 + fprintf(stderr, "Cannot get Data (%i): %s\n", getstatus, outMessage); 323 + goto disposeEngine; 324 + } 325 + if (bytes_recv) { 326 + if ((bufused + bytes_recv) <= bufferSize) { 327 + memcpy(buffer+bufused, (int8_t *) outbuf, bytes_recv); 328 + bufused += bytes_recv; 329 + } else { 330 + done = picoos_sdfPutSamples( 331 + sdOutFile, 332 + bufused / 2, 333 + (picoos_int16*) (buffer)); 334 + bufused = 0; 335 + memcpy(buffer, (int8_t *) outbuf, bytes_recv); 336 + bufused += bytes_recv; 337 + } 338 + } 339 + } while (PICO_STEP_BUSY == getstatus); 340 + /* This chunk of synthesis is finished; pass the remaining samples. */ 341 + if (!picoSynthAbort) { 342 + done = picoos_sdfPutSamples( 343 + sdOutFile, 344 + bufused / 2, 345 + (picoos_int16*) (buffer)); 346 + } 347 + picoSynthAbort = 0; 348 + } 349 + 350 + if(TRUE != (done = picoos_sdfCloseOut(common, &sdOutFile))) 351 + { 352 + fprintf(stderr, "Cannot close output wave file\n"); 353 + ret = 1; 354 + goto disposeEngine; 355 + } 356 + 357 +disposeEngine: 358 + if (picoEngine) { 359 + pico_disposeEngine( picoSystem, &picoEngine ); 360 + pico_releaseVoiceDefinition( picoSystem, (pico_Char *) PICO_VOICE_NAME ); 361 + picoEngine = NULL; 362 + } 363 +unloadUtppResource: 364 + if (picoUtppResource) { 365 + pico_unloadResource( picoSystem, &picoUtppResource ); 366 + picoUtppResource = NULL; 367 + } 368 +unloadSgResource: 369 + if (picoSgResource) { 370 + pico_unloadResource( picoSystem, &picoSgResource ); 371 + picoSgResource = NULL; 372 + } 373 +unloadTaResource: 374 + if (picoTaResource) { 375 + pico_unloadResource( picoSystem, &picoTaResource ); 376 + picoTaResource = NULL; 377 + } 378 +terminate: 379 + if (picoSystem) { 380 + pico_terminate(&picoSystem); 381 + picoSystem = NULL; 382 + } 383 + exit(ret); 384 +} 385 + 386 diff --git a/pico/configure.in b/pico/configure.in 387 index 0afb56d..349eb1d 100644 388 --- a/pico/configure.in 389 +++ b/pico/configure.in 390 @@ -14,3 +14,6 @@ AC_CONFIG_FILES([Makefile]) 391 AC_OUTPUT 392 393 AC_CONFIG_MACRO_DIR([m4]) 394 + 395 +AC_CHECK_LIB(popt, poptGetContext) 396 + 397 -- 398 1.7.1 399