diff options
-rwxr-xr-x | libvideoeditor/lvpp/VideoEditorSRC.cpp | 3 | ||||
-rwxr-xr-x | libvideoeditor/vss/src/VideoEditorResampler.cpp | 2 | ||||
-rw-r--r-- | services/audioflinger/Android.mk | 4 | ||||
-rw-r--r-- | services/audioflinger/AudioMixer.cpp | 14 | ||||
-rw-r--r-- | services/audioflinger/AudioResampler.cpp | 134 | ||||
-rw-r--r-- | services/audioflinger/AudioResampler.h | 24 | ||||
-rw-r--r-- | services/audioflinger/AudioResamplerCubic.h | 2 | ||||
-rw-r--r-- | services/audioflinger/AudioResamplerSinc.cpp | 177 | ||||
-rw-r--r-- | services/audioflinger/AudioResamplerSinc.h | 39 |
9 files changed, 272 insertions, 127 deletions
diff --git a/libvideoeditor/lvpp/VideoEditorSRC.cpp b/libvideoeditor/lvpp/VideoEditorSRC.cpp index 4753dd4..36d0812 100755 --- a/libvideoeditor/lvpp/VideoEditorSRC.cpp +++ b/libvideoeditor/lvpp/VideoEditorSRC.cpp @@ -321,8 +321,7 @@ void VideoEditorSRC::checkAndSetResampler() { mResampler = AudioResampler::create( 16 /* bit depth */, mChannelCnt, - mOutputSampleRate, - AudioResampler::DEFAULT); + mOutputSampleRate); CHECK(mResampler); mResampler->setSampleRate(mSampleRate); mResampler->setVolume(kUnityGain, kUnityGain); diff --git a/libvideoeditor/vss/src/VideoEditorResampler.cpp b/libvideoeditor/vss/src/VideoEditorResampler.cpp index 38dffb7..1129c3c 100755 --- a/libvideoeditor/vss/src/VideoEditorResampler.cpp +++ b/libvideoeditor/vss/src/VideoEditorResampler.cpp @@ -80,7 +80,7 @@ M4OSA_Context LVAudioResamplerCreate(M4OSA_Int32 bitDepth, M4OSA_Int32 inChanne VideoEditorResampler *context = new VideoEditorResampler(); context->mResampler = AudioResampler::create( - bitDepth, inChannelCount, sampleRate, AudioResampler::DEFAULT); + bitDepth, inChannelCount, sampleRate); if (context->mResampler == NULL) { return NULL; } diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index 7a1c020..85c2dac 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -20,7 +20,9 @@ LOCAL_SRC_FILES:= \ AudioPolicyService.cpp \ ServiceUtilities.cpp \ AudioResamplerSinc.cpp.arm -# AudioResamplerCubic.cpp.arm + +# uncomment to enable AudioResampler::MED_QUALITY +# LOCAL_SRC_FILES += AudioResamplerCubic.cpp.arm LOCAL_SRC_FILES += StateQueue.cpp diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index ab75dd0..af169d5 100644 --- a/services/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp @@ -539,11 +539,23 @@ bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate) if (sampleRate != value) { sampleRate = value; if (resampler == NULL) { + ALOGV("creating resampler from track %d Hz to device %d Hz", value, devSampleRate); + AudioResampler::src_quality quality; + // force lowest quality level resampler if use case isn't music or video + // FIXME this is flawed for dynamic sample rates, as we choose the resampler + // quality level based on the initial ratio, but that could change later. + // Should have a way to distinguish tracks with static ratios vs. dynamic ratios. + if (!((value == 44100 && devSampleRate == 48000) || + (value == 48000 && devSampleRate == 44100))) { + quality = AudioResampler::LOW_QUALITY; + } else { + quality = AudioResampler::DEFAULT_QUALITY; + } resampler = AudioResampler::create( format, // the resampler sees the number of channels after the downmixer, if any downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount, - devSampleRate); + devSampleRate, quality); resampler->setLocalTimeFreq(localTimeFreq); } return true; diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp index 5c1c905..96293e3 100644 --- a/services/audioflinger/AudioResampler.cpp +++ b/services/audioflinger/AudioResampler.cpp @@ -24,9 +24,7 @@ #include <cutils/properties.h> #include "AudioResampler.h" #include "AudioResamplerSinc.h" -#if 0 #include "AudioResamplerCubic.h" -#endif #ifdef __arm__ #include <machine/cpu-features.h> @@ -42,7 +40,7 @@ namespace android { class AudioResamplerOrder1 : public AudioResampler { public: AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) : - AudioResampler(bitDepth, inChannelCount, sampleRate), mX0L(0), mX0R(0) { + AudioResampler(bitDepth, inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) { } virtual void resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); @@ -79,29 +77,120 @@ private: int mX0R; }; +bool AudioResampler::qualityIsSupported(src_quality quality) +{ + switch (quality) { + case DEFAULT_QUALITY: + case LOW_QUALITY: +#if 0 // these have not been qualified recently so are not supported unless explicitly requested + case MED_QUALITY: + case HIGH_QUALITY: +#endif + case VERY_HIGH_QUALITY: + return true; + default: + return false; + } +} + // ---------------------------------------------------------------------------- -AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount, - int32_t sampleRate, int quality) { - // can only create low quality resample now - AudioResampler* resampler; +static pthread_once_t once_control = PTHREAD_ONCE_INIT; +static AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY; +void AudioResampler::init_routine() +{ char value[PROPERTY_VALUE_MAX]; - if (property_get("af.resampler.quality", value, 0)) { - quality = atoi(value); - ALOGD("forcing AudioResampler quality to %d", quality); + if (property_get("af.resampler.quality", value, NULL) > 0) { + char *endptr; + unsigned long l = strtoul(value, &endptr, 0); + if (*endptr == '\0') { + defaultQuality = (src_quality) l; + ALOGD("forcing AudioResampler quality to %d", defaultQuality); + if (defaultQuality < DEFAULT_QUALITY || defaultQuality > VERY_HIGH_QUALITY) { + defaultQuality = DEFAULT_QUALITY; + } + } } +} - if (quality == DEFAULT) - quality = LOW_QUALITY; +uint32_t AudioResampler::qualityMHz(src_quality quality) +{ + switch (quality) { + default: + case DEFAULT_QUALITY: + case LOW_QUALITY: + return 3; + case MED_QUALITY: + return 6; + case HIGH_QUALITY: + return 20; + case VERY_HIGH_QUALITY: + return 34; + } +} + +static const uint32_t maxMHz = 75; // an arbitrary number that permits 2 VHQ, should be tunable +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static uint32_t currentMHz = 0; + +AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount, + int32_t sampleRate, src_quality quality) { + + bool atFinalQuality; + if (quality == DEFAULT_QUALITY) { + // read the resampler default quality property the first time it is needed + int ok = pthread_once(&once_control, init_routine); + if (ok != 0) { + ALOGE("%s pthread_once failed: %d", __func__, ok); + } + quality = defaultQuality; + atFinalQuality = false; + } else { + atFinalQuality = true; + } + + // naive implementation of CPU load throttling doesn't account for whether resampler is active + pthread_mutex_lock(&mutex); + for (;;) { + uint32_t deltaMHz = qualityMHz(quality); + uint32_t newMHz = currentMHz + deltaMHz; + if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) { + ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d", + currentMHz, newMHz, deltaMHz, quality); + currentMHz = newMHz; + break; + } + // not enough CPU available for proposed quality level, so try next lowest level + switch (quality) { + default: + case DEFAULT_QUALITY: + case LOW_QUALITY: + atFinalQuality = true; + break; + case MED_QUALITY: + quality = LOW_QUALITY; + break; + case HIGH_QUALITY: + quality = MED_QUALITY; + break; + case VERY_HIGH_QUALITY: + quality = HIGH_QUALITY; + break; + } + } + pthread_mutex_unlock(&mutex); + + AudioResampler* resampler; switch (quality) { default: + case DEFAULT_QUALITY: case LOW_QUALITY: ALOGV("Create linear Resampler"); resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate); break; -#if 0 +#if 0 // disabled because it has not been qualified recently, if requested will use default: case MED_QUALITY: ALOGV("Create cubic Resampler"); resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate); @@ -110,8 +199,9 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount, case HIGH_QUALITY: ALOGV("Create HIGH_QUALITY sinc Resampler"); resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate); + break; case VERY_HIGH_QUALITY: - ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d",quality); + ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality); resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate, quality); break; } @@ -122,17 +212,20 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount, } AudioResampler::AudioResampler(int bitDepth, int inChannelCount, - int32_t sampleRate) : + int32_t sampleRate, src_quality quality) : mBitDepth(bitDepth), mChannelCount(inChannelCount), mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0), mPhaseFraction(0), mLocalTimeFreq(0), - mPTS(AudioBufferProvider::kInvalidPTS) { + mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) { // sanity check on format if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) { ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth, inChannelCount); // ALOG_ASSERT(0); } + if (sampleRate <= 0) { + ALOGE("Unsupported sample rate %d Hz", sampleRate); + } // initialize common members mVolume[0] = mVolume[1] = 0; @@ -141,6 +234,15 @@ AudioResampler::AudioResampler(int bitDepth, int inChannelCount, } AudioResampler::~AudioResampler() { + pthread_mutex_lock(&mutex); + src_quality quality = getQuality(); + uint32_t deltaMHz = qualityMHz(quality); + int32_t newMHz = currentMHz - deltaMHz; + ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d", + currentMHz, newMHz, deltaMHz, quality); + LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz); + currentMHz = newMHz; + pthread_mutex_unlock(&mutex); } void AudioResampler::setSampleRate(int32_t inSampleRate) { diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h index 71cdfda..2b8694f 100644 --- a/services/audioflinger/AudioResampler.h +++ b/services/audioflinger/AudioResampler.h @@ -35,15 +35,15 @@ public: // certain fixed rate conversions. Sample rate cannot be // changed dynamically. enum src_quality { - DEFAULT=0, + DEFAULT_QUALITY=0, LOW_QUALITY=1, MED_QUALITY=2, HIGH_QUALITY=3, - VERY_HIGH_QUALITY=255 + VERY_HIGH_QUALITY=4, }; static AudioResampler* create(int bitDepth, int inChannelCount, - int32_t sampleRate, int quality=DEFAULT); + int32_t sampleRate, src_quality quality=DEFAULT_QUALITY); virtual ~AudioResampler(); @@ -61,6 +61,9 @@ public: virtual void reset(); virtual size_t getUnreleasedFrames() const { return mInputIndex; } + // called from destructor, so must not be virtual + src_quality getQuality() const { return mQuality; } + protected: // number of bits for phase fraction - 30 bits allows nearly 2x downsampling static const int kNumPhaseBits = 30; @@ -71,7 +74,7 @@ protected: // multiplier to calculate fixed point phase increment static const double kPhaseMultiplier = 1L << kNumPhaseBits; - AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate); + AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate, src_quality quality); // prevent copying AudioResampler(const AudioResampler&); @@ -94,6 +97,19 @@ protected: uint32_t mPhaseFraction; uint64_t mLocalTimeFreq; int64_t mPTS; + +private: + const src_quality mQuality; + + // Return 'true' if the quality level is supported without explicit request + static bool qualityIsSupported(src_quality quality); + + // For pthread_once() + static void init_routine(); + + // Return the estimated CPU load for specific resampler in MHz. + // The absolute number is irrelevant, it's the relative values that matter. + static uint32_t qualityMHz(src_quality quality); }; // ---------------------------------------------------------------------------- diff --git a/services/audioflinger/AudioResamplerCubic.h b/services/audioflinger/AudioResamplerCubic.h index 892785a..203b933 100644 --- a/services/audioflinger/AudioResamplerCubic.h +++ b/services/audioflinger/AudioResamplerCubic.h @@ -29,7 +29,7 @@ namespace android { class AudioResamplerCubic : public AudioResampler { public: AudioResamplerCubic(int bitDepth, int inChannelCount, int32_t sampleRate) : - AudioResampler(bitDepth, inChannelCount, sampleRate) { + AudioResampler(bitDepth, inChannelCount, sampleRate, MED_QUALITY) { } virtual void resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider); diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp index 0ae4b64..90651f1 100644 --- a/services/audioflinger/AudioResamplerSinc.cpp +++ b/services/audioflinger/AudioResamplerSinc.cpp @@ -64,13 +64,65 @@ const int32_t AudioResamplerSinc::mFirCoefsDown[] = { 0x00000000 // this one is needed for lerping the last coefficient }; -//Define the static variables -int AudioResamplerSinc::coefsBits; -int AudioResamplerSinc::cShift; -uint32_t AudioResamplerSinc::cMask; -int AudioResamplerSinc::pShift; -uint32_t AudioResamplerSinc::pMask; -unsigned int AudioResamplerSinc::halfNumCoefs; +// we use 15 bits to interpolate between these samples +// this cannot change because the mul below rely on it. +static const int pLerpBits = 15; + +static pthread_once_t once_control = PTHREAD_ONCE_INIT; +static readCoefficientsFn readResampleCoefficients = NULL; + +/*static*/ AudioResamplerSinc::Constants AudioResamplerSinc::highQualityConstants; +/*static*/ AudioResamplerSinc::Constants AudioResamplerSinc::veryHighQualityConstants; + +void AudioResamplerSinc::init_routine() +{ + // for high quality resampler, the parameters for coefficients are compile-time constants + Constants *c = &highQualityConstants; + c->coefsBits = RESAMPLE_FIR_LERP_INT_BITS; + c->cShift = kNumPhaseBits - c->coefsBits; + c->cMask = ((1<< c->coefsBits)-1) << c->cShift; + c->pShift = kNumPhaseBits - c->coefsBits - pLerpBits; + c->pMask = ((1<< pLerpBits)-1) << c->pShift; + c->halfNumCoefs = RESAMPLE_FIR_NUM_COEF; + + // for very high quality resampler, the parameters are load-time constants + veryHighQualityConstants = highQualityConstants; + + // Open the dll to get the coefficients for VERY_HIGH_QUALITY + void *resampleCoeffLib = dlopen("libaudio-resampler.so", RTLD_NOW); + ALOGV("Open libaudio-resampler library = %p", resampleCoeffLib); + if (resampleCoeffLib == NULL) { + ALOGE("Could not open audio-resampler library: %s", dlerror()); + return; + } + + readResampleCoefficients = (readCoefficientsFn) dlsym(resampleCoeffLib, + "readResamplerCoefficients"); + readResampleFirNumCoeffFn readResampleFirNumCoeff = (readResampleFirNumCoeffFn) + dlsym(resampleCoeffLib, "readResampleFirNumCoeff"); + readResampleFirLerpIntBitsFn readResampleFirLerpIntBits = (readResampleFirLerpIntBitsFn) + dlsym(resampleCoeffLib, "readResampleFirLerpIntBits"); + if (!readResampleCoefficients || !readResampleFirNumCoeff || !readResampleFirLerpIntBits) { + readResampleCoefficients = NULL; + dlclose(resampleCoeffLib); + resampleCoeffLib = NULL; + ALOGE("Could not find symbol: %s", dlerror()); + return; + } + + c = &veryHighQualityConstants; + // we have 16 coefs samples per zero-crossing + c->coefsBits = readResampleFirLerpIntBits(); + ALOGV("coefsBits = %d", c->coefsBits); + c->cShift = kNumPhaseBits - c->coefsBits; + c->cMask = ((1<<c->coefsBits)-1) << c->cShift; + c->pShift = kNumPhaseBits - c->coefsBits - pLerpBits; + c->pMask = ((1<<pLerpBits)-1) << c->pShift; + // number of zero-crossing on each side + c->halfNumCoefs = readResampleFirNumCoeff(); + ALOGV("halfNumCoefs = %d", c->halfNumCoefs); + // note that we "leak" resampleCoeffLib until the process exits +} // ---------------------------------------------------------------------------- @@ -148,8 +200,8 @@ int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a) // ---------------------------------------------------------------------------- AudioResamplerSinc::AudioResamplerSinc(int bitDepth, - int inChannelCount, int32_t sampleRate, int32_t quality) - : AudioResampler(bitDepth, inChannelCount, sampleRate), + int inChannelCount, int32_t sampleRate, src_quality quality) + : AudioResampler(bitDepth, inChannelCount, sampleRate, quality), mState(0) { /* @@ -168,74 +220,28 @@ AudioResamplerSinc::AudioResamplerSinc(int bitDepth, * */ - mResampleCoeffLib = NULL; - //Intialize the parameters for resampler coefficients - //for high quality - coefsBits = RESAMPLE_FIR_LERP_INT_BITS; - cShift = kNumPhaseBits - coefsBits; - cMask = ((1<< coefsBits)-1) << cShift; - - pShift = kNumPhaseBits - coefsBits - pLerpBits; - pMask = ((1<< pLerpBits)-1) << pShift; - - halfNumCoefs = RESAMPLE_FIR_NUM_COEF; - - //Check if qcom highest quality can be used - char value[PROPERTY_VALUE_MAX]; - //Open the dll to get the coefficients for VERY_HIGH_QUALITY - if (quality == VERY_HIGH_QUALITY ) { - mResampleCoeffLib = dlopen("libaudio-resampler.so", RTLD_NOW); - ALOGV("Open libaudio-resampler library = %p",mResampleCoeffLib); - if (mResampleCoeffLib == NULL) { - ALOGE("Could not open audio-resampler library: %s", dlerror()); - return; - } - mReadResampleCoefficients = (readCoefficientsFn)dlsym(mResampleCoeffLib, "readResamplerCoefficients"); - mReadResampleFirNumCoeff = (readResampleFirNumCoeffFn)dlsym(mResampleCoeffLib, "readResampleFirNumCoeff"); - mReadResampleFirLerpIntBits = (readResampleFirLerpIntBitsFn)dlsym(mResampleCoeffLib,"readResampleFirLerpIntBits"); - if (!mReadResampleCoefficients || !mReadResampleFirNumCoeff || !mReadResampleFirLerpIntBits) { - mReadResampleCoefficients = NULL; - mReadResampleFirNumCoeff = NULL; - mReadResampleFirLerpIntBits = NULL; - dlclose(mResampleCoeffLib); - mResampleCoeffLib = NULL; - ALOGE("Could not find convert symbol: %s", dlerror()); - return; - } - // we have 16 coefs samples per zero-crossing - coefsBits = mReadResampleFirLerpIntBits(); - ALOGV("coefsBits = %d",coefsBits); - cShift = kNumPhaseBits - coefsBits; - cMask = ((1<<coefsBits)-1) << cShift; - pShift = kNumPhaseBits - coefsBits - pLerpBits; - pMask = ((1<<pLerpBits)-1) << pShift; - // number of zero-crossing on each side - halfNumCoefs = mReadResampleFirNumCoeff(); - ALOGV("halfNumCoefs = %d",halfNumCoefs); + // Load the constants for coefficients + int ok = pthread_once(&once_control, init_routine); + if (ok != 0) { + ALOGE("%s pthread_once failed: %d", __func__, ok); } + mConstants = (quality == VERY_HIGH_QUALITY) ? &veryHighQualityConstants : &highQualityConstants; } AudioResamplerSinc::~AudioResamplerSinc() { - if(mResampleCoeffLib) { - ALOGV("close the libaudio-resampler library"); - dlclose(mResampleCoeffLib); - mResampleCoeffLib = NULL; - mReadResampleCoefficients = NULL; - mReadResampleFirNumCoeff = NULL; - mReadResampleFirLerpIntBits = NULL; - } - delete [] mState; + delete[] mState; } void AudioResamplerSinc::init() { + const Constants *c = mConstants; - const size_t numCoefs = 2*halfNumCoefs; + const size_t numCoefs = 2*c->halfNumCoefs; const size_t stateSize = numCoefs * mChannelCount * 2; mState = new int16_t[stateSize]; memset(mState, 0, sizeof(int16_t)*stateSize); - mImpulse = mState + (halfNumCoefs-1)*mChannelCount; + mImpulse = mState + (c->halfNumCoefs-1)*mChannelCount; mRingFull = mImpulse + (numCoefs+1)*mChannelCount; } @@ -243,11 +249,14 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { - if(mResampleCoeffLib){ + // FIXME store current state (up or down sample) and only load the coefs when the state + // changes. Or load two pointers one for up and one for down in the init function. + // Not critical now since the read functions are fast, but would be important if read was slow. + if (readResampleCoefficients) { ALOGV("get coefficient from libmm-audio resampler library"); - mFirCoefs = (mInSampleRate <= mSampleRate) ? mReadResampleCoefficients(true) : mReadResampleCoefficients(false); - } - else { + mFirCoefs = (mInSampleRate <= mSampleRate) ? readResampleCoefficients(true) : + readResampleCoefficients(false); + } else { ALOGV("Use default coefficients"); mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown; } @@ -269,6 +278,7 @@ template<int CHANNELS> void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) { + const Constants *c = mConstants; int16_t* impulse = mImpulse; uint32_t vRL = mVolumeRL; size_t inputIndex = mInputIndex; @@ -307,7 +317,7 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, const size_t frameCount = mBuffer.frameCount; // Always read-in the first samples from the input buffer - int16_t* head = impulse + halfNumCoefs*CHANNELS; + int16_t* head = impulse + c->halfNumCoefs*CHANNELS; head[0] = in[inputIndex*CHANNELS + 0]; if (CHANNELS == 2) head[1] = in[inputIndex*CHANNELS + 1]; @@ -365,15 +375,16 @@ void AudioResamplerSinc::read( int16_t*& impulse, uint32_t& phaseFraction, const int16_t* in, size_t inputIndex) { + const Constants *c = mConstants; const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits; impulse += CHANNELS; phaseFraction -= 1LU<<kNumPhaseBits; if (impulse >= mRingFull) { - const size_t stateSize = (halfNumCoefs*2)*CHANNELS; + const size_t stateSize = (c->halfNumCoefs*2)*CHANNELS; memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize); impulse -= stateSize; } - int16_t* head = impulse + halfNumCoefs*CHANNELS; + int16_t* head = impulse + c->halfNumCoefs*CHANNELS; head[0] = in[inputIndex*CHANNELS + 0]; if (CHANNELS == 2) head[1] = in[inputIndex*CHANNELS + 1]; @@ -383,15 +394,17 @@ template<int CHANNELS> void AudioResamplerSinc::filterCoefficient( int32_t& l, int32_t& r, uint32_t phase, const int16_t *samples) { + const Constants *c = mConstants; + // compute the index of the coefficient on the positive side and // negative side - uint32_t indexP = (phase & cMask) >> cShift; - uint16_t lerpP = (phase & pMask) >> pShift; - uint32_t indexN = (-phase & cMask) >> cShift; - uint16_t lerpN = (-phase & pMask) >> pShift; + uint32_t indexP = (phase & c->cMask) >> c->cShift; + uint16_t lerpP = (phase & c->pMask) >> c->pShift; + uint32_t indexN = (-phase & c->cMask) >> c->cShift; + uint16_t lerpN = (-phase & c->pMask) >> c->pShift; if ((indexP == 0) && (lerpP == 0)) { - indexN = cMask >> cShift; - lerpN = pMask >> pShift; + indexN = c->cMask >> c->cShift; + lerpN = c->pMask >> c->pShift; } l = 0; @@ -399,19 +412,19 @@ void AudioResamplerSinc::filterCoefficient( const int32_t* coefs = mFirCoefs; const int16_t *sP = samples; const int16_t *sN = samples+CHANNELS; - for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) { + for (unsigned int i=0 ; i < c->halfNumCoefs/4 ; i++) { interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; + sP -= CHANNELS; sN += CHANNELS; coefs += 1 << c->coefsBits; interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; + sP -= CHANNELS; sN += CHANNELS; coefs += 1 << c->coefsBits; interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; + sP -= CHANNELS; sN += CHANNELS; coefs += 1 << c->coefsBits; interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP); interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN); - sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits; + sP -= CHANNELS; sN += CHANNELS; coefs += 1 << c->coefsBits; } } diff --git a/services/audioflinger/AudioResamplerSinc.h b/services/audioflinger/AudioResamplerSinc.h index c53c66d..25fc025 100644 --- a/services/audioflinger/AudioResamplerSinc.h +++ b/services/audioflinger/AudioResamplerSinc.h @@ -27,14 +27,15 @@ namespace android { typedef const int32_t * (*readCoefficientsFn)(bool upDownSample); -typedef int32_t (*readResampleFirNumCoeffFn)(); -typedef int32_t (*readResampleFirLerpIntBitsFn)(); +typedef int32_t (*readResampleFirNumCoeffFn)(); +typedef int32_t (*readResampleFirLerpIntBitsFn)(); // ---------------------------------------------------------------------------- class AudioResamplerSinc : public AudioResampler { public: - AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate, int32_t quality = HIGH_QUALITY); + AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate, + src_quality quality = HIGH_QUALITY); virtual ~AudioResamplerSinc(); @@ -60,10 +61,6 @@ private: inline void read(int16_t*& impulse, uint32_t& phaseFraction, const int16_t* in, size_t inputIndex); - readCoefficientsFn mReadResampleCoefficients ; - readResampleFirNumCoeffFn mReadResampleFirNumCoeff; - readResampleFirLerpIntBitsFn mReadResampleFirLerpIntBits; - int16_t *mState; int16_t *mImpulse; int16_t *mRingFull; @@ -72,24 +69,28 @@ private: static const int32_t mFirCoefsDown[]; static const int32_t mFirCoefsUp[]; - void * mResampleCoeffLib; // ---------------------------------------------------------------------------- static const int32_t RESAMPLE_FIR_NUM_COEF = 8; static const int32_t RESAMPLE_FIR_LERP_INT_BITS = 4; - // we have 16 coefs samples per zero-crossing - static int coefsBits; - static int cShift; - static uint32_t cMask; + struct Constants { + // we have 16 coefs samples per zero-crossing + int coefsBits; + int cShift; + uint32_t cMask; + + int pShift; + uint32_t pMask; + + // number of zero-crossing on each side + unsigned int halfNumCoefs; + }; - // and we use 15 bits to interpolate between these samples - // this cannot change because the mul below rely on it. - static const int pLerpBits = 15; - static int pShift; - static uint32_t pMask; + static Constants highQualityConstants; + static Constants veryHighQualityConstants; + const Constants *mConstants; // points to appropriate set of coefficient parameters - // number of zero-crossing on each side - static unsigned int halfNumCoefs; + static void init_routine(); }; // ---------------------------------------------------------------------------- |