15fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent/* /android/src/frameworks/base/libs/audioflinger/AudioShelvingFilter.cpp
25fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent**
35fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent** Copyright 2009, The Android Open Source Project
45fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent**
55fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent** Licensed under the Apache License, Version 2.0 (the "License");
65fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent** you may not use this file except in compliance with the License.
75fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent** You may obtain a copy of the License at
85fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent**
95fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent**     http://www.apache.org/licenses/LICENSE-2.0
105fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent**
115fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent** Unless required by applicable law or agreed to in writing, software
125fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent** distributed under the License is distributed on an "AS IS" BASIS,
135fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent** See the License for the specific language governing permissions and
155fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent** limitations under the License.
165fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent*/
175fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
185fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent#include "AudioShelvingFilter.h"
195fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent#include "AudioCommon.h"
205fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent#include "EffectsMath.h"
215fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
225fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent#include <new>
235fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent#include <assert.h>
245fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
255fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
265fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
275fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
285fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurentnamespace android {
295fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent// Format of the coefficient tables:
305fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent// kCoefTable[freq][gain][coef]
315fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent// freq  - cutoff frequency, in octaves below Nyquist,from -10 to -6 in low
325fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent//         shelf, -2 to 0 in high shelf.
335fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent// gain  - gain, in millibel, starting at -9600, jumps of 1024, to 4736 millibel.
345fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent// coef - 0: b0
355fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent//        1: b1
365fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent//        2: b2
375fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent//        3: -a1
385fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent//        4: -a2
395fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurentstatic const size_t kHiInDims[2] = {3, 15};
405fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurentstatic const audio_coef_t kHiCoefTable[3*15*5] = {
415fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent#include "AudioHighShelfFilterCoef.inl"
425fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent};
435fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurentstatic const size_t kLoInDims[2] = {5, 15};
445fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurentstatic const audio_coef_t kLoCoefTable[5*15*5] = {
455fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent#include "AudioLowShelfFilterCoef.inl"
465fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent};
475fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
485fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric LaurentAudioCoefInterpolator AudioShelvingFilter::mHiCoefInterp(2, kHiInDims, 5, (const audio_coef_t*) kHiCoefTable);
495fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric LaurentAudioCoefInterpolator AudioShelvingFilter::mLoCoefInterp(2, kLoInDims, 5, (const audio_coef_t*) kLoCoefTable);
505fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
515fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric LaurentAudioShelvingFilter::AudioShelvingFilter(ShelfType type, int nChannels,
525fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent                                         int sampleRate)
5353334cdb81bab4a4dfd0a41d2ef50709015a36c8Eric Laurent        : mType(type),
5453334cdb81bab4a4dfd0a41d2ef50709015a36c8Eric Laurent          mBiquad(nChannels, sampleRate)  {
555fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    configure(nChannels, sampleRate);
565fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent}
575fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
585fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurentvoid AudioShelvingFilter::configure(int nChannels, int sampleRate) {
595fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    mNiquistFreq = sampleRate * 500;
605fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    mFrequencyFactor = ((1ull) << 42) / mNiquistFreq;
615fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    mBiquad.configure(nChannels, sampleRate);
625fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    setFrequency(mNominalFrequency);
635fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    commit(true);
645fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent}
655fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
665fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurentvoid AudioShelvingFilter::reset() {
675fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    setGain(0);
685fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    setFrequency(mType == kLowShelf ? 0 : mNiquistFreq);
695fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    commit(true);
705fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent}
715fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
725fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurentvoid AudioShelvingFilter::setFrequency(uint32_t millihertz) {
735fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    mNominalFrequency = millihertz;
745fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    if (UNLIKELY(millihertz > mNiquistFreq / 2)) {
755fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent        millihertz = mNiquistFreq / 2;
765fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    }
775fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    uint32_t normFreq = static_cast<uint32_t>(
785fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent            (static_cast<uint64_t>(millihertz) * mFrequencyFactor) >> 10);
795fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    uint32_t log2minFreq = (mType == kLowShelf ? (32-10) : (32-2));
805fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    if (LIKELY(normFreq > (1U << log2minFreq))) {
815fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent        mFrequency = (Effects_log2(normFreq) - (log2minFreq << 15)) << (FREQ_PRECISION_BITS - 15);
825fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    } else {
835fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent        mFrequency = 0;
845fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    }
855fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent}
865fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
875fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurentvoid AudioShelvingFilter::setGain(int32_t millibel) {
885fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    mGain = millibel + 9600;
895fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent}
905fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
915fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurentvoid AudioShelvingFilter::commit(bool immediate) {
925fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    audio_coef_t coefs[5];
935fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    int intCoord[2] = {
945fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent        mFrequency >> FREQ_PRECISION_BITS,
955fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent        mGain >> GAIN_PRECISION_BITS
965fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    };
975fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    uint32_t fracCoord[2] = {
985fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent        mFrequency << (32 - FREQ_PRECISION_BITS),
995fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent        static_cast<uint32_t>(mGain) << (32 - GAIN_PRECISION_BITS)
1005fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    };
1015fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    if (mType == kHighShelf) {
1025fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent        mHiCoefInterp.getCoef(intCoord, fracCoord, coefs);
1035fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    } else {
1045fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent        mLoCoefInterp.getCoef(intCoord, fracCoord, coefs);
1055fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    }
1065fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent    mBiquad.setCoefs(coefs, immediate);
1075fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent}
1085fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent
1095fe37c6838de9fbd959ad19ba44aa3d00d1b4e6fEric Laurent}
110