diff options
-rw-r--r-- | src/tts/qtexttospeech.cpp | 26 | ||||
-rw-r--r-- | src/tts/qtexttospeech.h | 29 | ||||
-rw-r--r-- | tests/auto/qtexttospeech/tst_qtexttospeech.cpp | 11 |
3 files changed, 55 insertions, 11 deletions
diff --git a/src/tts/qtexttospeech.cpp b/src/tts/qtexttospeech.cpp index 47cad9c..bcebc46 100644 --- a/src/tts/qtexttospeech.cpp +++ b/src/tts/qtexttospeech.cpp @@ -9,6 +9,8 @@ #include <QtCore/qdebug.h> #include <QtCore/private/qfactoryloader_p.h> +#include <QtMultimedia/qaudiobuffer.h> + QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; @@ -877,8 +879,9 @@ void QTextToSpeech::synthesize(const QString &text) This function synthesizes the speech asynchronously into raw audio data. When data is available, the \a functor will be called as - \c {functor(const QAudioFormat &format, const QByteArray &bytes)}, with - \c format describing the \l {QAudioFormat}{format} of the data in \c bytes. + \c {functor(QAudioFormat format, QByteArray bytes)}, with \c format + describing the \l {QAudioFormat}{format} of the data in \c bytes; + or as \c {functor(QAudioBuffer &buffer)}. The \l state property is set to \l Synthesizing when the synthesis starts, and to \l Ready once the synthesis is finished. While synthesizing, the @@ -923,19 +926,26 @@ void QTextToSpeech::synthesize(const QString &text) in updateState() when the state of the engine transitions back to Ready. */ void QTextToSpeech::synthesizeImpl(const QString &text, - QtPrivate::QSlotObjectBase *slotObj, const QObject *context) + QtPrivate::QSlotObjectBase *slotObj, const QObject *context, + SynthesizeOverload overload) { Q_D(QTextToSpeech); Q_ASSERT(slotObj); if (d->m_slotObject) d->m_slotObject->destroyIfLastRef(); d->m_slotObject = slotObj; - const auto receive = [d, context](const QAudioFormat &format, const QByteArray &bytes){ + const auto receive = [d, context, overload](const QAudioFormat &format, const QByteArray &bytes){ Q_ASSERT(d->m_slotObject); - void *args[] = {nullptr, - const_cast<QAudioFormat *>(&format), - const_cast<QByteArray *>(&bytes)}; - d->m_slotObject->call(const_cast<QObject *>(context), args); + if (overload == SynthesizeOverload::AudioBuffer) { + const QAudioBuffer buffer(bytes, format); + void *args[] = {nullptr, const_cast<QAudioBuffer *>(&buffer)}; + d->m_slotObject->call(const_cast<QObject *>(context), args); + } else { + void *args[] = {nullptr, + const_cast<QAudioFormat *>(&format), + const_cast<QByteArray *>(&bytes)}; + d->m_slotObject->call(const_cast<QObject *>(context), args); + } }; d->m_synthesizeConnection = connect(d->m_engine.get(), &QTextToSpeechEngine::synthesized, context ? context : this, receive); diff --git a/src/tts/qtexttospeech.h b/src/tts/qtexttospeech.h index 2b3951b..6792cf6 100644 --- a/src/tts/qtexttospeech.h +++ b/src/tts/qtexttospeech.h @@ -17,6 +17,7 @@ QT_BEGIN_NAMESPACE class QAudioFormat; +class QAudioBuffer; class QTextToSpeechPrivate; class Q_TEXTTOSPEECH_EXPORT QTextToSpeech : public QObject @@ -105,8 +106,19 @@ public: # endif // Q_QDOC Functor &&func) { - using Prototype = void(*)(QAudioFormat, QByteArray); - synthesizeImpl(text, QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(func)), receiver); + using Prototype2 = void(*)(QAudioFormat, QByteArray); + using Prototype1 = void(*)(QAudioBuffer); + if constexpr (qxp::is_detected_v<CompatibleCallbackTest2, Functor>) { + synthesizeImpl(text, QtPrivate::makeCallableObject<Prototype2>(std::forward<Functor>(func)), + receiver, SynthesizeOverload::AudioFormatByteArray); + } else if constexpr (qxp::is_detected_v<CompatibleCallbackTest1, Functor>) { + synthesizeImpl(text, QtPrivate::makeCallableObject<Prototype1>(std::forward<Functor>(func)), + receiver, SynthesizeOverload::AudioBuffer); + } else { + static_assert(QtPrivate::type_dependent_false<Functor>(), + "Incompatible functor signature, must be either " + "(QAudioFormat, QByteArray) or (QAudioBuffer)!"); + } } // synthesize to a functor or function pointer (without context) @@ -167,8 +179,19 @@ protected: QList<QVoice> allVoices(const QLocale *locale) const; private: + template <typename Functor> + using CompatibleCallbackTest2 = decltype(QtPrivate::makeCallableObject<void(*)(QAudioFormat, QByteArray)>(std::declval<Functor>())); + template <typename Functor> + using CompatibleCallbackTest1 = decltype(QtPrivate::makeCallableObject<void(*)(QAudioBuffer)>(std::declval<Functor>())); + + enum class SynthesizeOverload { + AudioFormatByteArray, + AudioBuffer + }; + void synthesizeImpl(const QString &text, - QtPrivate::QSlotObjectBase *slotObj, const QObject *context); + QtPrivate::QSlotObjectBase *slotObj, const QObject *context, + SynthesizeOverload overload); // Helper type to find the index of a type in a tuple, which allows // us to generate a compile-time error if there are multiple criteria diff --git a/tests/auto/qtexttospeech/tst_qtexttospeech.cpp b/tests/auto/qtexttospeech/tst_qtexttospeech.cpp index 701effe..317c683 100644 --- a/tests/auto/qtexttospeech/tst_qtexttospeech.cpp +++ b/tests/auto/qtexttospeech/tst_qtexttospeech.cpp @@ -8,6 +8,7 @@ #include <QMediaDevices> #include <QAudioFormat> #include <QAudioDevice> +#include <QAudioBuffer> #include <QOperatingSystemVersion> #include <QRegularExpression> #include <qttexttospeech-config.h> @@ -1063,6 +1064,16 @@ void tst_QTextToSpeech::synthesizeCallback() QTRY_COMPARE(tts.state(), QTextToSpeech::Ready); QCOMPARE(processor.m_allBytes, QByteArray()); processor.reset(); + + // Taking QAudioBuffer + tts.synthesize(text, [&processor](const QAudioBuffer &buffer) { + processor.m_format = buffer.format(); + processor.m_allBytes += QByteArrayView(buffer.data<uchar>(), buffer.byteCount()); + }); + QTRY_COMPARE(processor.m_format, expectedFormat); + QTRY_COMPARE(tts.state(), QTextToSpeech::Ready); + QCOMPARE(processor.m_allBytes, expectedBytes); + processor.reset(); } QTEST_MAIN(tst_QTextToSpeech) |