Dynamics Processing Effect
Effect and command implementation
Bug: 64161702
Bug: 38266419
Test: manual testing and cts tests
Change-Id: Iead2cd5efd22f735fdcdfd17e81180c4b52260c5
diff --git a/media/libeffects/dynamicsproc/dsp/DPBase.cpp b/media/libeffects/dynamicsproc/dsp/DPBase.cpp
new file mode 100644
index 0000000..30c2c36
--- /dev/null
+++ b/media/libeffects/dynamicsproc/dsp/DPBase.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2018 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 <android/log.h>
+#include "DPBase.h"
+
+namespace dp_fx {
+
+DPStage::DPStage() : mInUse(DP_DEFAULT_STAGE_INUSE),
+ mEnabled(DP_DEFAULT_STAGE_ENABLED) {
+}
+
+void DPStage::init(bool inUse, bool enabled) {
+ mInUse = inUse;
+ mEnabled = enabled;
+}
+
+//----
+DPBandStage::DPBandStage() : mBandCount(0) {
+}
+
+void DPBandStage::init(bool inUse, bool enabled, int bandCount) {
+ DPStage::init(inUse, enabled);
+ mBandCount = inUse ? bandCount : 0;
+}
+
+//---
+DPBandBase::DPBandBase() {
+ init(DP_DEFAULT_BAND_ENABLED,
+ DP_DEFAULT_BAND_CUTOFF_FREQUENCY_HZ);
+}
+
+void DPBandBase::init(bool enabled, float cutoffFrequency){
+ mEnabled = enabled;
+ mCutoofFrequencyHz = cutoffFrequency;
+}
+
+//-----
+DPEqBand::DPEqBand() {
+ init(DP_DEFAULT_BAND_ENABLED,
+ DP_DEFAULT_BAND_CUTOFF_FREQUENCY_HZ,
+ DP_DEFAULT_GAIN_DB);
+}
+
+void DPEqBand::init(bool enabled, float cutoffFrequency, float gain) {
+ DPBandBase::init(enabled, cutoffFrequency);
+ setGain(gain);
+}
+
+float DPEqBand::getGain() const{
+ return mGainDb;
+}
+
+void DPEqBand::setGain(float gain) {
+ mGainDb = gain;
+}
+
+//------
+DPMbcBand::DPMbcBand() {
+ init(DP_DEFAULT_BAND_ENABLED,
+ DP_DEFAULT_BAND_CUTOFF_FREQUENCY_HZ,
+ DP_DEFAULT_ATTACK_TIME_MS,
+ DP_DEFAULT_RELEASE_TIME_MS,
+ DP_DEFAULT_RATIO,
+ DP_DEFAULT_THRESHOLD_DB,
+ DP_DEFAULT_KNEE_WIDTH_DB,
+ DP_DEFAULT_NOISE_GATE_THRESHOLD_DB,
+ DP_DEFAULT_EXPANDER_RATIO,
+ DP_DEFAULT_GAIN_DB,
+ DP_DEFAULT_GAIN_DB);
+}
+
+void DPMbcBand::init(bool enabled, float cutoffFrequency, float attackTime, float releaseTime,
+ float ratio, float threshold, float kneeWidth, float noiseGateThreshold,
+ float expanderRatio, float preGain, float postGain) {
+ DPBandBase::init(enabled, cutoffFrequency);
+ setAttackTime(attackTime);
+ setReleaseTime(releaseTime);
+ setRatio(ratio);
+ setThreshold(threshold);
+ setKneeWidth(kneeWidth);
+ setNoiseGateThreshold(noiseGateThreshold);
+ setExpanderRatio(expanderRatio);
+ setPreGain(preGain);
+ setPostGain(postGain);
+}
+
+//------
+DPEq::DPEq() {
+}
+
+void DPEq::init(bool inUse, bool enabled, uint32_t bandCount) {
+ DPBandStage::init(inUse, enabled, bandCount);
+ mBands.resize(getBandCount());
+}
+
+DPEqBand * DPEq::getBand(uint32_t band) {
+ if (band < getBandCount()) {
+ return &mBands[band];
+ }
+ return NULL;
+}
+
+void DPEq::setBand(uint32_t band, DPEqBand &src) {
+ if (band < getBandCount()) {
+ mBands[band] = src;
+ }
+}
+
+//------
+DPMbc::DPMbc() {
+}
+
+void DPMbc::init(bool inUse, bool enabled, uint32_t bandCount) {
+ DPBandStage::init(inUse, enabled, bandCount);
+ if (isInUse()) {
+ mBands.resize(bandCount);
+ } else {
+ mBands.resize(0);
+ }
+}
+
+DPMbcBand * DPMbc::getBand(uint32_t band) {
+ if (band < getBandCount()) {
+ return &mBands[band];
+ }
+ return NULL;
+}
+
+void DPMbc::setBand(uint32_t band, DPMbcBand &src) {
+ if (band < getBandCount()) {
+ mBands[band] = src;
+ }
+}
+
+//------
+DPLimiter::DPLimiter() {
+ init(DP_DEFAULT_STAGE_INUSE,
+ DP_DEFAULT_STAGE_ENABLED,
+ DP_DEFAULT_LINK_GROUP,
+ DP_DEFAULT_ATTACK_TIME_MS,
+ DP_DEFAULT_RELEASE_TIME_MS,
+ DP_DEFAULT_RATIO,
+ DP_DEFAULT_THRESHOLD_DB,
+ DP_DEFAULT_GAIN_DB);
+}
+
+void DPLimiter::init(bool inUse, bool enabled, uint32_t linkGroup, float attackTime, float releaseTime,
+ float ratio, float threshold, float postGain) {
+ DPStage::init(inUse, enabled);
+ setLinkGroup(linkGroup);
+ setAttackTime(attackTime);
+ setReleaseTime(releaseTime);
+ setRatio(ratio);
+ setThreshold(threshold);
+ setPostGain(postGain);
+}
+
+//----
+DPChannel::DPChannel() : mInitialized(false), mInputGainDb(0), mPreEqInUse(false), mMbcInUse(false),
+ mPostEqInUse(false), mLimiterInUse(false) {
+}
+
+void DPChannel::init(float inputGain, bool preEqInUse, uint32_t preEqBandCount,
+ bool mbcInUse, uint32_t mbcBandCount, bool postEqInUse, uint32_t postEqBandCount,
+ bool limiterInUse) {
+ setInputGain(inputGain);
+ mPreEqInUse = preEqInUse;
+ mMbcInUse = mbcInUse;
+ mPostEqInUse = postEqInUse;
+ mLimiterInUse = limiterInUse;
+
+ mPreEq.init(mPreEqInUse, false, preEqBandCount);
+ mMbc.init(mMbcInUse, false, mbcBandCount);
+ mPostEq.init(mPostEqInUse, false, postEqBandCount);
+ mLimiter.init(mLimiterInUse, false, 0, 50, 120, 2, -30, 0);
+ mInitialized = true;
+}
+
+DPEq* DPChannel::getPreEq() {
+ if (!mInitialized) {
+ return NULL;
+ }
+ return &mPreEq;
+}
+
+DPMbc* DPChannel::getMbc() {
+ if (!mInitialized) {
+ return NULL;
+ }
+ return &mMbc;
+}
+
+DPEq* DPChannel::getPostEq() {
+ if (!mInitialized) {
+ return NULL;
+ }
+ return &mPostEq;
+}
+
+DPLimiter* DPChannel::getLimiter() {
+ if (!mInitialized) {
+ return NULL;
+ }
+ return &mLimiter;
+}
+
+void DPChannel::setLimiter(DPLimiter &limiter) {
+ if (!mInitialized) {
+ return;
+ }
+ mLimiter = limiter;
+}
+
+//----
+DPBase::DPBase() : mInitialized(false), mChannelCount(0), mPreEqInUse(false), mPreEqBandCount(0),
+ mMbcInUse(false), mMbcBandCount(0), mPostEqInUse(false), mPostEqBandCount(0),
+ mLimiterInUse(false) {
+}
+
+void DPBase::init(uint32_t channelCount, bool preEqInUse, uint32_t preEqBandCount,
+ bool mbcInUse, uint32_t mbcBandCount, bool postEqInUse, uint32_t postEqBandCount,
+ bool limiterInUse) {
+ mChannelCount = channelCount;
+ mPreEqInUse = preEqInUse;
+ mPreEqBandCount = preEqBandCount;
+ mMbcInUse = mbcInUse;
+ mMbcBandCount = mbcBandCount;
+ mPostEqInUse = postEqInUse;
+ mPostEqBandCount = postEqBandCount;
+ mLimiterInUse = limiterInUse;
+ mChannel.resize(mChannelCount);
+ for (size_t ch = 0; ch < mChannelCount; ch++) {
+ mChannel[ch].init(0, preEqInUse, preEqBandCount, mbcInUse, mbcBandCount,
+ postEqInUse, postEqBandCount, limiterInUse);
+ }
+ mInitialized = true;
+}
+
+void DPBase::reset() {
+ //perform reset operations with current architecture.
+}
+
+size_t DPBase::processSamples(float *in, float *out, size_t samples) {
+ //actually do something with samples, for now, just apply level.
+ uint32_t channelCount = getChannelCount();
+ std::vector<float> level(channelCount);
+ for (uint32_t ch = 0; ch < channelCount; ch++) {
+ DPChannel *pChannel = getChannel(ch);
+ if (pChannel != NULL) {
+ level[ch] = pow(10, pChannel->getInputGain() / 20.0);
+ }
+ }
+ size_t processedSamples = 0;
+ float *pInput = in;
+ float *pOutput = out;
+ for (size_t k = 0; k < samples; k++) {
+ float value = *pInput++;
+ *pOutput++ = value * level[k % channelCount];
+ processedSamples++;
+ }
+ return processedSamples;
+}
+
+DPChannel* DPBase::getChannel(uint32_t channelIndex) {
+ if (!mInitialized || channelIndex < 0 || channelIndex >= mChannel.size()) {
+ return NULL;
+ }
+ return & mChannel[channelIndex];
+}
+
+} //namespace dp_fx
diff --git a/media/libeffects/dynamicsproc/dsp/DPBase.h b/media/libeffects/dynamicsproc/dsp/DPBase.h
new file mode 100644
index 0000000..52593ef
--- /dev/null
+++ b/media/libeffects/dynamicsproc/dsp/DPBase.h
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2018 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 <stdint.h>
+#include <cmath>
+#include <vector>
+#include <android/log.h>
+
+namespace dp_fx {
+
+#define DP_DEFAULT_BAND_ENABLED false
+#define DP_DEFAULT_BAND_CUTOFF_FREQUENCY_HZ 1000
+#define DP_DEFAULT_ATTACK_TIME_MS 50
+#define DP_DEFAULT_RELEASE_TIME_MS 120
+#define DP_DEFAULT_RATIO 2
+#define DP_DEFAULT_THRESHOLD_DB -30
+#define DP_DEFAULT_KNEE_WIDTH_DB 0
+#define DP_DEFAULT_NOISE_GATE_THRESHOLD_DB -90
+#define DP_DEFAULT_EXPANDER_RATIO 1
+#define DP_DEFAULT_GAIN_DB 0
+#define DP_DEFAULT_STAGE_INUSE false
+#define DP_DEFAULT_STAGE_ENABLED false
+#define DP_DEFAULT_LINK_GROUP 0
+
+
+
+class DPStage {
+public:
+ DPStage();
+ ~DPStage() = default;
+ void init(bool inUse, bool enabled);
+ bool isInUse() const {
+ return mInUse;
+ }
+ bool isEnabled() const {
+ return mEnabled;
+ }
+ void setEnabled(bool enabled) {
+ mEnabled = enabled;
+ }
+private:
+ bool mInUse;
+ bool mEnabled;
+};
+
+class DPBandStage : public DPStage {
+public:
+ DPBandStage();
+ ~DPBandStage() = default;
+ void init(bool inUse, bool enabled, int bandCount);
+ uint32_t getBandCount() const {
+ return mBandCount;
+ }
+ void setBandCount(uint32_t bandCount) {
+ mBandCount = bandCount;
+ }
+private:
+ uint32_t mBandCount;
+};
+
+class DPBandBase {
+public:
+ DPBandBase();
+ ~DPBandBase() = default;
+ void init(bool enabled, float cutoffFrequency);
+ bool isEnabled() const {
+ return mEnabled;
+ }
+ void setEnabled(bool enabled) {
+ mEnabled = enabled;
+ }
+ float getCutoffFrequency() const {
+ return mCutoofFrequencyHz;
+ }
+ void setCutoffFrequency(float cutoffFrequency) {
+ mCutoofFrequencyHz = cutoffFrequency;
+ }
+private:
+ bool mEnabled;
+ float mCutoofFrequencyHz;
+};
+
+class DPEqBand : public DPBandBase {
+public:
+ DPEqBand();
+ ~DPEqBand() = default;
+ void init(bool enabled, float cutoffFrequency, float gain);
+ float getGain() const;
+ void setGain(float gain);
+private:
+ float mGainDb;
+};
+
+class DPMbcBand : public DPBandBase {
+public:
+ DPMbcBand();
+ ~DPMbcBand() = default;
+ void init(bool enabled, float cutoffFrequency, float attackTime, float releaseTime,
+ float ratio, float threshold, float kneeWidth, float noiseGateThreshold,
+ float expanderRatio, float preGain, float postGain);
+ float getAttackTime() const {
+ return mAttackTimeMs;
+ }
+ void setAttackTime(float attackTime) {
+ mAttackTimeMs = attackTime;
+ }
+ float getReleaseTime() const {
+ return mReleaseTimeMs;
+ }
+ void setReleaseTime(float releaseTime) {
+ mReleaseTimeMs = releaseTime;
+ }
+ float getRatio() const {
+ return mRatio;
+ }
+ void setRatio(float ratio) {
+ mRatio = ratio;
+ }
+ float getThreshold() const {
+ return mThresholdDb;
+ }
+ void setThreshold(float threshold) {
+ mThresholdDb = threshold;
+ }
+ float getKneeWidth() const {
+ return mKneeWidthDb;
+ }
+ void setKneeWidth(float kneeWidth) {
+ mKneeWidthDb = kneeWidth;
+ }
+ float getNoiseGateThreshold() const {
+ return mNoiseGateThresholdDb;
+ }
+ void setNoiseGateThreshold(float noiseGateThreshold) {
+ mNoiseGateThresholdDb = noiseGateThreshold;
+ }
+ float getExpanderRatio() const {
+ return mExpanderRatio;
+ }
+ void setExpanderRatio(float expanderRatio) {
+ mExpanderRatio = expanderRatio;
+ }
+ float getPreGain() const {
+ return mPreGainDb;
+ }
+ void setPreGain(float preGain) {
+ mPreGainDb = preGain;
+ }
+ float getPostGain() const {
+ return mPostGainDb;
+ }
+ void setPostGain(float postGain) {
+ mPostGainDb = postGain;
+ }
+private:
+ float mAttackTimeMs;
+ float mReleaseTimeMs;
+ float mRatio;
+ float mThresholdDb;
+ float mKneeWidthDb;
+ float mNoiseGateThresholdDb;
+ float mExpanderRatio;
+ float mPreGainDb;
+ float mPostGainDb;
+};
+
+class DPEq : public DPBandStage {
+public:
+ DPEq();
+ ~DPEq() = default;
+ void init(bool inUse, bool enabled, uint32_t bandCount);
+ DPEqBand * getBand(uint32_t band);
+ void setBand(uint32_t band, DPEqBand &src);
+private:
+ std::vector<DPEqBand> mBands;
+};
+
+class DPMbc : public DPBandStage {
+public:
+ DPMbc();
+ ~DPMbc() = default;
+ void init(bool inUse, bool enabled, uint32_t bandCount);
+ DPMbcBand * getBand(uint32_t band);
+ void setBand(uint32_t band, DPMbcBand &src);
+private:
+ std::vector<DPMbcBand> mBands;
+};
+
+class DPLimiter : public DPStage {
+public:
+ DPLimiter();
+ ~DPLimiter() = default;
+ void init(bool inUse, bool enabled, uint32_t linkGroup, float attackTime, float releaseTime,
+ float ratio, float threshold, float postGain);
+ uint32_t getLinkGroup() const {
+ return mLinkGroup;
+ }
+ void setLinkGroup(uint32_t linkGroup) {
+ mLinkGroup = linkGroup;
+ }
+ float getAttackTime() const {
+ return mAttackTimeMs;
+ }
+ void setAttackTime(float attackTime) {
+ mAttackTimeMs = attackTime;
+ }
+ float getReleaseTime() const {
+ return mReleaseTimeMs;
+ }
+ void setReleaseTime(float releaseTime) {
+ mReleaseTimeMs = releaseTime;
+ }
+ float getRatio() const {
+ return mRatio;
+ }
+ void setRatio(float ratio) {
+ mRatio = ratio;
+ }
+ float getThreshold() const {
+ return mThresholdDb;
+ }
+ void setThreshold(float threshold) {
+ mThresholdDb = threshold;
+ }
+ float getPostGain() const {
+ return mPostGainDb;
+ }
+ void setPostGain(float postGain) {
+ mPostGainDb = postGain;
+ }
+private:
+ uint32_t mLinkGroup;
+ float mAttackTimeMs;
+ float mReleaseTimeMs;
+ float mRatio;
+ float mThresholdDb;
+ float mPostGainDb;
+};
+
+class DPChannel {
+public:
+ DPChannel();
+ ~DPChannel() = default;
+ void init(float inputGain, bool preEqInUse, uint32_t preEqBandCount,
+ bool mbcInUse, uint32_t mbcBandCount, bool postEqInUse, uint32_t postEqBandCount,
+ bool limiterInUse);
+
+ float getInputGain() const {
+ if (!mInitialized) {
+ return 0;
+ }
+ return mInputGainDb;
+ }
+ void setInputGain(float gain) {
+ mInputGainDb = gain;
+ }
+
+ DPEq* getPreEq();
+ DPMbc* getMbc();
+ DPEq* getPostEq();
+ DPLimiter *getLimiter();
+ void setLimiter(DPLimiter &limiter);
+
+private:
+ bool mInitialized;
+ float mInputGainDb;
+
+ DPEq mPreEq;
+ DPMbc mMbc;
+ DPEq mPostEq;
+ DPLimiter mLimiter;
+
+ bool mPreEqInUse;
+ bool mMbcInUse;
+ bool mPostEqInUse;
+ bool mLimiterInUse;
+};
+
+class DPBase {
+public:
+ DPBase();
+ virtual ~DPBase() = default;
+
+ void init(uint32_t channelCount, bool preEqInUse, uint32_t preEqBandCount,
+ bool mbcInUse, uint32_t mbcBandCount, bool postEqInUse, uint32_t postEqBandCount,
+ bool limiterInUse);
+ virtual size_t processSamples(float *in, float *out, size_t samples);
+ virtual void reset();
+
+ DPChannel* getChannel(uint32_t channelIndex);
+ uint32_t getChannelCount() const {
+ return mChannelCount;
+ }
+ uint32_t getPreEqBandCount() const {
+ return mPreEqBandCount;
+ }
+ uint32_t getMbcBandCount() const {
+ return mMbcBandCount;
+ }
+ uint32_t getPostEqBandCount() const {
+ return mPostEqBandCount;
+ }
+ bool isPreEQInUse() const {
+ return mPreEqInUse;
+ }
+ bool isMbcInUse() const {
+ return mMbcInUse;
+ }
+ bool isPostEqInUse() const {
+ return mPostEqInUse;
+ }
+ bool isLimiterInUse() const {
+ return mLimiterInUse;
+ }
+
+private:
+ bool mInitialized;
+ //general
+ uint32_t mChannelCount;
+ bool mPreEqInUse;
+ uint32_t mPreEqBandCount;
+ bool mMbcInUse;
+ uint32_t mMbcBandCount;
+ bool mPostEqInUse;
+ uint32_t mPostEqBandCount;
+ bool mLimiterInUse;
+
+ std::vector<DPChannel> mChannel;
+};
+
+} //namespace dp_fx