1
0
Fork 0

Be able to control atis speech pitch, volume and speed.

Uses these properties:
    /sim/atis/speed
    /sim/atis/volume
    /sim/atis/pitch

Values 1.0 behave as default. Other values are used to multiply default
settings.

Changes don't take affect immediately. But changing com frequency seems to
often cause an update which will then pick up the new values.
This commit is contained in:
Julian Smith 2020-10-21 23:56:01 +01:00
parent 1a4d3785c4
commit 3591bd8631
2 changed files with 42 additions and 10 deletions

View file

@ -81,6 +81,9 @@ private:
AtisSpeaker::AtisSpeaker() AtisSpeaker::AtisSpeaker()
{ {
_synthesizeRequest.listener = this; _synthesizeRequest.listener = this;
if (!fgHasNode("/sim/atis/speed")) fgSetDouble("/sim/atis/speed", 1);
if (!fgHasNode("/sim/atis/pitch")) fgSetDouble("/sim/atis/pitch", 1);
if (!fgHasNode("/sim/atis/enabled")) fgSetBool("/sim/atis/enabled", true);
} }
AtisSpeaker::~AtisSpeaker() AtisSpeaker::~AtisSpeaker()
@ -115,9 +118,9 @@ void AtisSpeaker::valueChanged(SGPropertyNode * node)
hash += *i; hash += *i;
} }
_synthesizeRequest.speed = (hash % 16) / 16.0; _synthesizeRequest.speed = (hash % 16) / 16.0 * fgGetDouble("/sim/atis/speed", 1);
_synthesizeRequest.pitch = (hash % 16) / 16.0; _synthesizeRequest.pitch = (hash % 16) / 16.0 * fgGetDouble("/sim/atis/pitch", 1);
if( starts_with( _stationId, "K" ) || starts_with( _stationId, "C" ) || if( starts_with( _stationId, "K" ) || starts_with( _stationId, "C" ) ||
starts_with( _stationId, "P" ) ) { starts_with( _stationId, "P" ) ) {
voice = FLITEVoiceSynthesizer::getVoicePath("cmu_us_arctic_slt"); voice = FLITEVoiceSynthesizer::getVoicePath("cmu_us_arctic_slt");
@ -133,7 +136,7 @@ void AtisSpeaker::valueChanged(SGPropertyNode * node)
FGSoundManager * smgr = globals->get_subsystem<FGSoundManager>(); FGSoundManager * smgr = globals->get_subsystem<FGSoundManager>();
assert(smgr != NULL); assert(smgr != NULL);
SG_LOG(SG_INSTR, SG_DEBUG,"AtisSpeaker voice is " << voice ); SG_LOG(SG_INSTR, SG_DEBUG,"node->getPath()=" << node->getPath() << " AtisSpeaker voice is " << voice );
FLITEVoiceSynthesizer * synthesizer = dynamic_cast<FLITEVoiceSynthesizer*>(smgr->getSynthesizer(voice)); FLITEVoiceSynthesizer * synthesizer = dynamic_cast<FLITEVoiceSynthesizer*>(smgr->getSynthesizer(voice));
synthesizer->synthesize(_synthesizeRequest); synthesizer->synthesize(_synthesizeRequest);
@ -484,6 +487,10 @@ private:
PropertyObject<bool> _addNoise; PropertyObject<bool> _addNoise;
PropertyObject<double> _cutoffSignalQuality; PropertyObject<double> _cutoffSignalQuality;
SGPropertyNode_ptr _atis_enabled_node;
bool _atis_enabled_prev;
SGSharedPtr<SGSoundSample> _atis_sample;
std::string _soundPrefix; std::string _soundPrefix;
void stopAudio(); void stopAudio();
void updateAudio(); void updateAudio();
@ -514,6 +521,8 @@ void CommRadioImpl::bind()
_volume_norm = PropertyObject<double>(_rootNode->getNode("volume", true)); _volume_norm = PropertyObject<double>(_rootNode->getNode("volume", true));
_atis = PropertyObject<string>(_rootNode->getNode("atis", true)); _atis = PropertyObject<string>(_rootNode->getNode("atis", true));
if (!fgHasNode("/sim/atis/enabled")) fgSetBool("/sim/atis/enabled", true);
_atis_enabled_node = fgGetNode("/sim/atis/enabled");
_addNoise = PropertyObject<bool>(_rootNode->getNode("add-noise", true)); _addNoise = PropertyObject<bool>(_rootNode->getNode("add-noise", true));
_cutoffSignalQuality = PropertyObject<double>(_rootNode->getNode("cutoff-signal-quality", true)); _cutoffSignalQuality = PropertyObject<double>(_rootNode->getNode("cutoff-signal-quality", true));
@ -682,15 +691,38 @@ void CommRadioImpl::updateAudio()
noiseSample = noise; noiseSample = noise;
} }
bool atis_enabled = _atis_enabled_node->getBoolValue();
int atis_delta = 0;
if (atis_enabled and !_atis_enabled_prev) atis_delta = 1;
if (!atis_enabled and _atis_enabled_prev) atis_delta = -1;
if (_atisSpeaker.hasSpokenAtis()) { if (_atisSpeaker.hasSpokenAtis()) {
// the speaker has created a new atis sample // the speaker has created a new atis sample
// remove previous atis sample // remove previous atis sample
_sampleGroup->remove(atisRef); _sampleGroup->remove(atisRef);
if (!atis_delta and atis_enabled) atis_delta = 1;
SGSharedPtr<SGSoundSample> sample = _atisSpeaker.getSpokenAtis();
_sampleGroup->add(sample, atisRef);
_sampleGroup->play_looped(atisRef);
} }
if (atis_delta == 1) {
// Start play of atis text. We store the most recent sample in _atis_sample
// so that we can resume if /sim/atis/enabled is changed from false to
// true.
SGSharedPtr<SGSoundSample> sample = _atisSpeaker.getSpokenAtis();
if (sample) _atis_sample = sample;
else sample = _atis_sample;
if (sample) {
SG_LOG(SG_INSTR, SG_DEBUG, "starting looped play of atis sample.");
_sampleGroup->add(sample, atisRef);
_sampleGroup->play_looped(atisRef);
}
else {
SG_LOG(SG_INSTR, SG_DEBUG, "no atis sample available");
}
}
if (atis_delta == -1) {
// Stop play of atis text.
_sampleGroup->remove(atisRef);
}
_atis_enabled_prev = atis_enabled;
// adjust volumes // adjust volumes
const bool doSquelch = (_signalQuality_norm < _cutoffSignalQuality); const bool doSquelch = (_signalQuality_norm < _cutoffSignalQuality);

View file

@ -112,8 +112,8 @@ FLITEVoiceSynthesizer::~FLITEVoiceSynthesizer()
SGSoundSample * FLITEVoiceSynthesizer::synthesize(const std::string & text, double volume, double speed, double pitch ) SGSoundSample * FLITEVoiceSynthesizer::synthesize(const std::string & text, double volume, double speed, double pitch )
{ {
SG_CLAMP_RANGE( volume, 0.0, 1.0 ); SG_CLAMP_RANGE( volume, 0.0, 1.0 );
SG_CLAMP_RANGE( speed, 0.0, 1.0 ); SG_CLAMP_RANGE( speed, 0.0, 10.0 );
SG_CLAMP_RANGE( pitch, 0.0, 1.0 ); SG_CLAMP_RANGE( pitch, 0.0, 10.0 );
HTS_Engine_set_volume( &_engine->engine, _volume ); HTS_Engine_set_volume( &_engine->engine, _volume );
HTS_Engine_set_speed( &_engine->engine, 0.8 + 0.4 * speed ); HTS_Engine_set_speed( &_engine->engine, 0.8 + 0.4 * speed );
HTS_Engine_add_half_tone(&_engine->engine, -4.0 + 8.0 * pitch ); HTS_Engine_add_half_tone(&_engine->engine, -4.0 + 8.0 * pitch );