]> git.mxchange.org Git - flightgear.git/blob - src/Sound/VoiceSynthesizer.cxx
use flite+hts for metar
[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 <simgear/debug/logstream.hxx>
11 #include <simgear/sound/readwav.hxx>
12 #include <simgear/misc/sg_path.hxx>
13 #include <OpenThreads/Thread>
14 #include <flite_hts_engine.h>
15
16 class ScopedTempfile {
17 public:
18   ScopedTempfile()
19   {
20     _name = ::tempnam(globals->get_fg_home().c_str(), "fgvox");
21
22   }
23   ~ScopedTempfile()
24   {
25     if (_name) ::unlink(_name);
26     ::free(_name);
27   }
28
29   const char * getName() const
30   {
31     return _name;
32   }
33   SGPath getPath()
34   {
35     return SGPath(_name);
36   }
37 private:
38   char * _name;
39 };
40
41 class FLITEVoiceSynthesizer::WorkerThread: public OpenThreads::Thread {
42 public:
43   WorkerThread(FLITEVoiceSynthesizer * synthesizer)
44       : _synthesizer(synthesizer)
45   {
46   }
47   virtual void run();
48 private:
49   FLITEVoiceSynthesizer * _synthesizer;
50 };
51
52 void FLITEVoiceSynthesizer::WorkerThread::run()
53 {
54   for (;;) {
55     SynthesizeRequest request = _synthesizer->_requests.pop();
56     if ( NULL != request.listener) {
57       SGSharedPtr<SGSoundSample> sample = _synthesizer->synthesize(request.text);
58       request.listener->SoundSampleReady( sample );
59     }
60   }
61 }
62
63 void FLITEVoiceSynthesizer::synthesize( SynthesizeRequest & request)
64 {
65   _requests.push(request);
66 }
67
68 FLITEVoiceSynthesizer::FLITEVoiceSynthesizer(const std::string & voice)
69     : _engine(new Flite_HTS_Engine), _worker(new FLITEVoiceSynthesizer::WorkerThread(this))
70 {
71   Flite_HTS_Engine_initialize(_engine);
72   Flite_HTS_Engine_load(_engine, voice.c_str());
73   _worker->start();
74 }
75
76 FLITEVoiceSynthesizer::~FLITEVoiceSynthesizer()
77 {
78   _worker->cancel();
79   _worker->join();
80   Flite_HTS_Engine_clear(_engine);
81 }
82
83 SGSoundSample * FLITEVoiceSynthesizer::synthesize(const std::string & text)
84 {
85   ScopedTempfile scratch;
86   if ( FALSE == Flite_HTS_Engine_synthesize(_engine, text.c_str(), scratch.getName())) return NULL;
87
88   SG_LOG(SG_SOUND, SG_ALERT, "created wav at " << scratch.getPath());
89
90   ALenum format;
91   ALsizei size;
92   ALfloat freqf;
93   ALvoid * data = simgear::loadWAVFromFile(scratch.getPath(), format, size, freqf);
94   SG_LOG(SG_ALL, SG_ALERT, "loaded wav at " << freqf << "Hz size=" << size << " format=" << format);
95
96   if (data == NULL) {
97     SG_LOG(SG_SOUND, SG_ALERT, "Failed to load wav file " << scratch.getPath());
98   }
99
100   if (format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16) {
101     free(data);
102     SG_LOG(SG_SOUND, SG_ALERT, "Warning: STEREO files are not supported for 3D audio effects: " << scratch.getPath());
103   }
104
105   return new SGSoundSample(&data, size, (ALsizei) freqf, format);
106 }
107