From 4f56b50df45cf81370c3a29bd443b91cf5fca1b0 Mon Sep 17 00:00:00 2001 From: Dominik Riebeling Date: Sat, 1 Oct 2011 19:48:58 +0000 Subject: 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 --- rbutil/rbutilqt/base/rbsettings.cpp | 1 + rbutil/rbutilqt/base/rbsettings.h | 1 + rbutil/rbutilqt/base/talkfile.cpp | 1 + rbutil/rbutilqt/base/talkgenerator.cpp | 81 +++++++++++++++++++++++++++++++++- rbutil/rbutilqt/base/talkgenerator.h | 11 +++++ rbutil/rbutilqt/base/voicefile.cpp | 7 ++- rbutil/rbutilqt/base/voicefile.h | 5 ++- rbutil/rbutilqt/configure.cpp | 4 ++ rbutil/rbutilqt/configurefrm.ui | 7 +++ rbutil/rbutilqt/rbutilqt.qrc | 9 ++-- 10 files changed, 119 insertions(+), 8 deletions(-) diff --git a/rbutil/rbutilqt/base/rbsettings.cpp b/rbutil/rbutilqt/base/rbsettings.cpp index 592e5c1148..29c893c66c 100644 --- a/rbutil/rbutilqt/base/rbsettings.cpp +++ b/rbutil/rbutilqt/base/rbsettings.cpp @@ -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", "" }, diff --git a/rbutil/rbutilqt/base/rbsettings.h b/rbutil/rbutilqt/base/rbsettings.h index 277b2197d1..ab001c4916 100644 --- a/rbutil/rbutilqt/base/rbsettings.h +++ b/rbutil/rbutilqt/base/rbsettings.h @@ -42,6 +42,7 @@ class RbSettings : public QObject Platform, Language, Tts, + UseTtsCorrections, LastTalkedFolder, VoiceLanguage, TtsLanguage, diff --git a/rbutil/rbutilqt/base/talkfile.cpp b/rbutil/rbutilqt/base/talkfile.cpp index 3813912347..badb77f42b 100644 --- a/rbutil/rbutilqt/base/talkfile.cpp +++ b/rbutil/rbutilqt/base/talkfile.cpp @@ -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))); diff --git a/rbutil/rbutilqt/base/talkgenerator.cpp b/rbutil/rbutilqt/base/talkgenerator.cpp index 9b0cbf4066..4dffe69a42 100644 --- a/rbutil/rbutilqt/base/talkgenerator.cpp +++ b/rbutil/rbutilqt/base/talkgenerator.cpp @@ -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* 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* 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(); +} diff --git a/rbutil/rbutilqt/base/talkgenerator.h b/rbutil/rbutilqt/base/talkgenerator.h index d0cbcd0af3..8617b27238 100644 --- a/rbutil/rbutilqt/base/talkgenerator.h +++ b/rbutil/rbutilqt/base/talkgenerator.h @@ -67,11 +67,13 @@ public: TalkGenerator(QObject* parent); Status process(QList* 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 m_corrections; }; diff --git a/rbutil/rbutilqt/base/voicefile.cpp b/rbutil/rbutilqt/base/voicefile.cpp index ce4596828f..04825f6d91 100644 --- a/rbutil/rbutilqt/base/voicefile.cpp +++ b/rbutil/rbutilqt/base/voicefile.cpp @@ -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))); diff --git a/rbutil/rbutilqt/base/voicefile.h b/rbutil/rbutilqt/base/voicefile.h index 72f905e4f2..94aea6c643 100644 --- a/rbutil/rbutilqt/base/voicefile.h +++ b/rbutil/rbutilqt/base/voicefile.h @@ -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 diff --git a/rbutil/rbutilqt/configure.cpp b/rbutil/rbutilqt/configure.cpp index 9e1978974f..4a6fb67a43 100644 --- a/rbutil/rbutilqt/configure.cpp +++ b/rbutil/rbutilqt/configure.cpp @@ -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()); } diff --git a/rbutil/rbutilqt/configurefrm.ui b/rbutil/rbutilqt/configurefrm.ui index 5d2de0647b..3c0afdc15b 100644 --- a/rbutil/rbutilqt/configurefrm.ui +++ b/rbutil/rbutilqt/configurefrm.ui @@ -449,6 +449,13 @@ + + + + &Use string corrections for TTS + + + diff --git a/rbutil/rbutilqt/rbutilqt.qrc b/rbutil/rbutilqt/rbutilqt.qrc index 4138db78bd..28ab8fa370 100644 --- a/rbutil/rbutilqt/rbutilqt.qrc +++ b/rbutil/rbutilqt/rbutilqt.qrc @@ -1,12 +1,13 @@ - + ../../docs/CREDITS ../../docs/gpl-2.0.html - + ../../tools/VOICE_PAUSE.wav + ../../tools/voice-corrections.txt - + icons/audio-input-microphone.png icons/bootloader_btn.png icons/dialog-error.png @@ -36,7 +37,7 @@ icons/wizard.jpg ../../docs/logo/rockbox-clef.svg - + rbutil.ini -- cgit v1.2.3