00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "synth_thread.h"
00024
00025 #include <interfaces/SpeechSynthInterface.h>
00026 #include <utils/time/wait.h>
00027 #include <asoundlib.h>
00028 #include <cmath>
00029
00030 using namespace fawkes;
00031
00032 extern "C" {
00033 extern cst_voice *register_cmu_us_kal(const char *voxdir);
00034 extern void unregister_cmu_us_kal(cst_voice *voice);
00035 }
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 FliteSynthThread::FliteSynthThread()
00046 : Thread("FliteSynthThread", Thread::OPMODE_WAITFORWAKEUP),
00047 BlackBoardInterfaceListener("FliteSynthThread")
00048 {
00049 }
00050
00051
00052 void
00053 FliteSynthThread::init()
00054 {
00055 __speechsynth_if = blackboard->open_for_writing<SpeechSynthInterface>("Flite");
00056 __voice = register_cmu_us_kal(NULL);
00057
00058 bbil_add_message_interface(__speechsynth_if);
00059 blackboard->register_listener(this, BlackBoard::BBIL_FLAG_MESSAGES);
00060
00061 say("Speech synth loaded");
00062 }
00063
00064
00065 void
00066 FliteSynthThread::finalize()
00067 {
00068 unregister_cmu_us_kal(__voice);
00069 blackboard->unregister_listener(this);
00070 blackboard->close(__speechsynth_if);
00071 }
00072
00073 void
00074 FliteSynthThread::loop()
00075 {
00076
00077 while ( __speechsynth_if->msgq_empty() ) {
00078 usleep(100);
00079 }
00080
00081
00082
00083 if ( ! __speechsynth_if->msgq_empty() ) {
00084 if ( __speechsynth_if->msgq_first_is<SpeechSynthInterface::SayMessage>() ) {
00085 SpeechSynthInterface::SayMessage *msg = __speechsynth_if->msgq_first<SpeechSynthInterface::SayMessage>();
00086 __speechsynth_if->set_msgid(msg->id());
00087 say(msg->text());
00088 }
00089
00090 __speechsynth_if->msgq_pop();
00091 }
00092 }
00093
00094
00095 bool
00096 FliteSynthThread::bb_interface_message_received(Interface *interface,
00097 Message *message) throw()
00098 {
00099 wakeup();
00100 return true;
00101 }
00102
00103
00104
00105
00106
00107 void
00108 FliteSynthThread::say(const char *text)
00109 {
00110 cst_wave *wave = flite_text_to_wave(text, __voice);
00111 cst_wave_save_riff(wave, "/tmp/test.wav");
00112
00113 __speechsynth_if->set_text(text);
00114 __speechsynth_if->set_final(false);
00115 __speechsynth_if->set_duration(get_duration(wave));
00116 __speechsynth_if->write();
00117
00118 play_wave(wave);
00119 delete_wave(wave);
00120
00121 __speechsynth_if->set_final(true);
00122 __speechsynth_if->write();
00123 }
00124
00125
00126 float
00127 FliteSynthThread::get_duration(cst_wave *wave)
00128 {
00129 return (float)cst_wave_num_samples(wave) / (float)cst_wave_sample_rate(wave);
00130 }
00131
00132
00133
00134
00135
00136 void
00137 FliteSynthThread::play_wave(cst_wave *wave)
00138 {
00139 snd_pcm_t *pcm;
00140 float duration = get_duration(wave);
00141 int err;
00142 if ((err = snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
00143 throw Exception("Failed to open PCM: %s", snd_strerror(err));
00144 }
00145 snd_pcm_nonblock(pcm, 0);
00146 if ((err = snd_pcm_set_params(pcm,
00147 SND_PCM_FORMAT_S16_LE,
00148 SND_PCM_ACCESS_RW_INTERLEAVED,
00149 cst_wave_num_channels(wave),
00150 cst_wave_sample_rate(wave),
00151 1,
00152 (unsigned int)roundf(duration * 1000000.))) < 0) {
00153 throw Exception("Playback to set params: %s", snd_strerror(err));
00154 }
00155
00156 snd_pcm_sframes_t frames;
00157 frames = snd_pcm_writei(pcm, cst_wave_samples(wave), cst_wave_num_samples(wave));
00158 if (frames < 0) {
00159 logger->log_warn(name(), "snd_pcm_writei failed (frames < 0)");
00160 frames = snd_pcm_recover(pcm, frames, 0);
00161 }
00162 if (frames < 0) {
00163 logger->log_warn(name(), "snd_pcm_writei failed: %s", snd_strerror(err));
00164 } else if ( frames < (long)cst_wave_num_samples(wave)) {
00165 logger->log_warn(name(), "Short write (expected %li, wrote %li)",
00166 (long)cst_wave_num_samples(wave), frames);
00167 }
00168
00169 TimeWait::wait_systime((unsigned int)roundf(duration * 1000000.f));
00170 snd_pcm_close(pcm);
00171 }