From d8c5e394cfd38e6ce4c7658e5f6aa84a88e2e5b8 Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Wed, 7 May 2014 20:09:15 +0200 Subject: [PATCH] Render voice to memory, no more temp files. Thanks you James --- .../include/flite_hts_engine.h | 3 + .../flite_hts_engine/lib/flite_hts_engine.c | 65 +++++++++++++++++++ src/Sound/VoiceSynthesizer.cxx | 55 +++------------- src/Sound/VoiceSynthesizer.hxx | 1 - 4 files changed, 77 insertions(+), 47 deletions(-) diff --git a/3rdparty/flite_hts_engine/include/flite_hts_engine.h b/3rdparty/flite_hts_engine/include/flite_hts_engine.h index 4fa5e65dc..e8a07855c 100644 --- a/3rdparty/flite_hts_engine/include/flite_hts_engine.h +++ b/3rdparty/flite_hts_engine/include/flite_hts_engine.h @@ -97,6 +97,9 @@ void Flite_HTS_Engine_set_speed(Flite_HTS_Engine * engine, double f); /* Flite_HTS_Engine_synthesize: synthesize speech */ HTS_Boolean Flite_HTS_Engine_synthesize(Flite_HTS_Engine * f, const char *txt, const char *wav); +HTS_Boolean Flite_HTS_Engine_synthesize_samples_mono16(Flite_HTS_Engine * f, const char *txt, + void** samples, int* sampleCount, int* sampleRate); + /* Flite_HTS_Engine_clear: free system */ void Flite_HTS_Engine_clear(Flite_HTS_Engine * f); diff --git a/3rdparty/flite_hts_engine/lib/flite_hts_engine.c b/3rdparty/flite_hts_engine/lib/flite_hts_engine.c index 451350960..0e81c8fb6 100644 --- a/3rdparty/flite_hts_engine/lib/flite_hts_engine.c +++ b/3rdparty/flite_hts_engine/lib/flite_hts_engine.c @@ -63,6 +63,12 @@ #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 @@ -243,6 +249,65 @@ HTS_Boolean Flite_HTS_Engine_synthesize(Flite_HTS_Engine * f, const char *txt, c 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) { diff --git a/src/Sound/VoiceSynthesizer.cxx b/src/Sound/VoiceSynthesizer.cxx index 66100217a..2a8aafee7 100644 --- a/src/Sound/VoiceSynthesizer.cxx +++ b/src/Sound/VoiceSynthesizer.cxx @@ -26,32 +26,6 @@ #include #include -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) @@ -80,10 +54,9 @@ void FLITEVoiceSynthesizer::synthesize( SynthesizeRequest & request) } 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(); @@ -98,8 +71,6 @@ FLITEVoiceSynthesizer::~FLITEVoiceSynthesizer() 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 ); @@ -107,22 +78,14 @@ SGSoundSample * FLITEVoiceSynthesizer::synthesize(const std::string & text, doub 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; + + ALvoid* data; + ALsizei rate, count; + if ( FALSE == Flite_HTS_Engine_synthesize_samples_mono16(_engine, text.c_str(), &data, &count, &rate)) 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()); - } - - return new SGSoundSample(&data, size, (ALsizei) freqf, format); + return new SGSoundSample(&data, + count * sizeof(short), + rate, + AL_FORMAT_MONO16); } diff --git a/src/Sound/VoiceSynthesizer.hxx b/src/Sound/VoiceSynthesizer.hxx index e6e36fab0..1b8648a21 100644 --- a/src/Sound/VoiceSynthesizer.hxx +++ b/src/Sound/VoiceSynthesizer.hxx @@ -91,7 +91,6 @@ private: SynthesizeRequestList _requests; double _volume; - bool _keepScratchFile; }; #endif /* VOICESYNTHESIZER_HXX_ */