Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * synth_thread.cpp - Festival synthesis thread 00004 * 00005 * Created: Tue Oct 28 14:34:14 2008 00006 * Copyright 2008 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 00021 */ 00022 00023 #include "synth_thread.h" 00024 00025 #include <interfaces/SpeechSynthInterface.h> 00026 #include <utils/time/wait.h> 00027 00028 #include <festival/festival.h> 00029 00030 using namespace fawkes; 00031 00032 /** @class FestivalSynthThread "synth_thread.h" 00033 * Festival Synthesis Thread. 00034 * This thread synthesises audio for text-to-speech using Festival. 00035 * @author Tim Niemueller 00036 */ 00037 00038 00039 /** Constructor. */ 00040 FestivalSynthThread::FestivalSynthThread() 00041 : Thread("FestivalSynthThread", Thread::OPMODE_WAITFORWAKEUP), 00042 BlackBoardInterfaceListener("FestivalSynthThread") 00043 { 00044 } 00045 00046 00047 void 00048 FestivalSynthThread::init() 00049 { 00050 try { 00051 __cfg_voice = config->get_string("/plugins/festival/voice"); 00052 } catch (Exception &e) { 00053 __cfg_voice = ""; 00054 } 00055 try { 00056 __cfg_extra_code = config->get_string("/plugins/festival/extra_code"); 00057 } catch (Exception &e) { 00058 __cfg_extra_code = ""; 00059 } 00060 00061 __speechsynth_if = blackboard->open_for_writing<SpeechSynthInterface>("Festival"); 00062 00063 bbil_add_message_interface(__speechsynth_if); 00064 blackboard->register_listener(this, BlackBoard::BBIL_FLAG_MESSAGES); 00065 00066 } 00067 00068 00069 void FestivalSynthThread::once() 00070 { 00071 festival_initialize(/* load init files */ 1, FESTIVAL_HEAP_SIZE); 00072 if (__cfg_voice != "") { 00073 std::string voice_cmd = "(voice_" + __cfg_voice + ")"; 00074 if (! festival_eval_command(voice_cmd.c_str())) { 00075 logger->log_error(name(), "Failed to load voice %s", __cfg_voice.c_str()); 00076 } 00077 } 00078 00079 if (__cfg_extra_code != "") { 00080 logger->log_debug(name(), "Executing extra code '%s'", __cfg_extra_code.c_str()); 00081 if (! festival_eval_command(__cfg_extra_code.c_str())) { 00082 logger->log_error(name(), "Failed to execute extra code '%s'", __cfg_extra_code.c_str()); 00083 } 00084 } 00085 00086 say("Festival speech synth loaded"); 00087 } 00088 00089 void 00090 FestivalSynthThread::finalize() 00091 { 00092 festival_tidy_up(); 00093 blackboard->unregister_listener(this); 00094 blackboard->close(__speechsynth_if); 00095 } 00096 00097 void 00098 FestivalSynthThread::loop() 00099 { 00100 // wait for message(s) to arrive, could take a (little) while after the wakeup 00101 while ( __speechsynth_if->msgq_empty() ) { 00102 usleep(100); 00103 } 00104 00105 // process messages, blocking 00106 if ( ! __speechsynth_if->msgq_empty() ) { 00107 if ( __speechsynth_if->msgq_first_is<SpeechSynthInterface::SayMessage>() ) { 00108 SpeechSynthInterface::SayMessage *msg = __speechsynth_if->msgq_first<SpeechSynthInterface::SayMessage>(); 00109 __speechsynth_if->set_msgid(msg->id()); 00110 say(msg->text()); 00111 } 00112 00113 __speechsynth_if->msgq_pop(); 00114 } 00115 } 00116 00117 00118 bool 00119 FestivalSynthThread::bb_interface_message_received(Interface *interface, 00120 Message *message) throw() 00121 { 00122 wakeup(); 00123 return true; 00124 } 00125 00126 00127 /** Say something. 00128 * @param text text to synthesize and speak. 00129 */ 00130 void 00131 FestivalSynthThread::say(const char *text) 00132 { 00133 EST_Wave wave; 00134 festival_text_to_wave(text, wave); 00135 00136 float duration = (float)wave.num_samples() / (float)wave.sample_rate(); 00137 00138 __speechsynth_if->set_text(text); 00139 __speechsynth_if->set_final(false); 00140 __speechsynth_if->set_duration(duration); 00141 __speechsynth_if->write(); 00142 00143 Time start; 00144 clock->get_systime(start); 00145 00146 EST_Option al; 00147 play_wave(wave, al); 00148 00149 // compensate for data in buffer that still needs to be player, should be 00150 // replaced with a call that actually determines the size of the buffer... 00151 Time now; 00152 clock->get_systime(now); 00153 float remaining = duration - (now - &start); 00154 if (remaining > 0) { 00155 Time waittime(remaining); 00156 waittime.wait_systime(); 00157 } 00158 00159 __speechsynth_if->set_final(true); 00160 __speechsynth_if->write(); 00161 }