summaryrefslogtreecommitdiffstats
path: root/src/plugins/tts/flite/qtexttospeech_flite.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/tts/flite/qtexttospeech_flite.cpp')
-rwxr-xr-xsrc/plugins/tts/flite/qtexttospeech_flite.cpp331
1 files changed, 32 insertions, 299 deletions
diff --git a/src/plugins/tts/flite/qtexttospeech_flite.cpp b/src/plugins/tts/flite/qtexttospeech_flite.cpp
index 86f6974..364727f 100755
--- a/src/plugins/tts/flite/qtexttospeech_flite.cpp
+++ b/src/plugins/tts/flite/qtexttospeech_flite.cpp
@@ -36,292 +36,19 @@
#include "qtexttospeech_flite.h"
-#include <QGlobalStatic>
-#include <QIODevice>
-#include <QAudioOutput>
-#include <QMutex>
-#include <QDebug>
-#include <QSemaphore>
-#include <QThread>
-
-#include <flite/flite.h>
-
-// en_US voice:
-extern "C" cst_voice *register_cmu_us_kal16();
-extern "C" void unregister_cmu_us_kal16(cst_voice *vox);
-
QT_BEGIN_NAMESPACE
-// Class that handles global Flite initialization and
-// creates the processor thread.
-class FliteLoader
-{
-public:
- struct FliteVoiceInfo {
- cst_voice *vox;
- void (*unregister_func)(cst_voice *vox);
- QString name;
- QString localeName;
- QString gender;
- QString age;
- };
- FliteLoader()
- {
- flite_init();
- FliteVoiceInfo voice_enus = { register_cmu_us_kal16(), unregister_cmu_us_kal16, "kal16", "en_US", "male", "adult" };
- if (voice_enus.vox)
- m_voices.append(voice_enus);
- m_processor = new FliteProcessor();
- QObject::connect(m_processor, &QThread::finished, &QThread::deleteLater);
- m_processor->start();
- }
- ~FliteLoader()
- {
- foreach (const FliteLoader::FliteVoiceInfo &voice, m_voices)
- voice.unregister_func(voice.vox);
- m_processor->exit();
- }
- const QVector<FliteVoiceInfo> &voices() const
- {
- return m_voices;
- }
- FliteProcessor *processor() const
- {
- return m_processor;
- }
-private:
- QVector<FliteVoiceInfo> m_voices;
- FliteProcessor *m_processor;
-};
-
-Q_GLOBAL_STATIC(FliteLoader, fliteLoader)
-
-FliteProcessor::FliteProcessor():
- m_stop(true),
- m_idle(true),
- m_rate(0),
- m_pitch(0),
- m_volume(100)
-{
-}
-
-FliteProcessor::~FliteProcessor()
-{
-}
-
-void FliteProcessor::say(cst_voice *voice, const QString &text)
-{
- if (isInterruptionRequested())
- return;
- QMutexLocker lock(&m_lock);
- m_stop = true; // Cancel any previous utterance
- m_idle = false;
- m_nextText = text;
- m_nextVoice = voice;
- setRateForVoice(m_nextVoice, m_rate);
- setPitchForVoice(m_nextVoice, m_pitch);
- m_speakSem.release();
-}
-
-void FliteProcessor::stop()
-{
- QMutexLocker lock(&m_lock);
- m_stop = true;
- m_nextText.clear();
- m_nextVoice = 0;
- m_speakSem.release();
-}
-
-bool FliteProcessor::setRate(float rate)
-{
- QMutexLocker lock(&m_lock);
- if (rate >= -1.0 && rate <= 1.0) {
- m_rate = rate;
- return true;
- }
- return false;
-}
-
-bool FliteProcessor::setPitch(float pitch)
-{
- QMutexLocker lock(&m_lock);
- if (pitch >= -1.0 && pitch <= 1.0) {
- m_pitch = pitch;
- return true;
- }
- return false;
-}
-
-bool FliteProcessor::setVolume(int volume)
-{
- QMutexLocker lock(&m_lock);
- if (volume >= 0 && volume <= 100) {
- m_volume = volume;
- if (m_audio)
- m_audio->setVolume(((qreal)m_volume) / 100.0);
- return true;
- }
- return false;
-}
-
-void FliteProcessor::exit()
-{
- QThread::exit();
- requestInterruption();
- stop();
-}
-
-bool FliteProcessor::isIdle()
-{
- QMutexLocker lock(&m_lock);
- return m_idle;
-}
-
-float FliteProcessor::rate()
-{
- QMutexLocker lock(&m_lock);
- return m_rate;
-}
-
-float FliteProcessor::pitch()
-{
- QMutexLocker lock(&m_lock);
- return m_pitch;
-}
-
-int FliteProcessor::volume()
-{
- QMutexLocker lock(&m_lock);
- return m_volume;
-}
-
-void FliteProcessor::run()
-{
- forever {
- m_lock.lock();
- if (!m_speakSem.tryAcquire()) {
- m_idle = true;
- m_lock.unlock();
- emit notSpeaking(); // Going idle
- m_speakSem.acquire();
- m_lock.lock();
- }
- if (isInterruptionRequested()) {
- m_lock.unlock();
- return;
- }
- m_stop = false;
- if (!m_nextText.isEmpty() && m_nextVoice) {
- cst_audio_streaming_info *asi;
- QString text = m_nextText;
- cst_voice *voice = m_nextVoice;
- m_nextText.clear();
- m_nextVoice = 0;
- m_lock.unlock();
- asi = new_audio_streaming_info();
- asi->asc = FliteProcessor::fliteAudioCb;
- asi->userdata = (void *)this;
- feat_set(voice->features, "streaming_info", audio_streaming_info_val(asi));
- flite_text_to_speech(text.toUtf8().constData(), voice, "none");
- } else {
- m_lock.unlock();
- }
- }
-}
-
-void FliteProcessor::setRateForVoice(cst_voice *voice, float rate)
-{
- float stretch = 1.0;
- Q_ASSERT(rate >= -1.0 && rate <= 1.0);
- // Stretch multipliers taken from Speech Dispatcher
- if (rate < 0)
- stretch -= rate * 2;
- if (rate > 0)
- stretch -= rate * (100.0 / 175.0);
- feat_set_float(voice->features, "duration_stretch", stretch);
-}
-
-void FliteProcessor::setPitchForVoice(cst_voice *voice, float pitch)
-{
- float f0;
- Q_ASSERT(pitch >= -1.0 && pitch <= 1.0);
- // Conversion taken from Speech Dispatcher
- f0 = (pitch * 80) + 100;
- feat_set_float(voice->features, "int_f0_target_mean", f0);
-}
-
-int FliteProcessor::audioOutput(const cst_wave *w, int start, int size,
- int last, cst_audio_streaming_info *asi)
-{
- Q_UNUSED(asi);
- int ret = CST_AUDIO_STREAM_CONT;
- if (start == 0) {
- m_lock.lock();
- QAudioFormat format;
- format.setSampleRate(w->sample_rate);
- format.setChannelCount(w->num_channels);
- format.setSampleSize(16);
- format.setSampleType(QAudioFormat::SignedInt);
- format.setCodec("audio/pcm");
- m_audio = new QAudioOutput(format);
- m_audio->setVolume(((qreal)m_volume) / 100.0);
- m_audioBuffer = m_audio->start();
- m_lock.unlock();
- }
- int bytesToWrite = size * sizeof(short);
- int bytesWritten = 0;
- forever {
- m_lock.lock();
- if (m_stop || !m_audioBuffer
- || m_audio->state() == QAudio::StoppedState || isInterruptionRequested()) {
- m_lock.unlock();
- ret = CST_AUDIO_STREAM_STOP;
- break;
- }
- bytesWritten += m_audioBuffer->write((const char*)(&w->samples[start + bytesWritten/sizeof(short)]), bytesToWrite - bytesWritten);
- m_lock.unlock();
- if (bytesWritten >= bytesToWrite)
- break;
- QThread::msleep(200);
- }
- m_lock.lock();
- if (m_stop || last == 1) {
- if (m_stop) {
- m_audio->reset(); // Discard buffered audio
- } else {
- // TODO: Find a way to reliably check if all the audio has been written out before stopping
- m_audioBuffer->write(QByteArray(1024, 0));
- QThread::msleep(200);
- m_audio->stop();
- }
- delete m_audio;
- m_audio = 0;
- m_audioBuffer = 0;
- }
- m_lock.unlock();
- return ret;
-}
-
-int FliteProcessor::fliteAudioCb(const cst_wave *w, int start, int size,
- int last, cst_audio_streaming_info *asi)
-{
- FliteProcessor *processor = static_cast<FliteProcessor *>(asi->userdata);
- if (processor)
- return processor->audioOutput(w, start, size, last, asi);
- return CST_AUDIO_STREAM_STOP;
-}
-
QTextToSpeechEngineFlite::QTextToSpeechEngineFlite(
const QVariantMap &parameters, QObject *parent) :
QTextToSpeechEngine(parent),
- m_state(QTextToSpeech::Ready)
+ m_state(QTextToSpeech::Ready),
+ m_processor(QTextToSpeechProcessorFlite::instance())
{
Q_UNUSED(parameters);
}
QTextToSpeechEngineFlite::~QTextToSpeechEngineFlite()
{
-
}
QVector<QLocale> QTextToSpeechEngineFlite::availableLocales() const
@@ -337,48 +64,54 @@ QVector<QVoice> QTextToSpeechEngineFlite::availableVoices() const
void QTextToSpeechEngineFlite::say(const QString &text)
{
int id = QTextToSpeechEngine::voiceData(m_currentVoice).toInt();
- cst_voice *voiceData = fliteLoader()->voices()[id].vox;
m_state = QTextToSpeech::Speaking;
emit stateChanged(m_state);
- fliteLoader()->processor()->say(voiceData, text);
+ m_processor->say(text, id);
}
void QTextToSpeechEngineFlite::stop()
{
- fliteLoader()->processor()->stop();
+ m_processor->stop();
m_state = QTextToSpeech::Ready;
emit stateChanged(m_state);
}
void QTextToSpeechEngineFlite::pause()
{
- // Not supported, just stop:
- stop();
+ if (m_state == QTextToSpeech::Speaking) {
+ m_processor->pause();
+ m_state = QTextToSpeech::Paused;
+ emit stateChanged(m_state);
+ }
}
void QTextToSpeechEngineFlite::resume()
{
-
+ if (m_state == QTextToSpeech::Paused) {
+ m_processor->resume();
+ m_state = QTextToSpeech::Speaking;
+ emit stateChanged(m_state);
+ }
}
double QTextToSpeechEngineFlite::rate() const
{
- return fliteLoader()->processor()->rate();
+ return m_processor->rate();
}
bool QTextToSpeechEngineFlite::setRate(double rate)
{
- return fliteLoader()->processor()->setRate(rate);
+ return m_processor->setRate(rate);
}
double QTextToSpeechEngineFlite::pitch() const
{
- return fliteLoader()->processor()->pitch();
+ return m_processor->pitch();
}
bool QTextToSpeechEngineFlite::setPitch(double pitch)
{
- return fliteLoader()->processor()->setPitch(pitch);
+ return m_processor->setPitch(pitch);
}
QLocale QTextToSpeechEngineFlite::locale() const
@@ -406,12 +139,12 @@ bool QTextToSpeechEngineFlite::setLocale(const QLocale &locale)
int QTextToSpeechEngineFlite::volume() const
{
- return fliteLoader()->processor()->volume();
+ return m_processor->volume();
}
bool QTextToSpeechEngineFlite::setVolume(int volume)
{
- return fliteLoader()->processor()->setVolume(volume);
+ return m_processor->setVolume(volume);
}
QVoice QTextToSpeechEngineFlite::voice() const
@@ -438,14 +171,13 @@ QTextToSpeech::State QTextToSpeechEngineFlite::state() const
bool QTextToSpeechEngineFlite::init(QString *errorString)
{
int i = 0;
- QVector<FliteLoader::FliteVoiceInfo> voices = fliteLoader()->voices();
- foreach (const FliteLoader::FliteVoiceInfo &fliteVoice, voices) {
- QVoice::Age age = QVoice::Other;
- QVoice::Gender gender = QVoice::Unknown;
- QString name = fliteVoice.name;
- QLocale locale(fliteVoice.localeName);
- QVoice voice = QTextToSpeechEngine::createVoice(name, gender, age, QVariant(i));
- m_voices.insert(fliteVoice.localeName, voice);
+ const QVector<QTextToSpeechProcessor::VoiceInfo> &voices = m_processor->voices();
+ foreach (const QTextToSpeechProcessor::VoiceInfo &voiceInfo, voices) {
+ QString name = voiceInfo.name;
+ QLocale locale(voiceInfo.locale);
+ QVoice voice = QTextToSpeechEngine::createVoice(name, voiceInfo.gender, voiceInfo.age,
+ QVariant(voiceInfo.id));
+ m_voices.insert(voiceInfo.locale, voice);
if (!m_locales.contains(locale))
m_locales.append(locale);
// Use the first available locale/voice as a fallback
@@ -457,16 +189,17 @@ bool QTextToSpeechEngineFlite::init(QString *errorString)
}
// Attempt to switch to the system locale
setLocale(QLocale::system());
- connect(fliteLoader()->processor(), &FliteProcessor::notSpeaking,
+ connect(m_processor.data(), &QTextToSpeechProcessor::notSpeaking,
this, &QTextToSpeechEngineFlite::onNotSpeaking);
if (errorString)
- *errorString = QStringLiteral("");
+ *errorString = QString();
return true;
}
-void QTextToSpeechEngineFlite::onNotSpeaking()
+void QTextToSpeechEngineFlite::onNotSpeaking(int statusCode)
{
- if (m_state != QTextToSpeech::Ready && fliteLoader()->processor()->isIdle()) {
+ Q_UNUSED(statusCode);
+ if (m_state != QTextToSpeech::Ready && m_processor->isIdle()) {
m_state = QTextToSpeech::Ready;
emit stateChanged(m_state);
}