summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioResampler.cpp11
-rw-r--r--services/audioflinger/AudioResamplerDyn.cpp251
-rw-r--r--services/audioflinger/AudioResamplerDyn.h82
-rw-r--r--services/audioflinger/AudioResamplerFirGen.h5
-rw-r--r--services/audioflinger/AudioResamplerFirProcess.h247
-rw-r--r--services/audioflinger/test-resample.cpp92
6 files changed, 410 insertions, 278 deletions
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index ca98f16..562c4ea 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -234,7 +234,16 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
case DYN_MED_QUALITY:
case DYN_HIGH_QUALITY:
ALOGV("Create dynamic Resampler = %d", quality);
- resampler = new AudioResamplerDyn(bitDepth, inChannelCount, sampleRate, quality);
+ if (bitDepth == 32) { /* bitDepth == 32 signals float precision */
+ resampler = new AudioResamplerDyn<float, float, float>(bitDepth, inChannelCount,
+ sampleRate, quality);
+ } else if (quality == DYN_HIGH_QUALITY) {
+ resampler = new AudioResamplerDyn<int32_t, int16_t, int32_t>(bitDepth, inChannelCount,
+ sampleRate, quality);
+ } else {
+ resampler = new AudioResamplerDyn<int16_t, int16_t, int32_t>(bitDepth, inChannelCount,
+ sampleRate, quality);
+ }
break;
}
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index 7e4ca0c..3abe8fd 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -25,6 +25,7 @@
#include <cutils/compiler.h>
#include <cutils/properties.h>
+#include <utils/Debug.h>
#include <utils/Log.h>
#include "AudioResamplerFirOps.h" // USE_NEON and USE_INLINE_ASSEMBLY defined here
@@ -38,9 +39,9 @@
namespace android {
// generate a unique resample type compile-time constant (constexpr)
-#define RESAMPLETYPE(CHANNELS, LOCKED, STRIDE, COEFTYPE) \
- ((((CHANNELS)-1)&1) | !!(LOCKED)<<1 | (COEFTYPE)<<2 \
- | ((STRIDE)==8 ? 1 : (STRIDE)==16 ? 2 : 0)<<3)
+#define RESAMPLETYPE(CHANNELS, LOCKED, STRIDE) \
+ ((((CHANNELS)-1)&1) | !!(LOCKED)<<1 \
+ | ((STRIDE)==8 ? 1 : (STRIDE)==16 ? 2 : 0)<<2)
/*
* InBuffer is a type agnostic input buffer.
@@ -58,42 +59,46 @@ namespace android {
* r = extra space for implementing the ring buffer
*/
-template<typename TI>
-AudioResamplerDyn::InBuffer<TI>::InBuffer()
- : mState(NULL), mImpulse(NULL), mRingFull(NULL), mStateSize(0) {
+template<typename TC, typename TI, typename TO>
+AudioResamplerDyn<TC, TI, TO>::InBuffer::InBuffer()
+ : mState(NULL), mImpulse(NULL), mRingFull(NULL), mStateCount(0)
+{
}
-template<typename TI>
-AudioResamplerDyn::InBuffer<TI>::~InBuffer() {
+template<typename TC, typename TI, typename TO>
+AudioResamplerDyn<TC, TI, TO>::InBuffer::~InBuffer()
+{
init();
}
-template<typename TI>
-void AudioResamplerDyn::InBuffer<TI>::init() {
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::InBuffer::init()
+{
free(mState);
mState = NULL;
mImpulse = NULL;
mRingFull = NULL;
- mStateSize = 0;
+ mStateCount = 0;
}
// resizes the state buffer to accommodate the appropriate filter length
-template<typename TI>
-void AudioResamplerDyn::InBuffer<TI>::resize(int CHANNELS, int halfNumCoefs) {
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::InBuffer::resize(int CHANNELS, int halfNumCoefs)
+{
// calculate desired state size
- int stateSize = halfNumCoefs * CHANNELS * 2
- * kStateSizeMultipleOfFilterLength;
+ int stateCount = halfNumCoefs * CHANNELS * 2 * kStateSizeMultipleOfFilterLength;
// check if buffer needs resizing
if (mState
- && stateSize == mStateSize
- && mRingFull-mState == mStateSize-halfNumCoefs*CHANNELS) {
+ && stateCount == mStateCount
+ && mRingFull-mState == mStateCount-halfNumCoefs*CHANNELS) {
return;
}
// create new buffer
- TI* state = (int16_t*)memalign(32, stateSize*sizeof(*state));
- memset(state, 0, stateSize*sizeof(*state));
+ TI* state;
+ (void)posix_memalign(reinterpret_cast<void**>(&state), 32, stateCount*sizeof(*state));
+ memset(state, 0, stateCount*sizeof(*state));
// attempt to preserve state
if (mState) {
@@ -105,8 +110,8 @@ void AudioResamplerDyn::InBuffer<TI>::resize(int CHANNELS, int halfNumCoefs) {
dst += mState-srcLo;
srcLo = mState;
}
- if (srcHi > mState + mStateSize) {
- srcHi = mState + mStateSize;
+ if (srcHi > mState + mStateCount) {
+ srcHi = mState + mStateCount;
}
memcpy(dst, srcLo, (srcHi - srcLo) * sizeof(*srcLo));
free(mState);
@@ -114,27 +119,29 @@ void AudioResamplerDyn::InBuffer<TI>::resize(int CHANNELS, int halfNumCoefs) {
// set class member vars
mState = state;
- mStateSize = stateSize;
- mImpulse = mState + halfNumCoefs*CHANNELS; // actually one sample greater than needed
- mRingFull = mState + mStateSize - halfNumCoefs*CHANNELS;
+ mStateCount = stateCount;
+ mImpulse = state + halfNumCoefs*CHANNELS; // actually one sample greater than needed
+ mRingFull = state + mStateCount - halfNumCoefs*CHANNELS;
}
// copy in the input data into the head (impulse+halfNumCoefs) of the buffer.
-template<typename TI>
+template<typename TC, typename TI, typename TO>
template<int CHANNELS>
-void AudioResamplerDyn::InBuffer<TI>::readAgain(TI*& impulse, const int halfNumCoefs,
- const TI* const in, const size_t inputIndex) {
- int16_t* head = impulse + halfNumCoefs*CHANNELS;
+void AudioResamplerDyn<TC, TI, TO>::InBuffer::readAgain(TI*& impulse, const int halfNumCoefs,
+ const TI* const in, const size_t inputIndex)
+{
+ TI* head = impulse + halfNumCoefs*CHANNELS;
for (size_t i=0 ; i<CHANNELS ; i++) {
head[i] = in[inputIndex*CHANNELS + i];
}
}
// advance the impulse pointer, and load in data into the head (impulse+halfNumCoefs)
-template<typename TI>
+template<typename TC, typename TI, typename TO>
template<int CHANNELS>
-void AudioResamplerDyn::InBuffer<TI>::readAdvance(TI*& impulse, const int halfNumCoefs,
- const TI* const in, const size_t inputIndex) {
+void AudioResamplerDyn<TC, TI, TO>::InBuffer::readAdvance(TI*& impulse, const int halfNumCoefs,
+ const TI* const in, const size_t inputIndex)
+{
impulse += CHANNELS;
if (CC_UNLIKELY(impulse >= mRingFull)) {
@@ -145,7 +152,8 @@ void AudioResamplerDyn::InBuffer<TI>::readAdvance(TI*& impulse, const int halfNu
readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
}
-void AudioResamplerDyn::Constants::set(
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::Constants::set(
int L, int halfNumCoefs, int inSampleRate, int outSampleRate)
{
int bits = 0;
@@ -158,10 +166,11 @@ void AudioResamplerDyn::Constants::set(
mHalfNumCoefs = halfNumCoefs;
}
-AudioResamplerDyn::AudioResamplerDyn(int bitDepth,
+template<typename TC, typename TI, typename TO>
+AudioResamplerDyn<TC, TI, TO>::AudioResamplerDyn(int bitDepth,
int inChannelCount, int32_t sampleRate, src_quality quality)
: AudioResampler(bitDepth, inChannelCount, sampleRate, quality),
- mResampleType(0), mFilterSampleRate(0), mFilterQuality(DEFAULT_QUALITY),
+ mResampleFunc(0), mFilterSampleRate(0), mFilterQuality(DEFAULT_QUALITY),
mCoefBuffer(NULL)
{
mVolumeSimd[0] = mVolumeSimd[1] = 0;
@@ -172,33 +181,48 @@ AudioResamplerDyn::AudioResamplerDyn(int bitDepth,
mConstants.set(128, 8, mSampleRate, mSampleRate); // TODO: set better
}
-AudioResamplerDyn::~AudioResamplerDyn() {
+template<typename TC, typename TI, typename TO>
+AudioResamplerDyn<TC, TI, TO>::~AudioResamplerDyn()
+{
free(mCoefBuffer);
}
-void AudioResamplerDyn::init() {
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::init()
+{
mFilterSampleRate = 0; // always trigger new filter generation
mInBuffer.init();
}
-void AudioResamplerDyn::setVolume(int16_t left, int16_t right) {
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::setVolume(int16_t left, int16_t right)
+{
AudioResampler::setVolume(left, right);
- mVolumeSimd[0] = static_cast<int32_t>(left)<<16;
- mVolumeSimd[1] = static_cast<int32_t>(right)<<16;
+ // volume is applied on the output type.
+ if (is_same<TO, float>::value || is_same<TO, double>::value) {
+ const TO scale = 1. / (1UL << 12);
+ mVolumeSimd[0] = static_cast<TO>(left) * scale;
+ mVolumeSimd[1] = static_cast<TO>(right) * scale;
+ } else {
+ mVolumeSimd[0] = static_cast<int32_t>(left) << 16;
+ mVolumeSimd[1] = static_cast<int32_t>(right) << 16;
+ }
}
-template <typename T> T max(T a, T b) {return a > b ? a : b;}
+template<typename T> T max(T a, T b) {return a > b ? a : b;}
-template <typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;}
+template<typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;}
-template<typename T>
-void AudioResamplerDyn::createKaiserFir(Constants &c, double stopBandAtten,
- int inSampleRate, int outSampleRate, double tbwCheat) {
- T* buf = reinterpret_cast<T*>(memalign(32, (c.mL+1)*c.mHalfNumCoefs*sizeof(T)));
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::createKaiserFir(Constants &c,
+ double stopBandAtten, int inSampleRate, int outSampleRate, double tbwCheat)
+{
+ TC* buf;
static const double atten = 0.9998; // to avoid ripple overflow
double fcr;
double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
+ (void)posix_memalign(reinterpret_cast<void**>(&buf), 32, (c.mL+1)*c.mHalfNumCoefs*sizeof(TC));
if (inSampleRate < outSampleRate) { // upsample
fcr = max(0.5*tbwCheat - tbw/2, tbw/2);
} else { // downsample
@@ -206,7 +230,7 @@ void AudioResamplerDyn::createKaiserFir(Constants &c, double stopBandAtten,
}
// create and set filter
firKaiserGen(buf, c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten);
- c.setBuf(buf);
+ c.mFirCoefs = buf;
if (mCoefBuffer) {
free(mCoefBuffer);
}
@@ -228,7 +252,8 @@ void AudioResamplerDyn::createKaiserFir(Constants &c, double stopBandAtten,
}
// recursive gcd. Using objdump, it appears the tail recursion is converted to a while loop.
-static int gcd(int n, int m) {
+static int gcd(int n, int m)
+{
if (m == 0) {
return n;
}
@@ -236,7 +261,8 @@ static int gcd(int n, int m) {
}
static bool isClose(int32_t newSampleRate, int32_t prevSampleRate,
- int32_t filterSampleRate, int32_t outSampleRate) {
+ int32_t filterSampleRate, int32_t outSampleRate)
+{
// different upsampling ratios do not need a filter change.
if (filterSampleRate != 0
@@ -253,7 +279,9 @@ static bool isClose(int32_t newSampleRate, int32_t prevSampleRate,
return pdiff < prevSampleRate>>4 && adiff < filterSampleRate>>3;
}
-void AudioResamplerDyn::setSampleRate(int32_t inSampleRate) {
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::setSampleRate(int32_t inSampleRate)
+{
if (mInSampleRate == inSampleRate) {
return;
}
@@ -357,13 +385,8 @@ void AudioResamplerDyn::setSampleRate(int32_t inSampleRate) {
// create the filter
mConstants.set(phases, halfLength, inSampleRate, mSampleRate);
- if (useS32) {
- createKaiserFir<int32_t>(mConstants, stopBandAtten,
- inSampleRate, mSampleRate, tbwCheat);
- } else {
- createKaiserFir<int16_t>(mConstants, stopBandAtten,
- inSampleRate, mSampleRate, tbwCheat);
- }
+ createKaiserFir(mConstants, stopBandAtten,
+ inSampleRate, mSampleRate, tbwCheat);
} // End Kaiser filter
// update phase and state based on the new filter.
@@ -385,7 +408,7 @@ void AudioResamplerDyn::setSampleRate(int32_t inSampleRate) {
mPhaseFraction = mPhaseFraction >> c.mShift << c.mShift; // remove fractional phase
}
- mResampleType = RESAMPLETYPE(mChannelCount, locked, stride, !!useS32);
+ setResampler(RESAMPLETYPE(mChannelCount, locked, stride));
#ifdef DEBUG_RESAMPLER
printf("channels:%d %s stride:%d %s coef:%d shift:%d\n",
mChannelCount, locked ? "locked" : "interpolated",
@@ -393,78 +416,45 @@ void AudioResamplerDyn::setSampleRate(int32_t inSampleRate) {
#endif
}
-void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount,
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider)
{
- // TODO:
- // 24 cases - this perhaps can be reduced later, as testing might take too long
- switch (mResampleType) {
+ (this->*mResampleFunc)(reinterpret_cast<TO*>(out), outFrameCount, provider);
+}
+template<typename TC, typename TI, typename TO>
+void AudioResamplerDyn<TC, TI, TO>::setResampler(unsigned resampleType)
+{
// stride 16 (falls back to stride 2 for machines that do not support NEON)
- case RESAMPLETYPE(1, true, 16, 0):
- return resample<1, true, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(2, true, 16, 0):
- return resample<2, true, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(1, false, 16, 0):
- return resample<1, false, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(2, false, 16, 0):
- return resample<2, false, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(1, true, 16, 1):
- return resample<1, true, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
- case RESAMPLETYPE(2, true, 16, 1):
- return resample<2, true, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
- case RESAMPLETYPE(1, false, 16, 1):
- return resample<1, false, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
- case RESAMPLETYPE(2, false, 16, 1):
- return resample<2, false, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-#if 0
- // TODO: Remove these?
- // stride 8
- case RESAMPLETYPE(1, true, 8, 0):
- return resample<1, true, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(2, true, 8, 0):
- return resample<2, true, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(1, false, 8, 0):
- return resample<1, false, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(2, false, 8, 0):
- return resample<2, false, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(1, true, 8, 1):
- return resample<1, true, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
- case RESAMPLETYPE(2, true, 8, 1):
- return resample<2, true, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
- case RESAMPLETYPE(1, false, 8, 1):
- return resample<1, false, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
- case RESAMPLETYPE(2, false, 8, 1):
- return resample<2, false, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
- // stride 2 (can handle any filter length)
- case RESAMPLETYPE(1, true, 2, 0):
- return resample<1, true, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(2, true, 2, 0):
- return resample<2, true, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(1, false, 2, 0):
- return resample<1, false, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(2, false, 2, 0):
- return resample<2, false, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
- case RESAMPLETYPE(1, true, 2, 1):
- return resample<1, true, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
- case RESAMPLETYPE(2, true, 2, 1):
- return resample<2, true, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
- case RESAMPLETYPE(1, false, 2, 1):
- return resample<1, false, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
- case RESAMPLETYPE(2, false, 2, 1):
- return resample<2, false, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
-#endif
+ switch (resampleType) {
+ case RESAMPLETYPE(1, true, 16):
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, true, 16>;
+ return;
+ case RESAMPLETYPE(2, true, 16):
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, true, 16>;
+ return;
+ case RESAMPLETYPE(1, false, 16):
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, false, 16>;
+ return;
+ case RESAMPLETYPE(2, false, 16):
+ mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, false, 16>;
+ return;
default:
- ; // error
+ LOG_ALWAYS_FATAL("Invalid resampler type: %u", resampleType);
+ mResampleFunc = NULL;
+ return;
}
}
-template<int CHANNELS, bool LOCKED, int STRIDE, typename TC>
-void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount,
- const TC* const coefs, AudioBufferProvider* provider)
+template<typename TC, typename TI, typename TO>
+template<int CHANNELS, bool LOCKED, int STRIDE>
+void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
+ AudioBufferProvider* provider)
{
const Constants& c(mConstants);
- int16_t* impulse = mInBuffer.getImpulse();
+ const TC* const coefs = mConstants.mFirCoefs;
+ TI* impulse = mInBuffer.getImpulse();
size_t inputIndex = mInputIndex;
uint32_t phaseFraction = mPhaseFraction;
const uint32_t phaseIncrement = mPhaseIncrement;
@@ -490,8 +480,9 @@ void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount,
goto resample_exit;
}
if (phaseFraction >= phaseWrapLimit) { // read in data
- mInBuffer.readAdvance<CHANNELS>(
- impulse, c.mHalfNumCoefs, mBuffer.i16, inputIndex);
+ mInBuffer.template readAdvance<CHANNELS>(
+ impulse, c.mHalfNumCoefs,
+ reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
phaseFraction -= phaseWrapLimit;
while (phaseFraction >= phaseWrapLimit) {
inputIndex++;
@@ -500,20 +491,21 @@ void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount,
provider->releaseBuffer(&mBuffer);
break;
}
- mInBuffer.readAdvance<CHANNELS>(
- impulse, c.mHalfNumCoefs, mBuffer.i16, inputIndex);
+ mInBuffer.template readAdvance<CHANNELS>(
+ impulse, c.mHalfNumCoefs,
+ reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
phaseFraction -= phaseWrapLimit;
}
}
}
- const int16_t* const in = mBuffer.i16;
+ const TI* const in = reinterpret_cast<const TI*>(mBuffer.raw);
const size_t frameCount = mBuffer.frameCount;
const int coefShift = c.mShift;
const int halfNumCoefs = c.mHalfNumCoefs;
- const int32_t* const volumeSimd = mVolumeSimd;
+ const TO* const volumeSimd = mVolumeSimd;
// reread the last input in.
- mInBuffer.readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
+ mInBuffer.template readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
// main processing loop
while (CC_LIKELY(outputIndex < outputSampleCount)) {
@@ -536,7 +528,7 @@ void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount,
if (inputIndex >= frameCount) {
goto done; // need a new buffer
}
- mInBuffer.readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
+ mInBuffer.template readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
phaseFraction -= phaseWrapLimit;
}
}
@@ -555,5 +547,10 @@ resample_exit:
mPhaseFraction = phaseFraction;
}
+/* instantiate templates used by AudioResampler::create */
+template class AudioResamplerDyn<float, float, float>;
+template class AudioResamplerDyn<int16_t, int16_t, int32_t>;
+template class AudioResamplerDyn<int32_t, int16_t, int32_t>;
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/services/audioflinger/AudioResamplerDyn.h b/services/audioflinger/AudioResamplerDyn.h
index df1fdbe..8c56319 100644
--- a/services/audioflinger/AudioResamplerDyn.h
+++ b/services/audioflinger/AudioResamplerDyn.h
@@ -25,10 +25,24 @@
namespace android {
+/* AudioResamplerDyn
+ *
+ * This class template is used for floating point and integer resamplers.
+ *
+ * Type variables:
+ * TC = filter coefficient type (one of int16_t, int32_t, or float)
+ * TI = input data type (one of int16_t or float)
+ * TO = output data type (one of int32_t or float)
+ *
+ * For integer input data types TI, the coefficient type TC is either int16_t or int32_t.
+ * For float input data types TI, the coefficient type TC is float.
+ */
+
+template<typename TC, typename TI, typename TO>
class AudioResamplerDyn: public AudioResampler {
public:
- AudioResamplerDyn(int bitDepth, int inChannelCount, int32_t sampleRate,
- src_quality quality);
+ AudioResamplerDyn(int bitDepth, int inChannelCount,
+ int32_t sampleRate, src_quality quality);
virtual ~AudioResamplerDyn();
@@ -46,46 +60,38 @@ private:
class Constants { // stores the filter constants.
public:
Constants() :
- mL(0), mShift(0), mHalfNumCoefs(0), mFirCoefsS16(NULL)
+ mL(0), mShift(0), mHalfNumCoefs(0), mFirCoefs(NULL)
{}
void set(int L, int halfNumCoefs,
int inSampleRate, int outSampleRate);
- inline void setBuf(int16_t* buf) {
- mFirCoefsS16 = buf;
- }
- inline void setBuf(int32_t* buf) {
- mFirCoefsS32 = buf;
- }
- int mL; // interpolation phases in the filter.
- int mShift; // right shift to get polyphase index
+ int mL; // interpolation phases in the filter.
+ int mShift; // right shift to get polyphase index
unsigned int mHalfNumCoefs; // filter half #coefs
- union { // polyphase filter bank
- const int16_t* mFirCoefsS16;
- const int32_t* mFirCoefsS32;
- };
+ const TC* mFirCoefs; // polyphase filter bank
};
- // Input buffer management for a given input type TI, now (int16_t)
- // Is agnostic of the actual type, can work with int32_t and float.
- template<typename TI>
- class InBuffer {
+ class InBuffer { // buffer management for input type TI
public:
InBuffer();
~InBuffer();
void init();
+
void resize(int CHANNELS, int halfNumCoefs);
// used for direct management of the mImpulse pointer
inline TI* getImpulse() {
return mImpulse;
}
+
inline void setImpulse(TI *impulse) {
mImpulse = impulse;
}
+
template<int CHANNELS>
inline void readAgain(TI*& impulse, const int halfNumCoefs,
const TI* const in, const size_t inputIndex);
+
template<int CHANNELS>
inline void readAdvance(TI*& impulse, const int halfNumCoefs,
const TI* const in, const size_t inputIndex);
@@ -94,31 +100,35 @@ private:
// tuning parameter guidelines: 2 <= multiple <= 8
static const int kStateSizeMultipleOfFilterLength = 4;
- TI* mState; // base pointer for the input buffer storage
- TI* mImpulse; // current location of the impulse response (centered)
- TI* mRingFull; // mState <= mImpulse < mRingFull
// in general, mRingFull = mState + mStateSize - halfNumCoefs*CHANNELS.
- size_t mStateSize; // in units of TI.
+ TI* mState; // base pointer for the input buffer storage
+ TI* mImpulse; // current location of the impulse response (centered)
+ TI* mRingFull; // mState <= mImpulse < mRingFull
+ size_t mStateCount; // size of state in units of TI.
};
- template<int CHANNELS, bool LOCKED, int STRIDE, typename TC>
- void resample(int32_t* out, size_t outFrameCount,
- const TC* const coefs, AudioBufferProvider* provider);
-
- template<typename T>
void createKaiserFir(Constants &c, double stopBandAtten,
int inSampleRate, int outSampleRate, double tbwCheat);
- InBuffer<int16_t> mInBuffer;
- Constants mConstants; // current set of coefficient parameters
- int32_t __attribute__ ((aligned (8))) mVolumeSimd[2];
- int32_t mResampleType; // contains the resample type.
- int32_t mFilterSampleRate; // designed filter sample rate.
- src_quality mFilterQuality; // designed filter quality.
- void* mCoefBuffer; // if a filter is created, this is not null
+ void setResampler(unsigned resampleType);
+
+ template<int CHANNELS, bool LOCKED, int STRIDE>
+ void resample(TO* out, size_t outFrameCount, AudioBufferProvider* provider);
+
+ // declare a pointer to member function for resample
+ typedef void (AudioResamplerDyn<TC, TI, TO>::*resample_ABP_t)(TO* out,
+ size_t outFrameCount, AudioBufferProvider* provider);
+
+ // data - the contiguous storage and layout of these is important.
+ InBuffer mInBuffer;
+ Constants mConstants; // current set of coefficient parameters
+ TO __attribute__ ((aligned (8))) mVolumeSimd[2]; // must be aligned or NEON may crash
+ resample_ABP_t mResampleFunc; // called function for resampling
+ int32_t mFilterSampleRate; // designed filter sample rate.
+ src_quality mFilterQuality; // designed filter quality.
+ void* mCoefBuffer; // if a filter is created, this is not null
};
-// ----------------------------------------------------------------------------
}; // namespace android
#endif /*ANDROID_AUDIO_RESAMPLER_DYN_H*/
diff --git a/services/audioflinger/AudioResamplerFirGen.h b/services/audioflinger/AudioResamplerFirGen.h
index fac3001..8833758 100644
--- a/services/audioflinger/AudioResamplerFirGen.h
+++ b/services/audioflinger/AudioResamplerFirGen.h
@@ -669,11 +669,12 @@ static inline void firKaiserGen(T* coef, int L, int halfNumCoef,
sg.advance();
}
- // (caution!) float version does not need rounding
if (is_same<T, int16_t>::value) { // int16_t needs noise shaping
*coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1), err));
- } else {
+ } else if (is_same<T, int32_t>::value) {
*coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1)));
+ } else { // assumed float or double
+ *coef++ = static_cast<T>(y);
}
}
}
diff --git a/services/audioflinger/AudioResamplerFirProcess.h b/services/audioflinger/AudioResamplerFirProcess.h
index 38e387c..76d2d66 100644
--- a/services/audioflinger/AudioResamplerFirProcess.h
+++ b/services/audioflinger/AudioResamplerFirProcess.h
@@ -21,47 +21,55 @@ namespace android {
// depends on AudioResamplerFirOps.h
-template<int CHANNELS, typename TC>
+/* variant for input type TI = int16_t input samples */
+template<typename TC>
static inline
-void mac(
- int32_t& l, int32_t& r,
- const TC coef,
- const int16_t* samples)
+void mac(int32_t& l, int32_t& r, TC coef, const int16_t* samples)
{
- if (CHANNELS == 2) {
- uint32_t rl = *reinterpret_cast<const uint32_t*>(samples);
- l = mulAddRL(1, rl, coef, l);
- r = mulAddRL(0, rl, coef, r);
- } else {
- r = l = mulAdd(samples[0], coef, l);
- }
+ uint32_t rl = *reinterpret_cast<const uint32_t*>(samples);
+ l = mulAddRL(1, rl, coef, l);
+ r = mulAddRL(0, rl, coef, r);
}
-template<int CHANNELS, typename TC>
+template<typename TC>
static inline
-void interpolate(
- int32_t& l, int32_t& r,
- const TC coef_0, const TC coef_1,
- const int16_t lerp, const int16_t* samples)
+void mac(int32_t& l, TC coef, const int16_t* samples)
{
- TC sinc;
+ l = mulAdd(samples[0], coef, l);
+}
- if (is_same<TC, int16_t>::value) {
- sinc = (lerp * ((coef_1-coef_0)<<1)>>16) + coef_0;
- } else {
- sinc = mulAdd(lerp, (coef_1-coef_0)<<1, coef_0);
- }
- if (CHANNELS == 2) {
- uint32_t rl = *reinterpret_cast<const uint32_t*>(samples);
- l = mulAddRL(1, rl, sinc, l);
- r = mulAddRL(0, rl, sinc, r);
- } else {
- r = l = mulAdd(samples[0], sinc, l);
- }
+/* variant for input type TI = float input samples */
+template<typename TC>
+static inline
+void mac(float& l, float& r, TC coef, const float* samples)
+{
+ l += *samples++ * coef;
+ r += *samples++ * coef;
+}
+
+template<typename TC>
+static inline
+void mac(float& l, TC coef, const float* samples)
+{
+ l += *samples++ * coef;
+}
+
+/* variant for output type TO = int32_t output samples */
+static inline
+int32_t volumeAdjust(int32_t value, int32_t volume)
+{
+ return 2 * mulRL(0, value, volume); // Note: only use top 16b
+}
+
+/* variant for output type TO = float output samples */
+static inline
+float volumeAdjust(float value, float volume)
+{
+ return value * volume;
}
/*
- * Calculates a single output sample (two stereo frames).
+ * Calculates a single output frame (two samples).
*
* This function computes both the positive half FIR dot product and
* the negative half FIR dot product, accumulates, and then applies the volume.
@@ -72,30 +80,43 @@ void interpolate(
* filter bank.
*/
-template <int CHANNELS, int STRIDE, typename TC>
+template <int CHANNELS, int STRIDE, typename TC, typename TI, typename TO>
static inline
-void ProcessL(int32_t* const out,
+void ProcessL(TO* const out,
int count,
const TC* coefsP,
const TC* coefsN,
- const int16_t* sP,
- const int16_t* sN,
- const int32_t* const volumeLR)
+ const TI* sP,
+ const TI* sN,
+ const TO* const volumeLR)
{
- int32_t l = 0;
- int32_t r = 0;
- do {
- mac<CHANNELS>(l, r, *coefsP++, sP);
- sP -= CHANNELS;
- mac<CHANNELS>(l, r, *coefsN++, sN);
- sN += CHANNELS;
- } while (--count > 0);
- out[0] += 2 * mulRL(0, l, volumeLR[0]); // Note: only use top 16b
- out[1] += 2 * mulRL(0, r, volumeLR[1]); // Note: only use top 16b
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS >= 1 && CHANNELS <= 2)
+ if (CHANNELS == 2) {
+ TO l = 0;
+ TO r = 0;
+ do {
+ mac(l, r, *coefsP++, sP);
+ sP -= CHANNELS;
+ mac(l, r, *coefsN++, sN);
+ sN += CHANNELS;
+ } while (--count > 0);
+ out[0] += volumeAdjust(l, volumeLR[0]);
+ out[1] += volumeAdjust(r, volumeLR[1]);
+ } else { /* CHANNELS == 1 */
+ TO l = 0;
+ do {
+ mac(l, *coefsP++, sP);
+ sP -= CHANNELS;
+ mac(l, *coefsN++, sN);
+ sN += CHANNELS;
+ } while (--count > 0);
+ out[0] += volumeAdjust(l, volumeLR[0]);
+ out[1] += volumeAdjust(l, volumeLR[1]);
+ }
}
/*
- * Calculates a single output sample (two stereo frames) interpolating phase.
+ * Calculates a single output frame (two samples) interpolating phase.
*
* This function computes both the positive half FIR dot product and
* the negative half FIR dot product, accumulates, and then applies the volume.
@@ -106,47 +127,91 @@ void ProcessL(int32_t* const out,
* filter bank.
*/
-template <int CHANNELS, int STRIDE, typename TC>
+template<typename TC, typename T>
+void adjustLerp(T& lerpP __unused)
+{
+}
+
+template<int32_t, typename T>
+void adjustLerp(T& lerpP)
+{
+ lerpP >>= 16; // lerpP is 32bit for NEON int32_t, but always 16 bit for non-NEON path
+}
+
+template<typename TC, typename TINTERP>
+static inline
+TC interpolate(TC coef_0, TC coef_1, TINTERP lerp)
+{
+ return lerp * (coef_1 - coef_0) + coef_0;
+}
+
+template<int16_t, uint32_t>
+static inline
+int16_t interpolate(int16_t coef_0, int16_t coef_1, uint32_t lerp)
+{
+ return (static_cast<int16_t>(lerp) * ((coef_1-coef_0)<<1)>>16) + coef_0;
+}
+
+template<int32_t, uint32_t>
+static inline
+int32_t interpolate(int32_t coef_0, int32_t coef_1, uint32_t lerp)
+{
+ return mulAdd(static_cast<int16_t>(lerp), (coef_1-coef_0)<<1, coef_0);
+}
+
+template <int CHANNELS, int STRIDE, typename TC, typename TI, typename TO, typename TINTERP>
static inline
-void Process(int32_t* const out,
+void Process(TO* const out,
int count,
const TC* coefsP,
const TC* coefsN,
- const TC* coefsP1,
- const TC* coefsN1,
- const int16_t* sP,
- const int16_t* sN,
- uint32_t lerpP,
- const int32_t* const volumeLR)
+ const TC* coefsP1 __unused,
+ const TC* coefsN1 __unused,
+ const TI* sP,
+ const TI* sN,
+ TINTERP lerpP,
+ const TO* const volumeLR)
{
- (void) coefsP1; // suppress unused parameter warning
- (void) coefsN1;
- if (sizeof(*coefsP)==4) {
- lerpP >>= 16; // ensure lerpP is 16b
- }
- int32_t l = 0;
- int32_t r = 0;
- for (size_t i = 0; i < count; ++i) {
- interpolate<CHANNELS>(l, r, coefsP[0], coefsP[count], lerpP, sP);
- coefsP++;
- sP -= CHANNELS;
- interpolate<CHANNELS>(l, r, coefsN[count], coefsN[0], lerpP, sN);
- coefsN++;
- sN += CHANNELS;
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CHANNELS >= 1 && CHANNELS <= 2)
+ adjustLerp<TC, TINTERP>(lerpP); // coefficient type adjustment for interpolation
+
+ if (CHANNELS == 2) {
+ TO l = 0;
+ TO r = 0;
+ for (size_t i = 0; i < count; ++i) {
+ mac(l, r, interpolate(coefsP[0], coefsP[count], lerpP), sP);
+ coefsP++;
+ sP -= CHANNELS;
+ mac(l, r, interpolate(coefsN[count], coefsN[0], lerpP), sN);
+ coefsN++;
+ sN += CHANNELS;
+ }
+ out[0] += volumeAdjust(l, volumeLR[0]);
+ out[1] += volumeAdjust(r, volumeLR[1]);
+ } else { /* CHANNELS == 1 */
+ TO l = 0;
+ for (size_t i = 0; i < count; ++i) {
+ mac(l, interpolate(coefsP[0], coefsP[count], lerpP), sP);
+ coefsP++;
+ sP -= CHANNELS;
+ mac(l, interpolate(coefsN[count], coefsN[0], lerpP), sN);
+ coefsN++;
+ sN += CHANNELS;
+ }
+ out[0] += volumeAdjust(l, volumeLR[0]);
+ out[1] += volumeAdjust(l, volumeLR[1]);
}
- out[0] += 2 * mulRL(0, l, volumeLR[0]); // Note: only use top 16b
- out[1] += 2 * mulRL(0, r, volumeLR[1]); // Note: only use top 16b
}
/*
- * Calculates a single output sample (two stereo frames) from input sample pointer.
+ * Calculates a single output frame (two samples) from input sample pointer.
*
* This sets up the params for the accelerated Process() and ProcessL()
* functions to do the appropriate dot products.
*
- * @param out should point to the output buffer with at least enough space for 2 output frames.
+ * @param out should point to the output buffer with space for at least one output frame.
*
- * @param phase is the fractional distance between input samples for interpolation:
+ * @param phase is the fractional distance between input frames for interpolation:
* phase >= 0 && phase < phaseWrapLimit. It can be thought of as a rational fraction
* of phase/phaseWrapLimit.
*
@@ -195,14 +260,17 @@ void Process(int32_t* const out,
* lerpP = phase << sizeof(phase)*8 - coefShift
* >> (sizeof(phase)-sizeof(*coefs))*8 + 1;
*
+ * For floating point, lerpP is the fractional phase scaled to [0.0, 1.0):
+ *
+ * lerpP = (phase << 32 - coefShift) / (1 << 32); // floating point equivalent
*/
-template<int CHANNELS, bool LOCKED, int STRIDE, typename TC>
+template<int CHANNELS, bool LOCKED, int STRIDE, typename TC, typename TI, typename TO>
static inline
-void fir(int32_t* const out,
+void fir(TO* const out,
const uint32_t phase, const uint32_t phaseWrapLimit,
const int coefShift, const int halfNumCoefs, const TC* const coefs,
- const int16_t* const samples, const int32_t* const volumeLR)
+ const TI* const samples, const TO* const volumeLR)
{
// NOTE: be very careful when modifying the code here. register
// pressure is very high and a small change might cause the compiler
@@ -216,8 +284,8 @@ void fir(int32_t* const out,
uint32_t indexN = (phaseWrapLimit - phase) >> coefShift;
const TC* coefsP = coefs + indexP*halfNumCoefs;
const TC* coefsN = coefs + indexN*halfNumCoefs;
- const int16_t* sP = samples;
- const int16_t* sN = samples + CHANNELS;
+ const TI* sP = samples;
+ const TI* sN = samples + CHANNELS;
// dot product filter.
ProcessL<CHANNELS, STRIDE>(out,
@@ -231,8 +299,8 @@ void fir(int32_t* const out,
const TC* coefsN = coefs + indexN*halfNumCoefs;
const TC* coefsP1 = coefsP + halfNumCoefs;
const TC* coefsN1 = coefsN + halfNumCoefs;
- const int16_t* sP = samples;
- const int16_t* sN = samples + CHANNELS;
+ const TI* sP = samples;
+ const TI* sN = samples + CHANNELS;
// Interpolation fraction lerpP derived by shifting all the way up and down
// to clear the appropriate bits and align to the appropriate level
@@ -242,12 +310,21 @@ void fir(int32_t* const out,
//
// interpolated[P] = index[P]*lerpP + index[P+1]*(1-lerpP)
// interpolated[N] = index[N+1]*lerpP + index[N]*(1-lerpP)
- uint32_t lerpP = phase << (sizeof(phase)*8 - coefShift)
- >> ((sizeof(phase)-sizeof(*coefs))*8 + 1);
// on-the-fly interpolated dot product filter
- Process<CHANNELS, STRIDE>(out,
- halfNumCoefs, coefsP, coefsN, coefsP1, coefsN1, sP, sN, lerpP, volumeLR);
+ if (is_same<TC, float>::value || is_same<TC, double>::value) {
+ static const TC scale = 1. / (65536. * 65536.); // scale phase bits to [0.0, 1.0)
+ TC lerpP = TC(phase << (sizeof(phase)*8 - coefShift)) * scale;
+
+ Process<CHANNELS, STRIDE>(out,
+ halfNumCoefs, coefsP, coefsN, coefsP1, coefsN1, sP, sN, lerpP, volumeLR);
+ } else {
+ uint32_t lerpP = phase << (sizeof(phase)*8 - coefShift)
+ >> ((sizeof(phase)-sizeof(*coefs))*8 + 1);
+
+ Process<CHANNELS, STRIDE>(out,
+ halfNumCoefs, coefsP, coefsN, coefsP1, coefsN1, sP, sN, lerpP, volumeLR);
+ }
}
}
diff --git a/services/audioflinger/test-resample.cpp b/services/audioflinger/test-resample.cpp
index 7b7cdac..d1de95d 100644
--- a/services/audioflinger/test-resample.cpp
+++ b/services/audioflinger/test-resample.cpp
@@ -24,20 +24,25 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
+#include <inttypes.h>
#include <time.h>
#include <math.h>
+#include <audio_utils/primitives.h>
#include <audio_utils/sndfile.h>
#include <utils/Vector.h>
using namespace android;
-bool gVerbose = false;
+static bool gVerbose = false;
static int usage(const char* name) {
- fprintf(stderr,"Usage: %s [-p] [-h] [-v] [-s] [-q {dq|lq|mq|hq|vhq|dlq|dmq|dhq}]"
- " [-i input-sample-rate] [-o output-sample-rate] [-O csv] [-P csv] [<input-file>]"
+ fprintf(stderr,"Usage: %s [-p] [-f] [-F] [-h] [-v] [-s] [-q {dq|lq|mq|hq|vhq|dlq|dmq|dhq}]"
+ " [-i input-sample-rate] [-o output-sample-rate]"
+ " [-O csv] [-P csv] [<input-file>]"
" <output-file>\n", name);
fprintf(stderr," -p enable profiling\n");
+ fprintf(stderr," -f enable filter profiling\n");
+ fprintf(stderr," -F enable floating point -q {dlq|dmq|dhq} only");
fprintf(stderr," -h create wav file\n");
fprintf(stderr," -v verbose : log buffer provider calls\n");
fprintf(stderr," -s stereo (ignored if input file is specified)\n");
@@ -102,6 +107,7 @@ int main(int argc, char* argv[]) {
bool profileResample = false;
bool profileFilter = false;
bool writeHeader = false;
+ bool useFloat = false;
int channels = 1;
int input_freq = 0;
int output_freq = 0;
@@ -110,7 +116,7 @@ int main(int argc, char* argv[]) {
Vector<int> Pvalues;
int ch;
- while ((ch = getopt(argc, argv, "pfhvsq:i:o:O:P:")) != -1) {
+ while ((ch = getopt(argc, argv, "pfFhvsq:i:o:O:P:")) != -1) {
switch (ch) {
case 'p':
profileResample = true;
@@ -118,6 +124,9 @@ int main(int argc, char* argv[]) {
case 'f':
profileFilter = true;
break;
+ case 'F':
+ useFloat = true;
+ break;
case 'h':
writeHeader = true;
break;
@@ -173,6 +182,12 @@ int main(int argc, char* argv[]) {
return -1;
}
}
+
+ if (useFloat && quality < AudioResampler::DYN_LOW_QUALITY) {
+ fprintf(stderr, "float processing is only possible for dynamic resamplers\n");
+ return -1;
+ }
+
argc -= optind;
argv += optind;
@@ -224,22 +239,37 @@ int main(int argc, char* argv[]) {
}
}
}
+ size_t frame_size = channels * sizeof(int16_t);
+ size_t input_frames = input_size / frame_size;
+
+ // For float processing, convert input int16_t to float array
+ if (useFloat) {
+ void *new_vaddr;
+
+ frame_size = channels * sizeof(float);
+ input_size = input_frames * frame_size;
+ new_vaddr = malloc(input_size);
+ memcpy_to_float_from_i16(reinterpret_cast<float*>(new_vaddr),
+ reinterpret_cast<int16_t*>(input_vaddr), input_frames * channels);
+ free(input_vaddr);
+ input_vaddr = new_vaddr;
+ }
// ----------------------------------------------------------
class Provider: public AudioBufferProvider {
- int16_t* const mAddr; // base address
+ const void* mAddr; // base address
const size_t mNumFrames; // total frames
- const int mChannels;
+ const size_t mFrameSize; // size of each frame in bytes
size_t mNextFrame; // index of next frame to provide
size_t mUnrel; // number of frames not yet released
const Vector<int> mPvalues; // number of frames provided per call
size_t mNextPidx; // index of next entry in mPvalues to use
public:
- Provider(const void* addr, size_t size, int channels, const Vector<int>& Pvalues)
- : mAddr((int16_t*) addr),
- mNumFrames(size / (channels*sizeof(int16_t))),
- mChannels(channels),
+ Provider(const void* addr, size_t frames, size_t frameSize, const Vector<int>& Pvalues)
+ : mAddr(addr),
+ mNumFrames(frames),
+ mFrameSize(frameSize),
mNextFrame(0), mUnrel(0), mPvalues(Pvalues), mNextPidx(0) {
}
virtual status_t getNextBuffer(Buffer* buffer,
@@ -251,7 +281,7 @@ int main(int argc, char* argv[]) {
}
if (!mPvalues.isEmpty()) {
size_t provided = mPvalues[mNextPidx++];
- printf("mPvalue[%d]=%u not %u\n", mNextPidx-1, provided, buffer->frameCount);
+ printf("mPvalue[%zu]=%zu not %zu\n", mNextPidx-1, provided, buffer->frameCount);
if (provided < buffer->frameCount) {
buffer->frameCount = provided;
}
@@ -260,45 +290,46 @@ int main(int argc, char* argv[]) {
}
}
if (gVerbose) {
- printf("getNextBuffer() requested %u frames out of %u frames available,"
- " and returned %u frames\n",
- requestedFrames, mNumFrames - mNextFrame, buffer->frameCount);
+ printf("getNextBuffer() requested %zu frames out of %zu frames available,"
+ " and returned %zu frames\n",
+ requestedFrames, (size_t) (mNumFrames - mNextFrame), buffer->frameCount);
}
mUnrel = buffer->frameCount;
if (buffer->frameCount > 0) {
- buffer->i16 = &mAddr[mChannels * mNextFrame];
+ buffer->raw = (char *)mAddr + mFrameSize * mNextFrame;
return NO_ERROR;
} else {
- buffer->i16 = NULL;
+ buffer->raw = NULL;
return NOT_ENOUGH_DATA;
}
}
virtual void releaseBuffer(Buffer* buffer) {
if (buffer->frameCount > mUnrel) {
- fprintf(stderr, "ERROR releaseBuffer() released %u frames but only %u available "
+ fprintf(stderr, "ERROR releaseBuffer() released %zu frames but only %zu available "
"to release\n", buffer->frameCount, mUnrel);
mNextFrame += mUnrel;
mUnrel = 0;
} else {
if (gVerbose) {
- printf("releaseBuffer() released %u frames out of %u frames available "
+ printf("releaseBuffer() released %zu frames out of %zu frames available "
"to release\n", buffer->frameCount, mUnrel);
}
mNextFrame += buffer->frameCount;
mUnrel -= buffer->frameCount;
}
buffer->frameCount = 0;
- buffer->i16 = NULL;
+ buffer->raw = NULL;
}
void reset() {
mNextFrame = 0;
}
- } provider(input_vaddr, input_size, channels, Pvalues);
+ } provider(input_vaddr, input_frames, frame_size, Pvalues);
- size_t input_frames = input_size / (channels * sizeof(int16_t));
if (gVerbose) {
- printf("%u input frames\n", input_frames);
+ printf("%zu input frames\n", input_frames);
}
+
+ int bit_depth = useFloat ? 32 : 16;
size_t output_size = 2 * 4 * ((int64_t) input_frames * output_freq) / input_freq;
output_size &= ~7; // always stereo, 32-bits
@@ -309,7 +340,7 @@ int main(int argc, char* argv[]) {
//
// On fast devices, filters should be generated between 0.1ms - 1ms.
// (single threaded).
- AudioResampler* resampler = AudioResampler::create(16, channels,
+ AudioResampler* resampler = AudioResampler::create(bit_depth, channels,
8000, quality);
int looplimit = 100;
timespec start, end;
@@ -347,7 +378,7 @@ int main(int argc, char* argv[]) {
}
void* output_vaddr = malloc(output_size);
- AudioResampler* resampler = AudioResampler::create(16, channels,
+ AudioResampler* resampler = AudioResampler::create(bit_depth, channels,
output_freq, quality);
size_t out_frames = output_size/8;
@@ -386,7 +417,7 @@ int main(int argc, char* argv[]) {
const int trials = 4;
const int looplimit = 4;
timespec start, end;
- int64_t time;
+ int64_t time = 0;
for (int n = 0; n < trials; ++n) {
clock_gettime(CLOCK_MONOTONIC, &start);
@@ -403,14 +434,14 @@ int main(int argc, char* argv[]) {
}
}
// Mfrms/s is "Millions of output frames per second".
- printf("quality: %d channels: %d msec: %lld Mfrms/s: %.2lf\n",
+ printf("quality: %d channels: %d msec: %" PRId64 " Mfrms/s: %.2lf\n",
quality, channels, time/1000000, out_frames * looplimit / (time / 1e9) / 1e6);
resampler->reset();
}
memset(output_vaddr, 0, output_size);
if (gVerbose) {
- printf("resample() %u output frames\n", out_frames);
+ printf("resample() %zu output frames\n", out_frames);
}
if (Ovalues.isEmpty()) {
Ovalues.push(out_frames);
@@ -436,6 +467,13 @@ int main(int argc, char* argv[]) {
delete resampler;
resampler = NULL;
+ // For float processing, convert output format from float to Q4.27,
+ // which is then converted to int16_t for final storage.
+ if (useFloat) {
+ memcpy_to_q4_27_from_float(reinterpret_cast<int32_t*>(output_vaddr),
+ reinterpret_cast<float*>(output_vaddr), out_frames * 2); // stereo samples
+ }
+
// mono takes left channel only
// stereo right channel is half amplitude of stereo left channel (due to input creation)
int32_t* out = (int32_t*) output_vaddr;