FS#13984 - Rockbox Utility: Add SAPI5 voice volume control (Alessio Lenzi)

Rockbox Utility currently exposes SAPI5 voice speed but not the SAPI
voice volume. The encoder volume setting is applied after synthesis, so
it cannot prevent clipping or distortion already present in the
generated wave file.

This patch adds a Volume control to the SAPI5 TTS configuration. The
value is passed to the standard SpVoice.Volume property before
synthesis.

Change-Id: Ifa43e55f716f98150e94c86e5e6a6c8bce0ca852
This commit is contained in:
Solomon Peachy 2026-08-25 11:09:09 -04:00
parent 3f1ec2385f
commit fd2b070bb1
5 changed files with 19 additions and 1 deletions

View file

@ -39,7 +39,7 @@ Dim oShell, oArgs, oEnv
Dim oFSO, oStdIn, oStdOut Dim oFSO, oStdIn, oStdOut
Dim bVerbose, bList Dim bVerbose, bList
Dim bMSSP Dim bMSSP
Dim sLanguage, sVoice, sSpeed, sName, sVendor Dim sLanguage, sVoice, sSpeed, sVolume, sName, sVendor
Dim oSpVoice, oSpFS ' SAPI5 voice and filestream Dim oSpVoice, oSpFS ' SAPI5 voice and filestream
Dim oVoice ' for traversing the list of voices Dim oVoice ' for traversing the list of voices
@ -64,6 +64,7 @@ bList = oArgs.Exists("listvoices")
sLanguage = oArgs.Item("language") sLanguage = oArgs.Item("language")
sVoice = oArgs.Item("voice") sVoice = oArgs.Item("voice")
sSpeed = oArgs.Item("speed") sSpeed = oArgs.Item("speed")
sVolume = oArgs.Item("volume")
' Create SAPI5 object ' Create SAPI5 object
If bMSSP Then If bMSSP Then
@ -116,6 +117,8 @@ End If
' Speed selection ' Speed selection
If sSpeed <> "" Then oSpVoice.Rate = sSpeed If sSpeed <> "" Then oSpVoice.Rate = sSpeed
' Volume selection
If sVolume <> "" Then oSpVoice.Volume = sVolume
' Get vendor information, protect from missing attribute ' Get vendor information, protect from missing attribute
sVendor = oSpVoice.Voice.GetAttribute("Vendor") sVendor = oSpVoice.Voice.GetAttribute("Vendor")
If Err.Number <> 0 Then If Err.Number <> 0 Then

View file

@ -77,6 +77,7 @@ const static struct {
{ RbSettings::EncoderNarrowBand, ":encoder:/narrowband", "false" }, { RbSettings::EncoderNarrowBand, ":encoder:/narrowband", "false" },
{ RbSettings::WavtrimThreshold, "wavtrimthreshold", "500"}, { RbSettings::WavtrimThreshold, "wavtrimthreshold", "500"},
{ RbSettings::TtsSpeed, ":tts:/speed", "175" }, { RbSettings::TtsSpeed, ":tts:/speed", "175" },
{ RbSettings::TtsVolume, ":tts:/volume", "100" },
{ RbSettings::EncoderComplexity, ":encoder:/complexity", "10" }, { RbSettings::EncoderComplexity, ":encoder:/complexity", "10" },
{ RbSettings::EncoderQuality, ":encoder:/quality", "-1.0" }, { RbSettings::EncoderQuality, ":encoder:/quality", "-1.0" },
{ RbSettings::EncoderVolume, ":encoder:/volume", "1.0" }, { RbSettings::EncoderVolume, ":encoder:/volume", "1.0" },

View file

@ -69,6 +69,7 @@ class RbSettings : public QObject
WavtrimThreshold, WavtrimThreshold,
EncoderComplexity, EncoderComplexity,
TtsSpeed, TtsSpeed,
TtsVolume,
CacheDisabled, CacheDisabled,
EncoderNarrowBand, EncoderNarrowBand,
EncoderQuality, EncoderQuality,

View file

@ -29,6 +29,7 @@ TTSSapi::TTSSapi(QObject* parent) : TTSBase(parent)
m_TTSTemplate << "/language:%lang"; m_TTSTemplate << "/language:%lang";
m_TTSTemplate << "/voice:%voice"; m_TTSTemplate << "/voice:%voice";
m_TTSTemplate << "/speed:%speed"; m_TTSTemplate << "/speed:%speed";
m_TTSTemplate << "/volume:%volume";
m_TTSTemplate << "%options"; m_TTSTemplate << "%options";
m_TTSVoiceTemplate << "//nologo"; m_TTSVoiceTemplate << "//nologo";
@ -74,6 +75,12 @@ void TTSSapi::generateSettings()
speed = 0; speed = 0;
insertSetting(eSPEED, new EncTtsSetting(this, insertSetting(eSPEED, new EncTtsSetting(this,
EncTtsSetting::eINT, tr("Speed:"), speed, -10, 10)); EncTtsSetting::eINT, tr("Speed:"), speed, -10, 10));
// volume
int volume = RbSettings::subValue(m_TTSType, RbSettings::TtsVolume).toInt();
if(volume > 100 || volume < 0)
volume = 100;
insertSetting(eVOLUME, new EncTtsSetting(this,
EncTtsSetting::eINT, tr("Volume:"), volume, 0, 100));
// options // options
insertSetting(eOPTIONS, new EncTtsSetting(this, insertSetting(eOPTIONS, new EncTtsSetting(this,
EncTtsSetting::eSTRING, tr("Options:"), EncTtsSetting::eSTRING, tr("Options:"),
@ -90,6 +97,8 @@ void TTSSapi::saveSettings()
getSetting(eVOICE)->current().toString()); getSetting(eVOICE)->current().toString());
RbSettings::setSubValue(m_TTSType, RbSettings::TtsSpeed, RbSettings::setSubValue(m_TTSType, RbSettings::TtsSpeed,
getSetting(eSPEED)->current().toInt()); getSetting(eSPEED)->current().toInt());
RbSettings::setSubValue(m_TTSType, RbSettings::TtsVolume,
getSetting(eVOLUME)->current().toInt());
RbSettings::setSubValue(m_TTSType, RbSettings::TtsOptions, RbSettings::setSubValue(m_TTSType, RbSettings::TtsOptions,
getSetting(eOPTIONS)->current().toString()); getSetting(eOPTIONS)->current().toString());
@ -112,6 +121,7 @@ bool TTSSapi::start(QString *errStr)
m_TTSLanguage =RbSettings::subValue(m_TTSType, RbSettings::TtsLanguage).toString(); m_TTSLanguage =RbSettings::subValue(m_TTSType, RbSettings::TtsLanguage).toString();
m_TTSVoice=RbSettings::subValue(m_TTSType, RbSettings::TtsVoice).toString(); m_TTSVoice=RbSettings::subValue(m_TTSType, RbSettings::TtsVoice).toString();
m_TTSSpeed=RbSettings::subValue(m_TTSType, RbSettings::TtsSpeed).toString(); m_TTSSpeed=RbSettings::subValue(m_TTSType, RbSettings::TtsSpeed).toString();
m_TTSVolume=RbSettings::subValue(m_TTSType, RbSettings::TtsVolume).toString();
QFile::remove(QDir::tempPath() +"/sapi_voice.vbs"); QFile::remove(QDir::tempPath() +"/sapi_voice.vbs");
QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs"); QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs");
@ -130,6 +140,7 @@ bool TTSSapi::start(QString *errStr)
exec.replaceInStrings("%lang",m_TTSLanguage); exec.replaceInStrings("%lang",m_TTSLanguage);
exec.replaceInStrings("%voice",m_TTSVoice); exec.replaceInStrings("%voice",m_TTSVoice);
exec.replaceInStrings("%speed",m_TTSSpeed); exec.replaceInStrings("%speed",m_TTSSpeed);
exec.replaceInStrings("%volume",m_TTSVolume);
LOG_INFO() << "Start: cscript " << exec; LOG_INFO() << "Start: cscript " << exec;
voicescript = new QProcess(nullptr); voicescript = new QProcess(nullptr);

View file

@ -31,6 +31,7 @@ class TTSSapi : public TTSBase
eLANGUAGE, eLANGUAGE,
eVOICE, eVOICE,
eSPEED, eSPEED,
eVOLUME,
eOPTIONS eOPTIONS
}; };
@ -64,6 +65,7 @@ class TTSSapi : public TTSBase
QString m_TTSLanguage; QString m_TTSLanguage;
QString m_TTSVoice; QString m_TTSVoice;
QString m_TTSSpeed; QString m_TTSSpeed;
QString m_TTSVolume;
bool m_started; bool m_started;
protected: protected: