#include "flite_hts_engine.h"
+/* HTS_GStreamSet_get_total_nsamples: get total number of sample */
+size_t HTS_GStreamSet_get_total_nsamples(HTS_GStreamSet * gss);
+
+/* HTS_GStreamSet_get_speech: get synthesized speech parameter */
+double HTS_GStreamSet_get_speech(HTS_GStreamSet * gss, size_t sample_index);
+
#define REGISTER_VOX register_cmu_us_kal
#define UNREGISTER_VOX unregister_cmu_us_kal
return TRUE;
}
+/* Flite_HTS_Engine_synthesize: synthesize speech */
+HTS_Boolean Flite_HTS_Engine_synthesize_samples_mono16(Flite_HTS_Engine * f, const char *txt,
+ void** samples, int* sampleCount, int* sampleRate)
+{
+ int i;
+ cst_voice *v = NULL;
+ cst_utterance *u = NULL;
+ cst_item *s = NULL;
+ char **label_data = NULL;
+ int label_size = 0;
+ short* samplePtr = NULL;
+ HTS_GStreamSet *gss;
+
+ if (txt == NULL)
+ return FALSE;
+
+ /* text analysis part */
+ v = REGISTER_VOX(NULL);
+ if (v == NULL)
+ return FALSE;
+ u = flite_synth_text(txt, v);
+ if (u == NULL)
+ return FALSE;
+ for (s = relation_head(utt_relation(u, "Segment")); s; s = item_next(s))
+ label_size++;
+ if (label_size <= 0)
+ return FALSE;
+ label_data = (char **) calloc(label_size, sizeof(char *));
+ for (i = 0, s = relation_head(utt_relation(u, "Segment")); s; s = item_next(s), i++) {
+ label_data[i] = (char *) calloc(MAXBUFLEN, sizeof(char));
+ Flite_HTS_Engine_create_label(f, s, label_data[i]);
+ }
+
+ /* speech synthesis part */
+ HTS_Engine_synthesize_from_strings(&f->engine, label_data, label_size);
+
+ gss = &f->engine.gss;
+ *sampleRate = f->engine.condition.sampling_frequency;
+ *sampleCount = HTS_GStreamSet_get_total_nsamples(gss);
+ *samples = malloc(sizeof(short) * *sampleCount);
+ samplePtr = *samples;
+
+ for (i=0; i < *sampleCount; ++i) {
+ *samplePtr++ = (short) HTS_GStreamSet_get_speech(gss, i);
+ }
+
+ HTS_Engine_refresh(&f->engine);
+
+ for (i = 0; i < label_size; i++)
+ free(label_data[i]);
+ free(label_data);
+
+ delete_utterance(u);
+ UNREGISTER_VOX(v);
+
+ return TRUE;
+}
+
+
/* Flite_HTS_Engine_clear: free system */
void Flite_HTS_Engine_clear(Flite_HTS_Engine * f)
{
#include <OpenThreads/Thread>
#include <flite_hts_engine.h>
-class ScopedTempfile {
-public:
- ScopedTempfile( bool keep = false ) : _keep(keep)
- {
- _name = ::tempnam(globals->get_fg_home().c_str(), "fgvox");
-
- }
- ~ScopedTempfile()
- {
- if (_name && !_keep) ::unlink(_name);
- ::free(_name);
- }
-
- const char * getName() const
- {
- return _name;
- }
- SGPath getPath()
- {
- return SGPath(_name);
- }
-private:
- char * _name;
- bool _keep;
-};
-
class FLITEVoiceSynthesizer::WorkerThread: public OpenThreads::Thread {
public:
WorkerThread(FLITEVoiceSynthesizer * synthesizer)
}
FLITEVoiceSynthesizer::FLITEVoiceSynthesizer(const std::string & voice)
- : _engine(new Flite_HTS_Engine), _worker(new FLITEVoiceSynthesizer::WorkerThread(this)), _volume(6.0), _keepScratchFile(false)
+ : _engine(new Flite_HTS_Engine), _worker(new FLITEVoiceSynthesizer::WorkerThread(this)), _volume(6.0)
{
_volume = fgGetDouble("/sim/sound/voice-synthesizer/volume", _volume );
- _keepScratchFile = fgGetBool("/sim/sound/voice-synthesizer/keep-scratch-file", _keepScratchFile);
Flite_HTS_Engine_initialize(_engine);
Flite_HTS_Engine_load(_engine, voice.c_str());
_worker->start();
SGSoundSample * FLITEVoiceSynthesizer::synthesize(const std::string & text, double volume, double speed, double pitch )
{
- ScopedTempfile scratch(_keepScratchFile);
-
SG_CLAMP_RANGE( volume, 0.0, 1.0 );
SG_CLAMP_RANGE( speed, 0.0, 1.0 );
SG_CLAMP_RANGE( pitch, 0.0, 1.0 );
HTS_Engine_set_speed( &_engine->engine, 0.8 + 0.4 * speed );
HTS_Engine_add_half_tone(&_engine->engine, -4.0 + 8.0 * pitch );
- if ( FALSE == Flite_HTS_Engine_synthesize(_engine, text.c_str(), scratch.getName())) return NULL;
-
- ALenum format;
- ALsizei size;
- ALfloat freqf;
- ALvoid * data = simgear::loadWAVFromFile(scratch.getPath(), format, size, freqf);
-
- if (data == NULL) {
- SG_LOG(SG_SOUND, SG_ALERT, "Failed to load wav file " << scratch.getPath());
- }
-
- if (format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16) {
- free(data);
- SG_LOG(SG_SOUND, SG_ALERT, "Warning: STEREO files are not supported for 3D audio effects: " << scratch.getPath());
- }
+
+ ALvoid* data;
+ ALsizei rate, count;
+ if ( FALSE == Flite_HTS_Engine_synthesize_samples_mono16(_engine, text.c_str(), &data, &count, &rate)) return NULL;
- return new SGSoundSample(&data, size, (ALsizei) freqf, format);
+ return new SGSoundSample(&data,
+ count * sizeof(short),
+ rate,
+ AL_FORMAT_MONO16);
}