From 357d35c20eef7873fb6397814f38b721024f2795 Mon Sep 17 00:00:00 2001 From: Dominik Wenger Date: Wed, 29 Apr 2009 21:29:35 +0000 Subject: rbutil: move the tts and encoders and its settings interface to base/ git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20825 a1c6a512-1295-4272-9138-f99709370657 --- rbutil/rbutilqt/base/encoders.cpp | 233 ++++++++++++ rbutil/rbutilqt/base/encoders.h | 133 +++++++ rbutil/rbutilqt/base/encttssettings.cpp | 70 ++++ rbutil/rbutilqt/base/encttssettings.h | 129 +++++++ rbutil/rbutilqt/base/tts.cpp | 656 ++++++++++++++++++++++++++++++++ rbutil/rbutilqt/base/tts.h | 185 +++++++++ rbutil/rbutilqt/encoders.cpp | 233 ------------ rbutil/rbutilqt/encoders.h | 133 ------- rbutil/rbutilqt/encttssettings.cpp | 70 ---- rbutil/rbutilqt/encttssettings.h | 129 ------- rbutil/rbutilqt/tts.cpp | 656 -------------------------------- rbutil/rbutilqt/tts.h | 185 --------- 12 files changed, 1406 insertions(+), 1406 deletions(-) create mode 100644 rbutil/rbutilqt/base/encoders.cpp create mode 100644 rbutil/rbutilqt/base/encoders.h create mode 100644 rbutil/rbutilqt/base/encttssettings.cpp create mode 100644 rbutil/rbutilqt/base/encttssettings.h create mode 100644 rbutil/rbutilqt/base/tts.cpp create mode 100644 rbutil/rbutilqt/base/tts.h delete mode 100644 rbutil/rbutilqt/encoders.cpp delete mode 100644 rbutil/rbutilqt/encoders.h delete mode 100644 rbutil/rbutilqt/encttssettings.cpp delete mode 100644 rbutil/rbutilqt/encttssettings.h delete mode 100644 rbutil/rbutilqt/tts.cpp delete mode 100644 rbutil/rbutilqt/tts.h diff --git a/rbutil/rbutilqt/base/encoders.cpp b/rbutil/rbutilqt/base/encoders.cpp new file mode 100644 index 0000000000..6ff1185c82 --- /dev/null +++ b/rbutil/rbutilqt/base/encoders.cpp @@ -0,0 +1,233 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "encoders.h" +#include "utils.h" + +/********************************************************************* +* Encoder Base +**********************************************************************/ +QMap EncBase::encoderList; + +EncBase::EncBase(QObject *parent): EncTtsSettingInterface(parent) +{ + +} + +// initialize list of encoders +void EncBase::initEncodernamesList() +{ + encoderList["rbspeex"] = "Rockbox Speex Encoder"; + encoderList["lame"] = "Lame Mp3 Encoder"; +} + + +// get nice name for a specific encoder +QString EncBase::getEncoderName(QString encoder) +{ + if(encoderList.isEmpty()) + initEncodernamesList(); + return encoderList.value(encoder); +} + + +// get a specific encoder object +EncBase* EncBase::getEncoder(QObject* parent,QString encoder) +{ + EncBase* enc; + if(encoder == "lame") + { + enc = new EncExes(encoder,parent); + return enc; + } + else // rbspeex is default + { + enc = new EncRbSpeex(parent); + return enc; + } +} + + +QStringList EncBase::getEncoderList() +{ + if(encoderList.isEmpty()) + initEncodernamesList(); + return encoderList.keys(); +} + + +/********************************************************************* +* GEneral Exe Encoder +**********************************************************************/ +EncExes::EncExes(QString name,QObject *parent) : EncBase(parent) +{ + m_name = name; + + m_TemplateMap["lame"] = "\"%exe\" %options \"%input\" \"%output\""; + +} + + + +void EncExes::generateSettings() +{ + QString exepath =settings->subValue(m_name,RbSettings::EncoderPath).toString(); + if(exepath == "") exepath = findExecutable(m_name); + + insertSetting(eEXEPATH,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Path to Encoder:",exepath,EncTtsSetting::eBROWSEBTN)); + insertSetting(eEXEOPTIONS,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Encoder options:",settings->subValue(m_name,RbSettings::EncoderOptions))); +} + +void EncExes::saveSettings() +{ + settings->setSubValue(m_name,RbSettings::EncoderPath,getSetting(eEXEPATH)->current().toString()); + settings->setSubValue(m_name,RbSettings::EncoderOptions,getSetting(eEXEOPTIONS)->current().toString()); + settings->sync(); +} + +bool EncExes::start() +{ + m_EncExec = settings->subValue(m_name, RbSettings::EncoderPath).toString(); + m_EncOpts = settings->subValue(m_name, RbSettings::EncoderOptions).toString(); + + m_EncTemplate = m_TemplateMap.value(m_name); + + QFileInfo enc(m_EncExec); + if(enc.exists()) + { + return true; + } + else + { + return false; + } +} + +bool EncExes::encode(QString input,QString output) +{ + //qDebug() << "encoding.."; + QString execstring = m_EncTemplate; + + execstring.replace("%exe",m_EncExec); + execstring.replace("%options",m_EncOpts); + execstring.replace("%input",input); + execstring.replace("%output",output); + qDebug() << execstring; + QProcess::execute(execstring); + return true; +} + + +bool EncExes::configOk() +{ + QString path = settings->subValue(m_name, RbSettings::EncoderPath).toString(); + + if (QFileInfo(path).exists()) + return true; + + return false; +} + +/********************************************************************* +* RB SPEEX ENCODER +**********************************************************************/ +EncRbSpeex::EncRbSpeex(QObject *parent) : EncBase(parent) +{ + +} + +void EncRbSpeex::generateSettings() +{ + insertSetting(eVOLUME,new EncTtsSetting(this,EncTtsSetting::eDOUBLE,"Volume:",settings->subValue("rbspeex",RbSettings::EncoderVolume),1.0,10.0)); + insertSetting(eQUALITY,new EncTtsSetting(this,EncTtsSetting::eDOUBLE,"Quality:",settings->subValue("rbspeex",RbSettings::EncoderQuality),0,10.0)); + insertSetting(eCOMPLEXITY,new EncTtsSetting(this,EncTtsSetting::eINT,"Complexity:",settings->subValue("rbspeex",RbSettings::EncoderComplexity),0,10)); + insertSetting(eNARROWBAND,new EncTtsSetting(this,EncTtsSetting::eBOOL,"Use Narrowband:",settings->subValue("rbspeex",RbSettings::EncoderNarrowBand))); +} + +void EncRbSpeex::saveSettings() +{ + //save settings in user config + settings->setSubValue("rbspeex",RbSettings::EncoderVolume,getSetting(eVOLUME)->current().toDouble()); + settings->setSubValue("rbspeex",RbSettings::EncoderQuality,getSetting(eQUALITY)->current().toDouble()); + settings->setSubValue("rbspeex",RbSettings::EncoderComplexity,getSetting(eCOMPLEXITY)->current().toInt()); + settings->setSubValue("rbspeex",RbSettings::EncoderNarrowBand,getSetting(eNARROWBAND)->current().toBool()); + + settings->sync(); +} + +bool EncRbSpeex::start() +{ + + // try to get config from settings + quality = settings->subValue("rbspeex", RbSettings::EncoderQuality).toDouble(); + complexity = settings->subValue("rbspeex", RbSettings::EncoderComplexity).toInt(); + volume = settings->subValue("rbspeex", RbSettings::EncoderVolume).toDouble(); + narrowband = settings->subValue("rbspeex", RbSettings::EncoderNarrowBand).toBool(); + + + return true; +} + +bool EncRbSpeex::encode(QString input,QString output) +{ + qDebug() << "encoding " << input << " to "<< output; + char errstr[512]; + + FILE *fin,*fout; + if ((fin = fopen(input.toLocal8Bit(), "rb")) == NULL) { + qDebug() << "Error: could not open input file\n"; + return false; + } + if ((fout = fopen(output.toLocal8Bit(), "wb")) == NULL) { + qDebug() << "Error: could not open output file\n"; + return false; + } + + + int ret = encode_file(fin, fout, quality, complexity, narrowband, volume, + errstr, sizeof(errstr)); + fclose(fout); + fclose(fin); + + if (!ret) { + /* Attempt to delete unfinished output */ + qDebug() << "Error:" << errstr; + QFile(output).remove(); + return false; + } + return true; +} + +bool EncRbSpeex::configOk() +{ + bool result=true; + // check config + + if(settings->subValue("rbspeex", RbSettings::EncoderVolume).toDouble() <= 0) + result =false; + + if(settings->subValue("rbspeex", RbSettings::EncoderQuality).toDouble() <= 0) + result =false; + + if(settings->subValue("rbspeex", RbSettings::EncoderComplexity).toInt() <= 0) + result =false; + + return result; +} + diff --git a/rbutil/rbutilqt/base/encoders.h b/rbutil/rbutilqt/base/encoders.h new file mode 100644 index 0000000000..d5d1723a46 --- /dev/null +++ b/rbutil/rbutilqt/base/encoders.h @@ -0,0 +1,133 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2007 by Dominik Wenger + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef ENCODERS_H +#define ENCODERS_H + +#include + +#include "rbsettings.h" +#include "encttssettings.h" +#include "rbspeex.h" + + +class EncBase : public EncTtsSettingInterface +{ + Q_OBJECT + public: + EncBase(QObject *parent ); + + //! Child class should encode a wav file + virtual bool encode(QString input,QString output) =0; + //! Child class should do startup + virtual bool start()=0; + //! Child class should stop + virtual bool stop()=0; + + // settings + //! Child class should return true when configuration is ok + virtual bool configOk()=0; + //! Child class should fill in the setttingsList + virtual void generateSettings() = 0; + //! Chlid class should commit the from SettingsList to permanent storage + virtual void saveSettings() = 0; + + // static functions + static QString getEncoderName(QString name); + static EncBase* getEncoder(QObject* parent,QString name); + static QStringList getEncoderList(void); + + //set the config. users of Encoder classes, always have to call this first + void setCfg(RbSettings *sett){settings = sett;} + private: + static void initEncodernamesList(void); + + protected: + RbSettings* settings; + + static QMap encoderList; +}; + + +class EncExes : public EncBase +{ + enum ESettings + { + eEXEPATH, + eEXEOPTIONS + }; + + Q_OBJECT +public: + EncExes(QString name,QObject *parent = NULL); + bool encode(QString input,QString output); + bool start(); + bool stop() {return true;} + + // setting + bool configOk(); + void generateSettings(); + void saveSettings(); + +private: + QString m_name; + QString m_EncExec; + QString m_EncOpts; + QMap m_TemplateMap; + QString m_EncTemplate; +}; + +class EncRbSpeex : public EncBase +{ + enum ESettings + { + eVOLUME, + eQUALITY, + eCOMPLEXITY, + eNARROWBAND + }; + + Q_OBJECT +public: + EncRbSpeex(QObject *parent = NULL); + bool encode(QString input,QString output); + bool start(); + bool stop() {return true;} + + // for settings view + bool configOk(); + void generateSettings(); + void saveSettings(); + +private: + float quality; + float volume; + int complexity; + bool narrowband; + + float defaultQuality; + float defaultVolume; + int defaultComplexity; + bool defaultBand; +}; + + +#endif diff --git a/rbutil/rbutilqt/base/encttssettings.cpp b/rbutil/rbutilqt/base/encttssettings.cpp new file mode 100644 index 0000000000..fa7cfb39c2 --- /dev/null +++ b/rbutil/rbutilqt/base/encttssettings.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2007 by Dominik Wenger + * $Id: encoders.h 17902 2008-06-30 22:09:45Z bluebrother $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "encttssettings.h" + + +EncTtsSetting::EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current, EButton btn) +{ + m_btn = btn; + m_name =name; + m_type =type; + m_currentValue = current; +} + +EncTtsSetting::EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current,QStringList list,EButton btn) +{ + m_btn = btn; + m_name =name; + m_type =type; + m_currentValue = current; + m_list = list; +} + +EncTtsSetting::EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current,QVariant min,QVariant max, EButton btn) +{ + m_btn = btn; + m_name =name; + m_type =type; + m_currentValue = current; + m_minValue = min; + m_maxValue = max; +} + +void EncTtsSetting::setCurrent(QVariant current,bool noticeGui) +{ + m_currentValue = current; + emit dataChanged(); + + if(noticeGui) emit updateGui(); +} + +//! insert a setting +void EncTtsSettingInterface::insertSetting(int id,EncTtsSetting* setting) +{ + settingsList.insert(id,setting); +} + +//! retrieve a specific setting +EncTtsSetting* EncTtsSettingInterface::getSetting(int id) +{ + return settingsList.at(id); +} diff --git a/rbutil/rbutilqt/base/encttssettings.h b/rbutil/rbutilqt/base/encttssettings.h new file mode 100644 index 0000000000..843829a815 --- /dev/null +++ b/rbutil/rbutilqt/base/encttssettings.h @@ -0,0 +1,129 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2007 by Dominik Wenger + * $Id: encoders.h 17902 2008-06-30 22:09:45Z bluebrother $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef ENCTTSSETTINGS_H +#define ENCTTSSETTINGS_H + +#include + +//! \brief This class stores everything needed to display a Setting. +//! +class EncTtsSetting : public QObject +{ + Q_OBJECT +public: + enum ESettingType + { + eBASE, + eBOOL, + eDOUBLE, + eINT, + eSTRING, + eREADONLYSTRING, + eSTRINGLIST, + }; + enum EButton + { + eNOBTN, + eBROWSEBTN, + eREFRESHBTN + }; + + //! constructor for a String or Bool setting + EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current,EButton btn = eNOBTN); + //! contructor for a Stringlist setting, ie a enumeration + EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current,QStringList list,EButton btn = eNOBTN); + //! constructor for a setting with a min-max range + EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current,QVariant min,QVariant max,EButton = eNOBTN); + + //! get currentValue + QVariant current() {return m_currentValue;} + //! set currentValue + void setCurrent(QVariant current,bool noticeGui=true); + + //! get name of the Setting + QString name() {return m_name;} + //! get the type of the setting + ESettingType type() {return m_type;} + //! get what type of button this setting needs + EButton button() {return m_btn;} + //! get the minValue (only valid for a range setting, ie eDOUBLE or eINT) + QVariant min() {return m_minValue; } + //! get the maxValue (only valid for a range setting, ie eDOUBLE or eINT) + QVariant max() {return m_maxValue; } + //! get the enumerationlist (only valid for eSTRINGLIST settings) + QStringList list() {return m_list;} + //! set the enumeration list + void setList(QStringList list){m_list = list;} + +signals: + //! connect to this signal if you want to get noticed when the data changes + void dataChanged(); + //! connect to this if you want to react on refresh button + void refresh(); + //! will be emited when the gui should update this setting + void updateGui(); + +private: + ESettingType m_type; + EButton m_btn; + QString m_name; + QVariant m_currentValue; + QVariant m_minValue; + QVariant m_maxValue; + QStringList m_list; +}; + + +//! \brief this class is the Interface for Encoder and TTS engines, to display settings +//! It wraps nearly everything needed, only updateModel() and commitModel() needs to be reimplemented +//! +class EncTtsSettingInterface : public QObject +{ + Q_OBJECT +public: + EncTtsSettingInterface(QObject* parent) : QObject(parent) {} + + //! get the Settings list + QList getSettings() {generateSettings(); return settingsList;} + + //! Chlid class should commit the from SettingsList to permanent storage + virtual void saveSettings() = 0; + +signals: + void busy(); // emit this if a operation takes time + void busyEnd(); // emit this at the end of a busy section + +protected: + //! Child class should fill in the setttingsList + virtual void generateSettings() = 0; + + //! insert a setting + void insertSetting(int id,EncTtsSetting* setting); + //! retrieve a specific setting + EncTtsSetting* getSetting(int id); + +private: + //! The setting storage. + QList settingsList; + +}; +#endif diff --git a/rbutil/rbutilqt/base/tts.cpp b/rbutil/rbutilqt/base/tts.cpp new file mode 100644 index 0000000000..d55ba9e739 --- /dev/null +++ b/rbutil/rbutilqt/base/tts.cpp @@ -0,0 +1,656 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "tts.h" +#include "utils.h" +/********************************************************************* +* TTS Base +**********************************************************************/ +QMap TTSBase::ttsList; + +TTSBase::TTSBase(QObject* parent): EncTtsSettingInterface(parent) +{ + +} + +// static functions +void TTSBase::initTTSList() +{ + ttsList["espeak"] = "Espeak TTS Engine"; + ttsList["flite"] = "Flite TTS Engine"; + ttsList["swift"] = "Swift TTS Engine"; +#if defined(Q_OS_WIN) + ttsList["sapi"] = "Sapi TTS Engine"; +#endif +#if defined(Q_OS_LINUX) + ttsList["festival"] = "Festival TTS Engine"; +#endif +} + +// function to get a specific encoder +TTSBase* TTSBase::getTTS(QObject* parent,QString ttsName) +{ + + TTSBase* tts; +#if defined(Q_OS_WIN) + if(ttsName == "sapi") + { + tts = new TTSSapi(parent); + return tts; + } + else +#endif +#if defined(Q_OS_LINUX) + if (ttsName == "festival") + { + tts = new TTSFestival(parent); + return tts; + } + else +#endif + if (true) // fix for OS other than WIN or LINUX + { + tts = new TTSExes(ttsName,parent); + return tts; + } +} + +// get the list of encoders, nice names +QStringList TTSBase::getTTSList() +{ + // init list if its empty + if(ttsList.count() == 0) + initTTSList(); + + return ttsList.keys(); +} + +// get nice name of a specific tts +QString TTSBase::getTTSName(QString tts) +{ + if(ttsList.isEmpty()) + initTTSList(); + return ttsList.value(tts); +} + + +/********************************************************************* +* General TTS Exes +**********************************************************************/ +TTSExes::TTSExes(QString name,QObject* parent) : TTSBase(parent) +{ + m_name = name; + + m_TemplateMap["espeak"] = "\"%exe\" %options -w \"%wavfile\" \"%text\""; + m_TemplateMap["flite"] = "\"%exe\" %options -o \"%wavfile\" -t \"%text\""; + m_TemplateMap["swift"] = "\"%exe\" %options -o \"%wavfile\" \"%text\""; + +} + +void TTSExes::generateSettings() +{ + QString exepath =settings->subValue(m_name,RbSettings::TtsPath).toString(); + if(exepath == "") exepath = findExecutable(m_name); + + insertSetting(eEXEPATH,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Path to TTS engine:",exepath,EncTtsSetting::eBROWSEBTN)); + insertSetting(eOPTIONS,new EncTtsSetting(this,EncTtsSetting::eSTRING,"TTS enginge options:",settings->subValue(m_name,RbSettings::TtsOptions))); +} + +void TTSExes::saveSettings() +{ + settings->setSubValue(m_name,RbSettings::TtsPath,getSetting(eEXEPATH)->current().toString()); + settings->setSubValue(m_name,RbSettings::TtsOptions,getSetting(eOPTIONS)->current().toString()); + settings->sync(); +} + +bool TTSExes::start(QString *errStr) +{ + m_TTSexec = settings->subValue(m_name,RbSettings::TtsPath).toString(); + m_TTSOpts = settings->subValue(m_name,RbSettings::TtsOptions).toString(); + + m_TTSTemplate = m_TemplateMap.value(m_name); + + QFileInfo tts(m_TTSexec); + if(tts.exists()) + { + return true; + } + else + { + *errStr = tr("TTS executable not found"); + return false; + } +} + +TTSStatus TTSExes::voice(QString text,QString wavfile, QString *errStr) +{ + (void) errStr; + QString execstring = m_TTSTemplate; + + execstring.replace("%exe",m_TTSexec); + execstring.replace("%options",m_TTSOpts); + execstring.replace("%wavfile",wavfile); + execstring.replace("%text",text); + //qDebug() << "voicing" << execstring; + QProcess::execute(execstring); + return NoError; + +} + +bool TTSExes::configOk() +{ + QString path = settings->subValue(m_name,RbSettings::TtsPath).toString(); + + if (QFileInfo(path).exists()) + return true; + + return false; +} + +/********************************************************************* +* TTS Sapi +**********************************************************************/ +TTSSapi::TTSSapi(QObject* parent) : TTSBase(parent) +{ + m_TTSTemplate = "cscript //nologo \"%exe\" /language:%lang /voice:\"%voice\" /speed:%speed \"%options\""; + defaultLanguage ="english"; + m_sapi4 =false; +} + +void TTSSapi::generateSettings() +{ + // language + QStringList languages = settings->languages(); + languages.sort(); + EncTtsSetting* setting =new EncTtsSetting(this,EncTtsSetting::eSTRINGLIST,"Language:",settings->subValue("sapi",RbSettings::TtsLanguage),languages); + connect(setting,SIGNAL(dataChanged()),this,SLOT(updateVoiceList())); + insertSetting(eLANGUAGE,setting); + // voice + setting = new EncTtsSetting(this,EncTtsSetting::eSTRINGLIST,"Voice:",settings->subValue("sapi",RbSettings::TtsVoice),getVoiceList(settings->subValue("sapi",RbSettings::TtsLanguage).toString()),EncTtsSetting::eREFRESHBTN); + connect(setting,SIGNAL(refresh()),this,SLOT(updateVoiceList())); + insertSetting(eVOICE,setting); + //speed + insertSetting(eSPEED,new EncTtsSetting(this,EncTtsSetting::eINT,"Speed:",settings->subValue("sapi",RbSettings::TtsSpeed),-10,10)); + // options + insertSetting(eOPTIONS,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Options:",settings->subValue("sapi",RbSettings::TtsOptions))); + +} + +void TTSSapi::saveSettings() +{ + //save settings in user config + settings->setSubValue("sapi",RbSettings::TtsLanguage,getSetting(eLANGUAGE)->current().toString()); + settings->setSubValue("sapi",RbSettings::TtsVoice,getSetting(eVOICE)->current().toString()); + settings->setSubValue("sapi",RbSettings::TtsSpeed,getSetting(eSPEED)->current().toInt()); + settings->setSubValue("sapi",RbSettings::TtsOptions,getSetting(eOPTIONS)->current().toString()); + + settings->sync(); +} + +void TTSSapi::updateVoiceList() +{ + qDebug() << "update voiceList"; + QStringList voiceList = getVoiceList(getSetting(eLANGUAGE)->current().toString()); + getSetting(eVOICE)->setList(voiceList); + if(voiceList.size() > 0) getSetting(eVOICE)->setCurrent(voiceList.at(0)); + else getSetting(eVOICE)->setCurrent(""); +} + +bool TTSSapi::start(QString *errStr) +{ + + m_TTSOpts = settings->subValue("sapi",RbSettings::TtsOptions).toString(); + m_TTSLanguage =settings->subValue("sapi",RbSettings::TtsLanguage).toString(); + m_TTSVoice=settings->subValue("sapi",RbSettings::TtsVoice).toString(); + m_TTSSpeed=settings->subValue("sapi",RbSettings::TtsSpeed).toString(); + m_sapi4 = settings->subValue("sapi",RbSettings::TtsUseSapi4).toBool(); + + QFile::remove(QDir::tempPath() +"/sapi_voice.vbs"); + QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs"); + m_TTSexec = QDir::tempPath() +"/sapi_voice.vbs"; + + QFileInfo tts(m_TTSexec); + if(!tts.exists()) + { + *errStr = tr("Could not copy the Sapi-script"); + return false; + } + // create the voice process + QString execstring = m_TTSTemplate; + execstring.replace("%exe",m_TTSexec); + execstring.replace("%options",m_TTSOpts); + execstring.replace("%lang",m_TTSLanguage); + execstring.replace("%voice",m_TTSVoice); + execstring.replace("%speed",m_TTSSpeed); + + if(m_sapi4) + execstring.append(" /sapi4 "); + + qDebug() << "init" << execstring; + voicescript = new QProcess(NULL); + //connect(voicescript,SIGNAL(readyReadStandardError()),this,SLOT(error())); + + voicescript->start(execstring); + if(!voicescript->waitForStarted()) + { + *errStr = tr("Could not start the Sapi-script"); + return false; + } + + if(!voicescript->waitForReadyRead(300)) + { + *errStr = voicescript->readAllStandardError(); + if(*errStr != "") + return false; + } + + voicestream = new QTextStream(voicescript); + voicestream->setCodec("UTF16-LE"); + + return true; +} + + +QStringList TTSSapi::getVoiceList(QString language) +{ + QStringList result; + + QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs"); + m_TTSexec = QDir::tempPath() +"/sapi_voice.vbs"; + + QFileInfo tts(m_TTSexec); + if(!tts.exists()) + return result; + + // create the voice process + QString execstring = "cscript //nologo \"%exe\" /language:%lang /listvoices"; + execstring.replace("%exe",m_TTSexec); + execstring.replace("%lang",language); + + if(settings->value(RbSettings::TtsUseSapi4).toBool()) + execstring.append(" /sapi4 "); + + qDebug() << "init" << execstring; + voicescript = new QProcess(NULL); + voicescript->start(execstring); + qDebug() << "wait for started"; + if(!voicescript->waitForStarted()) + return result; + voicescript->closeWriteChannel(); + voicescript->waitForReadyRead(); + + QString dataRaw = voicescript->readAllStandardError().data(); + result = dataRaw.split(",",QString::SkipEmptyParts); + if(result.size() > 0) + { + result.sort(); + result.removeFirst(); + for(int i = 0; i< result.size();i++) + { + result[i] = result.at(i).simplified(); + } + } + + delete voicescript; + QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",QFile::ReadOwner |QFile::WriteOwner|QFile::ExeOwner + |QFile::ReadUser| QFile::WriteUser| QFile::ExeUser + |QFile::ReadGroup |QFile::WriteGroup |QFile::ExeGroup + |QFile::ReadOther |QFile::WriteOther |QFile::ExeOther ); + QFile::remove(QDir::tempPath() +"/sapi_voice.vbs"); + return result; +} + + + +TTSStatus TTSSapi::voice(QString text,QString wavfile, QString *errStr) +{ + (void) errStr; + QString query = "SPEAK\t"+wavfile+"\t"+text+"\r\n"; + qDebug() << "voicing" << query; + *voicestream << query; + *voicestream << "SYNC\tbla\r\n"; + voicestream->flush(); + voicescript->waitForReadyRead(); + return NoError; +} + +bool TTSSapi::stop() +{ + + *voicestream << "QUIT\r\n"; + voicestream->flush(); + voicescript->waitForFinished(); + delete voicestream; + delete voicescript; + QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",QFile::ReadOwner |QFile::WriteOwner|QFile::ExeOwner + |QFile::ReadUser| QFile::WriteUser| QFile::ExeUser + |QFile::ReadGroup |QFile::WriteGroup |QFile::ExeGroup + |QFile::ReadOther |QFile::WriteOther |QFile::ExeOther ); + QFile::remove(QDir::tempPath() +"/sapi_voice.vbs"); + return true; +} + +bool TTSSapi::configOk() +{ + if(settings->subValue("sapi",RbSettings::TtsVoice).toString().isEmpty()) + return false; + return true; +} +/********************************************************************** + * TSSFestival - client-server wrapper + **********************************************************************/ +TTSFestival::~TTSFestival() +{ + stop(); +} + +void TTSFestival::generateSettings() +{ + // server path + QString exepath = settings->subValue("festival-server",RbSettings::TtsPath).toString(); + if(exepath == "" ) exepath = findExecutable("festival"); + insertSetting(eSERVERPATH,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Path to Festival server:",exepath,EncTtsSetting::eBROWSEBTN)); + + // client path + QString clientpath = settings->subValue("festival-client",RbSettings::TtsPath).toString(); + if(clientpath == "" ) clientpath = findExecutable("festival_client"); + insertSetting(eCLIENTPATH,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Path to Festival client:",clientpath,EncTtsSetting::eBROWSEBTN)); + + // voice + EncTtsSetting* setting = new EncTtsSetting(this,EncTtsSetting::eSTRINGLIST,"Voice:",settings->subValue("festival",RbSettings::TtsVoice),getVoiceList(exepath),EncTtsSetting::eREFRESHBTN); + connect(setting,SIGNAL(refresh()),this,SLOT(updateVoiceList())); + connect(setting,SIGNAL(dataChanged()),this,SLOT(clearVoiceDescription())); + insertSetting(eVOICE,setting); + + //voice description + setting = new EncTtsSetting(this,EncTtsSetting::eREADONLYSTRING,"Voice description:","",EncTtsSetting::eREFRESHBTN); + connect(setting,SIGNAL(refresh()),this,SLOT(updateVoiceDescription())); + insertSetting(eVOICEDESC,setting); +} + +void TTSFestival::saveSettings() +{ + //save settings in user config + settings->setSubValue("festival-server",RbSettings::TtsPath,getSetting(eSERVERPATH)->current().toString()); + settings->setSubValue("festival-client",RbSettings::TtsPath,getSetting(eCLIENTPATH)->current().toString()); + settings->setSubValue("festival",RbSettings::TtsVoice,getSetting(eVOICE)->current().toString()); + + settings->sync(); +} + +void TTSFestival::updateVoiceDescription() +{ + // get voice Info with current voice and path + QString info = getVoiceInfo(getSetting(eVOICE)->current().toString(),getSetting(eSERVERPATH)->current().toString()); + getSetting(eVOICEDESC)->setCurrent(info); +} + +void TTSFestival::clearVoiceDescription() +{ + getSetting(eVOICEDESC)->setCurrent(""); +} + +void TTSFestival::updateVoiceList() +{ + QStringList voiceList = getVoiceList(getSetting(eSERVERPATH)->current().toString()); + getSetting(eVOICE)->setList(voiceList); + if(voiceList.size() > 0) getSetting(eVOICE)->setCurrent(voiceList.at(0)); + else getSetting(eVOICE)->setCurrent(""); +} + +void TTSFestival::startServer(QString path) +{ + if(!configOk()) + return; + + if(path == "") + path = settings->subValue("festival-server",RbSettings::TtsPath).toString(); + + serverProcess.start(QString("%1 --server").arg(path)); + serverProcess.waitForStarted(); + + queryServer("(getpid)",300,path); + if(serverProcess.state() == QProcess::Running) + qDebug() << "Festival is up and running"; + else + qDebug() << "Festival failed to start"; +} + +void TTSFestival::ensureServerRunning(QString path) +{ + if(serverProcess.state() != QProcess::Running) + { + startServer(path); + } +} + +bool TTSFestival::start(QString* errStr) +{ + (void) errStr; + ensureServerRunning(); + if (!settings->subValue("festival",RbSettings::TtsVoice).toString().isEmpty()) + queryServer(QString("(voice.select '%1)") + .arg(settings->subValue("festival", RbSettings::TtsVoice).toString())); + + return true; +} + +bool TTSFestival::stop() +{ + serverProcess.terminate(); + serverProcess.kill(); + + return true; +} + +TTSStatus TTSFestival::voice(QString text, QString wavfile, QString* errStr) +{ + qDebug() << text << "->" << wavfile; + + QString path = settings->subValue("festival-client",RbSettings::TtsPath).toString(); + QString cmd = QString("%1 --server localhost --otype riff --ttw --withlisp --output \"%2\" - ").arg(path).arg(wavfile); + qDebug() << cmd; + + QProcess clientProcess; + clientProcess.start(cmd); + clientProcess.write(QString("%1.\n").arg(text).toAscii()); + clientProcess.waitForBytesWritten(); + clientProcess.closeWriteChannel(); + clientProcess.waitForReadyRead(); + QString response = clientProcess.readAll(); + response = response.trimmed(); + if(!response.contains("Utterance")) + { + qDebug() << "Could not voice string: " << response; + *errStr = tr("engine could not voice string"); + return Warning; + /* do not stop the voicing process because of a single string + TODO: needs proper settings */ + } + clientProcess.closeReadChannel(QProcess::StandardError); + clientProcess.closeReadChannel(QProcess::StandardOutput); + clientProcess.terminate(); + clientProcess.kill(); + + return NoError; +} + +bool TTSFestival::configOk() +{ + QString serverPath = settings->subValue("festival-server",RbSettings::TtsPath).toString(); + QString clientPath = settings->subValue("festival-client",RbSettings::TtsVoice).toString(); + + bool ret = QFileInfo(serverPath).isExecutable() && + QFileInfo(clientPath).isExecutable(); + if(settings->subValue("festival",RbSettings::TtsVoice).toString().size() > 0 && voices.size() > 0) + ret = ret && (voices.indexOf(settings->subValue("festival",RbSettings::TtsVoice).toString()) != -1); + return ret; +} + +QStringList TTSFestival::getVoiceList(QString path) +{ + if(!configOk()) + return QStringList(); + + if(voices.size() > 0) + { + qDebug() << "Using voice cache"; + return voices; + } + + QString response = queryServer("(voice.list)",3000,path); + + // get the 2nd line. It should be (, ) + response = response.mid(response.indexOf('\n') + 1, -1); + response = response.left(response.indexOf('\n')).trimmed(); + + voices = response.mid(1, response.size()-2).split(' '); + + voices.sort(); + if (voices.size() == 1 && voices[0].size() == 0) + voices.removeAt(0); + if (voices.size() > 0) + qDebug() << "Voices: " << voices; + else + qDebug() << "No voices."; + + return voices; +} + +QString TTSFestival::getVoiceInfo(QString voice,QString path) +{ + if(!configOk()) + return ""; + + if(!getVoiceList().contains(voice)) + return ""; + + if(voiceDescriptions.contains(voice)) + return voiceDescriptions[voice]; + + QString response = queryServer(QString("(voice.description '%1)").arg(voice), 3000,path); + + if (response == "") + { + voiceDescriptions[voice]=tr("No description available"); + } + else + { + response = response.remove(QRegExp("(description \"*\")", Qt::CaseInsensitive, QRegExp::Wildcard)); + qDebug() << "voiceInfo w/o descr: " << response; + response = response.remove(')'); + QStringList responseLines = response.split('(', QString::SkipEmptyParts); + responseLines.removeAt(0); // the voice name itself + + QString description; + foreach(QString line, responseLines) + { + line = line.remove('('); + line = line.simplified(); + + line[0] = line[0].toUpper(); // capitalize the key + + int firstSpace = line.indexOf(' '); + if (firstSpace > 0) + { + line = line.insert(firstSpace, ':'); // add a colon between the key and the value + line[firstSpace+2] = line[firstSpace+2].toUpper(); // capitalize the value + } + + description += line + "\n"; + } + voiceDescriptions[voice] = description.trimmed(); + } + + return voiceDescriptions[voice]; +} + +QString TTSFestival::queryServer(QString query, int timeout,QString path) +{ + if(!configOk()) + return ""; + + // this operation could take some time + emit busy(); + + ensureServerRunning(path); + + qDebug() << "queryServer with " << query; + QString response; + + QDateTime endTime; + if(timeout > 0) + endTime = QDateTime::currentDateTime().addMSecs(timeout); + + /* Festival is *extremely* unreliable. Although at this + * point we are sure that SIOD is accepting commands, + * we might end up with an empty response. Hence, the loop. + */ + while(true) + { + QCoreApplication::processEvents(QEventLoop::AllEvents, 50); + QTcpSocket socket; + + socket.connectToHost("localhost", 1314); + socket.waitForConnected(); + + if(socket.state() == QAbstractSocket::ConnectedState) + { + socket.write(QString("%1\n").arg(query).toAscii()); + socket.waitForBytesWritten(); + socket.waitForReadyRead(); + + response = socket.readAll().trimmed(); + + if (response != "LP" && response != "") + break; + } + socket.abort(); + socket.disconnectFromHost(); + + if(timeout > 0 && QDateTime::currentDateTime() >= endTime) + { + emit busyEnd(); + return ""; + } + /* make sure we wait a little as we don't want to flood the server with requests */ + QDateTime tmpEndTime = QDateTime::currentDateTime().addMSecs(500); + while(QDateTime::currentDateTime() < tmpEndTime) + QCoreApplication::processEvents(QEventLoop::AllEvents); + } + if(response == "nil") + { + emit busyEnd(); + return ""; + } + + QStringList lines = response.split('\n'); + if(lines.size() > 2) + { + lines.removeFirst(); + lines.removeLast(); + } + else + qDebug() << "Response too short: " << response; + + emit busyEnd(); + return lines.join("\n"); + +} + diff --git a/rbutil/rbutilqt/base/tts.h b/rbutil/rbutilqt/base/tts.h new file mode 100644 index 0000000000..093ccd6138 --- /dev/null +++ b/rbutil/rbutilqt/base/tts.h @@ -0,0 +1,185 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2007 by Dominik Wenger + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + + +#ifndef TTS_H +#define TTS_H + +#include "rbsettings.h" +#include +#include +#include +#include +#include + +#include "encttssettings.h" + +enum TTSStatus{ FatalError, NoError, Warning }; + +class TTSBase : public EncTtsSettingInterface +{ + Q_OBJECT + public: + TTSBase(QObject *parent); + //! Child class should generate a clip + virtual TTSStatus voice(QString text,QString wavfile, QString* errStr) =0; + //! Child class should do startup + virtual bool start(QString *errStr) =0; + //! child class should stop + virtual bool stop() =0; + + // configuration + //! Child class should return true, when configuration is good + virtual bool configOk()=0; + //! Child class should generate and insertSetting(..) its settings + virtual void generateSettings() = 0; + //! Chlid class should commit the Settings to permanent storage + virtual void saveSettings() = 0; + + // static functions + static TTSBase* getTTS(QObject* parent,QString ttsname); + static QStringList getTTSList(); + static QString getTTSName(QString tts); + + // sets the config. Users of TTS classes, always have to call this first + void setCfg(RbSettings* sett) { settings = sett; } + + private: + //inits the tts List + static void initTTSList(); + + protected: + RbSettings* settings; + static QMap ttsList; +}; + +class TTSSapi : public TTSBase +{ + //! Enum to identify the settings + enum ESettings + { + eLANGUAGE, + eVOICE, + eSPEED, + eOPTIONS + }; + + Q_OBJECT + public: + TTSSapi(QObject* parent=NULL); + + TTSStatus voice(QString text,QString wavfile, QString *errStr); + bool start(QString *errStr); + bool stop(); + + // for settings + bool configOk(); + void generateSettings(); + void saveSettings(); + + private slots: + void updateVoiceList(); + + private: + QStringList getVoiceList(QString language); + + QProcess* voicescript; + QTextStream* voicestream; + QString defaultLanguage; + + QString m_TTSexec; + QString m_TTSOpts; + QString m_TTSTemplate; + QString m_TTSLanguage; + QString m_TTSVoice; + QString m_TTSSpeed; + bool m_sapi4; +}; + + +class TTSExes : public TTSBase +{ + enum ESettings + { + eEXEPATH, + eOPTIONS + }; + + Q_OBJECT + public: + TTSExes(QString name,QObject* parent=NULL); + TTSStatus voice(QString text,QString wavfile, QString *errStr); + bool start(QString *errStr); + bool stop() {return true;} + + // for settings + void generateSettings(); + void saveSettings(); + bool configOk(); + + private: + QString m_name; + QString m_TTSexec; + QString m_TTSOpts; + QString m_TTSTemplate; + QMap m_TemplateMap; +}; + +class TTSFestival : public TTSBase +{ + enum ESettings + { + eSERVERPATH, + eCLIENTPATH, + eVOICE, + eVOICEDESC + }; + + Q_OBJECT +public: + TTSFestival(QObject* parent=NULL) :TTSBase(parent) {} + ~TTSFestival(); + bool start(QString *errStr); + bool stop(); + TTSStatus voice(QString text,QString wavfile, QString *errStr); + + // for settings + bool configOk(); + void generateSettings(); + void saveSettings(); + +private slots: + void updateVoiceList(); + void updateVoiceDescription(); + void clearVoiceDescription(); +private: + QStringList getVoiceList(QString path =""); + QString getVoiceInfo(QString voice,QString path =""); + + inline void startServer(QString path=""); + inline void ensureServerRunning(QString path=""); + QString queryServer(QString query, int timeout = -1,QString path=""); + QProcess serverProcess; + QStringList voices; + QMap voiceDescriptions; +}; + +#endif diff --git a/rbutil/rbutilqt/encoders.cpp b/rbutil/rbutilqt/encoders.cpp deleted file mode 100644 index 6ff1185c82..0000000000 --- a/rbutil/rbutilqt/encoders.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * 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 "encoders.h" -#include "utils.h" - -/********************************************************************* -* Encoder Base -**********************************************************************/ -QMap EncBase::encoderList; - -EncBase::EncBase(QObject *parent): EncTtsSettingInterface(parent) -{ - -} - -// initialize list of encoders -void EncBase::initEncodernamesList() -{ - encoderList["rbspeex"] = "Rockbox Speex Encoder"; - encoderList["lame"] = "Lame Mp3 Encoder"; -} - - -// get nice name for a specific encoder -QString EncBase::getEncoderName(QString encoder) -{ - if(encoderList.isEmpty()) - initEncodernamesList(); - return encoderList.value(encoder); -} - - -// get a specific encoder object -EncBase* EncBase::getEncoder(QObject* parent,QString encoder) -{ - EncBase* enc; - if(encoder == "lame") - { - enc = new EncExes(encoder,parent); - return enc; - } - else // rbspeex is default - { - enc = new EncRbSpeex(parent); - return enc; - } -} - - -QStringList EncBase::getEncoderList() -{ - if(encoderList.isEmpty()) - initEncodernamesList(); - return encoderList.keys(); -} - - -/********************************************************************* -* GEneral Exe Encoder -**********************************************************************/ -EncExes::EncExes(QString name,QObject *parent) : EncBase(parent) -{ - m_name = name; - - m_TemplateMap["lame"] = "\"%exe\" %options \"%input\" \"%output\""; - -} - - - -void EncExes::generateSettings() -{ - QString exepath =settings->subValue(m_name,RbSettings::EncoderPath).toString(); - if(exepath == "") exepath = findExecutable(m_name); - - insertSetting(eEXEPATH,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Path to Encoder:",exepath,EncTtsSetting::eBROWSEBTN)); - insertSetting(eEXEOPTIONS,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Encoder options:",settings->subValue(m_name,RbSettings::EncoderOptions))); -} - -void EncExes::saveSettings() -{ - settings->setSubValue(m_name,RbSettings::EncoderPath,getSetting(eEXEPATH)->current().toString()); - settings->setSubValue(m_name,RbSettings::EncoderOptions,getSetting(eEXEOPTIONS)->current().toString()); - settings->sync(); -} - -bool EncExes::start() -{ - m_EncExec = settings->subValue(m_name, RbSettings::EncoderPath).toString(); - m_EncOpts = settings->subValue(m_name, RbSettings::EncoderOptions).toString(); - - m_EncTemplate = m_TemplateMap.value(m_name); - - QFileInfo enc(m_EncExec); - if(enc.exists()) - { - return true; - } - else - { - return false; - } -} - -bool EncExes::encode(QString input,QString output) -{ - //qDebug() << "encoding.."; - QString execstring = m_EncTemplate; - - execstring.replace("%exe",m_EncExec); - execstring.replace("%options",m_EncOpts); - execstring.replace("%input",input); - execstring.replace("%output",output); - qDebug() << execstring; - QProcess::execute(execstring); - return true; -} - - -bool EncExes::configOk() -{ - QString path = settings->subValue(m_name, RbSettings::EncoderPath).toString(); - - if (QFileInfo(path).exists()) - return true; - - return false; -} - -/********************************************************************* -* RB SPEEX ENCODER -**********************************************************************/ -EncRbSpeex::EncRbSpeex(QObject *parent) : EncBase(parent) -{ - -} - -void EncRbSpeex::generateSettings() -{ - insertSetting(eVOLUME,new EncTtsSetting(this,EncTtsSetting::eDOUBLE,"Volume:",settings->subValue("rbspeex",RbSettings::EncoderVolume),1.0,10.0)); - insertSetting(eQUALITY,new EncTtsSetting(this,EncTtsSetting::eDOUBLE,"Quality:",settings->subValue("rbspeex",RbSettings::EncoderQuality),0,10.0)); - insertSetting(eCOMPLEXITY,new EncTtsSetting(this,EncTtsSetting::eINT,"Complexity:",settings->subValue("rbspeex",RbSettings::EncoderComplexity),0,10)); - insertSetting(eNARROWBAND,new EncTtsSetting(this,EncTtsSetting::eBOOL,"Use Narrowband:",settings->subValue("rbspeex",RbSettings::EncoderNarrowBand))); -} - -void EncRbSpeex::saveSettings() -{ - //save settings in user config - settings->setSubValue("rbspeex",RbSettings::EncoderVolume,getSetting(eVOLUME)->current().toDouble()); - settings->setSubValue("rbspeex",RbSettings::EncoderQuality,getSetting(eQUALITY)->current().toDouble()); - settings->setSubValue("rbspeex",RbSettings::EncoderComplexity,getSetting(eCOMPLEXITY)->current().toInt()); - settings->setSubValue("rbspeex",RbSettings::EncoderNarrowBand,getSetting(eNARROWBAND)->current().toBool()); - - settings->sync(); -} - -bool EncRbSpeex::start() -{ - - // try to get config from settings - quality = settings->subValue("rbspeex", RbSettings::EncoderQuality).toDouble(); - complexity = settings->subValue("rbspeex", RbSettings::EncoderComplexity).toInt(); - volume = settings->subValue("rbspeex", RbSettings::EncoderVolume).toDouble(); - narrowband = settings->subValue("rbspeex", RbSettings::EncoderNarrowBand).toBool(); - - - return true; -} - -bool EncRbSpeex::encode(QString input,QString output) -{ - qDebug() << "encoding " << input << " to "<< output; - char errstr[512]; - - FILE *fin,*fout; - if ((fin = fopen(input.toLocal8Bit(), "rb")) == NULL) { - qDebug() << "Error: could not open input file\n"; - return false; - } - if ((fout = fopen(output.toLocal8Bit(), "wb")) == NULL) { - qDebug() << "Error: could not open output file\n"; - return false; - } - - - int ret = encode_file(fin, fout, quality, complexity, narrowband, volume, - errstr, sizeof(errstr)); - fclose(fout); - fclose(fin); - - if (!ret) { - /* Attempt to delete unfinished output */ - qDebug() << "Error:" << errstr; - QFile(output).remove(); - return false; - } - return true; -} - -bool EncRbSpeex::configOk() -{ - bool result=true; - // check config - - if(settings->subValue("rbspeex", RbSettings::EncoderVolume).toDouble() <= 0) - result =false; - - if(settings->subValue("rbspeex", RbSettings::EncoderQuality).toDouble() <= 0) - result =false; - - if(settings->subValue("rbspeex", RbSettings::EncoderComplexity).toInt() <= 0) - result =false; - - return result; -} - diff --git a/rbutil/rbutilqt/encoders.h b/rbutil/rbutilqt/encoders.h deleted file mode 100644 index d5d1723a46..0000000000 --- a/rbutil/rbutilqt/encoders.h +++ /dev/null @@ -1,133 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * - * Copyright (C) 2007 by Dominik Wenger - * $Id$ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#ifndef ENCODERS_H -#define ENCODERS_H - -#include - -#include "rbsettings.h" -#include "encttssettings.h" -#include "rbspeex.h" - - -class EncBase : public EncTtsSettingInterface -{ - Q_OBJECT - public: - EncBase(QObject *parent ); - - //! Child class should encode a wav file - virtual bool encode(QString input,QString output) =0; - //! Child class should do startup - virtual bool start()=0; - //! Child class should stop - virtual bool stop()=0; - - // settings - //! Child class should return true when configuration is ok - virtual bool configOk()=0; - //! Child class should fill in the setttingsList - virtual void generateSettings() = 0; - //! Chlid class should commit the from SettingsList to permanent storage - virtual void saveSettings() = 0; - - // static functions - static QString getEncoderName(QString name); - static EncBase* getEncoder(QObject* parent,QString name); - static QStringList getEncoderList(void); - - //set the config. users of Encoder classes, always have to call this first - void setCfg(RbSettings *sett){settings = sett;} - private: - static void initEncodernamesList(void); - - protected: - RbSettings* settings; - - static QMap encoderList; -}; - - -class EncExes : public EncBase -{ - enum ESettings - { - eEXEPATH, - eEXEOPTIONS - }; - - Q_OBJECT -public: - EncExes(QString name,QObject *parent = NULL); - bool encode(QString input,QString output); - bool start(); - bool stop() {return true;} - - // setting - bool configOk(); - void generateSettings(); - void saveSettings(); - -private: - QString m_name; - QString m_EncExec; - QString m_EncOpts; - QMap m_TemplateMap; - QString m_EncTemplate; -}; - -class EncRbSpeex : public EncBase -{ - enum ESettings - { - eVOLUME, - eQUALITY, - eCOMPLEXITY, - eNARROWBAND - }; - - Q_OBJECT -public: - EncRbSpeex(QObject *parent = NULL); - bool encode(QString input,QString output); - bool start(); - bool stop() {return true;} - - // for settings view - bool configOk(); - void generateSettings(); - void saveSettings(); - -private: - float quality; - float volume; - int complexity; - bool narrowband; - - float defaultQuality; - float defaultVolume; - int defaultComplexity; - bool defaultBand; -}; - - -#endif diff --git a/rbutil/rbutilqt/encttssettings.cpp b/rbutil/rbutilqt/encttssettings.cpp deleted file mode 100644 index fa7cfb39c2..0000000000 --- a/rbutil/rbutilqt/encttssettings.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * - * Copyright (C) 2007 by Dominik Wenger - * $Id: encoders.h 17902 2008-06-30 22:09:45Z bluebrother $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "encttssettings.h" - - -EncTtsSetting::EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current, EButton btn) -{ - m_btn = btn; - m_name =name; - m_type =type; - m_currentValue = current; -} - -EncTtsSetting::EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current,QStringList list,EButton btn) -{ - m_btn = btn; - m_name =name; - m_type =type; - m_currentValue = current; - m_list = list; -} - -EncTtsSetting::EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current,QVariant min,QVariant max, EButton btn) -{ - m_btn = btn; - m_name =name; - m_type =type; - m_currentValue = current; - m_minValue = min; - m_maxValue = max; -} - -void EncTtsSetting::setCurrent(QVariant current,bool noticeGui) -{ - m_currentValue = current; - emit dataChanged(); - - if(noticeGui) emit updateGui(); -} - -//! insert a setting -void EncTtsSettingInterface::insertSetting(int id,EncTtsSetting* setting) -{ - settingsList.insert(id,setting); -} - -//! retrieve a specific setting -EncTtsSetting* EncTtsSettingInterface::getSetting(int id) -{ - return settingsList.at(id); -} diff --git a/rbutil/rbutilqt/encttssettings.h b/rbutil/rbutilqt/encttssettings.h deleted file mode 100644 index 843829a815..0000000000 --- a/rbutil/rbutilqt/encttssettings.h +++ /dev/null @@ -1,129 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * - * Copyright (C) 2007 by Dominik Wenger - * $Id: encoders.h 17902 2008-06-30 22:09:45Z bluebrother $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#ifndef ENCTTSSETTINGS_H -#define ENCTTSSETTINGS_H - -#include - -//! \brief This class stores everything needed to display a Setting. -//! -class EncTtsSetting : public QObject -{ - Q_OBJECT -public: - enum ESettingType - { - eBASE, - eBOOL, - eDOUBLE, - eINT, - eSTRING, - eREADONLYSTRING, - eSTRINGLIST, - }; - enum EButton - { - eNOBTN, - eBROWSEBTN, - eREFRESHBTN - }; - - //! constructor for a String or Bool setting - EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current,EButton btn = eNOBTN); - //! contructor for a Stringlist setting, ie a enumeration - EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current,QStringList list,EButton btn = eNOBTN); - //! constructor for a setting with a min-max range - EncTtsSetting(QObject* parent,ESettingType type,QString name,QVariant current,QVariant min,QVariant max,EButton = eNOBTN); - - //! get currentValue - QVariant current() {return m_currentValue;} - //! set currentValue - void setCurrent(QVariant current,bool noticeGui=true); - - //! get name of the Setting - QString name() {return m_name;} - //! get the type of the setting - ESettingType type() {return m_type;} - //! get what type of button this setting needs - EButton button() {return m_btn;} - //! get the minValue (only valid for a range setting, ie eDOUBLE or eINT) - QVariant min() {return m_minValue; } - //! get the maxValue (only valid for a range setting, ie eDOUBLE or eINT) - QVariant max() {return m_maxValue; } - //! get the enumerationlist (only valid for eSTRINGLIST settings) - QStringList list() {return m_list;} - //! set the enumeration list - void setList(QStringList list){m_list = list;} - -signals: - //! connect to this signal if you want to get noticed when the data changes - void dataChanged(); - //! connect to this if you want to react on refresh button - void refresh(); - //! will be emited when the gui should update this setting - void updateGui(); - -private: - ESettingType m_type; - EButton m_btn; - QString m_name; - QVariant m_currentValue; - QVariant m_minValue; - QVariant m_maxValue; - QStringList m_list; -}; - - -//! \brief this class is the Interface for Encoder and TTS engines, to display settings -//! It wraps nearly everything needed, only updateModel() and commitModel() needs to be reimplemented -//! -class EncTtsSettingInterface : public QObject -{ - Q_OBJECT -public: - EncTtsSettingInterface(QObject* parent) : QObject(parent) {} - - //! get the Settings list - QList getSettings() {generateSettings(); return settingsList;} - - //! Chlid class should commit the from SettingsList to permanent storage - virtual void saveSettings() = 0; - -signals: - void busy(); // emit this if a operation takes time - void busyEnd(); // emit this at the end of a busy section - -protected: - //! Child class should fill in the setttingsList - virtual void generateSettings() = 0; - - //! insert a setting - void insertSetting(int id,EncTtsSetting* setting); - //! retrieve a specific setting - EncTtsSetting* getSetting(int id); - -private: - //! The setting storage. - QList settingsList; - -}; -#endif diff --git a/rbutil/rbutilqt/tts.cpp b/rbutil/rbutilqt/tts.cpp deleted file mode 100644 index d55ba9e739..0000000000 --- a/rbutil/rbutilqt/tts.cpp +++ /dev/null @@ -1,656 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * 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 "tts.h" -#include "utils.h" -/********************************************************************* -* TTS Base -**********************************************************************/ -QMap TTSBase::ttsList; - -TTSBase::TTSBase(QObject* parent): EncTtsSettingInterface(parent) -{ - -} - -// static functions -void TTSBase::initTTSList() -{ - ttsList["espeak"] = "Espeak TTS Engine"; - ttsList["flite"] = "Flite TTS Engine"; - ttsList["swift"] = "Swift TTS Engine"; -#if defined(Q_OS_WIN) - ttsList["sapi"] = "Sapi TTS Engine"; -#endif -#if defined(Q_OS_LINUX) - ttsList["festival"] = "Festival TTS Engine"; -#endif -} - -// function to get a specific encoder -TTSBase* TTSBase::getTTS(QObject* parent,QString ttsName) -{ - - TTSBase* tts; -#if defined(Q_OS_WIN) - if(ttsName == "sapi") - { - tts = new TTSSapi(parent); - return tts; - } - else -#endif -#if defined(Q_OS_LINUX) - if (ttsName == "festival") - { - tts = new TTSFestival(parent); - return tts; - } - else -#endif - if (true) // fix for OS other than WIN or LINUX - { - tts = new TTSExes(ttsName,parent); - return tts; - } -} - -// get the list of encoders, nice names -QStringList TTSBase::getTTSList() -{ - // init list if its empty - if(ttsList.count() == 0) - initTTSList(); - - return ttsList.keys(); -} - -// get nice name of a specific tts -QString TTSBase::getTTSName(QString tts) -{ - if(ttsList.isEmpty()) - initTTSList(); - return ttsList.value(tts); -} - - -/********************************************************************* -* General TTS Exes -**********************************************************************/ -TTSExes::TTSExes(QString name,QObject* parent) : TTSBase(parent) -{ - m_name = name; - - m_TemplateMap["espeak"] = "\"%exe\" %options -w \"%wavfile\" \"%text\""; - m_TemplateMap["flite"] = "\"%exe\" %options -o \"%wavfile\" -t \"%text\""; - m_TemplateMap["swift"] = "\"%exe\" %options -o \"%wavfile\" \"%text\""; - -} - -void TTSExes::generateSettings() -{ - QString exepath =settings->subValue(m_name,RbSettings::TtsPath).toString(); - if(exepath == "") exepath = findExecutable(m_name); - - insertSetting(eEXEPATH,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Path to TTS engine:",exepath,EncTtsSetting::eBROWSEBTN)); - insertSetting(eOPTIONS,new EncTtsSetting(this,EncTtsSetting::eSTRING,"TTS enginge options:",settings->subValue(m_name,RbSettings::TtsOptions))); -} - -void TTSExes::saveSettings() -{ - settings->setSubValue(m_name,RbSettings::TtsPath,getSetting(eEXEPATH)->current().toString()); - settings->setSubValue(m_name,RbSettings::TtsOptions,getSetting(eOPTIONS)->current().toString()); - settings->sync(); -} - -bool TTSExes::start(QString *errStr) -{ - m_TTSexec = settings->subValue(m_name,RbSettings::TtsPath).toString(); - m_TTSOpts = settings->subValue(m_name,RbSettings::TtsOptions).toString(); - - m_TTSTemplate = m_TemplateMap.value(m_name); - - QFileInfo tts(m_TTSexec); - if(tts.exists()) - { - return true; - } - else - { - *errStr = tr("TTS executable not found"); - return false; - } -} - -TTSStatus TTSExes::voice(QString text,QString wavfile, QString *errStr) -{ - (void) errStr; - QString execstring = m_TTSTemplate; - - execstring.replace("%exe",m_TTSexec); - execstring.replace("%options",m_TTSOpts); - execstring.replace("%wavfile",wavfile); - execstring.replace("%text",text); - //qDebug() << "voicing" << execstring; - QProcess::execute(execstring); - return NoError; - -} - -bool TTSExes::configOk() -{ - QString path = settings->subValue(m_name,RbSettings::TtsPath).toString(); - - if (QFileInfo(path).exists()) - return true; - - return false; -} - -/********************************************************************* -* TTS Sapi -**********************************************************************/ -TTSSapi::TTSSapi(QObject* parent) : TTSBase(parent) -{ - m_TTSTemplate = "cscript //nologo \"%exe\" /language:%lang /voice:\"%voice\" /speed:%speed \"%options\""; - defaultLanguage ="english"; - m_sapi4 =false; -} - -void TTSSapi::generateSettings() -{ - // language - QStringList languages = settings->languages(); - languages.sort(); - EncTtsSetting* setting =new EncTtsSetting(this,EncTtsSetting::eSTRINGLIST,"Language:",settings->subValue("sapi",RbSettings::TtsLanguage),languages); - connect(setting,SIGNAL(dataChanged()),this,SLOT(updateVoiceList())); - insertSetting(eLANGUAGE,setting); - // voice - setting = new EncTtsSetting(this,EncTtsSetting::eSTRINGLIST,"Voice:",settings->subValue("sapi",RbSettings::TtsVoice),getVoiceList(settings->subValue("sapi",RbSettings::TtsLanguage).toString()),EncTtsSetting::eREFRESHBTN); - connect(setting,SIGNAL(refresh()),this,SLOT(updateVoiceList())); - insertSetting(eVOICE,setting); - //speed - insertSetting(eSPEED,new EncTtsSetting(this,EncTtsSetting::eINT,"Speed:",settings->subValue("sapi",RbSettings::TtsSpeed),-10,10)); - // options - insertSetting(eOPTIONS,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Options:",settings->subValue("sapi",RbSettings::TtsOptions))); - -} - -void TTSSapi::saveSettings() -{ - //save settings in user config - settings->setSubValue("sapi",RbSettings::TtsLanguage,getSetting(eLANGUAGE)->current().toString()); - settings->setSubValue("sapi",RbSettings::TtsVoice,getSetting(eVOICE)->current().toString()); - settings->setSubValue("sapi",RbSettings::TtsSpeed,getSetting(eSPEED)->current().toInt()); - settings->setSubValue("sapi",RbSettings::TtsOptions,getSetting(eOPTIONS)->current().toString()); - - settings->sync(); -} - -void TTSSapi::updateVoiceList() -{ - qDebug() << "update voiceList"; - QStringList voiceList = getVoiceList(getSetting(eLANGUAGE)->current().toString()); - getSetting(eVOICE)->setList(voiceList); - if(voiceList.size() > 0) getSetting(eVOICE)->setCurrent(voiceList.at(0)); - else getSetting(eVOICE)->setCurrent(""); -} - -bool TTSSapi::start(QString *errStr) -{ - - m_TTSOpts = settings->subValue("sapi",RbSettings::TtsOptions).toString(); - m_TTSLanguage =settings->subValue("sapi",RbSettings::TtsLanguage).toString(); - m_TTSVoice=settings->subValue("sapi",RbSettings::TtsVoice).toString(); - m_TTSSpeed=settings->subValue("sapi",RbSettings::TtsSpeed).toString(); - m_sapi4 = settings->subValue("sapi",RbSettings::TtsUseSapi4).toBool(); - - QFile::remove(QDir::tempPath() +"/sapi_voice.vbs"); - QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs"); - m_TTSexec = QDir::tempPath() +"/sapi_voice.vbs"; - - QFileInfo tts(m_TTSexec); - if(!tts.exists()) - { - *errStr = tr("Could not copy the Sapi-script"); - return false; - } - // create the voice process - QString execstring = m_TTSTemplate; - execstring.replace("%exe",m_TTSexec); - execstring.replace("%options",m_TTSOpts); - execstring.replace("%lang",m_TTSLanguage); - execstring.replace("%voice",m_TTSVoice); - execstring.replace("%speed",m_TTSSpeed); - - if(m_sapi4) - execstring.append(" /sapi4 "); - - qDebug() << "init" << execstring; - voicescript = new QProcess(NULL); - //connect(voicescript,SIGNAL(readyReadStandardError()),this,SLOT(error())); - - voicescript->start(execstring); - if(!voicescript->waitForStarted()) - { - *errStr = tr("Could not start the Sapi-script"); - return false; - } - - if(!voicescript->waitForReadyRead(300)) - { - *errStr = voicescript->readAllStandardError(); - if(*errStr != "") - return false; - } - - voicestream = new QTextStream(voicescript); - voicestream->setCodec("UTF16-LE"); - - return true; -} - - -QStringList TTSSapi::getVoiceList(QString language) -{ - QStringList result; - - QFile::copy(":/builtin/sapi_voice.vbs",QDir::tempPath() + "/sapi_voice.vbs"); - m_TTSexec = QDir::tempPath() +"/sapi_voice.vbs"; - - QFileInfo tts(m_TTSexec); - if(!tts.exists()) - return result; - - // create the voice process - QString execstring = "cscript //nologo \"%exe\" /language:%lang /listvoices"; - execstring.replace("%exe",m_TTSexec); - execstring.replace("%lang",language); - - if(settings->value(RbSettings::TtsUseSapi4).toBool()) - execstring.append(" /sapi4 "); - - qDebug() << "init" << execstring; - voicescript = new QProcess(NULL); - voicescript->start(execstring); - qDebug() << "wait for started"; - if(!voicescript->waitForStarted()) - return result; - voicescript->closeWriteChannel(); - voicescript->waitForReadyRead(); - - QString dataRaw = voicescript->readAllStandardError().data(); - result = dataRaw.split(",",QString::SkipEmptyParts); - if(result.size() > 0) - { - result.sort(); - result.removeFirst(); - for(int i = 0; i< result.size();i++) - { - result[i] = result.at(i).simplified(); - } - } - - delete voicescript; - QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",QFile::ReadOwner |QFile::WriteOwner|QFile::ExeOwner - |QFile::ReadUser| QFile::WriteUser| QFile::ExeUser - |QFile::ReadGroup |QFile::WriteGroup |QFile::ExeGroup - |QFile::ReadOther |QFile::WriteOther |QFile::ExeOther ); - QFile::remove(QDir::tempPath() +"/sapi_voice.vbs"); - return result; -} - - - -TTSStatus TTSSapi::voice(QString text,QString wavfile, QString *errStr) -{ - (void) errStr; - QString query = "SPEAK\t"+wavfile+"\t"+text+"\r\n"; - qDebug() << "voicing" << query; - *voicestream << query; - *voicestream << "SYNC\tbla\r\n"; - voicestream->flush(); - voicescript->waitForReadyRead(); - return NoError; -} - -bool TTSSapi::stop() -{ - - *voicestream << "QUIT\r\n"; - voicestream->flush(); - voicescript->waitForFinished(); - delete voicestream; - delete voicescript; - QFile::setPermissions(QDir::tempPath() +"/sapi_voice.vbs",QFile::ReadOwner |QFile::WriteOwner|QFile::ExeOwner - |QFile::ReadUser| QFile::WriteUser| QFile::ExeUser - |QFile::ReadGroup |QFile::WriteGroup |QFile::ExeGroup - |QFile::ReadOther |QFile::WriteOther |QFile::ExeOther ); - QFile::remove(QDir::tempPath() +"/sapi_voice.vbs"); - return true; -} - -bool TTSSapi::configOk() -{ - if(settings->subValue("sapi",RbSettings::TtsVoice).toString().isEmpty()) - return false; - return true; -} -/********************************************************************** - * TSSFestival - client-server wrapper - **********************************************************************/ -TTSFestival::~TTSFestival() -{ - stop(); -} - -void TTSFestival::generateSettings() -{ - // server path - QString exepath = settings->subValue("festival-server",RbSettings::TtsPath).toString(); - if(exepath == "" ) exepath = findExecutable("festival"); - insertSetting(eSERVERPATH,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Path to Festival server:",exepath,EncTtsSetting::eBROWSEBTN)); - - // client path - QString clientpath = settings->subValue("festival-client",RbSettings::TtsPath).toString(); - if(clientpath == "" ) clientpath = findExecutable("festival_client"); - insertSetting(eCLIENTPATH,new EncTtsSetting(this,EncTtsSetting::eSTRING,"Path to Festival client:",clientpath,EncTtsSetting::eBROWSEBTN)); - - // voice - EncTtsSetting* setting = new EncTtsSetting(this,EncTtsSetting::eSTRINGLIST,"Voice:",settings->subValue("festival",RbSettings::TtsVoice),getVoiceList(exepath),EncTtsSetting::eREFRESHBTN); - connect(setting,SIGNAL(refresh()),this,SLOT(updateVoiceList())); - connect(setting,SIGNAL(dataChanged()),this,SLOT(clearVoiceDescription())); - insertSetting(eVOICE,setting); - - //voice description - setting = new EncTtsSetting(this,EncTtsSetting::eREADONLYSTRING,"Voice description:","",EncTtsSetting::eREFRESHBTN); - connect(setting,SIGNAL(refresh()),this,SLOT(updateVoiceDescription())); - insertSetting(eVOICEDESC,setting); -} - -void TTSFestival::saveSettings() -{ - //save settings in user config - settings->setSubValue("festival-server",RbSettings::TtsPath,getSetting(eSERVERPATH)->current().toString()); - settings->setSubValue("festival-client",RbSettings::TtsPath,getSetting(eCLIENTPATH)->current().toString()); - settings->setSubValue("festival",RbSettings::TtsVoice,getSetting(eVOICE)->current().toString()); - - settings->sync(); -} - -void TTSFestival::updateVoiceDescription() -{ - // get voice Info with current voice and path - QString info = getVoiceInfo(getSetting(eVOICE)->current().toString(),getSetting(eSERVERPATH)->current().toString()); - getSetting(eVOICEDESC)->setCurrent(info); -} - -void TTSFestival::clearVoiceDescription() -{ - getSetting(eVOICEDESC)->setCurrent(""); -} - -void TTSFestival::updateVoiceList() -{ - QStringList voiceList = getVoiceList(getSetting(eSERVERPATH)->current().toString()); - getSetting(eVOICE)->setList(voiceList); - if(voiceList.size() > 0) getSetting(eVOICE)->setCurrent(voiceList.at(0)); - else getSetting(eVOICE)->setCurrent(""); -} - -void TTSFestival::startServer(QString path) -{ - if(!configOk()) - return; - - if(path == "") - path = settings->subValue("festival-server",RbSettings::TtsPath).toString(); - - serverProcess.start(QString("%1 --server").arg(path)); - serverProcess.waitForStarted(); - - queryServer("(getpid)",300,path); - if(serverProcess.state() == QProcess::Running) - qDebug() << "Festival is up and running"; - else - qDebug() << "Festival failed to start"; -} - -void TTSFestival::ensureServerRunning(QString path) -{ - if(serverProcess.state() != QProcess::Running) - { - startServer(path); - } -} - -bool TTSFestival::start(QString* errStr) -{ - (void) errStr; - ensureServerRunning(); - if (!settings->subValue("festival",RbSettings::TtsVoice).toString().isEmpty()) - queryServer(QString("(voice.select '%1)") - .arg(settings->subValue("festival", RbSettings::TtsVoice).toString())); - - return true; -} - -bool TTSFestival::stop() -{ - serverProcess.terminate(); - serverProcess.kill(); - - return true; -} - -TTSStatus TTSFestival::voice(QString text, QString wavfile, QString* errStr) -{ - qDebug() << text << "->" << wavfile; - - QString path = settings->subValue("festival-client",RbSettings::TtsPath).toString(); - QString cmd = QString("%1 --server localhost --otype riff --ttw --withlisp --output \"%2\" - ").arg(path).arg(wavfile); - qDebug() << cmd; - - QProcess clientProcess; - clientProcess.start(cmd); - clientProcess.write(QString("%1.\n").arg(text).toAscii()); - clientProcess.waitForBytesWritten(); - clientProcess.closeWriteChannel(); - clientProcess.waitForReadyRead(); - QString response = clientProcess.readAll(); - response = response.trimmed(); - if(!response.contains("Utterance")) - { - qDebug() << "Could not voice string: " << response; - *errStr = tr("engine could not voice string"); - return Warning; - /* do not stop the voicing process because of a single string - TODO: needs proper settings */ - } - clientProcess.closeReadChannel(QProcess::StandardError); - clientProcess.closeReadChannel(QProcess::StandardOutput); - clientProcess.terminate(); - clientProcess.kill(); - - return NoError; -} - -bool TTSFestival::configOk() -{ - QString serverPath = settings->subValue("festival-server",RbSettings::TtsPath).toString(); - QString clientPath = settings->subValue("festival-client",RbSettings::TtsVoice).toString(); - - bool ret = QFileInfo(serverPath).isExecutable() && - QFileInfo(clientPath).isExecutable(); - if(settings->subValue("festival",RbSettings::TtsVoice).toString().size() > 0 && voices.size() > 0) - ret = ret && (voices.indexOf(settings->subValue("festival",RbSettings::TtsVoice).toString()) != -1); - return ret; -} - -QStringList TTSFestival::getVoiceList(QString path) -{ - if(!configOk()) - return QStringList(); - - if(voices.size() > 0) - { - qDebug() << "Using voice cache"; - return voices; - } - - QString response = queryServer("(voice.list)",3000,path); - - // get the 2nd line. It should be (, ) - response = response.mid(response.indexOf('\n') + 1, -1); - response = response.left(response.indexOf('\n')).trimmed(); - - voices = response.mid(1, response.size()-2).split(' '); - - voices.sort(); - if (voices.size() == 1 && voices[0].size() == 0) - voices.removeAt(0); - if (voices.size() > 0) - qDebug() << "Voices: " << voices; - else - qDebug() << "No voices."; - - return voices; -} - -QString TTSFestival::getVoiceInfo(QString voice,QString path) -{ - if(!configOk()) - return ""; - - if(!getVoiceList().contains(voice)) - return ""; - - if(voiceDescriptions.contains(voice)) - return voiceDescriptions[voice]; - - QString response = queryServer(QString("(voice.description '%1)").arg(voice), 3000,path); - - if (response == "") - { - voiceDescriptions[voice]=tr("No description available"); - } - else - { - response = response.remove(QRegExp("(description \"*\")", Qt::CaseInsensitive, QRegExp::Wildcard)); - qDebug() << "voiceInfo w/o descr: " << response; - response = response.remove(')'); - QStringList responseLines = response.split('(', QString::SkipEmptyParts); - responseLines.removeAt(0); // the voice name itself - - QString description; - foreach(QString line, responseLines) - { - line = line.remove('('); - line = line.simplified(); - - line[0] = line[0].toUpper(); // capitalize the key - - int firstSpace = line.indexOf(' '); - if (firstSpace > 0) - { - line = line.insert(firstSpace, ':'); // add a colon between the key and the value - line[firstSpace+2] = line[firstSpace+2].toUpper(); // capitalize the value - } - - description += line + "\n"; - } - voiceDescriptions[voice] = description.trimmed(); - } - - return voiceDescriptions[voice]; -} - -QString TTSFestival::queryServer(QString query, int timeout,QString path) -{ - if(!configOk()) - return ""; - - // this operation could take some time - emit busy(); - - ensureServerRunning(path); - - qDebug() << "queryServer with " << query; - QString response; - - QDateTime endTime; - if(timeout > 0) - endTime = QDateTime::currentDateTime().addMSecs(timeout); - - /* Festival is *extremely* unreliable. Although at this - * point we are sure that SIOD is accepting commands, - * we might end up with an empty response. Hence, the loop. - */ - while(true) - { - QCoreApplication::processEvents(QEventLoop::AllEvents, 50); - QTcpSocket socket; - - socket.connectToHost("localhost", 1314); - socket.waitForConnected(); - - if(socket.state() == QAbstractSocket::ConnectedState) - { - socket.write(QString("%1\n").arg(query).toAscii()); - socket.waitForBytesWritten(); - socket.waitForReadyRead(); - - response = socket.readAll().trimmed(); - - if (response != "LP" && response != "") - break; - } - socket.abort(); - socket.disconnectFromHost(); - - if(timeout > 0 && QDateTime::currentDateTime() >= endTime) - { - emit busyEnd(); - return ""; - } - /* make sure we wait a little as we don't want to flood the server with requests */ - QDateTime tmpEndTime = QDateTime::currentDateTime().addMSecs(500); - while(QDateTime::currentDateTime() < tmpEndTime) - QCoreApplication::processEvents(QEventLoop::AllEvents); - } - if(response == "nil") - { - emit busyEnd(); - return ""; - } - - QStringList lines = response.split('\n'); - if(lines.size() > 2) - { - lines.removeFirst(); - lines.removeLast(); - } - else - qDebug() << "Response too short: " << response; - - emit busyEnd(); - return lines.join("\n"); - -} - diff --git a/rbutil/rbutilqt/tts.h b/rbutil/rbutilqt/tts.h deleted file mode 100644 index 093ccd6138..0000000000 --- a/rbutil/rbutilqt/tts.h +++ /dev/null @@ -1,185 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * - * Copyright (C) 2007 by Dominik Wenger - * $Id$ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - - -#ifndef TTS_H -#define TTS_H - -#include "rbsettings.h" -#include -#include -#include -#include -#include - -#include "encttssettings.h" - -enum TTSStatus{ FatalError, NoError, Warning }; - -class TTSBase : public EncTtsSettingInterface -{ - Q_OBJECT - public: - TTSBase(QObject *parent); - //! Child class should generate a clip - virtual TTSStatus voice(QString text,QString wavfile, QString* errStr) =0; - //! Child class should do startup - virtual bool start(QString *errStr) =0; - //! child class should stop - virtual bool stop() =0; - - // configuration - //! Child class should return true, when configuration is good - virtual bool configOk()=0; - //! Child class should generate and insertSetting(..) its settings - virtual void generateSettings() = 0; - //! Chlid class should commit the Settings to permanent storage - virtual void saveSettings() = 0; - - // static functions - static TTSBase* getTTS(QObject* parent,QString ttsname); - static QStringList getTTSList(); - static QString getTTSName(QString tts); - - // sets the config. Users of TTS classes, always have to call this first - void setCfg(RbSettings* sett) { settings = sett; } - - private: - //inits the tts List - static void initTTSList(); - - protected: - RbSettings* settings; - static QMap ttsList; -}; - -class TTSSapi : public TTSBase -{ - //! Enum to identify the settings - enum ESettings - { - eLANGUAGE, - eVOICE, - eSPEED, - eOPTIONS - }; - - Q_OBJECT - public: - TTSSapi(QObject* parent=NULL); - - TTSStatus voice(QString text,QString wavfile, QString *errStr); - bool start(QString *errStr); - bool stop(); - - // for settings - bool configOk(); - void generateSettings(); - void saveSettings(); - - private slots: - void updateVoiceList(); - - private: - QStringList getVoiceList(QString language); - - QProcess* voicescript; - QTextStream* voicestream; - QString defaultLanguage; - - QString m_TTSexec; - QString m_TTSOpts; - QString m_TTSTemplate; - QString m_TTSLanguage; - QString m_TTSVoice; - QString m_TTSSpeed; - bool m_sapi4; -}; - - -class TTSExes : public TTSBase -{ - enum ESettings - { - eEXEPATH, - eOPTIONS - }; - - Q_OBJECT - public: - TTSExes(QString name,QObject* parent=NULL); - TTSStatus voice(QString text,QString wavfile, QString *errStr); - bool start(QString *errStr); - bool stop() {return true;} - - // for settings - void generateSettings(); - void saveSettings(); - bool configOk(); - - private: - QString m_name; - QString m_TTSexec; - QString m_TTSOpts; - QString m_TTSTemplate; - QMap m_TemplateMap; -}; - -class TTSFestival : public TTSBase -{ - enum ESettings - { - eSERVERPATH, - eCLIENTPATH, - eVOICE, - eVOICEDESC - }; - - Q_OBJECT -public: - TTSFestival(QObject* parent=NULL) :TTSBase(parent) {} - ~TTSFestival(); - bool start(QString *errStr); - bool stop(); - TTSStatus voice(QString text,QString wavfile, QString *errStr); - - // for settings - bool configOk(); - void generateSettings(); - void saveSettings(); - -private slots: - void updateVoiceList(); - void updateVoiceDescription(); - void clearVoiceDescription(); -private: - QStringList getVoiceList(QString path =""); - QString getVoiceInfo(QString voice,QString path =""); - - inline void startServer(QString path=""); - inline void ensureServerRunning(QString path=""); - QString queryServer(QString query, int timeout = -1,QString path=""); - QProcess serverProcess; - QStringList voices; - QMap voiceDescriptions; -}; - -#endif -- cgit v1.2.3