13 #include <yarp/os/Thread.h>
14 #include <yarp/os/Time.h>
15 #include <yarp/os/Stamp.h>
16 #include <yarp/os/LogStream.h>
20 using namespace yarp::os;
21 using namespace yarp::dev;
23 #define PICO_MEM_SIZE 2500000
24 #define DummyLen 100000000
25 #define MAX_OUTBUF_SIZE 128
27 const char * PICO_VOICE_NAME =
"PicoVoice";
30 const char * picoSupportedLangIso3[] = {
"eng",
"eng",
"deu",
"spa",
"fra",
"ita" };
31 const char * picoSupportedCountryIso3[] = {
"USA",
"GBR",
"DEU",
"ESP",
"FRA",
"ITA" };
32 const char * picoSupportedLang[] = {
"en-US",
"en-GB",
"de-DE",
"es-ES",
"fr-FR",
"it-IT" };
33 const char * picoInternalLang[] = {
"en-US",
"en-GB",
"de-DE",
"es-ES",
"fr-FR",
"it-IT" };
34 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" };
35 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" };
36 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" };
37 const int picoNumSupportedVocs = 6;
46 supportedLangs.push_back(
"en-US");
47 supportedLangs.push_back(
"en-GB");
48 supportedLangs.push_back(
"es-ES");
49 supportedLangs.push_back(
"fr-FR");
50 supportedLangs.push_back(
"it-IT");
51 supportedLangs.push_back(
"de-DE");
55 picoTaResource = NULL;
56 picoSgResource = NULL;
57 picoUtppResource = NULL;
59 picoTaFileName = NULL;
60 picoSgFileName = NULL;
61 picoUtppFileName = NULL;
62 picoTaResourceName = NULL;
63 picoSgResourceName = NULL;
64 picoUtppResourceName = NULL;
73 bool Speech::open(yarp::os::Searchable &config)
75 Speech::config.fromString(config.toString());
77 if(config.check(
"pcm-device"))
78 pcmDevice = config.find(
"pcm-device").asString();
79 if(config.check(
"default-language"))
80 if(!setLanguage(config.find(
"default-language").asString())) {
81 yError()<<
"Cannot set the default language to"<<config.find(
"default-language").asString();
85 setPitch(config.check(
"pitch",Value(90)).asInt32());
86 setSpeed(config.check(
"speed",Value(105)).asInt32());
88 lingwareRF.setDefaultContext(config.check(
"lingware-context",Value(
"speech")).asString());
89 lingwareRF.configure(0,NULL);
91 this->yarp().attachAsServer(rpcPort);
93 std::string robot=config.check(
"robot",Value(
"icub")).asString();
94 std::string portName=std::string(
"/"+robot+
"/speech:rpc");
95 if(!rpcPort.open(portName)) {
96 yError()<<
"Cannot open port "<<portName;
106 yInfo()<<
"closing Speech!";
111 bool Speech::threadInit() {
115 void Speech::threadRelease() {
123 bool Speech::playWav(
const std::string& filename) {
126 cmd =
"powershell -c (New-Object Media.SoundPlayer ";
128 cmd +=
").PlaySync()";
133 cmd +=
"--device=\""+pcmDevice+
"\" ";
137 int ret = system(cmd.c_str());
139 yWarning()<<
"Cannot play wave file"<<filename;
145 bool Speech::setLanguage(
const std::string& language) {
146 if(std::find(supportedLangs.begin(),
147 supportedLangs.end(),
148 language) == supportedLangs.end()) {
152 Speech::language = language;
156 bool Speech::setSpeed(
const int16_t speed) {
157 Speech::speed = speed;
161 bool Speech::setPitch(
const int16_t pitch){
162 Speech::pitch = pitch;
166 std::vector<std::string> Speech::getSupportedLang() {
167 return supportedLangs;
170 int16_t Speech::getSpeed() {
174 int16_t Speech::getPitch(){
179 bool Speech::say(
const std::string& text) {
180 std::string waveFile = renderSpeech(text);
181 if(waveFile.size() == 0)
183 return playWav(waveFile);
186 bool Speech::play() {
190 bool Speech::pause() {
194 bool Speech::stop() {
198 const std::string Speech::renderSpeech(
const std::string &text) {
200 char* cmdText = (
char*) std::malloc(text.size()+256);
201 std::string filename;
203 if (
const char* env_tmp = std::getenv(
"TMP"))
206 filename +=
"\\speech.wav";
209 filename =
"speech.wav";
212 filename =
"/tmp/speech.wav";
215 (cmdText,text.size()+255,
216 "<pitch level='%d'><speed level='%d'> %s </speed></pitch>",
217 pitch, speed, text.c_str());
228 const char * lang = language.c_str();
229 int langIndex = -1, langIndexTmp = -1;
230 size_t bufferSize = 256;
234 for(langIndexTmp =0; langIndexTmp<picoNumSupportedVocs; langIndexTmp++) {
235 if(!std::strcmp(picoSupportedLang[langIndexTmp], lang)) {
236 langIndex = langIndexTmp;
240 yAssert(langIndex != -1);
243 pico_Char * inp = NULL;
244 pico_Char * local_text = NULL;
245 short outbuf[MAX_OUTBUF_SIZE/2];
246 pico_Int16 bytes_sent, bytes_recv, text_remaining, out_data_type;
247 pico_Retstring outMessage;
251 picoMemArea = std::malloc( PICO_MEM_SIZE );
252 if((ret = pico_initialize( picoMemArea, PICO_MEM_SIZE, &picoSystem ))) {
253 pico_getSystemStatusMessage(picoSystem, ret, outMessage);
254 std::fprintf(stderr,
"Cannot initialize pico (%i): %s\n", ret, outMessage);
260 picoTaFileName = (pico_Char *) std::malloc( PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE );
261 std::strcpy((
char *) picoTaFileName, lingwareRF.findFileByName(picoInternalTaLingware[langIndex]).c_str());
262 if((ret = pico_loadResource( picoSystem, picoTaFileName, &picoTaResource ))) {
263 pico_getSystemStatusMessage(picoSystem, ret, outMessage);
264 std::fprintf(stderr,
"Cannot load text analysis resource file (%i): %s\n", ret, outMessage);
270 picoSgFileName = (pico_Char *) std::malloc( PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE );
271 std::strcpy((
char *) picoSgFileName, lingwareRF.findFileByName(picoInternalSgLingware[langIndex]).c_str());
272 if((ret = pico_loadResource( picoSystem, picoSgFileName, &picoSgResource ))) {
273 pico_getSystemStatusMessage(picoSystem, ret, outMessage);
274 std::fprintf(stderr,
"Cannot load signal generation Lingware resource file (%i): %s\n", ret, outMessage);
291 picoTaResourceName = (pico_Char *) std::malloc( PICO_MAX_RESOURCE_NAME_SIZE );
292 if((ret = pico_getResourceName( picoSystem, picoTaResource, (
char *) picoTaResourceName ))) {
293 pico_getSystemStatusMessage(picoSystem, ret, outMessage);
294 std::fprintf(stderr,
"Cannot get the text analysis resource name (%i): %s\n", ret, outMessage);
300 picoSgResourceName = (pico_Char *) std::malloc( PICO_MAX_RESOURCE_NAME_SIZE );
301 if((ret = pico_getResourceName( picoSystem, picoSgResource, (
char *) picoSgResourceName ))) {
302 pico_getSystemStatusMessage(picoSystem, ret, outMessage);
303 std::fprintf(stderr,
"Cannot get the signal generation resource name (%i): %s\n", ret, outMessage);
310 if((ret = pico_createVoiceDefinition( picoSystem, (
const pico_Char *) PICO_VOICE_NAME ))) {
311 pico_getSystemStatusMessage(picoSystem, ret, outMessage);
312 std::fprintf(stderr,
"Cannot create voice definition (%i): %s\n", ret, outMessage);
318 if((ret = pico_addResourceToVoiceDefinition( picoSystem, (
const pico_Char *) PICO_VOICE_NAME, picoTaResourceName ))) {
319 pico_getSystemStatusMessage(picoSystem, ret, outMessage);
320 std::fprintf(stderr,
"Cannot add the text analysis resource to the voice (%i): %s\n", ret, outMessage);
326 if((ret = pico_addResourceToVoiceDefinition( picoSystem, (
const pico_Char *) PICO_VOICE_NAME, picoSgResourceName ))) {
327 pico_getSystemStatusMessage(picoSystem, ret, outMessage);
328 std::fprintf(stderr,
"Cannot add the signal generation resource to the voice (%i): %s\n", ret, outMessage);
334 if((ret = pico_newEngine( picoSystem, (
const pico_Char *) PICO_VOICE_NAME, &picoEngine ))) {
335 pico_getSystemStatusMessage(picoSystem, ret, outMessage);
336 std::fprintf(stderr,
"Cannot create a new pico engine (%i): %s\n", ret, outMessage);
341 local_text = (pico_Char *) cmdText;
342 text_remaining = std::strlen((
const char *) local_text) + 1;
344 inp = (pico_Char *) local_text;
348 picoos_Common common = (picoos_Common) pico_sysGetCommon(picoSystem);
350 picoos_SDFile sdOutFile = NULL;
352 picoos_bool done = TRUE;
353 if(TRUE != (done = picoos_sdfOpenOut(common, &sdOutFile,
354 (picoos_char *) filename.c_str(), SAMPLE_FREQ_16KHZ, PICOOS_ENC_LIN)))
356 std::fprintf(stderr,
"Cannot open output wave file\n");
362 int8_t* buffer = (int8_t*) std::malloc( bufferSize );
364 while (text_remaining) {
366 if((ret = pico_putTextUtf8( picoEngine, inp, text_remaining, &bytes_sent ))) {
367 pico_getSystemStatusMessage(picoSystem, ret, outMessage);
368 std::fprintf(stderr,
"Cannot put Text (%i): %s\n", ret, outMessage);
373 text_remaining -= bytes_sent;
376 if (picoSynthAbort) {
381 getstatus = pico_getData( picoEngine, (
void *) outbuf,
382 MAX_OUTBUF_SIZE, &bytes_recv, &out_data_type );
383 if((getstatus !=PICO_STEP_BUSY) && (getstatus !=PICO_STEP_IDLE)){
384 pico_getSystemStatusMessage(picoSystem, getstatus, outMessage);
385 std::fprintf(stderr,
"Cannot get Data (%i): %s\n", getstatus, outMessage);
390 if ((bufused + bytes_recv) <= bufferSize) {
391 std::memcpy(buffer+bufused, (int8_t *) outbuf, bytes_recv);
392 bufused += bytes_recv;
394 done = picoos_sdfPutSamples(
397 (picoos_int16*) (buffer));
399 std::memcpy(buffer, (int8_t *) outbuf, bytes_recv);
400 bufused += bytes_recv;
403 }
while (PICO_STEP_BUSY == getstatus);
405 if (!picoSynthAbort) {
406 done = picoos_sdfPutSamples(
409 (picoos_int16*) (buffer));
414 if(TRUE != (done = picoos_sdfCloseOut(common, &sdOutFile))) {
415 std::fprintf(stderr,
"Cannot close output wave file\n");
427 void Speech::releasePico() {
430 pico_disposeEngine( picoSystem, &picoEngine );
431 pico_releaseVoiceDefinition( picoSystem, (pico_Char *) PICO_VOICE_NAME );
435 if (picoUtppResource) {
436 pico_unloadResource( picoSystem, &picoUtppResource );
437 picoUtppResource = NULL;
440 if (picoSgResource) {
441 pico_unloadResource( picoSystem, &picoSgResource );
442 picoSgResource = NULL;
445 if (picoTaResource) {
446 pico_unloadResource( picoSystem, &picoTaResource );
447 picoTaResource = NULL;
451 pico_terminate(&picoSystem);
455 std::free(picoMemArea);