| From 8bec80dccc9f4fe147a500486813f4e89a0d56d8 Mon Sep 17 00:00:00 2001 |
| From: Mathieu Parent <math.parent@gmail.com> |
| Date: Sun, 25 Oct 2009 15:19:01 +0100 |
| Subject: [PATCH 3/7] pico2wave: Convert text to .wav using svox text-to-speech system. |
| |
| --- |
| pico/.gitignore | 1 + |
| pico/Makefile.am | 7 + |
| pico/bin/pico2wave.c | 341 ++++++++++++++++++++++++++++++++++++++++++++++++++ |
| pico/configure.in | 3 + |
| 4 files changed, 352 insertions(+), 0 deletions(-) |
| create mode 100644 pico/bin/pico2wave.c |
| |
| --- a/pico/.gitignore |
| +++ b/pico/.gitignore |
| @@ -29,4 +29,5 @@ libtool |
| *.lo |
| .libs |
| libttspico.la |
| +pico2wave |
| |
| --- a/pico/Makefile.am |
| +++ b/pico/Makefile.am |
| @@ -34,3 +34,10 @@ libttspico_la_SOURCES = \ |
| lib/picotrns.c \ |
| lib/picowa.c |
| |
| +bin_PROGRAMS = pico2wave |
| +pico2wave_SOURCES = \ |
| + bin/pico2wave.c |
| +pico2wave_LDADD = \ |
| + libttspico.la -lm -lpopt |
| +pico2wave_CFLAGS = -Wall -I lib |
| + |
| --- /dev/null |
| +++ b/pico/bin/pico2wave.c |
| @@ -0,0 +1,342 @@ |
| +/* pico2wave.c |
| + |
| + * Copyright (C) 2009 Mathieu Parent <math.parent@gmail.com> |
| + * |
| + * Licensed under the Apache License, Version 2.0 (the "License"); |
| + * you may not use this file except in compliance with the License. |
| + * You may obtain a copy of the License at |
| + * |
| + * http://www.apache.org/licenses/LICENSE-2.0 |
| + * |
| + * Unless required by applicable law or agreed to in writing, software |
| + * distributed under the License is distributed on an "AS IS" BASIS, |
| + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| + * See the License for the specific language governing permissions and |
| + * limitations under the License. |
| + * |
| + * Convert text to .wav using svox text-to-speech system. |
| + * |
| + */ |
| + |
| + |
| +#include <popt.h> |
| +#include <stdio.h> |
| +#include <stdint.h> |
| +#include <stdlib.h> |
| +#include <string.h> |
| + |
| +#include <picoapi.h> |
| +#include <picoapid.h> |
| +#include <picoos.h> |
| + |
| + |
| +/* adaptation layer defines */ |
| +#define PICO_MEM_SIZE 2500000 |
| +#define DummyLen 100000000 |
| + |
| +/* string constants */ |
| +#define MAX_OUTBUF_SIZE 128 |
| +const char * PICO_LINGWARE_PATH = "./lang/"; |
| +const char * PICO_VOICE_NAME = "PicoVoice"; |
| + |
| +/* supported voices |
| + Pico does not separately specify the voice and locale. */ |
| +const char * picoSupportedLangIso3[] = { "eng", "eng", "deu", "spa", "fra", "ita" }; |
| +const char * picoSupportedCountryIso3[] = { "USA", "GBR", "DEU", "ESP", "FRA", "ITA" }; |
| +const char * picoSupportedLang[] = { "en-US", "en-GB", "de-DE", "es-ES", "fr-FR", "it-IT" }; |
| +const char * picoInternalLang[] = { "en-US", "en-GB", "de-DE", "es-ES", "fr-FR", "it-IT" }; |
| +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" }; |
| +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" }; |
| +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" }; |
| +const int picoNumSupportedVocs = 6; |
| + |
| +/* adapation layer global variables */ |
| +void * picoMemArea = NULL; |
| +pico_System picoSystem = NULL; |
| +pico_Resource picoTaResource = NULL; |
| +pico_Resource picoSgResource = NULL; |
| +pico_Resource picoUtppResource = NULL; |
| +pico_Engine picoEngine = NULL; |
| +pico_Char * picoTaFileName = NULL; |
| +pico_Char * picoSgFileName = NULL; |
| +pico_Char * picoUtppFileName = NULL; |
| +pico_Char * picoTaResourceName = NULL; |
| +pico_Char * picoSgResourceName = NULL; |
| +pico_Char * picoUtppResourceName = NULL; |
| +int picoSynthAbort = 0; |
| + |
| + |
| +int main(int argc, const char *argv[]) { |
| + char * wavefile = NULL; |
| + char * lang = "en-US"; |
| + int langIndex = -1, langIndexTmp = -1; |
| + char * text; |
| + int8_t * buffer; |
| + size_t bufferSize = 256; |
| + |
| + /* Parsing options */ |
| + poptContext optCon; /* context for parsing command-line options */ |
| + int opt; /* used for argument parsing */ |
| + |
| + struct poptOption optionsTable[] = { |
| + { "wave", 'w', POPT_ARG_STRING, &wavefile, 0, |
| + "Write output to this WAV file (extension SHOULD be .wav)", "filename.wav" }, |
| + { "lang", 'l', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &lang, 0, |
| + "Language", "lang" }, |
| + POPT_AUTOHELP |
| + POPT_TABLEEND |
| + }; |
| + optCon = poptGetContext(NULL, argc, argv, optionsTable, POPT_CONTEXT_POSIXMEHARDER); |
| + poptSetOtherOptionHelp(optCon, "<words>"); |
| + |
| + /* Reporting about invalid extra options */ |
| + while ((opt = poptGetNextOpt(optCon)) != -1) { |
| + switch (opt) { |
| + default: |
| + fprintf(stderr, "Invalid option %s: %s\n", |
| + poptBadOption(optCon, 0), poptStrerror(opt)); |
| + poptPrintHelp(optCon, stderr, 0); |
| + exit(1); |
| + } |
| + } |
| + |
| + /* Mandatory option: --wave */ |
| + if(!wavefile) { |
| + fprintf(stderr, "Mandatory option: %s\n\n", |
| + "--wave=filename.wav"); |
| + poptPrintHelp(optCon, stderr, 0); |
| + exit(1); |
| + } |
| + /* option: --lang */ |
| + for(langIndexTmp =0; langIndexTmp<picoNumSupportedVocs; langIndexTmp++) { |
| + if(!strcmp(picoSupportedLang[langIndexTmp], lang)) { |
| + langIndex = langIndexTmp; |
| + break; |
| + } |
| + } |
| + if(langIndex == -1) { |
| + fprintf(stderr, "Unknown language: %s\nValid languages:\n", |
| + lang); |
| + for(langIndexTmp =0; langIndexTmp<picoNumSupportedVocs; langIndexTmp++) { |
| + fprintf(stderr, "%s\n", picoSupportedLang[langIndexTmp]); |
| + } |
| + lang = "en-US"; |
| + fprintf(stderr, "\n"); |
| + poptPrintHelp(optCon, stderr, 0); |
| + exit(1); |
| + } |
| + |
| + /* Remaining argument is <words> */ |
| + const char **extra_argv; |
| + extra_argv = poptGetArgs(optCon); |
| + if(extra_argv) { |
| + text = (char *) &(*extra_argv)[0]; |
| + } else { |
| + //TODO: stdin not supported yet. |
| + fprintf(stderr, "Missing argument: %s\n\n", |
| + "<words>"); |
| + poptPrintHelp(optCon, stderr, 0); |
| + exit(1); |
| + } |
| + |
| + poptFreeContext(optCon); |
| + |
| + buffer = malloc( bufferSize ); |
| + |
| + int ret, getstatus; |
| + pico_Char * inp = NULL; |
| + pico_Char * local_text = NULL; |
| + short outbuf[MAX_OUTBUF_SIZE/2]; |
| + pico_Int16 bytes_sent, bytes_recv, text_remaining, out_data_type; |
| + pico_Retstring outMessage; |
| + |
| + picoSynthAbort = 0; |
| + |
| + picoMemArea = malloc( PICO_MEM_SIZE ); |
| + if((ret = pico_initialize( picoMemArea, PICO_MEM_SIZE, &picoSystem ))) { |
| + pico_getSystemStatusMessage(picoSystem, ret, outMessage); |
| + fprintf(stderr, "Cannot initialize pico (%i): %s\n", ret, outMessage); |
| + goto terminate; |
| + } |
| + |
| + /* Load the text analysis Lingware resource file. */ |
| + picoTaFileName = (pico_Char *) malloc( PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE ); |
| + strcpy((char *) picoTaFileName, PICO_LINGWARE_PATH); |
| + strcat((char *) picoTaFileName, (const char *) picoInternalTaLingware[langIndex]); |
| + if((ret = pico_loadResource( picoSystem, picoTaFileName, &picoTaResource ))) { |
| + pico_getSystemStatusMessage(picoSystem, ret, outMessage); |
| + fprintf(stderr, "Cannot load text analysis resource file (%i): %s\n", ret, outMessage); |
| + goto unloadTaResource; |
| + } |
| + |
| + /* Load the signal generation Lingware resource file. */ |
| + picoSgFileName = (pico_Char *) malloc( PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE ); |
| + strcpy((char *) picoSgFileName, PICO_LINGWARE_PATH); |
| + strcat((char *) picoSgFileName, (const char *) picoInternalSgLingware[langIndex]); |
| + if((ret = pico_loadResource( picoSystem, picoSgFileName, &picoSgResource ))) { |
| + pico_getSystemStatusMessage(picoSystem, ret, outMessage); |
| + fprintf(stderr, "Cannot load signal generation Lingware resource file (%i): %s\n", ret, outMessage); |
| + goto unloadSgResource; |
| + } |
| + |
| + /* Load the utpp Lingware resource file if exists - NOTE: this file is optional |
| + and is currently not used. Loading is only attempted for future compatibility. |
| + If this file is not present the loading will still succeed. // |
| + picoUtppFileName = (pico_Char *) malloc( PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE ); |
| + strcpy((char *) picoUtppFileName, PICO_LINGWARE_PATH); |
| + strcat((char *) picoUtppFileName, (const char *) picoInternalUtppLingware[langIndex]); |
| + ret = pico_loadResource( picoSystem, picoUtppFileName, &picoUtppResource ); |
| + pico_getSystemStatusMessage(picoSystem, ret, outMessage); |
| + printf("pico_loadResource: %i: %s\n", ret, outMessage); |
| + */ |
| + |
| + /* Get the text analysis resource name. */ |
| + picoTaResourceName = (pico_Char *) malloc( PICO_MAX_RESOURCE_NAME_SIZE ); |
| + if((ret = pico_getResourceName( picoSystem, picoTaResource, (char *) picoTaResourceName ))) { |
| + pico_getSystemStatusMessage(picoSystem, ret, outMessage); |
| + fprintf(stderr, "Cannot get the text analysis resource name (%i): %s\n", ret, outMessage); |
| + goto unloadUtppResource; |
| + } |
| + |
| + /* Get the signal generation resource name. */ |
| + picoSgResourceName = (pico_Char *) malloc( PICO_MAX_RESOURCE_NAME_SIZE ); |
| + if((ret = pico_getResourceName( picoSystem, picoSgResource, (char *) picoSgResourceName ))) { |
| + pico_getSystemStatusMessage(picoSystem, ret, outMessage); |
| + fprintf(stderr, "Cannot get the signal generation resource name (%i): %s\n", ret, outMessage); |
| + goto unloadUtppResource; |
| + } |
| + |
| + |
| + /* Create a voice definition. */ |
| + if((ret = pico_createVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME ))) { |
| + pico_getSystemStatusMessage(picoSystem, ret, outMessage); |
| + fprintf(stderr, "Cannot create voice definition (%i): %s\n", ret, outMessage); |
| + goto unloadUtppResource; |
| + } |
| + |
| + /* Add the text analysis resource to the voice. */ |
| + if((ret = pico_addResourceToVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME, picoTaResourceName ))) { |
| + pico_getSystemStatusMessage(picoSystem, ret, outMessage); |
| + fprintf(stderr, "Cannot add the text analysis resource to the voice (%i): %s\n", ret, outMessage); |
| + goto unloadUtppResource; |
| + } |
| + |
| + /* Add the signal generation resource to the voice. */ |
| + if((ret = pico_addResourceToVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME, picoSgResourceName ))) { |
| + pico_getSystemStatusMessage(picoSystem, ret, outMessage); |
| + fprintf(stderr, "Cannot add the signal generation resource to the voice (%i): %s\n", ret, outMessage); |
| + goto unloadUtppResource; |
| + } |
| + |
| + /* Create a new Pico engine. */ |
| + if((ret = pico_newEngine( picoSystem, (const pico_Char *) PICO_VOICE_NAME, &picoEngine ))) { |
| + pico_getSystemStatusMessage(picoSystem, ret, outMessage); |
| + fprintf(stderr, "Cannot create a new pico engine (%i): %s\n", ret, outMessage); |
| + goto disposeEngine; |
| + } |
| + |
| + local_text = (pico_Char *) text ; |
| + text_remaining = strlen((const char *) local_text) + 1; |
| + |
| + inp = (pico_Char *) local_text; |
| + |
| + size_t bufused = 0; |
| + |
| + picoos_Common common = (picoos_Common) pico_sysGetCommon(picoSystem); |
| + |
| + picoos_SDFile sdOutFile = NULL; |
| + |
| + picoos_bool done = TRUE; |
| + if(TRUE != (done = picoos_sdfOpenOut(common, &sdOutFile, |
| + (picoos_char *) wavefile, SAMPLE_FREQ_16KHZ, PICOOS_ENC_LIN))) |
| + { |
| + fprintf(stderr, "Cannot open output wave file\n"); |
| + ret = 1; |
| + goto disposeEngine; |
| + } |
| + |
| + /* synthesis loop */ |
| + while (text_remaining) { |
| + /* Feed the text into the engine. */ |
| + if((ret = pico_putTextUtf8( picoEngine, inp, text_remaining, &bytes_sent ))) { |
| + pico_getSystemStatusMessage(picoSystem, ret, outMessage); |
| + fprintf(stderr, "Cannot put Text (%i): %s\n", ret, outMessage); |
| + goto disposeEngine; |
| + } |
| + |
| + text_remaining -= bytes_sent; |
| + inp += bytes_sent; |
| + |
| + do { |
| + if (picoSynthAbort) { |
| + goto disposeEngine; |
| + } |
| + /* Retrieve the samples and add them to the buffer. */ |
| + getstatus = pico_getData( picoEngine, (void *) outbuf, |
| + MAX_OUTBUF_SIZE, &bytes_recv, &out_data_type ); |
| + if((getstatus !=PICO_STEP_BUSY) && (getstatus !=PICO_STEP_IDLE)){ |
| + pico_getSystemStatusMessage(picoSystem, getstatus, outMessage); |
| + fprintf(stderr, "Cannot get Data (%i): %s\n", getstatus, outMessage); |
| + goto disposeEngine; |
| + } |
| + if (bytes_recv) { |
| + if ((bufused + bytes_recv) <= bufferSize) { |
| + memcpy(buffer+bufused, (int8_t *) outbuf, bytes_recv); |
| + bufused += bytes_recv; |
| + } else { |
| + done = picoos_sdfPutSamples( |
| + sdOutFile, |
| + bufused / 2, |
| + (picoos_int16*) (buffer)); |
| + bufused = 0; |
| + memcpy(buffer, (int8_t *) outbuf, bytes_recv); |
| + bufused += bytes_recv; |
| + } |
| + } |
| + } while (PICO_STEP_BUSY == getstatus); |
| + /* This chunk of synthesis is finished; pass the remaining samples. */ |
| + if (!picoSynthAbort) { |
| + done = picoos_sdfPutSamples( |
| + sdOutFile, |
| + bufused / 2, |
| + (picoos_int16*) (buffer)); |
| + } |
| + picoSynthAbort = 0; |
| + } |
| + |
| + if(TRUE != (done = picoos_sdfCloseOut(common, &sdOutFile))) |
| + { |
| + fprintf(stderr, "Cannot close output wave file\n"); |
| + ret = 1; |
| + goto disposeEngine; |
| + } |
| + |
| +disposeEngine: |
| + if (picoEngine) { |
| + pico_disposeEngine( picoSystem, &picoEngine ); |
| + pico_releaseVoiceDefinition( picoSystem, (pico_Char *) PICO_VOICE_NAME ); |
| + picoEngine = NULL; |
| + } |
| +unloadUtppResource: |
| + if (picoUtppResource) { |
| + pico_unloadResource( picoSystem, &picoUtppResource ); |
| + picoUtppResource = NULL; |
| + } |
| +unloadSgResource: |
| + if (picoSgResource) { |
| + pico_unloadResource( picoSystem, &picoSgResource ); |
| + picoSgResource = NULL; |
| + } |
| +unloadTaResource: |
| + if (picoTaResource) { |
| + pico_unloadResource( picoSystem, &picoTaResource ); |
| + picoTaResource = NULL; |
| + } |
| +terminate: |
| + if (picoSystem) { |
| + pico_terminate(&picoSystem); |
| + picoSystem = NULL; |
| + } |
| + exit(ret); |
| +} |
| + |
| --- a/pico/configure.in |
| +++ b/pico/configure.in |
| @@ -14,3 +14,6 @@ AC_CONFIG_FILES([Makefile]) |
| AC_OUTPUT |
| |
| AC_CONFIG_MACRO_DIR([m4]) |
| + |
| +AC_CHECK_LIB(popt, poptGetContext) |
| + |