1
0
Fork 0

voice system: all doors in FLITE

Prepare for festival lite generated voices
This commit is contained in:
Torsten Dreyer 2014-04-23 17:09:00 +02:00
parent 19dd46c5b0
commit f6b6cfc645
2 changed files with 123 additions and 87 deletions

View file

@ -30,35 +30,51 @@
#include <Main/fg_props.hxx>
#include "voice.hxx"
#if defined(ENABLE_FLITE)
#include "flitevoice.hxx"
#endif
#define VOICE "/sim/sound/voices"
using std::string;
class FGFestivalVoice : public FGVoiceMgr::FGVoice {
public:
FGFestivalVoice(FGVoiceMgr *, const SGPropertyNode_ptr);
virtual ~FGFestivalVoice();
virtual void speak( const string & msg );
virtual void update();
void setVolume(double);
void setPitch(double);
void setSpeed(double);
private:
SGSocket *_sock;
double _volume;
double _pitch;
double _speed;
SGPropertyNode_ptr _volumeNode;
SGPropertyNode_ptr _pitchNode;
SGPropertyNode_ptr _speedNode;
};
/// MANAGER ///
FGVoiceMgr::FGVoiceMgr() :
#if defined(ENABLE_THREADS)
_thread(NULL),
#endif
_host(fgGetString(VOICE "/host", "localhost")),
_port(fgGetString(VOICE "/port", "1314")),
_enabled(fgGetBool(VOICE "/enabled", false)),
_pausedNode(fgGetNode("/sim/sound/working", true))
_pausedNode(fgGetNode("/sim/sound/working", true)),
_paused(false)
{
#if defined(ENABLE_THREADS)
if (!_enabled)
return;
_thread = new FGVoiceThread(this);
#endif
}
FGVoiceMgr::~FGVoiceMgr()
{
#if defined(ENABLE_THREADS)
if (!_enabled)
return;
_thread->cancel();
_thread->join();
delete _thread;
#endif
}
@ -67,14 +83,30 @@ void FGVoiceMgr::init()
if (!_enabled)
return;
#if defined(ENABLE_THREADS)
_thread = new FGVoiceThread(this);
#endif
SGPropertyNode *base = fgGetNode(VOICE, true);
vector<SGPropertyNode_ptr> voices = base->getChildren("voice");
try {
for (unsigned int i = 0; i < voices.size(); i++)
_voices.push_back(new FGVoice(this, voices[i]));
} catch (const std::string& s) {
SG_LOG(SG_SOUND, SG_ALERT, "VOICE: " << s);
}
for (unsigned int i = 0; i < voices.size(); i++) {
SGPropertyNode_ptr voice = voices[i];
if( voice->getBoolValue("festival", false ) ) {
try {
SG_LOG(SG_ALL,SG_ALERT,"creating festival voice" );
_voices.push_back(new FGFestivalVoice(this, voice));
} catch (const std::string& s) {
SG_LOG(SG_SOUND, SG_ALERT, "VOICE: " << s);
}
} else {
#if defined(ENABLE_FLITE)
SG_LOG(SG_ALL,SG_ALERT,"creating flite voice" );
_voices.push_back(new FGFLITEVoice(this, voice));
#else
SG_LOG(SG_ALL,SG_ALERT,"non festival voice not supported." );
#endif
}
}
#if defined(ENABLE_THREADS)
_thread->setProcessorAffinity(1);
@ -82,6 +114,19 @@ void FGVoiceMgr::init()
#endif
}
void FGVoiceMgr::shutdown()
{
#if defined(ENABLE_THREADS)
_thread->cancel();
_thread->join();
delete _thread;
_thread = NULL;
#endif
for( std::vector<FGVoice*>::iterator it = _voices.begin(); it != _voices.end(); ++it )
delete *it;
}
void FGVoiceMgr::update(double)
{
@ -95,7 +140,6 @@ void FGVoiceMgr::update(double)
_voices[i]->speak();
#endif
}
}
@ -103,12 +147,11 @@ void FGVoiceMgr::update(double)
/// VOICE ///
FGVoiceMgr::FGVoice::FGVoice(FGVoiceMgr *mgr, const SGPropertyNode_ptr node) :
FGFestivalVoice::FGFestivalVoice(FGVoiceMgr *mgr, const SGPropertyNode_ptr node) :
FGVoice(mgr),
_volumeNode(node->getNode("volume", true)),
_pitchNode(node->getNode("pitch", true)),
_speedNode(node->getNode("speed", true)),
_festival(node->getBoolValue("festival", true)),
_mgr(mgr)
_speedNode(node->getNode("speed", true))
{
SG_LOG(SG_SOUND, SG_INFO, "VOICE: adding `" << node->getStringValue("desc", "<unnamed>")
<< "' voice");
@ -120,7 +163,7 @@ FGVoiceMgr::FGVoice::FGVoice(FGVoiceMgr *mgr, const SGPropertyNode_ptr node) :
if (!_sock->open(SG_IO_OUT))
throw string("no connection to `") + host + ':' + port + '\'';
if (_festival) {
{
_sock->writestring("(SayText \"\")\015\012");
char buf[4];
int len = _sock->read(buf, 3);
@ -140,42 +183,59 @@ FGVoiceMgr::FGVoice::FGVoice(FGVoiceMgr *mgr, const SGPropertyNode_ptr node) :
string preamble = node->getStringValue("preamble", "");
if (!preamble.empty())
pushMessage(preamble);
node->getNode("text", true)->addChangeListener(new FGVoiceListener(this));
node->getNode("text", true)->addChangeListener(this);
}
FGVoiceMgr::FGVoice::~FGVoice()
FGFestivalVoice::~FGFestivalVoice()
{
_sock->close();
delete _sock;
}
void FGVoiceMgr::FGVoice::pushMessage(string m)
void FGVoiceMgr::FGVoice::pushMessage( const string & m)
{
_msg.push(m + "\015\012");
_msg.push(m);
#if defined(ENABLE_THREADS)
_mgr->_thread->wake_up();
#endif
}
bool FGVoiceMgr::FGVoice::speak(void)
{
if (_msg.empty())
return false;
if (_msg.empty())
return false;
const string s = _msg.front();
_msg.pop();
const string s = _msg.front();
_msg.pop();
speak(s);
return !_msg.empty();
}
void FGFestivalVoice::speak( const string & msg )
{
if( msg.empty() )
return;
string s;
if( msg[0] == '(' ) {
s = msg;
} else {
s.append("(SayText \"");
s.append(msg).append("\")");
}
s.append("\015\012");
_sock->writestring(s.c_str());
return !_msg.empty();
}
void FGVoiceMgr::FGVoice::update(void)
void FGFestivalVoice::update(void)
{
if (_festival) {
double d;
d = _volumeNode->getDoubleValue();
if (d != _volume)
@ -186,11 +246,10 @@ void FGVoiceMgr::FGVoice::update(void)
d = _speedNode->getDoubleValue();
if (d != _speed)
setSpeed(_speed = d);
}
}
void FGVoiceMgr::FGVoice::setVolume(double d)
void FGFestivalVoice::setVolume(double d)
{
std::ostringstream s;
s << "(set! default_after_synth_hooks (list (lambda (utt)"
@ -199,7 +258,7 @@ void FGVoiceMgr::FGVoice::setVolume(double d)
}
void FGVoiceMgr::FGVoice::setPitch(double d)
void FGFestivalVoice::setPitch(double d)
{
std::ostringstream s;
s << "(set! int_lr_params '((target_f0_mean " << d <<
@ -209,16 +268,13 @@ void FGVoiceMgr::FGVoice::setPitch(double d)
}
void FGVoiceMgr::FGVoice::setSpeed(double d)
void FGFestivalVoice::setSpeed(double d)
{
std::ostringstream s;
s << "(Parameter.set 'Duration_Stretch " << d << ')';
pushMessage(s.str());
}
/// THREAD ///
#if defined(ENABLE_THREADS)
@ -240,9 +296,9 @@ void FGVoiceMgr::FGVoiceThread::run(void)
/// LISTENER ///
void FGVoiceMgr::FGVoice::FGVoiceListener::valueChanged(SGPropertyNode *node)
void FGVoiceMgr::FGVoice::valueChanged(SGPropertyNode *node)
{
if (_voice->_mgr->_paused)
if (_mgr->_paused)
return;
const string s = node->getStringValue();
@ -273,10 +329,8 @@ void FGVoiceMgr::FGVoice::FGVoiceListener::valueChanged(SGPropertyNode *node)
m += c;
}
//cerr << "\033[31;1mAFTER [" << m << "]\033[m" << endl;
if (_voice->_festival)
m = string("(SayText \"") + m + "\")";
_voice->pushMessage(m);
pushMessage(m);
}

View file

@ -55,11 +55,13 @@ public:
FGVoiceMgr();
~FGVoiceMgr();
void init(void);
void shutdown();
void update(double dt);
private:
class FGVoice;
class FGVoice;
protected:
friend class FGFestivalVoice;
#if defined(ENABLE_THREADS)
class FGVoiceThread;
FGVoiceThread *_thread;
@ -86,53 +88,33 @@ private:
void wait_for_jobs() { OpenThreads::ScopedLock<OpenThreads::Mutex> g(_mutex); _jobs.wait(&_mutex); }
OpenThreads::Condition _jobs;
OpenThreads::Mutex _mutex;
protected:
FGVoiceMgr *_mgr;
};
#endif
class FGVoiceMgr::FGVoice {
class FGVoiceMgr::FGVoice : public SGPropertyChangeListener {
public:
FGVoice(FGVoiceMgr *, const SGPropertyNode_ptr);
~FGVoice();
bool speak();
void update();
void setVolume(double);
void setPitch(double);
void setSpeed(double);
void pushMessage(std::string);
FGVoice(FGVoiceMgr * mgr ) : _mgr(mgr) {}
virtual ~FGVoice() {}
virtual void speak( const std::string & msg ) = 0;
virtual void update() = 0;
void pushMessage( const std::string & m);
bool speak();
private:
class FGVoiceListener;
SGSocket *_sock;
double _volume;
double _pitch;
double _speed;
SGPropertyNode_ptr _volumeNode;
SGPropertyNode_ptr _pitchNode;
SGPropertyNode_ptr _speedNode;
bool _festival;
FGVoiceMgr *_mgr;
protected:
void valueChanged(SGPropertyNode *node);
#if defined(ENABLE_THREADS)
SGLockedQueue<std::string> _msg;
FGVoiceMgr *_mgr;
#if defined(ENABLE_THREADS)
SGLockedQueue<std::string> _msg;
#else
std::queue<std::string> _msg;
#endif
};
class FGVoiceMgr::FGVoice::FGVoiceListener : public SGPropertyChangeListener {
public:
FGVoiceListener(FGVoice *voice) : _voice(voice) {}
void valueChanged(SGPropertyNode *node);
private:
FGVoice *_voice;
};
#endif // _VOICE_HXX