diff options
author | Tuomas Tuononen <tuomas.tuononen@code-q.fi> | 2015-08-31 16:53:58 +0300 |
---|---|---|
committer | Tuomas Tuononen <tuomas.tuononen@code-q.fi> | 2015-10-16 13:15:48 +0000 |
commit | e207c6542f50977b5eb420e576c9b198db273dfe (patch) | |
tree | 1d886eb23a125bbdf03ff7416e6b29d14b89af45 | |
parent | 0de45e249d5e0b9de9cb4f45ee785a1b05d67598 (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.cpp | 55 | ||||
-rw-r--r-- | config.tests/flite/flite.pro | 3 | ||||
-rw-r--r-- | qtspeech.pro | 2 | ||||
-rwxr-xr-x | src/plugins/tts/flite/flite.pro | 19 | ||||
-rw-r--r-- | src/plugins/tts/flite/flite_legal.qdoc | 217 | ||||
-rwxr-xr-x | src/plugins/tts/flite/flite_plugin.json | 6 | ||||
-rwxr-xr-x | src/plugins/tts/flite/qtexttospeechengine_flite.cpp | 475 | ||||
-rwxr-xr-x | src/plugins/tts/flite/qtexttospeechengine_flite.h | 141 | ||||
-rwxr-xr-x | src/plugins/tts/flite/qtexttospeechplugin_flite.cpp | 55 | ||||
-rwxr-xr-x | src/plugins/tts/flite/qtexttospeechplugin_flite.h | 66 | ||||
-rwxr-xr-x | src/plugins/tts/tts.pro | 4 |
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 ¶meters, 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 ¶meters, 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 ¶meters, 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 ¶meters, + 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 +} |