6#include <QtCore/qiodevice.h>
7#include <QtCore/qdebug.h>
8#include <QtCore/qelapsedtimer.h>
10#include <QtMultimedia/qaudiodecoder.h>
11#include <QtMultimedia/qmediadevices.h>
12#include <QtMultimedia/qaudiosink.h>
14# include <QtMultimedia/private/qwindows_wasapi_warmup_client_p.h>
17#include <QtSpatialAudio/private/qambientsound_p.h>
18#include <QtSpatialAudio/private/qspatialsound_p.h>
19#include <QtSpatialAudio/private/qaudioroom_p.h>
20#include <QtSpatialAudio/private/qambisonicdecoder_p.h>
21#include <QtSpatialAudio/qambientsound.h>
22#include <QtSpatialAudio/qaudiolistener.h>
24#include <resonance_audio.h>
41 open(QIODevice::ReadOnly);
51 return std::numeric_limits<qint64>::max();
68 auto channelConfig = d->outputMode == QAudioEngine::Surround ?
69 d->device.channelConfiguration() : QAudioFormat::ChannelConfigStereo;
70 if (channelConfig != QAudioFormat::ChannelConfigUnknown)
71 format.setChannelConfig(channelConfig);
73 format.setChannelCount(d->device.preferredFormat().channelCount());
75 format.setSampleFormat(QAudioFormat::Int16);
76 ambisonicDecoder.reset(
new QAmbisonicDecoder(QAmbisonicDecoder::HighQuality, format));
77 sink.reset(
new QAudioSink(d->device, format));
78 const qsizetype bufferSize = format.bytesForDuration(bufferTimeMs * 1000);
79 sink->setBufferSize(bufferSize);
86 QtMultimediaPrivate::refreshWarmupClient();
96 ambisonicDecoder.reset();
115 std::unique_ptr<QAudioSink> sink;
116 std::unique_ptr<QAmbisonicDecoder> ambisonicDecoder;
131 if (d->paused.loadRelaxed())
134 QMutexLocker l(&d->mutex);
137 int nChannels = ambisonicDecoder ? ambisonicDecoder->nOutputChannels() : 2;
141 short *fd = (
short *)data;
142 qint64 frames = len / nChannels /
sizeof(
short);
146 for (
auto *source : std::as_const(d->sources)) {
147 auto *sp = QSpatialSoundPrivate::get(source);
150 float buf[QAudioEnginePrivate::bufferSize];
151 sp->getBuffer(buf, QAudioEnginePrivate::bufferSize, 1);
152 d->resonanceAudio->api->SetInterleavedBuffer(sp->sourceId, buf, 1, QAudioEnginePrivate::bufferSize);
154 for (
auto *source : std::as_const(d->stereoSources)) {
155 auto *sp = QAmbientSoundPrivate::get(source);
158 float buf[2*QAudioEnginePrivate::bufferSize];
159 sp->getBuffer(buf, QAudioEnginePrivate::bufferSize, 2);
160 d->resonanceAudio->api->SetInterleavedBuffer(sp->sourceId, buf, 2, QAudioEnginePrivate::bufferSize);
163 if (ambisonicDecoder && d->outputMode == QAudioEngine::Surround) {
164 const float *channels[QAmbisonicDecoder::maxAmbisonicChannels];
165 const float *reverbBuffers[2];
166 int nSamples = d->resonanceAudio->getAmbisonicOutput(channels, reverbBuffers, ambisonicDecoder->nInputChannels());
167 Q_ASSERT(ambisonicDecoder->nOutputChannels() <= 8);
168 ambisonicDecoder->processBufferWithReverb(channels, reverbBuffers, fd, nSamples);
175 if (d->sources.isEmpty() && d->stereoSources.isEmpty()) {
179 qWarning() <<
" Reading failed!";
187 const int bytesProcessed = ((
char *)fd - data);
188 m_pos += bytesProcessed;
189 return bytesProcessed;
194 audioThread.setObjectName(u"QAudioThread");
195 device = QMediaDevices::defaultAudioOutput();
209 resonanceAudio->api->SetStereoSpeakerMode(outputMode != QAudioEngine::Headphone);
210 resonanceAudio->api->SetMasterVolume(masterVolume);
212 outputStream = std::make_unique<QAudioOutputStream>(
this);
213 outputStream->moveToThread(&audioThread);
214 audioThread.start(QThread::TimeCriticalPriority);
216 QMetaObject::invokeMethod(outputStream.get(), &QAudioOutputStream::startOutput);
221 QMetaObject::invokeMethod(outputStream.get(), &QAudioOutputStream::stopOutput,
222 Qt::BlockingQueuedConnection);
223 outputStream.reset();
230 bool old =
this->paused.fetchAndStoreRelaxed(paused);
233 outputStream->setPaused(paused);
234 emit q->pausedChanged();
240 if (
this->device == device)
242 if (resonanceAudio->api) {
243 qWarning() <<
"Changing device on a running engine not implemented";
246 this->device = device;
247 emit q->outputDeviceChanged();
252 if (outputMode == mode)
255 if (resonanceAudio->api)
256 resonanceAudio->api->SetStereoSpeakerMode(mode != QAudioEngine::Headphone);
258 QMetaObject::invokeMethod(outputStream.get(), &QAudioOutputStream::restartOutput,
259 Qt::BlockingQueuedConnection);
261 emit q->outputModeChanged();
266 QMutexLocker l(&mutex);
267 QAmbientSoundPrivate *sd = QAmbientSoundPrivate::get(sound);
269 sd->sourceId = resonanceAudio->api->CreateSoundObjectSource(vraudio::kBinauralHighQuality);
270 sources.append(sound);
275 QMutexLocker l(&mutex);
276 QAmbientSoundPrivate *sd = QAmbientSoundPrivate::get(sound);
278 resonanceAudio->api->DestroySource(sd->sourceId);
279 sd->sourceId = vraudio::ResonanceAudioApi::kInvalidSourceId;
280 sources.removeOne(sound);
285 QMutexLocker l(&mutex);
286 QAmbientSoundPrivate *sd = QAmbientSoundPrivate::get(sound);
288 sd->sourceId = resonanceAudio->api->CreateStereoSource(2);
289 stereoSources.append(sound);
294 QMutexLocker l(&mutex);
295 QAmbientSoundPrivate *sd = QAmbientSoundPrivate::get(sound);
297 resonanceAudio->api->DestroySource(sd->sourceId);
298 sd->sourceId = vraudio::ResonanceAudioApi::kInvalidSourceId;
299 stereoSources.removeOne(sound);
304 QMutexLocker l(&mutex);
310 QMutexLocker l(&mutex);
311 rooms.removeOne(room);
323 bool roomDirty =
false;
324 for (
const auto &room : std::as_const(rooms)) {
325 auto *rd = QAudioRoomPrivate::get(room);
336 QVector3D listenerPos = listenerPosition();
337 float roomVolume =
float(qInf());
338 QAudioRoom *room =
nullptr;
340 for (
auto *r : std::as_const(rooms)) {
341 QVector3D dim2 = r->dimensions()/2.;
342 float vol = dim2.x()*dim2.y()*dim2.z();
343 if (vol > roomVolume)
345 QVector3D dist = r->position() - listenerPos;
347 dist = r->rotation().rotatedVector(dist);
348 if (qAbs(dist.x()) <= dim2.x() &&
349 qAbs(dist.y()) <= dim2.y() &&
350 qAbs(dist.z()) <= dim2.z()) {
365 resonanceAudio->api->EnableRoomEffects(
false);
369 resonanceAudio->api->EnableRoomEffects(
true);
371 QAudioRoomPrivate *rp = QAudioRoomPrivate::get(room);
372 resonanceAudio->api->SetReflectionProperties(rp->reflections);
373 resonanceAudio->api->SetReverbProperties(rp->reverb);
376 for (
auto *s : std::as_const(sources)) {
377 auto *sp = QSpatialSoundPrivate::get(s);
380 sp->updateRoomEffects();
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449QAudioEngine::QAudioEngine(
int sampleRate, QObject *parent)
450 : QObject(parent), d(
new QAudioEnginePrivate(
this))
452 d->sampleRate = sampleRate;
453 d->resonanceAudio = std::make_unique<vraudio::ResonanceAudio>(
454 2, QAudioEnginePrivate::bufferSize, d->sampleRate);
458
459
460QAudioEngine::~QAudioEngine()
467
468
469
470
471
472
473
474
477
478
479
480
481
482
483void QAudioEngine::setOutputMode(OutputMode mode)
485 d->setOutputMode(mode);
488QAudioEngine::OutputMode QAudioEngine::outputMode()
const
490 return d->outputMode;
494
495
496int QAudioEngine::sampleRate()
const
498 return d->sampleRate;
502
503
504
505
506void QAudioEngine::setOutputDevice(
const QAudioDevice &device)
508 d->setOutputDevice(device);
511QAudioDevice QAudioEngine::outputDevice()
const
517
518
519
520
521void QAudioEngine::setMasterVolume(
float volume)
523 if (d->masterVolume == volume)
525 d->masterVolume = volume;
526 d->resonanceAudio->api->SetMasterVolume(volume);
527 emit masterVolumeChanged();
530float QAudioEngine::masterVolume()
const
532 return d->masterVolume;
536
537
538void QAudioEngine::start()
544
545
546void QAudioEngine::stop()
552
553
554
555
556void QAudioEngine::setPaused(
bool paused)
558 d->setPaused(paused);
561bool QAudioEngine::paused()
const
563 return d->paused.loadRelaxed();
567
568
569
570
571
572
573
574void QAudioEngine::setRoomEffectsEnabled(
bool enabled)
576 if (d->roomEffectsEnabled == enabled)
578 d->roomEffectsEnabled = enabled;
579 d->resonanceAudio->roomEffectsEnabled = enabled;
583
584
585bool QAudioEngine::roomEffectsEnabled()
const
587 return d->roomEffectsEnabled;
591
592
593
594
595
596
597
598
599void QAudioEngine::setDistanceScale(
float scale)
604 qWarning() <<
"QAudioEngine: Invalid distance scale.";
607 if (scale == d->distanceScale)
609 d->distanceScale = scale;
610 emit distanceScaleChanged();
613float QAudioEngine::distanceScale()
const
615 return d->distanceScale*100.f;
619
620
621
622
624
625
626
627
629
630
631
633
634
635
639#include "moc_qaudioengine.cpp"
void setPaused(bool paused)
bool listenerPositionDirty
void addRoom(QAudioRoom *room)
void addStereoSound(QAmbientSound *sound)
QVector3D listenerPosition() const
void removeRoom(QAudioRoom *room)
void addSpatialSound(QSpatialSound *sound)
void setOutputMode(QAudioEngine::OutputMode)
void removeStereoSound(QAmbientSound *sound)
void removeSpatialSound(QSpatialSound *sound)
QAudioEnginePrivate(QAudioEngine *)
QAudioListener * listener
static constexpr int bufferSize
void setOutputDevice(const QAudioDevice &device)
void setPaused(bool paused)
QAudioOutputStream(QAudioEnginePrivate *d)
qint64 readData(char *data, qint64 len) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
bool atEnd() const override
Returns true if the current read and write position is at the end of the device (i....
~QAudioOutputStream() override
qint64 pos() const override
For random-access devices, this function returns the position that data is written to or read from.
bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
qint64 bytesAvailable() const override
Returns the number of bytes that are available for reading.
qint64 writeData(const char *, qint64) override
Writes up to maxSize bytes from data to the device.
qint64 size() const override
For open random-access devices, this function returns the size of the device.
QT_BEGIN_NAMESPACE const int bufferTimeMs