From 08819597500b1f807f5005844e321364abcbccdd Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Wed, 27 Aug 2014 17:30:11 -0700 Subject: [PATCH] left/right channels of head shadow filter now have independent gain + implemented all-pass filter --- assignment-client/src/audio/AudioMixer.cpp | 39 +++++++++++----------- libraries/audio/src/AudioFilter.h | 37 ++++++++++++++++++++ 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 52a922b4e3..b0d9cae8d9 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -308,38 +308,37 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream* if (_enableFilter && shouldAttenuate) { glm::vec3 relativePosition = streamToAdd->getPosition() - listeningNodeStream->getPosition(); - if (relativePosition.z < 0) { // if the source is behind us - + if (relativePosition.z < 0) { // if the source is behind us AudioFilterHSF1s& penumbraFilter = streamToAdd->getFilter(); // calculate penumbra angle float headPenumbraAngle = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f), glm::normalize(relativePosition)); - // normalize penumbra angle - float normalizedHeadPenumbraAngle = headPenumbraAngle / PI_OVER_TWO; - - if (normalizedHeadPenumbraAngle < EPSILON) { - normalizedHeadPenumbraAngle = EPSILON; + if (relativePosition.x < 0) { + headPenumbraAngle *= -1.0f; // [-pi/2,+pi/2] } - const float SQUARE_ROOT_OF_TWO_OVER_TWO = 0.71f; + const float SQUARE_ROOT_OF_TWO_OVER_TWO = 0.71f; // half power + const float ONE_OVER_TWO_PI = 1.0f / TWO_PI; const float FILTER_CUTOFF_FREQUENCY_HZ = 4000.0f; - float penumbraFilterGain; - float penumbraFilterFrequency; - float penumbraFilterSlope; - - // calculate the updated gain. this will be tuned over time. - // consider this only a crude-first pass at correlating gain, freq and slope with penumbra angle. - penumbraFilterGain = SQUARE_ROOT_OF_TWO_OVER_TWO * (normalizedHeadPenumbraAngle + SQUARE_ROOT_OF_TWO_OVER_TWO); - penumbraFilterFrequency = FILTER_CUTOFF_FREQUENCY_HZ; // constant frequency - penumbraFilterSlope = SQUARE_ROOT_OF_TWO_OVER_TWO; // constant slope - qDebug() << "penumbra gain=" << penumbraFilterGain << ", penumbraAngle=" << normalizedHeadPenumbraAngle; + // calculate the updated gain, frequency and slope. this will be tuned over time. + const float penumbraFilterGainL = (-1.0f * ONE_OVER_TWO_PI * headPenumbraAngle ) + SQUARE_ROOT_OF_TWO_OVER_TWO; + const float penumbraFilterGainR = (+1.0f * ONE_OVER_TWO_PI * headPenumbraAngle ) + SQUARE_ROOT_OF_TWO_OVER_TWO; + const float penumbraFilterFrequency = FILTER_CUTOFF_FREQUENCY_HZ; // constant frequency + const float penumbraFilterSlope = SQUARE_ROOT_OF_TWO_OVER_TWO; // constant slope + + qDebug() << "penumbra gainL=" + << penumbraFilterGainL + << "penumbra gainR=" + << penumbraFilterGainR + << "penumbraAngle=" + << headPenumbraAngle; // set the gain on both filter channels - penumbraFilter.setParameters(0, 0, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGain, penumbraFilterSlope); - penumbraFilter.setParameters(0, 1, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGain, penumbraFilterSlope); + penumbraFilter.setParameters(0, 0, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainL, penumbraFilterSlope); + penumbraFilter.setParameters(0, 1, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainR, penumbraFilterSlope); penumbraFilter.render(_clientSamples, _clientSamples, NETWORK_BUFFER_LENGTH_SAMPLES_STEREO / 2); } diff --git a/libraries/audio/src/AudioFilter.h b/libraries/audio/src/AudioFilter.h index 7c3c98582b..eb65593e51 100644 --- a/libraries/audio/src/AudioFilter.h +++ b/libraries/audio/src/AudioFilter.h @@ -236,6 +236,43 @@ public: } }; +// +// Implements a all-pass filter using a biquad +// +class AudioFilterALL : +public AudioFilter< AudioFilterALL > +{ +public: + + // + // helpers + // + void updateKernel() { + + const float omega = TWO_PI * _frequency / _sampleRate; + const float cosOmega = cosf(omega); + const float alpha = 0.5f * sinf(omega) / _slope; + /* + b0 = 1 - alpha + b1 = -2*cos(w0) + b2 = 1 + alpha + a0 = 1 + alpha + a1 = -2*cos(w0) + a2 = 1 - alpha + */ + const float b0 = +1.0f - alpha; + const float b1 = -2.0f * cosOmega; + const float b2 = +1.0f + alpha; + const float a0 = +1.0f + alpha; + const float a1 = -2.0f * cosOmega; + const float a2 = +1.0f - alpha; + + const float normA0 = 1.0f / a0; + + _kernel.setParameters(b0 * normA0, b1 * normA0 , b2 * normA0, a1 * normA0, a2 * normA0); + } +}; + // // Implements a single-band parametric EQ using a biquad "peaking EQ" configuration //