Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qambientsound.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-3.0-only
3#include "qambientsound.h"
4#include "qambientsound_p.h"
5#include "qaudioengine_p.h"
6#include "resonance_audio.h"
7#include <qaudiosink.h>
8#include <qurl.h>
9#include <qdebug.h>
10#include <qaudiodecoder.h>
11
13
15{
16 decoder.reset(new QAudioDecoder);
17 buffers.clear();
18 currentBuffer = 0;
19 sourceDeviceFile.reset(nullptr);
20 bufPos = 0;
21 m_playing = false;
22 m_loading = true;
26 f.setSampleRate(ep->sampleRate);
28 decoder->setAudioFormat(f);
29 if (url.scheme().compare(u"qrc", Qt::CaseInsensitive) == 0) {
30 auto qrcFile = std::make_unique<QFile>(u':' + url.path());
31 if (!qrcFile->open(QFile::ReadOnly))
32 return;
33 sourceDeviceFile = std::move(qrcFile);
34 decoder->setSourceDevice(sourceDeviceFile.get());
35 } else {
36 decoder->setSource(url);
37 }
38 connect(decoder.get(), &QAudioDecoder::bufferReady, this, &QAmbientSoundPrivate::bufferReady);
39 connect(decoder.get(), &QAudioDecoder::finished, this, &QAmbientSoundPrivate::finished);
40 decoder->start();
41}
42
43void QAmbientSoundPrivate::getBuffer(float *buf, int nframes, int channels)
44{
45 Q_ASSERT(channels == nchannels);
47 if (!m_playing || currentBuffer >= buffers.size()) {
48 memset(buf, 0, channels * nframes * sizeof(float));
49 } else {
50 int frames = nframes;
51 float *ff = buf;
52 while (frames) {
53 if (currentBuffer < buffers.size()) {
55 // qDebug() << s << b.format().sampleRate() << b.format().channelCount() << b.format().sampleFormat();
56 auto *f = b.constData<float>() + bufPos*nchannels;
57 int toCopy = qMin(b.frameCount() - bufPos, frames);
58 memcpy(ff, f, toCopy*sizeof(float)*nchannels);
59 ff += toCopy*nchannels;
60 frames -= toCopy;
61 bufPos += toCopy;
62 Q_ASSERT(bufPos <= b.frameCount());
63 if (bufPos == b.frameCount()) {
65 bufPos = 0;
66 }
67 } else {
68 // no more data available
69 if (m_loading)
70 qDebug() << "underrun" << frames << "frames when loading" << url;
71 memset(ff, 0, frames * channels * sizeof(float));
72 ff += frames * channels;
73 frames = 0;
74 }
75 if (!m_loading) {
76 if (currentBuffer == buffers.size()) {
77 currentBuffer = 0;
79 }
80 if (m_loops > 0 && m_currentLoop >= m_loops) {
81 m_playing = false;
82 m_currentLoop = 0;
83 }
84 }
85 }
86 Q_ASSERT(ff - buf == channels*nframes);
87 }
88}
89
90void QAmbientSoundPrivate::bufferReady()
91{
93 auto b = decoder->read();
94 // qDebug() << "read buffer" << b.format() << b.startTime() << b.duration();
95 buffers.append(b);
96 if (m_autoPlay)
97 m_playing = true;
98}
99
100void QAmbientSoundPrivate::finished()
101{
102 m_loading = false;
103}
104
126
128{
129 setEngine(nullptr);
130 delete d;
131}
132
141void QAmbientSound::setVolume(float volume)
142{
143 if (d->volume == volume)
144 return;
145 d->volume = volume;
146 auto *ep = QAudioEnginePrivate::get(d->engine);
147 if (ep)
148 ep->resonanceAudio->api->SetSourceVolume(d->sourceId, d->volume);
150}
151
153{
154 return d->volume;
155}
156
158{
159 if (d->url == url)
160 return;
161 d->url = url;
162
163 d->load();
165}
166
173{
174 return d->url;
175}
194{
195 return d->m_loops.loadRelaxed();
196}
197
199{
200 int oldLoops = d->m_loops.fetchAndStoreRelaxed(loops);
201 if (oldLoops != loops)
203}
204
214{
215 return d->m_autoPlay.loadRelaxed();
216}
217
218void QAmbientSound::setAutoPlay(bool autoPlay)
219{
221 if (old != autoPlay)
223}
224
229{
230 d->play();
231}
232
237{
238 d->pause();
239}
240
246{
247 d->stop();
248}
249
253void QAmbientSound::setEngine(QAudioEngine *engine)
254{
255 if (d->engine == engine)
256 return;
257
258 // Remove self from old engine (if necessary)
259 auto *ep = QAudioEnginePrivate::get(d->engine);
260 if (ep)
261 ep->removeStereoSound(this);
262
263 d->engine = engine;
264
265 // Add self to new engine if necessary
267 if (ep) {
268 ep->addStereoSound(this);
269 ep->resonanceAudio->api->SetSourceVolume(d->sourceId, d->volume);
270 }
271}
272
277{
278 return d->engine;
279}
280
282
283#include "moc_qambientsound.cpp"
std::unique_ptr< QAudioDecoder > decoder
QAtomicInteger< bool > m_playing
QAudioEngine * engine
QAtomicInteger< bool > m_autoPlay
void getBuffer(float *buf, int frames, int channels)
std::unique_ptr< QFile > sourceDeviceFile
void setAutoPlay(bool autoPlay)
void volumeChanged()
QAmbientSound(QAudioEngine *engine)
Creates a stereo sound source for engine.
void pause()
Pauses sound playback.
void setLoops(int loops)
void play()
Starts playing back the sound.
QAudioEngine * engine() const
Returns the engine associated with this sound.
void loopsChanged()
int loops
Determines how many times the sound is played before the player stops.
float volume
Defines the volume of the sound.
bool autoPlay
Determines whether the sound should automatically start playing when a source gets specified.
void sourceChanged()
void autoPlayChanged()
void setSource(const QUrl &url)
QUrl source
The source file for the sound to be played.
void stop()
Stops sound playback and resets the current position and current loop count to 0.
void setVolume(float volume)
\inmodule QtMultimedia
const T * constData() const
Returns a pointer to this buffer's data.
The QAudioDecoder class implements decoding audio.
void bufferReady()
Signals that a new decoded audio buffer is available to be read.
void finished()
Signals that the decoding has finished successfully.
static QAudioEnginePrivate * get(QAudioEngine *engine)
\inmodule QtSpatialAudio
The QAudioFormat class stores audio stream parameter information.
constexpr void setSampleFormat(SampleFormat f) noexcept
Sets the sample format to format.
T fetchAndStoreRelaxed(T newValue) noexcept
T loadRelaxed() const noexcept
\inmodule QtCore
Definition qmutex.h:313
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.cpp:6664
\inmodule QtCore
Definition qurl.h:94
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1991
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
Definition qurl.cpp:2468
#define this
Definition dialogs.cpp:9
Combined button and popup list for selecting options.
@ CaseInsensitive
#define qDebug
[1]
Definition qlogging.h:164
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLboolean GLboolean GLboolean b
GLuint const GLuint * buffers
GLfloat GLfloat f
GLenum GLuint GLenum GLsizei const GLchar * buf
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define emit
QUrl url("example.com")
[constructor-url-reference]
QJSEngine engine
[0]