diff --git a/rbutil/rbutilqt/base/talkgenerator.cpp b/rbutil/rbutilqt/base/talkgenerator.cpp index 42f84be..a0fbf2a 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), encFutureWatcher(this) +TalkGenerator::TalkGenerator(QObject* parent): QObject(parent), encFutureWatcher(this), ttsFutureWatcher(this) { } @@ -31,7 +31,6 @@ TalkGenerator::TalkGenerator(QObject* parent): QObject(parent), encFutureWatcher //! TalkGenerator::Status TalkGenerator::process(QList* list,int wavtrimth) { - m_abort = false; QString errStr; bool warnings = false; @@ -104,82 +103,94 @@ 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].tts = m_tts; + (*list)[i].wavtrim = wavtrimth; - // skip dublicated wav entrys - if(!dublicates.contains(list->at(i).wavfilename)) - dublicates.append(list->at(i).wavfilename); + // skip duplicated wav entrys + 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; } + } + + /* If the engine can't be parallelized, we use only 1 thread */ + int maxThreadCount = QThreadPool::globalInstance()->maxThreadCount(); + if ((m_tts->capabilities() & 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() & RunInParallel) == 0) + QThreadPool::globalInstance()->setMaxThreadCount(maxThreadCount); + + if(ttsFutureWatcher.isCanceled()) + return eERROR; + else if(m_ttsWarnings) + return eWARNING; + else + return eOK; +} - // skip already voiced entrys - if(list->at(i).voiced == true) +void TalkGenerator::ttsEntryPoint(TalkEntry& entry) { - emit logProgress(++m_progress,progressMax); - continue; + if (!entry.voiced && !entry.toSpeak.isEmpty()) + { + QString error; + qDebug() << "[TalkGen] voicing: " << entry.toSpeak << "to" << entry.wavfilename; + TTSStatus status = entry.tts->voice(entry.toSpeak,entry.wavfilename, &error); + if (status == Warning || status == FatalError) + { + entry.generator->ttsFailEntry(entry, status, error); + return; } - // skip entry whith empty text - if(list->at(i).toSpeak == "") + if (entry.wavtrim != -1) { - emit logProgress(++m_progress,progressMax); - continue; + char buffer[255]; + wavtrim(entry.wavfilename.toLocal8Bit().data(),entry.wavtrim,buffer,255); + } + entry.voiced = true; + } } - // voice entry - 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); +void TalkGenerator::ttsFailEntry(const TalkEntry& entry, TTSStatus status, QString error) +{ if(status == Warning) { - warnings = true; - emit logItem(tr("Voicing of %1 failed: %2").arg(list->at(i).toSpeak).arg(error), + 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(list->at(i).toSpeak).arg(error), + emit logItem(tr("Voicing of %1 failed: %2").arg(entry.toSpeak).arg(error), LOGERROR); - return eERROR; + abort(); } - else - (*list)[i].voiced = true; - - //wavetrim if needed - if(wavtrimth != -1) - { - char buffer[255]; - wavtrim(list->at(i).wavfilename.toLocal8Bit().data(),wavtrimth,buffer,255); } - emit logProgress(++m_progress,progressMax); - QCoreApplication::processEvents(); - } - 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) @@ -238,23 +249,25 @@ void TalkGenerator::encEntryPoint(TalkEntry& entry) void TalkGenerator::encProgress(int value) { - qDebug() << "[TalkGen] Progress at " << value; emit logProgress(value, encFutureWatcher.progressMaximum()); } void TalkGenerator::encFailEntry(const TalkEntry& entry) { - encFutureWatcher.cancel(); - encFutureWatcher.waitForFinished(); 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(); + ttsFutureWatcher.waitForFinished(); + emit logItem(tr("Voicing aborted"), LOGERROR); + } if (encFutureWatcher.isRunning()) { encFutureWatcher.cancel(); diff --git a/rbutil/rbutilqt/base/talkgenerator.h b/rbutil/rbutilqt/base/talkgenerator.h index 87ab33e..6a5a424 100644 --- a/rbutil/rbutilqt/base/talkgenerator.h +++ b/rbutil/rbutilqt/base/talkgenerator.h @@ -52,11 +52,13 @@ class TalkGenerator :public QObject /* We need the following members because * 1) the QtConcurrent entry points are all static methods (and we need to communicate - * with the TalkGenerator + * with the TalkGenerator) * 2) we are not guaranteed to go through the list in any particular order, * so we can't use the progress slot for error checking */ EncBase* encoder; + TTSBase* tts; TalkGenerator* generator; + int wavtrim; }; TalkGenerator(QObject* parent); @@ -65,6 +67,7 @@ class TalkGenerator :public QObject public slots: void abort(); void encProgress(int value); + void ttsProgress(int value); signals: void done(bool); @@ -73,17 +76,20 @@ signals: private: QFutureWatcher encFutureWatcher; + QFutureWatcher ttsFutureWatcher; void encFailEntry(const TalkEntry& entry); + void ttsFailEntry(const TalkEntry& entry, TTSStatus status, QString error); Status voiceList(QList* list,int wavetrimth); Status encodeList(QList* list); static void encEntryPoint(TalkEntry& entry); + static void ttsEntryPoint(TalkEntry& entry); TTSBase* m_tts; EncBase* m_enc; - bool m_abort; + bool m_ttsWarnings; }; diff --git a/rbutil/rbutilqt/base/ttsbase.h b/rbutil/rbutilqt/base/ttsbase.h index 7c59324..4c26833 100644 --- a/rbutil/rbutilqt/base/ttsbase.h +++ b/rbutil/rbutilqt/base/ttsbase.h @@ -32,7 +32,7 @@ #include "encttssettings.h" enum TTSStatus{ FatalError, NoError, Warning }; - +enum TTSCapabilities { None = 0, RunInParallel = 1 }; class TTSBase : public EncTtsSettingInterface { Q_OBJECT @@ -53,6 +53,8 @@ class TTSBase : public EncTtsSettingInterface //! Chlid class should commit the Settings to permanent storage virtual void saveSettings() = 0; + virtual int capabilities() = 0; + // static functions static TTSBase* getTTS(QObject* parent,QString ttsname); static QStringList getTTSList(); diff --git a/rbutil/rbutilqt/base/ttscarbon.cpp b/rbutil/rbutilqt/base/ttscarbon.cpp index a74cb23..979d1d2 100644 --- a/rbutil/rbutilqt/base/ttscarbon.cpp +++ b/rbutil/rbutilqt/base/ttscarbon.cpp @@ -34,6 +34,10 @@ TTSCarbon::TTSCarbon(QObject* parent) : TTSBase(parent) { } +int TTSCarbon::capabilities() +{ + return None; +} bool TTSCarbon::configOk() { diff --git a/rbutil/rbutilqt/base/ttscarbon.h b/rbutil/rbutilqt/base/ttscarbon.h index b2d3904..defeb27 100644 --- a/rbutil/rbutilqt/base/ttscarbon.h +++ b/rbutil/rbutilqt/base/ttscarbon.h @@ -53,6 +53,8 @@ class TTSCarbon : public TTSBase //! Chlid class should commit the Settings to permanent storage void saveSettings(); + int capabilities(); + private: SpeechChannel m_channel; CFStringBuiltInEncodings m_voiceScript; diff --git a/rbutil/rbutilqt/base/ttsexes.cpp b/rbutil/rbutilqt/base/ttsexes.cpp index 05ed23b..420a8bf 100644 --- a/rbutil/rbutilqt/base/ttsexes.cpp +++ b/rbutil/rbutilqt/base/ttsexes.cpp @@ -31,6 +31,11 @@ TTSExes::TTSExes(QString name,QObject* parent) : TTSBase(parent) } +int TTSExes::capabilities() +{ + return RunInParallel; +} + void TTSExes::generateSettings() { QString exepath =RbSettings::subValue(m_name,RbSettings::TtsPath).toString(); diff --git a/rbutil/rbutilqt/base/ttsexes.h b/rbutil/rbutilqt/base/ttsexes.h index c03beb7..03cf894 100644 --- a/rbutil/rbutilqt/base/ttsexes.h +++ b/rbutil/rbutilqt/base/ttsexes.h @@ -38,6 +38,7 @@ class TTSExes : public TTSBase TTSStatus voice(QString text, QString wavfile, QString *errStr); bool start(QString *errStr); bool stop() {return true;} + int capabilities(); // for settings void generateSettings(); diff --git a/rbutil/rbutilqt/base/ttsfestival.cpp b/rbutil/rbutilqt/base/ttsfestival.cpp index be67b67..b46a396 100644 --- a/rbutil/rbutilqt/base/ttsfestival.cpp +++ b/rbutil/rbutilqt/base/ttsfestival.cpp @@ -27,6 +27,11 @@ TTSFestival::~TTSFestival() stop(); } +int TTSFestival::capabilities() +{ + return RunInParallel; +} + void TTSFestival::generateSettings() { // server path diff --git a/rbutil/rbutilqt/base/ttsfestival.h b/rbutil/rbutilqt/base/ttsfestival.h index 8a68737..915c3a4 100644 --- a/rbutil/rbutilqt/base/ttsfestival.h +++ b/rbutil/rbutilqt/base/ttsfestival.h @@ -42,6 +42,7 @@ class TTSFestival : public TTSBase bool start(QString *errStr); bool stop(); TTSStatus voice(QString text,QString wavfile, QString *errStr); + int capabilities(); // for settings bool configOk(); diff --git a/rbutil/rbutilqt/base/ttssapi.cpp b/rbutil/rbutilqt/base/ttssapi.cpp index 4f69de5..7030b72 100644 --- a/rbutil/rbutilqt/base/ttssapi.cpp +++ b/rbutil/rbutilqt/base/ttssapi.cpp @@ -30,6 +30,11 @@ TTSSapi::TTSSapi(QObject* parent) : TTSBase(parent) m_sapi4 =false; } +int TTSSapi::capabilities() +{ + return None; +} + void TTSSapi::generateSettings() { // language diff --git a/rbutil/rbutilqt/base/ttssapi.h b/rbutil/rbutilqt/base/ttssapi.h index 531f256..b871893 100644 --- a/rbutil/rbutilqt/base/ttssapi.h +++ b/rbutil/rbutilqt/base/ttssapi.h @@ -42,6 +42,7 @@ class TTSSapi : public TTSBase TTSStatus voice(QString text,QString wavfile, QString *errStr); bool start(QString *errStr); bool stop(); + int capabilities(); // for settings bool configOk();