Merge pull request #14797 from kencooke/audio-injector-stereo-distattn-bugfix2

case 20805: RC78.1 to master: Fix the distance attenuation of stereo local injectors
This commit is contained in:
Shannon Romano 2019-01-29 13:12:51 -08:00 committed by GitHub
commit 72d3eb9d33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 60 additions and 26 deletions

View file

@ -4194,7 +4194,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<bool> notificationSounds{ MenuOption::NotificationSounds, true };
Setting::Handle<bool> notificationSoundSnapshot{ MenuOption::NotificationSoundsSnapshot, true };
if (notificationSounds.get() && notificationSoundSnapshot.get()) {

View file

@ -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 {

View file

@ -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; }

View file

@ -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,13 @@ 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));
if (injectorOptions.positionSet) {
obj.setProperty("position", vec3ToScriptValue(engine, injectorOptions.position));
}
obj.setProperty("volume", injectorOptions.volume);
obj.setProperty("loop", injectorOptions.loop);
obj.setProperty("orientation", quatToScriptValue(engine, injectorOptions.orientation));
@ -68,12 +70,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") {

View file

@ -21,6 +21,7 @@ class AudioInjectorOptions {
public:
AudioInjectorOptions();
glm::vec3 position;
bool positionSet;
float volume;
bool loop;
glm::quat orientation;

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}