3#include <qaudioengine_p.h>
4#include <qambientsound_p.h>
5#include <qspatialsound_p.h>
6#include <qambientsound.h>
7#include <qaudioroom_p.h>
8#include <qaudiolistener.h>
9#include <resonance_audio.h>
10#include <qambisonicdecoder_p.h>
11#include <qaudiodecoder.h>
12#include <qmediadevices.h>
14#include <qaudiosink.h>
16#include <qelapsedtimer.h>
46 return std::numeric_limits<qint64>::max();
62 auto channelConfig = d->outputMode == QAudioEngine::Surround ?
63 d->device.channelConfiguration() : QAudioFormat::ChannelConfigStereo;
70 ambisonicDecoder.reset(
new QAmbisonicDecoder(QAmbisonicDecoder::HighQuality, format));
71 sink.reset(
new QAudioSink(d->device, format));
72 const qsizetype bufferSize = format.bytesForDuration(
bufferTimeMs * 1000);
73 sink->setBufferSize(bufferSize);
85 ambisonicDecoder.reset();
103 std::unique_ptr<QAudioSink> sink;
104 std::unique_ptr<QAmbisonicDecoder> ambisonicDecoder;
119 if (d->paused.loadRelaxed())
125 int nChannels = ambisonicDecoder ? ambisonicDecoder->nOutputChannels() : 2;
129 short *fd = (
short *)data;
130 qint64 frames = len / nChannels /
sizeof(
short);
134 for (
auto *source : std::as_const(d->sources)) {
135 auto *sp = QSpatialSoundPrivate::get(source);
138 float buf[QAudioEnginePrivate::bufferSize];
139 sp->getBuffer(buf, QAudioEnginePrivate::bufferSize, 1);
140 d->resonanceAudio->api->SetInterleavedBuffer(sp->sourceId, buf, 1, QAudioEnginePrivate::bufferSize);
142 for (
auto *source : std::as_const(d->stereoSources)) {
143 auto *sp = QAmbientSoundPrivate::get(source);
146 float buf[2*QAudioEnginePrivate::bufferSize];
147 sp->getBuffer(buf, QAudioEnginePrivate::bufferSize, 2);
148 d->resonanceAudio->api->SetInterleavedBuffer(sp->sourceId, buf, 2, QAudioEnginePrivate::bufferSize);
151 if (ambisonicDecoder && d->outputMode == QAudioEngine::Surround) {
153 const float *reverbBuffers[2];
154 int nSamples = d->resonanceAudio->getAmbisonicOutput(channels, reverbBuffers, ambisonicDecoder->nInputChannels());
155 Q_ASSERT(ambisonicDecoder->nOutputChannels() <= 8);
156 ambisonicDecoder->processBufferWithReverb(channels, reverbBuffers, fd, nSamples);
163 if (d->sources.isEmpty() && d->stereoSources.isEmpty()) {
167 qWarning() <<
" Reading failed!";
175 const int bytesProcessed = ((
char *)fd - data);
176 m_pos += bytesProcessed;
177 return bytesProcessed;
183 audioThread.setObjectName(u"QAudioThread");
184 device = QMediaDevices::defaultAudioOutput();
197 sd->sourceId = resonanceAudio->api->CreateSoundObjectSource(vraudio::kBinauralHighQuality);
198 sources.append(sound);
207 sd->sourceId = vraudio::ResonanceAudioApi::kInvalidSourceId;
208 sources.removeOne(sound);
217 stereoSources.append(sound);
226 sd->sourceId = vraudio::ResonanceAudioApi::kInvalidSourceId;
227 stereoSources.removeOne(sound);
239 rooms.removeOne(room);
251 bool roomDirty =
false;
252 for (
const auto &room : std::as_const(rooms)) {
253 auto *rd = QAudioRoomPrivate::get(room);
264 QVector3D listenerPos = listenerPosition();
265 float roomVolume =
float(qInf());
266 QAudioRoom *room =
nullptr;
268 for (
auto *r : std::as_const(rooms)) {
269 QVector3D dim2 = r->dimensions()/2.;
270 float vol = dim2.x()*dim2.y()*dim2.z();
271 if (vol > roomVolume)
273 QVector3D dist = r->position() - listenerPos;
275 dist = r->rotation().rotatedVector(dist);
276 if (qAbs(dist.x()) <= dim2.x() &&
277 qAbs(dist.y()) <= dim2.y() &&
278 qAbs(dist.z()) <= dim2.z()) {
299 QAudioRoomPrivate *rp = QAudioRoomPrivate::get(room);
304 for (
auto *s : std::as_const(sources)) {
305 auto *sp = QSpatialSoundPrivate::get(s);
308 sp->updateRoomEffects();
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378QAudioEngine::QAudioEngine(
int sampleRate, QObject *parent)
380 , d(
new QAudioEnginePrivate)
382 d->sampleRate = sampleRate;
383 d->resonanceAudio =
new vraudio::ResonanceAudio(2, QAudioEnginePrivate::bufferSize, d->sampleRate);
387
388
389QAudioEngine::~QAudioEngine()
396
397
398
399
400
401
402
403
406
407
408
409
410
411
412void QAudioEngine::setOutputMode(OutputMode mode)
414 if (d->outputMode == mode)
416 d->outputMode = mode;
417 if (d->resonanceAudio->api)
418 d->resonanceAudio->api->SetStereoSpeakerMode(mode != Headphone);
420 QMetaObject::invokeMethod(d->outputStream.get(),
"restartOutput", Qt::BlockingQueuedConnection);
422 emit outputModeChanged();
425QAudioEngine::OutputMode QAudioEngine::outputMode()
const
427 return d->outputMode;
431
432
433int QAudioEngine::sampleRate()
const
435 return d->sampleRate;
439
440
441
442
443void QAudioEngine::setOutputDevice(
const QAudioDevice &device)
445 if (d->device == device)
447 if (d->resonanceAudio->api) {
448 qWarning() <<
"Changing device on a running engine not implemented";
452 emit outputDeviceChanged();
455QAudioDevice QAudioEngine::outputDevice()
const
461
462
463
464
465void QAudioEngine::setMasterVolume(
float volume)
467 if (d->masterVolume == volume)
469 d->masterVolume = volume;
470 d->resonanceAudio->api->SetMasterVolume(volume);
471 emit masterVolumeChanged();
474float QAudioEngine::masterVolume()
const
476 return d->masterVolume;
480
481
482void QAudioEngine::start()
488 d->resonanceAudio->api->SetStereoSpeakerMode(d->outputMode != Headphone);
489 d->resonanceAudio->api->SetMasterVolume(d->masterVolume);
491 d->outputStream.reset(
new QAudioOutputStream(d));
492 d->outputStream->moveToThread(&d->audioThread);
493 d->audioThread.start(QThread::TimeCriticalPriority);
495 QMetaObject::invokeMethod(d->outputStream.get(),
"startOutput");
499
500
501void QAudioEngine::stop()
503 QMetaObject::invokeMethod(d->outputStream.get(),
"stopOutput", Qt::BlockingQueuedConnection);
504 d->outputStream.reset();
505 d->audioThread.exit(0);
506 d->audioThread.wait();
507 delete d->resonanceAudio->api;
508 d->resonanceAudio->api =
nullptr;
512
513
514
515
516void QAudioEngine::setPaused(
bool paused)
518 bool old = d->paused.fetchAndStoreRelaxed(paused);
521 d->outputStream->setPaused(paused);
522 emit pausedChanged();
526bool QAudioEngine::paused()
const
528 return d->paused.loadRelaxed();
532
533
534
535
536
537
538
539void QAudioEngine::setRoomEffectsEnabled(
bool enabled)
541 if (d->roomEffectsEnabled == enabled)
543 d->roomEffectsEnabled = enabled;
544 d->resonanceAudio->roomEffectsEnabled = enabled;
548
549
550bool QAudioEngine::roomEffectsEnabled()
const
552 return d->roomEffectsEnabled;
556
557
558
559
560
561
562
563
564void QAudioEngine::setDistanceScale(
float scale)
569 qWarning() <<
"QAudioEngine: Invalid distance scale.";
572 if (scale == d->distanceScale)
574 d->distanceScale = scale;
575 emit distanceScaleChanged();
578float QAudioEngine::distanceScale()
const
580 return d->distanceScale*100.f;
584
585
586
587
589
590
591
592
594
595
596
598
599
600
604#include "moc_qaudioengine.cpp"
605#include "qaudioengine.moc"
static constexpr int maxAmbisonicChannels
bool listenerPositionDirty
vraudio::ResonanceAudio * resonanceAudio
void addRoom(QAudioRoom *room)
void addStereoSound(QAmbientSound *sound)
QVector3D listenerPosition() const
void removeRoom(QAudioRoom *room)
void addSpatialSound(QSpatialSound *sound)
void removeStereoSound(QAmbientSound *sound)
void removeSpatialSound(QSpatialSound *sound)
QAudioListener * listener
static constexpr int bufferSize
void setPaused(bool paused)
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...
Q_INVOKABLE void restartOutput()
bool atEnd() const override
Returns true if the current read and write position is at the end of the device (i....
Q_INVOKABLE void stopOutput()
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.
Q_INVOKABLE void startOutput()
qint64 size() const override
For open random-access devices, this function returns the size of the device.
Combined button and popup list for selecting options.
QT_BEGIN_NAMESPACE const int bufferTimeMs