1 /***************************************************** vim:set ts=4 sw=4 sts=4:
2 Configuration widget and functions for Festival (Interactive) plug in
5 (C) 2004 by Gary Cramblitt <garycramblitt@comcast.net>
7 Original author: Gary Cramblitt <garycramblitt@comcast.net>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 ******************************************************************************/
40 #include <kcombobox.h>
42 #include <ktemporaryfile.h>
43 #include <kstandarddirs.h>
44 #include <knuminput.h>
46 #include <kprogressdialog.h>
50 #include "testplayer.h"
52 // FestivalInt includes.
53 #include "festivalintproc.h"
54 #include "festivalintconf.h"
55 #include "festivalintconf.moc"
58 FestivalIntConf::FestivalIntConf( QWidget
* parent
, const QStringList
& /*args*/) :
59 PlugInConf(parent
, "festivalintconf")
61 // kDebug() << "FestivalIntConf::FestivalIntConf: Running" << endl;
64 m_supportsSSML
= FestivalIntProc::ssUnknown
;
68 festivalPath
->setMode(KFile::File
| KFile::ExistingOnly
);
69 festivalPath
->setFilter("*");
71 // Build codec list and fill combobox.
72 m_codecList
= PlugInProc::buildCodecList();
73 characterCodingBox
->clear();
74 characterCodingBox
->addItems(m_codecList
);
78 connect(festivalPath
, SIGNAL(textChanged(const QString
&)),
79 this, SLOT(slotFestivalPath_textChanged()));
80 connect(selectVoiceCombo
, SIGNAL(activated(const QString
&)),
81 this, SLOT(slotSelectVoiceCombo_activated()));
82 connect(selectVoiceCombo
, SIGNAL(activated(const QString
&)),
83 this, SLOT(configChanged()));
84 connect(testButton
, SIGNAL(clicked()), this, SLOT(slotTest_clicked()));
85 connect(rescan
, SIGNAL(clicked()), this, SLOT(scanVoices()));
86 connect(volumeBox
, SIGNAL(valueChanged(int)),
87 this, SLOT(volumeBox_valueChanged(int)));
88 connect(timeBox
, SIGNAL(valueChanged(int)),
89 this, SLOT(timeBox_valueChanged(int)));
90 connect(frequencyBox
, SIGNAL(valueChanged(int)),
91 this, SLOT(frequencyBox_valueChanged(int)));
92 connect(volumeSlider
, SIGNAL(valueChanged(int)),
93 this, SLOT(volumeSlider_valueChanged(int)));
94 connect(timeSlider
, SIGNAL(valueChanged(int)),
95 this, SLOT(timeSlider_valueChanged(int)));
96 connect(frequencySlider
, SIGNAL(valueChanged(int)),
97 this, SLOT(frequencySlider_valueChanged(int)));
98 connect(volumeBox
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
99 connect(volumeSlider
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
100 connect(timeBox
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
101 connect(timeSlider
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
102 connect(frequencyBox
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
103 connect(frequencySlider
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
104 connect(preloadCheckBox
, SIGNAL(clicked()), this, SLOT(configChanged()));
105 connect(characterCodingBox
, SIGNAL(textChanged(const QString
&)),
106 this, SLOT(configChanged()));
107 connect(characterCodingBox
, SIGNAL(activated(const QString
&)),
108 this, SLOT(configChanged()));
112 FestivalIntConf::~FestivalIntConf(){
113 // kDebug() << "FestivalIntConf::~FestivalIntConf: Running" << endl;
114 if (!m_waveFile
.isNull()) QFile::remove(m_waveFile
);
116 delete m_progressDlg
;
120 * Given a voice code, returns index into m_voiceList array (and voiceCombo box).
123 int FestivalIntConf::voiceCodeToListIndex(const QString
& voiceCode
) const
125 for (int i
= 0; i
< m_voiceList
.size(); ++i
)
126 if (m_voiceList
[i
].code
== voiceCode
) return i
;
130 void FestivalIntConf::load(KConfig
*c
, const QString
&configGroup
){
131 //kDebug() << "FestivalIntConf::load: Running" << endl;
132 KConfigGroup
festivalConfig(c
, "FestivalInt");
133 QString exePath
= festivalConfig
.readEntry("FestivalExecutablePath", "festival");
134 QString exeLocation
= getLocation(exePath
);
135 if (!exeLocation
.isEmpty()) exePath
= exeLocation
;
136 exePath
= realFilePath(exePath
);
138 KConfigGroup
config(c
, configGroup
);
139 festivalPath
->setUrl(KUrl::fromPath(config
.readEntry("FestivalExecutablePath", exePath
)));
140 preloadCheckBox
->setChecked(false);
142 QString
voiceSelected(config
.readEntry("Voice"));
143 int index
= voiceCodeToListIndex(voiceSelected
);
146 selectVoiceCombo
->setCurrentIndex(index
);
147 preloadCheckBox
->setChecked(m_voiceList
[index
].preload
);
149 volumeBox
->setValue(config
.readEntry("volume", 100));
150 timeBox
->setValue(config
.readEntry("time", 100));
151 frequencyBox
->setValue(config
.readEntry("pitch", 100));
152 preloadCheckBox
->setChecked(config
.readEntry(
153 "Preload", preloadCheckBox
->isChecked()));
154 m_languageCode
= config
.readEntry("LanguageCode", m_languageCode
);
155 m_supportsSSML
= static_cast<FestivalIntProc::SupportsSSML
>(
156 config
.readEntry("SupportsSSML", int(FestivalIntProc::ssUnknown
)));
157 QString codecName
= PlugInProc::codecIndexToCodecName(
158 characterCodingBox
->currentIndex(), m_codecList
);
159 codecName
= config
.readEntry("Codec", codecName
);
160 int codecNdx
= PlugInProc::codecNameToListIndex(codecName
, m_codecList
);
161 characterCodingBox
->setCurrentIndex(codecNdx
);
164 void FestivalIntConf::save(KConfig
*c
, const QString
&configGroup
){
165 // kDebug() << "FestivalIntConf::save: Running" << endl;
166 KConfigGroup
festivalConfig(c
, "FestivalInt");
167 festivalConfig
.writeEntry("FestivalExecutablePath", realFilePath(festivalPath
->url().path()));
169 KConfigGroup
config(c
, configGroup
);
170 config
.writeEntry("FestivalExecutablePath", realFilePath(festivalPath
->url().path()));
171 config
.writeEntry("Voice", m_voiceList
[selectVoiceCombo
->currentIndex()].code
);
172 config
.writeEntry("volume", volumeBox
->value());
173 config
.writeEntry("time", timeBox
->value());
174 config
.writeEntry("pitch", frequencyBox
->value());
175 config
.writeEntry("Preload", preloadCheckBox
->isChecked());
176 config
.writeEntry("LanguageCode", m_voiceList
[selectVoiceCombo
->currentIndex()].languageCode
);
177 config
.writeEntry("SupportsSSML", int(m_supportsSSML
));
178 int codec
= characterCodingBox
->currentIndex();
179 config
.writeEntry("Codec", PlugInProc::codecIndexToCodecName(codec
, m_codecList
));
182 void FestivalIntConf::defaults(){
183 // kDebug() << "FestivalIntConf::defaults: Running" << endl;
184 festivalPath
->setUrl(KUrl("festival"));
185 timeBox
->setValue(100);
186 timeBox_valueChanged(100);
187 volumeBox
->setValue(100);
188 volumeBox_valueChanged(100);
189 frequencyBox
->setValue(100);
190 frequencyBox_valueChanged(100);
191 preloadCheckBox
->setChecked(false);
192 characterCodingBox
->setCurrentIndex(
193 PlugInProc::codecNameToListIndex("ISO 8859-1", m_codecList
));
197 void FestivalIntConf::setDesiredLanguage(const QString
&lang
)
199 // kDebug() << "FestivalIntConf::setDesiredLanguage: Running" << endl;
200 m_languageCode
= splitLanguageCode(lang
, m_countryCode
);
203 QString
FestivalIntConf::getTalkerCode()
205 if (!selectVoiceCombo
->isEnabled()) return QString();
206 QString exePath
= realFilePath(festivalPath
->url().path());
207 if (exePath
.isEmpty()) return QString();
208 if (getLocation(exePath
).isEmpty()) return QString();
209 if (m_voiceList
.count() == 0) return QString();
210 QString normalTalkerCode
;
211 voiceStruct voiceTemp
= m_voiceList
[selectVoiceCombo
->currentIndex()];
212 // Determine volume attribute. soft < 75% <= medium <= 125% < loud.
213 QString volume
= "medium";
214 if (volumeBox
->value() < 75) volume
= "soft";
215 if (volumeBox
->value() > 125) volume
= "loud";
216 // Determine rate attribute. slow < 75% <= medium <= 125% < fast.
217 QString rate
= "medium";
218 if (timeBox
->value() < 75) rate
= "slow";
219 if (timeBox
->value() > 125) rate
= "fast";
220 normalTalkerCode
= QString(
221 "<voice lang=\"%1\" name=\"%2\" gender=\"%3\" />"
222 "<prosody volume=\"%4\" rate=\"%5\" />"
223 "<kttsd synthesizer=\"%6\" />")
224 .arg(voiceTemp
.languageCode
)
226 .arg(voiceTemp
.gender
)
229 .arg("Festival Interactive");
230 return normalTalkerCode
;
234 * Chooses a default voice given scanned list of voices in m_voiceList and current
235 * language and country code, and updates controls.
236 * @param currentVoiceIndex This voice is preferred if it matches.
238 void FestivalIntConf::setDefaultVoice(int currentVoiceIndex
)
240 // kDebug() << "FestivalIntCont::setDefaultVoice: Running" << endl;
241 // If language code is known, auto pick first voice that matches the language code.
242 if (!m_languageCode
.isEmpty())
245 // First search for a match on both language code and country code.
246 QString languageCode
= m_languageCode
;
247 if (!m_countryCode
.isNull()) languageCode
+= '_' + m_countryCode
;
248 // kDebug() << "FestivalIntConf::setDefaultVoice:: looking for default voice to match language code " << languageCode << endl;
250 // Prefer existing voice if it matches.
251 if (currentVoiceIndex
>= 0)
253 QString vlCode
= m_voiceList
[currentVoiceIndex
].languageCode
.left(languageCode
.length());
254 if (languageCode
== vlCode
)
257 index
= currentVoiceIndex
;
262 for(index
= 0 ; index
< m_voiceList
.count(); ++index
)
264 QString vlCode
= m_voiceList
[index
].languageCode
.left(languageCode
.length());
265 // kDebug() << "FestivalIntConf::setDefaultVoice: testing " << vlCode << endl;
266 if(languageCode
== vlCode
)
273 // If not found, search for a match on just the language code.
276 languageCode
= m_languageCode
;
277 // Prefer existing voice if it matches.
278 if (currentVoiceIndex
>= 0)
280 QString vlCode
= m_voiceList
[currentVoiceIndex
].languageCode
.left(languageCode
.length());
281 if (languageCode
== vlCode
)
284 index
= currentVoiceIndex
;
289 for(index
= 0 ; index
< m_voiceList
.count(); ++index
)
291 QString vlCode
= m_voiceList
[index
].languageCode
.left(languageCode
.length());
292 // kDebug() << "FestivalIntConf::setDefaultVoice: testing " << vlCode << endl;
293 if(languageCode
== vlCode
)
301 // If not found, pick first voice that is not "Unknown".
304 for(index
= 0 ; index
< m_voiceList
.count(); ++index
)
306 if (m_voiceList
[index
].name
!= i18n("Unknown"))
315 // kDebug() << "FestivalIntConf::setDefaultVoice: auto picking voice code " << m_voiceList[index].code << endl;
316 selectVoiceCombo
->setCurrentIndex(index
);
317 preloadCheckBox
->setChecked(m_voiceList
[index
].preload
);
318 QString codecName
= m_voiceList
[index
].codecName
;
319 int codecNdx
= PlugInProc::codecNameToListIndex(codecName
, m_codecList
);
320 characterCodingBox
->setCurrentIndex(codecNdx
);
321 if (m_voiceList
[index
].volumeAdjustable
)
323 volumeBox
->setEnabled(true);
324 volumeSlider
->setEnabled(true);
328 volumeBox
->setValue(100);
329 volumeBox_valueChanged(100);
330 volumeBox
->setEnabled(false);
331 volumeSlider
->setEnabled(false);
333 if (m_voiceList
[index
].rateAdjustable
)
335 timeBox
->setEnabled(true);
336 timeSlider
->setEnabled(true);
340 timeBox
->setValue(100);
341 timeBox_valueChanged(100);
342 timeBox
->setEnabled(false);
343 timeSlider
->setEnabled(false);
345 if (m_voiceList
[index
].pitchAdjustable
)
347 frequencyBox
->setEnabled(true);
348 frequencySlider
->setEnabled(true);
352 frequencyBox
->setValue(100);
353 frequencyBox_valueChanged(100);
354 frequencyBox
->setEnabled(false);
355 frequencySlider
->setEnabled(false);
357 if ((int)index
!= currentVoiceIndex
) configChanged();
363 * Given an XML node and child element name, returns the string value from the child element.
364 * If no such child element, returns def.
366 QString
FestivalIntConf::readXmlString(QDomNode
&node
, const QString
&elementName
, const QString
&def
)
368 QDomNode childNode
= node
.namedItem(elementName
);
369 if (!childNode
.isNull())
370 return childNode
.toElement().text();
376 * Given an XML node and child element name, returns the boolean value from the child element.
377 * If no such child element, returns def.
379 bool FestivalIntConf::readXmlBool(QDomNode
&node
, const QString
&elementName
, bool def
)
381 QDomNode childNode
= node
.namedItem(elementName
);
382 if (!childNode
.isNull())
383 return (childNode
.toElement().text() == "true");
388 void FestivalIntConf::scanVoices()
390 // kDebug() << "FestivalIntConf::scanVoices: Running" << endl;
391 // Get existing voice code (if any).
392 QString currentVoiceCode
;
393 int index
= selectVoiceCombo
->currentIndex();
394 if (index
>= 0 && index
< m_voiceList
.count()) currentVoiceCode
= m_voiceList
[index
].code
;
397 selectVoiceCombo
->clear();
398 selectVoiceCombo
->addItem(i18n("Scanning... Please wait."));
400 // Save current state of selectVoiceCombo box and disable.
401 bool selectVoiceComboEnabled
= selectVoiceCombo
->isEnabled();
402 selectVoiceCombo
->setEnabled(false);
404 // Clear existing list of supported voice codes.
405 // m_supportedVoiceCodes.clear();
406 selectVoiceCombo
->clear();
408 QString exePath
= realFilePath(festivalPath
->url().path());
409 if (!getLocation(exePath
).isEmpty())
411 // Set up a progress dialog.
412 m_progressDlg
= new KProgressDialog(this,
413 i18n("Query Voices"),
414 i18n("Querying Festival for available voices. This could take up to 15 seconds."));
415 m_progressDlg
->setModal(true);
416 m_progressDlg
->progressBar()->hide();
417 m_progressDlg
->setAllowCancel(true);
418 // TODO: This is a bug workaround. Remove when no longer needed.
419 m_progressDlg
->setDefaultButton(KDialog::Cancel
);
421 // Create Festival process and request a list of voice codes.
423 m_festProc
->stopText();
426 m_festProc
= new FestivalIntProc();
427 connect (m_festProc
, SIGNAL(stopped()), this, SLOT(slotSynthStopped()));
429 connect (m_festProc
, SIGNAL(queryVoicesFinished(const QStringList
&)),
430 this, SLOT(slotQueryVoicesFinished(const QStringList
&)));
431 m_festProc
->queryVoices(exePath
);
433 // Display progress dialog modally.
434 m_progressDlg
->exec();
435 // kDebug() << "FestivalIntConf::scanVoices: back from progressDlg->exec()" << endl;
437 // Processing continues until either user clicks Cancel button, or until
438 // Festival responds with the list. When Festival responds with list,
439 // the progress dialog is closed.
441 disconnect (m_festProc
, SIGNAL(queryVoicesFinished(const QStringList
&)),
442 this, SLOT(slotQueryVoicesFinished(const QStringList
&)));
443 if (!m_progressDlg
->wasCancelled()) m_festProc
->stopText();
444 delete m_progressDlg
;
446 m_supportsSSML
= m_festProc
->supportsSSML();
449 if (!m_supportedVoiceCodes
.isEmpty())
451 // User's desktop language setting.
452 QString desktopLanguageCode
= KGlobal::locale()->language();
457 KGlobal::locale()->splitLocale(desktopLanguageCode
, langAlpha
, countryCode
, modifier
, charSet
);
458 desktopLanguageCode
= langAlpha
.toLower();
460 // Festival known voices list.
461 QString voicesFilename
= KGlobal::dirs()->resourceDirs("data").last() + "/kttsd/festivalint/voices";
462 QDomDocument
voicesDoc("Festival Voices");
463 QFile
voicesFile(voicesFilename
);
464 if (voicesFile
.open(QIODevice::ReadOnly
)) voicesDoc
.setContent(&voicesFile
);
466 QDomNodeList voices
= voicesDoc
.elementsByTagName("voice");
467 uint voicesCount
= voices
.count();
468 if (voicesCount
== 0)
469 kDebug() << "FestivalIntConf::scanVoices: Unable to open " << voicesFilename
<< ". Is KDEDIR defined?" << endl
;
471 // Iterate thru list of voice codes returned by Festival,
472 // find matching entry in voices.xml file, and add to list of supported voices.
473 KIcon
maleIcon("male");
474 KIcon
femaleIcon("female");
475 QStringList::ConstIterator itEnd
= m_supportedVoiceCodes
.constEnd();
476 for(QStringList::ConstIterator it
= m_supportedVoiceCodes
.begin(); it
!= itEnd
; ++it
)
480 for (uint index
=0; index
< voicesCount
; ++index
)
482 QDomNode voiceNode
= voices
.item(index
);
483 QString voiceCode
= readXmlString(voiceNode
, "code", QString());
484 // kDebug() << "FestivalIntConf::scanVoices: Comparing code " << code << " to " << voiceCode << endl;
485 if (voiceCode
== code
)
488 voiceStruct voiceTemp
;
489 voiceTemp
.code
= code
;
490 voiceTemp
.name
= i18nc("FestivalVoiceName",
491 readXmlString(voiceNode
, "name", "Unknown").toUtf8());
492 voiceTemp
.languageCode
= readXmlString(voiceNode
, "language", m_languageCode
);
493 voiceTemp
.codecName
= readXmlString(voiceNode
, "codec", "ISO 8859-1");
494 voiceTemp
.gender
= readXmlString(voiceNode
, "gender", "neutral");
495 voiceTemp
.preload
= readXmlBool(voiceNode
, "preload", false);
496 voiceTemp
.volumeAdjustable
= readXmlBool(voiceNode
, "volume-adjustable", true);
497 voiceTemp
.rateAdjustable
= readXmlBool(voiceNode
, "rate-adjustable", true);
498 voiceTemp
.pitchAdjustable
= readXmlBool(voiceNode
, "pitch-adjustable", true);
499 m_voiceList
.append(voiceTemp
);
500 QString voiceDisplayName
= voiceTemp
.name
+ " (" + voiceTemp
.code
+ ')';
501 if (voiceTemp
.gender
== "male")
502 selectVoiceCombo
->addItem(maleIcon
, voiceDisplayName
);
503 else if (voiceTemp
.gender
== "female")
504 selectVoiceCombo
->addItem(femaleIcon
, voiceDisplayName
);
506 selectVoiceCombo
->addItem(voiceDisplayName
);
512 voiceStruct voiceTemp
;
513 voiceTemp
.code
= code
;
514 voiceTemp
.name
= i18n("Unknown");
515 voiceTemp
.languageCode
= m_languageCode
;
516 voiceTemp
.codecName
= "ISO 8858-1";
517 voiceTemp
.gender
= "neutral";
518 voiceTemp
.preload
= false;
519 voiceTemp
.volumeAdjustable
= true;
520 voiceTemp
.rateAdjustable
= true;
521 voiceTemp
.pitchAdjustable
= true;
522 m_voiceList
.append(voiceTemp
);
523 selectVoiceCombo
->addItem(voiceTemp
.name
+ " (" + voiceTemp
.code
+ ')');
526 selectVoiceCombo
->setEnabled(true);
527 } else kDebug() << "FestivalIntConf::scanVoices: No voices found" << endl
;
528 setDefaultVoice(voiceCodeToListIndex(currentVoiceCode
));
529 // Emit configChanged if the enabled state of the selectVoiceCombo has changed.
530 // This occurs when user changes Festival EXE path, then clicks Rescan.
531 if (selectVoiceComboEnabled
!= selectVoiceCombo
->isEnabled()) configChanged();
534 void FestivalIntConf::slotQueryVoicesFinished(const QStringList
&voiceCodes
)
536 // kDebug() << "FestivalIntConf::slotQueryVoicesFinished: voiceCodes.count() = " << voiceCodes.count() << endl;
537 m_supportedVoiceCodes
= voiceCodes
;
538 if (m_progressDlg
) m_progressDlg
->close();
541 void FestivalIntConf::slotTest_clicked()
543 // kDebug() << "FestivalIntConf::slotTest_clicked: Running " << endl;
544 // If currently synthesizing, stop it.
546 m_festProc
->stopText();
549 m_festProc
= new FestivalIntProc();
550 connect (m_festProc
, SIGNAL(stopped()), this, SLOT(slotSynthStopped()));
552 // Create a temp file name for the wave file.
553 KTemporaryFile
*tempFile
= new KTemporaryFile();
554 tempFile
->setPrefix("festivalintplugin-");
555 tempFile
->setSuffix(".wav");
557 QString tmpWaveFile
= tempFile
->fileName();
560 kDebug() << "FestivalIntConf::slotTest_clicked: tmpWaveFile = " << tmpWaveFile
<< endl
;
562 // Get the code for the selected voice.
563 QString voiceCode
= m_voiceList
[selectVoiceCombo
->currentIndex()].code
;
565 // Get language code for the selected voice.
566 QString languageCode
= m_voiceList
[selectVoiceCombo
->currentIndex()].languageCode
;
568 // Get test message in the language of the voice.
569 QString testMsg
= testMessage(languageCode
);
572 QTextCodec
* codec
= PlugInProc::codecIndexToCodec(
573 characterCodingBox
->currentIndex(), m_codecList
);
575 // Tell user to wait.
576 m_progressDlg
= new KProgressDialog(this,
578 i18n("Testing. MultiSyn voices require several seconds to load. Please be patient."));
579 m_progressDlg
->setModal(true);
580 m_progressDlg
->progressBar()->hide();
581 m_progressDlg
->setAllowCancel(true);
583 // kDebug() << "FestivalIntConf::slotTest_clicked: calling synth with voiceCode: " << voiceCode << " time percent: " << timeBox->value() << endl;
584 connect (m_festProc
, SIGNAL(synthFinished()), this, SLOT(slotSynthFinished()));
586 realFilePath(festivalPath
->url().path()),
591 frequencyBox
->value(),
596 // Display progress dialog modally. Processing continues when plugin signals synthFinished,
597 // or if user clicks Cancel button.
598 m_progressDlg
->exec();
599 disconnect (m_festProc
, SIGNAL(synthFinished()), this, SLOT(slotSynthFinished()));
600 if (m_progressDlg
->wasCancelled()) m_festProc
->stopText();
601 delete m_progressDlg
;
605 void FestivalIntConf::slotSynthFinished()
607 // kDebug() << "FestivalIntConf::slotSynthFinished: Running" << endl;
608 // If user canceled, progress dialog is gone, so exit.
611 m_festProc
->ackFinished();
614 // Hide the Cancel button so user can't cancel in the middle of playback.
615 m_progressDlg
->showCancelButton(false);
616 // Get new wavefile name.
617 m_waveFile
= m_festProc
->getFilename();
618 // Tell synth we're done.
619 m_festProc
->ackFinished();
620 // Play the wave file (possibly adjusting its Speed).
621 // Player object deletes the wave file when done.
622 if (m_player
) m_player
->play(m_waveFile
);
623 QFile::remove(m_waveFile
);
625 if (m_progressDlg
) m_progressDlg
->close();
628 void FestivalIntConf::slotSynthStopped()
630 // Clean up after canceling test.
631 QString filename
= m_festProc
->getFilename();
632 // kDebug() << "FestivalIntConf::slotSynthStopped: filename = " << filename << endl;
633 if (!filename
.isNull()) QFile::remove(filename
);
636 void FestivalIntConf::slotFestivalPath_textChanged()
638 QString exePath
= realFilePath(festivalPath
->url().path());
639 selectVoiceCombo
->setEnabled(false);
640 if (!exePath
.isEmpty() && !getLocation(exePath
).isEmpty())
642 rescan
->setEnabled(true);
643 } else rescan
->setEnabled(false);
646 void FestivalIntConf::slotSelectVoiceCombo_activated()
648 int index
= selectVoiceCombo
->currentIndex();
649 QString codecName
= m_voiceList
[index
].codecName
;
650 int codecNdx
= PlugInProc::codecNameToListIndex(codecName
, m_codecList
);
651 characterCodingBox
->setCurrentIndex(codecNdx
);
652 preloadCheckBox
->setChecked(
653 m_voiceList
[index
].preload
);
654 if (m_voiceList
[index
].volumeAdjustable
)
656 volumeBox
->setEnabled(true);
657 volumeSlider
->setEnabled(true);
661 volumeBox
->setValue(100);
662 volumeBox_valueChanged(100);
663 volumeBox
->setEnabled(false);
664 volumeSlider
->setEnabled(false);
666 if (m_voiceList
[index
].rateAdjustable
)
668 timeBox
->setEnabled(true);
669 timeSlider
->setEnabled(true);
673 timeBox
->setValue(100);
674 timeBox_valueChanged(100);
675 timeBox
->setEnabled(false);
676 timeSlider
->setEnabled(false);
678 if (m_voiceList
[index
].pitchAdjustable
)
680 frequencyBox
->setEnabled(true);
681 frequencySlider
->setEnabled(true);
685 frequencyBox
->setValue(100);
686 frequencyBox_valueChanged(100);
687 frequencyBox
->setEnabled(false);
688 frequencySlider
->setEnabled(false);
692 // Basically the slider values are logarithmic (0,...,1000) whereas percent
693 // values are linear (50%,...,200%).
695 // slider = alpha * (log(percent)-log(50))
696 // with alpha = 1000/(log(200)-log(50))
698 int FestivalIntConf::percentToSlider(int percentValue
) {
699 double alpha
= 1000 / (log(200) - log(50));
700 return (int)floor (0.5 + alpha
* (log(percentValue
)-log(50)));
703 int FestivalIntConf::sliderToPercent(int sliderValue
) {
704 double alpha
= 1000 / (log(200) - log(50));
705 return (int)floor(0.5 + exp (sliderValue
/alpha
+ log(50)));
708 void FestivalIntConf::volumeBox_valueChanged(int percentValue
) {
709 volumeSlider
->setValue(percentToSlider(percentValue
));
712 void FestivalIntConf::timeBox_valueChanged(int percentValue
) {
713 timeSlider
->setValue (percentToSlider (percentValue
));
716 void FestivalIntConf::frequencyBox_valueChanged(int percentValue
) {
717 frequencySlider
->setValue(percentToSlider(percentValue
));
720 void FestivalIntConf::volumeSlider_valueChanged(int sliderValue
) {
721 volumeBox
->setValue(sliderToPercent(sliderValue
));
724 void FestivalIntConf::timeSlider_valueChanged(int sliderValue
) {
725 timeBox
->setValue (sliderToPercent (sliderValue
));
728 void FestivalIntConf::frequencySlider_valueChanged(int sliderValue
) {
729 frequencyBox
->setValue(sliderToPercent(sliderValue
));