diff options
author | Richard Moe Gustavsen <richard.gustavsen@qt.io> | 2016-08-31 12:55:51 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@qt.io> | 2016-09-13 08:54:31 +0000 |
commit | e7bd63efa002878e0049925ebc971ae816377a0f (patch) | |
tree | ecdf589f3c97d28abeb46b379507e0d90bc62d3d | |
parent | 577060af2daa198b3607911fd410bb1fa03ae861 (diff) |
iOS: add tts backend for iOS
This will add a new tts backend for iOS.
Change-Id: Ie8eec9cda260c7bfe8c1f5ed52152c2fdfd472da
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
-rw-r--r-- | src/plugins/tts/ios/ios.pro | 24 | ||||
-rw-r--r-- | src/plugins/tts/ios/ios_plugin.json | 6 | ||||
-rw-r--r-- | src/plugins/tts/ios/qtexttospeech_ios.h | 93 | ||||
-rw-r--r-- | src/plugins/tts/ios/qtexttospeech_ios.mm | 282 | ||||
-rw-r--r-- | src/plugins/tts/ios/qtexttospeech_ios_plugin.cpp | 44 | ||||
-rw-r--r-- | src/plugins/tts/ios/qtexttospeech_ios_plugin.h | 63 | ||||
-rw-r--r-- | src/plugins/tts/tts.pro | 1 |
7 files changed, 513 insertions, 0 deletions
diff --git a/src/plugins/tts/ios/ios.pro b/src/plugins/tts/ios/ios.pro new file mode 100644 index 0000000..247aac4 --- /dev/null +++ b/src/plugins/tts/ios/ios.pro @@ -0,0 +1,24 @@ +TARGET = qtexttospeech_speechios +PLUGIN_TYPE = texttospeech +PLUGIN_CLASS_NAME = QTextToSpeechPluginIos + +load(qt_plugin) + +QT += core texttospeech +LIBS += -framework AVFoundation + +HEADERS += \ + qtexttospeech_ios_plugin.h \ + qtexttospeech_ios.h \ + +OBJECTIVE_HEADERS += \ + qtexttospeech_ios.h \ + +SOURCES += \ + qtexttospeech_ios_plugin.cpp \ + +OBJECTIVE_SOURCES += \ + qtexttospeech_ios.mm \ + +OTHER_FILES += \ + ios_plugin.json diff --git a/src/plugins/tts/ios/ios_plugin.json b/src/plugins/tts/ios/ios_plugin.json new file mode 100644 index 0000000..694c226 --- /dev/null +++ b/src/plugins/tts/ios/ios_plugin.json @@ -0,0 +1,6 @@ +{ + "Keys": ["ios"], + "Provider": "ios", + "Version": 100, + "Features": [] +} diff --git a/src/plugins/tts/ios/qtexttospeech_ios.h b/src/plugins/tts/ios/qtexttospeech_ios.h new file mode 100644 index 0000000..8791f94 --- /dev/null +++ b/src/plugins/tts/ios/qtexttospeech_ios.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_IOS_H +#define QTEXTTOSPEECHENGINE_IOS_H + +#include <QtCore/qvector.h> +#include <QtTextToSpeech/qtexttospeechengine.h> +#include <QtTextToSpeech/qvoice.h> + +Q_FORWARD_DECLARE_OBJC_CLASS(AVSpeechSynthesizer); +Q_FORWARD_DECLARE_OBJC_CLASS(AVSpeechSynthesisVoice); + +QT_BEGIN_NAMESPACE + +class QTextToSpeechEngineIos : public QTextToSpeechEngine +{ + Q_OBJECT + +public: + QTextToSpeechEngineIos(const QVariantMap ¶meters, QObject *parent); + ~QTextToSpeechEngineIos(); + + QVector<QLocale> availableLocales() const override; + QVector<QVoice> availableVoices() const override; + void say(const QString &text) override; + void stop() override; + void pause() override; + void resume() override; + double rate() const override; + bool setRate(double rate) override; + double pitch() const override; + bool setPitch(double pitch) override; + QLocale locale() const override; + bool setLocale(const QLocale &locale) override; + double volume() const override; + bool setVolume(double volume) override; + QVoice voice() const override; + bool setVoice(const QVoice &voice) override; + QTextToSpeech::State state() const override; + + void setState(QTextToSpeech::State state); + +private: + AVSpeechSynthesisVoice *fromQVoice(const QVoice &voice) const; + QVoice toQVoice(AVSpeechSynthesisVoice *avVoice) const; + + AVSpeechSynthesizer *m_speechSynthesizer; + QLocale m_locale; + QVoice m_voice; + QTextToSpeech::State m_state; + + double m_pitch; + double m_rate; + double m_volume; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/tts/ios/qtexttospeech_ios.mm b/src/plugins/tts/ios/qtexttospeech_ios.mm new file mode 100644 index 0000000..ca885a5 --- /dev/null +++ b/src/plugins/tts/ios/qtexttospeech_ios.mm @@ -0,0 +1,282 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 <AVFoundation/AVFoundation.h> + +#include "qtexttospeech_ios.h" + +@interface QIOSSpeechSynthesizerDelegate : NSObject <AVSpeechSynthesizerDelegate> { + QTextToSpeechEngineIos *_engine; +} +@end + +@implementation QIOSSpeechSynthesizerDelegate + +- (id)initWithQIOSTextToSpeechEngineIos:(QTextToSpeechEngineIos *)engine +{ + if (self = [super init]) { + _engine = engine; + } + return self; +} + +- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didCancelSpeechUtterance:(AVSpeechUtterance *)utterance +{ + Q_UNUSED(synthesizer); + Q_UNUSED(utterance); + _engine->setState(QTextToSpeech::Ready); +} + +- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didContinueSpeechUtterance:(AVSpeechUtterance *)utterance +{ + Q_UNUSED(synthesizer); + Q_UNUSED(utterance); + _engine->setState(QTextToSpeech::Speaking); +} + +- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance +{ + Q_UNUSED(synthesizer); + Q_UNUSED(utterance); + _engine->setState(QTextToSpeech::Ready); +} + +- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didPauseSpeechUtterance:(AVSpeechUtterance *)utterance +{ + Q_UNUSED(synthesizer); + Q_UNUSED(utterance); + _engine->setState(QTextToSpeech::Paused); +} + +- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didStartSpeechUtterance:(AVSpeechUtterance *)utterance +{ + Q_UNUSED(synthesizer); + Q_UNUSED(utterance); + _engine->setState(QTextToSpeech::Speaking); +} + +@end + +// ------------------------------------------------------------------------- + +QT_BEGIN_NAMESPACE + +QTextToSpeechEngineIos::QTextToSpeechEngineIos(const QVariantMap &/*parameters*/, QObject *parent) + : QTextToSpeechEngine(parent) + , m_speechSynthesizer([AVSpeechSynthesizer new]) + , m_locale(QLocale()) + , m_voice(QVoice()) + , m_state(QTextToSpeech::Ready) + , m_pitch(0) + , m_rate(0) + , m_volume(1) +{ + m_speechSynthesizer.delegate = [[QIOSSpeechSynthesizerDelegate alloc] initWithQIOSTextToSpeechEngineIos:this]; +} + +QTextToSpeechEngineIos::~QTextToSpeechEngineIos() +{ + [m_speechSynthesizer.delegate autorelease]; + [m_speechSynthesizer release]; +} + +void QTextToSpeechEngineIos::say(const QString &text) +{ + stop(); + + AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:text.toNSString()]; + utterance.volume = m_volume; + utterance.voice = fromQVoice(m_voice); + // Pitch: Qt range: [-1.0, 1.0], iOS range: [0.5, 2.0] + utterance.pitchMultiplier = 0.5 + ((m_pitch + 1.0) / 2.0 * 1.5); + + if (m_rate >= 0) { + // The QtTextToSpeech documentation states that a rate of 0.0 represents normal speech flow. + // To map that to AVSpeechUtteranceDefaultSpeechRate while at the same time preserve the Qt + // range [-1.0, 1.0], we choose to operate with two differente rate convertions; one for + // values in the range [-1, 0), and for [0, 1]. + float range = AVSpeechUtteranceMaximumSpeechRate - AVSpeechUtteranceDefaultSpeechRate; + utterance.rate = AVSpeechUtteranceDefaultSpeechRate + (m_rate * range); + } else { + float range = AVSpeechUtteranceDefaultSpeechRate - AVSpeechUtteranceMinimumSpeechRate; + utterance.rate = AVSpeechUtteranceMinimumSpeechRate + (m_rate * range); + } + + [m_speechSynthesizer speakUtterance:utterance]; +} + +void QTextToSpeechEngineIos::stop() +{ + [m_speechSynthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate]; +} + +void QTextToSpeechEngineIos::pause() +{ + [m_speechSynthesizer pauseSpeakingAtBoundary:AVSpeechBoundaryWord]; +} + +void QTextToSpeechEngineIos::resume() +{ + [m_speechSynthesizer continueSpeaking]; +} + +bool QTextToSpeechEngineIos::setRate(double rate) +{ + m_rate = rate; + return true; +} + +double QTextToSpeechEngineIos::rate() const +{ + return m_rate; +} + +bool QTextToSpeechEngineIos::setPitch(double pitch) +{ + m_pitch = pitch; + return true; +} + +double QTextToSpeechEngineIos::pitch() const +{ + return m_pitch; +} + +bool QTextToSpeechEngineIos::setVolume(double volume) +{ + m_volume = volume; + return true; +} + +double QTextToSpeechEngineIos::volume() const +{ + return m_volume; +} + +QVector<QLocale> QTextToSpeechEngineIos::availableLocales() const +{ + QVector<QLocale> localeVector; + QString prevVoiceLanguage; + for (AVSpeechSynthesisVoice *voice in [AVSpeechSynthesisVoice speechVoices]) { + QString language = QString::fromNSString(voice.language); + // Filter out languages already added. A language will occur several times + // in sequence if more than one voice name exists for them. + if (language == prevVoiceLanguage) + continue; + localeVector << QLocale(language); + prevVoiceLanguage = language; + } + + return localeVector; +} + +bool QTextToSpeechEngineIos::setLocale(const QLocale &locale) +{ + NSString *bcp47 = locale.bcp47Name().toNSString(); + AVSpeechSynthesisVoice *defaultAvVoice = [AVSpeechSynthesisVoice voiceWithLanguage:bcp47]; + if (!defaultAvVoice) + return false; + + m_locale = locale; + m_voice = toQVoice(defaultAvVoice); + return true; +} + +QLocale QTextToSpeechEngineIos::locale() const +{ + return m_locale; +} + +QVector<QVoice> QTextToSpeechEngineIos::availableVoices() const +{ + QVector<QVoice> voiceVector; + QString countryCode = m_locale.name().mid(3); + + for (AVSpeechSynthesisVoice *avVoice in [AVSpeechSynthesisVoice speechVoices]) { + if (QString::fromNSString(avVoice.language).endsWith(countryCode)) + voiceVector << toQVoice(avVoice); + } + + return voiceVector; +} + +bool QTextToSpeechEngineIos::setVoice(const QVoice &voice) +{ + AVSpeechSynthesisVoice *avVoice = fromQVoice(voice); + if (!avVoice) + return false; + + m_voice = voice; + return true; +} + +QVoice QTextToSpeechEngineIos::voice() const +{ + return m_voice; +} + +AVSpeechSynthesisVoice *QTextToSpeechEngineIos::fromQVoice(const QVoice &voice) const +{ + for (AVSpeechSynthesisVoice *avVoice in [AVSpeechSynthesisVoice speechVoices]) { + if (voice.name() == QString::fromNSString(avVoice.name)) + return avVoice; + } + + return Q_NULLPTR; +} + +QVoice QTextToSpeechEngineIos::toQVoice(AVSpeechSynthesisVoice *avVoice) const +{ + return createVoice(QString::fromNSString(avVoice.name), QVoice::Unknown, QVoice::Other, QVariant()); +} + +void QTextToSpeechEngineIos::setState(QTextToSpeech::State state) +{ + if (m_state == state) + return; + + m_state = state; + emit stateChanged(m_state); +} + +QTextToSpeech::State QTextToSpeechEngineIos::state() const +{ + return m_state; +} + + + +QT_END_NAMESPACE diff --git a/src/plugins/tts/ios/qtexttospeech_ios_plugin.cpp b/src/plugins/tts/ios/qtexttospeech_ios_plugin.cpp new file mode 100644 index 0000000..db03b13 --- /dev/null +++ b/src/plugins/tts/ios/qtexttospeech_ios_plugin.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** 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 "qtexttospeech_ios_plugin.h" +#include "qtexttospeech_ios.h" + +QTextToSpeechEngine *QTextToSpeechPluginIos::createTextToSpeechEngine(const QVariantMap ¶meters, QObject *parent, QString *errorString) const +{ + Q_UNUSED(errorString) + return new QTextToSpeechEngineIos(parameters, parent); +} diff --git a/src/plugins/tts/ios/qtexttospeech_ios_plugin.h b/src/plugins/tts/ios/qtexttospeech_ios_plugin.h new file mode 100644 index 0000000..f6d4e0d --- /dev/null +++ b/src/plugins/tts/ios/qtexttospeech_ios_plugin.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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_IOS_H +#define QTEXTTOSPEECHPLUGIN_IOS_H + +#include <QtCore/QObject> +#include <QtCore/QLoggingCategory> +#include <QtTextToSpeech/qtexttospeechplugin.h> +#include <QtTextToSpeech/qtexttospeechengine.h> + +QT_BEGIN_NAMESPACE + +class QTextToSpeechPluginIos : public QObject, public QTextToSpeechPlugin +{ + Q_OBJECT + Q_INTERFACES(QTextToSpeechPlugin) + Q_PLUGIN_METADATA(IID "org.qt-project.qt.speech.tts.plugin/5.0" + FILE "ios_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 0d56920..5ae366a 100644 --- a/src/plugins/tts/tts.pro +++ b/src/plugins/tts/tts.pro @@ -13,6 +13,7 @@ windows:!winrt:!mingw: SUBDIRS += sapi winrt: SUBDIRS += winrt osx: SUBDIRS += osx +ios: SUBDIRS += ios android: SUBDIRS += android |