diff options
Diffstat (limited to 'examples/spatialaudio/audiopanning/main.cpp')
-rw-r--r-- | examples/spatialaudio/audiopanning/main.cpp | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/examples/spatialaudio/audiopanning/main.cpp b/examples/spatialaudio/audiopanning/main.cpp new file mode 100644 index 000000000..84e5197bd --- /dev/null +++ b/examples/spatialaudio/audiopanning/main.cpp @@ -0,0 +1,241 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include <QApplication> +#include <QAudioEngine> +#include <QAudioListener> +#include <QAudioRoom> +#include <QCheckBox> +#include <QComboBox> +#include <QCommandLineParser> +#include <QFileDialog> +#include <QFormLayout> +#include <QHBoxLayout> +#include <QLibraryInfo> +#include <QLineEdit> +#include <QPropertyAnimation> +#include <QPushButton> +#include <QSlider> +#include <QSpatialSound> +#include <QStandardPaths> + +class AudioWidget : public QWidget +{ +public: + AudioWidget(); + void setFile(const QString &file); + +private slots: + void updatePosition(); + void newOcclusion(); + void modeChanged(); + void fileChanged(const QString &file); + void openFileDialog(); + void updateRoom(); + void animateChanged(); + +private: + QLineEdit *fileEdit = nullptr; + QPushButton *fileDialogButton = nullptr; + QSlider *azimuth = nullptr; + QSlider *elevation = nullptr; + QSlider *distance = nullptr; + QSlider *occlusion = nullptr; + QSlider *roomDimension = nullptr; + QSlider *reverbGain = nullptr; + QSlider *reflectionGain = nullptr; + QComboBox *mode = nullptr; + QCheckBox *animateButton = nullptr; + QPropertyAnimation *animation = nullptr; + + QAudioEngine engine; + QAudioListener *listener = nullptr; + QSpatialSound *sound = nullptr; + QAudioRoom *room = nullptr; + QFileDialog *fileDialog = nullptr; +}; + +AudioWidget::AudioWidget() + : QWidget() +{ + setMinimumSize(400, 300); + auto *form = new QFormLayout(this); + + auto *fileLayout = new QHBoxLayout; + fileEdit = new QLineEdit; + fileEdit->setPlaceholderText(tr("Audio File")); + fileLayout->addWidget(fileEdit); + fileDialogButton = new QPushButton(tr("Choose...")); + fileLayout->addWidget(fileDialogButton); + form->addRow(fileLayout); + + azimuth = new QSlider(Qt::Horizontal); + azimuth->setRange(-180, 180); + form->addRow(tr("Azimuth (-180 - 180 degree):"), azimuth); + + elevation = new QSlider(Qt::Horizontal); + elevation->setRange(-90, 90); + form->addRow(tr("Elevation (-90 - 90 degree)"), elevation); + + distance = new QSlider(Qt::Horizontal); + distance->setRange(0, 1000); + distance->setValue(100); + form->addRow(tr("Distance (0 - 10 meter):"), distance); + + occlusion = new QSlider(Qt::Horizontal); + occlusion->setRange(0, 400); + form->addRow(tr("Occlusion (0 - 4):"), occlusion); + + roomDimension = new QSlider(Qt::Horizontal); + roomDimension->setRange(0, 10000); + roomDimension->setValue(1000); + form->addRow(tr("Room dimension (0 - 100 meter):"), roomDimension); + + reverbGain = new QSlider(Qt::Horizontal); + reverbGain->setRange(0, 500); + reverbGain->setValue(0); + form->addRow(tr("Reverb gain (0-5):"), reverbGain); + + reflectionGain = new QSlider(Qt::Horizontal); + reflectionGain->setRange(0, 500); + reflectionGain->setValue(0); + form->addRow(tr("Reflection gain (0-5):"), reflectionGain); + + mode = new QComboBox; + mode->addItem(tr("Surround"), QVariant::fromValue(QAudioEngine::Surround)); + mode->addItem(tr("Stereo"), QVariant::fromValue(QAudioEngine::Stereo)); + mode->addItem(tr("Headphone"), QVariant::fromValue(QAudioEngine::Headphone)); + + form->addRow(tr("Output mode:"), mode); + + animateButton = new QCheckBox(tr("Animate sound position")); + form->addRow(animateButton); + + connect(fileEdit, &QLineEdit::textChanged, this, &AudioWidget::fileChanged); + connect(fileDialogButton, &QPushButton::clicked, this, &AudioWidget::openFileDialog); + + connect(azimuth, &QSlider::valueChanged, this, &AudioWidget::updatePosition); + connect(elevation, &QSlider::valueChanged, this, &AudioWidget::updatePosition); + connect(distance, &QSlider::valueChanged, this, &AudioWidget::updatePosition); + connect(occlusion, &QSlider::valueChanged, this, &AudioWidget::newOcclusion); + + connect(roomDimension, &QSlider::valueChanged, this, &AudioWidget::updateRoom); + connect(reverbGain, &QSlider::valueChanged, this, &AudioWidget::updateRoom); + connect(reflectionGain, &QSlider::valueChanged, this, &AudioWidget::updateRoom); + + connect(mode, &QComboBox::currentIndexChanged, this, &AudioWidget::modeChanged); + + room = new QAudioRoom(&engine); + room->setWallMaterial(QAudioRoom::BackWall, QAudioRoom::BrickBare); + room->setWallMaterial(QAudioRoom::FrontWall, QAudioRoom::BrickBare); + room->setWallMaterial(QAudioRoom::LeftWall, QAudioRoom::BrickBare); + room->setWallMaterial(QAudioRoom::RightWall, QAudioRoom::BrickBare); + room->setWallMaterial(QAudioRoom::Floor, QAudioRoom::Marble); + room->setWallMaterial(QAudioRoom::Ceiling, QAudioRoom::WoodCeiling); + updateRoom(); + + listener = new QAudioListener(&engine); + listener->setPosition({}); + listener->setRotation({}); + engine.start(); + + sound = new QSpatialSound(&engine); + updatePosition(); + + animation = new QPropertyAnimation(azimuth, "value"); + animation->setDuration(10000); + animation->setStartValue(-180); + animation->setEndValue(180); + animation->setLoopCount(-1); + connect(animateButton, &QCheckBox::toggled, this, &AudioWidget::animateChanged); +} + +void AudioWidget::setFile(const QString &file) +{ + fileEdit->setText(file); +} + +void AudioWidget::updatePosition() +{ + const float az = azimuth->value() / 180. * M_PI; + const float el = elevation->value() / 180. * M_PI; + const float d = distance->value(); + + const float x = d * sin(az) * cos(el); + const float y = d * sin(el); + const float z = -d * cos(az) * cos(el); + sound->setPosition({x, y, z}); +} + +void AudioWidget::newOcclusion() +{ + sound->setOcclusionIntensity(occlusion->value() / 100.); +} + +void AudioWidget::modeChanged() +{ + engine.setOutputMode(mode->currentData().value<QAudioEngine::OutputMode>()); +} + +void AudioWidget::fileChanged(const QString &file) +{ + sound->setSource(QUrl::fromLocalFile(file)); + sound->setSize(5); + sound->setLoops(QSpatialSound::Infinite); +} + +void AudioWidget::openFileDialog() +{ + if (fileDialog == nullptr) { + const QString dir = QStandardPaths::writableLocation(QStandardPaths::MusicLocation); + fileDialog = new QFileDialog(this, tr("Open Audio File"), dir); + fileDialog->setAcceptMode(QFileDialog::AcceptOpen); + const QStringList mimeTypes{"audio/mpeg", "audio/aac", "audio/x-ms-wma", + "audio/x-flac+ogg", "audio/x-wav"}; + fileDialog->setMimeTypeFilters(mimeTypes); + fileDialog->selectMimeTypeFilter(mimeTypes.constFirst()); + } + + if (fileDialog->exec() == QDialog::Accepted) + fileEdit->setText(fileDialog->selectedFiles().constFirst()); +} + +void AudioWidget::updateRoom() +{ + const float d = roomDimension->value(); + room->setDimensions(QVector3D(d, d, 400)); + room->setReflectionGain(float(reflectionGain->value()) / 100); + room->setReverbGain(float(reverbGain->value()) / 100); +} + +void AudioWidget::animateChanged() +{ + if (animateButton->isChecked()) + animation->start(); + else + animation->stop(); +} + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + QCoreApplication::setApplicationVersion(qVersion()); + QGuiApplication::setApplicationDisplayName(AudioWidget::tr("Spatial Audio test application")); + + QCommandLineParser commandLineParser; + commandLineParser.addVersionOption(); + commandLineParser.addHelpOption(); + commandLineParser.addPositionalArgument("Audio File", + "Audio File to play"); + + commandLineParser.process(app); + + AudioWidget w; + w.show(); + + if (!commandLineParser.positionalArguments().isEmpty()) + w.setFile(commandLineParser.positionalArguments().constFirst()); + + return app.exec(); +} |