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
qsoundeffectwithplayer.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 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
5
6#include <QtCore/qmutex.h>
7#include <QtCore/q20map.h>
8
9#include <utility>
10
11QT_BEGIN_NAMESPACE
12
13namespace QtMultimediaPrivate {
14
15namespace {
16
17QSpan<const float> toFloatSpan(QSpan<const char> byteArray)
18{
19 return QSpan{
20 reinterpret_cast<const float *>(byteArray.data()),
21 qsizetype(byteArray.size_bytes() / sizeof(float)),
22 };
23}
24
25} // namespace
26
27///////////////////////////////////////////////////////////////////////////////////////////////////
28
29QSoundEffectVoice::QSoundEffectVoice(VoiceId voiceId, std::shared_ptr<const QSample> sample,
30 float volume, bool muted, int totalLoopCount)
33 m_volume{ volume },
34 m_muted{ muted },
36{
37}
38
40{
44
47
49
50 // later: (auto)vectorize?
52 if (m_muted || m_volume == 0.f) {
55 } else if (m_volume == 1.f) {
56 for (qsizetype i = 0; i != samplesToPlay; ++i)
58 } else {
59 for (qsizetype i = 0; i != samplesToPlay; ++i)
61 }
62
64
68
69 if (!isInfiniteLoop)
71
72 if (continuePlaying) {
73 if (!isInfiniteLoop)
78 }
80 }
82}
83
85{
87 return true;
88
89 return loopsRemaining() != 0;
90}
91
93{
96
97 // caveat: reading frame is not atomic, so we may have a race here ... is is rare, though,
98 // not sure if we really care
100 return clone;
101}
102
103///////////////////////////////////////////////////////////////////////////////////////////////////
104
121
126
128{
129 if (device == m_audioDevice)
130 return false;
131
134 return true;
135}
136
138{
140 return;
141
143
144 if (!m_player)
145 return;
146
147 for (const auto &voice : m_voices)
149
152 };
153 m_voices.clear();
154
155 bool hasPlayer = updatePlayer();
156 if (!hasPlayer)
157 return;
158
159 for (const auto &voice : voices)
160 // we re-allocate a new voice ID and play on the new player
161 play(voice->clone());
162}
163
165{
166 if (m_audioDevice.isNull())
169}
170
175
177{
180
181 m_url = url;
182 m_sample = {};
183
184 if (url.isEmpty()) {
186 return false;
187 }
188
189 if (!url.isValid()) {
191 return false;
192 }
193
195
198 if (result) {
200 qWarning("QSoundEffect: QSoundEffect only supports mono or stereo files");
202 return;
203 }
204
207 bool hasPlayer = updatePlayer();
208 if (std::exchange(m_playPending, false)) {
209 if (hasPlayer)
210 play();
211 }
212 } else {
213 qWarning("QSoundEffect: Error decoding source %ls", qUtf16Printable(m_url.toString()));
215 }
216 });
217
218 return true;
219}
220
222{
223 return m_url;
224}
225
227{
228 if (status == m_status)
229 return;
232}
233
238
240{
241 return m_loopCount;
242}
243
245{
246 if (loopCount == 0)
247 loopCount = 1;
248
249 if (loopCount == m_loopCount)
250 return false;
251
253
254 if (m_voices.empty())
255 return true;
256
259
261
262 return true;
263}
264
266{
267 if (m_voices.empty())
268 return 0;
269
270 return m_loopsRemaining;
271}
272
274{
275 return m_volume;
276}
277
279{
280 if (m_volume == volume)
281 return false;
282
284 for (const auto &voice : m_voices) {
287 });
288 }
289 return true;
290}
291
293{
294 return m_muted;
295}
296
298{
299 if (m_muted == muted)
300 return false;
301
302 m_muted = muted;
303 for (const auto &voice : m_voices) {
306 });
307 }
308 return true;
309}
310
312{
313 if (!m_sample) {
314 m_playPending = true;
315 return;
316 }
317
318 // each `play` will start a new voice
320
323
324 play(std::move(voice));
325}
326
328{
330 for (const auto &voice : m_voices)
333
334 m_voices.clear();
335 m_playPending = false;
336 if (activeVoices)
338}
339
341{
342 return !m_voices.empty();
343}
344
346{
348 [this, voiceId = voice->voiceId()] {
350 if (foundVoice == m_voices.end())
351 return;
352
353 if (voiceId != activeVoice())
354 return;
355
357 });
358
362 if (m_voices.size() == 1)
364}
365
367{
370
371 m_player = {};
373 return false;
374
377
379 this, [this](VoiceId voiceId) {
380 if (voiceId == activeVoice())
382
383 auto found = m_voices.find(voiceId);
384 if (found != m_voices.end()) {
386 if (m_voices.empty())
388 }
389 });
390 return true;
391}
392
394{
395 if (m_voices.empty())
396 return std::nullopt;
397 return (*m_voices.rbegin())->voiceId();
398}
399
401{
402 switch (fmt.channelCount()) {
403 case 1:
404 case 2:
405 return true;
406 default:
407 return false;
408 }
409}
410
412{
414 return;
417}
418
419} // namespace QtMultimediaPrivate
420
421QT_END_NAMESPACE
QSoundEffectVoice(VoiceId voiceId, std::shared_ptr< const QSample > sample, float volume, bool muted, int totalLoopCount)