From fa08e42da6f7061ea19975d7f4eb6759d98b95e8 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 29 Jan 2019 09:40:59 -0800 Subject: [PATCH] Restore legacy attenuation behavior for system sounds and scripts that do not set position. JS detects when "position" was not set by the script. C++ explicitly sets .positionSet=false when not set (for system sounds). Local rendering uses a direct mix (no attenuation/HRTF) when not set. --- interface/src/Application.cpp | 2 + libraries/audio-client/src/AudioClient.cpp | 61 +++++++++++++------ libraries/audio/src/AudioInjector.h | 1 + libraries/audio/src/AudioInjectorOptions.cpp | 9 ++- libraries/audio/src/AudioInjectorOptions.h | 1 + .../src/AudioScriptingInterface.cpp | 4 +- .../src/AudioScriptingInterface.h | 4 +- .../ui/src/ui/TabletScriptingInterface.cpp | 1 + 8 files changed, 58 insertions(+), 25 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a5c1ad6cf0..a2313c8d0b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4030,7 +4030,9 @@ void Application::keyPressEvent(QKeyEvent* event) { if (!isShifted && !isMeta && !isOption && !event->isAutoRepeat()) { AudioInjectorOptions options; options.localOnly = true; + options.positionSet = false; // system sound options.stereo = true; + Setting::Handle notificationSounds{ MenuOption::NotificationSounds, true }; Setting::Handle notificationSoundSnapshot{ MenuOption::NotificationSoundsSnapshot, true }; if (notificationSounds.get() && notificationSoundSnapshot.get()) { diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 36fb701168..338074ba3b 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1310,10 +1310,17 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) { memset(_localScratchBuffer, 0, bytesToRead); if (0 < injectorBuffer->readData((char*)_localScratchBuffer, bytesToRead)) { + float gain = injector->getVolume(); + if (injector->isAmbisonic()) { - // no distance attenuation - float gain = injector->getVolume(); + if (injector->isPositionSet()) { + + // distance attenuation + glm::vec3 relativePosition = injector->getPosition() - _positionGetter(); + float distance = glm::max(glm::length(relativePosition), EPSILON); + gain = gainForSource(distance, gain); + } // // Calculate the soundfield orientation relative to the listener. @@ -1327,33 +1334,49 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) { float qy = -relativeOrientation.x; float qz = relativeOrientation.y; - // Ambisonic gets spatialized into mixBuffer + // spatialize into mixBuffer injector->getLocalFOA().render(_localScratchBuffer, mixBuffer, HRTF_DATASET_INDEX, qw, qx, qy, qz, gain, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); } else if (injector->isStereo()) { - // calculate distance, gain - glm::vec3 relativePosition = injector->getPosition() - _positionGetter(); - float distance = glm::max(glm::length(relativePosition), EPSILON); - float gain = gainForSource(distance, injector->getVolume()); + if (injector->isPositionSet()) { - // stereo gets directly mixed into mixBuffer - for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; i++) { - mixBuffer[i] += convertToFloat(_localScratchBuffer[i]) * gain; + // distance attenuation + glm::vec3 relativePosition = injector->getPosition() - _positionGetter(); + float distance = glm::max(glm::length(relativePosition), EPSILON); + gain = gainForSource(distance, gain); } - } else { + // direct mix into mixBuffer + for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL; i++) { + mixBuffer[2*i+0] += convertToFloat(_localScratchBuffer[2*i+0]) * gain; + mixBuffer[2*i+1] += convertToFloat(_localScratchBuffer[2*i+1]) * gain; + } - // calculate distance, gain and azimuth for hrtf - glm::vec3 relativePosition = injector->getPosition() - _positionGetter(); - float distance = glm::max(glm::length(relativePosition), EPSILON); - float gain = gainForSource(distance, injector->getVolume()); - float azimuth = azimuthForSource(relativePosition); + } else { // injector is mono - // mono gets spatialized into mixBuffer - injector->getLocalHRTF().render(_localScratchBuffer, mixBuffer, HRTF_DATASET_INDEX, - azimuth, distance, gain, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + if (injector->isPositionSet()) { + + // distance attenuation + glm::vec3 relativePosition = injector->getPosition() - _positionGetter(); + float distance = glm::max(glm::length(relativePosition), EPSILON); + gain = gainForSource(distance, gain); + + float azimuth = azimuthForSource(relativePosition); + + // spatialize into mixBuffer + injector->getLocalHRTF().render(_localScratchBuffer, mixBuffer, HRTF_DATASET_INDEX, + azimuth, distance, gain, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); + } else { + + // direct mix into mixBuffer + for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL; i++) { + float sample = convertToFloat(_localScratchBuffer[i]) * gain; + mixBuffer[2*i+0] += sample; + mixBuffer[2*i+1] += sample; + } + } } } else { diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 49faa61b91..3c21d2eccf 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -67,6 +67,7 @@ public: bool isLocalOnly() const { return _options.localOnly; } float getVolume() const { return _options.volume; } + bool isPositionSet() const { return _options.positionSet; } glm::vec3 getPosition() const { return _options.position; } glm::quat getOrientation() const { return _options.orientation; } bool isStereo() const { return _options.stereo; } diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index 295da1506e..f823698ea1 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -19,6 +19,7 @@ AudioInjectorOptions::AudioInjectorOptions() : position(0.0f, 0.0f, 0.0f), + positionSet(true), // default to legacy behavior volume(1.0f), loop(false), orientation(glm::vec3(0.0f, 0.0f, 0.0f)), @@ -29,12 +30,12 @@ AudioInjectorOptions::AudioInjectorOptions() : secondOffset(0.0f), pitch(1.0f) { - } QScriptValue injectorOptionsToScriptValue(QScriptEngine* engine, const AudioInjectorOptions& injectorOptions) { QScriptValue obj = engine->newObject(); obj.setProperty("position", vec3ToScriptValue(engine, injectorOptions.position)); + obj.setProperty("positionSet", injectorOptions.positionSet); obj.setProperty("volume", injectorOptions.volume); obj.setProperty("loop", injectorOptions.loop); obj.setProperty("orientation", quatToScriptValue(engine, injectorOptions.orientation)); @@ -68,12 +69,18 @@ void injectorOptionsFromScriptValue(const QScriptValue& object, AudioInjectorOpt return; } + if (injectorOptions.positionSet == false) { + qWarning() << "Audio injector options: injectorOptionsFromScriptValue() called more than once?"; + } + injectorOptions.positionSet = false; + QScriptValueIterator it(object); while (it.hasNext()) { it.next(); if (it.name() == "position") { vec3FromScriptValue(object.property("position"), injectorOptions.position); + injectorOptions.positionSet = true; } else if (it.name() == "orientation") { quatFromScriptValue(object.property("orientation"), injectorOptions.orientation); } else if (it.name() == "volume") { diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index 4dd38ce915..5dec8a0240 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -21,6 +21,7 @@ class AudioInjectorOptions { public: AudioInjectorOptions(); glm::vec3 position; + bool positionSet; float volume; bool loop; glm::quat orientation; diff --git a/libraries/script-engine/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp index 0c4a593487..8e54d2d5de 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -38,10 +38,10 @@ void AudioScriptingInterface::setLocalAudioInterface(AbstractAudioInterface* aud } } -ScriptAudioInjector* AudioScriptingInterface::playSystemSound(SharedSoundPointer sound, const QVector3D& position) { +ScriptAudioInjector* AudioScriptingInterface::playSystemSound(SharedSoundPointer sound) { AudioInjectorOptions options; - options.position = glm::vec3(position.x(), position.y(), position.z()); options.localOnly = true; + options.positionSet = false; // system sound return playSound(sound, options); } diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 2854445b4f..d2f886d2dd 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -102,11 +102,9 @@ protected: * @function Audio.playSystemSound * @param {SoundObject} sound - The content of an audio file, loaded using {@link SoundCache.getSound}. See * {@link SoundObject} for supported formats. - * @param {Vec3} position - The position in the domain to play the sound. * @returns {AudioInjector} The audio injector that plays the audio file. */ - // FIXME: there is no way to play a positionless sound - Q_INVOKABLE ScriptAudioInjector* playSystemSound(SharedSoundPointer sound, const QVector3D& position); + Q_INVOKABLE ScriptAudioInjector* playSystemSound(SharedSoundPointer sound); /**jsdoc * Set whether or not the audio input should be used in stereo. If the audio input does not support stereo then setting a diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index e75687c512..a78b9a17fc 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -210,6 +210,7 @@ void TabletScriptingInterface::playSound(TabletAudioEvents aEvent) { options.stereo = sound->isStereo(); options.ambisonic = sound->isAmbisonic(); options.localOnly = true; + options.positionSet = false; // system sound AudioInjectorPointer injector = AudioInjector::playSoundAndDelete(sound, options); }