/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * * Copyright (C) 2007 by Dominik Wenger * $Id$ * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "talkfile.h" #include "rbsettings.h" TalkFileCreator::TalkFileCreator(QObject* parent): QObject(parent) { } //! \brief Creates Talkfiles. //! //! \param logger A pointer to a Loggerobject bool TalkFileCreator::createTalkFiles(ProgressloggerInterface* logger) { m_abort = false; m_logger = logger; QMultiMap fileList; QMultiMap dirList; QStringList toSpeakList, voicedEntries, encodedEntries; QString errStr; m_logger->addItem(tr("Starting Talk file generation"),LOGINFO); //tts m_tts = TTSBase::getTTS(this,RbSettings::value(RbSettings::Tts).toString()); if(!m_tts->start(&errStr)) { m_logger->addItem(errStr.trimmed(),LOGERROR); m_logger->addItem(tr("Init of TTS engine failed"),LOGERROR); m_logger->setFinished(); return false; } // Encoder m_enc = EncBase::getEncoder(this,RbSettings::value(RbSettings::CurEncoder).toString()); if(!m_enc->start()) { m_logger->addItem(tr("Init of Encoder engine failed"),LOGERROR); m_logger->setFinished(); m_tts->stop(); return false; } QCoreApplication::processEvents(); connect(logger,SIGNAL(aborted()),this,SLOT(abort())); m_logger->setProgressMax(0); // read in Maps of paths - file/dirnames m_logger->addItem(tr("Reading Filelist..."),LOGINFO); if(createDirAndFileMaps(m_dir,&dirList,&fileList) == false) { m_logger->addItem(tr("Talk file creation aborted"),LOGERROR); doAbort(toSpeakList); return false; } // create List of all Files/Dirs to speak QMapIterator dirIt(dirList); while (dirIt.hasNext()) { dirIt.next(); // insert only non dublicate dir entries into list if(!toSpeakList.contains(dirIt.value())) { qDebug() << "toSpeaklist dir:" << dirIt.value(); toSpeakList.append(dirIt.value()); } } QMapIterator fileIt(fileList); while (fileIt.hasNext()) { fileIt.next(); // insert only non- dublictae file entries into list if(!toSpeakList.contains(fileIt.value())) { if(m_stripExtensions) toSpeakList.append(stripExtension(fileIt.value())); else toSpeakList.append(fileIt.value()); } } // Voice entries m_logger->addItem(tr("Voicing entries..."),LOGINFO); TTSStatus voiceStatus= voiceList(toSpeakList,voicedEntries); if(voiceStatus == FatalError) { doAbort(toSpeakList); return false; } // Encoding Entries m_logger->addItem(tr("Encoding files..."),LOGINFO); if(encodeList(voicedEntries,encodedEntries) == false) { doAbort(toSpeakList); return false; } // Copying talk files m_logger->addItem(tr("Copying Talkfile for Dirs..."),LOGINFO); if(copyTalkDirFiles(dirList,&errStr) == false) { m_logger->addItem(errStr,LOGERROR); doAbort(toSpeakList); return false; } //Copying file talk files m_logger->addItem(tr("Copying Talkfile for Files..."),LOGINFO); if(copyTalkFileFiles(fileList,&errStr) == false) { m_logger->addItem(errStr,LOGERROR); doAbort(toSpeakList); return false; } // Deleting left overs if( !cleanup(toSpeakList)) return false; m_tts->stop(); m_enc->stop(); m_logger->addItem(tr("Finished creating Talk files"),LOGOK); m_logger->setProgressMax(1); m_logger->setProgressValue(1); m_logger->setFinished(); return true; } //! \brief resets the internal progress counter, and sets the Progressbar in the Logger //! //! \param max The maximum to shich the Progressbar is set. void TalkFileCreator::resetProgress(int max) { m_progress = 0; m_logger->setProgressMax(max); m_logger->setProgressValue(m_progress); } //! \brief Strips everything after and including the last dot in a string. If there is no dot, nothing is changed //! //! \param filename The filename from which to strip the Extension //! \returns the modified string QString TalkFileCreator::stripExtension(QString filename) { if(filename.lastIndexOf(".") != -1) return filename.left(filename.lastIndexOf(".")); else return filename; } //! \brief Does needed Tasks when we need to abort. Cleans up Files. Stops the Logger, Stops TTS and Encoder //! //! \param cleanupList List of filenames to give to cleanup() void TalkFileCreator::doAbort(QStringList cleanupList) { cleanup(cleanupList); m_logger->setProgressMax(1); m_logger->setProgressValue(0); m_logger->setFinished(); m_tts->stop(); m_enc->stop(); } //! \brief Creates MultiMaps (paths -> File/dir names) of all Dirs and Files in a Folder. //! Depending on settings, either Dirs or Files can be ignored. //! Also recursion is controlled by settings //! //! \param startDir The dir where it beginns scanning //! \param dirMap The MulitMap where the dirs are stored //! \param filMap The MultiMap where Files are stored //! \returns true on Success, false if User aborted. bool TalkFileCreator::createDirAndFileMaps(QDir startDir,QMultiMap *dirMap,QMultiMap *fileMap) { // create Iterator QDirIterator::IteratorFlags flags = QDirIterator::NoIteratorFlags; if(m_recursive) flags = QDirIterator::Subdirectories; QDirIterator it(startDir,flags); // read in Maps of paths - file/dirnames while (it.hasNext()) { it.next(); if(m_abort) { return false; } QFileInfo fileInf = it.fileInfo(); // its a dir if(fileInf.isDir()) { QDir dir = fileInf.dir(); // insert into List if(!dir.dirName().isEmpty() && m_talkFolders) { qDebug() << "Dir: " << dir.dirName() << " - " << dir.path(); dirMap->insert(dir.path(),dir.dirName()); } } else // its a File { // insert into List if( !fileInf.fileName().isEmpty() && !fileInf.fileName().endsWith(".talk") && m_talkFiles) { qDebug() << "File: " << fileInf.fileName() << " - " << fileInf.path(); fileMap->insert(fileInf.path(),fileInf.fileName()); } } QCoreApplication::processEvents(); } return true; } //! \brief Voices a List of string to the temp dir. Progress is handled inside. //! //! \param toSpeak QStringList with the Entries to voice. //! \param errString pointer to where the Error cause is written //! \returns true on success, false on error or user abort TTSStatus TalkFileCreator::voiceList(QStringList toSpeak,QStringList& voicedEntries) { resetProgress(toSpeak.size()); QStringList errors; bool warnings = false; for(int i=0; i < toSpeak.size(); i++) { if(m_abort) { m_logger->addItem(tr("Talk file creation aborted"), LOGERROR); return FatalError; } QString filename = QDir::tempPath()+ "/"+ toSpeak[i] + ".wav"; QString error; TTSStatus status = m_tts->voice(toSpeak[i],filename, &error); if(status == Warning) { warnings = true; m_logger->addItem(tr("Voicing of %1 failed: %2").arg(toSpeak[i]).arg(error), LOGWARNING); } else if (status == FatalError) { m_logger->addItem(tr("Voicing of %1 failed: %2").arg(toSpeak[i]).arg(error), LOGERROR); return FatalError; } else voicedEntries.append(toSpeak[i]); m_logger->setProgressValue(++m_progress); QCoreApplication::processEvents(); } if(warnings) return Warning; else return NoError; } //! \brief Encodes a List of strings from/to the temp dir. Progress is handled inside. //! It expects the inputfile in the temp dir with the name in the List appended with ".wav" //! //! \param toSpeak QStringList with the Entries to encode. //! \param errString pointer to where the Error cause is written //! \returns true on success, false on error or user abort bool TalkFileCreator::encodeList(QStringList toEncode,QStringList& encodedEntries) { resetProgress(toEncode.size()); for(int i=0; i < toEncode.size(); i++) { if(m_abort) { m_logger->addItem(tr("Talk file creation aborted"), LOGERROR); return false; } QString wavfilename = QDir::tempPath()+ "/"+ toEncode[i] + ".wav"; QString filename = QDir::tempPath()+ "/"+ toEncode[i] + ".talk"; if(!m_enc->encode(wavfilename,filename)) { m_logger->addItem(tr("Encoding of %1 failed").arg(filename), LOGERROR); return false; } encodedEntries.append(toEncode[i]); m_logger->setProgressValue(++m_progress); QCoreApplication::processEvents(); } return true; } //! \brief copys Talkfile for Dirs from the temp dir to the target. Progress and installlog is handled inside //! //! \param dirMap a MultiMap of Paths -> Dirnames //! \param errString Pointer to a QString where the error cause is written. //! \returns true on success, false on error or user abort bool TalkFileCreator::copyTalkDirFiles(QMultiMap dirMap,QString* errString) { resetProgress(dirMap.size()); QSettings installlog(m_mountpoint + "/.rockbox/rbutil.log", QSettings::IniFormat, 0); installlog.beginGroup("talkfiles"); QMapIterator it(dirMap); while (it.hasNext()) { it.next(); if(m_abort) { *errString = tr("Talk file creation aborted"); return false; } QString source = QDir::tempPath()+ "/"+ it.value() + ".talk"; if(!QFileInfo(source).exists()) continue; // this file was skipped in one of the previous steps QString target = it.key() + "/" + "_dirname.talk"; // remove target if it exists, and if we should overwrite it if(m_overwriteTalk && QFile::exists(target)) QFile::remove(target); // copying if(!QFile::copy(source,target)) { *errString = tr("Copying of %1 to %2 failed").arg(source).arg(target); return false; } // add to installlog QString now = QDate::currentDate().toString("yyyyMMdd"); installlog.setValue(target.remove(0,m_mountpoint.length()),now); m_logger->setProgressValue(++m_progress); QCoreApplication::processEvents(); } installlog.endGroup(); installlog.sync(); return true; } //! \brief copys Talkfile for Files from the temp dir to the target. Progress and installlog is handled inside //! //! \param fileMap a MultiMap of Paths -> Filenames //! \param errString Pointer to a QString where the error cause is written. //! \returns true on success, false on error or user abort bool TalkFileCreator::copyTalkFileFiles(QMultiMap fileMap,QString* errString) { resetProgress(fileMap.size()); QSettings installlog(m_mountpoint + "/.rockbox/rbutil.log", QSettings::IniFormat, 0); installlog.beginGroup("talkfiles"); QMapIterator it(fileMap); while (it.hasNext()) { it.next(); if(m_abort) { *errString = tr("Talk file creation aborted"); return false; } QString source; QString target = it.key() + "/" + it.value() + ".talk"; // correct source if we hav stripExtension enabled if(m_stripExtensions) source = QDir::tempPath()+ "/"+ stripExtension(it.value()) + ".talk"; else source = QDir::tempPath()+ "/"+ it.value() + ".talk"; if(!QFileInfo(source).exists()) continue; // this file was skipped in one of the previous steps // remove target if it exists, and if we should overwrite it if(m_overwriteTalk && QFile::exists(target)) QFile::remove(target); // copy file qDebug() << "copying: " << source << " to " << target; if(!QFile::copy(source,target)) { *errString = tr("Copying of %1 to %2 failed").arg(source).arg(target); return false; } // add to Install log QString now = QDate::currentDate().toString("yyyyMMdd"); installlog.setValue(target.remove(0,m_mountpoint.length()),now); m_logger->setProgressValue(++m_progress); QCoreApplication::processEvents(); } installlog.endGroup(); installlog.sync(); return true; } //! \brief Cleans up Files potentially left in the temp dir //! //! \param list List of file to try to delete in the temp dir. Function appends ".wav" and ".talk" to the filenames bool TalkFileCreator::cleanup(QStringList list) { m_logger->addItem(tr("Cleaning up.."),LOGINFO); for(int i=0; i < list.size(); i++) { if(QFile::exists(QDir::tempPath()+ "/"+ list[i] + ".wav")) QFile::remove(QDir::tempPath()+ "/"+ list[i] + ".wav"); if(QFile::exists(QDir::tempPath()+ "/"+ list[i] + ".talk")) QFile::remove(QDir::tempPath()+ "/"+ list[i] + ".talk"); QCoreApplication::processEvents(); } return true; } //! \brief slot, which is connected to the abort of the Logger. Sets a flag, so Creating Talkfiles ends at the next possible position //! void TalkFileCreator::abort() { m_abort = true; }