summaryrefslogtreecommitdiffstats
path: root/kttsd/plugins/hadifix/hadifixconf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kttsd/plugins/hadifix/hadifixconf.cpp')
-rw-r--r--kttsd/plugins/hadifix/hadifixconf.cpp406
1 files changed, 406 insertions, 0 deletions
diff --git a/kttsd/plugins/hadifix/hadifixconf.cpp b/kttsd/plugins/hadifix/hadifixconf.cpp
new file mode 100644
index 0000000..a2c5547
--- /dev/null
+++ b/kttsd/plugins/hadifix/hadifixconf.cpp
@@ -0,0 +1,406 @@
+/***************************************************************************
+ begin : Mon Okt 14 2002
+ copyright : (C) 2002 by Gunnar Schmi Dt
+ email : gunnar@schmi-dt.de
+ current mainainer: : Gary Cramblitt <garycramblitt@comcast.net>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+// Qt includes.
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qgroupbox.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qfile.h>
+
+// KDE includes.
+#include <ktempfile.h>
+#include <kaboutdata.h>
+#include <kaboutapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kcombobox.h>
+#include <kstandarddirs.h>
+#include <kurlrequester.h>
+#include <kdialogbase.h>
+#include <klineedit.h>
+#include <knuminput.h>
+#include <kprogress.h>
+
+// KTTS includes.
+#include <pluginconf.h>
+#include <testplayer.h>
+#include <talkercode.h>
+
+// Hadifix includes.
+#include "hadifixproc.h"
+#include "voicefileui.h"
+#include "hadifixconfigui.h"
+#include "hadifixconf.h"
+#include "hadifixconf.moc"
+
+class HadifixConfPrivate {
+ friend class HadifixConf;
+ private:
+ HadifixConfPrivate() {
+ hadifixProc = 0;
+ progressDlg = 0;
+ findInitialConfig();
+ };
+
+ ~HadifixConfPrivate() {
+ if (hadifixProc) hadifixProc->stopText();
+ delete hadifixProc;
+ if (!waveFile.isNull()) QFile::remove(waveFile);
+ delete progressDlg;
+ };
+
+ #include "initialconfig.h"
+
+ void setConfiguration (QString hadifixExec, QString mbrolaExec,
+ QString voice, bool male,
+ int volume, int time, int pitch,
+ QString codecName)
+ {
+ configWidget->hadifixURL->setURL (hadifixExec);
+ configWidget->mbrolaURL->setURL (mbrolaExec);
+ configWidget->setVoice (voice, male);
+
+ configWidget->volumeBox->setValue (volume);
+ configWidget->timeBox->setValue (time);
+ configWidget->frequencyBox->setValue (pitch);
+ int codec = PlugInProc::codecNameToListIndex(codecName, codecList);
+ configWidget->characterCodingBox->setCurrentItem(codec);
+ }
+
+ void initializeVoices () {
+ QStringList::iterator it;
+ for (it = defaultVoices.begin(); it != defaultVoices.end(); ++it) {
+ HadifixProc::VoiceGender gender;
+ QString name = QFileInfo(*it).fileName();
+ gender = HadifixProc::determineGender(defaultMbrolaExec, *it);
+ if (gender == HadifixProc::MaleGender)
+ configWidget->addVoice(*it, true, i18n("Male voice \"%1\"").arg(name));
+ else if (gender == HadifixProc::FemaleGender)
+ configWidget->addVoice(*it, false, i18n("Female voice \"%1\"").arg(name));
+ else {
+ if (name == "de1")
+ configWidget->addVoice(*it, false, i18n("Female voice \"%1\"").arg(name));
+ else {
+ configWidget->addVoice(*it, true, i18n("Unknown voice \"%1\"").arg(name));
+ configWidget->addVoice(*it, false, i18n("Unknown voice \"%1\"").arg(name));
+ }
+ }
+ }
+ };
+
+ void initializeCharacterCodes() {
+ // Build codec list and fill combobox.
+ codecList = PlugInProc::buildCodecList();
+ configWidget->characterCodingBox->clear();
+ configWidget->characterCodingBox->insertStringList(codecList);
+ }
+
+ void setDefaultEncodingFromVoice() {
+ QString voiceFile = configWidget->getVoiceFilename();
+ QString voiceCode = QFileInfo(voiceFile).baseName(false);
+ voiceCode = voiceCode.left(2);
+ QString codecName = "Local";
+ if (voiceCode == "de") codecName = "ISO 8859-1";
+ if (voiceCode == "hu") codecName = "ISO 8859-2";
+ configWidget->characterCodingBox->setCurrentItem(PlugInProc::codecNameToListIndex(
+ codecName, codecList));
+}
+
+ void setDefaults () {
+ QStringList::iterator it = defaultVoices.begin();
+ // Find a voice that matches language code, if any.
+ if (!languageCode.isEmpty())
+ {
+ QString justLang = languageCode.left(2);
+ for (;it != defaultVoices.end();++it)
+ {
+ QString voiceCode = QFileInfo(*it).baseName(false).left(2);
+ if (voiceCode == justLang) break;
+ }
+ if (it == defaultVoices.end()) it = defaultVoices.begin();
+ }
+ HadifixProc::VoiceGender gender;
+ gender = HadifixProc::determineGender(defaultMbrolaExec, *it);
+
+ setConfiguration (defaultHadifixExec, defaultMbrolaExec,
+ *it, gender == HadifixProc::MaleGender,
+ 100, 100, 100, "Local");
+ };
+
+ void load (KConfig *config, const QString &configGroup) {
+ config->setGroup(configGroup);
+
+ QString voice = config->readEntry("voice", configWidget->getVoiceFilename());
+
+ HadifixProc::VoiceGender gender;
+ gender = HadifixProc::determineGender(defaultMbrolaExec, voice);
+ bool isMale = (gender == HadifixProc::MaleGender);
+
+ QString defaultCodecName = "Local";
+ // TODO: Need a better way to determine proper codec for each voice.
+ // This will do for now.
+ QString voiceCode = QFileInfo(voice).baseName(false);
+ if (voiceCode.left(2) == "de") defaultCodecName = "ISO 8859-1";
+ if (voiceCode.left(2) == "hu") defaultCodecName = "ISO 8859-2";
+
+ setConfiguration (
+ config->readEntry ("hadifixExec",defaultHadifixExec),
+ config->readEntry ("mbrolaExec", defaultMbrolaExec),
+ config->readEntry ("voice", voice),
+ config->readBoolEntry("gender", isMale),
+ config->readNumEntry ("volume", 100),
+ config->readNumEntry ("time", 100),
+ config->readNumEntry ("pitch", 100),
+ config->readEntry ("codec", defaultCodecName)
+ );
+ };
+
+ void save (KConfig *config, const QString &configGroup) {
+ config->setGroup(configGroup);
+ config->writeEntry ("hadifixExec", PlugInConf::realFilePath(configWidget->hadifixURL->url()));
+ config->writeEntry ("mbrolaExec", PlugInConf::realFilePath(configWidget->mbrolaURL->url()));
+ config->writeEntry ("voice", configWidget->getVoiceFilename());
+ config->writeEntry ("gender", configWidget->isMaleVoice());
+ config->writeEntry ("volume", configWidget->volumeBox->value());
+ config->writeEntry ("time", configWidget->timeBox->value());
+ config->writeEntry ("pitch", configWidget->frequencyBox->value());
+ config->writeEntry ("codec", PlugInProc::codecIndexToCodecName(
+ configWidget->characterCodingBox->currentItem(), codecList));
+ }
+
+ HadifixConfigUI *configWidget;
+
+ QString languageCode;
+ QString defaultHadifixExec;
+ QString defaultMbrolaExec;
+ QStringList defaultVoices;
+ QStringList codecList;
+
+ // Wave file playing on play object.
+ QString waveFile;
+ // Synthesizer.
+ HadifixProc* hadifixProc;
+ // Progress Dialog.
+ KProgressDialog* progressDlg;
+};
+
+/** Constructor */
+HadifixConf::HadifixConf( QWidget* parent, const char* name, const QStringList &) :
+ PlugInConf( parent, name ){
+ // kdDebug() << "HadifixConf::HadifixConf: Running" << endl;
+ QVBoxLayout *layout = new QVBoxLayout (this, KDialog::marginHint(), KDialog::spacingHint(), "CommandConfigWidgetLayout");
+ layout->setAlignment (Qt::AlignTop);
+
+ d = new HadifixConfPrivate();
+ d->configWidget = new HadifixConfigUI (this, "configWidget");
+
+ QString file = locate("data", "LICENSES/LGPL_V2");
+ i18n("This plugin is distributed under the terms of the GPL v2 or later.");
+
+ connect(d->configWidget->voiceButton, SIGNAL(clicked()), this, SLOT(voiceButton_clicked()));
+ connect(d->configWidget->testButton, SIGNAL(clicked()), this, SLOT(testButton_clicked()));
+ connect(d->configWidget, SIGNAL(changed(bool)), this, SLOT(configChanged (bool)));
+ connect(d->configWidget->characterCodingBox, SIGNAL(textChanged(const QString&)),
+ this, SLOT(configChanged()));
+ connect(d->configWidget->voiceCombo, SIGNAL(activated(int)), this, SLOT(voiceCombo_activated(int)));
+ d->initializeCharacterCodes();
+ d->initializeVoices();
+ d->setDefaults();
+ layout->addWidget (d->configWidget);
+}
+
+/** Destructor */
+HadifixConf::~HadifixConf(){
+ // kdDebug() << "HadifixConf::~HadifixConf: Running" << endl;
+ delete d;
+}
+
+void HadifixConf::load(KConfig *config, const QString &configGroup) {
+ // kdDebug() << "HadifixConf::load: Running" << endl;
+ d->setDefaults();
+ d->load (config, configGroup);
+}
+
+void HadifixConf::save(KConfig *config, const QString &configGroup) {
+ // kdDebug() << "HadifixConf::save: Running" << endl;
+ d->save (config, configGroup);
+}
+
+void HadifixConf::defaults() {
+ // kdDebug() << "HadifixConf::defaults: Running" << endl;
+ d->setDefaults();
+}
+
+void HadifixConf::setDesiredLanguage(const QString &lang)
+{
+ d->languageCode = lang;
+}
+
+QString HadifixConf::getTalkerCode()
+{
+ if (!d->configWidget->hadifixURL->url().isEmpty() && !d->configWidget->mbrolaURL->url().isEmpty())
+ {
+ QString voiceFile = d->configWidget->getVoiceFilename();
+ if (QFileInfo(voiceFile).exists())
+ {
+ // mbrola voice file names usually start with two-letter language code,
+ // but this is by no means guaranteed.
+ QString voiceCode = QFileInfo(voiceFile).baseName(false);
+ QString voiceLangCode = voiceCode.left(2);
+ if (d->languageCode.left(2) != voiceLangCode)
+ {
+ // Verify that first two letters of voice filename are a valid language code.
+ // If they are, switch to that language.
+ if (!TalkerCode::languageCodeToLanguage(voiceLangCode).isEmpty())
+ d->languageCode = voiceLangCode;
+ }
+ QString gender = "male";
+ if (!d->configWidget->isMaleVoice()) gender = "female";
+ QString volume = "medium";
+ if (d->configWidget->volumeBox->value() < 75) volume = "soft";
+ if (d->configWidget->volumeBox->value() > 125) volume = "loud";
+ QString rate = "medium";
+ if (d->configWidget->timeBox->value() < 75) rate = "slow";
+ if (d->configWidget->timeBox->value() > 125) rate = "fast";
+ return QString(
+ "<voice lang=\"%1\" name=\"%2\" gender=\"%3\" />"
+ "<prosody volume=\"%4\" rate=\"%5\" />"
+ "<kttsd synthesizer=\"%6\" />")
+ .arg(d->languageCode)
+ .arg(voiceCode)
+ .arg(gender)
+ .arg(volume)
+ .arg(rate)
+ .arg("Hadifix");
+ }
+ }
+ return QString::null;
+}
+
+void HadifixConf::voiceButton_clicked () {
+ KDialogBase *dialog = new KDialogBase (this, 0, true,
+ i18n("Voice File - Hadifix Plugin"),
+ KDialogBase::Ok|KDialogBase::Cancel,
+ KDialogBase::Ok, true);
+ VoiceFileWidget *widget = new VoiceFileWidget(dialog);
+ dialog->setMainWidget (widget);
+
+ widget->femaleOption->setChecked(!d->configWidget->isMaleVoice());
+ widget->maleOption->setChecked(d->configWidget->isMaleVoice());
+ widget->voiceFileURL->setURL(d->configWidget->getVoiceFilename());
+ widget->mbrola = d->defaultMbrolaExec;
+
+ if (dialog->exec() == QDialog::Accepted) {
+ d->configWidget->setVoice (widget->voiceFileURL->url(),
+ widget->maleOption->isChecked());
+ d->setDefaultEncodingFromVoice();
+ emit changed(true);
+ }
+
+ delete dialog;
+}
+
+void HadifixConf::voiceCombo_activated(int /*index*/)
+{
+ d->setDefaultEncodingFromVoice();
+}
+
+void HadifixConf::testButton_clicked () {
+ // If currently synthesizing, stop it.
+ if (d->hadifixProc)
+ d->hadifixProc->stopText();
+ else
+ {
+ d->hadifixProc = new HadifixProc();
+ connect (d->hadifixProc, SIGNAL(stopped()), this, SLOT(slotSynthStopped()));
+ }
+ // Create a temp file name for the wave file.
+ KTempFile tempFile (locateLocal("tmp", "hadifixplugin-"), ".wav");
+ QString tmpWaveFile = tempFile.file()->name();
+ tempFile.close();
+
+ // Tell user to wait.
+ d->progressDlg = new KProgressDialog(d->configWidget, "ktts_hadifix_testdlg",
+ i18n("Testing"),
+ i18n("Testing."),
+ true);
+ d->progressDlg->progressBar()->hide();
+ d->progressDlg->setAllowCancel(true);
+
+ // Speak a German sentence as hadifix is a German tts
+ // TODO: Actually, Hadifix does support English (and other languages?) as well,
+ // If you install the right voice files. The hard part is finding and installing
+ // a working txt2pho for the desired language. There seem to be some primitive french,
+ // italian, and a few others, written in perl, but they have many issues.
+ // Go to the mbrola website and click on "TTS" to learn more.
+
+ // QString testMsg = "K D E ist eine moderne grafische Arbeitsumgebung für UNIX-Computer.";
+ QString testMsg = testMessage(d->languageCode);
+ connect (d->hadifixProc, SIGNAL(synthFinished()), this, SLOT(slotSynthFinished()));
+ d->hadifixProc->synth (testMsg,
+ realFilePath(d->configWidget->hadifixURL->url()),
+ d->configWidget->isMaleVoice(),
+ realFilePath(d->configWidget->mbrolaURL->url()),
+ d->configWidget->getVoiceFilename(),
+ d->configWidget->volumeBox->value(),
+ d->configWidget->timeBox->value(),
+ d->configWidget->frequencyBox->value(),
+ PlugInProc::codecIndexToCodec(d->configWidget->characterCodingBox->currentItem(), d->codecList),
+ tmpWaveFile);
+
+ // Display progress dialog modally. Processing continues when plugin signals synthFinished,
+ // or if user clicks Cancel button.
+ d->progressDlg->exec();
+ disconnect (d->hadifixProc, SIGNAL(synthFinished()), this, SLOT(slotSynthFinished()));
+ if (d->progressDlg->wasCancelled()) d->hadifixProc->stopText();
+ delete d->progressDlg;
+ d->progressDlg = 0;
+}
+
+void HadifixConf::slotSynthFinished()
+{
+ // If user canceled, progress dialog is gone, so exit.
+ if (!d->progressDlg)
+ {
+ d->hadifixProc->ackFinished();
+ return;
+ }
+ // Hide the Cancel button so user can't cancel in the middle of playback.
+ d->progressDlg->showCancelButton(false);
+ // Get new wavefile name.
+ d->waveFile = d->hadifixProc->getFilename();
+ // Tell synth we're done.
+ d->hadifixProc->ackFinished();
+ // Play the wave file (possibly adjusting its Speed).
+ // Player object deletes the wave file when done.
+ if (m_player) m_player->play(d->waveFile);
+ QFile::remove(d->waveFile);
+ d->waveFile = QString::null;
+ if (d->progressDlg) d->progressDlg->close();
+}
+
+void HadifixConf::slotSynthStopped()
+{
+ // Clean up after canceling test.
+ QString filename = d->hadifixProc->getFilename();
+ // kdDebug() << "HadifixConf::slotSynthStopped: filename = " << filename << endl;
+ if (!filename.isNull()) QFile::remove(filename);
+}