]> git.mxchange.org Git - flightgear.git/commitdiff
Use FLITE voices in FGVoiceMgr
authorTorsten Dreyer <torsten@t3r.de>
Wed, 7 May 2014 20:12:23 +0000 (22:12 +0200)
committerTorsten Dreyer <torsten@t3r.de>
Wed, 7 May 2014 20:12:23 +0000 (22:12 +0200)
This patch enables spoken words without the need for external
festival using the existing FGVoiceMgr subsystem and the
properties under /sim/sound/voices
To hear the generated voices, set /sim/sound/voices/enabled=true
at startup

- use FLITEVoiceSynthesizer if a voice has <festival>false</festival>
- use FLITEVoiceSynthesizer if the festival server is unreachable
- decouple FGFLITEVoice from FGVoiceThread

src/Sound/flitevoice.cxx
src/Sound/flitevoice.hxx
src/Sound/voice.cxx

index bc70b5f2e88dbcab10cd8450bd87e896b1aafde4..1c357d445f84205eaf32815ac3afaa9b8a294eb3 100644 (file)
@@ -32,45 +32,50 @@ using std::string;
 
 #include "VoiceSynthesizer.hxx"
 
-FGFLITEVoice::FGFLITEVoice(FGVoiceMgr * mgr, const SGPropertyNode_ptr node)
-    : FGVoice(mgr), _synthesizer( NULL )
+FGFLITEVoice::FGFLITEVoice(FGVoiceMgr * mgr, const SGPropertyNode_ptr node, const char * sampleGroupRefName)
+    : FGVoice(mgr), _synthesizer( NULL)
 {
-  string voice = globals->get_fg_root() + "/ATC/cmu_us_arctic_slt.htsvoice";
-  _synthesizer = new FLITEVoiceSynthesizer( voice.c_str() );
+
+  _sampleName = node->getStringValue("desc", node->getPath().c_str());
+
+  string voice = globals->get_fg_root() + "/ATC/" +
+      node->getStringValue("htsvoice", "cmu_us_arctic_slt.htsvoice");
+
+  _synthesizer = new FLITEVoiceSynthesizer(voice.c_str());
 
   SGSoundMgr *smgr = globals->get_soundmgr();
-  _sgr = smgr->find("atc", true);
+  _sgr = smgr->find(sampleGroupRefName, true);
   _sgr->tie_to_listener();
 
   node->getNode("text", true)->addChangeListener(this);
 
-  SG_LOG(SG_ALL, SG_ALERT, "FLITEVoice initialized");
+  SG_LOG(SG_ALL, SG_INFO, "FLITEVoice initialized for sample-group '" << sampleGroupRefName
+      << "'. Samples will be named '" << _sampleName << "' "
+      << "voice is '" << voice << "'");
 }
 
 FGFLITEVoice::~FGFLITEVoice()
 {
   delete _synthesizer;
-  SG_LOG(SG_ALL, SG_ALERT, "FLITEVoice dtor()");
 }
 
 void FGFLITEVoice::speak(const string & msg)
 {
-  SG_LOG(SG_ALL, SG_ALERT, "FLITEVoice speak(" << msg << ")");
-
-  _sgr->remove("flite");
-
-  string s = simgear::strutils::strip( msg );
-  if( false == s.empty() ) {
-    SGSoundSample * sample = _synthesizer->synthesize( msg, 1.0, 0.5, 0.5 );
-    _sgr->add(sample, "flite");
-    _sgr->set_volume(1.0);
-    _sgr->resume();
-    _sgr->play("flite", true);
+  // this is called from voice.cxx:FGVoiceMgr::FGVoiceThread::run
+  string s = simgear::strutils::strip(msg);
+  if (false == s.empty()) {
+    _sampleQueue.push(_synthesizer->synthesize(msg, 1.0, 0.5, 0.5));
   }
 }
 
 void FGFLITEVoice::update()
 {
-
+  SGSharedPtr<SGSoundSample> sample = _sampleQueue.pop();
+  if (sample.valid()) {
+    _sgr->remove(_sampleName);
+    _sgr->add(sample, _sampleName);
+    _sgr->resume();
+    _sgr->play(_sampleName, false);
+  }
 }
 
index 4322b9d18f026abaa6762749c87b58f1afff7fed..f1315276b3c3584fe32b87f7acf6be154a414a40 100644 (file)
 
 #include "voice.hxx"
 #include <simgear/sound/soundmgr_openal.hxx>
+#include <simgear/threads/SGQueue.hxx>
 
 class VoiceSynthesizer;
 
 class FGFLITEVoice: public FGVoiceMgr::FGVoice {
 public:
-  FGFLITEVoice(FGVoiceMgr *, const SGPropertyNode_ptr);
+  FGFLITEVoice(FGVoiceMgr *, const SGPropertyNode_ptr, const char * sampleGroupRefName = "flite-voice");
   virtual ~FGFLITEVoice();
   virtual void speak(const std::string & msg);
   virtual void update();
+
 private:
   FGFLITEVoice(const FGFLITEVoice & other);
   FGFLITEVoice & operator =(const FGFLITEVoice & other);
 
   SGSharedPtr<SGSampleGroup> _sgr;
   VoiceSynthesizer * _synthesizer;
+  SGLockedQueue<SGSharedPtr<SGSoundSample> > _sampleQueue;
+  std::string _sampleName;
 };
 
 #endif // _FLITEVOICE_HXX
index eec16ba530a5c1efb1c76b1e5d15d0a74e4d2632..25355a949a8e3259633cd18c461aea8dfeefce99 100644 (file)
@@ -93,19 +93,18 @@ void FGVoiceMgr::init()
     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));
+        continue;
       } catch (const std::string& s) {
-        SG_LOG(SG_SOUND, SG_ALERT, "VOICE: " << s);
+        SG_LOG(SG_SOUND, SG_WARN, "failed to create festival voice, falling back to flite voice" );
       }
-    } else {
+    }
 #if defined(ENABLE_FLITE)
-      SG_LOG(SG_ALL,SG_ALERT,"creating flite voice" );
-      _voices.push_back(new FGFLITEVoice(this, voice));
+    SG_LOG(SG_ALL,SG_INFO,"creating flite voice" );
+    _voices.push_back(new FGFLITEVoice(this, voice));
 #else
-      SG_LOG(SG_ALL,SG_ALERT,"non festival voice not supported." );
+    SG_LOG(SG_ALL,SG_ALERT,"non festival voice not supported." );
 #endif
-    }
   }
 
 #if defined(ENABLE_THREADS)