]> git.mxchange.org Git - flightgear.git/blob - src/Sound/VoiceSynthesizer.cxx
VoiceSynthesizer: add some test/debug properties
[flightgear.git] / src / Sound / VoiceSynthesizer.cxx
1 /*
2  * VoiceSynthesizer.cxx
3  *
4  *  Created on: Apr 24, 2014
5  *      Author: flightgear
6  */
7
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>
16
17 class ScopedTempfile {
18 public:
19   ScopedTempfile( bool keep = false ) : _keep(keep)
20   {
21     _name = ::tempnam(globals->get_fg_home().c_str(), "fgvox");
22
23   }
24   ~ScopedTempfile()
25   {
26     if (_name && !_keep) ::unlink(_name);
27     ::free(_name);
28   }
29
30   const char * getName() const
31   {
32     return _name;
33   }
34   SGPath getPath()
35   {
36     return SGPath(_name);
37   }
38 private:
39   char * _name;
40   bool _keep;
41 };
42
43 class FLITEVoiceSynthesizer::WorkerThread: public OpenThreads::Thread {
44 public:
45   WorkerThread(FLITEVoiceSynthesizer * synthesizer)
46       : _synthesizer(synthesizer)
47   {
48   }
49   virtual void run();
50 private:
51   FLITEVoiceSynthesizer * _synthesizer;
52 };
53
54 void FLITEVoiceSynthesizer::WorkerThread::run()
55 {
56   for (;;) {
57     SynthesizeRequest request = _synthesizer->_requests.pop();
58     if ( NULL != request.listener) {
59       SGSharedPtr<SGSoundSample> sample = _synthesizer->synthesize(request.text);
60       request.listener->SoundSampleReady( sample );
61     }
62   }
63 }
64
65 void FLITEVoiceSynthesizer::synthesize( SynthesizeRequest & request)
66 {
67   _requests.push(request);
68 }
69
70 FLITEVoiceSynthesizer::FLITEVoiceSynthesizer(const std::string & voice)
71     : _engine(new Flite_HTS_Engine), _worker(new FLITEVoiceSynthesizer::WorkerThread(this)), _volume(6.0), _keepScratchFile(false)
72 {
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());
77   _worker->start();
78 }
79
80 FLITEVoiceSynthesizer::~FLITEVoiceSynthesizer()
81 {
82   _worker->cancel();
83   _worker->join();
84   Flite_HTS_Engine_clear(_engine);
85 }
86
87 SGSoundSample * FLITEVoiceSynthesizer::synthesize(const std::string & text)
88 {
89   ScopedTempfile scratch(_keepScratchFile);
90   HTS_Engine_set_volume( &_engine->engine, _volume );
91
92   if ( FALSE == Flite_HTS_Engine_synthesize(_engine, text.c_str(), scratch.getName())) return NULL;
93
94   SG_LOG(SG_SOUND, SG_ALERT, "created wav at " << scratch.getPath());
95
96   ALenum format;
97   ALsizei size;
98   ALfloat freqf;
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);
101
102   if (data == NULL) {
103     SG_LOG(SG_SOUND, SG_ALERT, "Failed to load wav file " << scratch.getPath());
104   }
105
106   if (format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16) {
107     free(data);
108     SG_LOG(SG_SOUND, SG_ALERT, "Warning: STEREO files are not supported for 3D audio effects: " << scratch.getPath());
109   }
110
111   return new SGSoundSample(&data, size, (ALsizei) freqf, format);
112 }
113