| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. |
| 4 | ** Contact: https://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:LGPL$ |
| 9 | ** Commercial License Usage |
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 11 | ** accordance with the commercial license agreement provided with the |
| 12 | ** Software or, alternatively, in accordance with the terms contained in |
| 13 | ** a written agreement between you and The Qt Company. For licensing terms |
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at https://www.qt.io/contact-us. |
| 16 | ** |
| 17 | ** GNU Lesser General Public License Usage |
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
| 19 | ** General Public License version 3 as published by the Free Software |
| 20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| 21 | ** packaging of this file. Please review the following information to |
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements |
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| 24 | ** |
| 25 | ** GNU General Public License Usage |
| 26 | ** Alternatively, this file may be used under the terms of the GNU |
| 27 | ** General Public License version 2.0 or (at your option) the GNU General |
| 28 | ** Public license version 3 or any later version approved by the KDE Free |
| 29 | ** Qt Foundation. The licenses are as published by the Free Software |
| 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| 31 | ** included in the packaging of this file. Please review the following |
| 32 | ** information to ensure the GNU General Public License requirements will |
| 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
| 35 | ** |
| 36 | ** $QT_END_LICENSE$ |
| 37 | ** |
| 38 | ****************************************************************************/ |
| 39 | |
| 40 | |
| 41 | #include <qaudio.h> |
| 42 | #include <qmath.h> |
| 43 | #include <QDebug> |
| 44 | |
| 45 | QT_BEGIN_NAMESPACE |
| 46 | |
| 47 | #define LOG100 4.60517018599 |
| 48 | |
| 49 | static void qRegisterAudioMetaTypes() |
| 50 | { |
| 51 | qRegisterMetaType<QAudio::Error>(); |
| 52 | qRegisterMetaType<QAudio::State>(); |
| 53 | qRegisterMetaType<QAudio::Mode>(); |
| 54 | qRegisterMetaType<QAudio::Role>(); |
| 55 | qRegisterMetaType<QAudio::VolumeScale>(); |
| 56 | } |
| 57 | |
| 58 | Q_CONSTRUCTOR_FUNCTION(qRegisterAudioMetaTypes) |
| 59 | |
| 60 | /*! |
| 61 | \namespace QAudio |
| 62 | \ingroup multimedia-namespaces |
| 63 | \brief The QAudio namespace contains enums used by the audio classes. |
| 64 | \inmodule QtMultimedia |
| 65 | \ingroup multimedia |
| 66 | \ingroup multimedia_audio |
| 67 | */ |
| 68 | |
| 69 | /*! |
| 70 | \enum QAudio::Error |
| 71 | |
| 72 | \value NoError No errors have occurred |
| 73 | \value OpenError An error occurred opening the audio device |
| 74 | \value IOError An error occurred during read/write of audio device |
| 75 | \value UnderrunError Audio data is not being fed to the audio device at a fast enough rate |
| 76 | \value FatalError A non-recoverable error has occurred, the audio device is not usable at this time. |
| 77 | */ |
| 78 | |
| 79 | /*! |
| 80 | \enum QAudio::State |
| 81 | |
| 82 | \value ActiveState Audio data is being processed, this state is set after start() is called |
| 83 | and while audio data is available to be processed. |
| 84 | \value SuspendedState The audio stream is in a suspended state. Entered after suspend() is called |
| 85 | or when another stream takes control of the audio device. In the later case, |
| 86 | a call to resume will return control of the audio device to this stream. This |
| 87 | should usually only be done upon user request. |
| 88 | \value StoppedState The audio device is closed, and is not processing any audio data |
| 89 | \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state |
| 90 | is set after start() is called and while no audio data is available to be processed. |
| 91 | \value InterruptedState This stream is in a suspended state because another higher priority stream currently |
| 92 | has control of the audio device. Playback cannot resume until the higher priority |
| 93 | stream relinquishes control of the audio device. |
| 94 | */ |
| 95 | |
| 96 | /*! |
| 97 | \enum QAudio::Mode |
| 98 | |
| 99 | \value AudioOutput audio output device |
| 100 | \value AudioInput audio input device |
| 101 | */ |
| 102 | |
| 103 | /*! |
| 104 | \enum QAudio::Role |
| 105 | |
| 106 | This enum describes the role of an audio stream. |
| 107 | |
| 108 | \value UnknownRole The role is unknown or undefined |
| 109 | \value MusicRole Music |
| 110 | \value VideoRole Soundtrack from a movie or a video |
| 111 | \value VoiceCommunicationRole Voice communications, such as telephony |
| 112 | \value AlarmRole Alarm |
| 113 | \value NotificationRole Notification, such as an incoming e-mail or a chat request |
| 114 | \value RingtoneRole Ringtone |
| 115 | \value AccessibilityRole For accessibility, such as with a screen reader |
| 116 | \value SonificationRole Sonification, such as with user interface sounds |
| 117 | \value GameRole Game audio |
| 118 | \value CustomRole The role is specified by QMediaPlayer::customAudioRole() |
| 119 | |
| 120 | \since 5.6 |
| 121 | \sa QMediaPlayer::setAudioRole() |
| 122 | */ |
| 123 | |
| 124 | /*! |
| 125 | \enum QAudio::VolumeScale |
| 126 | |
| 127 | This enum defines the different audio volume scales. |
| 128 | |
| 129 | \value LinearVolumeScale Linear scale. \c 0.0 (0%) is silence and \c 1.0 (100%) is full |
| 130 | volume. All Qt Multimedia classes that have an audio volume use |
| 131 | a linear scale. |
| 132 | \value CubicVolumeScale Cubic scale. \c 0.0 (0%) is silence and \c 1.0 (100%) is full |
| 133 | volume. |
| 134 | \value LogarithmicVolumeScale Logarithmic Scale. \c 0.0 (0%) is silence and \c 1.0 (100%) is |
| 135 | full volume. UI volume controls should usually use a logarithmic |
| 136 | scale. |
| 137 | \value DecibelVolumeScale Decibel (dB, amplitude) logarithmic scale. \c -200 is silence |
| 138 | and \c 0 is full volume. |
| 139 | |
| 140 | \since 5.8 |
| 141 | \sa QAudio::convertVolume() |
| 142 | */ |
| 143 | |
| 144 | namespace QAudio |
| 145 | { |
| 146 | |
| 147 | /*! |
| 148 | \fn qreal QAudio::convertVolume(qreal volume, VolumeScale from, VolumeScale to) |
| 149 | |
| 150 | Converts an audio \a volume \a from a volume scale \a to another, and returns the result. |
| 151 | |
| 152 | Depending on the context, different scales are used to represent audio volume. All Qt Multimedia |
| 153 | classes that have an audio volume use a linear scale, the reason is that the loudness of a |
| 154 | speaker is controlled by modulating its voltage on a linear scale. The human ear on the other |
| 155 | hand, perceives loudness in a logarithmic way. Using a logarithmic scale for volume controls |
| 156 | is therefore appropriate in most applications. The decibel scale is logarithmic by nature and |
| 157 | is commonly used to define sound levels, it is usually used for UI volume controls in |
| 158 | professional audio applications. The cubic scale is a computationally cheap approximation of a |
| 159 | logarithmic scale, it provides more control over lower volume levels. |
| 160 | |
| 161 | The following example shows how to convert the volume value from a slider control before passing |
| 162 | it to a QMediaPlayer. As a result, the perceived increase in volume is the same when increasing |
| 163 | the volume slider from 20 to 30 as it is from 50 to 60: |
| 164 | |
| 165 | \snippet multimedia-snippets/audio.cpp Volume conversion |
| 166 | |
| 167 | \since 5.8 |
| 168 | \sa VolumeScale, QMediaPlayer::setVolume(), QAudioOutput::setVolume(), |
| 169 | QAudioInput::setVolume(), QSoundEffect::setVolume(), QMediaRecorder::setVolume() |
| 170 | */ |
| 171 | qreal convertVolume(qreal volume, VolumeScale from, VolumeScale to) |
| 172 | { |
| 173 | switch (from) { |
| 174 | case LinearVolumeScale: |
| 175 | volume = qMax(a: qreal(0), b: volume); |
| 176 | switch (to) { |
| 177 | case LinearVolumeScale: |
| 178 | return volume; |
| 179 | case CubicVolumeScale: |
| 180 | return qPow(x: volume, y: qreal(1 / 3.0)); |
| 181 | case LogarithmicVolumeScale: |
| 182 | return 1 - std::exp(x: -volume * LOG100); |
| 183 | case DecibelVolumeScale: |
| 184 | if (volume < 0.001) |
| 185 | return qreal(-200); |
| 186 | else |
| 187 | return qreal(20.0) * std::log10(x: volume); |
| 188 | } |
| 189 | break; |
| 190 | case CubicVolumeScale: |
| 191 | volume = qMax(a: qreal(0), b: volume); |
| 192 | switch (to) { |
| 193 | case LinearVolumeScale: |
| 194 | return volume * volume * volume; |
| 195 | case CubicVolumeScale: |
| 196 | return volume; |
| 197 | case LogarithmicVolumeScale: |
| 198 | return 1 - std::exp(x: -volume * volume * volume * LOG100); |
| 199 | case DecibelVolumeScale: |
| 200 | if (volume < 0.001) |
| 201 | return qreal(-200); |
| 202 | else |
| 203 | return qreal(3.0 * 20.0) * std::log10(x: volume); |
| 204 | } |
| 205 | break; |
| 206 | case LogarithmicVolumeScale: |
| 207 | volume = qMax(a: qreal(0), b: volume); |
| 208 | switch (to) { |
| 209 | case LinearVolumeScale: |
| 210 | if (volume > 0.99) |
| 211 | return 1; |
| 212 | else |
| 213 | return -std::log(x: 1 - volume) / LOG100; |
| 214 | case CubicVolumeScale: |
| 215 | if (volume > 0.99) |
| 216 | return 1; |
| 217 | else |
| 218 | return qPow(x: -std::log(x: 1 - volume) / LOG100, y: qreal(1 / 3.0)); |
| 219 | case LogarithmicVolumeScale: |
| 220 | return volume; |
| 221 | case DecibelVolumeScale: |
| 222 | if (volume < 0.001) |
| 223 | return qreal(-200); |
| 224 | else if (volume > 0.99) |
| 225 | return 0; |
| 226 | else |
| 227 | return qreal(20.0) * std::log10(x: -std::log(x: 1 - volume) / LOG100); |
| 228 | } |
| 229 | break; |
| 230 | case DecibelVolumeScale: |
| 231 | switch (to) { |
| 232 | case LinearVolumeScale: |
| 233 | return qPow(x: qreal(10.0), y: volume / qreal(20.0)); |
| 234 | case CubicVolumeScale: |
| 235 | return qPow(x: qreal(10.0), y: volume / qreal(3.0 * 20.0)); |
| 236 | case LogarithmicVolumeScale: |
| 237 | if (qFuzzyIsNull(d: volume)) |
| 238 | return 1; |
| 239 | else |
| 240 | return 1 - std::exp(x: -qPow(x: qreal(10.0), y: volume / qreal(20.0)) * LOG100); |
| 241 | case DecibelVolumeScale: |
| 242 | return volume; |
| 243 | } |
| 244 | break; |
| 245 | } |
| 246 | |
| 247 | return volume; |
| 248 | } |
| 249 | |
| 250 | } |
| 251 | |
| 252 | #ifndef QT_NO_DEBUG_STREAM |
| 253 | QDebug operator<<(QDebug dbg, QAudio::Error error) |
| 254 | { |
| 255 | QDebugStateSaver saver(dbg); |
| 256 | dbg.nospace(); |
| 257 | switch (error) { |
| 258 | case QAudio::NoError: |
| 259 | dbg << "NoError" ; |
| 260 | break; |
| 261 | case QAudio::OpenError: |
| 262 | dbg << "OpenError" ; |
| 263 | break; |
| 264 | case QAudio::IOError: |
| 265 | dbg << "IOError" ; |
| 266 | break; |
| 267 | case QAudio::UnderrunError: |
| 268 | dbg << "UnderrunError" ; |
| 269 | break; |
| 270 | case QAudio::FatalError: |
| 271 | dbg << "FatalError" ; |
| 272 | break; |
| 273 | } |
| 274 | return dbg; |
| 275 | } |
| 276 | |
| 277 | QDebug operator<<(QDebug dbg, QAudio::State state) |
| 278 | { |
| 279 | QDebugStateSaver saver(dbg); |
| 280 | dbg.nospace(); |
| 281 | switch (state) { |
| 282 | case QAudio::ActiveState: |
| 283 | dbg << "ActiveState" ; |
| 284 | break; |
| 285 | case QAudio::SuspendedState: |
| 286 | dbg << "SuspendedState" ; |
| 287 | break; |
| 288 | case QAudio::StoppedState: |
| 289 | dbg << "StoppedState" ; |
| 290 | break; |
| 291 | case QAudio::IdleState: |
| 292 | dbg << "IdleState" ; |
| 293 | break; |
| 294 | case QAudio::InterruptedState: |
| 295 | dbg << "InterruptedState" ; |
| 296 | break; |
| 297 | } |
| 298 | return dbg; |
| 299 | } |
| 300 | |
| 301 | QDebug operator<<(QDebug dbg, QAudio::Mode mode) |
| 302 | { |
| 303 | QDebugStateSaver saver(dbg); |
| 304 | dbg.nospace(); |
| 305 | switch (mode) { |
| 306 | case QAudio::AudioInput: |
| 307 | dbg << "AudioInput" ; |
| 308 | break; |
| 309 | case QAudio::AudioOutput: |
| 310 | dbg << "AudioOutput" ; |
| 311 | break; |
| 312 | } |
| 313 | return dbg; |
| 314 | } |
| 315 | |
| 316 | QDebug operator<<(QDebug dbg, QAudio::Role role) |
| 317 | { |
| 318 | QDebugStateSaver saver(dbg); |
| 319 | dbg.nospace(); |
| 320 | switch (role) { |
| 321 | case QAudio::UnknownRole: |
| 322 | dbg << "UnknownRole" ; |
| 323 | break; |
| 324 | case QAudio::AccessibilityRole: |
| 325 | dbg << "AccessibilityRole" ; |
| 326 | break; |
| 327 | case QAudio::AlarmRole: |
| 328 | dbg << "AlarmRole" ; |
| 329 | break; |
| 330 | case QAudio::GameRole: |
| 331 | dbg << "GameRole" ; |
| 332 | break; |
| 333 | case QAudio::MusicRole: |
| 334 | dbg << "MusicRole" ; |
| 335 | break; |
| 336 | case QAudio::NotificationRole: |
| 337 | dbg << "NotificationRole" ; |
| 338 | break; |
| 339 | case QAudio::RingtoneRole: |
| 340 | dbg << "RingtoneRole" ; |
| 341 | break; |
| 342 | case QAudio::SonificationRole: |
| 343 | dbg << "SonificationRole" ; |
| 344 | break; |
| 345 | case QAudio::VideoRole: |
| 346 | dbg << "VideoRole" ; |
| 347 | break; |
| 348 | case QAudio::VoiceCommunicationRole: |
| 349 | dbg << "VoiceCommunicationRole" ; |
| 350 | break; |
| 351 | case QAudio::CustomRole: |
| 352 | dbg << "CustomRole" ; |
| 353 | break; |
| 354 | } |
| 355 | return dbg; |
| 356 | } |
| 357 | |
| 358 | QDebug operator<<(QDebug dbg, QAudio::VolumeScale scale) |
| 359 | { |
| 360 | QDebugStateSaver saver(dbg); |
| 361 | dbg.nospace(); |
| 362 | switch (scale) { |
| 363 | case QAudio::LinearVolumeScale: |
| 364 | dbg << "LinearVolumeScale" ; |
| 365 | break; |
| 366 | case QAudio::CubicVolumeScale: |
| 367 | dbg << "CubicVolumeScale" ; |
| 368 | break; |
| 369 | case QAudio::LogarithmicVolumeScale: |
| 370 | dbg << "LogarithmicVolumeScale" ; |
| 371 | break; |
| 372 | case QAudio::DecibelVolumeScale: |
| 373 | dbg << "DecibelVolumeScale" ; |
| 374 | break; |
| 375 | } |
| 376 | return dbg; |
| 377 | } |
| 378 | |
| 379 | #endif |
| 380 | |
| 381 | |
| 382 | QT_END_NAMESPACE |
| 383 | |
| 384 | |