Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsoundeffect.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsoundeffect.h"
5
6#include <QtCore/qloggingcategory.h>
7#include <QtCore/qfuture.h>
8#include <QtMultimedia/qaudiobuffer.h>
9#include <QtMultimedia/qaudiodevice.h>
10#include <QtMultimedia/qaudiosink.h>
11#include <QtMultimedia/qmediadevices.h>
12#include <QtMultimedia/private/qaudiosystem_p.h>
13#include <QtMultimedia/private/qsamplecache_p.h>
14#include <QtMultimedia/private/qsoundeffectsynchronous_p.h>
15#include <QtMultimedia/private/qsoundeffectwithplayer_p.h>
16#include <QtMultimedia/private/qtmultimediaglobal_p.h>
17
19
20Q_LOGGING_CATEGORY(qLcSoundEffect, "qt.multimedia.soundeffect")
21
22namespace {
23
24QSoundEffectPrivate *makeSoundEffectPrivate(QSoundEffect *fx, const QAudioDevice &audioDevice)
25{
26#if defined(Q_OS_MACOS) && defined(Q_OS_WIN)
27 return new QtMultimediaPrivate::QSoundEffectPrivateWithPlayer(fx, audioDevice);
28#endif
29
30 QAudioSink dummySink(audioDevice.isNull() ? QMediaDevices::defaultAudioOutput() : audioDevice);
31 auto platformSink = QPlatformAudioSink::get(dummySink);
32
33 if (platformSink && platformSink->hasCallbackAPI())
34 return new QtMultimediaPrivate::QSoundEffectPrivateWithPlayer(fx, audioDevice);
35 else
36 return new QSoundEffectPrivateSynchronous(fx, audioDevice);
37}
38
39} // namespace
40
41/*!
42 \class QSoundEffect
43 \brief The QSoundEffect class provides a way to play low latency sound effects.
44
45 \ingroup multimedia
46 \ingroup multimedia_audio
47 \inmodule QtMultimedia
48
49 This class allows you to play uncompressed audio files (typically WAV files) in
50 a generally lower latency way, and is suitable for "feedback" type sounds in
51 response to user actions (e.g. virtual keyboard sounds, positive or negative
52 feedback for popup dialogs, or game sounds). If low latency is not important,
53 consider using the QMediaPlayer class instead, since it supports a wider
54 variety of media formats and is less resource intensive.
55
56 This example shows how a looping, somewhat quiet sound effect
57 can be played:
58
59 \snippet multimedia-snippets/qsound.cpp 2
60
61 Typically the sound effect should be reused, which allows all the
62 parsing and preparation to be done ahead of time, and only triggered
63 when necessary. This assists with lower latency audio playback.
64
65 \snippet multimedia-snippets/qsound.cpp 3
66
67 Since QSoundEffect requires slightly more resources to achieve lower
68 latency playback, the platform may limit the number of simultaneously playing
69 sound effects.
70*/
71
72
73/*!
74 \qmltype SoundEffect
75 \nativetype QSoundEffect
76 \brief The SoundEffect type provides a way to play sound effects in QML.
77
78 \inmodule QtMultimedia
79 \ingroup multimedia_qml
80 \ingroup multimedia_audio_qml
81 \inqmlmodule QtMultimedia
82
83 This type allows you to play uncompressed audio files (typically WAV files) in
84 a generally lower latency way, and is suitable for "feedback" type sounds in
85 response to user actions (e.g. virtual keyboard sounds, positive or negative
86 feedback for popup dialogs, or game sounds). If low latency is not important,
87 consider using the MediaPlayer type instead, since it support a wider
88 variety of media formats and is less resource intensive.
89
90 Typically the sound effect should be reused, which allows all the
91 parsing and preparation to be done ahead of time, and only triggered
92 when necessary. This is easy to achieve with QML, since you can declare your
93 SoundEffect instance and refer to it elsewhere.
94
95 The following example plays a WAV file on mouse click.
96
97 \snippet multimedia-snippets/soundeffect.qml complete snippet
98
99 \note QSoundEffect only supports mono or stereo sound files. Using sound files with
100 a sampling rate of 48000hz is recommended, as this is the typical native sampling rate
101 on most platforms (\l QAudioDevice::preferredFormat()).
102*/
103
104/*!
105 Creates a QSoundEffect with the given \a parent.
106*/
107QSoundEffect::QSoundEffect(QObject *parent)
108 : QSoundEffect(QAudioDevice(), parent)
109{
110}
111
112/*!
113 Creates a QSoundEffect with the given \a audioDevice and \a parent.
114*/
115QSoundEffect::QSoundEffect(const QAudioDevice &audioDevice, QObject *parent)
116 : QObject(*makeSoundEffectPrivate(this, audioDevice), parent)
117{
118}
119
120/*!
121 Destroys this sound effect.
122 */
123QSoundEffect::~QSoundEffect()
124{
125 stop();
126}
127
128/*!
129 \fn QSoundEffect::supportedMimeTypes()
130
131 Returns a list of the supported mime types for this platform.
132*/
133QStringList QSoundEffect::supportedMimeTypes()
134{
135 // Only return supported mime types if we have a audio device available
136 const QList<QAudioDevice> devices = QMediaDevices::audioOutputs();
137 if (devices.isEmpty())
138 return QStringList();
139
140 using namespace Qt::Literals;
141 static const QStringList mimeTypes{
142 u"audio/aiff"_s,
143 u"audio/vnd.wave"_s,
144 u"audio/wav"_s,
145 u"audio/wave"_s,
146 u"audio/x-aiff"_s
147 u"audio/x-pn-wav"_s,
148 u"audio/x-wav"_s,
149 };
150
151 return mimeTypes;
152}
153
154/*!
155 \qmlproperty url QtMultimedia::SoundEffect::source
156
157 This property holds the url for the sound to play. For the SoundEffect
158 to attempt to load the source, the URL must exist and the application must have read permission
159 in the specified directory. If the desired source is a local file the URL may be specified
160 using either absolute or relative (to the file that declared the SoundEffect) pathing.
161*/
162/*!
163 \property QSoundEffect::source
164
165 This property holds the url for the sound to play. For the SoundEffect
166 to attempt to load the source, the URL must exist and the application must have read permission
167 in the specified directory.
168*/
169
170/*! Returns the URL of the current source to play */
171QUrl QSoundEffect::source() const
172{
173 Q_D(const QSoundEffect);
174
175 return d->url();
176}
177
178/*! Set the current URL to play to \a url. */
179void QSoundEffect::setSource(const QUrl &url)
180{
181 Q_D(QSoundEffect);
182
183 qCDebug(qLcSoundEffect) << this << "setSource current=" << d->url() << ", to=" << url;
184 if (d->url() == url)
185 return;
186 stop();
187
188 d->resolveAndSetSource(url, *QSampleCache::instance());
189
190 emit sourceChanged();
191}
192
193/*!
194 \qmlproperty int QtMultimedia::SoundEffect::loops
195
196 This property holds the number of times the sound is played. A value of 0 or 1 means
197 the sound will be played only once; set to SoundEffect.Infinite to enable infinite looping.
198
199 The value can be changed while the sound effect is playing, in which case it will update
200 the remaining loops to the new value.
201*/
202
203/*!
204 \property QSoundEffect::loops
205 This property holds the number of times the sound is played. A value of 0 or 1 means
206 the sound will be played only once; set to SoundEffect.Infinite to enable infinite looping.
207
208 The value can be changed while the sound effect is playing, in which case it will update
209 the remaining loops to the new value.
210*/
211
212/*!
213 Returns the total number of times that this sound effect will be played before stopping.
214
215 See the \l loopsRemaining() method for the number of loops currently remaining.
216 */
217int QSoundEffect::loopCount() const
218{
219 Q_D(const QSoundEffect);
220 return d->loopCount();
221}
222
223/*!
224 \enum QSoundEffect::Loop
225
226 \value Infinite Used as a parameter to \l setLoopCount() for infinite looping
227*/
228
229/*!
230 Set the total number of times to play this sound effect to \a loopCount.
231
232 Setting the loop count to 0 or 1 means the sound effect will be played only once;
233 pass \c QSoundEffect::Infinite to repeat indefinitely. The loop count can be changed while
234 the sound effect is playing, in which case it will update the remaining loops to
235 the new \a loopCount.
236
237 \sa loopsRemaining()
238*/
239void QSoundEffect::setLoopCount(int loopCount)
240{
241 Q_D(QSoundEffect);
242
243 if (loopCount < 0 && loopCount != Infinite) {
244 qWarning("SoundEffect: loops should be SoundEffect.Infinite, 0 or positive integer");
245 return;
246 }
247
248 if (d->setLoopCount(loopCount))
249 emit loopCountChanged();
250}
251
252/*!
253 \property QSoundEffect::audioDevice
254
255 Returns the QAudioDevice instance.
256*/
257QAudioDevice QSoundEffect::audioDevice()
258{
259 Q_D(const QSoundEffect);
260 return d->audioDevice();
261}
262
263void QSoundEffect::setAudioDevice(const QAudioDevice &device)
264{
265 Q_D(QSoundEffect);
266
267 qCDebug(qLcSoundEffect) << this << "setAudioDevice:" << device.description();
268
269 if (d->setAudioDevice(device))
270 emit audioDeviceChanged();
271}
272
273/*!
274 \qmlproperty int QtMultimedia::SoundEffect::loopsRemaining
275
276 This property contains the number of loops remaining before the sound effect
277 stops by itself, or SoundEffect.Infinite if that's what has been set in \l loops.
278*/
279/*!
280 \property QSoundEffect::loopsRemaining
281
282 This property contains the number of loops remaining before the sound effect
283 stops by itself, or QSoundEffect::Infinite if that's what has been set in \l loops.
284*/
285int QSoundEffect::loopsRemaining() const
286{
287 Q_D(const QSoundEffect);
288 return d->loopsRemaining();
289}
290
291/*!
292 \qmlproperty real QtMultimedia::SoundEffect::volume
293
294 This property holds the volume of the sound effect playback.
295
296 The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this
297 range will be clamped.
298
299 The default volume is \c 1.0.
300
301 UI volume controls should usually be scaled non-linearly. For example, using a logarithmic scale
302 will produce linear changes in perceived loudness, which is what a user would normally expect
303 from a volume control. See \l {QtAudio::convertVolume()}{convertVolume()}
304 for more details.
305*/
306/*!
307 \property QSoundEffect::volume
308
309 This property holds the volume of the sound effect playback, from 0.0 (silence) to 1.0 (full volume).
310*/
311
312/*!
313 Returns the current volume of this sound effect, from 0.0 (silent) to 1.0 (maximum volume).
314 */
315float QSoundEffect::volume() const
316{
317 Q_D(const QSoundEffect);
318 return d->volume();
319}
320
321/*!
322 Sets the sound effect volume to \a volume.
323
324 The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this
325 range will be clamped.
326
327 The default volume is \c 1.0.
328
329 UI volume controls should usually be scaled non-linearly. For example, using a logarithmic scale
330 will produce linear changes in perceived loudness, which is what a user would normally expect
331 from a volume control. See QtAudio::convertVolume() for more details.
332 */
333void QSoundEffect::setVolume(float volume)
334{
335 Q_D(QSoundEffect);
336 if (d->setVolume(volume))
337 emit volumeChanged();
338}
339
340/*!
341 \qmlproperty bool QtMultimedia::SoundEffect::muted
342
343 This property provides a way to control muting. A value of \c true will mute this effect.
344 Otherwise, playback will occur with the currently specified \l volume.
345*/
346/*!
347 \property QSoundEffect::muted
348
349 This property provides a way to control muting. A value of \c true will mute this effect.
350*/
351
352/*! Returns whether this sound effect is muted */
353bool QSoundEffect::isMuted() const
354{
355 Q_D(const QSoundEffect);
356 return d->muted();
357}
358
359/*!
360 Sets whether to mute this sound effect's playback.
361
362 If \a muted is true, playback will be muted (silenced),
363 and otherwise playback will occur with the currently
364 specified volume().
365*/
366void QSoundEffect::setMuted(bool muted)
367{
368 Q_D(QSoundEffect);
369 if (d->setMuted(muted))
370 emit mutedChanged();
371}
372
373/*!
374 \fn QSoundEffect::isLoaded() const
375
376 Returns whether the sound effect has finished loading the \l source().
377*/
378/*!
379 \qmlmethod bool QtMultimedia::SoundEffect::isLoaded()
380
381 Returns whether the sound effect has finished loading the \l source.
382*/
383bool QSoundEffect::isLoaded() const
384{
385 Q_D(const QSoundEffect);
386 return d->status() == QSoundEffect::Ready;
387}
388
389/*!
390 \qmlmethod void QtMultimedia::SoundEffect::play()
391
392 Start playback of the sound effect, looping the effect for the number of
393 times as specified in the loops property.
394
395 This is the default method for SoundEffect.
396
397 \snippet multimedia-snippets/soundeffect.qml play sound on click
398*/
399/*!
400 \fn QSoundEffect::play()
401
402 Start playback of the sound effect, looping the effect for the number of
403 times as specified in the loops property.
404*/
405void QSoundEffect::play()
406{
407 Q_D(QSoundEffect);
408 d->play();
409}
410
411/*!
412 \qmlproperty bool QtMultimedia::SoundEffect::playing
413
414 This property indicates whether the sound effect is playing or not.
415*/
416/*!
417 \property QSoundEffect::playing
418
419 This property indicates whether the sound effect is playing or not.
420*/
421
422/*! Returns true if the sound effect is currently playing, or false otherwise */
423bool QSoundEffect::isPlaying() const
424{
425 Q_D(const QSoundEffect);
426 return d->playing();
427}
428
429/*!
430 \enum QSoundEffect::Status
431
432 \value Null No source has been set or the source is null.
433 \value Loading The SoundEffect is trying to load the source.
434 \value Ready The source is loaded and ready for play.
435 \value Error An error occurred during operation, such as failure of loading the source.
436
437*/
438
439/*!
440 \qmlproperty enumeration QtMultimedia::SoundEffect::status
441
442 This property indicates the current status of the SoundEffect
443 as enumerated within SoundEffect.
444 Possible statuses are listed below.
445
446 \table
447 \header \li Value \li Description
448 \row \li SoundEffect.Null \li No source has been set or the source is null.
449 \row \li SoundEffect.Loading \li The SoundEffect is trying to load the source.
450 \row \li SoundEffect.Ready \li The source is loaded and ready for play.
451 \row \li SoundEffect.Error \li An error occurred during operation, such as failure of loading the source.
452 \endtable
453*/
454/*!
455 \property QSoundEffect::status
456
457 This property indicates the current status of the sound effect
458 from the \l QSoundEffect::Status enumeration.
459*/
460
461/*!
462 Returns the current status of this sound effect.
463 */
464QSoundEffect::Status QSoundEffect::status() const
465{
466 Q_D(const QSoundEffect);
467 return d->status();
468}
469
470/*!
471 \qmlmethod void QtMultimedia::SoundEffect::stop()
472
473 Stop current playback.
474
475 */
476/*!
477 \fn QSoundEffect::stop()
478
479 Stop current playback.
480
481 */
482void QSoundEffect::stop()
483{
484 Q_D(QSoundEffect);
485 d->stop();
486}
487
488/* Signals */
489
490/*!
491 \fn void QSoundEffect::sourceChanged()
492
493 The \c sourceChanged signal is emitted when the source has been changed.
494*/
495/*!
496 \qmlsignal QtMultimedia::SoundEffect::sourceChanged()
497
498 The \c sourceChanged signal is emitted when the source has been changed.
499*/
500/*!
501 \fn void QSoundEffect::loadedChanged()
502
503 The \c loadedChanged signal is emitted when the loading state has changed.
504*/
505/*!
506 \qmlsignal QtMultimedia::SoundEffect::loadedChanged()
507
508 The \c loadedChanged signal is emitted when the loading state has changed.
509*/
510
511/*!
512 \fn void QSoundEffect::loopCountChanged()
513
514 The \c loopCountChanged signal is emitted when the initial number of loops has changed.
515*/
516/*!
517 \qmlsignal QtMultimedia::SoundEffect::loopCountChanged()
518
519 The \c loopCountChanged signal is emitted when the initial number of loops has changed.
520*/
521
522/*!
523 \fn void QSoundEffect::loopsRemainingChanged()
524
525 The \c loopsRemainingChanged signal is emitted when the remaining number of loops has changed.
526*/
527/*!
528 \qmlsignal QtMultimedia::SoundEffect::loopsRemainingChanged()
529
530 The \c loopsRemainingChanged signal is emitted when the remaining number of loops has changed.
531*/
532
533/*!
534 \fn void QSoundEffect::volumeChanged()
535
536 The \c volumeChanged signal is emitted when the volume has changed.
537*/
538/*!
539 \qmlsignal QtMultimedia::SoundEffect::volumeChanged()
540
541 The \c volumeChanged signal is emitted when the volume has changed.
542*/
543
544/*!
545 \fn void QSoundEffect::mutedChanged()
546
547 The \c mutedChanged signal is emitted when the mute state has changed.
548*/
549/*!
550 \qmlsignal QtMultimedia::SoundEffect::mutedChanged()
551
552 The \c mutedChanged signal is emitted when the mute state has changed.
553*/
554
555/*!
556 \fn void QSoundEffect::playingChanged()
557
558 The \c playingChanged signal is emitted when the playing property has changed.
559*/
560/*!
561 \qmlsignal QtMultimedia::SoundEffect::playingChanged()
562
563 The \c playingChanged signal is emitted when the playing property has changed.
564*/
565
566/*!
567 \fn void QSoundEffect::statusChanged()
568
569 The \c statusChanged signal is emitted when the status property has changed.
570*/
571/*!
572 \qmlsignal QtMultimedia::SoundEffect::statusChanged()
573
574 The \c statusChanged signal is emitted when the status property has changed.
575*/
576
577void QSoundEffectPrivate::resolveAndSetSource(const QUrl &url, QSampleCache &cache)
578{
579 m_unresolvedUrl = url;
580 QUrl resolvedUrl = m_sourceResolver->resolve(url);
581 setSource(std::move(resolvedUrl), cache);
582}
583
584QUrl QSoundEffectPrivate::url() const
585{
586 return m_unresolvedUrl;
587}
588
589QSoundEffectPrivate *QSoundEffectPrivate::get(QSoundEffect *sfx)
590{
591 return sfx->d_func();
592}
593
594QT_END_NAMESPACE
595
596#include "moc_qsoundeffect.cpp"
Combined button and popup list for selecting options.
QSoundEffectPrivate * makeSoundEffectPrivate(QSoundEffect *fx, const QAudioDevice &audioDevice)