4 * Created on: Apr 24, 2014
8 #include "VoiceSynthesizer.hxx"
9 #include <Main/globals.hxx>
10 #include <Main/fg_props.hxx>
11 #include <simgear/debug/logstream.hxx>
12 #include <simgear/sound/readwav.hxx>
13 #include <simgear/misc/sg_path.hxx>
14 #include <OpenThreads/Thread>
15 #include <flite_hts_engine.h>
17 class ScopedTempfile {
19 ScopedTempfile( bool keep = false ) : _keep(keep)
21 _name = ::tempnam(globals->get_fg_home().c_str(), "fgvox");
26 if (_name && !_keep) ::unlink(_name);
30 const char * getName() const
43 class FLITEVoiceSynthesizer::WorkerThread: public OpenThreads::Thread {
45 WorkerThread(FLITEVoiceSynthesizer * synthesizer)
46 : _synthesizer(synthesizer)
51 FLITEVoiceSynthesizer * _synthesizer;
54 void FLITEVoiceSynthesizer::WorkerThread::run()
57 SynthesizeRequest request = _synthesizer->_requests.pop();
58 if ( NULL != request.listener) {
59 SGSharedPtr<SGSoundSample> sample = _synthesizer->synthesize(request.text);
60 request.listener->SoundSampleReady( sample );
65 void FLITEVoiceSynthesizer::synthesize( SynthesizeRequest & request)
67 _requests.push(request);
70 FLITEVoiceSynthesizer::FLITEVoiceSynthesizer(const std::string & voice)
71 : _engine(new Flite_HTS_Engine), _worker(new FLITEVoiceSynthesizer::WorkerThread(this)), _volume(6.0), _keepScratchFile(false)
73 _volume = fgGetDouble("/sim/sound/voice-synthesizer/volume", _volume );
74 _keepScratchFile = fgGetBool("/sim/sound/voice-synthesizer/keep-scratch-file", _keepScratchFile);
75 Flite_HTS_Engine_initialize(_engine);
76 Flite_HTS_Engine_load(_engine, voice.c_str());
80 FLITEVoiceSynthesizer::~FLITEVoiceSynthesizer()
84 Flite_HTS_Engine_clear(_engine);
87 SGSoundSample * FLITEVoiceSynthesizer::synthesize(const std::string & text)
89 ScopedTempfile scratch(_keepScratchFile);
90 HTS_Engine_set_volume( &_engine->engine, _volume );
92 if ( FALSE == Flite_HTS_Engine_synthesize(_engine, text.c_str(), scratch.getName())) return NULL;
94 SG_LOG(SG_SOUND, SG_ALERT, "created wav at " << scratch.getPath());
99 ALvoid * data = simgear::loadWAVFromFile(scratch.getPath(), format, size, freqf);
100 SG_LOG(SG_ALL, SG_ALERT, "loaded wav at " << freqf << "Hz size=" << size << " format=" << format);
103 SG_LOG(SG_SOUND, SG_ALERT, "Failed to load wav file " << scratch.getPath());
106 if (format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16) {
108 SG_LOG(SG_SOUND, SG_ALERT, "Warning: STEREO files are not supported for 3D audio effects: " << scratch.getPath());
111 return new SGSoundSample(&data, size, (ALsizei) freqf, format);