diff options
Diffstat (limited to 'src/multimedia/audio/qtaudio.cpp')
-rw-r--r-- | src/multimedia/audio/qtaudio.cpp | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/src/multimedia/audio/qtaudio.cpp b/src/multimedia/audio/qtaudio.cpp new file mode 100644 index 000000000..fb14e5093 --- /dev/null +++ b/src/multimedia/audio/qtaudio.cpp @@ -0,0 +1,245 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + + +#include <qtaudio.h> +#include <qmath.h> +#include <QDebug> + +QT_BEGIN_NAMESPACE + +#define LOG100 4.60517018599 + +/*! + \namespace QtAudio + \ingroup multimedia-namespaces + \brief The QtAudio namespace contains enums used by the audio classes. + \inmodule QtMultimedia + \ingroup multimedia + \ingroup multimedia_audio +*/ + +/*! + \enum QtAudio::Error + + \value NoError No errors have occurred + \value OpenError An error occurred opening the audio device + \value IOError An error occurred during read/write of audio device + \value UnderrunError Audio data is not being fed to the audio device at a fast enough rate + \value FatalError A non-recoverable error has occurred, the audio device is not usable at this time. +*/ + +/*! + \enum QtAudio::State + + \value ActiveState Audio data is being processed, this state is set after start() is called + and while audio data is available to be processed. + \value SuspendedState The audio stream is in a suspended state. Entered after suspend() is called + or when another stream takes control of the audio device. In the later case, + a call to resume will return control of the audio device to this stream. This + should usually only be done upon user request. + \value StoppedState The audio device is closed, and is not processing any audio data + \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state + is set after start() is called and while no audio data is available to be processed. +*/ + +/*! + \enum QtAudio::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. + \value LogarithmicVolumeScale Logarithmic Scale. \c 0.0 (0%) is silence and \c 1.0 (100%) is + full volume. UI volume controls should usually use a logarithmic + scale. + \value DecibelVolumeScale Decibel (dB, amplitude) logarithmic scale. \c -200 is silence + and \c 0 is full volume. + + \sa QtAudio::convertVolume() +*/ + +#if defined(Q_QDOC) +namespace QtAudio +#else +namespace QAudio +#endif +{ + +/*! + 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. Using a logarithmic scale for volume controls + is therefore appropriate in most applications. The decibel scale is logarithmic by nature and + is commonly used to define sound levels, it is usually used for UI volume controls in + professional audio applications. The cubic scale is a computationally cheap approximation of a + logarithmic scale, it provides more control over lower volume levels. + + 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 + + \sa VolumeScale, QAudioSink::setVolume(), QAudioSource::setVolume(), + QSoundEffect::setVolume() +*/ +float convertVolume(float volume, VolumeScale from, VolumeScale to) +{ + switch (from) { + case LinearVolumeScale: + volume = qMax(float(0), volume); + switch (to) { + case LinearVolumeScale: + return volume; + case CubicVolumeScale: + return qPow(volume, float(1 / 3.0)); + case LogarithmicVolumeScale: + return 1 - std::exp(-volume * LOG100); + case DecibelVolumeScale: + if (volume < 0.001) + return float(-200); + else + return float(20.0) * std::log10(volume); + } + break; + case CubicVolumeScale: + volume = qMax(float(0), volume); + switch (to) { + case LinearVolumeScale: + return volume * volume * volume; + case CubicVolumeScale: + return volume; + case LogarithmicVolumeScale: + return 1 - std::exp(-volume * volume * volume * LOG100); + case DecibelVolumeScale: + if (volume < 0.001) + return float(-200); + else + return float(3.0 * 20.0) * std::log10(volume); + } + break; + case LogarithmicVolumeScale: + volume = qMax(float(0), volume); + switch (to) { + case LinearVolumeScale: + if (volume > 0.99) + return 1; + else + return -std::log(1 - volume) / LOG100; + case CubicVolumeScale: + if (volume > 0.99) + return 1; + else + return qPow(-std::log(1 - volume) / LOG100, float(1 / 3.0)); + case LogarithmicVolumeScale: + return volume; + case DecibelVolumeScale: + if (volume < 0.001) + return float(-200); + else if (volume > 0.99) + return 0; + else + return float(20.0) * std::log10(-std::log(1 - volume) / LOG100); + } + break; + case DecibelVolumeScale: + switch (to) { + case LinearVolumeScale: + return qPow(float(10.0), volume / float(20.0)); + case CubicVolumeScale: + return qPow(float(10.0), volume / float(3.0 * 20.0)); + case LogarithmicVolumeScale: + if (qFuzzyIsNull(volume)) + return 1; + else + return 1 - std::exp(-qPow(float(10.0), volume / float(20.0)) * LOG100); + case DecibelVolumeScale: + return volume; + } + break; + } + + return volume; +} + +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, QAudio::Error error) +{ + QDebugStateSaver saver(dbg); + dbg.nospace(); + switch (error) { + case QAudio::NoError: + dbg << "NoError"; + break; + case QAudio::OpenError: + dbg << "OpenError"; + break; + case QAudio::IOError: + dbg << "IOError"; + break; + case QAudio::UnderrunError: + dbg << "UnderrunError"; + break; + case QAudio::FatalError: + dbg << "FatalError"; + break; + } + return dbg; +} + +QDebug operator<<(QDebug dbg, QAudio::State state) +{ + QDebugStateSaver saver(dbg); + dbg.nospace(); + switch (state) { + case QAudio::ActiveState: + dbg << "ActiveState"; + break; + case QAudio::SuspendedState: + dbg << "SuspendedState"; + break; + case QAudio::StoppedState: + dbg << "StoppedState"; + break; + case QAudio::IdleState: + dbg << "IdleState"; + break; + } + 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::LogarithmicVolumeScale: + dbg << "LogarithmicVolumeScale"; + break; + case QAudio::DecibelVolumeScale: + dbg << "DecibelVolumeScale"; + break; + } + return dbg; +} + +#endif + + +QT_END_NAMESPACE + |