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 | #include <QtMultimedia/private/qtmultimediaglobal_p.h> |
41 | #include "qsoundeffect.h" |
42 | |
43 | #if QT_CONFIG(pulseaudio) |
44 | #include "qsoundeffect_pulse_p.h" |
45 | #else |
46 | #include "qsoundeffect_qaudio_p.h" |
47 | #endif |
48 | |
49 | QT_BEGIN_NAMESPACE |
50 | |
51 | /*! |
52 | \class QSoundEffect |
53 | \brief The QSoundEffect class provides a way to play low latency sound effects. |
54 | |
55 | \ingroup multimedia |
56 | \ingroup multimedia_audio |
57 | \inmodule QtMultimedia |
58 | |
59 | This class allows you to play uncompressed audio files (typically WAV files) in |
60 | a generally lower latency way, and is suitable for "feedback" type sounds in |
61 | response to user actions (e.g. virtual keyboard sounds, positive or negative |
62 | feedback for popup dialogs, or game sounds). If low latency is not important, |
63 | consider using the QMediaPlayer class instead, since it supports a wider |
64 | variety of media formats and is less resource intensive. |
65 | |
66 | This example shows how a looping, somewhat quiet sound effect |
67 | can be played: |
68 | |
69 | \snippet multimedia-snippets/qsound.cpp 2 |
70 | |
71 | Typically the sound effect should be reused, which allows all the |
72 | parsing and preparation to be done ahead of time, and only triggered |
73 | when necessary. This assists with lower latency audio playback. |
74 | |
75 | \snippet multimedia-snippets/qsound.cpp 3 |
76 | |
77 | Since QSoundEffect requires slightly more resources to achieve lower |
78 | latency playback, the platform may limit the number of simultaneously playing |
79 | sound effects. |
80 | */ |
81 | |
82 | |
83 | /*! |
84 | \qmltype SoundEffect |
85 | \instantiates QSoundEffect |
86 | \brief The SoundEffect type provides a way to play sound effects in QML. |
87 | |
88 | \inmodule QtMultimedia |
89 | \ingroup multimedia_qml |
90 | \ingroup multimedia_audio_qml |
91 | \inqmlmodule QtMultimedia |
92 | |
93 | This type allows you to play uncompressed audio files (typically WAV files) in |
94 | a generally lower latency way, and is suitable for "feedback" type sounds in |
95 | response to user actions (e.g. virtual keyboard sounds, positive or negative |
96 | feedback for popup dialogs, or game sounds). If low latency is not important, |
97 | consider using the MediaPlayer or Audio types instead, since they support a wider |
98 | variety of media formats and are less resource intensive. |
99 | |
100 | Typically the sound effect should be reused, which allows all the |
101 | parsing and preparation to be done ahead of time, and only triggered |
102 | when necessary. This is easy to achieve with QML, since you can declare your |
103 | SoundEffect instance and refer to it elsewhere. |
104 | |
105 | The following example plays a WAV file on mouse click. |
106 | |
107 | \snippet multimedia-snippets/soundeffect.qml complete snippet |
108 | |
109 | Since SoundEffect requires slightly more resources to achieve lower |
110 | latency playback, the platform may limit the number of simultaneously playing |
111 | sound effects. |
112 | */ |
113 | |
114 | static QSoundEffectPrivate *initPrivate(QSoundEffect *self, QSoundEffectPrivate *d) |
115 | { |
116 | QObject::connect(sender: d, signal: &QSoundEffectPrivate::loopsRemainingChanged, receiver: self, slot: &QSoundEffect::loopsRemainingChanged); |
117 | QObject::connect(sender: d, signal: &QSoundEffectPrivate::volumeChanged, receiver: self, slot: &QSoundEffect::volumeChanged); |
118 | QObject::connect(sender: d, signal: &QSoundEffectPrivate::mutedChanged, receiver: self, slot: &QSoundEffect::mutedChanged); |
119 | QObject::connect(sender: d, signal: &QSoundEffectPrivate::loadedChanged, receiver: self, slot: &QSoundEffect::loadedChanged); |
120 | QObject::connect(sender: d, signal: &QSoundEffectPrivate::playingChanged, receiver: self, slot: &QSoundEffect::playingChanged); |
121 | QObject::connect(sender: d, signal: &QSoundEffectPrivate::statusChanged, receiver: self, slot: &QSoundEffect::statusChanged); |
122 | QObject::connect(sender: d, signal: &QSoundEffectPrivate::categoryChanged, receiver: self, slot: &QSoundEffect::categoryChanged); |
123 | |
124 | return d; |
125 | } |
126 | /*! |
127 | Creates a QSoundEffect with the given \a parent. |
128 | */ |
129 | QSoundEffect::QSoundEffect(QObject *parent) |
130 | : QObject(parent) |
131 | , d(initPrivate(self: this, d: new QSoundEffectPrivate(this))) |
132 | { |
133 | } |
134 | |
135 | /*! |
136 | Creates a QSoundEffect with the given \a audioDevice and \a parent. |
137 | */ |
138 | QSoundEffect::QSoundEffect(const QAudioDeviceInfo &audioDevice, QObject *parent) |
139 | : QObject(parent) |
140 | , d(initPrivate(self: this, d: new QSoundEffectPrivate(audioDevice, this))) |
141 | { |
142 | } |
143 | |
144 | /*! |
145 | Destroys this sound effect. |
146 | */ |
147 | QSoundEffect::~QSoundEffect() |
148 | { |
149 | d->release(); |
150 | } |
151 | |
152 | /*! |
153 | \fn QSoundEffect::supportedMimeTypes() |
154 | |
155 | Returns a list of the supported mime types for this platform. |
156 | */ |
157 | QStringList QSoundEffect::supportedMimeTypes() |
158 | { |
159 | return QSoundEffectPrivate::supportedMimeTypes(); |
160 | } |
161 | |
162 | /*! |
163 | \qmlproperty url QtMultimedia::SoundEffect::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. If the desired source is a local file the URL may be specified |
168 | using either absolute or relative (to the file that declared the SoundEffect) pathing. |
169 | */ |
170 | /*! |
171 | \property QSoundEffect::source |
172 | |
173 | This property holds the url for the sound to play. For the SoundEffect |
174 | to attempt to load the source, the URL must exist and the application must have read permission |
175 | in the specified directory. |
176 | */ |
177 | |
178 | /*! Returns the URL of the current source to play */ |
179 | QUrl QSoundEffect::source() const |
180 | { |
181 | return d->source(); |
182 | } |
183 | |
184 | /*! Set the current URL to play to \a url. */ |
185 | void QSoundEffect::setSource(const QUrl &url) |
186 | { |
187 | if (d->source() == url) |
188 | return; |
189 | |
190 | d->setSource(url); |
191 | |
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 | */ |
219 | int QSoundEffect::loopCount() const |
220 | { |
221 | return d->loopCount(); |
222 | } |
223 | |
224 | /*! |
225 | \enum QSoundEffect::Loop |
226 | |
227 | \value Infinite Used as a parameter to \l setLoopCount() for infinite looping |
228 | */ |
229 | |
230 | /*! |
231 | Set the total number of times to play this sound effect to \a loopCount. |
232 | |
233 | Setting the loop count to 0 or 1 means the sound effect will be played only once; |
234 | pass \c QSoundEffect::Infinite to repeat indefinitely. The loop count can be changed while |
235 | the sound effect is playing, in which case it will update the remaining loops to |
236 | the new \a loopCount. |
237 | |
238 | \sa loopsRemaining() |
239 | */ |
240 | void QSoundEffect::setLoopCount(int loopCount) |
241 | { |
242 | if (loopCount < 0 && loopCount != Infinite) { |
243 | qWarning(msg: "SoundEffect: loops should be SoundEffect.Infinite, 0 or positive integer" ); |
244 | return; |
245 | } |
246 | if (loopCount == 0) |
247 | loopCount = 1; |
248 | if (d->loopCount() == loopCount) |
249 | return; |
250 | |
251 | d->setLoopCount(loopCount); |
252 | emit loopCountChanged(); |
253 | } |
254 | |
255 | /*! |
256 | \qmlproperty int QtMultimedia::SoundEffect::loopsRemaining |
257 | |
258 | This property contains the number of loops remaining before the sound effect |
259 | stops by itself, or SoundEffect.Infinite if that's what has been set in \l loops. |
260 | */ |
261 | /*! |
262 | \property QSoundEffect::loopsRemaining |
263 | |
264 | This property contains the number of loops remaining before the sound effect |
265 | stops by itself, or QSoundEffect::Infinite if that's what has been set in \l loops. |
266 | */ |
267 | int QSoundEffect::loopsRemaining() const |
268 | { |
269 | return d->loopsRemaining(); |
270 | } |
271 | |
272 | |
273 | /*! |
274 | \qmlproperty qreal QtMultimedia::SoundEffect::volume |
275 | |
276 | This property holds the volume of the sound effect playback. |
277 | |
278 | The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this |
279 | range will be clamped. |
280 | |
281 | The default volume is \c 1.0. |
282 | |
283 | UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale |
284 | will produce linear changes in perceived loudness, which is what a user would normally expect |
285 | from a volume control. See \l {QtMultimedia::QtMultimedia::convertVolume()}{QtMultimedia.convertVolume()} |
286 | for more details. |
287 | */ |
288 | /*! |
289 | \property QSoundEffect::volume |
290 | |
291 | This property holds the volume of the sound effect playback, from 0.0 (silence) to 1.0 (full volume). |
292 | */ |
293 | |
294 | /*! |
295 | Returns the current volume of this sound effect, from 0.0 (silent) to 1.0 (maximum volume). |
296 | */ |
297 | qreal QSoundEffect::volume() const |
298 | { |
299 | return d->volume(); |
300 | } |
301 | |
302 | /*! |
303 | Sets the sound effect volume to \a volume. |
304 | |
305 | The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this |
306 | range will be clamped. |
307 | |
308 | The default volume is \c 1.0. |
309 | |
310 | UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale |
311 | will produce linear changes in perceived loudness, which is what a user would normally expect |
312 | from a volume control. See QAudio::convertVolume() for more details. |
313 | */ |
314 | void QSoundEffect::setVolume(qreal volume) |
315 | { |
316 | volume = qBound(min: qreal(0.0), val: volume, max: qreal(1.0)); |
317 | if (qFuzzyCompare(p1: d->volume(), p2: volume)) |
318 | return; |
319 | |
320 | d->setVolume(volume); |
321 | } |
322 | |
323 | /*! |
324 | \qmlproperty bool QtMultimedia::SoundEffect::muted |
325 | |
326 | This property provides a way to control muting. A value of \c true will mute this effect. |
327 | Otherwise, playback will occur with the currently specified \l volume. |
328 | */ |
329 | /*! |
330 | \property QSoundEffect::muted |
331 | |
332 | This property provides a way to control muting. A value of \c true will mute this effect. |
333 | */ |
334 | |
335 | /*! Returns whether this sound effect is muted */ |
336 | bool QSoundEffect::isMuted() const |
337 | { |
338 | return d->isMuted(); |
339 | } |
340 | |
341 | /*! |
342 | Sets whether to mute this sound effect's playback. |
343 | |
344 | If \a muted is true, playback will be muted (silenced), |
345 | and otherwise playback will occur with the currently |
346 | specified volume(). |
347 | */ |
348 | void QSoundEffect::setMuted(bool muted) |
349 | { |
350 | if (d->isMuted() == muted) |
351 | return; |
352 | |
353 | d->setMuted(muted); |
354 | } |
355 | |
356 | /*! |
357 | \fn QSoundEffect::isLoaded() const |
358 | |
359 | Returns whether the sound effect has finished loading the \l source(). |
360 | */ |
361 | /*! |
362 | \qmlmethod bool QtMultimedia::SoundEffect::isLoaded() |
363 | |
364 | Returns whether the sound effect has finished loading the \l source. |
365 | */ |
366 | bool QSoundEffect::isLoaded() const |
367 | { |
368 | return d->isLoaded(); |
369 | } |
370 | |
371 | /*! |
372 | \qmlmethod QtMultimedia::SoundEffect::play() |
373 | |
374 | Start playback of the sound effect, looping the effect for the number of |
375 | times as specified in the loops property. |
376 | |
377 | This is the default method for SoundEffect. |
378 | |
379 | \snippet multimedia-snippets/soundeffect.qml play sound on click |
380 | */ |
381 | /*! |
382 | \fn QSoundEffect::play() |
383 | |
384 | Start playback of the sound effect, looping the effect for the number of |
385 | times as specified in the loops property. |
386 | */ |
387 | void QSoundEffect::play() |
388 | { |
389 | d->play(); |
390 | } |
391 | |
392 | /*! |
393 | \qmlproperty bool QtMultimedia::SoundEffect::playing |
394 | |
395 | This property indicates whether the sound effect is playing or not. |
396 | */ |
397 | /*! |
398 | \property QSoundEffect::playing |
399 | |
400 | This property indicates whether the sound effect is playing or not. |
401 | */ |
402 | |
403 | /*! Returns true if the sound effect is currently playing, or false otherwise */ |
404 | bool QSoundEffect::isPlaying() const |
405 | { |
406 | return d->isPlaying(); |
407 | } |
408 | |
409 | /*! |
410 | \enum QSoundEffect::Status |
411 | |
412 | \value Null No source has been set or the source is null. |
413 | \value Loading The SoundEffect is trying to load the source. |
414 | \value Ready The source is loaded and ready for play. |
415 | \value Error An error occurred during operation, such as failure of loading the source. |
416 | |
417 | */ |
418 | |
419 | /*! |
420 | \qmlproperty enumeration QtMultimedia::SoundEffect::status |
421 | |
422 | This property indicates the current status of the SoundEffect |
423 | as enumerated within SoundEffect. |
424 | Possible statuses are listed below. |
425 | |
426 | \table |
427 | \header \li Value \li Description |
428 | \row \li SoundEffect.Null \li No source has been set or the source is null. |
429 | \row \li SoundEffect.Loading \li The SoundEffect is trying to load the source. |
430 | \row \li SoundEffect.Ready \li The source is loaded and ready for play. |
431 | \row \li SoundEffect.Error \li An error occurred during operation, such as failure of loading the source. |
432 | \endtable |
433 | */ |
434 | /*! |
435 | \property QSoundEffect::status |
436 | |
437 | This property indicates the current status of the sound effect |
438 | from the \l QSoundEffect::Status enumeration. |
439 | */ |
440 | |
441 | /*! |
442 | Returns the current status of this sound effect. |
443 | */ |
444 | QSoundEffect::Status QSoundEffect::status() const |
445 | { |
446 | return d->status(); |
447 | } |
448 | |
449 | /*! |
450 | \qmlproperty string QtMultimedia::SoundEffect::category |
451 | |
452 | This property contains the \e category of this sound effect. |
453 | |
454 | Some platforms can perform different audio routing |
455 | for different categories, or may allow the user to |
456 | set different volume levels for different categories. |
457 | |
458 | This setting will be ignored on platforms that do not |
459 | support audio categories. |
460 | */ |
461 | /*! |
462 | \property QSoundEffect::category |
463 | |
464 | This property contains the \e category of this sound effect. |
465 | |
466 | Some platforms can perform different audio routing |
467 | for different categories, or may allow the user to |
468 | set different volume levels for different categories. |
469 | |
470 | This setting will be ignored on platforms that do not |
471 | support audio categories. |
472 | */ |
473 | /*! |
474 | Returns the current \e category for this sound effect. |
475 | |
476 | Some platforms can perform different audio routing |
477 | for different categories, or may allow the user to |
478 | set different volume levels for different categories. |
479 | |
480 | This setting will be ignored on platforms that do not |
481 | support audio categories. |
482 | |
483 | \sa setCategory() |
484 | */ |
485 | QString QSoundEffect::category() const |
486 | { |
487 | return d->category(); |
488 | } |
489 | |
490 | /*! |
491 | Sets the \e category of this sound effect to \a category. |
492 | |
493 | Some platforms can perform different audio routing |
494 | for different categories, or may allow the user to |
495 | set different volume levels for different categories. |
496 | |
497 | This setting will be ignored on platforms that do not |
498 | support audio categories. |
499 | |
500 | If this setting is changed while a sound effect is playing |
501 | it will only take effect when the sound effect has stopped |
502 | playing. |
503 | |
504 | \sa category() |
505 | */ |
506 | void QSoundEffect::setCategory(const QString &category) |
507 | { |
508 | d->setCategory(category); |
509 | } |
510 | |
511 | |
512 | /*! |
513 | \qmlmethod QtMultimedia::SoundEffect::stop() |
514 | |
515 | Stop current playback. |
516 | |
517 | */ |
518 | /*! |
519 | \fn QSoundEffect::stop() |
520 | |
521 | Stop current playback. |
522 | |
523 | */ |
524 | void QSoundEffect::stop() |
525 | { |
526 | d->stop(); |
527 | } |
528 | |
529 | /* Signals */ |
530 | |
531 | /*! |
532 | \fn void QSoundEffect::sourceChanged() |
533 | |
534 | The \c sourceChanged signal is emitted when the source has been changed. |
535 | */ |
536 | /*! |
537 | \qmlsignal QtMultimedia::SoundEffect::sourceChanged() |
538 | |
539 | The \c sourceChanged signal is emitted when the source has been changed. |
540 | |
541 | The corresponding handler is \c onSourceChanged. |
542 | */ |
543 | /*! |
544 | \fn void QSoundEffect::loadedChanged() |
545 | |
546 | The \c loadedChanged signal is emitted when the loading state has changed. |
547 | */ |
548 | /*! |
549 | \qmlsignal QtMultimedia::SoundEffect::loadedChanged() |
550 | |
551 | The \c loadedChanged signal is emitted when the loading state has changed. |
552 | |
553 | The corresponding handler is \c onLoadedChanged. |
554 | */ |
555 | |
556 | /*! |
557 | \fn void QSoundEffect::loopCountChanged() |
558 | |
559 | The \c loopCountChanged signal is emitted when the initial number of loops has changed. |
560 | */ |
561 | /*! |
562 | \qmlsignal QtMultimedia::SoundEffect::loopCountChanged() |
563 | |
564 | The \c loopCountChanged signal is emitted when the initial number of loops has changed. |
565 | |
566 | The corresponding handler is \c onLoopCountChanged. |
567 | */ |
568 | |
569 | /*! |
570 | \fn void QSoundEffect::loopsRemainingChanged() |
571 | |
572 | The \c loopsRemainingChanged signal is emitted when the remaining number of loops has changed. |
573 | */ |
574 | /*! |
575 | \qmlsignal QtMultimedia::SoundEffect::loopsRemainingChanged() |
576 | |
577 | The \c loopsRemainingChanged signal is emitted when the remaining number of loops has changed. |
578 | |
579 | The corresponding handler is \c onLoopsRemainingChanged. |
580 | */ |
581 | |
582 | /*! |
583 | \fn void QSoundEffect::volumeChanged() |
584 | |
585 | The \c volumeChanged signal is emitted when the volume has changed. |
586 | */ |
587 | /*! |
588 | \qmlsignal QtMultimedia::SoundEffect::volumeChanged() |
589 | |
590 | The \c volumeChanged signal is emitted when the volume has changed. |
591 | |
592 | The corresponding handler is \c onVolumeChanged. |
593 | */ |
594 | |
595 | /*! |
596 | \fn void QSoundEffect::mutedChanged() |
597 | |
598 | The \c mutedChanged signal is emitted when the mute state has changed. |
599 | */ |
600 | /*! |
601 | \qmlsignal QtMultimedia::SoundEffect::mutedChanged() |
602 | |
603 | The \c mutedChanged signal is emitted when the mute state has changed. |
604 | |
605 | The corresponding handler is \c onMutedChanged. |
606 | */ |
607 | |
608 | /*! |
609 | \fn void QSoundEffect::playingChanged() |
610 | |
611 | The \c playingChanged signal is emitted when the playing property has changed. |
612 | */ |
613 | /*! |
614 | \qmlsignal QtMultimedia::SoundEffect::playingChanged() |
615 | |
616 | The \c playingChanged signal is emitted when the playing property has changed. |
617 | |
618 | The corresponding handler is \c onPlayingChanged. |
619 | */ |
620 | |
621 | /*! |
622 | \fn void QSoundEffect::statusChanged() |
623 | |
624 | The \c statusChanged signal is emitted when the status property has changed. |
625 | */ |
626 | /*! |
627 | \qmlsignal QtMultimedia::SoundEffect::statusChanged() |
628 | |
629 | The \c statusChanged signal is emitted when the status property has changed. |
630 | |
631 | The corresponding handler is \c onStatusChanged. |
632 | */ |
633 | |
634 | /*! |
635 | \fn void QSoundEffect::categoryChanged() |
636 | |
637 | The \c categoryChanged signal is emitted when the category property has changed. |
638 | */ |
639 | /*! |
640 | \qmlsignal QtMultimedia::SoundEffect::categoryChanged() |
641 | |
642 | The \c categoryChanged signal is emitted when the category property has changed. |
643 | |
644 | The corresponding handler is \c onCategoryChanged. |
645 | */ |
646 | |
647 | |
648 | QT_END_NAMESPACE |
649 | |
650 | #include "moc_qsoundeffect.cpp" |
651 | |