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
29using 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
44void
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
64void
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
85void
87{
88 festival_tidy_up();
90 blackboard->close(speechsynth_if_);
91}
92
93void
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>()) {
106 speechsynth_if_->set_msgid(msg->id());
107 say(msg->text());
108 }
109
110 speechsynth_if_->msgq_pop();
111 }
112}
113
114bool
116{
117 wakeup();
118 return true;
119}
120
121/** Say something.
122 * @param text text to synthesize and speak.
123 */
124void
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}
virtual bool bb_interface_message_received(fawkes::Interface *interface, fawkes::Message *message) noexcept
BlackBoard message received notification.
virtual void loop()
Code to execute in the thread.
virtual void once()
Execute an action exactly once.
void say(const char *text)
Say something.
FestivalSynthThread()
Constructor.
virtual void init()
Initialize the thread.
virtual void finalize()
Finalize the thread.
BlackBoard * blackboard
This is the BlackBoard instance you can use to interact with the BlackBoard.
Definition: blackboard.h:44
BlackBoard interface listener.
void bbil_add_message_interface(Interface *interface)
Add an interface to the message received watch list.
virtual void unregister_listener(BlackBoardInterfaceListener *listener)
Unregister BB interface listener.
Definition: blackboard.cpp:212
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
virtual void register_listener(BlackBoardInterfaceListener *listener, ListenerRegisterFlag flag=BBIL_FLAG_ALL)
Register BB event listener.
Definition: blackboard.cpp:185
virtual void close(Interface *interface)=0
Close interface.
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:42
void get_systime(struct timeval *tv) const
Returns the system time.
Definition: clock.cpp:215
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:41
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
Base class for exceptions in Fawkes.
Definition: exception.h:36
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:80
bool msgq_first_is()
Check if first message has desired type.
Definition: interface.h:351
void msgq_pop()
Erase first message from queue.
Definition: interface.cpp:1215
Message * msgq_first()
Get the first message from the message queue.
Definition: interface.cpp:1200
void write()
Write from local copy into BlackBoard memory.
Definition: interface.cpp:501
bool msgq_empty()
Check if queue is empty.
Definition: interface.cpp:1062
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
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:181
SayMessage Fawkes BlackBoard Interface Message.
SpeechSynthInterface Fawkes BlackBoard Interface.
void set_duration(const float new_duration)
Set duration value.
void set_text(const char *new_text)
Set text value.
void set_msgid(const uint32_t new_msgid)
Set msgid value.
void set_final(const bool new_final)
Set final value.
Thread class encapsulation of pthreads.
Definition: thread.h:46
const char * name() const
Get name of thread.
Definition: thread.h:100
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:499
A class for handling time.
Definition: time.h:93
void wait_systime()
Wait (sleep) for this system time.
Definition: time.cpp:760
Fawkes library namespace.