You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

400 lines
15 KiB

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