Merge pull request #3320 from chansensturm/master

added high-shelf and low-shelf filters, positional audio now uses high-shelf filter
This commit is contained in:
Brad Hefta-Gaub 2014-08-26 13:13:10 -07:00
commit 9b35dc784d
5 changed files with 104 additions and 40 deletions

View file

@ -275,7 +275,7 @@ void AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream*
glm::vec3 relativePosition = streamToAdd->getPosition() - listeningNodeStream->getPosition();
if (relativePosition.z < 0) { // if the source is behind us
AudioFilterPEQ1s& penumbraFilter = streamToAdd->getFilter();
AudioFilterHSF1s& penumbraFilter = streamToAdd->getFilter();
// calculate penumbra angle
float headPenumbraAngle = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f),
@ -288,14 +288,17 @@ void AudioMixer::addStreamToMixForListeningNodeWithStream(PositionalAudioStream*
normalizedHeadPenumbraAngle = EPSILON;
}
const float SQUARE_ROOT_OF_TWO_OVER_TWO = 0.71f;
const float FILTER_CUTOFF_FREQUENCY_HZ = 4000.0f;
float penumbraFilterGain;
float penumbraFilterFrequency;
float penumbraFilterSlope;
// calculate the updated gain
penumbraFilterGain = normalizedHeadPenumbraAngle; // Note this will be tuned - consider this only a crude-first pass at correlating gain with penumbra angle.
penumbraFilterFrequency = 2000.0f;
penumbraFilterSlope = 1.0f; // gentle slope
// 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;

View file

@ -95,7 +95,7 @@ public:
// Implements common base class interface for all Audio Filter Objects
//
template< class T >
class AudioFilterBase {
class AudioFilter {
protected:
@ -119,11 +119,11 @@ public:
//
// ctor/dtor
//
AudioFilterBase() {
AudioFilter() {
setParameters(0.,0.,0.,0.);
}
~AudioFilterBase() {
~AudioFilter() {
}
//
@ -156,7 +156,7 @@ public:
// Implements a low-shelf filter using a biquad
//
class AudioFilterLSF :
public AudioFilterBase< AudioFilterLSF >
public AudioFilter< AudioFilterLSF >
{
public:
@ -164,7 +164,33 @@ public:
// helpers
//
void updateKernel() {
// TBD
const float a = _gain;
const float aAdd1 = a + 1.0f;
const float aSub1 = a - 1.0f;
const float omega = TWO_PI * _frequency / _sampleRate;
const float aAdd1TimesCosOmega = aAdd1 * cosf(omega);
const float aSub1TimesCosOmega = aSub1 * cosf(omega);
const float alpha = 0.5f * sinf(omega) / _slope;
const float zeta = 2.0f * sqrtf(a) * alpha;
/*
b0 = A*( (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha )
b1 = 2*A*( (A-1) - (A+1)*cos(w0) )
b2 = A*( (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha )
a0 = (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha
a1 = -2*( (A-1) + (A+1)*cos(w0) )
a2 = (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha
*/
const float b0 = +1.0f * (aAdd1 - aSub1TimesCosOmega + zeta) * a;
const float b1 = +2.0f * (aSub1 - aAdd1TimesCosOmega + ZERO) * a;
const float b2 = +1.0f * (aAdd1 - aSub1TimesCosOmega - zeta) * a;
const float a0 = +1.0f * (aAdd1 + aSub1TimesCosOmega + zeta);
const float a1 = -2.0f * (aSub1 + aAdd1TimesCosOmega + ZERO);
const float a2 = +1.0f * (aAdd1 + aSub1TimesCosOmega - zeta);
const float normA0 = 1.0f / a0;
_kernel.setParameters(b0 * normA0, b1 * normA0 , b2 * normA0, a1 * normA0, a2 * normA0);
}
};
@ -172,7 +198,7 @@ public:
// Implements a hi-shelf filter using a biquad
//
class AudioFilterHSF :
public AudioFilterBase< AudioFilterHSF >
public AudioFilter< AudioFilterHSF >
{
public:
@ -180,7 +206,33 @@ public:
// helpers
//
void updateKernel() {
// TBD
const float a = _gain;
const float aAdd1 = a + 1.0f;
const float aSub1 = a - 1.0f;
const float omega = TWO_PI * _frequency / _sampleRate;
const float aAdd1TimesCosOmega = aAdd1 * cosf(omega);
const float aSub1TimesCosOmega = aSub1 * cosf(omega);
const float alpha = 0.5f * sinf(omega) / _slope;
const float zeta = 2.0f * sqrtf(a) * alpha;
/*
b0 = A*( (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha )
b1 = -2*A*( (A-1) + (A+1)*cos(w0) )
b2 = A*( (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha )
a0 = (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha
a1 = 2*( (A-1) - (A+1)*cos(w0) )
a2 = (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha
*/
const float b0 = +1.0f * (aAdd1 + aSub1TimesCosOmega + zeta) * a;
const float b1 = -2.0f * (aSub1 + aAdd1TimesCosOmega + ZERO) * a;
const float b2 = +1.0f * (aAdd1 + aSub1TimesCosOmega - zeta) * a;
const float a0 = +1.0f * (aAdd1 - aSub1TimesCosOmega + zeta);
const float a1 = +2.0f * (aSub1 - aAdd1TimesCosOmega + ZERO);
const float a2 = +1.0f * (aAdd1 - aSub1TimesCosOmega - zeta);
const float normA0 = 1.0f / a0;
_kernel.setParameters(b0 * normA0, b1 * normA0 , b2 * normA0, a1 * normA0, a2 * normA0);
}
};
@ -188,7 +240,7 @@ public:
// Implements a single-band parametric EQ using a biquad "peaking EQ" configuration
//
class AudioFilterPEQ :
public AudioFilterBase< AudioFilterPEQ >
public AudioFilter< AudioFilterPEQ >
{
public:
@ -197,26 +249,30 @@ public:
//
void updateKernel() {
const float a = _gain;
const float omega = TWO_PI * _frequency / _sampleRate;
const float alpha = 0.5f * sinf(omega) / _slope;
const float a = _gain;
const float omega = TWO_PI * _frequency / _sampleRate;
const float cosOmega = cosf(omega);
const float alpha = 0.5f * sinf(omega) / _slope;
const float alphaMulA = alpha * a;
const float alphaDivA = alpha / a;
/*
a0 = 1 + alpha*A
a1 = -2*cos(w0)
a2 = 1 - alpha*A
b0 = 1 + alpha*A
b1 = -2*cos(w0)
b2 = 1 - alpha/A
b2 = 1 - alpha*A
a0 = 1 + alpha/A
a1 = -2*cos(w0)
a2 = 1 - alpha/A
*/
const float a0 = 1.0f + (alpha * a);
const float a1 = -2.0f * cosf(omega);
const float a2 = 1.0f - (alpha * a);
const float b1 = a1;
const float b2 = 1.0f - (alpha / a);
const float b0 = +1.0f + alphaMulA;
const float b1 = -2.0f * cosOmega;
const float b2 = +1.0f - alphaMulA;
const float a0 = +1.0f + alphaDivA;
const float a1 = -2.0f * cosOmega;
const float a2 = +1.0f - alphaDivA;
const float scale = 1.0f / (1.0f + (alpha / a));
const float normA0 = 1.0f / a0;
_kernel.setParameters(a0 * scale, a1 * scale, a2 * scale, b1 * scale, b2 * scale);
_kernel.setParameters(b0 * normA0, b1 * normA0 , b2 * normA0, a1 * normA0, a2 * normA0);
}
};

View file

@ -16,29 +16,33 @@
#include "AudioFilterBank.h"
template<>
AudioFilterLSF1s::FilterParameter AudioFilterLSF1s::_profiles[ AudioFilterLSF1s::_profileCount ][ AudioFilterLSF1s::_filterCount ] = {
AudioFilterLSF1s::FilterParameter
AudioFilterLSF1s::_profiles[ AudioFilterLSF1s::_profileCount ][ AudioFilterLSF1s::_filterCount ] = {
// Freq Gain Slope
{ { 1000.0f, 1.0f, 1.0f } } // flat response (default)
};
template<>
AudioFilterHSF1s::FilterParameter AudioFilterHSF1s::_profiles[ AudioFilterHSF1s::_profileCount ][ AudioFilterHSF1s::_filterCount ] = {
AudioFilterHSF1s::FilterParameter
AudioFilterHSF1s::_profiles[ AudioFilterHSF1s::_profileCount ][ AudioFilterHSF1s::_filterCount ] = {
// Freq Gain Slope
{ { 1000.0f, 1.0f, 1.0f } } // flat response (default)
};
template<>
AudioFilterPEQ1s::FilterParameter AudioFilterPEQ1s::_profiles[ AudioFilterPEQ1s::_profileCount ][ AudioFilterPEQ1s::_filterCount ] = {
AudioFilterPEQ1s::FilterParameter
AudioFilterPEQ1s::_profiles[ AudioFilterPEQ1s::_profileCount ][ AudioFilterPEQ1s::_filterCount ] = {
// Freq Gain Q
{ { 1000.0f, 1.0f, 1.0f } } // flat response (default)
};
template<>
AudioFilterPEQ3m::FilterParameter AudioFilterPEQ3m::_profiles[ AudioFilterPEQ3m::_profileCount ][ AudioFilterPEQ3m::_filterCount ] = {
AudioFilterPEQ3m::FilterParameter
AudioFilterPEQ3m::_profiles[ AudioFilterPEQ3m::_profileCount ][ AudioFilterPEQ3m::_filterCount ] = {
// Freq Gain Q Freq Gain Q Freq Gain Q
{ { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // flat response (default)
{ { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 0.1f, 1.0f } }, // treble cut
{ { 300.0f, 0.1f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // bass cut
{ { 300.0f, 1.5f, 0.71f }, { 1000.0f, 0.5f, 1.0f }, { 4000.0f, 1.50f, 0.71f } } // smiley curve
{ { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // flat response (default)
{ { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 0.1f, 1.0f } }, // treble cut
{ { 300.0f, 0.1f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // bass cut
{ { 300.0f, 1.5f, 0.71f }, { 1000.0f, 0.5f, 1.0f }, { 4000.0f, 1.50f, 0.71f } } // smiley curve
};

View file

@ -33,7 +33,8 @@ PositionalAudioStream::PositionalAudioStream(PositionalAudioStream::Type type, b
_lastPopOutputTrailingLoudness(0.0f),
_listenerUnattenuatedZone(NULL)
{
// constant defined in AudioMixer.h. However, we don't want to include this here, since we will soon find a better common home for these audio-related constants
// constant defined in AudioMixer.h. However, we don't want to include this here
// we will soon find a better common home for these audio-related constants
const int SAMPLE_PHASE_DELAY_AT_90 = 20;
_filter.initialize(SAMPLE_RATE, (NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (SAMPLE_PHASE_DELAY_AT_90 * 2)) / 2);
}

View file

@ -46,7 +46,7 @@ public:
void setListenerUnattenuatedZone(AABox* listenerUnattenuatedZone) { _listenerUnattenuatedZone = listenerUnattenuatedZone; }
AudioFilterPEQ1s& getFilter() { return _filter; }
AudioFilterHSF1s& getFilter() { return _filter; }
protected:
// disallow copying of PositionalAudioStream objects
@ -66,7 +66,7 @@ protected:
float _lastPopOutputTrailingLoudness;
AABox* _listenerUnattenuatedZone;
AudioFilterPEQ1s _filter;
AudioFilterHSF1s _filter;
};
#endif // hifi_PositionalAudioStream_h