From a8c1934c9d8d3618b78a2a15788f6d3cf5040ca4 Mon Sep 17 00:00:00 2001 From: Dominik Wenger Date: Fri, 4 Jun 2010 21:22:25 +0000 Subject: rbutil: Make TTS and encoders run on all cores \n FS#11160 by Delyan Kratunov git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26558 a1c6a512-1295-4272-9138-f99709370657 --- rbutil/rbutilqt/base/talkgenerator.cpp | 220 ++++++++++++++++++++------------- 1 file changed, 131 insertions(+), 89 deletions(-) (limited to 'rbutil/rbutilqt/base/talkgenerator.cpp') diff --git a/rbutil/rbutilqt/base/talkgenerator.cpp b/rbutil/rbutilqt/base/talkgenerator.cpp index 5c0f8e985b..bc7e5f18b0 100644 --- a/rbutil/rbutilqt/base/talkgenerator.cpp +++ b/rbutil/rbutilqt/base/talkgenerator.cpp @@ -22,7 +22,7 @@ #include "systeminfo.h" #include "wavtrim.h" -TalkGenerator::TalkGenerator(QObject* parent): QObject(parent) +TalkGenerator::TalkGenerator(QObject* parent): QObject(parent), encFutureWatcher(this), ttsFutureWatcher(this) { } @@ -31,7 +31,6 @@ TalkGenerator::TalkGenerator(QObject* parent): QObject(parent) //! TalkGenerator::Status TalkGenerator::process(QList* list,int wavtrimth) { - m_abort = false; QString errStr; bool warnings = false; @@ -104,136 +103,179 @@ TalkGenerator::Status TalkGenerator::process(QList* list,int wavtrimt //! TalkGenerator::Status TalkGenerator::voiceList(QList* list,int wavtrimth) { - int progressMax = list->size(); - int m_progress = 0; - emit logProgress(m_progress,progressMax); + emit logProgress(0, list->size()); - QStringList errors; - QStringList dublicates; + QStringList duplicates; - bool warnings = false; + m_ttsWarnings = false; for(int i=0; i < list->size(); i++) { - if(m_abort) - { - emit logItem(tr("Voicing aborted"), LOGERROR); - return eERROR; - } + (*list)[i].refs.tts = m_tts; + (*list)[i].refs.wavtrim = wavtrimth; + (*list)[i].refs.generator = this; - // skip dublicated wav entrys - if(!dublicates.contains(list->at(i).wavfilename)) - dublicates.append(list->at(i).wavfilename); + // skip duplicated wav entries + if(!duplicates.contains(list->at(i).wavfilename)) + duplicates.append(list->at(i).wavfilename); else { - qDebug() << "dublicate skipped"; + qDebug() << "[TalkGen] duplicate skipped"; (*list)[i].voiced = true; - emit logProgress(++m_progress,progressMax); continue; } + } - // skip already voiced entrys - if(list->at(i).voiced == true) - { - emit logProgress(++m_progress,progressMax); - continue; - } - // skip entry whith empty text - if(list->at(i).toSpeak == "") - { - emit logProgress(++m_progress,progressMax); - continue; - } + /* If the engine can't be parallelized, we use only 1 thread */ + int maxThreadCount = QThreadPool::globalInstance()->maxThreadCount(); + if ((m_tts->capabilities() & TTSBase::RunInParallel) == 0) + QThreadPool::globalInstance()->setMaxThreadCount(1); + + connect(&ttsFutureWatcher, SIGNAL(progressValueChanged(int)), + this, SLOT(ttsProgress(int))); + ttsFutureWatcher.setFuture(QtConcurrent::map(*list, &TalkGenerator::ttsEntryPoint)); + + /* We use this loop as an equivalent to ttsFutureWatcher.waitForFinished() + * since the latter blocks all events */ + while(ttsFutureWatcher.isRunning()) + QCoreApplication::processEvents(); + + /* Restore global settings, if we changed them */ + if ((m_tts->capabilities() & TTSBase::RunInParallel) == 0) + QThreadPool::globalInstance()->setMaxThreadCount(maxThreadCount); + + if(ttsFutureWatcher.isCanceled()) + return eERROR; + else if(m_ttsWarnings) + return eWARNING; + else + return eOK; +} - // voice entry +void TalkGenerator::ttsEntryPoint(TalkEntry& entry) +{ + if (!entry.voiced && !entry.toSpeak.isEmpty()) + { QString error; - qDebug() << "voicing: " << list->at(i).toSpeak << "to" << list->at(i).wavfilename; - TTSStatus status = m_tts->voice(list->at(i).toSpeak,list->at(i).wavfilename, &error); - if(status == Warning) + qDebug() << "[TalkGen] voicing: " << entry.toSpeak << "to" << entry.wavfilename; + TTSStatus status = entry.refs.tts->voice(entry.toSpeak,entry.wavfilename, &error); + if (status == Warning || status == FatalError) { - warnings = true; - emit logItem(tr("Voicing of %1 failed: %2").arg(list->at(i).toSpeak).arg(error), - LOGWARNING); + entry.refs.generator->ttsFailEntry(entry, status, error); + return; } - else if (status == FatalError) - { - emit logItem(tr("Voicing of %1 failed: %2").arg(list->at(i).toSpeak).arg(error), - LOGERROR); - return eERROR; - } - else - (*list)[i].voiced = true; - - //wavetrim if needed - if(wavtrimth != -1) + if (entry.refs.wavtrim != -1) { char buffer[255]; - wavtrim(list->at(i).wavfilename.toLocal8Bit().data(),wavtrimth,buffer,255); + wavtrim(entry.wavfilename.toLocal8Bit().data(), entry.refs.wavtrim, buffer, 255); } + entry.voiced = true; + } +} - emit logProgress(++m_progress,progressMax); - QCoreApplication::processEvents(); +void TalkGenerator::ttsFailEntry(const TalkEntry& entry, TTSStatus status, QString error) +{ + if(status == Warning) + { + m_ttsWarnings = true; + emit logItem(tr("Voicing of %1 failed: %2").arg(entry.toSpeak).arg(error), + LOGWARNING); + } + else if (status == FatalError) + { + emit logItem(tr("Voicing of %1 failed: %2").arg(entry.toSpeak).arg(error), + LOGERROR); + abort(); } - if(warnings) - return eWARNING; - else - return eOK; } +void TalkGenerator::ttsProgress(int value) +{ + emit logProgress(value,ttsFutureWatcher.progressMaximum()); +} //! \brief Encodes a List of strings //! TalkGenerator::Status TalkGenerator::encodeList(QList* list) { - QStringList dublicates; + QStringList duplicates; - int progressMax = list->size(); - int m_progress = 0; - emit logProgress(m_progress,progressMax); + int itemsCount = list->size(); + emit logProgress(0, itemsCount); - for(int i=0; i < list->size(); i++) + /* Do some preprocessing and remove entries that have not been voiced. */ + for (int idx=0; idx < itemsCount; idx++) { - if(m_abort) - { - emit logItem(tr("Encoding aborted"), LOGERROR); - return eERROR; - } - - //skip non-voiced entrys - if(list->at(i).voiced == false) + if(list->at(idx).voiced == false) { - qDebug() << "non voiced entry" << list->at(i).toSpeak <<"detected"; - emit logProgress(++m_progress,progressMax); + qDebug() << "[TalkGen] unvoiced entry" << list->at(idx).toSpeak <<"detected"; + list->removeAt(idx); + itemsCount--; + idx--; continue; } - //skip dublicates - if(!dublicates.contains(list->at(i).talkfilename)) - dublicates.append(list->at(i).talkfilename); - else + if(duplicates.contains(list->at(idx).talkfilename)) { - qDebug() << "dublicate skipped"; - (*list)[i].encoded = true; - emit logProgress(++m_progress,progressMax); + (*list)[idx].encoded = true; /* make sure we skip this entry */ continue; } + duplicates.append(list->at(idx).talkfilename); + (*list)[idx].refs.encoder = m_enc; + (*list)[idx].refs.generator = this; /* not really needed, unless we end up + voicing and encoding with two different + TalkGenerators.*/ + } - //encode entry - qDebug() << "encoding " << list->at(i).wavfilename << "to" << list->at(i).talkfilename; - if(!m_enc->encode(list->at(i).wavfilename,list->at(i).talkfilename)) - { - emit logItem(tr("Encoding of %1 failed").arg(list->at(i).wavfilename), LOGERROR); - return eERROR; + connect(&encFutureWatcher, SIGNAL(progressValueChanged(int)), + this, SLOT(encProgress(int))); + encFutureWatcher.setFuture(QtConcurrent::map(*list, &TalkGenerator::encEntryPoint)); + + /* We use this loop as an equivalent to encFutureWatcher.waitForFinished() + * since the latter blocks all events */ + while (encFutureWatcher.isRunning()) + QCoreApplication::processEvents(QEventLoop::AllEvents); + + if (encFutureWatcher.isCanceled()) + return eERROR; + else + return eOK; +} + +void TalkGenerator::encEntryPoint(TalkEntry& entry) +{ + if(!entry.encoded) + { + bool res = entry.refs.encoder->encode(entry.wavfilename, entry.talkfilename); + entry.encoded = res; + if (!entry.encoded) + entry.refs.generator->encFailEntry(entry); } - (*list)[i].encoded = true; - emit logProgress(++m_progress,progressMax); - QCoreApplication::processEvents(); - } - return eOK; + return; +} + +void TalkGenerator::encProgress(int value) +{ + emit logProgress(value, encFutureWatcher.progressMaximum()); +} + +void TalkGenerator::encFailEntry(const TalkEntry& entry) +{ + emit logItem(tr("Encoding of %1 failed").arg(entry.wavfilename), LOGERROR); + abort(); } //! \brief slot, which is connected to the abort of the Logger. Sets a flag, so Creating Talkfiles ends at the next possible position //! void TalkGenerator::abort() { - m_abort = true; + if (ttsFutureWatcher.isRunning()) + { + ttsFutureWatcher.cancel(); + emit logItem(tr("Voicing aborted"), LOGERROR); + } + if (encFutureWatcher.isRunning()) + { + encFutureWatcher.cancel(); + emit logItem(tr("Encoding aborted"), LOGERROR); + } } -- cgit v1.2.3