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