diff options
author | Frederik Gladhorn <frederik.gladhorn@theqtcompany.com> | 2015-10-19 16:38:03 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@theqtcompany.com> | 2015-10-28 11:56:15 +0000 |
commit | 1f497d36c94fe857be9909038c7474b7032f08e6 (patch) | |
tree | 33c17a65bc050045beed6b74a97eb9252e48b0e7 | |
parent | b9151f75c83f021f9ff9d57f768299b9ca92f8b1 (diff) |
Port OS X backend to plugin infrastructure
Change-Id: I15d19782c7c18f9b02b46e35fb5e527c3fd72ccc
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@theqtcompany.com>
-rw-r--r-- | src/plugins/tts/osx/osx.pro | 25 | ||||
-rw-r--r-- | src/plugins/tts/osx/osx_plugin.json | 6 | ||||
-rw-r--r-- | src/plugins/tts/osx/qtexttospeech_osx.h | 99 | ||||
-rw-r--r-- | src/plugins/tts/osx/qtexttospeech_osx.mm (renamed from src/tts/qtexttospeech_mac.mm) | 169 | ||||
-rw-r--r-- | src/plugins/tts/osx/qtexttospeech_osx_plugin.cpp | 44 | ||||
-rw-r--r-- | src/plugins/tts/osx/qtexttospeech_osx_plugin.h | 63 | ||||
-rw-r--r-- | src/plugins/tts/tts.pro | 2 |
7 files changed, 296 insertions, 112 deletions
diff --git a/src/plugins/tts/osx/osx.pro b/src/plugins/tts/osx/osx.pro new file mode 100644 index 0000000..4eb42e8 --- /dev/null +++ b/src/plugins/tts/osx/osx.pro @@ -0,0 +1,25 @@ +TARGET = qtexttospeech_speechosx +PLUGIN_TYPE = texttospeech +PLUGIN_CLASS_NAME = QTextToSpeechPluginOsx + +load(qt_plugin) + +QT += core texttospeech + +LIBS += -framework Cocoa + +HEADERS += \ + qtexttospeech_osx_plugin.h \ + qtexttospeech_osx.h \ + +OBJECTIVE_HEADERS += \ + qtexttospeech_osx.h \ + +SOURCES += \ + qtexttospeech_osx_plugin.cpp \ + +OBJECTIVE_SOURCES += \ + qtexttospeech_osx.mm \ + +OTHER_FILES += \ + osx_plugin.json diff --git a/src/plugins/tts/osx/osx_plugin.json b/src/plugins/tts/osx/osx_plugin.json new file mode 100644 index 0000000..5b039f3 --- /dev/null +++ b/src/plugins/tts/osx/osx_plugin.json @@ -0,0 +1,6 @@ +{ + "Keys": ["osx"], + "Provider": "osx", + "Version": 100, + "Features": [] +} diff --git a/src/plugins/tts/osx/qtexttospeech_osx.h b/src/plugins/tts/osx/qtexttospeech_osx.h new file mode 100644 index 0000000..70de317 --- /dev/null +++ b/src/plugins/tts/osx/qtexttospeech_osx.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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_OSX_H +#define QTEXTTOSPEECHENGINE_OSX_H + +#include <QtCore/qobject.h> +#include <QtCore/qvector.h> +#include <QtCore/qstring.h> +#include <QtCore/qlocale.h> +#include <QtTextToSpeech/qtexttospeechengine.h> +#include <QtTextToSpeech/qvoice.h> + +Q_FORWARD_DECLARE_OBJC_CLASS(StateDelegate); +Q_FORWARD_DECLARE_OBJC_CLASS(NSSpeechSynthesizer); +Q_FORWARD_DECLARE_OBJC_CLASS(NSString); + +QT_BEGIN_NAMESPACE + +class QTextToSpeechEngineOsx : public QTextToSpeechEngine +{ + Q_OBJECT + +public: + QTextToSpeechEngineOsx(const QVariantMap ¶meters, QObject *parent); + ~QTextToSpeechEngineOsx(); + + // 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; + + void speechStopped(bool); + +private: + void updateVoices(); + bool isSpeaking() const; + bool isPaused() const; + + QTextToSpeech::State m_state; +// QVoice m_currentVoice; + + QVoice voiceForNSVoice(NSString *voiceString) const; + NSSpeechSynthesizer *speechSynthesizer; + StateDelegate *stateDelegate; + QVector<QLocale> m_locales; + QMultiMap<QString, QVoice> m_voices; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/tts/qtexttospeech_mac.mm b/src/plugins/tts/osx/qtexttospeech_osx.mm index 886676a..20b6ce2 100644 --- a/src/tts/qtexttospeech_mac.mm +++ b/src/plugins/tts/osx/qtexttospeech_osx.mm @@ -34,66 +34,23 @@ ** ****************************************************************************/ - - -#include "qtexttospeech.h" -#include "qtexttospeech_p.h" - -#import <Cocoa/Cocoa.h> +#include <Cocoa/Cocoa.h> +#include "qtexttospeech_osx.h" #include <qdebug.h> - QT_BEGIN_NAMESPACE -class QTextToSpeechPrivateMac; +class QTextToSpeechEngineOsx; + @interface StateDelegate : NSObject <NSSpeechSynthesizerDelegate> { - QTextToSpeechPrivateMac *speechPrivate; + QTextToSpeechEngineOsx *speechPrivate; } @end -class QTextToSpeechPrivateMac : public QTextToSpeechPrivate -{ -public: - QTextToSpeechPrivateMac(QTextToSpeech *speech); - ~QTextToSpeechPrivateMac(); - - 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; - void setRate(double rate) Q_DECL_OVERRIDE; - double pitch() const Q_DECL_OVERRIDE; - void setPitch(double pitch) Q_DECL_OVERRIDE; - int volume() const Q_DECL_OVERRIDE; - void setVolume(int volume) Q_DECL_OVERRIDE; - void setLocale(const QLocale &locale) Q_DECL_OVERRIDE; - QLocale locale() const Q_DECL_OVERRIDE; - void setVoice(const QVoice &voice) Q_DECL_OVERRIDE; - QVoice voice() const Q_DECL_OVERRIDE; - QTextToSpeech::State state() const Q_DECL_OVERRIDE; - - bool isPaused() const; - bool isSpeaking() const; - - void speechStopped(bool success); - -private: - void updateVoices(); - QVoice voiceForNSVoice(NSString *voiceString) const; - NSSpeechSynthesizer *speechSynthesizer; - StateDelegate *stateDelegate; - QVector<QLocale> m_locales; - QMultiMap<QString, QVoice> m_voices; -}; - @implementation StateDelegate -- (id)initWithSpeechPrivate:(QTextToSpeechPrivateMac *) priv { +- (id)initWithSpeechPrivate:(QTextToSpeechEngineOsx *) priv { self = [super init]; speechPrivate = priv; return self; @@ -102,17 +59,11 @@ private: Q_UNUSED(sender); speechPrivate->speechStopped(success); } - @end -QTextToSpeech::QTextToSpeech(QObject *parent) - : QObject(*new QTextToSpeechPrivateMac(this), parent) -{ - qRegisterMetaType<QTextToSpeech::State>(); -} -QTextToSpeechPrivateMac::QTextToSpeechPrivateMac(QTextToSpeech *speech) - : QTextToSpeechPrivate(speech) +QTextToSpeechEngineOsx::QTextToSpeechEngineOsx(const QVariantMap &/*parameters*/, QObject *parent) + : QTextToSpeechEngine(parent), m_state(QTextToSpeech::Ready) { stateDelegate = [[StateDelegate alloc] initWithSpeechPrivate:this]; @@ -121,33 +72,33 @@ QTextToSpeechPrivateMac::QTextToSpeechPrivateMac(QTextToSpeech *speech) updateVoices(); } -QTextToSpeechPrivateMac::~QTextToSpeechPrivateMac() +QTextToSpeechEngineOsx::~QTextToSpeechEngineOsx() { [speechSynthesizer release]; [stateDelegate release]; } -QTextToSpeech::State QTextToSpeechPrivate::state() const +QTextToSpeech::State QTextToSpeechEngineOsx::state() const { return m_state; } -bool QTextToSpeechPrivateMac::isSpeaking() const +bool QTextToSpeechEngineOsx::isSpeaking() const { return [speechSynthesizer isSpeaking]; } -void QTextToSpeechPrivateMac::speechStopped(bool success) +void QTextToSpeechEngineOsx::speechStopped(bool success) { Q_UNUSED(success); if (m_state != QTextToSpeech::Ready) { m_state = QTextToSpeech::Ready; - emitStateChanged(m_state); + emit stateChanged(m_state); } } -void QTextToSpeechPrivateMac::say(const QString &text) +void QTextToSpeechEngineOsx::say(const QString &text) { if (text.isEmpty()) return; @@ -164,70 +115,73 @@ void QTextToSpeechPrivateMac::say(const QString &text) if (m_state != QTextToSpeech::Speaking) { m_state = QTextToSpeech::Speaking; - emitStateChanged(m_state); + emit stateChanged(m_state); } } -void QTextToSpeechPrivateMac::stop() +void QTextToSpeechEngineOsx::stop() { if([speechSynthesizer isSpeaking]) [speechSynthesizer stopSpeaking]; } -void QTextToSpeechPrivateMac::pause() +void QTextToSpeechEngineOsx::pause() { if ([speechSynthesizer isSpeaking]) { [speechSynthesizer pauseSpeakingAtBoundary: NSSpeechWordBoundary]; m_state = QTextToSpeech::Paused; - emitStateChanged(m_state); + emit stateChanged(m_state); } } -bool QTextToSpeechPrivateMac::isPaused() const +bool QTextToSpeechEngineOsx::isPaused() const { return m_state == QTextToSpeech::Paused; } -void QTextToSpeechPrivateMac::resume() +void QTextToSpeechEngineOsx::resume() { m_state = QTextToSpeech::Speaking; - emitStateChanged(m_state); + emit stateChanged(m_state); [speechSynthesizer continueSpeaking]; } -double QTextToSpeechPrivateMac::rate() const +double QTextToSpeechEngineOsx::rate() const { return ([speechSynthesizer rate] - 200) / 200.0; } -void QTextToSpeechPrivateMac::setPitch(double pitch) +bool QTextToSpeechEngineOsx::setPitch(double pitch) { // 30 to 65 double p = 30.0 + ((pitch + 1.0) / 2.0) * 35.0; [speechSynthesizer setObject:[NSNumber numberWithFloat:p] forProperty:NSSpeechPitchBaseProperty error:nil]; + return true; } -double QTextToSpeechPrivateMac::pitch() const +double QTextToSpeechEngineOsx::pitch() const { double pitch = [[speechSynthesizer objectForProperty:NSSpeechPitchBaseProperty error:nil] floatValue]; return (pitch - 30.0) / 35.0 * 2.0 - 1.0; } -int QTextToSpeechPrivateMac::volume() const +int QTextToSpeechEngineOsx::volume() const { return [speechSynthesizer volume] * 100; } -void QTextToSpeechPrivateMac::setRate(double rate) +bool QTextToSpeechEngineOsx::setRate(double rate) { // NSSpeechSynthesizer supports words per minute, // human speech is 180 to 220 - use 0 to 400 as range here [speechSynthesizer setRate: 200 + (rate * 200)]; + return true; } -void QTextToSpeechPrivateMac::setVolume(int volume) +bool QTextToSpeechEngineOsx::setVolume(int volume) { [speechSynthesizer setVolume: volume / 100.0]; + return true; } QLocale localeForVoice(NSString *voice) @@ -236,66 +190,59 @@ QLocale localeForVoice(NSString *voice) return QString::fromNSString(attrs[NSVoiceLocaleIdentifier]); } -QVoice QTextToSpeechPrivateMac::voiceForNSVoice(NSString *voiceString) const +QVoice QTextToSpeechEngineOsx::voiceForNSVoice(NSString *voiceString) const { NSDictionary *attrs = [NSSpeechSynthesizer attributesForVoice:voiceString]; - QVoice voice; QString voiceName = QString::fromNSString(attrs[NSVoiceName]); - voice.setName(voiceName); - NSString *gender = attrs[NSVoiceGender]; - voice.setGender([gender isEqualToString:NSVoiceGenderMale] ? QVoice::Male : - [gender isEqualToString:NSVoiceGenderFemale] ? QVoice::Female : - QVoice::Unknown); - NSNumber *age = attrs[NSVoiceAge]; - int ageInt = age.intValue; - voice.setAge(ageInt < 13 ? QVoice::Child : - ageInt < 20 ? QVoice::Teenager : - ageInt < 45 ? QVoice::Adult : - ageInt < 90 ? QVoice::Senior : QVoice::Other); - voice.setData(QVariant(QString::fromNSString(attrs[NSVoiceIdentifier]))); + + NSString *genderString = attrs[NSVoiceGender]; + QVoice::Gender gender = [genderString isEqualToString:NSVoiceGenderMale] ? QVoice::Male : + [genderString isEqualToString:NSVoiceGenderFemale] ? QVoice::Female : + QVoice::Unknown; + + NSNumber *ageNSNumber = attrs[NSVoiceAge]; + int ageInt = ageNSNumber.intValue; + QVoice::Age age = (ageInt < 13 ? QVoice::Child : + ageInt < 20 ? QVoice::Teenager : + ageInt < 45 ? QVoice::Adult : + ageInt < 90 ? QVoice::Senior : QVoice::Other); + QVariant data = QString::fromNSString(attrs[NSVoiceIdentifier]); + QVoice voice = createVoice(voiceName, gender, age, data); return voice; } -QVector<QLocale> QTextToSpeechPrivateMac::availableLocales() const +QVector<QLocale> QTextToSpeechEngineOsx::availableLocales() const { return m_locales; } -void QTextToSpeechPrivateMac::setLocale(const QLocale &locale) +bool QTextToSpeechEngineOsx::setLocale(const QLocale &locale) { NSArray *voices = [NSSpeechSynthesizer availableVoices]; NSString *voice = [NSSpeechSynthesizer defaultVoice]; // always prefer default if (locale == localeForVoice(voice)) { [speechSynthesizer setVoice:voice]; - emitLocaleChanged(locale); - emitVoiceChanged(voiceForNSVoice(voice)); - return; + return true; } for (voice in voices) { QLocale voiceLocale = localeForVoice(voice); if (locale == voiceLocale) { [speechSynthesizer setVoice:voice]; - emitLocaleChanged(locale); - emitVoiceChanged(voiceForNSVoice(voice)); - return; + return true; } } + return false; } -QLocale QTextToSpeechPrivateMac::locale() const +QLocale QTextToSpeechEngineOsx::locale() const { NSString *voice = [speechSynthesizer voice]; return localeForVoice(voice); } -QTextToSpeech::State QTextToSpeechPrivateMac::state() const -{ - return m_state; -} - -void QTextToSpeechPrivateMac::updateVoices() +void QTextToSpeechEngineOsx::updateVoices() { NSArray *voices = [NSSpeechSynthesizer availableVoices]; for (NSString *voice in voices) { @@ -307,21 +254,19 @@ void QTextToSpeechPrivateMac::updateVoices() } } -QVector<QVoice> QTextToSpeechPrivateMac::availableVoices() const +QVector<QVoice> QTextToSpeechEngineOsx::availableVoices() const { return m_voices.values(locale().name()).toVector(); } -void QTextToSpeechPrivateMac::setVoice(const QVoice &voice) +bool QTextToSpeechEngineOsx::setVoice(const QVoice &voice) { - NSString *identifier = voice.data().toString().toNSString(); + NSString *identifier = voiceData(voice).toString().toNSString(); [speechSynthesizer setVoice:identifier]; - QLocale newLocale = localeForVoice(identifier); - emitLocaleChanged(newLocale); - emitVoiceChanged(voice); + return true; } -QVoice QTextToSpeechPrivateMac::voice() const +QVoice QTextToSpeechEngineOsx::voice() const { NSString *voice = [speechSynthesizer voice]; return voiceForNSVoice(voice); diff --git a/src/plugins/tts/osx/qtexttospeech_osx_plugin.cpp b/src/plugins/tts/osx/qtexttospeech_osx_plugin.cpp new file mode 100644 index 0000000..3dbac52 --- /dev/null +++ b/src/plugins/tts/osx/qtexttospeech_osx_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_osx_plugin.h" +#include "qtexttospeech_osx.h" + +QTextToSpeechEngine *QTextToSpeechPluginOsx::createTextToSpeechEngine(const QVariantMap ¶meters, QObject *parent, QString *errorString) const +{ + Q_UNUSED(errorString) + return new QTextToSpeechEngineOsx(parameters, parent); +} diff --git a/src/plugins/tts/osx/qtexttospeech_osx_plugin.h b/src/plugins/tts/osx/qtexttospeech_osx_plugin.h new file mode 100644 index 0000000..36cdb3a --- /dev/null +++ b/src/plugins/tts/osx/qtexttospeech_osx_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_OSX_H +#define QTEXTTOSPEECHPLUGIN_OSX_H + +#include <QtCore/QObject> +#include <QtCore/QLoggingCategory> +#include <QtTextToSpeech/qtexttospeechplugin.h> +#include <QtTextToSpeech/qtexttospeechengine.h> + +QT_BEGIN_NAMESPACE + +class QTextToSpeechPluginOsx : public QObject, public QTextToSpeechPlugin +{ + Q_OBJECT + Q_INTERFACES(QTextToSpeechPlugin) + Q_PLUGIN_METADATA(IID "org.qt-project.qt.speech.tts.plugin/5.0" + FILE "osx_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 08adb5f..4f1e5ae 100644 --- a/src/plugins/tts/tts.pro +++ b/src/plugins/tts/tts.pro @@ -11,6 +11,8 @@ unix { # until those are written, disable the sapi plugin for mingw windows: !mingw: SUBDIRS += sapi +osx: SUBDIRS += osx + config_flite { SUBDIRS += flite } |