You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeaccessibility/kttsd/plugins/festivalint/festivalintconf.cpp

731 lines
30 KiB

/***************************************************** vim:set ts=4 sw=4 sts=4:
Configuration widget and functions for Festival (Interactive) plug in
-------------------
Copyright:
(C) 2004 by Gary Cramblitt <garycramblitt@comcast.net>
-------------------
Original author: 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
******************************************************************************/
// C++ includes.
#include <math.h>
// TQt includes.
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqstring.h>
#include <tqstringlist.h>
#include <tqcheckbox.h>
#include <tqdir.h>
#include <tqslider.h>
#include <tqdom.h>
#include <tqtextcodec.h>
// KDE includes.
#include <kdialog.h>
#include <kdebug.h>
#include <klocale.h>
#include <kcombobox.h>
#include <kglobal.h>
#include <ktempfile.h>
#include <kstandarddirs.h>
#include <knuminput.h>
#include <kprocio.h>
#include <kprogress.h>
#include <kiconloader.h>
// KTTS includes.
#include "testplayer.h"
// FestivalInt includes.
#include "festivalintproc.h"
#include "festivalintconf.h"
#include "festivalintconf.moc"
/** Constructor */
FestivalIntConf::FestivalIntConf( TQWidget* parent, const char* name, const TQStringList& /*args*/) :
PlugInConf(parent, name)
{
// kdDebug() << "FestivalIntConf::FestivalIntConf: Running" << endl;
m_festProc = 0;
m_progressDlg = 0;
m_supportsSSML = FestivalIntProc::ssUnknown;
TQVBoxLayout *layout = new TQVBoxLayout(this, KDialog::marginHint(),
KDialog::spacingHint(), "FestivalIntConfigWidgetLayout");
layout->setAlignment (TQt::AlignTop);
m_widget = new FestivalIntConfWidget(this, "FestivalIntConfigWidget");
layout->addWidget(m_widget);
m_widget->festivalPath->setMode(KFile::File | KFile::ExistingOnly);
m_widget->festivalPath->setFilter("*");
// Build codec list and fill combobox.
m_codecList = PlugInProc::buildCodecList();
m_widget->characterCodingBox->clear();
m_widget->characterCodingBox->insertStringList(m_codecList);
// defaults();
connect(m_widget->festivalPath, TQT_SIGNAL(textChanged(const TQString&)),
this, TQT_SLOT(slotFestivalPath_textChanged()));
connect(m_widget->selectVoiceCombo, TQT_SIGNAL(activated(const TQString&)),
this, TQT_SLOT(slotSelectVoiceCombo_activated()));
connect(m_widget->selectVoiceCombo, TQT_SIGNAL(activated(const TQString&)),
this, TQT_SLOT(configChanged()));
connect(m_widget->testButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotTest_clicked()));
connect(m_widget->rescan, TQT_SIGNAL(clicked()), this, TQT_SLOT(scanVoices()));
connect(m_widget->volumeBox, TQT_SIGNAL(valueChanged(int)),
this, TQT_SLOT(volumeBox_valueChanged(int)));
connect(m_widget->timeBox, TQT_SIGNAL(valueChanged(int)),
this, TQT_SLOT(timeBox_valueChanged(int)));
connect(m_widget->frequencyBox, TQT_SIGNAL(valueChanged(int)),
this, TQT_SLOT(frequencyBox_valueChanged(int)));
connect(m_widget->volumeSlider, TQT_SIGNAL(valueChanged(int)),
this, TQT_SLOT(volumeSlider_valueChanged(int)));
connect(m_widget->timeSlider, TQT_SIGNAL(valueChanged(int)),
this, TQT_SLOT(timeSlider_valueChanged(int)));
connect(m_widget->frequencySlider, TQT_SIGNAL(valueChanged(int)),
this, TQT_SLOT(frequencySlider_valueChanged(int)));
connect(m_widget->volumeBox, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(configChanged()));
connect(m_widget->volumeSlider, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(configChanged()));
connect(m_widget->timeBox, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(configChanged()));
connect(m_widget->timeSlider, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(configChanged()));
connect(m_widget->frequencyBox, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(configChanged()));
connect(m_widget->frequencySlider, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(configChanged()));
connect(m_widget->preloadCheckBox, TQT_SIGNAL(clicked()), this, TQT_SLOT(configChanged()));
connect(m_widget->characterCodingBox, TQT_SIGNAL(textChanged(const TQString&)),
this, TQT_SLOT(configChanged()));
connect(m_widget->characterCodingBox, TQT_SIGNAL(activated(const TQString&)),
this, TQT_SLOT(configChanged()));
}
/** Destructor */
FestivalIntConf::~FestivalIntConf(){
// kdDebug() << "FestivalIntConf::~FestivalIntConf: Running" << endl;
if (!m_waveFile.isNull()) TQFile::remove(m_waveFile);
delete m_festProc;
delete m_progressDlg;
}
/**
* Given a voice code, returns index into m_voiceList array (and voiceCombo box).
* -1 if not found.
*/
int FestivalIntConf::voiceCodeToListIndex(const TQString& voiceCode) const
{
const int voiceListCount = m_voiceList.count();
for(int index = 0; index < voiceListCount; ++index){
// kdDebug() << "Testing: " << voiceCode << " == " << m_voiceList[index].code << endl;
if(voiceCode == m_voiceList[index].code)
return index;
}
return -1;
}
void FestivalIntConf::load(TDEConfig *config, const TQString &configGroup){
//kdDebug() << "FestivalIntConf::load: Running" << endl;
config->setGroup("FestivalInt");
TQString exePath = config->readEntry("FestivalExecutablePath", "festival");
TQString exeLocation = getLocation(exePath);
if (!exeLocation.isEmpty()) exePath = exeLocation;
exePath = realFilePath(exePath);
config->setGroup(configGroup);
m_widget->festivalPath->setURL(config->readEntry("FestivalExecutablePath", exePath));
m_widget->preloadCheckBox->setChecked(false);
scanVoices();
TQString voiceSelected(config->readEntry("Voice"));
int index = voiceCodeToListIndex(voiceSelected);
if (index >= 0)
{
m_widget->selectVoiceCombo->setCurrentItem(index);
m_widget->preloadCheckBox->setChecked(m_voiceList[index].preload);
}
m_widget->volumeBox->setValue(config->readNumEntry("volume", 100));
m_widget->timeBox->setValue(config->readNumEntry("time", 100));
m_widget->frequencyBox->setValue(config->readNumEntry("pitch", 100));
m_widget->preloadCheckBox->setChecked(config->readBoolEntry(
"Preload", m_widget->preloadCheckBox->isChecked()));
m_languageCode = config->readEntry("LanguageCode", m_languageCode);
m_supportsSSML = static_cast<FestivalIntProc::SupportsSSML>(
config->readNumEntry("SupportsSSML", FestivalIntProc::ssUnknown));
TQString codecName = PlugInProc::codecIndexToCodecName(
m_widget->characterCodingBox->currentItem(), m_codecList);
codecName = config->readEntry("Codec", codecName);
int codecNdx = PlugInProc::codecNameToListIndex(codecName, m_codecList);
m_widget->characterCodingBox->setCurrentItem(codecNdx);
}
void FestivalIntConf::save(TDEConfig *config, const TQString &configGroup){
// kdDebug() << "FestivalIntConf::save: Running" << endl;
config->setGroup("FestivalInt");
config->writeEntry("FestivalExecutablePath", realFilePath(m_widget->festivalPath->url()));
config->setGroup(configGroup);
config->writeEntry("FestivalExecutablePath", realFilePath(m_widget->festivalPath->url()));
config->writeEntry("Voice", m_voiceList[m_widget->selectVoiceCombo->currentItem()].code);
config->writeEntry("volume", m_widget->volumeBox->value());
config->writeEntry("time", m_widget->timeBox->value());
config->writeEntry("pitch", m_widget->frequencyBox->value());
config->writeEntry("Preload", m_widget->preloadCheckBox->isChecked());
config->writeEntry("LanguageCode", m_voiceList[m_widget->selectVoiceCombo->currentItem()].languageCode);
config->writeEntry("SupportsSSML", m_supportsSSML);
int codec = m_widget->characterCodingBox->currentItem();
config->writeEntry("Codec", PlugInProc::codecIndexToCodecName(codec, m_codecList));
}
void FestivalIntConf::defaults(){
// kdDebug() << "FestivalIntConf::defaults: Running" << endl;
m_widget->festivalPath->setURL("festival");
m_widget->timeBox->setValue(100);
timeBox_valueChanged(100);
m_widget->volumeBox->setValue(100);
volumeBox_valueChanged(100);
m_widget->frequencyBox->setValue(100);
frequencyBox_valueChanged(100);
m_widget->preloadCheckBox->setChecked(false);
m_widget->characterCodingBox->setCurrentItem(
PlugInProc::codecNameToListIndex("ISO 8859-1", m_codecList));
scanVoices();
}
void FestivalIntConf::setDesiredLanguage(const TQString &lang)
{
// kdDebug() << "FestivalIntConf::setDesiredLanguage: Running" << endl;
m_languageCode = splitLanguageCode(lang, m_countryCode);
}
TQString FestivalIntConf::getTalkerCode()
{
if (!m_widget->selectVoiceCombo->isEnabled()) return TQString();
TQString exePath = realFilePath(m_widget->festivalPath->url());
if (exePath.isEmpty()) return TQString();
if (getLocation(exePath).isEmpty()) return TQString();
if (m_voiceList.count() == 0) return TQString();
TQString normalTalkerCode;
voiceStruct voiceTemp = m_voiceList[m_widget->selectVoiceCombo->currentItem()];
// Determine volume attribute. soft < 75% <= medium <= 125% < loud.
TQString volume = "medium";
if (m_widget->volumeBox->value() < 75) volume = "soft";
if (m_widget->volumeBox->value() > 125) volume = "loud";
// Determine rate attribute. slow < 75% <= medium <= 125% < fast.
TQString rate = "medium";
if (m_widget->timeBox->value() < 75) rate = "slow";
if (m_widget->timeBox->value() > 125) rate = "fast";
normalTalkerCode = TQString(
"<voice lang=\"%1\" name=\"%2\" gender=\"%3\" />"
"<prosody volume=\"%4\" rate=\"%5\" />"
"<kttsd synthesizer=\"%6\" />")
.arg(voiceTemp.languageCode)
.arg(voiceTemp.code)
.arg(voiceTemp.gender)
.arg(volume)
.arg(rate)
.arg("Festival Interactive");
return normalTalkerCode;
}
/**
* Chooses a default voice given scanned list of voices in m_voiceList and current
* language and country code, and updates controls.
* @param currentVoiceIndex This voice is preferred if it matches.
*/
void FestivalIntConf::setDefaultVoice(int currentVoiceIndex)
{
// kdDebug() << "FestivalIntCont::setDefaultVoice: Running" << endl;
// If language code is known, auto pick first voice that matches the language code.
if (!m_languageCode.isEmpty())
{
bool found = false;
// First search for a match on both language code and country code.
TQString languageCode = m_languageCode;
if (!m_countryCode.isNull()) languageCode += "_" + m_countryCode;
// kdDebug() << "FestivalIntConf::setDefaultVoice:: looking for default voice to match language code " << languageCode << endl;
uint index = 0;
// Prefer existing voice if it matches.
if (currentVoiceIndex >= 0)
{
TQString vlCode = m_voiceList[currentVoiceIndex].languageCode.left(languageCode.length());
if (languageCode == vlCode)
{
found = true;
index = currentVoiceIndex;
}
}
if (!found)
{
for(index = 0 ; index < m_voiceList.count(); ++index)
{
TQString vlCode = m_voiceList[index].languageCode.left(languageCode.length());
// kdDebug() << "FestivalIntConf::setDefaultVoice: testing " << vlCode << endl;
if(languageCode == vlCode)
{
found = true;
break;
}
}
}
// If not found, search for a match on just the language code.
if (!found)
{
languageCode = m_languageCode;
// Prefer existing voice if it matches.
if (currentVoiceIndex >= 0)
{
TQString vlCode = m_voiceList[currentVoiceIndex].languageCode.left(languageCode.length());
if (languageCode == vlCode)
{
found = true;
index = currentVoiceIndex;
}
}
if (!found)
{
for(index = 0 ; index < m_voiceList.count(); ++index)
{
TQString vlCode = m_voiceList[index].languageCode.left(languageCode.length());
// kdDebug() << "FestivalIntConf::setDefaultVoice: testing " << vlCode << endl;
if(languageCode == vlCode)
{
found = true;
break;
}
}
}
}
// If not found, pick first voice that is not "Unknown".
if (!found)
{
for(index = 0 ; index < m_voiceList.count(); ++index)
{
if (m_voiceList[index].name != i18n("Unknown"))
{
found = true;
break;
}
}
}
if (found)
{
// kdDebug() << "FestivalIntConf::setDefaultVoice: auto picking voice code " << m_voiceList[index].code << endl;
m_widget->selectVoiceCombo->setCurrentItem(index);
m_widget->preloadCheckBox->setChecked(m_voiceList[index].preload);
TQString codecName = m_voiceList[index].codecName;
int codecNdx = PlugInProc::codecNameToListIndex(codecName, m_codecList);
m_widget->characterCodingBox->setCurrentItem(codecNdx);
if (m_voiceList[index].volumeAdjustable)
{
m_widget->volumeBox->setEnabled(true);
m_widget->volumeSlider->setEnabled(true);
}
else
{
m_widget->volumeBox->setValue(100);
volumeBox_valueChanged(100);
m_widget->volumeBox->setEnabled(false);
m_widget->volumeSlider->setEnabled(false);
}
if (m_voiceList[index].rateAdjustable)
{
m_widget->timeBox->setEnabled(true);
m_widget->timeSlider->setEnabled(true);
}
else
{
m_widget->timeBox->setValue(100);
timeBox_valueChanged(100);
m_widget->timeBox->setEnabled(false);
m_widget->timeSlider->setEnabled(false);
}
if (m_voiceList[index].pitchAdjustable)
{
m_widget->frequencyBox->setEnabled(true);
m_widget->frequencySlider->setEnabled(true);
}
else
{
m_widget->frequencyBox->setValue(100);
frequencyBox_valueChanged(100);
m_widget->frequencyBox->setEnabled(false);
m_widget->frequencySlider->setEnabled(false);
}
if ((int)index != currentVoiceIndex) configChanged();
}
}
}
/**
* Given an XML node and child element name, returns the string value from the child element.
* If no such child element, returns def.
*/
TQString FestivalIntConf::readXmlString(TQDomNode &node, const TQString &elementName, const TQString &def)
{
TQDomNode childNode = node.namedItem(elementName);
if (!childNode.isNull())
return childNode.toElement().text();
else
return def;
}
/**
* Given an XML node and child element name, returns the boolean value from the child element.
* If no such child element, returns def.
*/
bool FestivalIntConf::readXmlBool(TQDomNode &node, const TQString &elementName, bool def)
{
TQDomNode childNode = node.namedItem(elementName);
if (!childNode.isNull())
return (childNode.toElement().text() == "true");
else
return def;
}
void FestivalIntConf::scanVoices()
{
// kdDebug() << "FestivalIntConf::scanVoices: Running" << endl;
// Get existing voice code (if any).
TQString currentVoiceCode;
int index = m_widget->selectVoiceCombo->currentItem();
if (index < (int)m_voiceList.count()) currentVoiceCode = m_voiceList[index].code;
m_voiceList.clear();
m_widget->selectVoiceCombo->clear();
m_widget->selectVoiceCombo->insertItem(i18n("Scanning... Please wait."));
// Save current state of selectVoiceCombo box and disable.
bool selectVoiceComboEnabled = m_widget->selectVoiceCombo->isEnabled();
m_widget->selectVoiceCombo->setEnabled(false);
// Clear existing list of supported voice codes.
// m_supportedVoiceCodes.clear();
m_widget->selectVoiceCombo->clear();
TQString exePath = realFilePath(m_widget->festivalPath->url());
if (!getLocation(exePath).isEmpty())
{
// Set up a progress dialog.
m_progressDlg = new KProgressDialog(m_widget, "kttsmgr_queryvoices",
i18n("Query Voices"),
i18n("Querying Festival for available voices. This could take up to 15 seconds."),
true);
m_progressDlg->progressBar()->hide();
m_progressDlg->setAllowCancel(true);
// Create Festival process and request a list of voice codes.
if (m_festProc)
m_festProc->stopText();
else
{
m_festProc = new FestivalIntProc();
connect (m_festProc, TQT_SIGNAL(stopped()), this, TQT_SLOT(slotSynthStopped()));
}
connect (m_festProc, TQT_SIGNAL(queryVoicesFinished(const TQStringList&)),
this, TQT_SLOT(slotQueryVoicesFinished(const TQStringList&)));
m_festProc->queryVoices(exePath);
// Display progress dialog modally.
m_progressDlg->exec();
// kdDebug() << "FestivalIntConf::scanVoices: back from progressDlg->exec()" << endl;
// Processing continues until either user clicks Cancel button, or until
// Festival responds with the list. When Festival responds with list,
// the progress dialog is closed.
disconnect (m_festProc, TQT_SIGNAL(queryVoicesFinished(const TQStringList&)),
this, TQT_SLOT(slotQueryVoicesFinished(const TQStringList&)));
if (!m_progressDlg->wasCancelled()) m_festProc->stopText();
delete m_progressDlg;
m_progressDlg = 0;
m_supportsSSML = m_festProc->supportsSSML();
}
if (!m_supportedVoiceCodes.isEmpty())
{
// User's desktop language setting.
TQString desktopLanguageCode = TDEGlobal::locale()->language();
TQString twoAlpha;
TQString countryCode;
TQString charSet;
TDEGlobal::locale()->splitLocale(desktopLanguageCode, twoAlpha, countryCode, charSet);
desktopLanguageCode = twoAlpha.lower();
// Festival known voices list.
TQString voicesFilename = TDEGlobal::dirs()->resourceDirs("data").last() + "/kttsd/festivalint/voices";
TQDomDocument voicesDoc("Festival Voices");
TQFile voicesFile(voicesFilename);
if (voicesFile.open(IO_ReadOnly)) voicesDoc.setContent(&voicesFile);
voicesFile.close();
TQDomNodeList voices = voicesDoc.elementsByTagName("voice");
uint voicesCount = voices.count();
if (voicesCount == 0)
kdDebug() << "FestivalIntConf::scanVoices: Unable to open " << voicesFilename << ". Is TDEDIR defined?" << endl;
// Iterate thru list of voice codes returned by Festival,
// find matching entry in voices.xml file, and add to list of supported voices.
TQPixmap maleIcon = TDEGlobal::iconLoader()->loadIcon("male", KIcon::Small);
TQPixmap femaleIcon = TDEGlobal::iconLoader()->loadIcon("female", KIcon::Small);
TQStringList::ConstIterator itEnd = m_supportedVoiceCodes.constEnd();
for(TQStringList::ConstIterator it = m_supportedVoiceCodes.begin(); it != itEnd; ++it )
{
TQString code = *it;
bool found = false;
for (uint index=0; index < voicesCount; ++index)
{
TQDomNode voiceNode = voices.item(index);
TQString voiceCode = readXmlString(voiceNode, "code", TQString());
// kdDebug() << "FestivalIntConf::scanVoices: Comparing code " << code << " to " << voiceCode << endl;
if (voiceCode == code)
{
found = true;
voiceStruct voiceTemp;
voiceTemp.code = code;
voiceTemp.name = i18n("FestivalVoiceName",
readXmlString(voiceNode, "name", "Unknown").utf8());
voiceTemp.languageCode = readXmlString(voiceNode, "language", m_languageCode);
voiceTemp.codecName = readXmlString(voiceNode, "codec", "ISO 8859-1");
voiceTemp.gender = readXmlString(voiceNode, "gender", "neutral");
voiceTemp.preload = readXmlBool(voiceNode, "preload", false);
voiceTemp.volumeAdjustable = readXmlBool(voiceNode, "volume-adjustable", true);
voiceTemp.rateAdjustable = readXmlBool(voiceNode, "rate-adjustable", true);
voiceTemp.pitchAdjustable = readXmlBool(voiceNode, "pitch-adjustable", true);
m_voiceList.append(voiceTemp);
TQString voiceDisplayName = voiceTemp.name + " (" + voiceTemp.code + ")";
if (voiceTemp.gender == "male")
m_widget->selectVoiceCombo->insertItem(maleIcon, voiceDisplayName);
else if (voiceTemp.gender == "female")
m_widget->selectVoiceCombo->insertItem(femaleIcon, voiceDisplayName);
else
m_widget->selectVoiceCombo->insertItem(voiceDisplayName);
break;
}
}
if (!found)
{
voiceStruct voiceTemp;
voiceTemp.code = code;
voiceTemp.name = i18n("Unknown");
voiceTemp.languageCode = m_languageCode;
voiceTemp.codecName = "ISO 8858-1";
voiceTemp.gender = "neutral";
voiceTemp.preload = false;
voiceTemp.volumeAdjustable = true;
voiceTemp.rateAdjustable = true;
voiceTemp.pitchAdjustable = true;
m_voiceList.append(voiceTemp);
m_widget->selectVoiceCombo->insertItem(voiceTemp.name + " (" + voiceTemp.code + ")");
}
}
m_widget->selectVoiceCombo->setEnabled(true);
} else kdDebug() << "FestivalIntConf::scanVoices: No voices found" << endl;
setDefaultVoice(voiceCodeToListIndex(currentVoiceCode));
// Emit configChanged if the enabled state of the selectVoiceCombo has changed.
// This occurs when user changes Festival EXE path, then clicks Rescan.
if (selectVoiceComboEnabled != m_widget->selectVoiceCombo->isEnabled()) configChanged();
}
void FestivalIntConf::slotQueryVoicesFinished(const TQStringList &voiceCodes)
{
// kdDebug() << "FestivalIntConf::slotQueryVoicesFinished: voiceCodes.count() = " << voiceCodes.count() << endl;
m_supportedVoiceCodes = voiceCodes;
if (m_progressDlg) m_progressDlg->close();
}
void FestivalIntConf::slotTest_clicked()
{
// kdDebug() << "FestivalIntConf::slotTest_clicked: Running " << endl;
// If currently synthesizing, stop it.
if (m_festProc)
m_festProc->stopText();
else
{
m_festProc = new FestivalIntProc();
connect (m_festProc, TQT_SIGNAL(stopped()), this, TQT_SLOT(slotSynthStopped()));
}
// Create a temp file name for the wave file.
KTempFile tempFile (locateLocal("tmp", "festivalintplugin-"), ".wav");
TQString tmpWaveFile = tempFile.file()->name();
tempFile.close();
// Get the code for the selected voice.
TQString voiceCode = m_voiceList[m_widget->selectVoiceCombo->currentItem()].code;
// Get language code for the selected voice.
TQString languageCode = m_voiceList[m_widget->selectVoiceCombo->currentItem()].languageCode;
// Get test message in the language of the voice.
TQString testMsg = testMessage(languageCode);
// Get codec.
TQTextCodec* codec = PlugInProc::codecIndexToCodec(
m_widget->characterCodingBox->currentItem(), m_codecList);
// Tell user to wait.
m_progressDlg = new KProgressDialog(m_widget, "ktts_festivalint_testdlg",
i18n("Testing"),
i18n("Testing. MultiSyn voices require several seconds to load. Please be patient."),
true);
m_progressDlg->progressBar()->hide();
m_progressDlg->setAllowCancel(true);
// kdDebug() << "FestivalIntConf::slotTest_clicked: calling synth with voiceCode: " << voiceCode << " time percent: " << m_widget->timeBox->value() << endl;
connect (m_festProc, TQT_SIGNAL(synthFinished()), this, TQT_SLOT(slotSynthFinished()));
m_festProc->synth(
realFilePath(m_widget->festivalPath->url()),
testMsg,
tmpWaveFile,
voiceCode,
m_widget->timeBox->value(),
m_widget->frequencyBox->value(),
m_widget->volumeBox->value(),
languageCode,
codec);
// Display progress dialog modally. Processing continues when plugin signals synthFinished,
// or if user clicks Cancel button.
m_progressDlg->exec();
disconnect (m_festProc, TQT_SIGNAL(synthFinished()), this, TQT_SLOT(slotSynthFinished()));
if (m_progressDlg->wasCancelled()) m_festProc->stopText();
delete m_progressDlg;
m_progressDlg = 0;
}
void FestivalIntConf::slotSynthFinished()
{
// kdDebug() << "FestivalIntConf::slotSynthFinished: Running" << endl;
// If user canceled, progress dialog is gone, so exit.
if (!m_progressDlg)
{
m_festProc->ackFinished();
return;
}
// Hide the Cancel button so user can't cancel in the middle of playback.
m_progressDlg->showCancelButton(false);
// Get new wavefile name.
m_waveFile = m_festProc->getFilename();
// Tell synth we're done.
m_festProc->ackFinished();
// Play the wave file (possibly adjusting its Speed).
// Player object deletes the wave file when done.
if (m_player) m_player->play(m_waveFile);
TQFile::remove(m_waveFile);
m_waveFile = TQString();
if (m_progressDlg) m_progressDlg->close();
}
void FestivalIntConf::slotSynthStopped()
{
// Clean up after canceling test.
TQString filename = m_festProc->getFilename();
// kdDebug() << "FestivalIntConf::slotSynthStopped: filename = " << filename << endl;
if (!filename.isNull()) TQFile::remove(filename);
}
void FestivalIntConf::slotFestivalPath_textChanged()
{
TQString exePath = realFilePath(m_widget->festivalPath->url());
m_widget->selectVoiceCombo->setEnabled(false);
if (!exePath.isEmpty() && !getLocation(exePath).isEmpty())
{
m_widget->rescan->setEnabled(true);
} else m_widget->rescan->setEnabled(false);
}
void FestivalIntConf::slotSelectVoiceCombo_activated()
{
int index = m_widget->selectVoiceCombo->currentItem();
TQString codecName = m_voiceList[index].codecName;
int codecNdx = PlugInProc::codecNameToListIndex(codecName, m_codecList);
m_widget->characterCodingBox->setCurrentItem(codecNdx);
m_widget->preloadCheckBox->setChecked(
m_voiceList[index].preload);
if (m_voiceList[index].volumeAdjustable)
{
m_widget->volumeBox->setEnabled(true);
m_widget->volumeSlider->setEnabled(true);
}
else
{
m_widget->volumeBox->setValue(100);
volumeBox_valueChanged(100);
m_widget->volumeBox->setEnabled(false);
m_widget->volumeSlider->setEnabled(false);
}
if (m_voiceList[index].rateAdjustable)
{
m_widget->timeBox->setEnabled(true);
m_widget->timeSlider->setEnabled(true);
}
else
{
m_widget->timeBox->setValue(100);
timeBox_valueChanged(100);
m_widget->timeBox->setEnabled(false);
m_widget->timeSlider->setEnabled(false);
}
if (m_voiceList[index].pitchAdjustable)
{
m_widget->frequencyBox->setEnabled(true);
m_widget->frequencySlider->setEnabled(true);
}
else
{
m_widget->frequencyBox->setValue(100);
frequencyBox_valueChanged(100);
m_widget->frequencyBox->setEnabled(false);
m_widget->frequencySlider->setEnabled(false);
}
}
// Basically the slider values are logarithmic (0,...,1000) whereas percent
// values are linear (50%,...,200%).
//
// slider = alpha * (log(percent)-log(50))
// with alpha = 1000/(log(200)-log(50))
int FestivalIntConf::percentToSlider(int percentValue) {
double alpha = 1000 / (log(200) - log(50));
return (int)floor (0.5 + alpha * (log(percentValue)-log(50)));
}
int FestivalIntConf::sliderToPercent(int sliderValue) {
double alpha = 1000 / (log(200) - log(50));
return (int)floor(0.5 + exp (sliderValue/alpha + log(50)));
}
void FestivalIntConf::volumeBox_valueChanged(int percentValue) {
m_widget->volumeSlider->setValue(percentToSlider(percentValue));
}
void FestivalIntConf::timeBox_valueChanged(int percentValue) {
m_widget->timeSlider->setValue (percentToSlider (percentValue));
}
void FestivalIntConf::frequencyBox_valueChanged(int percentValue) {
m_widget->frequencySlider->setValue(percentToSlider(percentValue));
}
void FestivalIntConf::volumeSlider_valueChanged(int sliderValue) {
m_widget->volumeBox->setValue(sliderToPercent(sliderValue));
}
void FestivalIntConf::timeSlider_valueChanged(int sliderValue) {
m_widget->timeBox->setValue (sliderToPercent (sliderValue));
}
void FestivalIntConf::frequencySlider_valueChanged(int sliderValue) {
m_widget->frequencyBox->setValue(sliderToPercent(sliderValue));
}