Voicefile generation: implement string corrections.
Voicefile generation now can correct strings for the TTS system similar to what voice.pl does. The current implementation has some limitations: - only implemented for voicefile creation. - the corrections file is built in and can't get changed. - string corrections can be disabled in the configuration dialog. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30628 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
7f2defc453
commit
4f56b50df4
10 changed files with 119 additions and 8 deletions
|
@ -48,6 +48,7 @@ const static struct {
|
|||
#else
|
||||
{ RbSettings::Tts, "tts", "espeak" },
|
||||
#endif
|
||||
{ RbSettings::UseTtsCorrections, "use_tts_corrections", "true" },
|
||||
{ RbSettings::LastTalkedFolder, "last_talked_folder", "" },
|
||||
{ RbSettings::VoiceLanguage, "voicelanguage", "" },
|
||||
{ RbSettings::TtsLanguage, ":tts:/language", "" },
|
||||
|
|
|
@ -42,6 +42,7 @@ class RbSettings : public QObject
|
|||
Platform,
|
||||
Language,
|
||||
Tts,
|
||||
UseTtsCorrections,
|
||||
LastTalkedFolder,
|
||||
VoiceLanguage,
|
||||
TtsLanguage,
|
||||
|
|
|
@ -50,6 +50,7 @@ bool TalkFileCreator::createTalkFiles()
|
|||
// generate entries
|
||||
{
|
||||
TalkGenerator generator(this);
|
||||
// no string corrections yet: do not set language for TalkGenerator.
|
||||
connect(&generator,SIGNAL(done(bool)),this,SIGNAL(done(bool)));
|
||||
connect(&generator,SIGNAL(logItem(QString,int)),this,SIGNAL(logItem(QString,int)));
|
||||
connect(&generator,SIGNAL(logProgress(int,int)),this,SIGNAL(logProgress(int,int)));
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
TalkGenerator::TalkGenerator(QObject* parent): QObject(parent), encFutureWatcher(this), ttsFutureWatcher(this)
|
||||
{
|
||||
m_userAborted = false;
|
||||
m_lang = "";
|
||||
}
|
||||
|
||||
//! \brief Creates Talkfiles.
|
||||
|
@ -113,6 +114,11 @@ TalkGenerator::Status TalkGenerator::voiceList(QList<TalkEntry>* list,int wavtri
|
|||
(*list)[i].refs.tts = m_tts;
|
||||
(*list)[i].refs.wavtrim = wavtrimth;
|
||||
(*list)[i].refs.generator = this;
|
||||
// enable voice corrections only if a language is set.
|
||||
if(!m_lang.isEmpty()) {
|
||||
QString s = (*list)[i].toSpeak;
|
||||
(*list)[i].toSpeak = correctString(s);
|
||||
}
|
||||
|
||||
// skip duplicated wav entries
|
||||
if(!duplicates.contains(list->at(i).wavfilename))
|
||||
|
@ -247,7 +253,7 @@ TalkGenerator::Status TalkGenerator::encodeList(QList<TalkEntry>* list)
|
|||
TalkGenerators.*/
|
||||
}
|
||||
|
||||
connect(&encFutureWatcher, SIGNAL(progressValueChanged(int)),
|
||||
connect(&encFutureWatcher, SIGNAL(progressValueChanged(int)),
|
||||
this, SLOT(encProgress(int)));
|
||||
encFutureWatcher.setFuture(QtConcurrent::map(*list, &TalkGenerator::encEntryPoint));
|
||||
|
||||
|
@ -302,3 +308,76 @@ void TalkGenerator::abort()
|
|||
m_userAborted = true;
|
||||
}
|
||||
|
||||
QString TalkGenerator::correctString(QString s)
|
||||
{
|
||||
QString corrected = s;
|
||||
int i = 0;
|
||||
int max = m_corrections.size();
|
||||
while(i < max) {
|
||||
corrected = corrected.replace(QRegExp(m_corrections.at(i).search,
|
||||
m_corrections.at(i).modifier.contains("i")
|
||||
? Qt::CaseInsensitive : Qt::CaseSensitive),
|
||||
m_corrections.at(i).replace);
|
||||
i++;
|
||||
}
|
||||
|
||||
if(corrected != s)
|
||||
qDebug() << "[VoiceFileCreator] corrected string" << s << "to" << corrected;
|
||||
|
||||
return corrected;
|
||||
}
|
||||
|
||||
|
||||
void TalkGenerator::setLang(QString name)
|
||||
{
|
||||
m_lang = name;
|
||||
|
||||
// re-initialize corrections list
|
||||
m_corrections.clear();
|
||||
QFile correctionsFile(":/builtin/voice-corrections.txt");
|
||||
correctionsFile.open(QIODevice::ReadOnly);
|
||||
|
||||
QString engine = RbSettings::value(RbSettings::Tts).toString();
|
||||
TTSBase* tts = TTSBase::getTTS(this,RbSettings::value(RbSettings::Tts).toString());
|
||||
QString vendor = tts->voiceVendor();
|
||||
delete tts;
|
||||
|
||||
if(m_lang.isEmpty())
|
||||
m_lang = "english";
|
||||
qDebug() << "[TalkGenerator] building string corrections list for"
|
||||
<< m_lang << engine << vendor;
|
||||
QTextStream stream(&correctionsFile);
|
||||
while(!stream.atEnd()) {
|
||||
QString line = stream.readLine();
|
||||
if(line.startsWith(" ") || line.length() < 10)
|
||||
continue;
|
||||
// separator is first character
|
||||
QString separator = line.at(0);
|
||||
line.remove(0, 1);
|
||||
QStringList items = line.split(separator);
|
||||
// we need to have at least 6 separate entries.
|
||||
if(items.size() < 6)
|
||||
continue;
|
||||
|
||||
QRegExp re_lang(items.at(0));
|
||||
QRegExp re_engine(items.at(1));
|
||||
QRegExp re_vendor(items.at(2));
|
||||
if(!re_lang.exactMatch(m_lang)) {
|
||||
continue;
|
||||
}
|
||||
if(!re_vendor.exactMatch(vendor)) {
|
||||
continue;
|
||||
}
|
||||
if(!re_engine.exactMatch(engine)) {
|
||||
continue;
|
||||
}
|
||||
struct CorrectionItems co;
|
||||
co.search = items.at(3);
|
||||
co.replace = items.at(4);
|
||||
// Qt uses backslash for back references, Perl uses dollar sign.
|
||||
co.replace.replace(QRegExp("\\$(\\d+)"), "\\\\1");
|
||||
co.modifier = items.at(5);
|
||||
m_corrections.append(co);
|
||||
}
|
||||
correctionsFile.close();
|
||||
}
|
||||
|
|
|
@ -67,11 +67,13 @@ public:
|
|||
|
||||
TalkGenerator(QObject* parent);
|
||||
Status process(QList<TalkEntry>* list,int wavtrimth = -1);
|
||||
QString correctString(QString s);
|
||||
|
||||
public slots:
|
||||
void abort();
|
||||
void encProgress(int value);
|
||||
void ttsProgress(int value);
|
||||
void setLang(QString name);
|
||||
|
||||
signals:
|
||||
void done(bool);
|
||||
|
@ -95,6 +97,15 @@ private:
|
|||
|
||||
bool m_ttsWarnings;
|
||||
bool m_userAborted;
|
||||
QString m_lang;
|
||||
|
||||
struct CorrectionItems
|
||||
{
|
||||
QString search;
|
||||
QString replace;
|
||||
QString modifier;
|
||||
};
|
||||
QList<struct CorrectionItems> m_corrections;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -132,6 +132,7 @@ void VoiceFileCreator::downloadDone(bool error)
|
|||
QString id, voice;
|
||||
bool idfound = false;
|
||||
bool voicefound=false;
|
||||
bool useCorrection = RbSettings::value(RbSettings::UseTtsCorrections).toBool();
|
||||
while (!in.atEnd())
|
||||
{
|
||||
QString line = in.readLine();
|
||||
|
@ -151,7 +152,8 @@ void VoiceFileCreator::downloadDone(bool error)
|
|||
TalkGenerator::TalkEntry entry;
|
||||
entry.toSpeak = voice;
|
||||
entry.wavfilename = m_path + "/" + id + ".wav";
|
||||
entry.talkfilename = m_path + "/" + id + ".mp3"; //voicefont wants them with .mp3 extension
|
||||
//voicefont wants them with .mp3 extension
|
||||
entry.talkfilename = m_path + "/" + id + ".mp3";
|
||||
entry.voiced = false;
|
||||
entry.encoded = false;
|
||||
if(id == "VOICE_PAUSE")
|
||||
|
@ -178,6 +180,9 @@ void VoiceFileCreator::downloadDone(bool error)
|
|||
// generate files
|
||||
{
|
||||
TalkGenerator generator(this);
|
||||
// set language for string correction. If not set no correction will be made.
|
||||
if(useCorrection)
|
||||
generator.setLang(m_lang);
|
||||
connect(&generator,SIGNAL(done(bool)),this,SIGNAL(done(bool)));
|
||||
connect(&generator,SIGNAL(logItem(QString,int)),this,SIGNAL(logItem(QString,int)));
|
||||
connect(&generator,SIGNAL(logProgress(int,int)),this,SIGNAL(logProgress(int,int)));
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
bool createVoiceFile();
|
||||
|
||||
void setMountPoint(QString mountpoint) {m_mountpoint =mountpoint; }
|
||||
void setLang(QString name){m_lang =name;}
|
||||
void setLang(QString name) { m_lang = name; }
|
||||
void setWavtrimThreshold(int th){m_wavtrimThreshold = th;}
|
||||
|
||||
public slots:
|
||||
|
@ -56,8 +56,9 @@ private slots:
|
|||
void downloadDone(bool error);
|
||||
|
||||
private:
|
||||
|
||||
void cleanup();
|
||||
|
||||
|
||||
HttpGet *getter;
|
||||
QString filename; //the temporary file
|
||||
QString m_mountpoint; //mountpoint of the device
|
||||
|
|
|
@ -205,6 +205,7 @@ void Config::accept()
|
|||
RbSettings::setValue(RbSettings::CacheOffline, ui.cacheOfflineMode->isChecked());
|
||||
|
||||
// tts settings
|
||||
RbSettings::setValue(RbSettings::UseTtsCorrections, ui.ttsCorrections->isChecked());
|
||||
int i = ui.comboTts->currentIndex();
|
||||
RbSettings::setValue(RbSettings::Tts, ui.comboTts->itemData(i).toString());
|
||||
|
||||
|
@ -288,6 +289,9 @@ void Config::setUserSettings()
|
|||
ui.cacheDisable->setChecked(RbSettings::value(RbSettings::CacheDisabled).toBool());
|
||||
ui.cacheOfflineMode->setChecked(RbSettings::value(RbSettings::CacheOffline).toBool());
|
||||
updateCacheInfo(RbSettings::value(RbSettings::CachePath).toString());
|
||||
|
||||
// TTS tab
|
||||
ui.ttsCorrections->setChecked(RbSettings::value(RbSettings::UseTtsCorrections).toBool());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -449,6 +449,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QCheckBox" name="ttsCorrections">
|
||||
<property name="text">
|
||||
<string>&Use string corrections for TTS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
<RCC>
|
||||
<qresource prefix="/" >
|
||||
<qresource prefix="/">
|
||||
<file>../../docs/CREDITS</file>
|
||||
<file>../../docs/gpl-2.0.html</file>
|
||||
</qresource>
|
||||
<qresource>
|
||||
<qresource>
|
||||
<file alias="builtin/VOICE_PAUSE.wav">../../tools/VOICE_PAUSE.wav</file>
|
||||
<file alias="builtin/voice-corrections.txt">../../tools/voice-corrections.txt</file>
|
||||
</qresource>
|
||||
<qresource prefix="/" >
|
||||
<qresource prefix="/">
|
||||
<file>icons/audio-input-microphone.png</file>
|
||||
<file>icons/bootloader_btn.png</file>
|
||||
<file>icons/dialog-error.png</file>
|
||||
|
@ -36,7 +37,7 @@
|
|||
<file>icons/wizard.jpg</file>
|
||||
<file alias="icons/rockbox-clef.svg">../../docs/logo/rockbox-clef.svg</file>
|
||||
</qresource>
|
||||
<qresource prefix="/ini" >
|
||||
<qresource prefix="/ini">
|
||||
<file>rbutil.ini</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
Loading…
Reference in a new issue