summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@qt.io>2016-05-13 17:13:03 +0200
committerYoann Lopes <yoann.lopes@qt.io>2016-06-03 21:11:58 +0000
commitfe46759fc0a39418a3b5f32cf78a162c35a7aef7 (patch)
treeb043309dc6ee6a3de2b7477113125adda6ae1911 /src
parent78a73643a31a761ada8cfafa80ddf2fb916c1d6a (diff)
Add new volume conversion API.
All Qt Multimedia volume APIs expect a linear volume factor. However, UI volume controls should typically use a logarithmic or cubic scale to match how the human ear perceives loudness. The new helper function (C++ and QML) provides a way to do the conversion from one scale to another. Change-Id: If7795426b728ab0e8fd6635988dbc9be795e3e5e Reviewed-by: Christian Stromme <christian.stromme@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/imports/multimedia/qdeclarativemultimediaglobal.cpp51
-rw-r--r--src/imports/multimedia/qdeclarativemultimediaglobal_p.h11
-rw-r--r--src/multimedia/audio/qaudio.cpp113
-rw-r--r--src/multimedia/audio/qaudio.h10
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/audio.cpp16
5 files changed, 201 insertions, 0 deletions
diff --git a/src/imports/multimedia/qdeclarativemultimediaglobal.cpp b/src/imports/multimedia/qdeclarativemultimediaglobal.cpp
index b2a1aed12..bb1b9c9d8 100644
--- a/src/imports/multimedia/qdeclarativemultimediaglobal.cpp
+++ b/src/imports/multimedia/qdeclarativemultimediaglobal.cpp
@@ -183,4 +183,55 @@ QJSValue QDeclarativeMultimediaGlobal::availableCameras() const
return availableCameras;
}
+/*!
+ \qmlmethod real QtMultimedia::QtMultimedia::convertVolume(real volume, VolumeScale from, VolumeScale to)
+
+ Converts an audio \a volume \a from a volume scale \a to another, and returns the result.
+
+ Depending on the context, different scales are used to represent audio volume. All Qt Multimedia
+ classes that have an audio volume use a linear scale, the reason is that the loudness of a
+ speaker is controlled by modulating its voltage on a linear scale. The human ear on the other
+ hand, perceives loudness in a logarithmic way. That is why the decibel scale, being a logarithmic
+ scale, is typically used to define sound levels. UI volume controls in professional audio
+ applications usually use a decibel scale. The cubic scale is a computationally cheap
+ approximation of a logarithmic scale, most applications should use a cubic scale for their UI
+ volume controls.
+
+ Valid values for \a from and \a to are:
+ \list
+ \li QtMultimedia.LinearVolumeScale - Linear scale. \c 0.0 (0%) is silence and \c 1.0 (100%) is
+ full volume. All Qt Multimedia types that have an audio volume use a linear scale.
+ \li QtMultimedia.CubicVolumeScale - Cubic scale. \c 0.0 (0%) is silence and \c 1.0 (100%) is full
+ volume. UI volume controls should usually use a cubic scale.
+ \li QtMultimedia.DecibelVolumeScale - Decibel (dB, amplitude) logarithmic scale. \c -200 is
+ silence and \c 0 is full volume.
+ \endlist
+
+ The following example shows how the volume value from a UI volume control can be converted so
+ that the perceived increase in loudness is the same when increasing the volume control from 0.2
+ to 0.3 as it is from 0.5 to 0.6:
+
+ \code
+ Slider {
+ id: volumeSlider
+
+ property real volume: QtMultimedia.convertVolume(volumeSlider.value,
+ QtMultimedia.CubicVolumeScale,
+ QtMultimedia.LinearVolumeScale)
+ }
+
+ MediaPlayer {
+ volume: volumeSlider.volume
+ }
+ \endcode
+
+ \since 5.8
+*/
+qreal QDeclarativeMultimediaGlobal::convertVolume(qreal volume,
+ QDeclarativeMultimediaGlobal::VolumeScale from,
+ QDeclarativeMultimediaGlobal::VolumeScale to) const
+{
+ return QAudio::convertVolume(volume, QAudio::VolumeScale(from), QAudio::VolumeScale(to));
+}
+
QT_END_NAMESPACE
diff --git a/src/imports/multimedia/qdeclarativemultimediaglobal_p.h b/src/imports/multimedia/qdeclarativemultimediaglobal_p.h
index 2374b560c..a8413cc09 100644
--- a/src/imports/multimedia/qdeclarativemultimediaglobal_p.h
+++ b/src/imports/multimedia/qdeclarativemultimediaglobal_p.h
@@ -53,6 +53,7 @@
#include <QtQml/qqml.h>
#include <QtQml/qjsvalue.h>
+#include <QtMultimedia/qaudio.h>
QT_BEGIN_NAMESPACE
@@ -63,12 +64,22 @@ class QDeclarativeMultimediaGlobal : public QObject
Q_PROPERTY(QJSValue defaultCamera READ defaultCamera NOTIFY defaultCameraChanged)
Q_PROPERTY(QJSValue availableCameras READ availableCameras NOTIFY availableCamerasChanged)
+ Q_ENUMS(VolumeScale)
+
public:
+ enum VolumeScale {
+ LinearVolumeScale = QAudio::LinearVolumeScale,
+ CubicVolumeScale = QAudio::CubicVolumeScale,
+ DecibelVolumeScale = QAudio::DecibelVolumeScale
+ };
+
explicit QDeclarativeMultimediaGlobal(QJSEngine *engine, QObject *parent = 0);
QJSValue defaultCamera() const;
QJSValue availableCameras() const;
+ Q_INVOKABLE qreal convertVolume(qreal volume, VolumeScale from, VolumeScale to) const;
+
Q_SIGNALS:
// Unused at the moment. QCameraInfo doesn't notify when cameras are added or removed,
// but it might change in the future.
diff --git a/src/multimedia/audio/qaudio.cpp b/src/multimedia/audio/qaudio.cpp
index c708fa4f8..426c984df 100644
--- a/src/multimedia/audio/qaudio.cpp
+++ b/src/multimedia/audio/qaudio.cpp
@@ -39,6 +39,7 @@
#include <qaudio.h>
+#include <qmath.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -49,6 +50,7 @@ static void qRegisterAudioMetaTypes()
qRegisterMetaType<QAudio::State>();
qRegisterMetaType<QAudio::Mode>();
qRegisterMetaType<QAudio::Role>();
+ qRegisterMetaType<QAudio::VolumeScale>();
}
Q_CONSTRUCTOR_FUNCTION(qRegisterAudioMetaTypes)
@@ -111,6 +113,98 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterAudioMetaTypes)
\sa QMediaPlayer::setAudioRole()
*/
+/*!
+ \enum QAudio::VolumeScale
+
+ This enum defines the different audio volume scales.
+
+ \value LinearVolumeScale Linear scale. \c 0.0 (0%) is silence and \c 1.0 (100%) is full
+ volume. All Qt Multimedia classes that have an audio volume use a
+ linear scale.
+ \value CubicVolumeScale Cubic scale. \c 0.0 (0%) is silence and \c 1.0 (100%) is full
+ volume. UI volume controls should usually use a cubic scale.
+ \value DecibelVolumeScale Decibel (dB, amplitude) logarithmic scale. \c -200 is silence and
+ \c 0 is full volume.
+
+ \since 5.8
+ \sa QAudio::convertVolume()
+*/
+
+namespace QAudio
+{
+
+/*!
+ \fn qreal QAudio::convertVolume(qreal volume, VolumeScale from, VolumeScale to)
+
+ Converts an audio \a volume \a from a volume scale \a to another, and returns the result.
+
+ Depending on the context, different scales are used to represent audio volume. All Qt Multimedia
+ classes that have an audio volume use a linear scale, the reason is that the loudness of a
+ speaker is controlled by modulating its voltage on a linear scale. The human ear on the other
+ hand, perceives loudness in a logarithmic way. That is why the decibel scale, being a logarithmic
+ scale, is typically used to define sound levels. UI volume controls in professional audio
+ applications usually use a decibel scale. The cubic scale is a computationally cheap
+ approximation of a logarithmic scale, most applications should use a cubic scale for their UI
+ volume controls.
+
+ The following example shows how to convert the volume value from a slider control before passing
+ it to a QMediaPlayer. As a result, the perceived increase in volume is the same when increasing
+ the volume slider from 20 to 30 as it is from 50 to 60:
+
+ \snippet multimedia-snippets/audio.cpp Volume conversion
+
+ \since 5.8
+ \sa VolumeScale, QMediaPlayer::setVolume(), QAudioOutput::setVolume(),
+ QAudioInput::setVolume(), QSoundEffect::setVolume(), QMediaRecorder::setVolume()
+*/
+qreal convertVolume(qreal volume, VolumeScale from, VolumeScale to)
+{
+ switch (from) {
+ case LinearVolumeScale:
+ volume = qMax(qreal(0), volume);
+ switch (to) {
+ case LinearVolumeScale:
+ return volume;
+ case CubicVolumeScale:
+ return qPow(volume, qreal(1 / 3.0));
+ case DecibelVolumeScale:
+ if (volume < 0.001)
+ return qreal(-200);
+ else
+ return qreal(20.0) * std::log10(volume);
+ }
+ break;
+ case CubicVolumeScale:
+ volume = qMax(qreal(0), volume);
+ switch (to) {
+ case LinearVolumeScale:
+ return volume * volume * volume;
+ case CubicVolumeScale:
+ return volume;
+ case DecibelVolumeScale:
+ if (volume < 0.001)
+ return qreal(-200);
+ else
+ return qreal(3.0 * 20.0) * std::log10(volume);
+ }
+ break;
+ case DecibelVolumeScale:
+ switch (to) {
+ case LinearVolumeScale:
+ return qPow(qreal(10.0), volume / qreal(20.0));
+ case CubicVolumeScale:
+ return qPow(qreal(10.0), volume / qreal(3.0 * 20.0));
+ case DecibelVolumeScale:
+ return volume;
+ }
+ break;
+ }
+
+ return volume;
+}
+
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, QAudio::Error error)
{
@@ -210,6 +304,25 @@ QDebug operator<<(QDebug dbg, QAudio::Role role)
}
return dbg;
}
+
+QDebug operator<<(QDebug dbg, QAudio::VolumeScale scale)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ switch (scale) {
+ case QAudio::LinearVolumeScale:
+ dbg << "LinearVolumeScale";
+ break;
+ case QAudio::CubicVolumeScale:
+ dbg << "CubicVolumeScale";
+ break;
+ case QAudio::DecibelVolumeScale:
+ dbg << "DecibelVolumeScale";
+ break;
+ }
+ return dbg;
+}
+
#endif
diff --git a/src/multimedia/audio/qaudio.h b/src/multimedia/audio/qaudio.h
index 449ddefae..9bbc6cf22 100644
--- a/src/multimedia/audio/qaudio.h
+++ b/src/multimedia/audio/qaudio.h
@@ -70,6 +70,14 @@ namespace QAudio
SonificationRole,
GameRole
};
+
+ enum VolumeScale {
+ LinearVolumeScale,
+ CubicVolumeScale,
+ DecibelVolumeScale
+ };
+
+ Q_MULTIMEDIA_EXPORT qreal convertVolume(qreal volume, VolumeScale from, VolumeScale to);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -77,6 +85,7 @@ Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QAudio::Error error);
Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QAudio::State state);
Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QAudio::Mode mode);
Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QAudio::Role role);
+Q_MULTIMEDIA_EXPORT QDebug operator<<(QDebug dbg, QAudio::VolumeScale role);
#endif
QT_END_NAMESPACE
@@ -85,5 +94,6 @@ Q_DECLARE_METATYPE(QAudio::Error)
Q_DECLARE_METATYPE(QAudio::State)
Q_DECLARE_METATYPE(QAudio::Mode)
Q_DECLARE_METATYPE(QAudio::Role)
+Q_DECLARE_METATYPE(QAudio::VolumeScale)
#endif // QAUDIO_H
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp b/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp
index 310206405..736d1b306 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp
+++ b/src/multimedia/doc/snippets/multimedia-snippets/audio.cpp
@@ -47,6 +47,7 @@
#include "qaudiooutput.h"
#include "qaudioprobe.h"
#include "qaudiodecoder.h"
+#include "qmediaplayer.h"
class AudioInputExample : public QObject {
Q_OBJECT
@@ -247,3 +248,18 @@ void AudioDecodingExample::decode()
// Now wait for bufferReady() signal and call decoder->read()
//! [Local audio decoding]
}
+
+QMediaPlayer player;
+
+//! [Volume conversion]
+void applyVolume(int volumeSliderValue)
+{
+ // volumeSliderValue is in the range [0..100]
+
+ qreal linearVolume = QAudio::convertVolume(volumeSliderValue / qreal(100.0),
+ QAudio::CubicVolumeScale,
+ QAudio::LinearVolumeScale);
+
+ player.setVolume(qRound(linearVolume * 100));
+}
+//! [Volume conversion]