summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xlibvideoeditor/lvpp/VideoEditorSRC.cpp3
-rwxr-xr-xlibvideoeditor/vss/src/VideoEditorResampler.cpp2
-rw-r--r--services/audioflinger/Android.mk4
-rw-r--r--services/audioflinger/AudioMixer.cpp14
-rw-r--r--services/audioflinger/AudioResampler.cpp134
-rw-r--r--services/audioflinger/AudioResampler.h24
-rw-r--r--services/audioflinger/AudioResamplerCubic.h2
-rw-r--r--services/audioflinger/AudioResamplerSinc.cpp177
-rw-r--r--services/audioflinger/AudioResamplerSinc.h39
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();
};
// ----------------------------------------------------------------------------