summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTuomas Tuononen <tuomas.tuononen@code-q.fi>2015-08-31 16:53:58 +0300
committerTuomas Tuononen <tuomas.tuononen@code-q.fi>2015-10-16 13:15:48 +0000
commite207c6542f50977b5eb420e576c9b198db273dfe (patch)
tree1d886eb23a125bbdf03ff7416e6b29d14b89af45
parent0de45e249d5e0b9de9cb4f45ee785a1b05d67598 (diff)
Initial implementation of Flite text-to-speech plug-in
Requires flite headers and libraries (version 2.0.0) installed in the system. Change-Id: Iccb5c6b467f76831e8c82d8823c2f2d29ac36d88 Reviewed-by: Jeremy Whiting <jpwhiting@kde.org> Reviewed-by: Frederik Gladhorn <frederik.gladhorn@theqtcompany.com>
-rw-r--r--config.tests/flite/flite.cpp55
-rw-r--r--config.tests/flite/flite.pro3
-rw-r--r--qtspeech.pro2
-rwxr-xr-xsrc/plugins/tts/flite/flite.pro19
-rw-r--r--src/plugins/tts/flite/flite_legal.qdoc217
-rwxr-xr-xsrc/plugins/tts/flite/flite_plugin.json6
-rwxr-xr-xsrc/plugins/tts/flite/qtexttospeechengine_flite.cpp475
-rwxr-xr-xsrc/plugins/tts/flite/qtexttospeechengine_flite.h141
-rwxr-xr-xsrc/plugins/tts/flite/qtexttospeechplugin_flite.cpp55
-rwxr-xr-xsrc/plugins/tts/flite/qtexttospeechplugin_flite.h66
-rwxr-xr-xsrc/plugins/tts/tts.pro4
11 files changed, 1043 insertions, 0 deletions
diff --git a/config.tests/flite/flite.cpp b/config.tests/flite/flite.cpp
new file mode 100644
index 0000000..d040c0b
--- /dev/null
+++ b/config.tests/flite/flite.cpp
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Speech module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <flite/flite.h>
+
+static int fliteAudioCb(const cst_wave *w, int start, int size,
+ int last, cst_audio_streaming_info *asi)
+{
+ (void)w;
+ (void)start;
+ (void)size;
+ (void)last;
+ (void)asi;
+ return CST_AUDIO_STREAM_STOP;
+}
+
+int main()
+{
+ cst_audio_streaming_info *asi = new_audio_streaming_info();
+ asi->asc = fliteAudioCb; // This fails for old Flite
+ return 0;
+}
diff --git a/config.tests/flite/flite.pro b/config.tests/flite/flite.pro
new file mode 100644
index 0000000..81e94eb
--- /dev/null
+++ b/config.tests/flite/flite.pro
@@ -0,0 +1,3 @@
+SOURCES = flite.cpp
+
+LIBS += -lflite_cmu_us_kal16 -lflite_usenglish -lflite_cmulex -lflite
diff --git a/qtspeech.pro b/qtspeech.pro
index 7da79db..a5c17fc 100644
--- a/qtspeech.pro
+++ b/qtspeech.pro
@@ -1,2 +1,4 @@
lessThan(QT_MAJOR_VERSION, 5): error("The QtSpeech library only supports Qt 5.")
+load(configure)
+qtCompileTest(flite)
load(qt_parts)
diff --git a/src/plugins/tts/flite/flite.pro b/src/plugins/tts/flite/flite.pro
new file mode 100755
index 0000000..f1cdc9b
--- /dev/null
+++ b/src/plugins/tts/flite/flite.pro
@@ -0,0 +1,19 @@
+TARGET = qttexttospeech_flite
+QT = core multimedia texttospeech
+
+PLUGIN_TYPE = texttospeech
+PLUGIN_CLASS_NAME = QTextToSpeechEngineFlite
+load(qt_plugin)
+
+HEADERS += \
+ qtexttospeechengine_flite.h \
+ qtexttospeechplugin_flite.h
+
+SOURCES += \
+ qtexttospeechengine_flite.cpp \
+ qtexttospeechplugin_flite.cpp
+
+OTHER_FILES += \
+ flite_plugin.json
+
+LIBS += -lflite_cmu_us_kal16 -lflite_usenglish -lflite_cmulex -lflite
diff --git a/src/plugins/tts/flite/flite_legal.qdoc b/src/plugins/tts/flite/flite_legal.qdoc
new file mode 100644
index 0000000..f8f4d96
--- /dev/null
+++ b/src/plugins/tts/flite/flite_legal.qdoc
@@ -0,0 +1,217 @@
+/*!
+\page legal-flite.html
+\title Flite Library
+\ingroup licensing
+
+\legalese
+\code
+
+Flite is free software.
+
+We have kept the core code to BSD-like copyright, thus the system is
+free to use in commercial products, with commercial extensions. GPL
+code is only included as part of the build process and does not
+taint any of the run-time code.
+
+As a collection it is distributed under the following license. Note
+a few files in this distribution have a different but equally free
+non-conflicting license, see below.
+
+ Language Technologies Institute
+ Carnegie Mellon University
+ Copyright (c) 1999-2014
+ All Rights Reserved.
+
+ Permission is hereby granted, free of charge, to use and distribute
+ this software and its documentation without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of this work, and to
+ permit persons to whom this work is furnished to do so, subject to
+ the following conditions:
+ 1. The code must retain the above copyright notice, this list of
+ conditions and the following disclaimer.
+ 2. Any modifications must be clearly marked as such.
+ 3. Original authors' names are not deleted.
+ 4. The authors' names are not used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+ CARNEGIE MELLON UNIVERSITY AND THE CONTRIBUTORS TO THIS WORK
+ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
+ SHALL CARNEGIE MELLON UNIVERSITY NOR THE CONTRIBUTORS BE LIABLE
+ FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+
+All files within this distribution have the above license except
+the following
+
+src/cg/cst_mlpg.h
+src/cg/cst_mlpg.c
+src/cg/cst_mlsa.h
+src/cg/cst_mlsa.c
+src/cg/cst_vc.h
+src/cg/cst_vc.c
+*********************************************************************
+* *
+* Nagoya Institute of Technology, Aichi, Japan, *
+* Nara Institute of Science and Technology, Nara, Japan *
+* and *
+* Carnegie Mellon University, Pittsburgh, PA *
+* Copyright (c) 2003-2004 *
+* All Rights Reserved. *
+* *
+* Permission is hereby granted, free of charge, to use and *
+* distribute this software and its documentation without *
+* restriction, including without limitation the rights to use, *
+* copy, modify, merge, publish, distribute, sublicense, and/or *
+* sell copies of this work, and to permit persons to whom this *
+* work is furnished to do so, subject to the following conditions: *
+* *
+* 1. The code must retain the above copyright notice, this list *
+* of conditions and the following disclaimer. *
+* 2. Any modifications must be clearly marked as such. *
+* 3. Original authors' names are not deleted. *
+* *
+* NAGOYA INSTITUTE OF TECHNOLOGY, NARA INSTITUTE OF SCIENCE AND *
+* TECHNOLOGY, CARNEGIE MELLON UNIVERSITY, AND THE CONTRIBUTORS TO *
+* THIS WORK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, *
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, *
+* IN NO EVENT SHALL NAGOYA INSTITUTE OF TECHNOLOGY, NARA *
+* INSTITUTE OF SCIENCE AND TECHNOLOGY, CARNEGIE MELLON UNIVERSITY, *
+* NOR THE CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR *
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM *
+* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, *
+* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN *
+* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+* *
+*********************************************************************
+
+These functions are derived from the versions in festvox/src/vc/ as
+modified by Tomoki Toda which in turn contain code derived from
+NITECH's HTS system. Their copyright has the same freedoms as
+as Flite's but under NAIST, NITECH and/or CMU.
+
+src/audio/au_wince.c
+src/utils/cst_file_stdio.c
+src/utils/cst_mmap_posix.c
+src/utils/cst_mmap_win32.c
+src/utils/cst_mmap_none.c
+src/utils/cst_file_wince.c
+sapi/
+ are copyright Cepstral, LLC rather than CMU but fall under the same
+ free license as the above, except for the owner. (Note the SAPI stuff
+ probably doesn't work any more)
+
+doc/alice
+ Is the first two chapters of Alice in Wonderland as distributed by the
+ Gutenburg project and is now in the public domain
+
+src/regex/regexp.c
+src/regex/regsub.c
+
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+
+src/speech/rateconv.c
+
+ * Copyright (c) 1992, 1995 by Markus Mummert
+ *
+ * Redistribution and use of this software, modifcation and inclusion
+ * into other forms of software are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of this software must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. If this software is redistributed in a modified condition
+ * it must reveal clearly that it has been modified.
+
+lang/usenglish/us_durz_cart.c
+lang/usenglish/us_durz_cart.h
+lang/usenglish/us_int_accent_cart.c
+lang/usenglish/us_int_accent_cart.h
+lang/usenglish/us_int_tone_cart.c
+lang/usenglish/us_int_tone_cart.h
+lang/usenglish/us_phoneset.c
+lang/usenglish/us_f0lr.c
+ These are directly (or indirectly) compiled/derived from files that are
+ part of the Festival Speech Synthesis System (1.4.1). Hence they have
+ a joint copyright CMU/Edinburgh but with the same free license
+
+configure
+ # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+ #
+ # This configure script is free software; the Free Software Foundation
+ # gives unlimited permission to copy, distribute and modify it.
+
+configure.sub
+config.guess
+missing
+install-sh
+mkinstalldirs
+ Copyright FSF, and under the GPL, these files are only used for
+ convenient configuration and are not part of the generated binary,
+ and therefore do not impose any GPL restrctions on the rest of the
+ system. But as they are standard methods for configuration they
+ are included.
+
+src/speech/g72x.h
+src/speech/g721.c
+src/speech/g72x.c
+src/speech/g723_24.c
+src/speech/g723_40.c
+
+ *
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ *
+
+lang/cmu_grapheme_lex/grapheme_unitran_tables.c
+ * Copyright 2008-2012, University of Illinois at Urbana-Champaign *
+ * distributed under the Apache License, Version (2.0) *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * Original table developed by Richard Sproat and Kyoung-young Kim *
+ * Ported for Festvox by Gopala Anumachipalli gopalakr@cs.cmu.edu Sep 2012 *
+ * Then converted to C for CMU Flite (cmuflite.org) *
+
+\endcode
+\endlegalese
+*/
diff --git a/src/plugins/tts/flite/flite_plugin.json b/src/plugins/tts/flite/flite_plugin.json
new file mode 100755
index 0000000..dad4918
--- /dev/null
+++ b/src/plugins/tts/flite/flite_plugin.json
@@ -0,0 +1,6 @@
+{
+ "Keys": ["flite"],
+ "Provider": "flite",
+ "Version": 100,
+ "Features": []
+}
diff --git a/src/plugins/tts/flite/qtexttospeechengine_flite.cpp b/src/plugins/tts/flite/qtexttospeechengine_flite.cpp
new file mode 100755
index 0000000..d49b1bf
--- /dev/null
+++ b/src/plugins/tts/flite/qtexttospeechengine_flite.cpp
@@ -0,0 +1,475 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Speech module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtexttospeechengine_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)
+{
+ Q_UNUSED(parameters);
+}
+
+QTextToSpeechEngineFlite::~QTextToSpeechEngineFlite()
+{
+
+}
+
+QVector<QLocale> QTextToSpeechEngineFlite::availableLocales() const
+{
+ return m_locales;
+}
+
+QVector<QVoice> QTextToSpeechEngineFlite::availableVoices() const
+{
+ return m_voices.values(m_currentLocale.name()).toVector();
+}
+
+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);
+}
+
+void QTextToSpeechEngineFlite::stop()
+{
+ fliteLoader()->processor()->stop();
+ m_state = QTextToSpeech::Ready;
+ emit stateChanged(m_state);
+}
+
+void QTextToSpeechEngineFlite::pause()
+{
+ // Not supported, just stop:
+ stop();
+}
+
+void QTextToSpeechEngineFlite::resume()
+{
+
+}
+
+double QTextToSpeechEngineFlite::rate() const
+{
+ return fliteLoader()->processor()->rate();
+}
+
+bool QTextToSpeechEngineFlite::setRate(double rate)
+{
+ return fliteLoader()->processor()->setRate(rate);
+}
+
+double QTextToSpeechEngineFlite::pitch() const
+{
+ return fliteLoader()->processor()->pitch();
+}
+
+bool QTextToSpeechEngineFlite::setPitch(double pitch)
+{
+ return fliteLoader()->processor()->setPitch(pitch);
+}
+
+QLocale QTextToSpeechEngineFlite::locale() const
+{
+ return m_currentLocale;
+}
+
+bool QTextToSpeechEngineFlite::setLocale(const QLocale &locale)
+{
+ bool localeFound = false;
+ foreach (const QLocale &l, m_locales) {
+ if (l.name() == locale.name()) {
+ localeFound = true;
+ break;
+ }
+ }
+ if (!localeFound)
+ return false;
+ if (m_currentLocale.name() != locale.name()) {
+ m_currentLocale = locale;
+ m_currentVoice = availableVoices().at(0);
+ }
+ return true;
+}
+
+int QTextToSpeechEngineFlite::volume() const
+{
+ return fliteLoader()->processor()->volume();
+}
+
+bool QTextToSpeechEngineFlite::setVolume(int volume)
+{
+ return fliteLoader()->processor()->setVolume(volume);
+}
+
+QVoice QTextToSpeechEngineFlite::voice() const
+{
+ return m_currentVoice;
+}
+
+bool QTextToSpeechEngineFlite::setVoice(const QVoice &voice)
+{
+ foreach (const QVoice &availableVoice, availableVoices()) {
+ if (QTextToSpeechEngine::voiceData(availableVoice) == QTextToSpeechEngine::voiceData(voice)) {
+ m_currentVoice = voice;
+ return true;
+ }
+ }
+ return false;
+}
+
+QTextToSpeech::State QTextToSpeechEngineFlite::state() const
+{
+ return m_state;
+}
+
+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);
+ if (!m_locales.contains(locale))
+ m_locales.append(locale);
+ // Use the first available locale/voice as a fallback
+ if (i == 0) {
+ m_currentVoice = voice;
+ m_currentLocale = locale;
+ }
+ i++;
+ }
+ // Attempt to switch to the system locale
+ setLocale(QLocale::system());
+ connect(fliteLoader()->processor(), &FliteProcessor::notSpeaking,
+ this, &QTextToSpeechEngineFlite::onNotSpeaking);
+ if (errorString)
+ *errorString = QStringLiteral("");
+ return true;
+}
+
+void QTextToSpeechEngineFlite::onNotSpeaking()
+{
+ if (m_state != QTextToSpeech::Ready && fliteLoader()->processor()->isIdle()) {
+ m_state = QTextToSpeech::Ready;
+ emit stateChanged(m_state);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tts/flite/qtexttospeechengine_flite.h b/src/plugins/tts/flite/qtexttospeechengine_flite.h
new file mode 100755
index 0000000..ff94bef
--- /dev/null
+++ b/src/plugins/tts/flite/qtexttospeechengine_flite.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Speech module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTEXTTOSPEECHENGINE_FLITE_H
+#define QTEXTTOSPEECHENGINE_FLITE_H
+
+#include "qtexttospeechengine.h"
+#include "qvoice.h"
+
+#include <QtCore/QString>
+#include <QtCore/QLocale>
+#include <QtCore/QVector>
+#include <QtCore/QThread>
+#include <QtCore/QMutex>
+#include <QtCore/QSemaphore>
+#include <QtCore/QIODevice>
+#include <QtMultimedia/QAudioOutput>
+
+#include <flite/flite.h>
+
+QT_BEGIN_NAMESPACE
+
+class FliteProcessor : public QThread {
+ Q_OBJECT
+
+public:
+ FliteProcessor();
+ ~FliteProcessor();
+ void say(cst_voice *voice, const QString &text);
+ void stop();
+ bool setRate(float rate);
+ bool setPitch(float pitch);
+ bool setVolume(int volume);
+ void exit();
+ bool isIdle();
+ float rate();
+ float pitch();
+ int volume();
+
+signals:
+ void notSpeaking();
+
+private:
+ QMutex m_lock;
+ bool m_stop;
+ bool m_idle;
+ float m_rate;
+ float m_pitch;
+ int m_volume;
+ QSemaphore m_speakSem;
+ QString m_nextText;
+ cst_voice *m_nextVoice;
+ QAudioOutput *m_audio;
+ QIODevice *m_audioBuffer;
+ void run();
+ void setRateForVoice(cst_voice *voice, float rate);
+ void setPitchForVoice(cst_voice *voice, float pitch);
+ int audioOutput(const cst_wave *w, int start, int size,
+ int last, cst_audio_streaming_info *asi);
+ static int fliteAudioCb(const cst_wave *w, int start, int size,
+ int last, cst_audio_streaming_info *asi);
+};
+
+class QTextToSpeechEngineFlite : public QTextToSpeechEngine
+{
+ Q_OBJECT
+
+public:
+ QTextToSpeechEngineFlite(const QVariantMap &parameters, QObject *parent);
+ virtual ~QTextToSpeechEngineFlite();
+
+ // Plug-in API:
+ QVector<QLocale> availableLocales() const Q_DECL_OVERRIDE;
+ QVector<QVoice> availableVoices() const Q_DECL_OVERRIDE;
+ void say(const QString &text) Q_DECL_OVERRIDE;
+ void stop() Q_DECL_OVERRIDE;
+ void pause() Q_DECL_OVERRIDE;
+ void resume() Q_DECL_OVERRIDE;
+ double rate() const Q_DECL_OVERRIDE;
+ bool setRate(double rate) Q_DECL_OVERRIDE;
+ double pitch() const Q_DECL_OVERRIDE;
+ bool setPitch(double pitch) Q_DECL_OVERRIDE;
+ QLocale locale() const Q_DECL_OVERRIDE;
+ bool setLocale(const QLocale &locale) Q_DECL_OVERRIDE;
+ int volume() const Q_DECL_OVERRIDE;
+ bool setVolume(int volume) Q_DECL_OVERRIDE;
+ QVoice voice() const Q_DECL_OVERRIDE;
+ bool setVoice(const QVoice &voice) Q_DECL_OVERRIDE;
+ QTextToSpeech::State state() const Q_DECL_OVERRIDE;
+
+ // Internal API:
+ bool init(QString *errorString);
+
+public slots:
+ void onNotSpeaking();
+
+private:
+ QTextToSpeech::State m_state;
+ QLocale m_currentLocale;
+ QVector<QLocale> m_locales;
+ QVoice m_currentVoice;
+ // Voices mapped by their locale name.
+ QMultiMap<QString, QVoice> m_voices;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/tts/flite/qtexttospeechplugin_flite.cpp b/src/plugins/tts/flite/qtexttospeechplugin_flite.cpp
new file mode 100755
index 0000000..783012b
--- /dev/null
+++ b/src/plugins/tts/flite/qtexttospeechplugin_flite.cpp
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Speech module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtexttospeechplugin_flite.h"
+#include "qtexttospeechengine_flite.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcSpeechTtsFlite, "qt.speech.tts.flite")
+
+QTextToSpeechEngine *QTextToSpeechPluginFlite::createTextToSpeechEngine(
+ const QVariantMap &parameters, QObject *parent, QString *errorString) const
+{
+ QTextToSpeechEngineFlite *flite = new QTextToSpeechEngineFlite(parameters, parent);
+ if (flite && flite->init(errorString)) {
+ return flite;
+ }
+ delete flite;
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/tts/flite/qtexttospeechplugin_flite.h b/src/plugins/tts/flite/qtexttospeechplugin_flite.h
new file mode 100755
index 0000000..fe9ed64
--- /dev/null
+++ b/src/plugins/tts/flite/qtexttospeechplugin_flite.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Speech module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTEXTTOSPEECHPLUGIN_FLITE_H
+#define QTEXTTOSPEECHPLUGIN_FLITE_H
+
+#include "qtexttospeechplugin.h"
+#include "qtexttospeechengine.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcSpeechTtsFlite)
+
+class QTextToSpeechPluginFlite : public QObject, public QTextToSpeechPlugin
+{
+ Q_OBJECT
+ Q_INTERFACES(QTextToSpeechPlugin)
+ Q_PLUGIN_METADATA(IID "org.qt-project.qt.speech.tts.plugin/5.0"
+ FILE "flite_plugin.json")
+
+public:
+ QTextToSpeechEngine *createTextToSpeechEngine(
+ const QVariantMap &parameters,
+ QObject *parent,
+ QString *errorString) const;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/tts/tts.pro b/src/plugins/tts/tts.pro
index ef07835..fd333c0 100755
--- a/src/plugins/tts/tts.pro
+++ b/src/plugins/tts/tts.pro
@@ -6,3 +6,7 @@ unix {
SUBDIRS += speechdispatcher
}
}
+
+config_flite {
+ SUBDIRS += flite
+}