diff options
Diffstat (limited to 'src/plugins/tts/osx')
-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 | 271 | ||||
-rw-r--r-- | src/plugins/tts/osx/qtexttospeech_osx_plugin.cpp | 44 | ||||
-rw-r--r-- | src/plugins/tts/osx/qtexttospeech_osx_plugin.h | 63 |
6 files changed, 508 insertions, 0 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..4739326 --- /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(QT_MANGLE_NAMESPACE(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; + QT_MANGLE_NAMESPACE(StateDelegate) *stateDelegate; + QVector<QLocale> m_locales; + QMultiMap<QString, QVoice> m_voices; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/tts/osx/qtexttospeech_osx.mm b/src/plugins/tts/osx/qtexttospeech_osx.mm new file mode 100644 index 0000000..9092144 --- /dev/null +++ b/src/plugins/tts/osx/qtexttospeech_osx.mm @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** 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 <Cocoa/Cocoa.h> +#include "qtexttospeech_osx.h" +#include <qdebug.h> + +@interface QT_MANGLE_NAMESPACE(StateDelegate) : NSObject <NSSpeechSynthesizerDelegate> +{ + QT_PREPEND_NAMESPACE(QTextToSpeechEngineOsx) *speechPrivate; +} +@end + +@implementation QT_MANGLE_NAMESPACE(StateDelegate) +- (id)initWithSpeechPrivate:(QTextToSpeechEngineOsx *) priv { + self = [super init]; + speechPrivate = priv; + return self; +} +- (void)speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)success { + Q_UNUSED(sender); + speechPrivate->speechStopped(success); +} +@end + +QT_BEGIN_NAMESPACE + +QTextToSpeechEngineOsx::QTextToSpeechEngineOsx(const QVariantMap &/*parameters*/, QObject *parent) + : QTextToSpeechEngine(parent), m_state(QTextToSpeech::Ready) +{ + stateDelegate = [[QT_MANGLE_NAMESPACE(StateDelegate) alloc] initWithSpeechPrivate:this]; + + speechSynthesizer = [[NSSpeechSynthesizer alloc] init]; + [speechSynthesizer setDelegate: stateDelegate]; + updateVoices(); +} + +QTextToSpeechEngineOsx::~QTextToSpeechEngineOsx() +{ + [speechSynthesizer release]; + [stateDelegate release]; +} + + +QTextToSpeech::State QTextToSpeechEngineOsx::state() const +{ + return m_state; +} + +bool QTextToSpeechEngineOsx::isSpeaking() const +{ + return [speechSynthesizer isSpeaking]; +} + +void QTextToSpeechEngineOsx::speechStopped(bool success) +{ + Q_UNUSED(success); + if (m_state != QTextToSpeech::Ready) { + m_state = QTextToSpeech::Ready; + emit stateChanged(m_state); + } +} + +void QTextToSpeechEngineOsx::say(const QString &text) +{ + if (text.isEmpty()) + return; + + if (m_state != QTextToSpeech::Ready) + stop(); + + if([speechSynthesizer isSpeaking]) { + [speechSynthesizer stopSpeaking]; + } + + NSString *ntext = text.toNSString(); + [speechSynthesizer startSpeakingString:ntext]; + + if (m_state != QTextToSpeech::Speaking) { + m_state = QTextToSpeech::Speaking; + emit stateChanged(m_state); + } +} + +void QTextToSpeechEngineOsx::stop() +{ + if([speechSynthesizer isSpeaking]) + [speechSynthesizer stopSpeaking]; +} + +void QTextToSpeechEngineOsx::pause() +{ + if ([speechSynthesizer isSpeaking]) { + [speechSynthesizer pauseSpeakingAtBoundary: NSSpeechWordBoundary]; + m_state = QTextToSpeech::Paused; + emit stateChanged(m_state); + } +} + +bool QTextToSpeechEngineOsx::isPaused() const +{ + return m_state == QTextToSpeech::Paused; +} + +void QTextToSpeechEngineOsx::resume() +{ + m_state = QTextToSpeech::Speaking; + emit stateChanged(m_state); + [speechSynthesizer continueSpeaking]; +} + +double QTextToSpeechEngineOsx::rate() const +{ + return ([speechSynthesizer rate] - 200) / 200.0; +} + +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 QTextToSpeechEngineOsx::pitch() const +{ + double pitch = [[speechSynthesizer objectForProperty:NSSpeechPitchBaseProperty error:nil] floatValue]; + return (pitch - 30.0) / 35.0 * 2.0 - 1.0; +} + +int QTextToSpeechEngineOsx::volume() const +{ + return [speechSynthesizer volume] * 100; +} + +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; +} + +bool QTextToSpeechEngineOsx::setVolume(int volume) +{ + [speechSynthesizer setVolume: volume / 100.0]; + return true; +} + +QLocale localeForVoice(NSString *voice) +{ + NSDictionary *attrs = [NSSpeechSynthesizer attributesForVoice:voice]; + return QString::fromNSString(attrs[NSVoiceLocaleIdentifier]); +} + +QVoice QTextToSpeechEngineOsx::voiceForNSVoice(NSString *voiceString) const +{ + NSDictionary *attrs = [NSSpeechSynthesizer attributesForVoice:voiceString]; + QString voiceName = QString::fromNSString(attrs[NSVoiceName]); + + 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> QTextToSpeechEngineOsx::availableLocales() const +{ + return m_locales; +} + +bool QTextToSpeechEngineOsx::setLocale(const QLocale &locale) +{ + NSArray *voices = [NSSpeechSynthesizer availableVoices]; + NSString *voice = [NSSpeechSynthesizer defaultVoice]; + // always prefer default + if (locale == localeForVoice(voice)) { + [speechSynthesizer setVoice:voice]; + return true; + } + + for (voice in voices) { + QLocale voiceLocale = localeForVoice(voice); + if (locale == voiceLocale) { + [speechSynthesizer setVoice:voice]; + return true; + } + } + return false; +} + +QLocale QTextToSpeechEngineOsx::locale() const +{ + NSString *voice = [speechSynthesizer voice]; + return localeForVoice(voice); +} + +void QTextToSpeechEngineOsx::updateVoices() +{ + NSArray *voices = [NSSpeechSynthesizer availableVoices]; + for (NSString *voice in voices) { + QLocale locale = localeForVoice(voice); + QVoice data = voiceForNSVoice(voice); + if (!m_locales.contains(locale)) + m_locales.append(locale); + m_voices.insert(locale.name(), data); + } +} + +QVector<QVoice> QTextToSpeechEngineOsx::availableVoices() const +{ + return m_voices.values(locale().name()).toVector(); +} + +bool QTextToSpeechEngineOsx::setVoice(const QVoice &voice) +{ + NSString *identifier = voiceData(voice).toString().toNSString(); + [speechSynthesizer setVoice:identifier]; + return true; +} + +QVoice QTextToSpeechEngineOsx::voice() const +{ + NSString *voice = [speechSynthesizer voice]; + return voiceForNSVoice(voice); +} + +QT_END_NAMESPACE 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 |