From 593fc6c96309acdc4534d841a89d862e1e0cd153 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 4 Apr 2014 17:29:39 -0700 Subject: [PATCH] lots of knobs and dials --- interface/src/Application.cpp | 25 +++-- interface/src/AudioReflector.cpp | 169 +++++++++++++++++++------------ interface/src/AudioReflector.h | 22 +++- interface/src/Menu.cpp | 14 ++- interface/src/Menu.h | 2 + 5 files changed, 154 insertions(+), 78 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 89f6a8e223..ac5a374a1f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2787,7 +2787,7 @@ void Application::displayStats() { glm::vec3 avatarPos = _myAvatar->getPosition(); - lines = _statsExpanded ? 5 : 3; + lines = _statsExpanded ? 8 : 3; displayStatsBackground(backgroundColor, horizontalOffset, 0, _glWidget->width() - (mirrorEnabled ? 301 : 411) - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; @@ -2840,26 +2840,34 @@ void Application::displayStats() { // add some reflection stats char reflectionsStatus[128]; - sprintf(reflectionsStatus, "Reflections: %d, Pre-Delay: %f, Separate Ears:%s", + sprintf(reflectionsStatus, "Reflections: %d, Original: %s, Ears: %s, Source: %s", _audioReflector.getReflections(), - _audioReflector.getDelayFromDistance(0.0f), - debug::valueOf(Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingSeparateEars))); + (Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingIncudeOriginal) + ? "with" : "without"), + (Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingSeparateEars) + ? "two" : "one"), + (Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingStereoSource) + ? "stereo" : "mono") + ); verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, reflectionsStatus, WHITE_TEXT); - sprintf(reflectionsStatus, "Delay: average %f, max %f, min %f", + sprintf(reflectionsStatus, "Delay: pre: %f, average %f, max %f, min %f, speed: %f", + _audioReflector.getDelayFromDistance(0.0f), _audioReflector.getAverageDelayMsecs(), _audioReflector.getMaxDelayMsecs(), - _audioReflector.getMinDelayMsecs()); + _audioReflector.getMinDelayMsecs(), + _audioReflector.getSoundMsPerMeter()); verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, reflectionsStatus, WHITE_TEXT); - sprintf(reflectionsStatus, "Attenuation: average %f, max %f, min %f", + sprintf(reflectionsStatus, "Attenuation: average %f, max %f, min %f, distance scale: %f", _audioReflector.getAverageAttenuation(), _audioReflector.getMaxAttenuation(), - _audioReflector.getMinAttenuation()); + _audioReflector.getMinAttenuation(), + _audioReflector.getDistanceAttenuationScalingFactor()); verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, reflectionsStatus, WHITE_TEXT); @@ -3725,6 +3733,7 @@ void Application::loadScript(const QString& scriptName) { scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); + scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector); QThread* workerThread = new QThread(this); diff --git a/interface/src/AudioReflector.cpp b/interface/src/AudioReflector.cpp index b7ee81ff1c..9a4da87014 100644 --- a/interface/src/AudioReflector.cpp +++ b/interface/src/AudioReflector.cpp @@ -11,8 +11,18 @@ #include "AudioReflector.h" #include "Menu.h" + +const float DEFAULT_PRE_DELAY = 20.0f; // this delay in msecs will always be added to all reflections +const float DEFAULT_MS_DELAY_PER_METER = 3.0f; +const float MINIMUM_ATTENUATION_TO_REFLECT = 1.0f / 256.0f; +const float DEFAULT_DISTANCE_SCALING_FACTOR = 2.0f; + + AudioReflector::AudioReflector(QObject* parent) : - QObject(parent) + QObject(parent), + _preDelay(DEFAULT_PRE_DELAY), + _soundMsPerMeter(DEFAULT_MS_DELAY_PER_METER), + _distanceAttenuationScalingFactor(DEFAULT_DISTANCE_SCALING_FACTOR) { reset(); } @@ -34,14 +44,12 @@ void AudioReflector::render() { // = 3ms per meter // attenuation = // BOUNCE_ATTENUATION_FACTOR [0.5] * (1/(1+distance)) -const float PRE_DELAY = 20.0f; // this delay in msecs will always be added to all reflections float AudioReflector::getDelayFromDistance(float distance) { - const int MS_DELAY_PER_METER = 3; - float delay = (MS_DELAY_PER_METER * distance); + float delay = (_soundMsPerMeter * distance); if (Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingPreDelay)) { - delay += PRE_DELAY; + delay += _preDelay; } @@ -52,14 +60,14 @@ float AudioReflector::getDelayFromDistance(float distance) { const float PER_BOUNCE_ATTENUATION_FACTOR = 0.5f; // **option 2**: we're not using these -const float BOUNCE_ATTENUATION_FACTOR = 0.125f; +//const float BOUNCE_ATTENUATION_FACTOR = 0.125f; // each bounce we adjust our attenuation by this factor, the result is an asymptotically decreasing attenuation... // 0.125, 0.25, 0.5, ... -const float PER_BOUNCE_ATTENUATION_ADJUSTMENT = 2.0f; +//const float PER_BOUNCE_ATTENUATION_ADJUSTMENT = 2.0f; // we don't grow larger than this, which means by the 4th bounce we don't get that much less quiet -const float MAX_BOUNCE_ATTENUATION = 0.99f; +//const float MAX_BOUNCE_ATTENUATION = 0.99f; -float getDistanceAttenuationCoefficient(float distance) { +float AudioReflector::getDistanceAttenuationCoefficient(float distance) { const float DISTANCE_SCALE = 2.5f; const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f; const float DISTANCE_LOG_BASE = 2.5f; @@ -72,13 +80,15 @@ float getDistanceAttenuationCoefficient(float distance) { DISTANCE_SCALE_LOG + (0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1); - const float DISTANCE_SCALING_FACTOR = 2.0f; - - distanceCoefficient = std::min(1.0f, distanceCoefficient * DISTANCE_SCALING_FACTOR); + distanceCoefficient = std::min(1.0f, distanceCoefficient * getDistanceAttenuationScalingFactor()); return distanceCoefficient; } +float getBounceAttenuationCoefficient(int bounceCount) { + return PER_BOUNCE_ATTENUATION_FACTOR * bounceCount; +} + glm::vec3 getFaceNormal(BoxFace face) { float surfaceRandomness = randFloatInRange(0.99,1.0); float surfaceRemainder = (1.0f - surfaceRandomness)/2.0f; @@ -128,29 +138,52 @@ void AudioReflector::calculateAllReflections() { // only recalculate when we've moved... // TODO: what about case where new voxels are added in front of us??? - if (_reflections == 0 || _myAvatar->getHead()->getPosition() != _origin) { + bool wantHeadOrientation = Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingHeadOriented); + glm::quat orientation = wantHeadOrientation ? _myAvatar->getHead()->getFinalOrientation() : _myAvatar->getOrientation(); + + bool shouldRecalc = _reflections == 0 || _myAvatar->getHead()->getPosition() != _origin || (orientation != _orientation); + + /* + qDebug() << "wantHeadOrientation=" << wantHeadOrientation; + + qDebug(" _myAvatar->getHead()->getPosition()=%f,%f,%f", + _myAvatar->getHead()->getPosition().x, + _myAvatar->getHead()->getPosition().y, + _myAvatar->getHead()->getPosition().z); + + qDebug(" _origin=%f,%f,%f", + _origin.x, + _origin.y, + _origin.z); + + qDebug(" orientation=%f,%f,%f,%f", + orientation.x, + orientation.y, + orientation.z, + orientation.w); + + qDebug(" _orientation=%f,%f,%f,%f", + _orientation.x, + _orientation.y, + _orientation.z, + _orientation.w); + */ + if (shouldRecalc) { + //qDebug() << "origin or orientation has changed..."; + QMutexLocker locker(&_mutex); - qDebug() << "origin has changed..."; - qDebug(" _myAvatar->getHead()->getPosition()=%f,%f,%f", - _myAvatar->getHead()->getPosition().x, - _myAvatar->getHead()->getPosition().y, - _myAvatar->getHead()->getPosition().z); - - qDebug(" _origin=%f,%f,%f", - _origin.x, - _origin.y, - _origin.z); quint64 start = usecTimestampNow(); _origin = _myAvatar->getHead()->getPosition(); + glm::vec3 averageEarPosition = _myAvatar->getHead()->getPosition(); - glm::quat orientation = _myAvatar->getOrientation(); // _myAvatar->getHead()->getOrientation(); - glm::vec3 right = glm::normalize(orientation * IDENTITY_RIGHT); - glm::vec3 up = glm::normalize(orientation * IDENTITY_UP); - glm::vec3 front = glm::normalize(orientation * IDENTITY_FRONT); + _orientation = orientation; + glm::vec3 right = glm::normalize(_orientation * IDENTITY_RIGHT); + glm::vec3 up = glm::normalize(_orientation * IDENTITY_UP); + glm::vec3 front = glm::normalize(_orientation * IDENTITY_FRONT); glm::vec3 left = -right; glm::vec3 down = -up; glm::vec3 back = -front; @@ -163,33 +196,31 @@ void AudioReflector::calculateAllReflections() { glm::vec3 backRightDown = glm::normalize(back + right + down); glm::vec3 backLeftDown = glm::normalize(back + left + down); - const int BOUNCE_COUNT = 5; - - _frontRightUpReflections = calculateReflections(_origin, frontRightUp, BOUNCE_COUNT); - _frontLeftUpReflections = calculateReflections(_origin, frontLeftUp, BOUNCE_COUNT); - _backRightUpReflections = calculateReflections(_origin, backRightUp, BOUNCE_COUNT); - _backLeftUpReflections = calculateReflections(_origin, backLeftUp, BOUNCE_COUNT); - _frontRightDownReflections = calculateReflections(_origin, frontRightDown, BOUNCE_COUNT); - _frontLeftDownReflections = calculateReflections(_origin, frontLeftDown, BOUNCE_COUNT); - _backRightDownReflections = calculateReflections(_origin, backRightDown, BOUNCE_COUNT); - _backLeftDownReflections = calculateReflections(_origin, backLeftDown, BOUNCE_COUNT); - _frontReflections = calculateReflections(_origin, front, BOUNCE_COUNT); - _backReflections = calculateReflections(_origin, back, BOUNCE_COUNT); - _leftReflections = calculateReflections(_origin, left, BOUNCE_COUNT); - _rightReflections = calculateReflections(_origin, right, BOUNCE_COUNT); - _upReflections = calculateReflections(_origin, up, BOUNCE_COUNT); - _downReflections = calculateReflections(_origin, down, BOUNCE_COUNT); + _frontRightUpReflections = calculateReflections(averageEarPosition, _origin, frontRightUp); + _frontLeftUpReflections = calculateReflections(averageEarPosition, _origin, frontLeftUp); + _backRightUpReflections = calculateReflections(averageEarPosition, _origin, backRightUp); + _backLeftUpReflections = calculateReflections(averageEarPosition, _origin, backLeftUp); + _frontRightDownReflections = calculateReflections(averageEarPosition, _origin, frontRightDown); + _frontLeftDownReflections = calculateReflections(averageEarPosition, _origin, frontLeftDown); + _backRightDownReflections = calculateReflections(averageEarPosition, _origin, backRightDown); + _backLeftDownReflections = calculateReflections(averageEarPosition, _origin, backLeftDown); + _frontReflections = calculateReflections(averageEarPosition, _origin, front); + _backReflections = calculateReflections(averageEarPosition, _origin, back); + _leftReflections = calculateReflections(averageEarPosition, _origin, left); + _rightReflections = calculateReflections(averageEarPosition, _origin, right); + _upReflections = calculateReflections(averageEarPosition, _origin, up); + _downReflections = calculateReflections(averageEarPosition, _origin, down); quint64 end = usecTimestampNow(); reset(); - qDebug() << "Reflections recalculated in " << (end - start) << "usecs"; + //qDebug() << "Reflections recalculated in " << (end - start) << "usecs"; } } -QVector AudioReflector::calculateReflections(const glm::vec3& origin, const glm::vec3& originalDirection, int maxBounces) { +QVector AudioReflector::calculateReflections(const glm::vec3& earPosition, const glm::vec3& origin, const glm::vec3& originalDirection) { QVector reflectionPoints; glm::vec3 start = origin; glm::vec3 direction = originalDirection; @@ -197,16 +228,28 @@ QVector AudioReflector::calculateReflections(const glm::vec3& origin, float distance; BoxFace face; const float SLIGHTLY_SHORT = 0.999f; // slightly inside the distance so we're on the inside of the reflection point + float currentAttenuation = 1.0f; + float totalDistance = 0.0f; + int bounceCount = 1; - for (int i = 0; i < maxBounces; i++) { + while (currentAttenuation > MINIMUM_ATTENUATION_TO_REFLECT) { if (_voxels->findRayIntersection(start, direction, elementHit, distance, face)) { glm::vec3 end = start + (direction * (distance * SLIGHTLY_SHORT)); + + totalDistance += glm::distance(start, end); + float earDistance = glm::distance(end, earPosition); + float totalDistance = earDistance + distance; + currentAttenuation = getDistanceAttenuationCoefficient(totalDistance) * getBounceAttenuationCoefficient(bounceCount); - reflectionPoints.push_back(end); - - glm::vec3 faceNormal = getFaceNormal(face); - direction = glm::normalize(glm::reflect(direction,faceNormal)); - start = end; + if (currentAttenuation > MINIMUM_ATTENUATION_TO_REFLECT) { + reflectionPoints.push_back(end); + glm::vec3 faceNormal = getFaceNormal(face); + direction = glm::normalize(glm::reflect(direction,faceNormal)); + start = end; + bounceCount++; + } + } else { + currentAttenuation = 0.0f; } } return reflectionPoints; @@ -234,6 +277,7 @@ void AudioReflector::echoReflections(const glm::vec3& origin, const QVectorisOptionChecked(MenuOption::AudioSpatialProcessingSeparateEars); + bool wantStereo = Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingStereoSource); glm::vec3 rightEarPosition = wantEarSeparation ? _myAvatar->getHead()->getRightEarPosition() : _myAvatar->getHead()->getPosition(); glm::vec3 leftEarPosition = wantEarSeparation ? _myAvatar->getHead()->getLeftEarPosition() : @@ -254,12 +298,10 @@ void AudioReflector::echoReflections(const glm::vec3& origin, const QVector& reflections, const QByteArray& samples, unsigned int sampleTime, int sampleRate); - QVector calculateReflections(const glm::vec3& origin, const glm::vec3& originalDirection, int maxBounces); + QVector calculateReflections(const glm::vec3& earPosition, const glm::vec3& origin, const glm::vec3& originalDirection); void drawReflections(const glm::vec3& origin, const glm::vec3& originalColor, const QVector& reflections); void calculateAllReflections(); void reset(); + float getDistanceAttenuationCoefficient(float distance); int _reflections; @@ -73,6 +84,7 @@ private: float _minAttenuation; glm::vec3 _origin; + glm::quat _orientation; QVector _frontRightUpReflections; QVector _frontLeftUpReflections; QVector _backRightUpReflections; @@ -89,6 +101,10 @@ private: QVector _downReflections; QMutex _mutex; + + float _preDelay; + float _soundMsPerMeter; + float _distanceAttenuationScalingFactor; }; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f0c7b27780..1a0adb5550 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -331,8 +331,8 @@ Menu::Menu() : QMenu* renderDebugMenu = developerMenu->addMenu("Render Debugging Tools"); - addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings, Qt::CTRL | Qt::SHIFT | Qt::Key_P); - addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings, Qt::CTRL | Qt::SHIFT | Qt::Key_S); + addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings); + addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings); addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::CullSharedFaces, @@ -383,7 +383,15 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioSpatialProcessingPreDelay, Qt::CTRL | Qt::SHIFT | Qt::Key_D, true); - + + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioSpatialProcessingStereoSource, + Qt::CTRL | Qt::SHIFT | Qt::Key_S, + true); + + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioSpatialProcessingHeadOriented, + Qt::CTRL | Qt::SHIFT | Qt::Key_H, + true); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::LowPassFilter, Qt::CTRL | Qt::SHIFT | Qt::Key_F, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index fbaf8b57a7..fd7873fae9 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -247,6 +247,8 @@ namespace MenuOption { const QString AudioSpatialProcessingIncudeOriginal = "Audio Spatial Processing includes Original"; const QString AudioSpatialProcessingSeparateEars = "Audio Spatial Processing separates ears"; const QString AudioSpatialProcessingPreDelay = "Audio Spatial Processing add Pre-Delay"; + const QString AudioSpatialProcessingStereoSource = "Audio Spatial Processing Stereo Source"; + const QString AudioSpatialProcessingHeadOriented = "Audio Spatial Processing Head Oriented"; const QString EchoServerAudio = "Echo Server Audio"; const QString EchoLocalAudio = "Echo Local Audio"; const QString MuteAudio = "Mute Microphone";