Fawkes API  Fawkes Development Version
synth_thread.cpp
1 
2 /***************************************************************************
3  * synth_thread.cpp - Festival synthesis thread
4  *
5  * Created: Tue Oct 28 14:34:14 2008
6  * Copyright 2008 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include "synth_thread.h"
24 
25 #include <festival/festival.h>
26 #include <interfaces/SpeechSynthInterface.h>
27 #include <utils/time/wait.h>
28 
29 using namespace fawkes;
30 
31 /** @class FestivalSynthThread "synth_thread.h"
32  * Festival Synthesis Thread.
33  * This thread synthesises audio for text-to-speech using Festival.
34  * @author Tim Niemueller
35  */
36 
37 /** Constructor. */
39 : Thread("FestivalSynthThread", Thread::OPMODE_WAITFORWAKEUP),
40  BlackBoardInterfaceListener("FestivalSynthThread")
41 {
42 }
43 
44 void
46 {
47  try {
48  cfg_voice_ = config->get_string("/plugins/festival/voice");
49  } catch (Exception &e) {
50  cfg_voice_ = "";
51  }
52  try {
53  cfg_extra_code_ = config->get_string("/plugins/festival/extra_code");
54  } catch (Exception &e) {
55  cfg_extra_code_ = "";
56  }
57 
58  speechsynth_if_ = blackboard->open_for_writing<SpeechSynthInterface>("Festival");
59 
60  bbil_add_message_interface(speechsynth_if_);
61  blackboard->register_listener(this, BlackBoard::BBIL_FLAG_MESSAGES);
62 }
63 
64 void
66 {
67  festival_initialize(/* load init files */ 1, FESTIVAL_HEAP_SIZE);
68  if (cfg_voice_ != "") {
69  std::string voice_cmd = "(voice_" + cfg_voice_ + ")";
70  if (!festival_eval_command(voice_cmd.c_str())) {
71  logger->log_error(name(), "Failed to load voice %s", cfg_voice_.c_str());
72  }
73  }
74 
75  if (cfg_extra_code_ != "") {
76  logger->log_debug(name(), "Executing extra code '%s'", cfg_extra_code_.c_str());
77  if (!festival_eval_command(cfg_extra_code_.c_str())) {
78  logger->log_error(name(), "Failed to execute extra code '%s'", cfg_extra_code_.c_str());
79  }
80  }
81 
82  say("Festival speech synth loaded");
83 }
84 
85 void
87 {
88  festival_tidy_up();
90  blackboard->close(speechsynth_if_);
91 }
92 
93 void
95 {
96  // wait for message(s) to arrive, could take a (little) while after the wakeup
97  while (speechsynth_if_->msgq_empty()) {
98  usleep(100);
99  }
100 
101  // process messages, blocking
102  if (!speechsynth_if_->msgq_empty()) {
103  if (speechsynth_if_->msgq_first_is<SpeechSynthInterface::SayMessage>()) {
105  speechsynth_if_->msgq_first<SpeechSynthInterface::SayMessage>();
106  speechsynth_if_->set_msgid(msg->id());
107  say(msg->text());
108  }
109 
110  speechsynth_if_->msgq_pop();
111  }
112 }
113 
114 bool
116 {
117  wakeup();
118  return true;
119 }
120 
121 /** Say something.
122  * @param text text to synthesize and speak.
123  */
124 void
125 FestivalSynthThread::say(const char *text)
126 {
127  EST_Wave wave;
128  festival_text_to_wave(text, wave);
129 
130  float duration = (float)wave.num_samples() / (float)wave.sample_rate();
131 
132  speechsynth_if_->set_text(text);
133  speechsynth_if_->set_final(false);
134  speechsynth_if_->set_duration(duration);
135  speechsynth_if_->write();
136 
137  Time start;
139 
140  EST_Option al;
141  play_wave(wave, al);
142 
143  // compensate for data in buffer that still needs to be player, should be
144  // replaced with a call that actually determines the size of the buffer...
145  Time now;
146  clock->get_systime(now);
147  float remaining = duration - (now - &start);
148  if (remaining > 0) {
149  Time waittime(remaining);
150  waittime.wait_systime();
151  }
152 
153  speechsynth_if_->set_final(true);
154  speechsynth_if_->write();
155 }
fawkes::Interface::msgq_first_is
bool msgq_first_is()
Check if first message has desired type.
Definition: interface.h:313
fawkes::Interface::msgq_pop
void msgq_pop()
Erase first message from queue.
Definition: interface.cpp:1182
fawkes::Interface::msgq_empty
bool msgq_empty()
Check if queue is empty.
Definition: interface.cpp:1029
fawkes::BlackBoard::register_listener
virtual void register_listener(BlackBoardInterfaceListener *listener, ListenerRegisterFlag flag=BBIL_FLAG_ALL)
Register BB event listener.
Definition: blackboard.cpp:188
fawkes::SpeechSynthInterface::set_final
void set_final(const bool new_final)
Set final value.
Definition: SpeechSynthInterface.cpp:177
fawkes::Message
Definition: message.h:40
FestivalSynthThread::loop
virtual void loop()
Code to execute in the thread.
Definition: synth_thread.cpp:93
fawkes::BlackBoard::unregister_listener
virtual void unregister_listener(BlackBoardInterfaceListener *listener)
Unregister BB interface listener.
Definition: blackboard.cpp:215
fawkes::BlackBoardInterfaceListener
Definition: interface_listener.h:45
fawkes::SpeechSynthInterface::SayMessage::text
char * text() const
Get text value.
Definition: SpeechSynthInterface.cpp:314
fawkes::Thread::name
const char * name() const
Definition: thread.h:99
fawkes::ClockAspect::clock
Clock * clock
Definition: clock.h:53
FestivalSynthThread::FestivalSynthThread
FestivalSynthThread()
Constructor.
Definition: synth_thread.cpp:37
fawkes::SpeechSynthInterface::set_msgid
void set_msgid(const uint32_t new_msgid)
Set msgid value.
Definition: SpeechSynthInterface.cpp:142
FestivalSynthThread::finalize
virtual void finalize()
Finalize the thread.
Definition: synth_thread.cpp:85
fawkes::LoggingAspect::logger
Logger * logger
Definition: logging.h:50
fawkes::BlackBoard::close
virtual void close(Interface *interface)=0
fawkes::Logger::log_error
virtual void log_error(const char *component, const char *format,...)=0
fawkes
FestivalSynthThread::init
virtual void init()
Initialize the thread.
Definition: synth_thread.cpp:44
fawkes::SpeechSynthInterface
Definition: SpeechSynthInterface.h:37
fawkes::Time::wait_systime
void wait_systime()
Wait (sleep) for this system time.
Definition: time.cpp:765
fawkes::BlackBoardInterfaceListener::bbil_add_message_interface
void bbil_add_message_interface(Interface *interface)
Add an interface to the message received watch list.
Definition: interface_listener.cpp:245
fawkes::Interface
Definition: interface.h:77
FestivalSynthThread::bb_interface_message_received
virtual bool bb_interface_message_received(fawkes::Interface *interface, fawkes::Message *message)
BlackBoard message received notification.
Definition: synth_thread.cpp:114
fawkes::Clock::get_systime
void get_systime(struct timeval *tv) const
Returns the system time.
Definition: clock.cpp:220
fawkes::ConfigurableAspect::config
Configuration * config
Definition: configurable.h:50
FestivalSynthThread::say
void say(const char *text)
Say something.
Definition: synth_thread.cpp:124
fawkes::SpeechSynthInterface::SayMessage
Definition: SpeechSynthInterface.h:76
fawkes::SpeechSynthInterface::set_text
void set_text(const char *new_text)
Set text value.
Definition: SpeechSynthInterface.cpp:104
fawkes::Time
Definition: time.h:96
FestivalSynthThread::once
virtual void once()
Execute an action exactly once.
Definition: synth_thread.cpp:64
fawkes::Thread
Definition: thread.h:44
fawkes::BlackBoardAspect::blackboard
BlackBoard * blackboard
Definition: blackboard.h:47
fawkes::Thread::start
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:503
fawkes::Configuration::get_string
virtual std::string get_string(const char *path)=0
fawkes::Message::id
unsigned int id() const
Get message ID.
Definition: message.cpp:184
fawkes::SpeechSynthInterface::set_duration
void set_duration(const float new_duration)
Set duration value.
Definition: SpeechSynthInterface.cpp:216
fawkes::Interface::msgq_first
Message * msgq_first()
Get the first message from the message queue.
Definition: interface.cpp:1167
fawkes::Logger::log_debug
virtual void log_debug(const char *component, const char *format,...)=0
fawkes::Interface::write
void write()
Write from local copy into BlackBoard memory.
Definition: interface.cpp:497
fawkes::BlackBoard::open_for_writing
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
fawkes::Exception
Definition: exception.h:39