summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2023-05-24 16:20:12 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2023-05-28 13:08:27 +0000
commit6bb360c464fa0a5fe571afab21b9edd3e863f630 (patch)
treea435deb8cd3105f3d0b719b5eadacdaea01f020a
parentc1afe1600d37c5533904da7e2862e87fa05464e6 (diff)
API review: Allow synthesize callbacks that take a QAudioBuffer
Formally, QAudioBuffer is the right type for carrying audio data, but it's hardly used in Qt Multimedia itself, and not very practical to use for writing the received PCM data to a file or to stream it out to a QAudioSink (which operators on a QIODevice, e.g. with a byte array). Nevertheless, allow a callback to take a QAudioBuffer instead of QAudioFormat and QByteArray, as the QAudioBuffer facilities might be useful for some use cases. Change-Id: I260a4cf6cf91f57356373f4ef9cf248927159b40 Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
-rw-r--r--src/tts/qtexttospeech.cpp26
-rw-r--r--src/tts/qtexttospeech.h29
-rw-r--r--tests/auto/qtexttospeech/tst_qtexttospeech.cpp11
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)