1
0
Fork 0
flightgear/src/Sound/VoiceSynthesizer.cxx
Florent Rougon 0deaec870a Adapt to SG 952d071c0 (SGSoundSample ctor now takes std::unique_ptr by value)
The aforementioned SG change[1] was done in line with Herb Sutter's
writing at [2] in order to clearly express sink semantics.

[1] 952d071c08/
[2] https://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/
2022-11-08 14:34:24 +01:00

138 lines
4.3 KiB
C++

/*
* VoiceSynthesizer.cxx - wraps flite+hts_engine
* Copyright (C) 2014 Torsten Dreyer - torsten (at) t3r (dot) de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <utility>
#include "VoiceSynthesizer.hxx"
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <simgear/sg_inlines.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/threads/SGThread.hxx>
#include <flite_hts_engine.h>
using std::string;
static const char * VOICE_FILES[] = {
"cmu_us_arctic_slt.htsvoice",
"cstr_uk_female-1.0.htsvoice"
};
class FLITEVoiceSynthesizer::WorkerThread : public SGThread
{
public:
WorkerThread(FLITEVoiceSynthesizer * synthesizer)
: _synthesizer(synthesizer)
{
}
virtual void run();
private:
FLITEVoiceSynthesizer * _synthesizer;
};
void FLITEVoiceSynthesizer::WorkerThread::run()
{
for (;;) {
SynthesizeRequest request = _synthesizer->_requests.pop();
// marker value indicating termination requested
if ((request.speed < 0.0) && (request.volume < 0.0)) {
SG_LOG(SG_SOUND, SG_DEBUG, "FLITE synthesis thread exiting");
return;
}
if ( NULL != request.listener) {
SGSharedPtr<SGSoundSample> sample = _synthesizer->synthesize(request.text, request.volume, request.speed, request.pitch);
request.listener->SoundSampleReady( sample );
}
}
}
SynthesizeRequest SynthesizeRequest::cancelThreadRequest()
{
SynthesizeRequest marker;
marker.volume = -999.0;
marker.speed = -999.0;
return marker;
}
string FLITEVoiceSynthesizer::getVoicePath( voice_t voice )
{
if( voice < 0 || voice >= VOICE_UNKNOWN ) return string("");
SGPath voicePath = globals->get_fg_root() / "ATC" / VOICE_FILES[voice];
return voicePath.utf8Str();
}
string FLITEVoiceSynthesizer::getVoicePath( const string & voice )
{
if( voice == "cmu_us_arctic_slt" ) return getVoicePath(CMU_US_ARCTIC_SLT);
if( voice == "cstr_uk_female" ) return getVoicePath(CSTR_UK_FEMALE);
return getVoicePath(VOICE_UNKNOWN);
}
void FLITEVoiceSynthesizer::synthesize( SynthesizeRequest & request)
{
_requests.push(request);
}
FLITEVoiceSynthesizer::FLITEVoiceSynthesizer(const std::string & voice)
// REVIEW: Memory Leak - 1,696 bytes in 4 blocks are definitely lost in loss record 6,145 of 6,440
: _engine(new Flite_HTS_Engine), _worker(new FLITEVoiceSynthesizer::WorkerThread(this)), _volume(6.0)
{
_volume = fgGetDouble("/sim/sound/voice-synthesizer/volume", _volume );
Flite_HTS_Engine_initialize(_engine);
Flite_HTS_Engine_load(_engine, voice.c_str());
_worker->start();
}
FLITEVoiceSynthesizer::~FLITEVoiceSynthesizer()
{
// push the special marker value
_requests.push(SynthesizeRequest::cancelThreadRequest());
_worker->join();
Flite_HTS_Engine_clear(_engine);
}
SGSoundSample * FLITEVoiceSynthesizer::synthesize(const std::string & text, double volume, double speed, double pitch )
{
SG_CLAMP_RANGE( volume, 0.0, 1.0 );
SG_CLAMP_RANGE( speed, 0.0, 10.0 );
SG_CLAMP_RANGE( pitch, 0.0, 10.0 );
HTS_Engine_set_volume( &_engine->engine, _volume );
HTS_Engine_set_speed( &_engine->engine, 0.8 + 0.4 * speed );
HTS_Engine_add_half_tone(&_engine->engine, -4.0 + 8.0 * pitch );
void* data;
int rate, count;
if ( FALSE == Flite_HTS_Engine_synthesize_samples_mono16(_engine, text.c_str(), &data, &count, &rate)) return NULL;
auto buf = std::unique_ptr<unsigned char, decltype(free)*>{
reinterpret_cast<unsigned char*>( data ),
free
};
return new SGSoundSample(std::move(buf),
count * sizeof(short),
rate,
SG_SAMPLE_MONO16);
}