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 <interfaces/SpeechSynthInterface.h>
26 #include <utils/time/wait.h>
27 
28 #include <festival/festival.h>
29 
30 using namespace fawkes;
31 
32 /** @class FestivalSynthThread "synth_thread.h"
33  * Festival Synthesis Thread.
34  * This thread synthesises audio for text-to-speech using Festival.
35  * @author Tim Niemueller
36  */
37 
38 
39 /** Constructor. */
41  : Thread("FestivalSynthThread", Thread::OPMODE_WAITFORWAKEUP),
42  BlackBoardInterfaceListener("FestivalSynthThread")
43 {
44 }
45 
46 
47 void
49 {
50  try {
51  __cfg_voice = config->get_string("/plugins/festival/voice");
52  } catch (Exception &e) {
53  __cfg_voice = "";
54  }
55  try {
56  __cfg_extra_code = config->get_string("/plugins/festival/extra_code");
57  } catch (Exception &e) {
58  __cfg_extra_code = "";
59  }
60 
61  __speechsynth_if = blackboard->open_for_writing<SpeechSynthInterface>("Festival");
62 
63  bbil_add_message_interface(__speechsynth_if);
64  blackboard->register_listener(this, BlackBoard::BBIL_FLAG_MESSAGES);
65 
66 }
67 
68 
70 {
71  festival_initialize(/* load init files */ 1, FESTIVAL_HEAP_SIZE);
72  if (__cfg_voice != "") {
73  std::string voice_cmd = "(voice_" + __cfg_voice + ")";
74  if (! festival_eval_command(voice_cmd.c_str())) {
75  logger->log_error(name(), "Failed to load voice %s", __cfg_voice.c_str());
76  }
77  }
78 
79  if (__cfg_extra_code != "") {
80  logger->log_debug(name(), "Executing extra code '%s'", __cfg_extra_code.c_str());
81  if (! festival_eval_command(__cfg_extra_code.c_str())) {
82  logger->log_error(name(), "Failed to execute extra code '%s'", __cfg_extra_code.c_str());
83  }
84  }
85 
86  say("Festival speech synth loaded");
87 }
88 
89 void
91 {
92  festival_tidy_up();
94  blackboard->close(__speechsynth_if);
95 }
96 
97 void
99 {
100  // wait for message(s) to arrive, could take a (little) while after the wakeup
101  while ( __speechsynth_if->msgq_empty() ) {
102  usleep(100);
103  }
104 
105  // process messages, blocking
106  if ( ! __speechsynth_if->msgq_empty() ) {
107  if ( __speechsynth_if->msgq_first_is<SpeechSynthInterface::SayMessage>() ) {
109  __speechsynth_if->set_msgid(msg->id());
110  say(msg->text());
111  }
112 
113  __speechsynth_if->msgq_pop();
114  }
115 }
116 
117 
118 bool
120  Message *message) throw()
121 {
122  wakeup();
123  return true;
124 }
125 
126 
127 /** Say something.
128  * @param text text to synthesize and speak.
129  */
130 void
131 FestivalSynthThread::say(const char *text)
132 {
133  EST_Wave wave;
134  festival_text_to_wave(text, wave);
135 
136  float duration = (float)wave.num_samples() / (float)wave.sample_rate();
137 
138  __speechsynth_if->set_text(text);
139  __speechsynth_if->set_final(false);
140  __speechsynth_if->set_duration(duration);
141  __speechsynth_if->write();
142 
143  Time start;
144  clock->get_systime(start);
145 
146  EST_Option al;
147  play_wave(wave, al);
148 
149  // compensate for data in buffer that still needs to be player, should be
150  // replaced with a call that actually determines the size of the buffer...
151  Time now;
152  clock->get_systime(now);
153  float remaining = duration - (now - &start);
154  if (remaining > 0) {
155  Time waittime(remaining);
156  waittime.wait_systime();
157  }
158 
159  __speechsynth_if->set_final(true);
160  __speechsynth_if->write();
161 }
void set_duration(const float new_duration)
Set duration value.
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:44
unsigned int id() const
Get message ID.
Definition: message.cpp:197
void set_final(const bool new_final)
Set final value.
bool msgq_empty()
Check if queue is empty.
Definition: interface.cpp:1048
Fawkes library namespace.
void get_systime(struct timeval *tv) const
Returns the system time.
Definition: clock.cpp:239
A class for handling time.
Definition: time.h:91
virtual void loop()
Code to execute in the thread.
SayMessage Fawkes BlackBoard Interface Message.
virtual void unregister_listener(BlackBoardInterfaceListener *listener)
Unregister BB interface listener.
Definition: blackboard.cpp:218
Thread class encapsulation of pthreads.
Definition: thread.h:42
void write()
Write from local copy into BlackBoard memory.
Definition: interface.cpp:500
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:79
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:44
void set_msgid(const uint32_t new_msgid)
Set msgid value.
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:45
void wait_systime()
Wait (sleep) for this system time.
Definition: time.cpp:842
virtual void register_listener(BlackBoardInterfaceListener *listener, ListenerRegisterFlag flag=BBIL_FLAG_ALL)
Register BB event listener.
Definition: blackboard.cpp:190
void msgq_pop()
Erase first message from queue.
Definition: interface.cpp:1193
void wakeup()
Wake up thread.
Definition: thread.cpp:1000
Base class for exceptions in Fawkes.
Definition: exception.h:36
void set_text(const char *new_text)
Set text value.
virtual void init()
Initialize the thread.
Message * msgq_first()
Get the first message from the message queue.
Definition: interface.cpp:1180
virtual void finalize()
Finalize the thread.
const char * name() const
Get name of thread.
Definition: thread.h:95
bool msgq_first_is()
Check if first message has desired type.
Definition: interface.h:314
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
FestivalSynthThread()
Constructor.
virtual bool bb_interface_message_received(fawkes::Interface *interface, fawkes::Message *message)
BlackBoard message received notification.
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
virtual void once()
Execute an action exactly once.
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:44
void bbil_add_message_interface(Interface *interface)
Add an interface to the message received watch list.
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
void say(const char *text)
Say something.
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
BlackBoard interface listener.
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:511
SpeechSynthInterface Fawkes BlackBoard Interface.
BlackBoard * blackboard
This is the BlackBoard instance you can use to interact with the BlackBoard.
Definition: blackboard.h:44
virtual void close(Interface *interface)=0
Close interface.