Loading media/libaaudio/src/Android.bp +11 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ cc_library { "client", "core", "fifo", "flowgraph", "legacy", "utility", ], Loading Loading @@ -42,6 +43,16 @@ cc_library { "binding/RingBufferParcelable.cpp", "binding/SharedMemoryParcelable.cpp", "binding/SharedRegionParcelable.cpp", "flowgraph/AudioProcessorBase.cpp", "flowgraph/ClipToRange.cpp", "flowgraph/MonoToMultiConverter.cpp", "flowgraph/RampLinear.cpp", "flowgraph/SinkFloat.cpp", "flowgraph/SinkI16.cpp", "flowgraph/SinkI24.cpp", "flowgraph/SourceFloat.cpp", "flowgraph/SourceI16.cpp", "flowgraph/SourceI24.cpp", ], cflags: [ Loading media/libaaudio/src/flowgraph/AudioProcessorBase.cpp 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * Copyright 2015 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 <sys/types.h> #include "AudioProcessorBase.h" using namespace flowgraph; /***************************************************************************/ int32_t AudioProcessorBase::pullData(int64_t framePosition, int32_t numFrames) { if (framePosition > mLastFramePosition) { mLastFramePosition = framePosition; mFramesValid = onProcess(framePosition, numFrames); } return mFramesValid; } /***************************************************************************/ AudioFloatBlockPort::AudioFloatBlockPort(AudioProcessorBase &parent, int32_t samplesPerFrame, int32_t framesPerBlock) : AudioPort(parent, samplesPerFrame) , mFramesPerBlock(framesPerBlock) , mSampleBlock(NULL) { int32_t numFloats = framesPerBlock * getSamplesPerFrame(); mSampleBlock = new float[numFloats]{0.0f}; } AudioFloatBlockPort::~AudioFloatBlockPort() { delete[] mSampleBlock; } /***************************************************************************/ int32_t AudioFloatOutputPort::pullData(int64_t framePosition, int32_t numFrames) { numFrames = std::min(getFramesPerBlock(), numFrames); return mParent.pullData(framePosition, numFrames); } // These need to be in the .cpp file because of forward cross references. void AudioFloatOutputPort::connect(AudioFloatInputPort *port) { port->connect(this); } void AudioFloatOutputPort::disconnect(AudioFloatInputPort *port) { port->disconnect(this); } /***************************************************************************/ int32_t AudioFloatInputPort::pullData(int64_t framePosition, int32_t numFrames) { return (mConnected == NULL) ? std::min(getFramesPerBlock(), numFrames) : mConnected->pullData(framePosition, numFrames); } float *AudioFloatInputPort::getBlock() { if (mConnected == NULL) { return AudioFloatBlockPort::getBlock(); // loaded using setValue() } else { return mConnected->getBlock(); } } /***************************************************************************/ int32_t AudioSink::pull(int32_t numFrames) { int32_t actualFrames = input.pullData(mFramePosition, numFrames); mFramePosition += actualFrames; return actualFrames; } No newline at end of file media/libaaudio/src/flowgraph/AudioProcessorBase.h 0 → 100644 +293 −0 Original line number Diff line number Diff line /* * Copyright 2015 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. */ /* * AudioProcessorBase.h * * Audio processing node and ports that can be used in a simple data flow graph. */ #ifndef FLOWGRAPH_AUDIO_PROCESSOR_BASE_H #define FLOWGRAPH_AUDIO_PROCESSOR_BASE_H #include <cassert> #include <cstring> #include <math.h> #include <sys/types.h> #include <time.h> #include <unistd.h> // TODO consider publishing all header files under "include/libaaudio/FlowGraph.h" namespace flowgraph { // Default block size that can be overridden when the AudioFloatBlockPort is created. // If it is too small then we will have too much overhead from switching between nodes. // If it is too high then we will thrash the caches. constexpr int kDefaultBlockSize = 8; // arbitrary class AudioFloatInputPort; /***************************************************************************/ class AudioProcessorBase { public: virtual ~AudioProcessorBase() = default; /** * Perform custom function. * * @param framePosition index of first frame to be processed * @param numFrames maximum number of frames requested for processing * @return number of frames actually processed */ virtual int32_t onProcess(int64_t framePosition, int32_t numFrames) = 0; /** * If the framePosition is at or after the last frame position then call onProcess(). * This prevents infinite recursion in case of cyclic graphs. * It also prevents nodes upstream from a branch from being executed twice. * * @param framePosition * @param numFrames * @return */ int32_t pullData(int64_t framePosition, int32_t numFrames); protected: int64_t mLastFramePosition = -1; // Start at -1 so that the first pull works. private: int32_t mFramesValid = 0; // num valid frames in the block }; /***************************************************************************/ /** * This is a connector that allows data to flow between modules. */ class AudioPort { public: AudioPort(AudioProcessorBase &parent, int32_t samplesPerFrame) : mParent(parent) , mSamplesPerFrame(samplesPerFrame) { } // Ports are often declared public. So let's make them non-copyable. AudioPort(const AudioPort&) = delete; AudioPort& operator=(const AudioPort&) = delete; int32_t getSamplesPerFrame() const { return mSamplesPerFrame; } protected: AudioProcessorBase &mParent; private: const int32_t mSamplesPerFrame = 1; }; /***************************************************************************/ /** * This port contains a float type buffer. * The size is framesPerBlock * samplesPerFrame). */ class AudioFloatBlockPort : public AudioPort { public: AudioFloatBlockPort(AudioProcessorBase &mParent, int32_t samplesPerFrame, int32_t framesPerBlock = kDefaultBlockSize ); virtual ~AudioFloatBlockPort(); int32_t getFramesPerBlock() const { return mFramesPerBlock; } protected: /** * @return buffer internal to the port or from a connected port */ virtual float *getBlock() { return mSampleBlock; } private: const int32_t mFramesPerBlock = 1; float *mSampleBlock = nullptr; // allocated in constructor }; /***************************************************************************/ /** * The results of a module are stored in the buffer of the output ports. */ class AudioFloatOutputPort : public AudioFloatBlockPort { public: AudioFloatOutputPort(AudioProcessorBase &parent, int32_t samplesPerFrame) : AudioFloatBlockPort(parent, samplesPerFrame) { } virtual ~AudioFloatOutputPort() = default; using AudioFloatBlockPort::getBlock; /** * Call the parent module's onProcess() method. * That may pull data from its inputs and recursively * process the entire graph. * @return number of frames actually pulled */ int32_t pullData(int64_t framePosition, int32_t numFrames); /** * Connect to the input of another module. * An input port can only have one connection. * An output port can have multiple connections. * If you connect a second output port to an input port * then it overwrites the previous connection. * * This not thread safe. Do not modify the graph topology form another thread while running. */ void connect(AudioFloatInputPort *port); /** * Disconnect from the input of another module. * This not thread safe. */ void disconnect(AudioFloatInputPort *port); }; /***************************************************************************/ class AudioFloatInputPort : public AudioFloatBlockPort { public: AudioFloatInputPort(AudioProcessorBase &parent, int32_t samplesPerFrame) : AudioFloatBlockPort(parent, samplesPerFrame) { } virtual ~AudioFloatInputPort() = default; /** * If connected to an output port then this will return * that output ports buffers. * If not connected then it returns the input ports own buffer * which can be loaded using setValue(). */ float *getBlock() override; /** * Pull data from any output port that is connected. */ int32_t pullData(int64_t framePosition, int32_t numFrames); /** * Write every value of the float buffer. * This value will be ignored if an output port is connected * to this port. */ void setValue(float value) { int numFloats = kDefaultBlockSize * getSamplesPerFrame(); float *buffer = getBlock(); for (int i = 0; i < numFloats; i++) { *buffer++ = value; } } /** * Connect to the output of another module. * An input port can only have one connection. * An output port can have multiple connections. * This not thread safe. */ void connect(AudioFloatOutputPort *port) { assert(getSamplesPerFrame() == port->getSamplesPerFrame()); mConnected = port; } void disconnect(AudioFloatOutputPort *port) { assert(mConnected == port); (void) port; mConnected = nullptr; } void disconnect() { mConnected = nullptr; } private: AudioFloatOutputPort *mConnected = nullptr; }; /***************************************************************************/ class AudioSource : public AudioProcessorBase { public: explicit AudioSource(int32_t channelCount) : output(*this, channelCount) { } virtual ~AudioSource() = default; AudioFloatOutputPort output; void setData(const void *data, int32_t numFrames) { mData = data; mSizeInFrames = numFrames; mFrameIndex = 0; } protected: const void *mData = nullptr; int32_t mSizeInFrames = 0; // number of frames in mData int32_t mFrameIndex = 0; // index of next frame to be processed }; /***************************************************************************/ class AudioSink : public AudioProcessorBase { public: explicit AudioSink(int32_t channelCount) : input(*this, channelCount) { } virtual ~AudioSink() = default; AudioFloatInputPort input; /** * Dummy processor. The work happens in the read() method. * * @param framePosition index of first frame to be processed * @param numFrames * @return number of frames actually processed */ int32_t onProcess(int64_t framePosition, int32_t numFrames) override { (void) framePosition; (void) numFrames; return 0; }; virtual int32_t read(void *data, int32_t numFrames) = 0; protected: int32_t pull(int32_t numFrames); private: int64_t mFramePosition = 0; }; } /* namespace flowgraph */ #endif /* FLOWGRAPH_AUDIO_PROCESSOR_BASE_H */ media/libaaudio/src/flowgraph/ClipToRange.cpp 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright 2015 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 <unistd.h> #include "AudioProcessorBase.h" #include "ClipToRange.h" using namespace flowgraph; ClipToRange::ClipToRange(int32_t channelCount) : input(*this, channelCount) , output(*this, channelCount) { } int32_t ClipToRange::onProcess(int64_t framePosition, int32_t numFrames) { int32_t framesToProcess = input.pullData(framePosition, numFrames); const float *inputBuffer = input.getBlock(); float *outputBuffer = output.getBlock(); int32_t numSamples = framesToProcess * output.getSamplesPerFrame(); for (int32_t i = 0; i < numSamples; i++) { *outputBuffer++ = std::min(mMaximum, std::max(mMinimum, *inputBuffer++)); } return framesToProcess; } media/libaaudio/src/flowgraph/ClipToRange.h 0 → 100644 +67 −0 Original line number Diff line number Diff line /* * Copyright 2015 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_CLIP_TO_RANGE_H #define FLOWGRAPH_CLIP_TO_RANGE_H #include <atomic> #include <unistd.h> #include <sys/types.h> #include "AudioProcessorBase.h" namespace flowgraph { // This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data. // It is designed to allow occasional transient peaks. constexpr float kDefaultMaxHeadroom = 1.41253754f; constexpr float kDefaultMinHeadroom = -kDefaultMaxHeadroom; class ClipToRange : public AudioProcessorBase { public: explicit ClipToRange(int32_t channelCount); virtual ~ClipToRange() = default; int32_t onProcess(int64_t framePosition, int32_t numFrames) override; void setMinimum(float min) { mMinimum = min; } float getMinimum() const { return mMinimum; } void setMaximum(float min) { mMaximum = min; } float getMaximum() const { return mMaximum; } AudioFloatInputPort input; AudioFloatOutputPort output; private: float mMinimum = kDefaultMinHeadroom; float mMaximum = kDefaultMaxHeadroom; }; } /* namespace flowgraph */ #endif //FLOWGRAPH_CLIP_TO_RANGE_H Loading
media/libaaudio/src/Android.bp +11 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ cc_library { "client", "core", "fifo", "flowgraph", "legacy", "utility", ], Loading Loading @@ -42,6 +43,16 @@ cc_library { "binding/RingBufferParcelable.cpp", "binding/SharedMemoryParcelable.cpp", "binding/SharedRegionParcelable.cpp", "flowgraph/AudioProcessorBase.cpp", "flowgraph/ClipToRange.cpp", "flowgraph/MonoToMultiConverter.cpp", "flowgraph/RampLinear.cpp", "flowgraph/SinkFloat.cpp", "flowgraph/SinkI16.cpp", "flowgraph/SinkI24.cpp", "flowgraph/SourceFloat.cpp", "flowgraph/SourceI16.cpp", "flowgraph/SourceI24.cpp", ], cflags: [ Loading
media/libaaudio/src/flowgraph/AudioProcessorBase.cpp 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * Copyright 2015 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 <sys/types.h> #include "AudioProcessorBase.h" using namespace flowgraph; /***************************************************************************/ int32_t AudioProcessorBase::pullData(int64_t framePosition, int32_t numFrames) { if (framePosition > mLastFramePosition) { mLastFramePosition = framePosition; mFramesValid = onProcess(framePosition, numFrames); } return mFramesValid; } /***************************************************************************/ AudioFloatBlockPort::AudioFloatBlockPort(AudioProcessorBase &parent, int32_t samplesPerFrame, int32_t framesPerBlock) : AudioPort(parent, samplesPerFrame) , mFramesPerBlock(framesPerBlock) , mSampleBlock(NULL) { int32_t numFloats = framesPerBlock * getSamplesPerFrame(); mSampleBlock = new float[numFloats]{0.0f}; } AudioFloatBlockPort::~AudioFloatBlockPort() { delete[] mSampleBlock; } /***************************************************************************/ int32_t AudioFloatOutputPort::pullData(int64_t framePosition, int32_t numFrames) { numFrames = std::min(getFramesPerBlock(), numFrames); return mParent.pullData(framePosition, numFrames); } // These need to be in the .cpp file because of forward cross references. void AudioFloatOutputPort::connect(AudioFloatInputPort *port) { port->connect(this); } void AudioFloatOutputPort::disconnect(AudioFloatInputPort *port) { port->disconnect(this); } /***************************************************************************/ int32_t AudioFloatInputPort::pullData(int64_t framePosition, int32_t numFrames) { return (mConnected == NULL) ? std::min(getFramesPerBlock(), numFrames) : mConnected->pullData(framePosition, numFrames); } float *AudioFloatInputPort::getBlock() { if (mConnected == NULL) { return AudioFloatBlockPort::getBlock(); // loaded using setValue() } else { return mConnected->getBlock(); } } /***************************************************************************/ int32_t AudioSink::pull(int32_t numFrames) { int32_t actualFrames = input.pullData(mFramePosition, numFrames); mFramePosition += actualFrames; return actualFrames; } No newline at end of file
media/libaaudio/src/flowgraph/AudioProcessorBase.h 0 → 100644 +293 −0 Original line number Diff line number Diff line /* * Copyright 2015 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. */ /* * AudioProcessorBase.h * * Audio processing node and ports that can be used in a simple data flow graph. */ #ifndef FLOWGRAPH_AUDIO_PROCESSOR_BASE_H #define FLOWGRAPH_AUDIO_PROCESSOR_BASE_H #include <cassert> #include <cstring> #include <math.h> #include <sys/types.h> #include <time.h> #include <unistd.h> // TODO consider publishing all header files under "include/libaaudio/FlowGraph.h" namespace flowgraph { // Default block size that can be overridden when the AudioFloatBlockPort is created. // If it is too small then we will have too much overhead from switching between nodes. // If it is too high then we will thrash the caches. constexpr int kDefaultBlockSize = 8; // arbitrary class AudioFloatInputPort; /***************************************************************************/ class AudioProcessorBase { public: virtual ~AudioProcessorBase() = default; /** * Perform custom function. * * @param framePosition index of first frame to be processed * @param numFrames maximum number of frames requested for processing * @return number of frames actually processed */ virtual int32_t onProcess(int64_t framePosition, int32_t numFrames) = 0; /** * If the framePosition is at or after the last frame position then call onProcess(). * This prevents infinite recursion in case of cyclic graphs. * It also prevents nodes upstream from a branch from being executed twice. * * @param framePosition * @param numFrames * @return */ int32_t pullData(int64_t framePosition, int32_t numFrames); protected: int64_t mLastFramePosition = -1; // Start at -1 so that the first pull works. private: int32_t mFramesValid = 0; // num valid frames in the block }; /***************************************************************************/ /** * This is a connector that allows data to flow between modules. */ class AudioPort { public: AudioPort(AudioProcessorBase &parent, int32_t samplesPerFrame) : mParent(parent) , mSamplesPerFrame(samplesPerFrame) { } // Ports are often declared public. So let's make them non-copyable. AudioPort(const AudioPort&) = delete; AudioPort& operator=(const AudioPort&) = delete; int32_t getSamplesPerFrame() const { return mSamplesPerFrame; } protected: AudioProcessorBase &mParent; private: const int32_t mSamplesPerFrame = 1; }; /***************************************************************************/ /** * This port contains a float type buffer. * The size is framesPerBlock * samplesPerFrame). */ class AudioFloatBlockPort : public AudioPort { public: AudioFloatBlockPort(AudioProcessorBase &mParent, int32_t samplesPerFrame, int32_t framesPerBlock = kDefaultBlockSize ); virtual ~AudioFloatBlockPort(); int32_t getFramesPerBlock() const { return mFramesPerBlock; } protected: /** * @return buffer internal to the port or from a connected port */ virtual float *getBlock() { return mSampleBlock; } private: const int32_t mFramesPerBlock = 1; float *mSampleBlock = nullptr; // allocated in constructor }; /***************************************************************************/ /** * The results of a module are stored in the buffer of the output ports. */ class AudioFloatOutputPort : public AudioFloatBlockPort { public: AudioFloatOutputPort(AudioProcessorBase &parent, int32_t samplesPerFrame) : AudioFloatBlockPort(parent, samplesPerFrame) { } virtual ~AudioFloatOutputPort() = default; using AudioFloatBlockPort::getBlock; /** * Call the parent module's onProcess() method. * That may pull data from its inputs and recursively * process the entire graph. * @return number of frames actually pulled */ int32_t pullData(int64_t framePosition, int32_t numFrames); /** * Connect to the input of another module. * An input port can only have one connection. * An output port can have multiple connections. * If you connect a second output port to an input port * then it overwrites the previous connection. * * This not thread safe. Do not modify the graph topology form another thread while running. */ void connect(AudioFloatInputPort *port); /** * Disconnect from the input of another module. * This not thread safe. */ void disconnect(AudioFloatInputPort *port); }; /***************************************************************************/ class AudioFloatInputPort : public AudioFloatBlockPort { public: AudioFloatInputPort(AudioProcessorBase &parent, int32_t samplesPerFrame) : AudioFloatBlockPort(parent, samplesPerFrame) { } virtual ~AudioFloatInputPort() = default; /** * If connected to an output port then this will return * that output ports buffers. * If not connected then it returns the input ports own buffer * which can be loaded using setValue(). */ float *getBlock() override; /** * Pull data from any output port that is connected. */ int32_t pullData(int64_t framePosition, int32_t numFrames); /** * Write every value of the float buffer. * This value will be ignored if an output port is connected * to this port. */ void setValue(float value) { int numFloats = kDefaultBlockSize * getSamplesPerFrame(); float *buffer = getBlock(); for (int i = 0; i < numFloats; i++) { *buffer++ = value; } } /** * Connect to the output of another module. * An input port can only have one connection. * An output port can have multiple connections. * This not thread safe. */ void connect(AudioFloatOutputPort *port) { assert(getSamplesPerFrame() == port->getSamplesPerFrame()); mConnected = port; } void disconnect(AudioFloatOutputPort *port) { assert(mConnected == port); (void) port; mConnected = nullptr; } void disconnect() { mConnected = nullptr; } private: AudioFloatOutputPort *mConnected = nullptr; }; /***************************************************************************/ class AudioSource : public AudioProcessorBase { public: explicit AudioSource(int32_t channelCount) : output(*this, channelCount) { } virtual ~AudioSource() = default; AudioFloatOutputPort output; void setData(const void *data, int32_t numFrames) { mData = data; mSizeInFrames = numFrames; mFrameIndex = 0; } protected: const void *mData = nullptr; int32_t mSizeInFrames = 0; // number of frames in mData int32_t mFrameIndex = 0; // index of next frame to be processed }; /***************************************************************************/ class AudioSink : public AudioProcessorBase { public: explicit AudioSink(int32_t channelCount) : input(*this, channelCount) { } virtual ~AudioSink() = default; AudioFloatInputPort input; /** * Dummy processor. The work happens in the read() method. * * @param framePosition index of first frame to be processed * @param numFrames * @return number of frames actually processed */ int32_t onProcess(int64_t framePosition, int32_t numFrames) override { (void) framePosition; (void) numFrames; return 0; }; virtual int32_t read(void *data, int32_t numFrames) = 0; protected: int32_t pull(int32_t numFrames); private: int64_t mFramePosition = 0; }; } /* namespace flowgraph */ #endif /* FLOWGRAPH_AUDIO_PROCESSOR_BASE_H */
media/libaaudio/src/flowgraph/ClipToRange.cpp 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright 2015 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 <unistd.h> #include "AudioProcessorBase.h" #include "ClipToRange.h" using namespace flowgraph; ClipToRange::ClipToRange(int32_t channelCount) : input(*this, channelCount) , output(*this, channelCount) { } int32_t ClipToRange::onProcess(int64_t framePosition, int32_t numFrames) { int32_t framesToProcess = input.pullData(framePosition, numFrames); const float *inputBuffer = input.getBlock(); float *outputBuffer = output.getBlock(); int32_t numSamples = framesToProcess * output.getSamplesPerFrame(); for (int32_t i = 0; i < numSamples; i++) { *outputBuffer++ = std::min(mMaximum, std::max(mMinimum, *inputBuffer++)); } return framesToProcess; }
media/libaaudio/src/flowgraph/ClipToRange.h 0 → 100644 +67 −0 Original line number Diff line number Diff line /* * Copyright 2015 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_CLIP_TO_RANGE_H #define FLOWGRAPH_CLIP_TO_RANGE_H #include <atomic> #include <unistd.h> #include <sys/types.h> #include "AudioProcessorBase.h" namespace flowgraph { // This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data. // It is designed to allow occasional transient peaks. constexpr float kDefaultMaxHeadroom = 1.41253754f; constexpr float kDefaultMinHeadroom = -kDefaultMaxHeadroom; class ClipToRange : public AudioProcessorBase { public: explicit ClipToRange(int32_t channelCount); virtual ~ClipToRange() = default; int32_t onProcess(int64_t framePosition, int32_t numFrames) override; void setMinimum(float min) { mMinimum = min; } float getMinimum() const { return mMinimum; } void setMaximum(float min) { mMaximum = min; } float getMaximum() const { return mMaximum; } AudioFloatInputPort input; AudioFloatOutputPort output; private: float mMinimum = kDefaultMinHeadroom; float mMaximum = kDefaultMaxHeadroom; }; } /* namespace flowgraph */ #endif //FLOWGRAPH_CLIP_TO_RANGE_H