2 * VoiceSynthesizer.cxx - wraps flite+hts_engine
3 * Copyright (C) 2014 Torsten Dreyer - torsten (at) t3r (dot) de
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "VoiceSynthesizer.hxx"
20 #include <Main/globals.hxx>
21 #include <Main/fg_props.hxx>
22 #include <simgear/debug/logstream.hxx>
23 #include <simgear/sound/readwav.hxx>
24 #include <simgear/misc/sg_path.hxx>
25 #include <OpenThreads/Thread>
26 #include <flite_hts_engine.h>
28 class ScopedTempfile {
30 ScopedTempfile( bool keep = false ) : _keep(keep)
32 _name = ::tempnam(globals->get_fg_home().c_str(), "fgvox");
37 if (_name && !_keep) ::unlink(_name);
41 const char * getName() const
54 class FLITEVoiceSynthesizer::WorkerThread: public OpenThreads::Thread {
56 WorkerThread(FLITEVoiceSynthesizer * synthesizer)
57 : _synthesizer(synthesizer)
62 FLITEVoiceSynthesizer * _synthesizer;
65 void FLITEVoiceSynthesizer::WorkerThread::run()
68 SynthesizeRequest request = _synthesizer->_requests.pop();
69 if ( NULL != request.listener) {
70 SGSharedPtr<SGSoundSample> sample = _synthesizer->synthesize(request.text);
71 request.listener->SoundSampleReady( sample );
76 void FLITEVoiceSynthesizer::synthesize( SynthesizeRequest & request)
78 _requests.push(request);
81 FLITEVoiceSynthesizer::FLITEVoiceSynthesizer(const std::string & voice)
82 : _engine(new Flite_HTS_Engine), _worker(new FLITEVoiceSynthesizer::WorkerThread(this)), _volume(6.0), _keepScratchFile(false)
84 _volume = fgGetDouble("/sim/sound/voice-synthesizer/volume", _volume );
85 _keepScratchFile = fgGetBool("/sim/sound/voice-synthesizer/keep-scratch-file", _keepScratchFile);
86 Flite_HTS_Engine_initialize(_engine);
87 Flite_HTS_Engine_load(_engine, voice.c_str());
91 FLITEVoiceSynthesizer::~FLITEVoiceSynthesizer()
95 Flite_HTS_Engine_clear(_engine);
98 SGSoundSample * FLITEVoiceSynthesizer::synthesize(const std::string & text)
100 ScopedTempfile scratch(_keepScratchFile);
101 HTS_Engine_set_volume( &_engine->engine, _volume );
103 if ( FALSE == Flite_HTS_Engine_synthesize(_engine, text.c_str(), scratch.getName())) return NULL;
108 ALvoid * data = simgear::loadWAVFromFile(scratch.getPath(), format, size, freqf);
111 SG_LOG(SG_SOUND, SG_ALERT, "Failed to load wav file " << scratch.getPath());
114 if (format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16) {
116 SG_LOG(SG_SOUND, SG_ALERT, "Warning: STEREO files are not supported for 3D audio effects: " << scratch.getPath());
119 return new SGSoundSample(&data, size, (ALsizei) freqf, format);