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 <QtMultimedia/private/qtmultimediaglobal_p.h> |
5 | #include "qsoundeffect.h" |
6 | #include "qsamplecache_p.h" |
7 | #include "qaudiodevice.h" |
8 | #include "qaudiosink.h" |
9 | #include "qmediadevices.h" |
10 | #include <QtCore/qloggingcategory.h> |
11 | #include <private/qplatformmediadevices_p.h> |
12 | |
13 | static Q_LOGGING_CATEGORY(qLcSoundEffect, "qt.multimedia.soundeffect" ) |
14 | |
15 | QT_BEGIN_NAMESPACE |
16 | |
17 | Q_GLOBAL_STATIC(QSampleCache, sampleCache) |
18 | |
19 | class QSoundEffectPrivate : public QIODevice |
20 | { |
21 | public: |
22 | QSoundEffectPrivate(QSoundEffect *q, const QAudioDevice &audioDevice = QAudioDevice()); |
23 | ~QSoundEffectPrivate() override = default; |
24 | |
25 | qint64 readData(char *data, qint64 len) override; |
26 | qint64 writeData(const char *data, qint64 len) override; |
27 | qint64 size() const override { |
28 | if (m_sample->state() != QSample::Ready) |
29 | return 0; |
30 | return m_loopCount == QSoundEffect::Infinite ? 0 : m_loopCount * m_sample->data().size(); |
31 | } |
32 | qint64 bytesAvailable() const override { |
33 | if (m_sample->state() != QSample::Ready) |
34 | return 0; |
35 | return m_loopCount == QSoundEffect::Infinite |
36 | ? std::numeric_limits<qint64>::max() : m_runningCount * m_sample->data().size() - m_offset; |
37 | } |
38 | bool isSequential() const override { |
39 | return m_loopCount == QSoundEffect::Infinite; |
40 | } |
41 | bool atEnd() const override { |
42 | return m_runningCount == 0; |
43 | } |
44 | |
45 | void setLoopsRemaining(int loopsRemaining); |
46 | void setStatus(QSoundEffect::Status status); |
47 | void setPlaying(bool playing); |
48 | |
49 | public Q_SLOTS: |
50 | void sampleReady(); |
51 | void decoderError(); |
52 | void stateChanged(QAudio::State); |
53 | |
54 | public: |
55 | QSoundEffect *q_ptr; |
56 | QUrl m_url; |
57 | int m_loopCount = 1; |
58 | int m_runningCount = 0; |
59 | bool m_playing = false; |
60 | QSoundEffect::Status m_status = QSoundEffect::Null; |
61 | QAudioSink *m_audioOutput = nullptr; |
62 | QSample *m_sample = nullptr; |
63 | bool m_muted = false; |
64 | float m_volume = 1.0; |
65 | bool m_sampleReady = false; |
66 | qint64 m_offset = 0; |
67 | QAudioDevice m_audioDevice; |
68 | }; |
69 | |
70 | QSoundEffectPrivate::QSoundEffectPrivate(QSoundEffect *q, const QAudioDevice &audioDevice) |
71 | : QIODevice(q) |
72 | , q_ptr(q) |
73 | , m_audioDevice(audioDevice) |
74 | { |
75 | open(mode: QIODevice::ReadOnly); |
76 | |
77 | QPlatformMediaDevices::instance()->prepareAudio(); |
78 | } |
79 | |
80 | void QSoundEffectPrivate::sampleReady() |
81 | { |
82 | if (m_status == QSoundEffect::Error) |
83 | return; |
84 | |
85 | qCDebug(qLcSoundEffect) << this << "sampleReady: sample size:" << m_sample->data().size(); |
86 | disconnect(sender: m_sample, signal: &QSample::error, receiver: this, slot: &QSoundEffectPrivate::decoderError); |
87 | disconnect(sender: m_sample, signal: &QSample::ready, receiver: this, slot: &QSoundEffectPrivate::sampleReady); |
88 | if (!m_audioOutput) { |
89 | m_audioOutput = new QAudioSink(m_audioDevice, m_sample->format()); |
90 | connect(sender: m_audioOutput, signal: &QAudioSink::stateChanged, context: this, slot: &QSoundEffectPrivate::stateChanged); |
91 | if (!m_muted) |
92 | m_audioOutput->setVolume(m_volume); |
93 | else |
94 | m_audioOutput->setVolume(0); |
95 | } |
96 | m_sampleReady = true; |
97 | setStatus(QSoundEffect::Ready); |
98 | |
99 | if (m_playing && m_audioOutput->state() == QAudio::StoppedState) { |
100 | qCDebug(qLcSoundEffect) << this << "starting playback on audiooutput" ; |
101 | m_audioOutput->start(device: this); |
102 | } |
103 | } |
104 | |
105 | void QSoundEffectPrivate::decoderError() |
106 | { |
107 | qWarning(msg: "QSoundEffect(qaudio): Error decoding source %ls" , qUtf16Printable(m_url.toString())); |
108 | disconnect(sender: m_sample, signal: &QSample::ready, receiver: this, slot: &QSoundEffectPrivate::sampleReady); |
109 | disconnect(sender: m_sample, signal: &QSample::error, receiver: this, slot: &QSoundEffectPrivate::decoderError); |
110 | m_playing = false; |
111 | setStatus(QSoundEffect::Error); |
112 | } |
113 | |
114 | void QSoundEffectPrivate::stateChanged(QAudio::State state) |
115 | { |
116 | qCDebug(qLcSoundEffect) << this << "stateChanged " << state; |
117 | if ((state == QAudio::IdleState && m_runningCount == 0) || state == QAudio::StoppedState) |
118 | q_ptr->stop(); |
119 | } |
120 | |
121 | qint64 QSoundEffectPrivate::readData(char *data, qint64 len) |
122 | { |
123 | qCDebug(qLcSoundEffect) << this << "readData" << len << m_runningCount; |
124 | if (!len) |
125 | return 0; |
126 | if (m_sample->state() != QSample::Ready) |
127 | return 0; |
128 | if (m_runningCount == 0 || !m_playing) |
129 | return 0; |
130 | |
131 | qint64 bytesWritten = 0; |
132 | |
133 | const int sampleSize = m_sample->data().size(); |
134 | const char* sampleData = m_sample->data().constData(); |
135 | |
136 | while (len && m_runningCount) { |
137 | int toWrite = qMin(a: sampleSize - m_offset, b: len); |
138 | memcpy(dest: data, src: sampleData + m_offset, n: toWrite); |
139 | bytesWritten += toWrite; |
140 | data += toWrite; |
141 | len -= toWrite; |
142 | m_offset += toWrite; |
143 | if (m_offset >= sampleSize) { |
144 | if (m_runningCount > 0 && m_runningCount != QSoundEffect::Infinite) |
145 | setLoopsRemaining(m_runningCount - 1); |
146 | m_offset = 0; |
147 | } |
148 | } |
149 | |
150 | return bytesWritten; |
151 | } |
152 | |
153 | qint64 QSoundEffectPrivate::writeData(const char *data, qint64 len) |
154 | { |
155 | Q_UNUSED(data); |
156 | Q_UNUSED(len); |
157 | return 0; |
158 | } |
159 | |
160 | void QSoundEffectPrivate::setLoopsRemaining(int loopsRemaining) |
161 | { |
162 | if (m_runningCount == loopsRemaining) |
163 | return; |
164 | qCDebug(qLcSoundEffect) << this << "setLoopsRemaining " << loopsRemaining; |
165 | m_runningCount = loopsRemaining; |
166 | emit q_ptr->loopsRemainingChanged(); |
167 | } |
168 | |
169 | void QSoundEffectPrivate::setStatus(QSoundEffect::Status status) |
170 | { |
171 | qCDebug(qLcSoundEffect) << this << "setStatus" << status; |
172 | if (m_status == status) |
173 | return; |
174 | bool oldLoaded = q_ptr->isLoaded(); |
175 | m_status = status; |
176 | emit q_ptr->statusChanged(); |
177 | if (oldLoaded != q_ptr->isLoaded()) |
178 | emit q_ptr->loadedChanged(); |
179 | } |
180 | |
181 | void QSoundEffectPrivate::setPlaying(bool playing) |
182 | { |
183 | qCDebug(qLcSoundEffect) << this << "setPlaying(" << playing << ")" << m_playing; |
184 | if (m_audioOutput) { |
185 | m_audioOutput->stop(); |
186 | if (playing && !m_sampleReady) |
187 | return; |
188 | } |
189 | |
190 | if (m_playing == playing) |
191 | return; |
192 | m_playing = playing; |
193 | |
194 | if (m_audioOutput && playing) |
195 | m_audioOutput->start(device: this); |
196 | |
197 | emit q_ptr->playingChanged(); |
198 | } |
199 | |
200 | /*! |
201 | \class QSoundEffect |
202 | \brief The QSoundEffect class provides a way to play low latency sound effects. |
203 | |
204 | \ingroup multimedia |
205 | \ingroup multimedia_audio |
206 | \inmodule QtMultimedia |
207 | |
208 | This class allows you to play uncompressed audio files (typically WAV files) in |
209 | a generally lower latency way, and is suitable for "feedback" type sounds in |
210 | response to user actions (e.g. virtual keyboard sounds, positive or negative |
211 | feedback for popup dialogs, or game sounds). If low latency is not important, |
212 | consider using the QMediaPlayer class instead, since it supports a wider |
213 | variety of media formats and is less resource intensive. |
214 | |
215 | This example shows how a looping, somewhat quiet sound effect |
216 | can be played: |
217 | |
218 | \snippet multimedia-snippets/qsound.cpp 2 |
219 | |
220 | Typically the sound effect should be reused, which allows all the |
221 | parsing and preparation to be done ahead of time, and only triggered |
222 | when necessary. This assists with lower latency audio playback. |
223 | |
224 | \snippet multimedia-snippets/qsound.cpp 3 |
225 | |
226 | Since QSoundEffect requires slightly more resources to achieve lower |
227 | latency playback, the platform may limit the number of simultaneously playing |
228 | sound effects. |
229 | */ |
230 | |
231 | |
232 | /*! |
233 | \qmltype SoundEffect |
234 | \instantiates QSoundEffect |
235 | \brief The SoundEffect type provides a way to play sound effects in QML. |
236 | |
237 | \inmodule QtMultimedia |
238 | \ingroup multimedia_qml |
239 | \ingroup multimedia_audio_qml |
240 | \inqmlmodule QtMultimedia |
241 | |
242 | This type allows you to play uncompressed audio files (typically WAV files) in |
243 | a generally lower latency way, and is suitable for "feedback" type sounds in |
244 | response to user actions (e.g. virtual keyboard sounds, positive or negative |
245 | feedback for popup dialogs, or game sounds). If low latency is not important, |
246 | consider using the MediaPlayer type instead, since it support a wider |
247 | variety of media formats and is less resource intensive. |
248 | |
249 | Typically the sound effect should be reused, which allows all the |
250 | parsing and preparation to be done ahead of time, and only triggered |
251 | when necessary. This is easy to achieve with QML, since you can declare your |
252 | SoundEffect instance and refer to it elsewhere. |
253 | |
254 | The following example plays a WAV file on mouse click. |
255 | |
256 | \snippet multimedia-snippets/soundeffect.qml complete snippet |
257 | |
258 | Since SoundEffect requires slightly more resources to achieve lower |
259 | latency playback, the platform may limit the number of simultaneously playing |
260 | sound effects. |
261 | */ |
262 | |
263 | /*! |
264 | Creates a QSoundEffect with the given \a parent. |
265 | */ |
266 | QSoundEffect::QSoundEffect(QObject *parent) |
267 | : QSoundEffect(QAudioDevice(), parent) |
268 | { |
269 | } |
270 | |
271 | /*! |
272 | Creates a QSoundEffect with the given \a audioDevice and \a parent. |
273 | */ |
274 | QSoundEffect::QSoundEffect(const QAudioDevice &audioDevice, QObject *parent) |
275 | : QObject(parent) |
276 | , d(new QSoundEffectPrivate(this, audioDevice)) |
277 | { |
278 | } |
279 | |
280 | /*! |
281 | Destroys this sound effect. |
282 | */ |
283 | QSoundEffect::~QSoundEffect() |
284 | { |
285 | stop(); |
286 | if (d->m_audioOutput) { |
287 | d->m_audioOutput->stop(); |
288 | d->m_audioOutput->deleteLater(); |
289 | d->m_sample->release(); |
290 | } |
291 | delete d; |
292 | } |
293 | |
294 | /*! |
295 | \fn QSoundEffect::supportedMimeTypes() |
296 | |
297 | Returns a list of the supported mime types for this platform. |
298 | */ |
299 | QStringList QSoundEffect::supportedMimeTypes() |
300 | { |
301 | // Only return supported mime types if we have a audio device available |
302 | const QList<QAudioDevice> devices = QMediaDevices::audioOutputs(); |
303 | if (devices.isEmpty()) |
304 | return QStringList(); |
305 | |
306 | return QStringList() << QLatin1String("audio/x-wav" ) |
307 | << QLatin1String("audio/wav" ) |
308 | << QLatin1String("audio/wave" ) |
309 | << QLatin1String("audio/x-pn-wav" ); |
310 | } |
311 | |
312 | /*! |
313 | \qmlproperty url QtMultimedia::SoundEffect::source |
314 | |
315 | This property holds the url for the sound to play. For the SoundEffect |
316 | to attempt to load the source, the URL must exist and the application must have read permission |
317 | in the specified directory. If the desired source is a local file the URL may be specified |
318 | using either absolute or relative (to the file that declared the SoundEffect) pathing. |
319 | */ |
320 | /*! |
321 | \property QSoundEffect::source |
322 | |
323 | This property holds the url for the sound to play. For the SoundEffect |
324 | to attempt to load the source, the URL must exist and the application must have read permission |
325 | in the specified directory. |
326 | */ |
327 | |
328 | /*! Returns the URL of the current source to play */ |
329 | QUrl QSoundEffect::source() const |
330 | { |
331 | return d->m_url; |
332 | } |
333 | |
334 | /*! Set the current URL to play to \a url. */ |
335 | void QSoundEffect::setSource(const QUrl &url) |
336 | { |
337 | qCDebug(qLcSoundEffect) << this << "setSource current=" << d->m_url << ", to=" << url; |
338 | if (d->m_url == url) |
339 | return; |
340 | |
341 | Q_ASSERT(d->m_url != url); |
342 | |
343 | stop(); |
344 | |
345 | d->m_url = url; |
346 | |
347 | d->m_sampleReady = false; |
348 | |
349 | if (url.isEmpty()) { |
350 | d->setStatus(QSoundEffect::Null); |
351 | return; |
352 | } |
353 | |
354 | if (!url.isValid()) { |
355 | d->setStatus(QSoundEffect::Error); |
356 | return; |
357 | } |
358 | |
359 | if (d->m_sample) { |
360 | if (!d->m_sampleReady) { |
361 | QObject::disconnect(sender: d->m_sample, signal: &QSample::error, receiver: d, slot: &QSoundEffectPrivate::decoderError); |
362 | QObject::disconnect(sender: d->m_sample, signal: &QSample::ready, receiver: d, slot: &QSoundEffectPrivate::sampleReady); |
363 | } |
364 | d->m_sample->release(); |
365 | d->m_sample = nullptr; |
366 | } |
367 | |
368 | if (d->m_audioOutput) { |
369 | QObject::disconnect(sender: d->m_audioOutput, signal: &QAudioSink::stateChanged, receiver: d, slot: &QSoundEffectPrivate::stateChanged); |
370 | d->m_audioOutput->stop(); |
371 | d->m_audioOutput->deleteLater(); |
372 | d->m_audioOutput = nullptr; |
373 | } |
374 | |
375 | d->setStatus(QSoundEffect::Loading); |
376 | d->m_sample = sampleCache()->requestSample(url); |
377 | QObject::connect(sender: d->m_sample, signal: &QSample::error, context: d, slot: &QSoundEffectPrivate::decoderError); |
378 | QObject::connect(sender: d->m_sample, signal: &QSample::ready, context: d, slot: &QSoundEffectPrivate::sampleReady); |
379 | |
380 | switch (d->m_sample->state()) { |
381 | case QSample::Ready: |
382 | d->sampleReady(); |
383 | break; |
384 | case QSample::Error: |
385 | d->decoderError(); |
386 | break; |
387 | default: |
388 | break; |
389 | } |
390 | |
391 | emit sourceChanged(); |
392 | } |
393 | |
394 | /*! |
395 | \qmlproperty int QtMultimedia::SoundEffect::loops |
396 | |
397 | This property holds the number of times the sound is played. A value of 0 or 1 means |
398 | the sound will be played only once; set to SoundEffect.Infinite to enable infinite looping. |
399 | |
400 | The value can be changed while the sound effect is playing, in which case it will update |
401 | the remaining loops to the new value. |
402 | */ |
403 | |
404 | /*! |
405 | \property QSoundEffect::loops |
406 | This property holds the number of times the sound is played. A value of 0 or 1 means |
407 | the sound will be played only once; set to SoundEffect.Infinite to enable infinite looping. |
408 | |
409 | The value can be changed while the sound effect is playing, in which case it will update |
410 | the remaining loops to the new value. |
411 | */ |
412 | |
413 | /*! |
414 | Returns the total number of times that this sound effect will be played before stopping. |
415 | |
416 | See the \l loopsRemaining() method for the number of loops currently remaining. |
417 | */ |
418 | int QSoundEffect::loopCount() const |
419 | { |
420 | return d->m_loopCount; |
421 | } |
422 | |
423 | /*! |
424 | \enum QSoundEffect::Loop |
425 | |
426 | \value Infinite Used as a parameter to \l setLoopCount() for infinite looping |
427 | */ |
428 | |
429 | /*! |
430 | Set the total number of times to play this sound effect to \a loopCount. |
431 | |
432 | Setting the loop count to 0 or 1 means the sound effect will be played only once; |
433 | pass \c QSoundEffect::Infinite to repeat indefinitely. The loop count can be changed while |
434 | the sound effect is playing, in which case it will update the remaining loops to |
435 | the new \a loopCount. |
436 | |
437 | \sa loopsRemaining() |
438 | */ |
439 | void QSoundEffect::setLoopCount(int loopCount) |
440 | { |
441 | if (loopCount < 0 && loopCount != Infinite) { |
442 | qWarning(msg: "SoundEffect: loops should be SoundEffect.Infinite, 0 or positive integer" ); |
443 | return; |
444 | } |
445 | if (loopCount == 0) |
446 | loopCount = 1; |
447 | if (d->m_loopCount == loopCount) |
448 | return; |
449 | |
450 | d->m_loopCount = loopCount; |
451 | if (d->m_playing) |
452 | d->setLoopsRemaining(loopCount); |
453 | emit loopCountChanged(); |
454 | } |
455 | |
456 | /*! |
457 | \property QSoundEffect::audioDevice |
458 | |
459 | Returns the QAudioDevice instance. |
460 | */ |
461 | QAudioDevice QSoundEffect::audioDevice() |
462 | { |
463 | return d->m_audioDevice; |
464 | } |
465 | |
466 | void QSoundEffect::setAudioDevice(const QAudioDevice &device) |
467 | { |
468 | if (d->m_audioDevice == device) |
469 | return; |
470 | // ### recreate the QAudioSink if needed |
471 | d->m_audioDevice = device; |
472 | emit audioDeviceChanged(); |
473 | } |
474 | |
475 | /*! |
476 | \qmlproperty int QtMultimedia::SoundEffect::loopsRemaining |
477 | |
478 | This property contains the number of loops remaining before the sound effect |
479 | stops by itself, or SoundEffect.Infinite if that's what has been set in \l loops. |
480 | */ |
481 | /*! |
482 | \property QSoundEffect::loopsRemaining |
483 | |
484 | This property contains the number of loops remaining before the sound effect |
485 | stops by itself, or QSoundEffect::Infinite if that's what has been set in \l loops. |
486 | */ |
487 | int QSoundEffect::loopsRemaining() const |
488 | { |
489 | return d->m_runningCount; |
490 | } |
491 | |
492 | |
493 | /*! |
494 | \qmlproperty qreal QtMultimedia::SoundEffect::volume |
495 | |
496 | This property holds the volume of the sound effect playback. |
497 | |
498 | The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this |
499 | range will be clamped. |
500 | |
501 | The default volume is \c 1.0. |
502 | |
503 | UI volume controls should usually be scaled non-linearly. For example, using a logarithmic scale |
504 | will produce linear changes in perceived loudness, which is what a user would normally expect |
505 | from a volume control. See \l {QAudio::convertVolume()}{convertVolume()} |
506 | for more details. |
507 | */ |
508 | /*! |
509 | \property QSoundEffect::volume |
510 | |
511 | This property holds the volume of the sound effect playback, from 0.0 (silence) to 1.0 (full volume). |
512 | */ |
513 | |
514 | /*! |
515 | Returns the current volume of this sound effect, from 0.0 (silent) to 1.0 (maximum volume). |
516 | */ |
517 | float QSoundEffect::volume() const |
518 | { |
519 | if (d->m_audioOutput && !d->m_muted) |
520 | return d->m_audioOutput->volume(); |
521 | |
522 | return d->m_volume; |
523 | } |
524 | |
525 | /*! |
526 | Sets the sound effect volume to \a volume. |
527 | |
528 | The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this |
529 | range will be clamped. |
530 | |
531 | The default volume is \c 1.0. |
532 | |
533 | UI volume controls should usually be scaled non-linearly. For example, using a logarithmic scale |
534 | will produce linear changes in perceived loudness, which is what a user would normally expect |
535 | from a volume control. See QAudio::convertVolume() for more details. |
536 | */ |
537 | void QSoundEffect::setVolume(float volume) |
538 | { |
539 | volume = qBound(min: 0.0f, val: volume, max: 1.0f); |
540 | if (d->m_volume == volume) |
541 | return; |
542 | |
543 | d->m_volume = volume; |
544 | |
545 | if (d->m_audioOutput && !d->m_muted) |
546 | d->m_audioOutput->setVolume(volume); |
547 | |
548 | emit volumeChanged(); |
549 | } |
550 | |
551 | /*! |
552 | \qmlproperty bool QtMultimedia::SoundEffect::muted |
553 | |
554 | This property provides a way to control muting. A value of \c true will mute this effect. |
555 | Otherwise, playback will occur with the currently specified \l volume. |
556 | */ |
557 | /*! |
558 | \property QSoundEffect::muted |
559 | |
560 | This property provides a way to control muting. A value of \c true will mute this effect. |
561 | */ |
562 | |
563 | /*! Returns whether this sound effect is muted */ |
564 | bool QSoundEffect::isMuted() const |
565 | { |
566 | return d->m_muted; |
567 | } |
568 | |
569 | /*! |
570 | Sets whether to mute this sound effect's playback. |
571 | |
572 | If \a muted is true, playback will be muted (silenced), |
573 | and otherwise playback will occur with the currently |
574 | specified volume(). |
575 | */ |
576 | void QSoundEffect::setMuted(bool muted) |
577 | { |
578 | if (d->m_muted == muted) |
579 | return; |
580 | |
581 | if (muted && d->m_audioOutput) |
582 | d->m_audioOutput->setVolume(0); |
583 | else if (!muted && d->m_audioOutput && d->m_muted) |
584 | d->m_audioOutput->setVolume(d->m_volume); |
585 | |
586 | d->m_muted = muted; |
587 | emit mutedChanged(); |
588 | } |
589 | |
590 | /*! |
591 | \fn QSoundEffect::isLoaded() const |
592 | |
593 | Returns whether the sound effect has finished loading the \l source(). |
594 | */ |
595 | /*! |
596 | \qmlmethod bool QtMultimedia::SoundEffect::isLoaded() |
597 | |
598 | Returns whether the sound effect has finished loading the \l source. |
599 | */ |
600 | bool QSoundEffect::isLoaded() const |
601 | { |
602 | return d->m_status == QSoundEffect::Ready; |
603 | } |
604 | |
605 | /*! |
606 | \qmlmethod QtMultimedia::SoundEffect::play() |
607 | |
608 | Start playback of the sound effect, looping the effect for the number of |
609 | times as specified in the loops property. |
610 | |
611 | This is the default method for SoundEffect. |
612 | |
613 | \snippet multimedia-snippets/soundeffect.qml play sound on click |
614 | */ |
615 | /*! |
616 | \fn QSoundEffect::play() |
617 | |
618 | Start playback of the sound effect, looping the effect for the number of |
619 | times as specified in the loops property. |
620 | */ |
621 | void QSoundEffect::play() |
622 | { |
623 | d->m_offset = 0; |
624 | d->setLoopsRemaining(d->m_loopCount); |
625 | qCDebug(qLcSoundEffect) << this << "play" << d->m_loopCount << d->m_runningCount; |
626 | if (d->m_status == QSoundEffect::Null || d->m_status == QSoundEffect::Error) { |
627 | d->setStatus(QSoundEffect::Null); |
628 | return; |
629 | } |
630 | d->setPlaying(true); |
631 | } |
632 | |
633 | /*! |
634 | \qmlproperty bool QtMultimedia::SoundEffect::playing |
635 | |
636 | This property indicates whether the sound effect is playing or not. |
637 | */ |
638 | /*! |
639 | \property QSoundEffect::playing |
640 | |
641 | This property indicates whether the sound effect is playing or not. |
642 | */ |
643 | |
644 | /*! Returns true if the sound effect is currently playing, or false otherwise */ |
645 | bool QSoundEffect::isPlaying() const |
646 | { |
647 | return d->m_playing; |
648 | } |
649 | |
650 | /*! |
651 | \enum QSoundEffect::Status |
652 | |
653 | \value Null No source has been set or the source is null. |
654 | \value Loading The SoundEffect is trying to load the source. |
655 | \value Ready The source is loaded and ready for play. |
656 | \value Error An error occurred during operation, such as failure of loading the source. |
657 | |
658 | */ |
659 | |
660 | /*! |
661 | \qmlproperty enumeration QtMultimedia::SoundEffect::status |
662 | |
663 | This property indicates the current status of the SoundEffect |
664 | as enumerated within SoundEffect. |
665 | Possible statuses are listed below. |
666 | |
667 | \table |
668 | \header \li Value \li Description |
669 | \row \li SoundEffect.Null \li No source has been set or the source is null. |
670 | \row \li SoundEffect.Loading \li The SoundEffect is trying to load the source. |
671 | \row \li SoundEffect.Ready \li The source is loaded and ready for play. |
672 | \row \li SoundEffect.Error \li An error occurred during operation, such as failure of loading the source. |
673 | \endtable |
674 | */ |
675 | /*! |
676 | \property QSoundEffect::status |
677 | |
678 | This property indicates the current status of the sound effect |
679 | from the \l QSoundEffect::Status enumeration. |
680 | */ |
681 | |
682 | /*! |
683 | Returns the current status of this sound effect. |
684 | */ |
685 | QSoundEffect::Status QSoundEffect::status() const |
686 | { |
687 | return d->m_status; |
688 | } |
689 | |
690 | /*! |
691 | \qmlmethod QtMultimedia::SoundEffect::stop() |
692 | |
693 | Stop current playback. |
694 | |
695 | */ |
696 | /*! |
697 | \fn QSoundEffect::stop() |
698 | |
699 | Stop current playback. |
700 | |
701 | */ |
702 | void QSoundEffect::stop() |
703 | { |
704 | if (!d->m_playing) |
705 | return; |
706 | qCDebug(qLcSoundEffect) << "stop()" ; |
707 | d->m_offset = 0; |
708 | |
709 | d->setPlaying(false); |
710 | } |
711 | |
712 | /* Signals */ |
713 | |
714 | /*! |
715 | \fn void QSoundEffect::sourceChanged() |
716 | |
717 | The \c sourceChanged signal is emitted when the source has been changed. |
718 | */ |
719 | /*! |
720 | \qmlsignal QtMultimedia::SoundEffect::sourceChanged() |
721 | |
722 | The \c sourceChanged signal is emitted when the source has been changed. |
723 | */ |
724 | /*! |
725 | \fn void QSoundEffect::loadedChanged() |
726 | |
727 | The \c loadedChanged signal is emitted when the loading state has changed. |
728 | */ |
729 | /*! |
730 | \qmlsignal QtMultimedia::SoundEffect::loadedChanged() |
731 | |
732 | The \c loadedChanged signal is emitted when the loading state has changed. |
733 | */ |
734 | |
735 | /*! |
736 | \fn void QSoundEffect::loopCountChanged() |
737 | |
738 | The \c loopCountChanged signal is emitted when the initial number of loops has changed. |
739 | */ |
740 | /*! |
741 | \qmlsignal QtMultimedia::SoundEffect::loopCountChanged() |
742 | |
743 | The \c loopCountChanged signal is emitted when the initial number of loops has changed. |
744 | */ |
745 | |
746 | /*! |
747 | \fn void QSoundEffect::loopsRemainingChanged() |
748 | |
749 | The \c loopsRemainingChanged signal is emitted when the remaining number of loops has changed. |
750 | */ |
751 | /*! |
752 | \qmlsignal QtMultimedia::SoundEffect::loopsRemainingChanged() |
753 | |
754 | The \c loopsRemainingChanged signal is emitted when the remaining number of loops has changed. |
755 | */ |
756 | |
757 | /*! |
758 | \fn void QSoundEffect::volumeChanged() |
759 | |
760 | The \c volumeChanged signal is emitted when the volume has changed. |
761 | */ |
762 | /*! |
763 | \qmlsignal QtMultimedia::SoundEffect::volumeChanged() |
764 | |
765 | The \c volumeChanged signal is emitted when the volume has changed. |
766 | */ |
767 | |
768 | /*! |
769 | \fn void QSoundEffect::mutedChanged() |
770 | |
771 | The \c mutedChanged signal is emitted when the mute state has changed. |
772 | */ |
773 | /*! |
774 | \qmlsignal QtMultimedia::SoundEffect::mutedChanged() |
775 | |
776 | The \c mutedChanged signal is emitted when the mute state has changed. |
777 | */ |
778 | |
779 | /*! |
780 | \fn void QSoundEffect::playingChanged() |
781 | |
782 | The \c playingChanged signal is emitted when the playing property has changed. |
783 | */ |
784 | /*! |
785 | \qmlsignal QtMultimedia::SoundEffect::playingChanged() |
786 | |
787 | The \c playingChanged signal is emitted when the playing property has changed. |
788 | */ |
789 | |
790 | /*! |
791 | \fn void QSoundEffect::statusChanged() |
792 | |
793 | The \c statusChanged signal is emitted when the status property has changed. |
794 | */ |
795 | /*! |
796 | \qmlsignal QtMultimedia::SoundEffect::statusChanged() |
797 | |
798 | The \c statusChanged signal is emitted when the status property has changed. |
799 | */ |
800 | |
801 | QT_END_NAMESPACE |
802 | |
803 | #include "moc_qsoundeffect.cpp" |
804 | |