Loading media/libaaudio/src/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -212,6 +212,7 @@ cc_library { "flowgraph/ChannelCountConverter.cpp", "flowgraph/ClipToRange.cpp", "flowgraph/FlowGraphNode.cpp", "flowgraph/Limiter.cpp", "flowgraph/ManyToMultiConverter.cpp", "flowgraph/MonoBlend.cpp", "flowgraph/MonoToMultiConverter.cpp", Loading media/libaaudio/src/client/AAudioFlowGraph.cpp +5 −5 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ #include "AAudioFlowGraph.h" #include <flowgraph/ClipToRange.h> #include <flowgraph/Limiter.h> #include <flowgraph/ManyToMultiConverter.h> #include <flowgraph/MonoBlend.h> #include <flowgraph/MonoToMultiConverter.h> Loading Loading @@ -78,11 +78,11 @@ aaudio_result_t AAudioFlowGraph::configure(audio_format_t sourceFormat, } // For a pure float graph, there is chance that the data range may be very large. // So we should clip to a reasonable value that allows a little headroom. // So we should limit to a reasonable value that allows a little headroom. if (sourceFormat == AUDIO_FORMAT_PCM_FLOAT && sinkFormat == AUDIO_FORMAT_PCM_FLOAT) { mClipper = std::make_unique<ClipToRange>(sourceChannelCount); lastOutput->connect(&mClipper->input); lastOutput = &mClipper->output; mLimiter = std::make_unique<Limiter>(sourceChannelCount); lastOutput->connect(&mLimiter->input); lastOutput = &mLimiter->output; } // Expand the number of channels if required. Loading media/libaaudio/src/client/AAudioFlowGraph.h +2 −2 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ #include <aaudio/AAudio.h> #include <audio_utils/Balance.h> #include <flowgraph/ClipToRange.h> #include <flowgraph/Limiter.h> #include <flowgraph/ManyToMultiConverter.h> #include <flowgraph/MonoBlend.h> #include <flowgraph/MonoToMultiConverter.h> Loading Loading @@ -74,7 +74,7 @@ public: private: std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::FlowGraphSourceBuffered> mSource; std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::MonoBlend> mMonoBlend; std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::ClipToRange> mClipper; std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::Limiter> mLimiter; std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::MonoToMultiConverter> mChannelConverter; std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::ManyToMultiConverter> mManyToMultiConverter; Loading media/libaaudio/src/flowgraph/Limiter.cpp 0 → 100644 +67 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 <algorithm> #include <math.h> #include <unistd.h> #include "FlowGraphNode.h" #include "Limiter.h" using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph; Limiter::Limiter(int32_t channelCount) : FlowGraphFilter(channelCount) { } int32_t Limiter::onProcess(int32_t numFrames) { const float *inputBuffer = input.getBuffer(); float *outputBuffer = output.getBuffer(); int32_t numSamples = numFrames * output.getSamplesPerFrame(); // Cache the last valid output to reduce memory read/write float lastValidOutput = mLastValidOutput; for (int32_t i = 0; i < numSamples; i++) { // Use the previous output if the input is NaN if (!isnan(*inputBuffer)) { lastValidOutput = processFloat(*inputBuffer); } inputBuffer++; *outputBuffer++ = lastValidOutput; } mLastValidOutput = lastValidOutput; return numFrames; } float Limiter::processFloat(float in) { float in_abs = fabsf(in); if (in_abs <= 1) { return in; } float out; if (in_abs < kXWhenYis3Decibels) { out = (kPolynomialSplineA * in_abs + kPolynomialSplineB) * in_abs + kPolynomialSplineC; } else { out = M_SQRT2; } if (in < 0) { out = -out; } return out; } media/libaaudio/src/flowgraph/Limiter.h 0 → 100644 +64 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 FLOWGRAPH_LIMITER_H #define FLOWGRAPH_LIMITER_H #include <atomic> #include <unistd.h> #include <sys/types.h> #include "FlowGraphNode.h" namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph { class Limiter : public FlowGraphFilter { public: explicit Limiter(int32_t channelCount); int32_t onProcess(int32_t numFrames) override; const char *getName() override { return "Limiter"; } private: // These numbers are based on a polynomial spline for a quadratic solution Ax^2 + Bx + C // The range is up to 3 dB, (10^(3/20)), to match AudioTrack for float data. static constexpr float kPolynomialSplineA = -0.6035533905; // -(1+sqrt(2))/4 static constexpr float kPolynomialSplineB = 2.2071067811; // (3+sqrt(2))/2 static constexpr float kPolynomialSplineC = -0.6035533905; // -(1+sqrt(2))/4 static constexpr float kXWhenYis3Decibels = 1.8284271247; // -1+2sqrt(2) /** * Process an input based on the following: * If between -1 and 1, return the input value. * If above kXWhenYis3Decibels, return sqrt(2). * If below -kXWhenYis3Decibels, return -sqrt(2). * If between 1 and kXWhenYis3Decibels, use a quadratic spline (Ax^2 + Bx + C). * If between -kXWhenYis3Decibels and -1, use the absolute value for the spline and flip it. * The derivative of the spline is 1 at 1 and 0 at kXWhenYis3Decibels. * This way, the graph is both continuous and differentiable. */ float processFloat(float in); // Use the previous valid output for NaN inputs float mLastValidOutput = 0.0f; }; } /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */ #endif //FLOWGRAPH_LIMITER_H Loading
media/libaaudio/src/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -212,6 +212,7 @@ cc_library { "flowgraph/ChannelCountConverter.cpp", "flowgraph/ClipToRange.cpp", "flowgraph/FlowGraphNode.cpp", "flowgraph/Limiter.cpp", "flowgraph/ManyToMultiConverter.cpp", "flowgraph/MonoBlend.cpp", "flowgraph/MonoToMultiConverter.cpp", Loading
media/libaaudio/src/client/AAudioFlowGraph.cpp +5 −5 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ #include "AAudioFlowGraph.h" #include <flowgraph/ClipToRange.h> #include <flowgraph/Limiter.h> #include <flowgraph/ManyToMultiConverter.h> #include <flowgraph/MonoBlend.h> #include <flowgraph/MonoToMultiConverter.h> Loading Loading @@ -78,11 +78,11 @@ aaudio_result_t AAudioFlowGraph::configure(audio_format_t sourceFormat, } // For a pure float graph, there is chance that the data range may be very large. // So we should clip to a reasonable value that allows a little headroom. // So we should limit to a reasonable value that allows a little headroom. if (sourceFormat == AUDIO_FORMAT_PCM_FLOAT && sinkFormat == AUDIO_FORMAT_PCM_FLOAT) { mClipper = std::make_unique<ClipToRange>(sourceChannelCount); lastOutput->connect(&mClipper->input); lastOutput = &mClipper->output; mLimiter = std::make_unique<Limiter>(sourceChannelCount); lastOutput->connect(&mLimiter->input); lastOutput = &mLimiter->output; } // Expand the number of channels if required. Loading
media/libaaudio/src/client/AAudioFlowGraph.h +2 −2 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ #include <aaudio/AAudio.h> #include <audio_utils/Balance.h> #include <flowgraph/ClipToRange.h> #include <flowgraph/Limiter.h> #include <flowgraph/ManyToMultiConverter.h> #include <flowgraph/MonoBlend.h> #include <flowgraph/MonoToMultiConverter.h> Loading Loading @@ -74,7 +74,7 @@ public: private: std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::FlowGraphSourceBuffered> mSource; std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::MonoBlend> mMonoBlend; std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::ClipToRange> mClipper; std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::Limiter> mLimiter; std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::MonoToMultiConverter> mChannelConverter; std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::ManyToMultiConverter> mManyToMultiConverter; Loading
media/libaaudio/src/flowgraph/Limiter.cpp 0 → 100644 +67 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 <algorithm> #include <math.h> #include <unistd.h> #include "FlowGraphNode.h" #include "Limiter.h" using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph; Limiter::Limiter(int32_t channelCount) : FlowGraphFilter(channelCount) { } int32_t Limiter::onProcess(int32_t numFrames) { const float *inputBuffer = input.getBuffer(); float *outputBuffer = output.getBuffer(); int32_t numSamples = numFrames * output.getSamplesPerFrame(); // Cache the last valid output to reduce memory read/write float lastValidOutput = mLastValidOutput; for (int32_t i = 0; i < numSamples; i++) { // Use the previous output if the input is NaN if (!isnan(*inputBuffer)) { lastValidOutput = processFloat(*inputBuffer); } inputBuffer++; *outputBuffer++ = lastValidOutput; } mLastValidOutput = lastValidOutput; return numFrames; } float Limiter::processFloat(float in) { float in_abs = fabsf(in); if (in_abs <= 1) { return in; } float out; if (in_abs < kXWhenYis3Decibels) { out = (kPolynomialSplineA * in_abs + kPolynomialSplineB) * in_abs + kPolynomialSplineC; } else { out = M_SQRT2; } if (in < 0) { out = -out; } return out; }
media/libaaudio/src/flowgraph/Limiter.h 0 → 100644 +64 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 FLOWGRAPH_LIMITER_H #define FLOWGRAPH_LIMITER_H #include <atomic> #include <unistd.h> #include <sys/types.h> #include "FlowGraphNode.h" namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph { class Limiter : public FlowGraphFilter { public: explicit Limiter(int32_t channelCount); int32_t onProcess(int32_t numFrames) override; const char *getName() override { return "Limiter"; } private: // These numbers are based on a polynomial spline for a quadratic solution Ax^2 + Bx + C // The range is up to 3 dB, (10^(3/20)), to match AudioTrack for float data. static constexpr float kPolynomialSplineA = -0.6035533905; // -(1+sqrt(2))/4 static constexpr float kPolynomialSplineB = 2.2071067811; // (3+sqrt(2))/2 static constexpr float kPolynomialSplineC = -0.6035533905; // -(1+sqrt(2))/4 static constexpr float kXWhenYis3Decibels = 1.8284271247; // -1+2sqrt(2) /** * Process an input based on the following: * If between -1 and 1, return the input value. * If above kXWhenYis3Decibels, return sqrt(2). * If below -kXWhenYis3Decibels, return -sqrt(2). * If between 1 and kXWhenYis3Decibels, use a quadratic spline (Ax^2 + Bx + C). * If between -kXWhenYis3Decibels and -1, use the absolute value for the spline and flip it. * The derivative of the spline is 1 at 1 and 0 at kXWhenYis3Decibels. * This way, the graph is both continuous and differentiable. */ float processFloat(float in); // Use the previous valid output for NaN inputs float mLastValidOutput = 0.0f; }; } /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */ #endif //FLOWGRAPH_LIMITER_H