mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 17:41:12 +02:00
left/right channels of head shadow filter now have independent gain + implemented all-pass filter
This commit is contained in:
parent
e8c3125985
commit
0881959750
2 changed files with 56 additions and 20 deletions
|
@ -308,38 +308,37 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream*
|
||||||
if (_enableFilter && shouldAttenuate) {
|
if (_enableFilter && shouldAttenuate) {
|
||||||
|
|
||||||
glm::vec3 relativePosition = streamToAdd->getPosition() - listeningNodeStream->getPosition();
|
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();
|
AudioFilterHSF1s& penumbraFilter = streamToAdd->getFilter();
|
||||||
|
|
||||||
// calculate penumbra angle
|
// calculate penumbra angle
|
||||||
float headPenumbraAngle = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f),
|
float headPenumbraAngle = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f),
|
||||||
glm::normalize(relativePosition));
|
glm::normalize(relativePosition));
|
||||||
|
|
||||||
// normalize penumbra angle
|
if (relativePosition.x < 0) {
|
||||||
float normalizedHeadPenumbraAngle = headPenumbraAngle / PI_OVER_TWO;
|
headPenumbraAngle *= -1.0f; // [-pi/2,+pi/2]
|
||||||
|
|
||||||
if (normalizedHeadPenumbraAngle < EPSILON) {
|
|
||||||
normalizedHeadPenumbraAngle = EPSILON;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
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
|
// set the gain on both filter channels
|
||||||
penumbraFilter.setParameters(0, 0, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGain, penumbraFilterSlope);
|
penumbraFilter.setParameters(0, 0, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainL, penumbraFilterSlope);
|
||||||
penumbraFilter.setParameters(0, 1, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGain, penumbraFilterSlope);
|
penumbraFilter.setParameters(0, 1, SAMPLE_RATE, penumbraFilterFrequency, penumbraFilterGainR, penumbraFilterSlope);
|
||||||
|
|
||||||
penumbraFilter.render(_clientSamples, _clientSamples, NETWORK_BUFFER_LENGTH_SAMPLES_STEREO / 2);
|
penumbraFilter.render(_clientSamples, _clientSamples, NETWORK_BUFFER_LENGTH_SAMPLES_STEREO / 2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
// Implements a single-band parametric EQ using a biquad "peaking EQ" configuration
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue