1 /***************************************************** vim:set ts=4 sw=4 sts=4:
2 Configuration widget and functions for Epos 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 ******************************************************************************/
24 // Epos Plugin includes.
27 #include "eposconf.moc"
33 #include <QtCore/QFile>
34 #include <QtGui/QApplication>
35 #include <QtCore/QTextCodec>
36 #include <QtGui/QSlider>
40 #include <ktemporaryfile.h>
41 #include <kstandarddirs.h>
42 #include <kcombobox.h>
44 #include <knuminput.h>
45 #include <kprogressdialog.h>
48 #include <testplayer.h>
51 EposConf::EposConf( QWidget
* parent
, const QStringList
& /*args*/) :
52 PlugInConf(parent
, "eposconf")
54 // kDebug() << "EposConf::EposConf: Running";
60 // Build codec list and fill combobox.
61 m_codecList
= PlugInProc::buildCodecList();
62 characterCodingBox
->clear();
63 characterCodingBox
->addItems(m_codecList
);
67 connect(eposServerPath
, SIGNAL(textChanged(const QString
&)),
68 this, SLOT(configChanged()));
69 connect(eposClientPath
, SIGNAL(textChanged(const QString
&)),
70 this, SLOT(configChanged()));
71 connect(timeBox
, SIGNAL(valueChanged(int)),
72 this, SLOT(timeBox_valueChanged(int)));
73 connect(frequencyBox
, SIGNAL(valueChanged(int)),
74 this, SLOT(frequencyBox_valueChanged(int)));
75 connect(timeSlider
, SIGNAL(valueChanged(int)),
76 this, SLOT(timeSlider_valueChanged(int)));
77 connect(frequencySlider
, SIGNAL(valueChanged(int)),
78 this, SLOT(frequencySlider_valueChanged(int)));
79 connect(timeBox
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
80 connect(timeSlider
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
81 connect(frequencyBox
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
82 connect(frequencySlider
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
83 connect(characterCodingBox
, SIGNAL(activated(const QString
&)),
84 this, SLOT(configChanged()));
85 connect(eposServerOptions
, SIGNAL(textChanged(const QString
&)),
86 this, SLOT(configChanged()));
87 connect(eposClientOptions
, SIGNAL(textChanged(const QString
&)),
88 this, SLOT(configChanged()));
89 connect(eposTest
, SIGNAL(clicked()),
90 this, SLOT(slotEposTest_clicked()));
94 EposConf::~EposConf(){
95 // kDebug() << "Running: EposConf::~EposConf()";
96 if (!m_waveFile
.isNull()) QFile::remove(m_waveFile
);
101 void EposConf::load(KConfig
*c
, const QString
&configGroup
){
102 // kDebug() << "EposConf::load: Running ";
104 KConfigGroup
config(c
, configGroup
);
105 eposServerPath
->setUrl(KUrl::fromPath(config
.readEntry("EposServerExePath", "epos")));
106 eposClientPath
->setUrl(KUrl::fromPath(config
.readEntry("EposClientExePath", "say")));
107 eposServerOptions
->setText(config
.readEntry("EposServerOptions", ""));
108 eposClientOptions
->setText(config
.readEntry("EposClientOptions", ""));
109 QString codecString
= config
.readEntry("Codec", "ISO 8859-2");
110 int codec
= PlugInProc::codecNameToListIndex(codecString
, m_codecList
);
111 timeBox
->setValue(config
.readEntry("time", 100));
112 frequencyBox
->setValue(config
.readEntry("pitch", 100));
113 characterCodingBox
->setCurrentIndex(codec
);
117 * Converts a language code into the language setting passed to Epos synth.
119 QString
EposConf::languageCodeToEposLanguage(const QString
&languageCode
)
121 QString eposLanguage
;
122 if (languageCode
.left(2) == "cs") eposLanguage
= "czech";
123 if (languageCode
.left(2) == "sk") eposLanguage
= "slovak";
127 void EposConf::save(KConfig
*c
, const QString
&configGroup
){
128 // kDebug() << "EposConf::save: Running";
131 KConfigGroup
config(c
, "Epos");
132 config
.writeEntry("EposServerExePath",
133 realFilePath(eposServerPath
->url().path()));
134 config
.writeEntry("EposClientExePath",
135 realFilePath(eposClientPath
->url().path()));
136 config
.writeEntry("Language", languageCodeToEposLanguage(m_languageCode
));
139 KConfigGroup
config(c
, configGroup
);
140 config
.writeEntry("EposServerExePath",
141 realFilePath(eposServerPath
->url().path()));
142 config
.writeEntry("EposClientExePath",
143 realFilePath(eposClientPath
->url().path()));
144 config
.writeEntry("EposServerOptions", eposServerOptions
->text());
145 config
.writeEntry("EposClientOptions", eposClientOptions
->text());
146 config
.writeEntry("time", timeBox
->value());
147 config
.writeEntry("pitch", frequencyBox
->value());
148 int codec
= characterCodingBox
->currentIndex();
149 config
.writeEntry("Codec", PlugInProc::codecIndexToCodecName(codec
, m_codecList
));
152 void EposConf::defaults(){
153 // kDebug() << "EposConf::defaults: Running";
154 eposServerPath
->setUrl(KUrl("epos"));
155 eposClientPath
->setUrl(KUrl("say"));
156 eposServerOptions
->setText("");
157 eposClientOptions
->setText("");
158 timeBox
->setValue(100);
159 timeBox_valueChanged(100);
160 frequencyBox
->setValue(100);
161 frequencyBox_valueChanged(100);
162 int codec
= PlugInProc::codecNameToListIndex("ISO 8859-2", m_codecList
);
163 characterCodingBox
->setCurrentIndex(codec
);
166 void EposConf::setDesiredLanguage(const QString
&lang
)
168 m_languageCode
= lang
;
171 QString
EposConf::getTalkerCode()
173 QString eposServerExe
= realFilePath(eposServerPath
->url().path());
174 QString eposClientExe
= realFilePath(eposClientPath
->url().path());
175 if (!eposServerExe
.isEmpty() && !eposClientExe
.isEmpty())
177 if (!getLocation(eposServerExe
).isEmpty() && !getLocation(eposClientExe
).isEmpty())
179 QString rate
= "medium";
180 if (timeBox
->value() < 75) rate
= "slow";
181 if (timeBox
->value() > 125) rate
= "fast";
183 "<voice lang=\"%1\" name=\"%2\" gender=\"%3\" />"
184 "<prosody volume=\"%4\" rate=\"%5\" />"
185 "<kttsd synthesizer=\"%6\" />")
191 .arg("Epos TTS Synthesis System");
197 void EposConf::slotEposTest_clicked()
199 // kDebug() << "EposConf::slotEposTest_clicked(): Running";
200 // If currently synthesizing, stop it.
202 m_eposProc
->stopText();
205 m_eposProc
= new EposProc();
206 connect (m_eposProc
, SIGNAL(stopped()), this, SLOT(slotSynthStopped()));
208 // Create a temp file name for the wave file.
209 KTemporaryFile tempFile
;
210 tempFile
.setPrefix("eposplugin-");
211 tempFile
.setSuffix(".wav");
212 tempFile
.setAutoRemove(false);
214 QString tmpWaveFile
= tempFile
.fileName();
216 // Get test message in the language of the voice.
217 QString testMsg
= testMessage(m_languageCode
);
219 // Tell user to wait.
220 m_progressDlg
= new KProgressDialog(this,
223 m_progressDlg
->setModal(true);
224 m_progressDlg
->progressBar()->hide();
225 m_progressDlg
->setAllowCancel(true);
227 // TODO: Whenever server options change, the server must be restarted.
228 // TODO: Do codec names contain non-ASCII characters?
229 connect (m_eposProc
, SIGNAL(synthFinished()), this, SLOT(slotSynthFinished()));
233 realFilePath(eposServerPath
->url().path()),
234 realFilePath(eposClientPath
->url().path()),
235 eposServerOptions
->text(),
236 eposClientOptions
->text(),
237 PlugInProc::codecIndexToCodec(characterCodingBox
->currentIndex(), m_codecList
),
238 languageCodeToEposLanguage(m_languageCode
),
240 frequencyBox
->value()
243 // Display progress dialog modally. Processing continues when plugin signals synthFinished,
244 // or if user clicks Cancel button.
245 m_progressDlg
->exec();
246 disconnect (m_eposProc
, SIGNAL(synthFinished()), this, SLOT(slotSynthFinished()));
247 if (m_progressDlg
->wasCancelled()) m_eposProc
->stopText();
248 delete m_progressDlg
;
252 void EposConf::slotSynthFinished()
254 // If user canceled, progress dialog is gone, so exit.
257 m_eposProc
->ackFinished();
260 // Hide the Cancel button so user can't cancel in the middle of playback.
261 m_progressDlg
->showCancelButton(false);
262 // Get new wavefile name.
263 m_waveFile
= m_eposProc
->getFilename();
264 // Tell synth we're done.
265 m_eposProc
->ackFinished();
266 // Play the wave file (possibly adjusting its Speed).
267 // Player object deletes the wave file when done.
268 if (m_player
) m_player
->play(m_waveFile
);
269 QFile::remove(m_waveFile
);
271 if (m_progressDlg
) m_progressDlg
->close();
274 void EposConf::slotSynthStopped()
276 // Clean up after canceling test.
277 QString filename
= m_eposProc
->getFilename();
278 if (!filename
.isNull()) QFile::remove(filename
);
281 // Basically the slider values are logarithmic (0,...,1000) whereas percent
282 // values are linear (50%,...,200%).
284 // slider = alpha * (log(percent)-log(50))
285 // with alpha = 1000/(log(200)-log(50))
287 int EposConf::percentToSlider(int percentValue
) {
288 double alpha
= 1000 / (log(200.0) - log(50.0));
289 return (int)floor (0.5 + alpha
* (log((double)percentValue
)-log(50.0L)));
292 int EposConf::sliderToPercent(int sliderValue
) {
293 double alpha
= 1000 / (log(200.0) - log(50.0));
294 return (int)floor(0.5 + exp (sliderValue
/alpha
+ log(50.0)));
297 void EposConf::timeBox_valueChanged(int percentValue
) {
298 timeSlider
->setValue (percentToSlider (percentValue
));
301 void EposConf::frequencyBox_valueChanged(int percentValue
) {
302 frequencySlider
->setValue(percentToSlider(percentValue
));
305 void EposConf::timeSlider_valueChanged(int sliderValue
) {
306 timeBox
->setValue (sliderToPercent (sliderValue
));
309 void EposConf::frequencySlider_valueChanged(int sliderValue
) {
310 frequencyBox
->setValue(sliderToPercent(sliderValue
));