resampler: use integer phase accumulation for all resamplers
Remove ContinuousResampler
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 65d843d..c555692 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,7 +32,6 @@
src/flowgraph/SourceFloat.cpp
src/flowgraph/SourceI16.cpp
src/flowgraph/SourceI24.cpp
- src/flowgraph/resampler/ContinuousResampler.cpp
src/flowgraph/resampler/IntegerRatio.cpp
src/flowgraph/resampler/LinearResampler.cpp
src/flowgraph/resampler/MultiChannelResampler.cpp
diff --git a/apps/OboeTester/app/CMakeLists.txt b/apps/OboeTester/app/CMakeLists.txt
index 38616c4..a3accd9 100644
--- a/apps/OboeTester/app/CMakeLists.txt
+++ b/apps/OboeTester/app/CMakeLists.txt
@@ -26,7 +26,6 @@
${OBOE_DIR}/src
)
-
### END OBOE INCLUDE SECTION ###
# link to oboe
diff --git a/src/flowgraph/resampler/ContinuousResampler.cpp b/src/flowgraph/resampler/ContinuousResampler.cpp
deleted file mode 100644
index a23b291..0000000
--- a/src/flowgraph/resampler/ContinuousResampler.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ContinuousResampler.h"
-
-using namespace resampler;
-
-ContinuousResampler::ContinuousResampler(const MultiChannelResampler::Builder &builder)
- : MultiChannelResampler(builder) {
- mPhaseIncrement = (double) builder.getInputRate() / (double) builder.getOutputRate();
-}
diff --git a/src/flowgraph/resampler/ContinuousResampler.h b/src/flowgraph/resampler/ContinuousResampler.h
deleted file mode 100644
index de7a973..0000000
--- a/src/flowgraph/resampler/ContinuousResampler.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef OBOE_CONTINUOUS_RESAMPLER_H
-#define OBOE_CONTINUOUS_RESAMPLER_H
-
-#include <sys/types.h>
-#include <unistd.h>
-#include "MultiChannelResampler.h"
-
-namespace resampler {
-
-/*
- * Resampler that uses a double precision phase internally.
- */
-class ContinuousResampler : public MultiChannelResampler {
-public:
- explicit ContinuousResampler(const MultiChannelResampler::Builder &builder);
-
- virtual ~ContinuousResampler() = default;
-
- bool isWriteNeeded() const override {
- return mPhase >= 1.0;
- }
-
- virtual void advanceWrite() override {
- mPhase -= 1.0;
- }
-
- virtual void advanceRead() override {
- mPhase += mPhaseIncrement;
- }
-
- double getPhase() {
- return (float) mPhase;
- }
-
-private:
- double mPhase = 1.0;
- double mPhaseIncrement = 1.0;
-};
-
-}
-#endif //OBOE_CONTINUOUS_RESAMPLER_H
diff --git a/src/flowgraph/resampler/LinearResampler.cpp b/src/flowgraph/resampler/LinearResampler.cpp
index af2ccb0..33e23e6 100644
--- a/src/flowgraph/resampler/LinearResampler.cpp
+++ b/src/flowgraph/resampler/LinearResampler.cpp
@@ -19,9 +19,9 @@
using namespace resampler;
LinearResampler::LinearResampler(const MultiChannelResampler::Builder &builder)
- : ContinuousResampler(builder) {
- mPreviousFrame = std::make_unique<float[]>(getChannelCount());
- mCurrentFrame = std::make_unique<float[]>(getChannelCount());
+ : MultiChannelResampler(builder) {
+ mPreviousFrame = std::make_unique<float[]>(getChannelCount());
+ mCurrentFrame = std::make_unique<float[]>(getChannelCount());
}
void LinearResampler::writeFrame(const float *frame) {
@@ -32,7 +32,7 @@
void LinearResampler::readFrame(float *frame) {
float *previous = mPreviousFrame.get();
float *current = mCurrentFrame.get();
- float phase = (float) getPhase();
+ float phase = (float) getIntegerPhase() / mDenominator;
for (int channel = 0; channel < getChannelCount(); channel++) {
float f0 = *previous++;
float f1 = *current++;
diff --git a/src/flowgraph/resampler/LinearResampler.h b/src/flowgraph/resampler/LinearResampler.h
index b4d0394..6dc8d29 100644
--- a/src/flowgraph/resampler/LinearResampler.h
+++ b/src/flowgraph/resampler/LinearResampler.h
@@ -20,11 +20,11 @@
#include <memory>
#include <sys/types.h>
#include <unistd.h>
-#include "ContinuousResampler.h"
+#include "MultiChannelResampler.h"
namespace resampler {
-class LinearResampler : public ContinuousResampler {
+class LinearResampler : public MultiChannelResampler {
public:
LinearResampler(const MultiChannelResampler::Builder &builder);
diff --git a/src/flowgraph/resampler/MultiChannelResampler.cpp b/src/flowgraph/resampler/MultiChannelResampler.cpp
index 42c756b..e461975 100644
--- a/src/flowgraph/resampler/MultiChannelResampler.cpp
+++ b/src/flowgraph/resampler/MultiChannelResampler.cpp
@@ -32,8 +32,17 @@
, mX(builder.getChannelCount() * builder.getNumTaps() * 2)
, mSingleFrame(builder.getChannelCount())
, mChannelCount(builder.getChannelCount())
- {}
+ {
+ // Reduce sample rates to the smallest ratio.
+ // For example 44100/48000 would become 147/160.
+ IntegerRatio ratio(builder.getInputRate(), builder.getOutputRate());
+ ratio.reduce();
+ mNumerator = ratio.getNumerator();
+ mDenominator = ratio.getDenominator();
+ mIntegerPhase = mDenominator;
+}
+// static factory method
MultiChannelResampler *MultiChannelResampler::make(int32_t channelCount,
int32_t inputRate,
int32_t outputRate,
@@ -115,9 +124,9 @@
}
// Unoptimized calculation used to construct lookup tables.
-float MultiChannelResampler::calculateWindowedSinc(float radians, int spread) {
- return sinc(radians) * hammingWindow(radians, spread); // TODO try Kaiser window
-}
+//float MultiChannelResampler::calculateWindowedSinc(float radians, int spread) {
+// return sinc(radians) * hammingWindow(radians, spread); // TODO try Kaiser window
+//}
// Generate coefficients in the order they will be used by readFrame().
diff --git a/src/flowgraph/resampler/MultiChannelResampler.h b/src/flowgraph/resampler/MultiChannelResampler.h
index a18ed6a..d4e3aa4 100644
--- a/src/flowgraph/resampler/MultiChannelResampler.h
+++ b/src/flowgraph/resampler/MultiChannelResampler.h
@@ -137,10 +137,10 @@
/**
* Factory method for making a resampler that is optimal for the given inputs.
*
- * @param channelCount
- * @param inputRate
- * @param outputRate
- * @param quality
+ * @param channelCount number of channels, 2 for stereo
+ * @param inputRate sample rate of the input stream
+ * @param outputRate sample rate of the output stream
+ * @param quality higher quality sounds better but uses more CPU
* @return an optimal resampler
*/
static MultiChannelResampler *make(int32_t channelCount,
@@ -148,7 +148,9 @@
int32_t outputRate,
Quality quality);
- virtual bool isWriteNeeded() const = 0;
+ bool isWriteNeeded() const {
+ return mIntegerPhase >= mDenominator;
+ }
/**
* Write a frame containing N samples.
@@ -190,7 +192,7 @@
* @param phase between 0.0 and 2*spread // TODO use centered phase, maybe
* @return windowedSinc
*/
- static float calculateWindowedSinc(float phase, int spread); // TODO remove
+ // static float calculateWindowedSinc(float phase, int spread); // TODO remove
/**
* Write a frame containing N samples.
@@ -203,26 +205,23 @@
* Read a frame containing N samples using interpolation.
* Call advanceRead() after calling this.
* @param frame pointer to the first sample in a frame
- * @param phase phase between 0.0 and 1.0 for interpolation
*/
virtual void readFrame(float *frame) = 0;
- virtual void advanceWrite() = 0;
- virtual void advanceRead() = 0;
+ void advanceWrite() {
+ mIntegerPhase -= mDenominator;
+ }
- const int mNumTaps;
- int mCursor = 0;
- std::vector<float> mX;
- std::vector<float> mSingleFrame;
-
- std::vector<float> mCoefficients;
- static constexpr int kMaxCoefficients = 8 * 1024;
-
+ void advanceRead() {
+ mIntegerPhase += mNumerator;
+ }
/**
* Generate the filter coefficients in optimal order.
- * @param inputRate
- * @param outputRate
+ * @param inputRate sample rate of the input stream
+ * @param outputRate sample rate of the output stream
+ * @param numRows number of rows in the array that contain a set of tap coefficients
+ * @param phaseIncrement how much to increment the phase between rows
* @param normalizedCutoff filter cutoff frequency normalized to Nyquist rate of output
*/
void generateCoefficients(int32_t inputRate,
@@ -231,13 +230,29 @@
double phaseIncrement,
float normalizedCutoff);
+
+ int32_t getIntegerPhase() {
+ return mIntegerPhase;
+ }
+
+ static constexpr int kMaxCoefficients = 8 * 1024;
+ std::vector<float> mCoefficients;
+
+ const int mNumTaps;
+ int mCursor = 0;
+ std::vector<float> mX;
+ std::vector<float> mSingleFrame;
+ int32_t mIntegerPhase = 0;
+ int32_t mNumerator = 0;
+ int32_t mDenominator = 0;
+
+
private:
// max coefficients for polyphase filter
static constexpr float kDefaultNormalizedCutoff = 0.90f;
const int mChannelCount;
-
};
}
diff --git a/src/flowgraph/resampler/PolyphaseResampler.cpp b/src/flowgraph/resampler/PolyphaseResampler.cpp
index 18ebe4c..4862ad8 100644
--- a/src/flowgraph/resampler/PolyphaseResampler.cpp
+++ b/src/flowgraph/resampler/PolyphaseResampler.cpp
@@ -28,14 +28,6 @@
int32_t inputRate = builder.getInputRate();
int32_t outputRate = builder.getOutputRate();
- // Reduce sample rates to the smallest ratio.
- // For example 44100/48000 would become 147/160.
- IntegerRatio ratio(inputRate, outputRate);
- ratio.reduce();
- mNumerator = ratio.getNumerator();
- mDenominator = ratio.getDenominator();
- mIntegerPhase = mDenominator;
-
int32_t numRows = mDenominator;
double phaseIncrement = (double) inputRate / (double) outputRate;
generateCoefficients(inputRate, outputRate,
diff --git a/src/flowgraph/resampler/PolyphaseResampler.h b/src/flowgraph/resampler/PolyphaseResampler.h
index fa267a1..13ab5e1 100644
--- a/src/flowgraph/resampler/PolyphaseResampler.h
+++ b/src/flowgraph/resampler/PolyphaseResampler.h
@@ -29,10 +29,7 @@
public:
/**
*
- * @param channelCount
- * @param numTaps
- * @param inputRate inputRate/outputRate should be a reduced fraction
- * @param outputRate
+ * @param builder containing lots of parameters
*/
explicit PolyphaseResampler(const MultiChannelResampler::Builder &builder);
@@ -40,24 +37,9 @@
void readFrame(float *frame) override;
- bool isWriteNeeded() const override {
- return mIntegerPhase >= mDenominator;
- }
-
- virtual void advanceWrite() override {
- mIntegerPhase -= mDenominator;
- }
-
- virtual void advanceRead() override {
- mIntegerPhase += mNumerator;
- }
-
protected:
int32_t mCoefficientCursor = 0;
- int32_t mIntegerPhase = 0;
- int32_t mNumerator = 0;
- int32_t mDenominator = 0;
};
diff --git a/src/flowgraph/resampler/SincResampler.cpp b/src/flowgraph/resampler/SincResampler.cpp
index 9acd192..d1938b9 100644
--- a/src/flowgraph/resampler/SincResampler.cpp
+++ b/src/flowgraph/resampler/SincResampler.cpp
@@ -20,11 +20,12 @@
using namespace resampler;
SincResampler::SincResampler(const MultiChannelResampler::Builder &builder)
- : ContinuousResampler(builder)
+ : MultiChannelResampler(builder)
, mSingleFrame2(builder.getChannelCount()) {
assert((getNumTaps() % 4) == 0); // Required for loop unrolling.
mNumRows = kMaxCoefficients / getNumTaps(); // no guard row needed
// printf("SincResampler: numRows = %d\n", mNumRows);
+ mPhaseScaler = (double) mNumRows / mDenominator;
double phaseIncrement = 1.0 / mNumRows;
generateCoefficients(builder.getInputRate(),
builder.getOutputRate(),
@@ -40,7 +41,7 @@
std::fill(mSingleFrame2.begin(), mSingleFrame2.end(), 0.0);
// Determine indices into coefficients table.
- double tablePhase = getPhase() * mNumRows;
+ double tablePhase = getIntegerPhase() * mPhaseScaler;
int index1 = static_cast<int>(floor(tablePhase));
if (index1 >= mNumRows) { // no guard row needed because we wrap the indices
tablePhase -= mNumRows;
diff --git a/src/flowgraph/resampler/SincResampler.h b/src/flowgraph/resampler/SincResampler.h
index cbfcc0b..edeb840 100644
--- a/src/flowgraph/resampler/SincResampler.h
+++ b/src/flowgraph/resampler/SincResampler.h
@@ -20,11 +20,11 @@
#include <memory>
#include <sys/types.h>
#include <unistd.h>
-#include "ContinuousResampler.h"
+#include "MultiChannelResampler.h"
namespace resampler {
-class SincResampler : public ContinuousResampler {
+class SincResampler : public MultiChannelResampler {
public:
explicit SincResampler(const MultiChannelResampler::Builder &builder);
@@ -36,7 +36,7 @@
std::vector<float> mSingleFrame2; // for interpolation
int32_t mNumRows = 0;
-
+ double mPhaseScaler = 1.0;
};
}
diff --git a/src/flowgraph/resampler/SincResamplerStereo.cpp b/src/flowgraph/resampler/SincResamplerStereo.cpp
index 5af7ff7..bde658a 100644
--- a/src/flowgraph/resampler/SincResamplerStereo.cpp
+++ b/src/flowgraph/resampler/SincResamplerStereo.cpp
@@ -51,7 +51,7 @@
std::fill(mSingleFrame2.begin(), mSingleFrame2.end(), 0.0);
// Determine indices into coefficients table.
- double tablePhase = getPhase() * mNumRows;
+ double tablePhase = getIntegerPhase() * mPhaseScaler;
int index1 = static_cast<int>(floor(tablePhase));
float *coefficients1 = &mCoefficients[index1 * getNumTaps()];
int index2 = (index1 + 1);
diff --git a/src/flowgraph/resampler/SincResamplerStereo.h b/src/flowgraph/resampler/SincResamplerStereo.h
index 6014b94..7d66c26 100644
--- a/src/flowgraph/resampler/SincResamplerStereo.h
+++ b/src/flowgraph/resampler/SincResamplerStereo.h
@@ -32,6 +32,7 @@
void writeFrame(const float *frame) override;
void readFrame(float *frame) override;
+
};
}