diff options
author | Phil Burk <philburk@google.com> | 2019-08-23 17:33:28 -0700 |
---|---|---|
committer | Phil Burk <philburk@google.com> | 2019-08-23 17:33:28 -0700 |
commit | b69847cf6416d711f3f1f4ec2871364125bff925 (patch) | |
tree | e760aa198cc375e82d811cb6cc21ed51d255dd0a | |
parent | 99c00483810f46db61d9a729f90f551d0f7c03f8 (diff) | |
download | oboe-b69847cf6416d711f3f1f4ec2871364125bff925.tar.gz |
resampler: add Fastest quality
It will use a bi-linear interpolation.
Also cleanup FullDuplexEcho
8 files changed, 38 insertions, 31 deletions
diff --git a/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp b/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp index 30511a4b..0da2d002 100644 --- a/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp +++ b/apps/OboeTester/app/src/main/cpp/FullDuplexEcho.cpp @@ -29,32 +29,21 @@ oboe::DataCallbackResult FullDuplexEcho::onBothStreamsReady( void *outputData, int numOutputFrames) { // FIXME only handles matching stream formats. - // TODO use array of delays // TODO Add delay node // TODO use flowgraph to handle format conversion int32_t framesToEcho = std::min(numInputFrames, numOutputFrames); float *inputFloat = (float *)inputData; float *outputFloat = (float *)outputData; + // zero out entire output array + memset(outputFloat, 0, numOutputFrames * getOutputStream()->getBytesPerFrame()); + int32_t inputStride = getInputStream()->getChannelCount(); int32_t outputStride = getOutputStream()->getChannelCount(); float delayFrames = mDelayTimeSeconds * getOutputStream()->getSampleRate(); - if (outputStride == 1) { - while (framesToEcho-- > 0) { - *outputFloat++ = mDelayLine->process(delayFrames, *inputFloat); // mono delay - inputFloat += inputStride; - } - } else if (outputStride == 2) { - while (framesToEcho-- > 0) { - *outputFloat++ = mDelayLine->process(delayFrames, *inputFloat); // mono delay - *outputFloat++ = 0.0f; - inputFloat += inputStride; - } - } // else TODO - - // zero out remainder of output array - int32_t framesLeft = numOutputFrames - numInputFrames; - if (framesLeft > 0) { - memset(outputFloat, 0, framesLeft * getOutputStream()->getBytesPerFrame()); + while (framesToEcho-- > 0) { + *outputFloat = mDelayLine->process(delayFrames, *inputFloat); // mono delay + inputFloat += inputStride; + outputFloat += outputStride; } return oboe::DataCallbackResult::Continue; }; diff --git a/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.h b/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.h index 694f9a74..2ea97e15 100644 --- a/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.h +++ b/apps/OboeTester/app/src/main/cpp/flowunits/LinearShape.h @@ -29,7 +29,7 @@ public: int32_t onProcess(int numFrames) override; - float getMinimum() const { // TODO create sweep base class + float getMinimum() const { return mMinimum; } diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/StreamConfiguration.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/StreamConfiguration.java index 733e9560..915dcdbd 100644 --- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/StreamConfiguration.java +++ b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/StreamConfiguration.java @@ -48,10 +48,11 @@ public class StreamConfiguration { public static final int PERFORMANCE_MODE_LOW_LATENCY = 12; // must match AAUDIO public static final int RATE_CONVERSION_QUALITY_NONE = 0; // must match Oboe - public static final int RATE_CONVERSION_QUALITY_LOW = 1; // must match Oboe - public static final int RATE_CONVERSION_QUALITY_MEDIUM = 2; // must match Oboe - public static final int RATE_CONVERSION_QUALITY_HIGH = 3; // must match Oboe - public static final int RATE_CONVERSION_QUALITY_BEST = 4; // must match Oboe + public static final int RATE_CONVERSION_QUALITY_FASTEST = 1; // must match Oboe + public static final int RATE_CONVERSION_QUALITY_LOW = 2; // must match Oboe + public static final int RATE_CONVERSION_QUALITY_MEDIUM = 3; // must match Oboe + public static final int RATE_CONVERSION_QUALITY_HIGH = 4; // must match Oboe + public static final int RATE_CONVERSION_QUALITY_BEST = 5; // must match Oboe private int mNativeApi; private int mBufferCapacityInFrames; @@ -67,7 +68,7 @@ public class StreamConfiguration { private boolean mChannelConversionAllowed = true; private int mRateConversionQuality = RATE_CONVERSION_QUALITY_HIGH; - private int mFramesPerBurst = 29; // TODO review + private int mFramesPerBurst = 0; private boolean mMMap = false; public StreamConfiguration() { diff --git a/apps/OboeTester/app/src/main/res/values/strings.xml b/apps/OboeTester/app/src/main/res/values/strings.xml index 53c3bea0..72d3cba1 100644 --- a/apps/OboeTester/app/src/main/res/values/strings.xml +++ b/apps/OboeTester/app/src/main/res/values/strings.xml @@ -120,6 +120,7 @@ <string name="src_prompt">SRC:</string> <string-array name="conversion_qualities"> <item>None</item> + <item>Fastest</item> <item>Low</item> <item>Medium</item> <item>High</item> diff --git a/include/oboe/AudioStreamBuilder.h b/include/oboe/AudioStreamBuilder.h index 092d1773..4e1dad74 100644 --- a/include/oboe/AudioStreamBuilder.h +++ b/include/oboe/AudioStreamBuilder.h @@ -341,12 +341,13 @@ public: } /** - * If set to None then Oboe will not do sample rate conversion. But the underlying APIs - * might do sample rate conversion. Unfortunately sample rate conversion in Android typically - * prevents one from getting a low latency stream. So we can do the conversion in Android - * and still get a low latency stream. + * Specify the quality of the sample rate converter in Oboe. * - * Default is SampleRateConversionType::Sinc. TODO currently Linear + * If set to None then Oboe will not do sample rate conversion. But then the underlying APIs + * might do sample rate conversion, which can prevent one from getting a low latency stream. + * If we do the conversion in Oboe then we can still get a low latency stream. + * + * Default is SampleRateConversionQuality::None */ AudioStreamBuilder *setSampleRateConversionQuality(SampleRateConversionQuality quality) { mSampleRateConversionQuality = quality; diff --git a/include/oboe/Definitions.h b/include/oboe/Definitions.h index 29fd55d1..b1ea7f13 100644 --- a/include/oboe/Definitions.h +++ b/include/oboe/Definitions.h @@ -228,18 +228,26 @@ namespace oboe { }; /** - * The algorithm used to perform sample rate conversion. + * Specifies the quality of the sample rate conversion performed by Oboe. * Higher quality will require more CPU load. + * Higher quality conversion will probably be implemented using a sinc based resampler. */ enum class SampleRateConversionQuality : int32_t { /** * No conversion by Oboe. Underlying APIs may still do conversion. */ None, - + /** + * Fastest conversion but may not sound great. + * This may be implemented using bilinear interpolation. + */ + Fastest, Low, Medium, High, + /** + * Highest quality conversion, which may be expensive in terms of CPU. + */ Best, }; diff --git a/src/flowgraph/resampler/MultiChannelResampler.cpp b/src/flowgraph/resampler/MultiChannelResampler.cpp index c35cf04f..c54ca758 100644 --- a/src/flowgraph/resampler/MultiChannelResampler.cpp +++ b/src/flowgraph/resampler/MultiChannelResampler.cpp @@ -54,6 +54,9 @@ MultiChannelResampler *MultiChannelResampler::make(int32_t channelCount, // TODO benchmark and review these numTaps switch (quality) { + case Quality::Fastest: + builder.setNumTaps(2); + break; case Quality::Low: builder.setNumTaps(4); break; @@ -77,6 +80,9 @@ MultiChannelResampler *MultiChannelResampler::make(int32_t channelCount, } MultiChannelResampler *MultiChannelResampler::Builder::build() { + if (getNumTaps() == 2) { + return new LinearResampler(*this); + } IntegerRatio ratio(getInputRate(), getOutputRate()); ratio.reduce(); bool usePolyphase = (getNumTaps() * ratio.getDenominator()) <= kMaxCoefficients; diff --git a/src/flowgraph/resampler/MultiChannelResampler.h b/src/flowgraph/resampler/MultiChannelResampler.h index 31ff2c0b..3e6bb438 100644 --- a/src/flowgraph/resampler/MultiChannelResampler.h +++ b/src/flowgraph/resampler/MultiChannelResampler.h @@ -39,6 +39,7 @@ class MultiChannelResampler { public: enum class Quality : int32_t { + Fastest, Low, Medium, High, |