summaryrefslogtreecommitdiffstats
path: root/media/libeffects/testlibs
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2010-07-09 12:28:50 -0700
committerEric Laurent <elaurent@google.com>2010-07-17 06:33:00 -0700
commit2c8e5cab3faa6d360e222b7a6c40a80083d021ac (patch)
treefd19b8baa829edb78116b089d1122ea4ef0921e1 /media/libeffects/testlibs
parentada2ac8e09b6d3f2b3c3155a852ba0fffae1b592 (diff)
downloadframeworks_av-2c8e5cab3faa6d360e222b7a6c40a80083d021ac.zip
frameworks_av-2c8e5cab3faa6d360e222b7a6c40a80083d021ac.tar.gz
frameworks_av-2c8e5cab3faa6d360e222b7a6c40a80083d021ac.tar.bz2
First submission of audio effect library from NXP software.
This CL contains the first open sourceable version of the audio effect library from NXP software. The effects implemented are: - Bass boost - Virtualizer (stereo widening) - Equalizer - Spectrum analyzer Source file for the effect engines are located under libeffects/lvm/lib The wrapper implementing the interface with the audio effect framework in under libeffects/lvm/wrapper The code of other effect libraries has also been reorganized fo clarity: - the effect factory is now under libeffects/factory - the test equalizer and reverb effects are under libeffect/testlibs - the visualizer is under libeffects/virtualizer Change-Id: I8d91e2181f81b89f8fc0c1e1e6bf552c5809b2eb
Diffstat (limited to 'media/libeffects/testlibs')
-rw-r--r--media/libeffects/testlibs/Android.mk_66
-rw-r--r--media/libeffects/testlibs/AudioBiquadFilter.cpp260
-rw-r--r--media/libeffects/testlibs/AudioBiquadFilter.h180
-rw-r--r--media/libeffects/testlibs/AudioCoefInterpolator.cpp84
-rw-r--r--media/libeffects/testlibs/AudioCoefInterpolator.h98
-rw-r--r--media/libeffects/testlibs/AudioCommon.h92
-rw-r--r--media/libeffects/testlibs/AudioEqualizer.cpp315
-rw-r--r--media/libeffects/testlibs/AudioEqualizer.h246
-rw-r--r--media/libeffects/testlibs/AudioFormatAdapter.h184
-rw-r--r--media/libeffects/testlibs/AudioHighShelfFilterCoef.inl225
-rw-r--r--media/libeffects/testlibs/AudioLowShelfFilterCoef.inl375
-rw-r--r--media/libeffects/testlibs/AudioPeakingFilter.cpp121
-rw-r--r--media/libeffects/testlibs/AudioPeakingFilter.h151
-rw-r--r--media/libeffects/testlibs/AudioPeakingFilterCoef.inl2700
-rw-r--r--media/libeffects/testlibs/AudioShelvingFilter.cpp109
-rw-r--r--media/libeffects/testlibs/AudioShelvingFilter.h146
-rw-r--r--media/libeffects/testlibs/EffectEqualizer.cpp654
-rw-r--r--media/libeffects/testlibs/EffectReverb.c2135
-rw-r--r--media/libeffects/testlibs/EffectReverb.h437
-rw-r--r--media/libeffects/testlibs/EffectsMath.c143
-rw-r--r--media/libeffects/testlibs/EffectsMath.h424
21 files changed, 9145 insertions, 0 deletions
diff --git a/media/libeffects/testlibs/Android.mk_ b/media/libeffects/testlibs/Android.mk_
new file mode 100644
index 0000000..9ba71ed
--- /dev/null
+++ b/media/libeffects/testlibs/Android.mk_
@@ -0,0 +1,66 @@
+LOCAL_PATH:= $(call my-dir)
+
+# Test Reverb library
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ EffectReverb.c.arm \
+ EffectsMath.c.arm
+LOCAL_CFLAGS+= -O2
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+LOCAL_MODULE:= libreverbtest
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+LOCAL_LDLIBS += -ldl
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, graphics corecg)
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Test Equalizer library
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ EffectsMath.c.arm \
+ EffectEqualizer.cpp \
+ AudioBiquadFilter.cpp.arm \
+ AudioCoefInterpolator.cpp.arm \
+ AudioPeakingFilter.cpp.arm \
+ AudioShelvingFilter.cpp.arm \
+ AudioEqualizer.cpp.arm
+
+LOCAL_CFLAGS+= -O2
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+LOCAL_MODULE:= libequalizertest
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+LOCAL_LDLIBS += -ldl
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, graphics corecg)
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/media/libeffects/testlibs/AudioBiquadFilter.cpp b/media/libeffects/testlibs/AudioBiquadFilter.cpp
new file mode 100644
index 0000000..72917a3
--- /dev/null
+++ b/media/libeffects/testlibs/AudioBiquadFilter.cpp
@@ -0,0 +1,260 @@
+/* //device/servers/AudioFlinger/AudioBiquadFilter.cpp
+**
+** Copyright 2009, 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 <string.h>
+#include <assert.h>
+
+#include "AudioBiquadFilter.h"
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+const audio_coef_t AudioBiquadFilter::IDENTITY_COEFS[AudioBiquadFilter::NUM_COEFS] = { AUDIO_COEF_ONE, 0, 0, 0, 0 };
+
+AudioBiquadFilter::AudioBiquadFilter(int nChannels, int sampleRate) {
+ configure(nChannels, sampleRate);
+ reset();
+}
+
+void AudioBiquadFilter::configure(int nChannels, int sampleRate) {
+ assert(nChannels > 0 && nChannels <= MAX_CHANNELS);
+ assert(sampleRate > 0);
+ mNumChannels = nChannels;
+ mMaxDelta = static_cast<int64_t>(MAX_DELTA_PER_SEC)
+ * AUDIO_COEF_ONE
+ / sampleRate;
+ clear();
+}
+
+void AudioBiquadFilter::reset() {
+ memcpy(mCoefs, IDENTITY_COEFS, sizeof(mCoefs));
+ mCoefDirtyBits = 0;
+ setState(STATE_BYPASS);
+}
+
+void AudioBiquadFilter::clear() {
+ memset(mDelays, 0, sizeof(mDelays));
+}
+
+void AudioBiquadFilter::setCoefs(const audio_coef_t coefs[NUM_COEFS], bool immediate) {
+ memcpy(mTargetCoefs, coefs, sizeof(mTargetCoefs));
+ if (mState & STATE_ENABLED_MASK) {
+ if (UNLIKELY(immediate)) {
+ memcpy(mCoefs, coefs, sizeof(mCoefs));
+ setState(STATE_NORMAL);
+ } else {
+ setState(STATE_TRANSITION_TO_NORMAL);
+ }
+ }
+}
+
+void AudioBiquadFilter::process(const audio_sample_t in[], audio_sample_t out[],
+ int frameCount) {
+ (this->*mCurProcessFunc)(in, out, frameCount);
+}
+
+void AudioBiquadFilter::enable(bool immediate) {
+ if (UNLIKELY(immediate)) {
+ memcpy(mCoefs, mTargetCoefs, sizeof(mCoefs));
+ setState(STATE_NORMAL);
+ } else {
+ setState(STATE_TRANSITION_TO_NORMAL);
+ }
+}
+
+void AudioBiquadFilter::disable(bool immediate) {
+ if (UNLIKELY(immediate)) {
+ memcpy(mCoefs, IDENTITY_COEFS, sizeof(mCoefs));
+ setState(STATE_BYPASS);
+ } else {
+ setState(STATE_TRANSITION_TO_BYPASS);
+ }
+}
+
+void AudioBiquadFilter::setState(state_t state) {
+ switch (state) {
+ case STATE_BYPASS:
+ mCurProcessFunc = &AudioBiquadFilter::process_bypass;
+ break;
+ case STATE_TRANSITION_TO_BYPASS:
+ if (mNumChannels == 1) {
+ mCurProcessFunc = &AudioBiquadFilter::process_transition_bypass_mono;
+ } else {
+ mCurProcessFunc = &AudioBiquadFilter::process_transition_bypass_multi;
+ }
+ mCoefDirtyBits = (1 << NUM_COEFS) - 1;
+ break;
+ case STATE_TRANSITION_TO_NORMAL:
+ if (mNumChannels == 1) {
+ mCurProcessFunc = &AudioBiquadFilter::process_transition_normal_mono;
+ } else {
+ mCurProcessFunc = &AudioBiquadFilter::process_transition_normal_multi;
+ }
+ mCoefDirtyBits = (1 << NUM_COEFS) - 1;
+ break;
+ case STATE_NORMAL:
+ if (mNumChannels == 1) {
+ mCurProcessFunc = &AudioBiquadFilter::process_normal_mono;
+ } else {
+ mCurProcessFunc = &AudioBiquadFilter::process_normal_multi;
+ }
+ break;
+ }
+ mState = state;
+}
+
+bool AudioBiquadFilter::updateCoefs(const audio_coef_t coefs[NUM_COEFS],
+ int frameCount) {
+ int64_t maxDelta = mMaxDelta * frameCount;
+ for (int i = 0; i < NUM_COEFS; ++i) {
+ if (mCoefDirtyBits & (1<<i)) {
+ audio_coef_t diff = coefs[i] - mCoefs[i];
+ if (diff > maxDelta) {
+ mCoefs[i] += maxDelta;
+ } else if (diff < -maxDelta) {
+ mCoefs[i] -= maxDelta;
+ } else {
+ mCoefs[i] = coefs[i];
+ mCoefDirtyBits ^= (1<<i);
+ }
+ }
+ }
+ return mCoefDirtyBits == 0;
+}
+
+void AudioBiquadFilter::process_bypass(const audio_sample_t * in,
+ audio_sample_t * out,
+ int frameCount) {
+ // The common case is in-place processing, because this is what the EQ does.
+ if (UNLIKELY(in != out)) {
+ memcpy(out, in, frameCount * mNumChannels * sizeof(audio_sample_t));
+ }
+}
+
+void AudioBiquadFilter::process_normal_mono(const audio_sample_t * in,
+ audio_sample_t * out,
+ int frameCount) {
+ size_t nFrames = frameCount;
+ audio_sample_t x1 = mDelays[0][0];
+ audio_sample_t x2 = mDelays[0][1];
+ audio_sample_t y1 = mDelays[0][2];
+ audio_sample_t y2 = mDelays[0][3];
+ const audio_coef_t b0 = mCoefs[0];
+ const audio_coef_t b1 = mCoefs[1];
+ const audio_coef_t b2 = mCoefs[2];
+ const audio_coef_t a1 = mCoefs[3];
+ const audio_coef_t a2 = mCoefs[4];
+ while (nFrames-- > 0) {
+ audio_sample_t x0 = *(in++);
+ audio_coef_sample_acc_t acc;
+ acc = mul_coef_sample(b0, x0);
+ acc = mac_coef_sample(b1, x1, acc);
+ acc = mac_coef_sample(b2, x2, acc);
+ acc = mac_coef_sample(a1, y1, acc);
+ acc = mac_coef_sample(a2, y2, acc);
+ audio_sample_t y0 = coef_sample_acc_to_sample(acc);
+ y2 = y1;
+ y1 = y0;
+ x2 = x1;
+ x1 = x0;
+ (*out++) = y0;
+ }
+ mDelays[0][0] = x1;
+ mDelays[0][1] = x2;
+ mDelays[0][2] = y1;
+ mDelays[0][3] = y2;
+}
+
+void AudioBiquadFilter::process_transition_normal_mono(const audio_sample_t * in,
+ audio_sample_t * out,
+ int frameCount) {
+ if (updateCoefs(mTargetCoefs, frameCount)) {
+ setState(STATE_NORMAL);
+ }
+ process_normal_mono(in, out, frameCount);
+}
+
+void AudioBiquadFilter::process_transition_bypass_mono(const audio_sample_t * in,
+ audio_sample_t * out,
+ int frameCount) {
+ if (updateCoefs(IDENTITY_COEFS, frameCount)) {
+ setState(STATE_NORMAL);
+ }
+ process_normal_mono(in, out, frameCount);
+}
+
+void AudioBiquadFilter::process_normal_multi(const audio_sample_t * in,
+ audio_sample_t * out,
+ int frameCount) {
+ const audio_coef_t b0 = mCoefs[0];
+ const audio_coef_t b1 = mCoefs[1];
+ const audio_coef_t b2 = mCoefs[2];
+ const audio_coef_t a1 = mCoefs[3];
+ const audio_coef_t a2 = mCoefs[4];
+ for (int ch = 0; ch < mNumChannels; ++ch) {
+ size_t nFrames = frameCount;
+ audio_sample_t x1 = mDelays[ch][0];
+ audio_sample_t x2 = mDelays[ch][1];
+ audio_sample_t y1 = mDelays[ch][2];
+ audio_sample_t y2 = mDelays[ch][3];
+ while (nFrames-- > 0) {
+ audio_sample_t x0 = *in;
+ audio_coef_sample_acc_t acc;
+ acc = mul_coef_sample(b0, x0);
+ acc = mac_coef_sample(b1, x1, acc);
+ acc = mac_coef_sample(b2, x2, acc);
+ acc = mac_coef_sample(a1, y1, acc);
+ acc = mac_coef_sample(a2, y2, acc);
+ audio_sample_t y0 = coef_sample_acc_to_sample(acc);
+ y2 = y1;
+ y1 = y0;
+ x2 = x1;
+ x1 = x0;
+ *out = y0;
+ in += mNumChannels;
+ out += mNumChannels;
+ }
+ mDelays[ch][0] = x1;
+ mDelays[ch][1] = x2;
+ mDelays[ch][2] = y1;
+ mDelays[ch][3] = y2;
+ in -= frameCount * mNumChannels - 1;
+ out -= frameCount * mNumChannels - 1;
+ }
+}
+
+void AudioBiquadFilter::process_transition_normal_multi(const audio_sample_t * in,
+ audio_sample_t * out,
+ int frameCount) {
+ if (updateCoefs(mTargetCoefs, frameCount)) {
+ setState(STATE_NORMAL);
+ }
+ process_normal_multi(in, out, frameCount);
+}
+
+void AudioBiquadFilter::process_transition_bypass_multi(const audio_sample_t * in,
+ audio_sample_t * out,
+ int frameCount) {
+ if (updateCoefs(IDENTITY_COEFS, frameCount)) {
+ setState(STATE_NORMAL);
+ }
+ process_normal_multi(in, out, frameCount);
+}
+
+}
diff --git a/media/libeffects/testlibs/AudioBiquadFilter.h b/media/libeffects/testlibs/AudioBiquadFilter.h
new file mode 100644
index 0000000..2b0e2d6
--- /dev/null
+++ b/media/libeffects/testlibs/AudioBiquadFilter.h
@@ -0,0 +1,180 @@
+/* //device/include/server/AudioFlinger/AudioBiquadFilter.h
+**
+** Copyright 2007, 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 ANDROID_AUDIO_BIQUAD_FILTER_H
+#define ANDROID_AUDIO_BIQUAD_FILTER_H
+
+#include "AudioCommon.h"
+
+namespace android {
+// A biquad filter.
+// Implements the recursion y[n]=a0*y[n-1]+a1*y[n-2]+b0*x[n]+b1*x[n-1]+b2*x[n-2]
+// (the a0 and a1 coefficients have an opposite sign to the common convention)
+// The filter works on fixed sized blocks of data (frameCount multi-channel
+// samples, as defined during construction). An arbitrary number of interlaced
+// channels is supported.
+// Filter can operate in an enabled (active) or disabled (bypassed) states.
+// A mechanism for suppression of artifacts caused by abrupt coefficient changes
+// is implemented: normally, when the enable(), disable() and setCoefs() methods
+// are called without the immediate flag set, the filter smoothly transitions
+// from its current state to the desired state.
+class AudioBiquadFilter {
+public:
+ // Max number of channels (can be changed here, and everything should work).
+ static const int MAX_CHANNELS = 2;
+ // Number of coefficients.
+ static const int NUM_COEFS = 5;
+
+ // Constructor.
+ // nChannels Number of input/output channels.
+ // sampleRate Sample rate, in Hz.
+ AudioBiquadFilter(int nChannels, int sampleRate);
+
+ // Reconfiguration of the filter. Implies clear().
+ // nChannels Number of input/output channels.
+ // sampleRate Sample rate, in Hz.
+ void configure(int nChannels, int sampleRate);
+
+ // Resets the internal state of the filter.
+ // Coefficients are reset to identity, state becomes disabled. This change
+ // happens immediately and might cause discontinuities in the output.
+ // Delay lines are not cleared.
+ void reset();
+
+ // Clears the delay lines.
+ // This change happens immediately and might cause discontinuities in the
+ // output.
+ void clear();
+
+ // Sets the coefficients.
+ // If called when filter is disabled, will have no immediate effect, but the
+ // new coefficients will be set and used next time the filter is enabled.
+ // coefs The new coefficients.
+ // immediate If true, transitions to new coefficients smoothly, without
+ // introducing discontinuities in the output. Otherwise,
+ // transitions immediately.
+ void setCoefs(const audio_coef_t coefs[NUM_COEFS], bool immediate = false);
+
+ // Process a buffer of data. Always processes frameCount multi-channel
+ // samples. Processing can be done in-place, by passing the same buffer as
+ // both arguments.
+ // in The input buffer. Should be of size frameCount * nChannels.
+ // out The output buffer. Should be of size frameCount * nChannels.
+ // frameCount Number of multi-channel samples to process.
+ void process(const audio_sample_t in[], audio_sample_t out[],
+ int frameCount);
+
+ // Enables (activates) the filter.
+ // immediate If true, transitions to new state smoothly, without
+ // introducing discontinuities in the output. Otherwise,
+ // transitions immediately.
+ void enable(bool immediate = false);
+
+ // Disables (bypasses) the filter.
+ // immediate If true, transitions to new state smoothly, without
+ // introducing discontinuities in the output. Otherwise,
+ // transitions immediately.
+ void disable(bool immediate = false);
+
+private:
+ // A prototype of the actual processing function. Has the same semantics as
+ // the process() method.
+ typedef void (AudioBiquadFilter::*process_func)(const audio_sample_t[],
+ audio_sample_t[],
+ int frameCount);
+
+ // The maximum rate of coefficient change, measured in coefficient units per
+ // second.
+ static const audio_coef_t MAX_DELTA_PER_SEC = 2000;
+
+ // Coefficients of identity transformation.
+ static const audio_coef_t IDENTITY_COEFS[NUM_COEFS];
+
+ // Filter state.
+ enum state_t {
+ // Bypass.
+ STATE_BYPASS = 0x01,
+ // In the process of smooth transition to bypass state.
+ STATE_TRANSITION_TO_BYPASS = 0x02,
+ // In the process of smooth transition to normal (enabled) state.
+ STATE_TRANSITION_TO_NORMAL = 0x04,
+ // In normal (enabled) state.
+ STATE_NORMAL = 0x05,
+ // A bit-mask for determining whether the filter is enabled or disabled
+ // in the eyes of the client.
+ STATE_ENABLED_MASK = 0x04
+ };
+
+ // Number of channels.
+ int mNumChannels;
+ // Current state.
+ state_t mState;
+ // Maximum coefficient delta per sample.
+ audio_coef_t mMaxDelta;
+
+ // A bit-mask designating for which coefficients the current value is not
+ // necessarily identical to the target value (since we're in transition
+ // state).
+ uint32_t mCoefDirtyBits;
+ // The current coefficients.
+ audio_coef_t mCoefs[NUM_COEFS];
+ // The target coefficients. Will not be identical to mCoefs if we are in a
+ // transition state.
+ audio_coef_t mTargetCoefs[NUM_COEFS];
+
+ // The delay lines.
+ audio_sample_t mDelays[MAX_CHANNELS][4];
+
+ // Current processing function (determines according to current state and
+ // number of channels).
+ process_func mCurProcessFunc;
+
+ // Sets a new state. Updates the processing function accordingly, and sets
+ // the dirty bits if changing to a transition state.
+ void setState(state_t state);
+
+ // In a transition state, modifies the current coefs towards the passed
+ // coefs, while keeping a smooth change rate. Whenever a coef reaches its
+ // target value, the dirty bit is cleared. If all are clear, the function
+ // returns true, and we can then change to our target state.
+ bool updateCoefs(const audio_coef_t coefs[NUM_COEFS], int frameCount);
+
+ // Processing function when in disabled state.
+ void process_bypass(const audio_sample_t * in, audio_sample_t * out,
+ int frameCount);
+ // Processing function when in normal state, mono.
+ void process_normal_mono(const audio_sample_t * in, audio_sample_t * out,
+ int frameCount);
+ // Processing function when transitioning to normal state, mono.
+ void process_transition_normal_mono(const audio_sample_t * in,
+ audio_sample_t * out, int frameCount);
+ // Processing function when transitioning to bypass state, mono.
+ void process_transition_bypass_mono(const audio_sample_t * in,
+ audio_sample_t * out, int frameCount);
+ // Processing function when in normal state, multi-channel.
+ void process_normal_multi(const audio_sample_t * in, audio_sample_t * out,
+ int frameCount);
+ // Processing function when transitioning to normal state, multi-channel.
+ void process_transition_normal_multi(const audio_sample_t * in,
+ audio_sample_t * out, int frameCount);
+ // Processing function when transitioning to bypass state, multi-channel.
+ void process_transition_bypass_multi(const audio_sample_t * in,
+ audio_sample_t * out, int frameCount);
+};
+}
+
+#endif // ANDROID_AUDIO_BIQUAD_FILTER_H
diff --git a/media/libeffects/testlibs/AudioCoefInterpolator.cpp b/media/libeffects/testlibs/AudioCoefInterpolator.cpp
new file mode 100644
index 0000000..039ab9f
--- /dev/null
+++ b/media/libeffects/testlibs/AudioCoefInterpolator.cpp
@@ -0,0 +1,84 @@
+/* //device/servers/AudioFlinger/AudioCoefInterpolator.cpp
+ **
+ ** Copyright 2008, 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 <string.h>
+#include "AudioCoefInterpolator.h"
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+AudioCoefInterpolator::AudioCoefInterpolator(size_t nInDims,
+ const size_t inDims[],
+ size_t nOutDims,
+ const audio_coef_t * table) {
+ mNumInDims = nInDims;
+ memcpy(mInDims, inDims, nInDims * sizeof(size_t));
+ mNumOutDims = nOutDims;
+ mTable = table;
+ // Initialize offsets array
+ size_t dim = nInDims - 1;
+ mInDimOffsets[nInDims - 1] = nOutDims;
+ while (dim-- > 0) {
+ mInDimOffsets[dim] = mInDimOffsets[dim + 1] * mInDims[dim + 1];
+ }
+}
+
+void AudioCoefInterpolator::getCoef(const int intCoord[], uint32_t fracCoord[],
+ audio_coef_t out[]) {
+ size_t index = 0;
+ size_t dim = mNumInDims;
+ while (dim-- > 0) {
+ if (UNLIKELY(intCoord[dim] < 0)) {
+ fracCoord[dim] = 0;
+ } else if (UNLIKELY(intCoord[dim] >= (int)mInDims[dim] - 1)) {
+ fracCoord[dim] = 0;
+ index += mInDimOffsets[dim] * (mInDims[dim] - 1);
+ } else {
+ index += mInDimOffsets[dim] * intCoord[dim];
+ }
+ }
+ getCoefRecurse(index, fracCoord, out, 0);
+}
+
+void AudioCoefInterpolator::getCoefRecurse(size_t index,
+ const uint32_t fracCoord[],
+ audio_coef_t out[], size_t dim) {
+ if (dim == mNumInDims) {
+ memcpy(out, mTable + index, mNumOutDims * sizeof(audio_coef_t));
+ } else {
+ getCoefRecurse(index, fracCoord, out, dim + 1);
+ if (LIKELY(fracCoord != 0)) {
+ audio_coef_t tempCoef[MAX_OUT_DIMS];
+ getCoefRecurse(index + mInDimOffsets[dim], fracCoord, tempCoef,
+ dim + 1);
+ size_t d = mNumOutDims;
+ while (d-- > 0) {
+ out[d] = interp(out[d], tempCoef[d], fracCoord[dim]);
+ }
+ }
+ }
+}
+
+audio_coef_t AudioCoefInterpolator::interp(audio_coef_t lo, audio_coef_t hi,
+ uint32_t frac) {
+ int64_t delta = static_cast<int64_t>(hi-lo) * frac;
+ return lo + static_cast<audio_coef_t> (delta >> 32);
+}
+
+}
diff --git a/media/libeffects/testlibs/AudioCoefInterpolator.h b/media/libeffects/testlibs/AudioCoefInterpolator.h
new file mode 100644
index 0000000..13e5697
--- /dev/null
+++ b/media/libeffects/testlibs/AudioCoefInterpolator.h
@@ -0,0 +1,98 @@
+/* //device/include/server/AudioFlinger/AudioCoefInterpolator.h
+ **
+ ** Copyright 2007, 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 ANDROID_AUDIO_COEF_INTERPOLATOR_H
+#define ANDROID_AUDIO_COEF_INTERPOLATOR_H
+
+#include "AudioCommon.h"
+
+namespace android {
+
+// A helper class for linear interpolation of N-D -> M-D coefficient tables.
+// This class provides support for out-of-range indexes.
+// Details:
+// The purpose is efficient approximation of a N-dimensional vector to
+// M-dimensional function. The approximation is based on a table of output
+// values on a uniform grid of the input values. Values not on the grid are
+// linearly interpolated.
+// Access to values are done by specifying input values in table index units,
+// having an integer and a fractional part, e.g. retrieving a value from index
+// 1.4 will result in linear interpolation between index 1 and index 2.
+class AudioCoefInterpolator {
+public:
+ // Constructor.
+ // nInDims Number of input dimensions (limited to MAX_IN_DIMS).
+ // inDims An array of size nInDims with the size of the table on each
+ // respective dimension.
+ // nOutDims Number of output dimensions (limited to MAX_OUT_DIMS).
+ // table The coefficient table. Should be of size:
+ // inDims[0]*inDims[1]*...*inDims[nInDims-1]*nOutDims, where
+ // func([i,j,k]) = table(i,j,k,:)
+ AudioCoefInterpolator(size_t nInDims, const size_t inDims[],
+ size_t nOutDims, const audio_coef_t * table);
+
+ // Get the value of the approximated function at a given point.
+ // intCoord The integer part of the input value. Should be an array of
+ // size nInDims.
+ // fracCoord The fractional part of the input value. Should be an array
+ // of size nInDims. This value is in 32-bit precision.
+ // out An array for the output value. Should be of size nOutDims.
+ void getCoef(const int intCoord[], uint32_t fracCoord[], audio_coef_t out[]);
+
+private:
+ // Maximum allowed number of input dimensions.
+ static const size_t MAX_IN_DIMS = 8;
+ // Maximum allowed number of output dimensions.
+ static const size_t MAX_OUT_DIMS = 8;
+
+ // Number of input dimensions.
+ size_t mNumInDims;
+ // Number of input dimensions.
+ size_t mInDims[MAX_IN_DIMS];
+ // The offset between two consecutive indexes of each dimension. This is in
+ // fact a cumulative product of mInDims (done in reverse).
+ size_t mInDimOffsets[MAX_IN_DIMS];
+ // Number of output dimensions.
+ size_t mNumOutDims;
+ // The coefficient table.
+ const audio_coef_t * mTable;
+
+ // A recursive function for getting an interpolated coefficient value.
+ // The recursion depth is the number of input dimensions.
+ // At each step, we fetch two interpolated values of the current dimension,
+ // by two recursive calls to this method for the next dimensions. We then
+ // linearly interpolate these values over the current dimension.
+ // index The linear integer index of the value we need to interpolate.
+ // fracCoord A vector of fractional coordinates for each of the input
+ // dimensions.
+ // out Where the output should be written. Needs to be of size
+ // mNumOutDims.
+ // dim The input dimensions we are currently interpolating. This
+ // value will be increased on recursive calls.
+ void getCoefRecurse(size_t index, const uint32_t fracCoord[],
+ audio_coef_t out[], size_t dim);
+
+ // Scalar interpolation of two data points.
+ // lo The first data point.
+ // hi The second data point.
+ // frac A 32-bit fraction designating the weight of the second point.
+ static audio_coef_t interp(audio_coef_t lo, audio_coef_t hi, uint32_t frac);
+};
+
+}
+
+#endif // ANDROID_AUDIO_COEF_INTERPOLATOR_H
diff --git a/media/libeffects/testlibs/AudioCommon.h b/media/libeffects/testlibs/AudioCommon.h
new file mode 100644
index 0000000..444f93a
--- /dev/null
+++ b/media/libeffects/testlibs/AudioCommon.h
@@ -0,0 +1,92 @@
+/*
+**
+** Copyright 2009, 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 ANDROID_AUDIO_COMMON_H
+#define ANDROID_AUDIO_COMMON_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+namespace android {
+
+// Audio coefficient type.
+typedef int32_t audio_coef_t;
+// Audio sample type.
+typedef int32_t audio_sample_t;
+// Accumulator type for coef x sample.
+typedef int64_t audio_coef_sample_acc_t;
+
+// Number of fraction bits for audio coefficient.
+static const int AUDIO_COEF_PRECISION = 24;
+// Audio coefficient with the value of 1.0
+static const audio_coef_t AUDIO_COEF_ONE = 1 << AUDIO_COEF_PRECISION;
+// Audio coefficient with the value of 0.5
+static const audio_coef_t AUDIO_COEF_HALF = 1 << (AUDIO_COEF_PRECISION - 1);
+// Number of fraction bits for audio sample.
+static const int AUDIO_SAMPLE_PRECISION = 24;
+// Audio sample with the value of 1.0
+static const audio_sample_t AUDIO_SAMPLE_ONE = 1 << AUDIO_SAMPLE_PRECISION;
+
+// TODO: These are just temporary naive implementations of the necessary
+// arithmetic operations needed for the filter. They should be moved to a more
+// generic location and implemented more efficiently.
+
+// Multiply a sample by a coefficient to return an accumulator.
+inline audio_coef_sample_acc_t mul_coef_sample(audio_coef_t x, audio_sample_t y) {
+ return ((audio_coef_sample_acc_t) (x)) * y;
+}
+
+// Multiply and accumulate sample by a coefficient to return an accumulator.
+inline audio_coef_sample_acc_t mac_coef_sample(audio_coef_t x, audio_sample_t y, audio_coef_sample_acc_t acc) {
+ return acc + ((audio_coef_sample_acc_t) (x)) * y;
+}
+
+// Convert a sample-coefficient accumulator to a sample.
+inline audio_sample_t coef_sample_acc_to_sample(audio_coef_sample_acc_t acc) {
+ if (acc < 0) {
+ acc += AUDIO_COEF_ONE - 1;
+ }
+ return (audio_sample_t) (acc >> AUDIO_COEF_PRECISION);
+}
+
+// Convert a S15 sample to audio_sample_t
+inline audio_sample_t s15_to_audio_sample_t(int16_t s15) {
+ return audio_sample_t(s15) << 9;
+}
+
+// Convert a audio_sample_t sample to S15 (no clipping)
+inline int16_t audio_sample_t_to_s15(audio_sample_t sample) {
+ return int16_t((sample + (1 << 8)) >> 9);
+}
+
+// Convert a audio_sample_t sample to S15 (with clipping)
+inline int16_t audio_sample_t_to_s15_clip(audio_sample_t sample) {
+ // TODO: optimize for targets supporting this as an atomic operation.
+ if (__builtin_expect(sample >= (0x7FFF << 9), 0)) {
+ return 0x7FFF;
+ } else if (__builtin_expect(sample <= -(0x8000 << 9), 0)) {
+ return 0x8000;
+ } else {
+ return audio_sample_t_to_s15(sample);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+}
+
+#endif // ANDROID_AUDIO_COMMON_H
diff --git a/media/libeffects/testlibs/AudioEqualizer.cpp b/media/libeffects/testlibs/AudioEqualizer.cpp
new file mode 100644
index 0000000..44c9476
--- /dev/null
+++ b/media/libeffects/testlibs/AudioEqualizer.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright 2009, 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.
+ */
+
+#define LOG_TAG "AudioEqualizer"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <new>
+#include <utils/Log.h>
+
+#include "AudioEqualizer.h"
+#include "AudioPeakingFilter.h"
+#include "AudioShelvingFilter.h"
+#include "EffectsMath.h"
+
+namespace android {
+
+size_t AudioEqualizer::GetInstanceSize(int nBands) {
+ assert(nBands >= 2);
+ return sizeof(AudioEqualizer) +
+ sizeof(AudioShelvingFilter) * 2 +
+ sizeof(AudioPeakingFilter) * (nBands - 2);
+}
+
+AudioEqualizer * AudioEqualizer::CreateInstance(void * pMem, int nBands,
+ int nChannels, int sampleRate,
+ const PresetConfig * presets,
+ int nPresets) {
+ LOGV("AudioEqualizer::CreateInstance(pMem=%p, nBands=%d, nChannels=%d, "
+ "sampleRate=%d, nPresets=%d)",
+ pMem, nBands, nChannels, sampleRate, nPresets);
+ assert(nBands >= 2);
+ bool ownMem = false;
+ if (pMem == NULL) {
+ pMem = malloc(GetInstanceSize(nBands));
+ if (pMem == NULL) {
+ return NULL;
+ }
+ ownMem = true;
+ }
+ return new (pMem) AudioEqualizer(pMem, nBands, nChannels, sampleRate,
+ ownMem, presets, nPresets);
+}
+
+void AudioEqualizer::configure(int nChannels, int sampleRate) {
+ LOGV("AudioEqualizer::configure(nChannels=%d, sampleRate=%d)", nChannels,
+ sampleRate);
+ mpLowShelf->configure(nChannels, sampleRate);
+ for (int i = 0; i < mNumPeaking; ++i) {
+ mpPeakingFilters[i].configure(nChannels, sampleRate);
+ }
+ mpHighShelf->configure(nChannels, sampleRate);
+}
+
+void AudioEqualizer::clear() {
+ LOGV("AudioEqualizer::clear()");
+ mpLowShelf->clear();
+ for (int i = 0; i < mNumPeaking; ++i) {
+ mpPeakingFilters[i].clear();
+ }
+ mpHighShelf->clear();
+}
+
+void AudioEqualizer::free() {
+ LOGV("AudioEqualizer::free()");
+ if (mpMem != NULL) {
+ ::free(mpMem);
+ }
+}
+
+void AudioEqualizer::reset() {
+ LOGV("AudioEqualizer::reset()");
+ const int32_t bottom = Effects_log2(kMinFreq);
+ const int32_t top = Effects_log2(mSampleRate * 500);
+ const int32_t jump = (top - bottom) / (mNumPeaking + 2);
+ int32_t centerFreq = bottom + jump/2;
+
+ mpLowShelf->reset();
+ mpLowShelf->setFrequency(Effects_exp2(centerFreq));
+ centerFreq += jump;
+ for (int i = 0; i < mNumPeaking; ++i) {
+ mpPeakingFilters[i].reset();
+ mpPeakingFilters[i].setFrequency(Effects_exp2(centerFreq));
+ centerFreq += jump;
+ }
+ mpHighShelf->reset();
+ mpHighShelf->setFrequency(Effects_exp2(centerFreq));
+ commit(true);
+ mCurPreset = PRESET_CUSTOM;
+}
+
+void AudioEqualizer::setGain(int band, int32_t millibel) {
+ LOGV("AudioEqualizer::setGain(band=%d, millibel=%d)", band, millibel);
+ assert(band >= 0 && band < mNumPeaking + 2);
+ if (band == 0) {
+ mpLowShelf->setGain(millibel);
+ } else if (band == mNumPeaking + 1) {
+ mpHighShelf->setGain(millibel);
+ } else {
+ mpPeakingFilters[band - 1].setGain(millibel);
+ }
+ mCurPreset = PRESET_CUSTOM;
+}
+
+void AudioEqualizer::setFrequency(int band, uint32_t millihertz) {
+ LOGV("AudioEqualizer::setFrequency(band=%d, millihertz=%d)", band,
+ millihertz);
+ assert(band >= 0 && band < mNumPeaking + 2);
+ if (band == 0) {
+ mpLowShelf->setFrequency(millihertz);
+ } else if (band == mNumPeaking + 1) {
+ mpHighShelf->setFrequency(millihertz);
+ } else {
+ mpPeakingFilters[band - 1].setFrequency(millihertz);
+ }
+ mCurPreset = PRESET_CUSTOM;
+}
+
+void AudioEqualizer::setBandwidth(int band, uint32_t cents) {
+ LOGV("AudioEqualizer::setBandwidth(band=%d, cents=%d)", band, cents);
+ assert(band >= 0 && band < mNumPeaking + 2);
+ if (band > 0 && band < mNumPeaking + 1) {
+ mpPeakingFilters[band - 1].setBandwidth(cents);
+ mCurPreset = PRESET_CUSTOM;
+ }
+}
+
+int32_t AudioEqualizer::getGain(int band) const {
+ assert(band >= 0 && band < mNumPeaking + 2);
+ if (band == 0) {
+ return mpLowShelf->getGain();
+ } else if (band == mNumPeaking + 1) {
+ return mpHighShelf->getGain();
+ } else {
+ return mpPeakingFilters[band - 1].getGain();
+ }
+}
+
+uint32_t AudioEqualizer::getFrequency(int band) const {
+ assert(band >= 0 && band < mNumPeaking + 2);
+ if (band == 0) {
+ return mpLowShelf->getFrequency();
+ } else if (band == mNumPeaking + 1) {
+ return mpHighShelf->getFrequency();
+ } else {
+ return mpPeakingFilters[band - 1].getFrequency();
+ }
+}
+
+uint32_t AudioEqualizer::getBandwidth(int band) const {
+ assert(band >= 0 && band < mNumPeaking + 2);
+ if (band == 0 || band == mNumPeaking + 1) {
+ return 0;
+ } else {
+ return mpPeakingFilters[band - 1].getBandwidth();
+ }
+}
+
+void AudioEqualizer::getBandRange(int band, uint32_t & low,
+ uint32_t & high) const {
+ assert(band >= 0 && band < mNumPeaking + 2);
+ if (band == 0) {
+ low = 0;
+ high = mpLowShelf->getFrequency();
+ } else if (band == mNumPeaking + 1) {
+ low = mpHighShelf->getFrequency();
+ high = mSampleRate * 500;
+ } else {
+ mpPeakingFilters[band - 1].getBandRange(low, high);
+ }
+}
+
+const char * AudioEqualizer::getPresetName(int preset) const {
+ assert(preset < mNumPresets && preset >= PRESET_CUSTOM);
+ if (preset == PRESET_CUSTOM) {
+ return "Custom";
+ } else {
+ return mpPresets[preset].name;
+ }
+}
+
+int AudioEqualizer::getNumPresets() const {
+ return mNumPresets;
+}
+
+int AudioEqualizer::getPreset() const {
+ return mCurPreset;
+}
+
+void AudioEqualizer::setPreset(int preset) {
+ LOGV("AudioEqualizer::setPreset(preset=%d)", preset);
+ assert(preset < mNumPresets && preset >= 0);
+ const PresetConfig &presetCfg = mpPresets[preset];
+ for (int band = 0; band < (mNumPeaking + 2); ++band) {
+ const BandConfig & bandCfg = presetCfg.bandConfigs[band];
+ setGain(band, bandCfg.gain);
+ setFrequency(band, bandCfg.freq);
+ setBandwidth(band, bandCfg.bandwidth);
+ }
+ mCurPreset = preset;
+}
+
+void AudioEqualizer::commit(bool immediate) {
+ LOGV("AudioEqualizer::commit(immediate=%d)", immediate);
+ mpLowShelf->commit(immediate);
+ for (int i = 0; i < mNumPeaking; ++i) {
+ mpPeakingFilters[i].commit(immediate);
+ }
+ mpHighShelf->commit(immediate);
+}
+
+void AudioEqualizer::process(const audio_sample_t * pIn,
+ audio_sample_t * pOut,
+ int frameCount) {
+// LOGV("AudioEqualizer::process(frameCount=%d)", frameCount);
+ mpLowShelf->process(pIn, pOut, frameCount);
+ for (int i = 0; i < mNumPeaking; ++i) {
+ mpPeakingFilters[i].process(pIn, pOut, frameCount);
+ }
+ mpHighShelf->process(pIn, pOut, frameCount);
+}
+
+void AudioEqualizer::enable(bool immediate) {
+ LOGV("AudioEqualizer::enable(immediate=%d)", immediate);
+ mpLowShelf->enable(immediate);
+ for (int i = 0; i < mNumPeaking; ++i) {
+ mpPeakingFilters[i].enable(immediate);
+ }
+ mpHighShelf->enable(immediate);
+}
+
+void AudioEqualizer::disable(bool immediate) {
+ LOGV("AudioEqualizer::disable(immediate=%d)", immediate);
+ mpLowShelf->disable(immediate);
+ for (int i = 0; i < mNumPeaking; ++i) {
+ mpPeakingFilters[i].disable(immediate);
+ }
+ mpHighShelf->disable(immediate);
+}
+
+int AudioEqualizer::getMostRelevantBand(uint32_t targetFreq) const {
+ // First, find the two bands that the target frequency is between.
+ uint32_t low = mpLowShelf->getFrequency();
+ if (targetFreq <= low) {
+ return 0;
+ }
+ uint32_t high = mpHighShelf->getFrequency();
+ if (targetFreq >= high) {
+ return mNumPeaking + 1;
+ }
+ int band = mNumPeaking;
+ for (int i = 0; i < mNumPeaking; ++i) {
+ uint32_t freq = mpPeakingFilters[i].getFrequency();
+ if (freq >= targetFreq) {
+ high = freq;
+ band = i;
+ break;
+ }
+ low = freq;
+ }
+ // Now, low is right below the target and high is right above. See which one
+ // is closer on a log scale.
+ low = Effects_log2(low);
+ high = Effects_log2(high);
+ targetFreq = Effects_log2(targetFreq);
+ if (high - targetFreq < targetFreq - low) {
+ return band + 1;
+ } else {
+ return band;
+ }
+}
+
+
+AudioEqualizer::AudioEqualizer(void * pMem, int nBands, int nChannels,
+ int sampleRate, bool ownMem,
+ const PresetConfig * presets, int nPresets)
+ : mSampleRate(sampleRate)
+ , mpPresets(presets)
+ , mNumPresets(nPresets) {
+ assert(pMem != NULL);
+ assert(nPresets == 0 || nPresets > 0 && presets != NULL);
+ mpMem = ownMem ? pMem : NULL;
+
+ pMem = (char *) pMem + sizeof(AudioEqualizer);
+ mpLowShelf = new (pMem) AudioShelvingFilter(AudioShelvingFilter::kLowShelf,
+ nChannels, sampleRate);
+ pMem = (char *) pMem + sizeof(AudioShelvingFilter);
+ mpHighShelf = new (pMem) AudioShelvingFilter(AudioShelvingFilter::kHighShelf,
+ nChannels, sampleRate);
+ pMem = (char *) pMem + sizeof(AudioShelvingFilter);
+ mNumPeaking = nBands - 2;
+ if (mNumPeaking > 0) {
+ mpPeakingFilters = reinterpret_cast<AudioPeakingFilter *>(pMem);
+ for (int i = 0; i < mNumPeaking; ++i) {
+ new (&mpPeakingFilters[i]) AudioPeakingFilter(nChannels,
+ sampleRate);
+ }
+ }
+ reset();
+}
+
+}
diff --git a/media/libeffects/testlibs/AudioEqualizer.h b/media/libeffects/testlibs/AudioEqualizer.h
new file mode 100644
index 0000000..4028462
--- /dev/null
+++ b/media/libeffects/testlibs/AudioEqualizer.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2009, 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 AUDIOEQUALIZER_H_
+#define AUDIOEQUALIZER_H_
+
+#include "AudioCommon.h"
+
+namespace android {
+
+class AudioShelvingFilter;
+class AudioPeakingFilter;
+
+// A parametric audio equalizer. Supports an arbitrary number of bands and
+// presets.
+// The EQ is composed of a low-shelf, zero or more peaking filters and a high
+// shelf, where each band has frequency and gain controls, and the peaking
+// filters have an additional bandwidth control.
+class AudioEqualizer {
+public:
+ // Configuration of a single band.
+ struct BandConfig {
+ // Gain in millibel.
+ int32_t gain;
+ // Frequency in millihertz.
+ uint32_t freq;
+ // Bandwidth in cents (ignored on shelving filters).
+ uint32_t bandwidth;
+ };
+
+ // Preset configuration.
+ struct PresetConfig {
+ // Human-readable name.
+ const char * name;
+ // An array of size nBands where each element is a configuration for the
+ // corresponding band.
+ const BandConfig * bandConfigs;
+ };
+
+ // This value is used when requesting current preset, and EQ is not using a
+ // preset.
+ static const int PRESET_CUSTOM = -1;
+
+ // Get the required memory size for an instance of this class.
+ // nBands Number of bands required in the instance.
+ static size_t GetInstanceSize(int nBands);
+
+ // Create an instance of this class.
+ // If succeeds, a respective call is expected to freeInstance(), regardless
+ // of who owns the context memory.
+ // pMem A memory buffer of at least the size returned by
+ // GetInstanceSize(), where the instance context is to be
+ // stored. If NULL, it will be automatically allocated (using
+ // malloc).
+ // nBands Number of bands. Must be >= 2.
+ // nChannels Number of input/output channels (interlaced).
+ // sampleRate The input/output sample rate, in Hz.
+ // presets The presets configuration. May be NULL, but in that case the
+ // client is required not to call preset-related functions.
+ // This array is owned by the client and is not copied. It
+ // must be kept valid by the client as long as the instance is
+ // alive.
+ // nPresets Number of elements in the presets array.
+ // returns The instance if success. NULL if pMem is NULL and allocation
+ // failed.
+ static AudioEqualizer * CreateInstance(void * pMem, int nBands,
+ int nChannels,
+ int sampleRate,
+ const PresetConfig * presets,
+ int nPresets);
+
+ // Reconfiguration of the filter. Changes input/output format, but does not
+ // alter current parameter values. Causes reset of the delay lines.
+ // nChannels Number of input/output channels (interlaced).
+ // sampleRate The input/output sample rate, in Hz.
+ void configure(int nChannels, int sampleRate);
+
+ // Resets the filter parameters to the following values:
+ // frequency: 0
+ // gain: 0
+ // bandwidth: 1200 cents.
+ // It also disables the filter. Does not clear the delay lines.
+ void reset();
+
+ // Clears delay lines. Does not alter parameter values.
+ void clear();
+
+ // Frees the object. Will free the memory if the object owned it, i.e. if
+ // a NULL pointer was passed to CreateInstance as pMem.
+ void free();
+
+ // Sets gain value. Actual change will only take place upon commit().
+ // This value will be remembered even if the filter is in disabled() state.
+ // band The band to set the gain for.
+ // millibel Gain value in millibel (1/100 of decibel).
+ void setGain(int band, int32_t millibel);
+
+ // Gets gain of a certain band. This is always the last value set (or
+ // default value after reset).
+ // band The band to get the gain for.
+ // returns Gain value in millibel (1/100 of decibel).
+ int32_t getGain(int band) const;
+
+ // Sets cutoff frequency value. Actual change will only take place upon
+ // commit().
+ // This value will be remembered even if the filter is in disabled() state.
+ // band The band to set the frequency for.
+ // millihertz Frequency value in mHz.
+ void setFrequency(int band, uint32_t millihertz);
+
+ // Gets frequency of a certain band. This is always the last value set (or
+ // default value after reset).
+ // band The band to get the frequency for.
+ // returns Frequency value in mHz.
+ uint32_t getFrequency(int band) const;
+
+ // Sets bandwidth value. Actual change will only take place upon commit().
+ // This value will be remembered even if the filter is in disabled() state.
+ // If called on the first or last band, this call is ignored.
+ // band The band to set the frequency for.
+ // cents Bandwidth value in cents (1/1200 octave).
+ void setBandwidth(int band, uint32_t cents);
+
+ // Gets bandwidth of a certain band. This is always the last value set (or
+ // default value after reset). For the first and last bands, 0 is always
+ // returned.
+ // band The band to get the bandwidth for.
+ // returns Bandwidth value in cents (1/1200 octave).
+ uint32_t getBandwidth(int band) const;
+
+ // Gets lower and upper boundaries of a band.
+ // For the low shelf, the low bound is 0 and the high bound is the band
+ // frequency.
+ // For the high shelf, the low bound is the band frequency and the high
+ // bound is Nyquist.
+ // For the peaking filters, they are the gain[dB]/2 points.
+ void getBandRange(int band, uint32_t & low, uint32_t & high) const;
+
+ // Gets a human-readable name for a preset ID. Will return "Custom" if
+ // PRESET_CUSTOM is passed.
+ // preset The preset ID. Must be less than number of presets.
+ const char * getPresetName(int preset) const;
+
+ // Gets the number of presets.
+ int getNumPresets() const;
+
+ // Gets the currently set preset ID.
+ // Will return PRESET_CUSTOM in case the EQ parameters have been modified
+ // manually since a preset was set.
+ int getPreset() const;
+
+ // Sets the current preset by ID.
+ // All the band parameters will be overridden.
+ // Change will not be applied until commit() is called.
+ // preset The preset ID. Must be less than number of presets.
+ // PRESET_CUSTOM is NOT a valid value here.
+ void setPreset(int preset);
+
+ // Applies all parameter changes done to this point in time.
+ // If the filter is disabled, the new parameters will take place when it is
+ // enabled again. Does not introduce artifacts, unless immediate is set.
+ // immediate Whether to apply change abruptly (ignored if filter is
+ // disabled).
+ void commit(bool immediate = false);
+
+ // Process a buffer of input data. The input and output should contain
+ // frameCount * nChannels interlaced samples. Processing can be done
+ // in-place, by passing the same buffer as both arguments.
+ // pIn Input buffer.
+ // pOut Output buffer.
+ // frameCount Number of frames to produce on each call to process().
+ void process(const audio_sample_t * pIn, audio_sample_t * pOut,
+ int frameCount);
+
+ // Enables the filter, so it would start processing input. Does not
+ // introduce artifacts, unless immediate is set.
+ // immediate Whether to apply change abruptly.
+ void enable(bool immediate = false);
+
+ // Disabled (bypasses) the filter. Does not introduce artifacts, unless
+ // immediate is set.
+ // immediate Whether to apply change abruptly.
+ void disable(bool immediate = false);
+
+ // Returns the band with the maximum influence on a given frequency.
+ // Result is unaffected by whether EQ is enabled or not, or by whether
+ // changes have been committed or not.
+ // targetFreq The target frequency, in millihertz.
+ int getMostRelevantBand(uint32_t targetFreq) const;
+
+private:
+ // Bottom frequency, in mHz.
+ static const int kMinFreq = 20000;
+ // Sample rate, in Hz.
+ int mSampleRate;
+ // Number of peaking filters. Total number of bands is +2.
+ int mNumPeaking;
+ // Preset configurations.
+ const PresetConfig * mpPresets;
+ // Number of elements in mpPresets;
+ int mNumPresets;
+ // Current preset.
+ int mCurPreset;
+
+ // Memory space to free when instance is deleted, or NULL if no memory is
+ // owned.
+ void * mpMem;
+ // The low-shelving filter.
+ AudioShelvingFilter * mpLowShelf;
+ // The high-shelving filter.
+ AudioShelvingFilter * mpHighShelf;
+ // An array of size mNumPeaking of peaking filters.
+ AudioPeakingFilter * mpPeakingFilters;
+
+ // Constructor. Resets the filter (see reset()). Must call init() doing
+ // anything else.
+ // pMem Memory buffer for bands.
+ // nChannels Number of input/output channels (interlaced).
+ // sampleRate The input/output sample rate, in Hz.
+ // ownMem Whether pMem is owned by me.
+ // presets The presets configuration. May be NULL, but in that case the
+ // client is required not to call preset-related functions.
+ // This array is owned by the client and is not copied. It
+ // must be kept valid by the client as long as the instance is
+ // alive.
+ // nPresets Number of elements in the presets array.
+ AudioEqualizer(void * pMem, int nBands, int nChannels, int sampleRate,
+ bool ownMem, const PresetConfig * presets, int nPresets);
+};
+
+}
+
+#endif // AUDIOEQUALIZER_H_
diff --git a/media/libeffects/testlibs/AudioFormatAdapter.h b/media/libeffects/testlibs/AudioFormatAdapter.h
new file mode 100644
index 0000000..d93ebe9
--- /dev/null
+++ b/media/libeffects/testlibs/AudioFormatAdapter.h
@@ -0,0 +1,184 @@
+/* /android/src/frameworks/base/media/libeffects/AudioFormatAdapter.h
+**
+** Copyright 2009, 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 AUDIOFORMATADAPTER_H_
+#define AUDIOFORMATADAPTER_H_
+
+#include <media/EffectApi.h>
+
+
+#define min(x,y) (((x) < (y)) ? (x) : (y))
+
+namespace android {
+
+// An adapter for an audio processor working on audio_sample_t samples with a
+// buffer override behavior to arbitrary sample formats and buffer behaviors.
+// The adapter may work on any processing class which has a processing function
+// with the following signature:
+// void process(const audio_sample_t * pIn,
+// audio_sample_t * pOut,
+// int frameCount);
+// It is assumed that the underlying processor works in S7.24 format and an
+// overwrite behavior.
+//
+// Usage is simple: just work with the processor normally, but instead of
+// calling its process() function directly, work with the process() function of
+// the adapter.
+// The adapter supports re-configuration to a different format on the fly.
+//
+// T The processor class.
+// bufSize The maximum number of samples (single channel) to process on a
+// single call to the underlying processor. Setting this to a small
+// number will save a little memory, but will cost function call
+// overhead, resulting from multiple calls to the underlying process()
+// per a single call to this class's process().
+template<class T, size_t bufSize>
+class AudioFormatAdapter {
+public:
+ // Configure the adapter.
+ // processor The underlying audio processor.
+ // nChannels Number of input and output channels. The adapter does not do
+ // channel conversion - this parameter must be in sync with the
+ // actual processor.
+ // pcmFormat The desired input/output sample format.
+ // behavior The desired behavior (overwrite or accumulate).
+ void configure(T & processor, int nChannels, uint8_t pcmFormat,
+ uint32_t behavior) {
+ mpProcessor = &processor;
+ mNumChannels = nChannels;
+ mPcmFormat = pcmFormat;
+ mBehavior = behavior;
+ mMaxSamplesPerCall = bufSize / nChannels;
+ }
+
+ // Process a block of samples.
+ // pIn A buffer of samples with the format specified on
+ // configure().
+ // pOut A buffer of samples with the format specified on
+ // configure(). May be the same as pIn.
+ // numSamples The number of multi-channel samples to process.
+ void process(const void * pIn, void * pOut, uint32_t numSamples) {
+ while (numSamples > 0) {
+ uint32_t numSamplesIter = min(numSamples, mMaxSamplesPerCall);
+ uint32_t nSamplesChannels = numSamplesIter * mNumChannels;
+ if (mPcmFormat == SAMPLE_FORMAT_PCM_S7_24) {
+ if (mBehavior == EFFECT_BUFFER_ACCESS_WRITE) {
+ mpProcessor->process(
+ reinterpret_cast<const audio_sample_t *> (pIn),
+ reinterpret_cast<audio_sample_t *> (pOut),
+ numSamplesIter);
+ } else if (mBehavior == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ mpProcessor->process(
+ reinterpret_cast<const audio_sample_t *> (pIn),
+ mBuffer, numSamplesIter);
+ MixOutput(pOut, numSamplesIter);
+ } else {
+ assert(false);
+ }
+ pIn = reinterpret_cast<const audio_sample_t *> (pIn)
+ + nSamplesChannels;
+ pOut = reinterpret_cast<audio_sample_t *> (pOut)
+ + nSamplesChannels;
+ } else {
+ ConvertInput(pIn, nSamplesChannels);
+ mpProcessor->process(mBuffer, mBuffer, numSamplesIter);
+ ConvertOutput(pOut, nSamplesChannels);
+ }
+ numSamples -= numSamplesIter;
+ }
+ }
+
+private:
+ // The underlying processor.
+ T * mpProcessor;
+ // The number of input/output channels.
+ int mNumChannels;
+ // The desired PCM format.
+ uint8_t mPcmFormat;
+ // The desired buffer behavior.
+ uint32_t mBehavior;
+ // An intermediate buffer for processing.
+ audio_sample_t mBuffer[bufSize];
+ // The buffer size, divided by the number of channels - represents the
+ // maximum number of multi-channel samples that can be stored in the
+ // intermediate buffer.
+ size_t mMaxSamplesPerCall;
+
+ // Converts a buffer of input samples to audio_sample_t format.
+ // Output is written to the intermediate buffer.
+ // pIn The input buffer with the format designated in configure().
+ // When function exist will point to the next unread input
+ // sample.
+ // numSamples The number of single-channel samples to process.
+ void ConvertInput(const void *& pIn, uint32_t numSamples) {
+ if (mPcmFormat == SAMPLE_FORMAT_PCM_S15) {
+ const int16_t * pIn16 = reinterpret_cast<const int16_t *>(pIn);
+ audio_sample_t * pOut = mBuffer;
+ while (numSamples-- > 0) {
+ *(pOut++) = s15_to_audio_sample_t(*(pIn16++));
+ }
+ pIn = pIn16;
+ } else {
+ assert(false);
+ }
+ }
+
+ // Converts audio_sample_t samples from the intermediate buffer to the
+ // output buffer, converting to the desired format and buffer behavior.
+ // pOut The buffer to write the output to.
+ // When function exist will point to the next output sample.
+ // numSamples The number of single-channel samples to process.
+ void ConvertOutput(void *& pOut, uint32_t numSamples) {
+ if (mPcmFormat == SAMPLE_FORMAT_PCM_S15) {
+ const audio_sample_t * pIn = mBuffer;
+ int16_t * pOut16 = reinterpret_cast<int16_t *>(pOut);
+ if (mBehavior == EFFECT_BUFFER_ACCESS_WRITE) {
+ while (numSamples-- > 0) {
+ *(pOut16++) = audio_sample_t_to_s15_clip(*(pIn++));
+ }
+ } else if (mBehavior == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ while (numSamples-- > 0) {
+ *(pOut16++) += audio_sample_t_to_s15_clip(*(pIn++));
+ }
+ } else {
+ assert(false);
+ }
+ pOut = pOut16;
+ } else {
+ assert(false);
+ }
+ }
+
+ // Accumulate data from the intermediate buffer to the output. Output is
+ // assumed to be of audio_sample_t type.
+ // pOut The buffer to mix the output to.
+ // When function exist will point to the next output sample.
+ // numSamples The number of single-channel samples to process.
+ void MixOutput(void *& pOut, uint32_t numSamples) {
+ const audio_sample_t * pIn = mBuffer;
+ audio_sample_t * pOut24 = reinterpret_cast<audio_sample_t *>(pOut);
+ numSamples *= mNumChannels;
+ while (numSamples-- > 0) {
+ *(pOut24++) += *(pIn++);
+ }
+ pOut = pOut24;
+ }
+};
+
+}
+
+#endif // AUDIOFORMATADAPTER_H_
diff --git a/media/libeffects/testlibs/AudioHighShelfFilterCoef.inl b/media/libeffects/testlibs/AudioHighShelfFilterCoef.inl
new file mode 100644
index 0000000..ebba139
--- /dev/null
+++ b/media/libeffects/testlibs/AudioHighShelfFilterCoef.inl
@@ -0,0 +1,225 @@
+13679,
+21575,
+8921,
+32315056,
+-15582015,
+26172,
+37678,
+14797,
+31891096,
+-15192527,
+51020,
+64449,
+23945,
+31322988,
+-14685186,
+101817,
+106144,
+37744,
+30562882,
+-14031372,
+208996,
+162163,
+58536,
+29548538,
+-13201017,
+442996,
+207459,
+93300,
+28200792,
+-12167331,
+971423,
+128786,
+169690,
+26422744,
+-10915428,
+2200461,
+-465686,
+394986,
+24103317,
+-9455862,
+5119991,
+-2777199,
+1147245,
+21129473,
+-7842294,
+12120379,
+-10198160,
+3631544,
+17411837,
+-6188384,
+28834234,
+-31647135,
+11337795,
+12924960,
+-4672638,
+68037766,
+-88974388,
+33477255,
+7752680,
+-3516098,
+157369944,
+-232063160,
+92282129,
+2113926,
+-2925624,
+353720112,
+-567427144,
+237164112,
+-3659993,
+-3019871,
+769091151,
+-1309871949,
+570539430,
+-9202114,
+-3779302,
+66791,
+121706,
+55888,
+30571245,
+-14038415,
+120426,
+212178,
+94820,
+29559679,
+-13209886,
+217130,
+365165,
+157610,
+28215554,
+-12178243,
+391489,
+617016,
+255010,
+26442131,
+-10928431,
+705862,
+1015147,
+398457,
+24128430,
+-9470680,
+1272682,
+1605251,
+596102,
+21161334,
+-7858153,
+2294668,
+2386833,
+848523,
+17451072,
+-6203880,
+4137327,
+3198789,
+1155536,
+12971362,
+-4685798,
+7459675,
+3470266,
+1567219,
+7804818,
+-3524761,
+13449926,
+1738911,
+2347406,
+2169089,
+-2928116,
+24250455,
+-5211241,
+4358971,
+-3605298,
+-3015671,
+43724001,
+-23849570,
+9823315,
+-9151253,
+-3769277,
+78835150,
+-66542375,
+23686373,
+-14161143,
+-5040790,
+142141173,
+-156324261,
+56024234,
+-18451275,
+-6612656,
+256283057,
+-335606326,
+126341244,
+-21970004,
+-8270755,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
+16777216,
+33554432,
+16777216,
+-33554432,
+-16777216,
diff --git a/media/libeffects/testlibs/AudioLowShelfFilterCoef.inl b/media/libeffects/testlibs/AudioLowShelfFilterCoef.inl
new file mode 100644
index 0000000..b57deb4
--- /dev/null
+++ b/media/libeffects/testlibs/AudioLowShelfFilterCoef.inl
@@ -0,0 +1,375 @@
+16212506,
+-32420574,
+16208068,
+32401411,
+-15662521,
+16356129,
+-32706246,
+16350118,
+32695525,
+-15939752,
+16464399,
+-32920670,
+16456274,
+32914686,
+-16149441,
+16546128,
+-33081289,
+16535165,
+33077955,
+-16307411,
+16608101,
+-33201422,
+16593328,
+33199569,
+-16426067,
+16655539,
+-33291174,
+16635647,
+33290147,
+-16514997,
+16692478,
+-33358171,
+16665715,
+33357608,
+-16581540,
+16722089,
+-33408149,
+16686099,
+33407850,
+-16631271,
+16746930,
+-33445409,
+16698549,
+33445267,
+-16668405,
+16769156,
+-33473168,
+16704138,
+33473133,
+-16696114,
+16790706,
+-33493827,
+16703348,
+33493886,
+-16716779,
+16813466,
+-33509166,
+16696111,
+33509342,
+-16732186,
+16839437,
+-33520498,
+16681802,
+33520852,
+-16743669,
+16870911,
+-33528765,
+16659191,
+33529424,
+-16752226,
+16910681,
+-33534607,
+16626337,
+33535807,
+-16758602,
+15667401,
+-31326224,
+15658825,
+31252161,
+-14623074,
+15945865,
+-31880007,
+15934146,
+31838205,
+-15144597,
+16157521,
+-32299091,
+16141578,
+32275604,
+-15545369,
+16318267,
+-32614903,
+16296651,
+32601755,
+-15850850,
+16440710,
+-32852157,
+16411473,
+32844820,
+-16082303,
+16534751,
+-33029985,
+16495281,
+33025910,
+-16256891,
+16608171,
+-33163043,
+16554957,
+33160803,
+-16388152,
+16667145,
+-33262468,
+16595477,
+33261275,
+-16486599,
+16716699,
+-33336671,
+16620252,
+33336105,
+-16560301,
+16761100,
+-33391976,
+16631379,
+33391836,
+-16615404,
+16804207,
+-33433103,
+16629806,
+33433341,
+-16656560,
+16849794,
+-33463551,
+16615399,
+33464251,
+-16687277,
+16901887,
+-33485857,
+16586933,
+33487271,
+-16710189,
+16965125,
+-33501781,
+16542000,
+33504415,
+-16727274,
+17045198,
+-33512384,
+16476824,
+33517183,
+-16740008,
+14635201,
+-29254376,
+14619184,
+28977711,
+-12753834,
+15157556,
+-30292825,
+15135285,
+30133938,
+-13674513,
+15561511,
+-31092298,
+15530817,
+31001860,
+-14405551,
+15872211,
+-31702342,
+15830187,
+31651218,
+-14976306,
+16111094,
+-32164834,
+16053843,
+32136101,
+-15416453,
+16295848,
+-32513802,
+16218140,
+32497757,
+-15752817,
+16440852,
+-32776179,
+16335665,
+32767326,
+-16008155,
+16557804,
+-32972907,
+16415715,
+32968179,
+-16201031,
+16656403,
+-33120052,
+16464758,
+33117802,
+-16346195,
+16745001,
+-33229805,
+16486810,
+33229247,
+-16455153,
+16831240,
+-33311306,
+16483692,
+33312252,
+-16536771,
+16922682,
+-33371278,
+16455145,
+33374070,
+-16597819,
+17027472,
+-33414465,
+16398818,
+33420110,
+-16643430,
+17155108,
+-33443875,
+16310110,
+33454398,
+-16677479,
+17317384,
+-33460760,
+16181887,
+33479933,
+-16702882,
+12792703,
+-25557388,
+12764716,
+24590507,
+-9747085,
+13706465,
+-27372621,
+13666215,
+26798296,
+-11169790,
+14439425,
+-28821830,
+14382518,
+28486469,
+-12380088,
+15018453,
+-29957273,
+14939030,
+29764018,
+-13373522,
+15472460,
+-30834757,
+15362688,
+30724568,
+-14168120,
+15828725,
+-31506123,
+15678118,
+31443928,
+-14791822,
+16111406,
+-32015988,
+15905901,
+31981391,
+-15274688,
+16341329,
+-32400984,
+16062061,
+32382398,
+-15644761,
+16536484,
+-32690238,
+16158133,
+32681354,
+-15926286,
+16712853,
+-32906337,
+16201432,
+32904128,
+-16139278,
+16885430,
+-33066336,
+16195306,
+33070090,
+-16299767,
+17069377,
+-33182599,
+16139282,
+33193711,
+-16420332,
+17281371,
+-33263294,
+16029039,
+33285785,
+-16510702,
+17541271,
+-33312390,
+15856243,
+33354359,
+-16578329,
+17874330,
+-33328902,
+15608287,
+33405430,
+-16628873,
+9881279,
+-19719268,
+9838084,
+16734303,
+-5927111,
+11264857,
+-22463447,
+11198784,
+20577584,
+-7572288,
+12460736,
+-24823046,
+12362697,
+23667359,
+-9201903,
+13459805,
+-26776851,
+13317799,
+26085683,
+-10691555,
+14276287,
+-28349256,
+14074406,
+27943899,
+-11978834,
+14936943,
+-29588248,
+14654011,
+29354533,
+-13047453,
+15473300,
+-30549299,
+15081036,
+30417203,
+-13909216,
+15917271,
+-31285788,
+15377817,
+31213972,
+-14589687,
+16299384,
+-31844320,
+15562006,
+31809683,
+-15118811,
+16648774,
+-32262999,
+15645414,
+32254329,
+-15525641,
+16994277,
+-32571090,
+15633607,
+32585895,
+-15835862,
+17366374,
+-32789019,
+15525801,
+32833003,
+-16070975,
+17799955,
+-32927834,
+15314895,
+33017107,
+-16248361,
+18338206,
+-32987318,
+14987686,
+33154246,
+-16381747,
+19038270,
+-32951545,
+14525592,
+33256392,
+-16481800,
diff --git a/media/libeffects/testlibs/AudioPeakingFilter.cpp b/media/libeffects/testlibs/AudioPeakingFilter.cpp
new file mode 100644
index 0000000..60fefe6
--- /dev/null
+++ b/media/libeffects/testlibs/AudioPeakingFilter.cpp
@@ -0,0 +1,121 @@
+/* //device/include/server/AudioFlinger/AudioPeakingFilter.cpp
+ **
+ ** Copyright 2007, 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 "AudioPeakingFilter.h"
+#include "AudioCommon.h"
+#include "EffectsMath.h"
+
+#include <new>
+#include <assert.h>
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+// Format of the coefficient table:
+// kCoefTable[freq][gain][bw][coef]
+// freq - peak frequency, in octaves below Nyquist,from -9 to -1.
+// gain - gain, in millibel, starting at -9600, jumps of 1024, to 4736 millibel.
+// bw - bandwidth, starting at 1 cent, jumps of 1024, to 3073 cents.
+// coef - 0: b0
+// 1: b1
+// 2: b2
+// 3: -a1
+// 4: -a2
+static const size_t kInDims[3] = {9, 15, 4};
+static const audio_coef_t kCoefTable[9*15*4*5] = {
+#include "AudioPeakingFilterCoef.inl"
+};
+
+AudioCoefInterpolator AudioPeakingFilter::mCoefInterp(3, kInDims, 5, (const audio_coef_t*) kCoefTable);
+
+AudioPeakingFilter::AudioPeakingFilter(int nChannels, int sampleRate)
+ : mBiquad(nChannels, sampleRate) {
+ configure(nChannels, sampleRate);
+ reset();
+}
+
+void AudioPeakingFilter::configure(int nChannels, int sampleRate) {
+ mNiquistFreq = sampleRate * 500;
+ mFrequencyFactor = ((1ull) << 42) / mNiquistFreq;
+ mBiquad.configure(nChannels, sampleRate);
+ setFrequency(mNominalFrequency);
+ commit(true);
+}
+
+void AudioPeakingFilter::reset() {
+ setGain(0);
+ setFrequency(0);
+ setBandwidth(2400);
+ commit(true);
+}
+
+void AudioPeakingFilter::setFrequency(uint32_t millihertz) {
+ mNominalFrequency = millihertz;
+ if (UNLIKELY(millihertz > mNiquistFreq / 2)) {
+ millihertz = mNiquistFreq / 2;
+ }
+ uint32_t normFreq = static_cast<uint32_t>(
+ (static_cast<uint64_t>(millihertz) * mFrequencyFactor) >> 10);
+ if (LIKELY(normFreq > (1 << 23))) {
+ mFrequency = (Effects_log2(normFreq) - ((32-9) << 15)) << (FREQ_PRECISION_BITS - 15);
+ } else {
+ mFrequency = 0;
+ }
+}
+
+void AudioPeakingFilter::setGain(int32_t millibel) {
+ mGain = millibel + 9600;
+}
+
+void AudioPeakingFilter::setBandwidth(uint32_t cents) {
+ mBandwidth = cents - 1;
+}
+
+void AudioPeakingFilter::commit(bool immediate) {
+ audio_coef_t coefs[5];
+ int intCoord[3] = {
+ mFrequency >> FREQ_PRECISION_BITS,
+ mGain >> GAIN_PRECISION_BITS,
+ mBandwidth >> BANDWIDTH_PRECISION_BITS
+ };
+ uint32_t fracCoord[3] = {
+ mFrequency << (32 - FREQ_PRECISION_BITS),
+ static_cast<uint32_t>(mGain) << (32 - GAIN_PRECISION_BITS),
+ mBandwidth << (32 - BANDWIDTH_PRECISION_BITS)
+ };
+ mCoefInterp.getCoef(intCoord, fracCoord, coefs);
+ mBiquad.setCoefs(coefs, immediate);
+}
+
+void AudioPeakingFilter::getBandRange(uint32_t & low, uint32_t & high) const {
+ // Half bandwidth, in octaves, 15-bit precision
+ int32_t halfBW = (((mBandwidth + 1) / 2) << 15) / 1200;
+
+ low = static_cast<uint32_t>((static_cast<uint64_t>(mNominalFrequency) * Effects_exp2(-halfBW + (16 << 15))) >> 16);
+ if (UNLIKELY(halfBW >= (16 << 15))) {
+ high = mNiquistFreq;
+ } else {
+ high = static_cast<uint32_t>((static_cast<uint64_t>(mNominalFrequency) * Effects_exp2(halfBW + (16 << 15))) >> 16);
+ if (UNLIKELY(high > mNiquistFreq)) {
+ high = mNiquistFreq;
+ }
+ }
+}
+
+}
+
diff --git a/media/libeffects/testlibs/AudioPeakingFilter.h b/media/libeffects/testlibs/AudioPeakingFilter.h
new file mode 100644
index 0000000..d0f49c9
--- /dev/null
+++ b/media/libeffects/testlibs/AudioPeakingFilter.h
@@ -0,0 +1,151 @@
+/* //device/include/server/AudioFlinger/AudioPeakingFilter.h
+**
+** Copyright 2009, 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 ANDROID_AUDIO_PEAKING_FILTER_H
+#define ANDROID_AUDIO_PEAKING_FILTER_H
+
+#include "AudioBiquadFilter.h"
+#include "AudioCoefInterpolator.h"
+
+namespace android {
+
+// A peaking audio filter, with unity skirt gain, and controllable peak
+// frequency, gain and bandwidth.
+// This filter is able to suppress introduce discontinuities and other artifacts
+// in the output, even when changing parameters abruptly.
+// Parameters can be set to any value - this class will make sure to clip them
+// when they are out of supported range.
+//
+// Implementation notes:
+// This class uses an underlying biquad filter whose parameters are determined
+// using a linear interpolation from a coefficient table, using a
+// AudioCoefInterpolator.
+// All is left for this class to do is mapping between high-level parameters to
+// fractional indices into the coefficient table.
+class AudioPeakingFilter {
+public:
+ // Constructor. Resets the filter (see reset()).
+ // nChannels Number of input/output channels (interlaced).
+ // sampleRate The input/output sample rate, in Hz.
+ AudioPeakingFilter(int nChannels, int sampleRate);
+
+ // Reconfiguration of the filter. Changes input/output format, but does not
+ // alter current parameter values. Clears delay lines.
+ // nChannels Number of input/output channels (interlaced).
+ // sampleRate The input/output sample rate, in Hz.
+ void configure(int nChannels, int sampleRate);
+
+ // Resets the filter parameters to the following values:
+ // frequency: 0
+ // gain: 0
+ // bandwidth: 1200 cents.
+ // It also disables the filter. Does not clear the delay lines.
+ void reset();
+
+ // Clears delay lines. Does not alter parameter values.
+ void clear() { mBiquad.clear(); }
+
+ // Sets gain value. Actual change will only take place upon commit().
+ // This value will be remembered even if the filter is in disabled() state.
+ // millibel Gain value in millibel (1/100 of decibel).
+ void setGain(int32_t millibel);
+
+ // Gets the gain, in millibel, as set.
+ int32_t getGain() const { return mGain - 9600; }
+
+ // Sets bandwidth value. Actual change will only take place upon commit().
+ // This value will be remembered even if the filter is in disabled() state.
+ // cents Bandwidth value in cents (1/1200 octave).
+ void setBandwidth(uint32_t cents);
+
+ // Gets the gain, in cents, as set.
+ uint32_t getBandwidth() const { return mBandwidth + 1; }
+
+ // Sets frequency value. Actual change will only take place upon commit().
+ // This value will be remembered even if the filter is in disabled() state.
+ // millihertz Frequency value in mHz.
+ void setFrequency(uint32_t millihertz);
+
+ // Gets the frequency, in mHz, as set.
+ uint32_t getFrequency() const { return mNominalFrequency; }
+
+ // Gets gain[dB]/2 points.
+ // Results in mHz, and are computed based on the nominal values set, not on
+ // possibly rounded or truncated actual values.
+ void getBandRange(uint32_t & low, uint32_t & high) const;
+
+ // Applies all parameter changes done to this point in time.
+ // If the filter is disabled, the new parameters will take place when it is
+ // enabled again. Does not introduce artifacts, unless immediate is set.
+ // immediate Whether to apply change abruptly (ignored if filter is
+ // disabled).
+ void commit(bool immediate = false);
+
+ // Process a buffer of input data. The input and output should contain
+ // frameCount * nChannels interlaced samples. Processing can be done
+ // in-place, by passing the same buffer as both arguments.
+ // in Input buffer.
+ // out Output buffer.
+ // frameCount Number of frames to produce.
+ void process(const audio_sample_t in[], audio_sample_t out[],
+ int frameCount) { mBiquad.process(in, out, frameCount); }
+
+ // Enables the filter, so it would start processing input. Does not
+ // introduce artifacts, unless immediate is set.
+ // immediate Whether to apply change abruptly.
+ void enable(bool immediate = false) { mBiquad.enable(immediate); }
+
+ // Disabled (bypasses) the filter. Does not introduce artifacts, unless
+ // immediate is set.
+ // immediate Whether to apply change abruptly.
+ void disable(bool immediate = false) { mBiquad.disable(immediate); }
+
+private:
+ // Precision for the mFrequency member.
+ static const int FREQ_PRECISION_BITS = 26;
+ // Precision for the mGain member.
+ static const int GAIN_PRECISION_BITS = 10;
+ // Precision for the mBandwidth member.
+ static const int BANDWIDTH_PRECISION_BITS = 10;
+
+ // Nyquist, in mHz.
+ uint32_t mNiquistFreq;
+ // Fractional index into the gain dimension of the coef table in
+ // GAIN_PRECISION_BITS precision.
+ int32_t mGain;
+ // Fractional index into the bandwidth dimension of the coef table in
+ // BANDWIDTH_PRECISION_BITS precision.
+ uint32_t mBandwidth;
+ // Fractional index into the frequency dimension of the coef table in
+ // FREQ_PRECISION_BITS precision.
+ uint32_t mFrequency;
+ // Nominal value of frequency, as set.
+ uint32_t mNominalFrequency;
+ // 1/Nyquist[mHz], in 42-bit precision (very small).
+ // Used for scaling the frequency.
+ uint32_t mFrequencyFactor;
+
+ // A biquad filter, used for the actual processing.
+ AudioBiquadFilter mBiquad;
+ // A coefficient interpolator, used for mapping the high level parameters to
+ // the low-level biquad coefficients.
+ static AudioCoefInterpolator mCoefInterp;
+};
+
+}
+
+#endif // ANDROID_AUDIO_PEAKING_FILTER_H
diff --git a/media/libeffects/testlibs/AudioPeakingFilterCoef.inl b/media/libeffects/testlibs/AudioPeakingFilterCoef.inl
new file mode 100644
index 0000000..374c6e1
--- /dev/null
+++ b/media/libeffects/testlibs/AudioPeakingFilterCoef.inl
@@ -0,0 +1,2700 @@
+16769751,
+-33538871,
+16769751,
+33538871,
+-16762286,
+11468083,
+-22935566,
+11467915,
+22935566,
+-6158781,
+8532673,
+-17064763,
+8532412,
+17064763,
+-287869,
+6567366,
+-13134160,
+6567042,
+13134160,
+3642808,
+16773075,
+-33545518,
+16773075,
+33545518,
+-16768934,
+13349658,
+-26698459,
+13349304,
+26698459,
+-9921746,
+10923581,
+-21846147,
+10922977,
+21846147,
+-5069342,
+9009390,
+-18017641,
+9008590,
+18017641,
+-1240764,
+16774919,
+-33549207,
+16774919,
+33549207,
+-16772622,
+14686150,
+-29371047,
+14685450,
+29371047,
+-12594384,
+12933736,
+-25865697,
+12932448,
+25865697,
+-9088968,
+11350364,
+-22698482,
+11348545,
+22698482,
+-5921693,
+16775943,
+-33551252,
+16775941,
+33551252,
+-16774668,
+15549746,
+-31097569,
+15548408,
+31097569,
+-14320938,
+14404163,
+-28805197,
+14401577,
+28805197,
+-12028524,
+13261978,
+-26519626,
+13258147,
+26519626,
+-9742909,
+16776511,
+-33552387,
+16776508,
+33552387,
+-16775803,
+16074349,
+-32145600,
+16071856,
+32145600,
+-15368989,
+15374244,
+-30742933,
+15369268,
+30742933,
+-13966296,
+14629431,
+-29250695,
+14621814,
+29250695,
+-12474030,
+16776826,
+-33553017,
+16776822,
+33553017,
+-16776432,
+16381548,
+-32757900,
+16376968,
+32757900,
+-15981300,
+15972161,
+-31934402,
+15962842,
+31934402,
+-15157787,
+15518882,
+-31022614,
+15504316,
+31022614,
+-14245982,
+16777003,
+-33553366,
+16776995,
+33553366,
+-16776781,
+16558315,
+-33107660,
+16549969,
+33107660,
+-16331067,
+16326848,
+-32635910,
+16309677,
+32635910,
+-15859308,
+16064456,
+-32101133,
+16037281,
+32101133,
+-15324521,
+16777103,
+-33553559,
+16777088,
+33553559,
+-16776975,
+16660325,
+-33304885,
+16645187,
+33304885,
+-16528296,
+16535200,
+-33038436,
+16503858,
+33038436,
+-16261842,
+16391425,
+-32732273,
+16341464,
+32732273,
+-15955673,
+16777162,
+-33553667,
+16777136,
+33553667,
+-16777082,
+16721651,
+-33415288,
+16694267,
+33415288,
+-16638701,
+16661761,
+-33265997,
+16604862,
+33265997,
+-16489407,
+16592417,
+-33093137,
+16501343,
+33093137,
+-16316544,
+16777203,
+-33553726,
+16777155,
+33553726,
+-16777142,
+16763466,
+-33476836,
+16714001,
+33476836,
+-16700251,
+16748588,
+-33393565,
+16645605,
+33393565,
+-16616978,
+16731288,
+-33296733,
+16566071,
+33296733,
+-16520144,
+16777238,
+-33553759,
+16777152,
+33553759,
+-16777175,
+16800489,
+-33511071,
+16711212,
+33511071,
+-16734485,
+16825723,
+-33464740,
+16639647,
+33464740,
+-16688154,
+16855137,
+-33410736,
+16556228,
+33410736,
+-16634149,
+16777282,
+-33553778,
+16777127,
+33553778,
+-16777193,
+16845889,
+-33530088,
+16684830,
+33530088,
+-16753503,
+16920437,
+-33504347,
+16584541,
+33504347,
+-16727762,
+17007449,
+-33474302,
+16467484,
+33474302,
+-16697716,
+16777349,
+-33553788,
+16777070,
+33553788,
+-16777203,
+16915880,
+-33540645,
+16625396,
+33540645,
+-16764060,
+17066504,
+-33526354,
+16460481,
+33526354,
+-16749769,
+17242444,
+-33509662,
+16267849,
+33509662,
+-16733077,
+16777464,
+-33553793,
+16776961,
+33553793,
+-16777209,
+17035487,
+-33546503,
+16511647,
+33546503,
+-16769918,
+17316137,
+-33538572,
+16223067,
+33538572,
+-16761988,
+17644089,
+-33529306,
+15885848,
+33529306,
+-16752721,
+16777668,
+-33553796,
+16776760,
+33553796,
+-16777212,
+17247484,
+-33549752,
+16302900,
+33549752,
+-16773168,
+17758603,
+-33545353,
+15787381,
+33545353,
+-16768768,
+18356007,
+-33540211,
+15184835,
+33540211,
+-16763626,
+16762293,
+-33522062,
+16762293,
+33522062,
+-16747370,
+8711405,
+-17421242,
+8711149,
+17421242,
+-645338,
+5721250,
+-11441288,
+5720900,
+11441288,
+5335066,
+4082836,
+-8164655,
+4082434,
+8164655,
+8611946,
+16768936,
+-33535347,
+16768936,
+33535347,
+-16760656,
+11085056,
+-22167856,
+11084469,
+22167856,
+-5392309,
+8098223,
+-16194333,
+8097329,
+16194333,
+581664,
+6158323,
+-12314623,
+6157228,
+12314623,
+4461665,
+16772623,
+-33542719,
+16772622,
+33542719,
+-16768029,
+13058634,
+-26114055,
+13057388,
+26114055,
+-9338806,
+10523211,
+-21042742,
+10521116,
+21042742,
+-4267110,
+8576560,
+-17149081,
+8573812,
+17149081,
+-373156,
+16774670,
+-33546810,
+16774667,
+33546810,
+-16772120,
+14489725,
+-28974776,
+14487233,
+28974776,
+-12199742,
+12619509,
+-25232587,
+12614979,
+25232587,
+-8457271,
+10965151,
+-21922319,
+10958818,
+21922319,
+-5146753,
+16775805,
+-33549079,
+16775800,
+33549079,
+-16774390,
+15428102,
+-30849095,
+15423317,
+30849095,
+-14074202,
+14188157,
+-28364996,
+14178975,
+28364996,
+-11589916,
+12969900,
+-25924346,
+12956398,
+25924346,
+-9149082,
+16776437,
+-33550338,
+16776428,
+33550338,
+-16775648,
+16004216,
+-31997074,
+15995268,
+31997074,
+-15222267,
+15241233,
+-30462393,
+15223454,
+30462393,
+-13687471,
+14437070,
+-28844880,
+14409982,
+28844880,
+-12069836,
+16776789,
+-33551036,
+16776773,
+33551036,
+-16776347,
+16345158,
+-32671383,
+16328685,
+32671383,
+-15896627,
+15900462,
+-31765104,
+15867034,
+31765104,
+-14990280,
+15410846,
+-30767279,
+15358750,
+30767279,
+-13992380,
+16776990,
+-33551423,
+16776960,
+33551423,
+-16776734,
+16545156,
+-33057769,
+16515103,
+33057769,
+-16283043,
+16300504,
+-32536823,
+16238769,
+32536823,
+-15762058,
+16024071,
+-31948201,
+15926537,
+31948201,
+-15173391,
+16777109,
+-33551638,
+16777056,
+33551638,
+-16776949,
+16666542,
+-33276035,
+16611999,
+33276035,
+-16501325,
+16548270,
+-32981225,
+16435439,
+32981225,
+-16206493,
+16412621,
+-32643103,
+16232940,
+32643103,
+-15868346,
+16777189,
+-33551757,
+16777094,
+33551757,
+-16777068,
+16749778,
+-33398338,
+16651075,
+33398338,
+-16623637,
+16720233,
+-33232976,
+16515245,
+33232976,
+-16458262,
+16686059,
+-33041706,
+16358135,
+33041706,
+-16266978,
+16777261,
+-33551823,
+16777089,
+33551823,
+-16777134,
+16823703,
+-33466559,
+16645376,
+33466559,
+-16691863,
+16873974,
+-33374267,
+16502806,
+33374267,
+-16599564,
+16932398,
+-33267006,
+16337114,
+33267006,
+-16492295,
+16777348,
+-33551860,
+16777038,
+33551860,
+-16777170,
+16914465,
+-33504517,
+16592574,
+33504517,
+-16729824,
+17063236,
+-33453150,
+16392432,
+33453150,
+-16678453,
+17236595,
+-33393293,
+16159213,
+33393293,
+-16618592,
+16777483,
+-33551880,
+16776924,
+33551880,
+-16777191,
+17054436,
+-33525606,
+16473695,
+33525606,
+-16750914,
+17355321,
+-33497061,
+16144262,
+33497061,
+-16722367,
+17706453,
+-33463749,
+15759816,
+33463749,
+-16689053,
+16777713,
+-33551891,
+16776705,
+33551891,
+-16777202,
+17293646,
+-33537314,
+16246194,
+33537314,
+-16762623,
+17854571,
+-33521465,
+15669419,
+33521465,
+-16746773,
+18509706,
+-33502954,
+14995772,
+33502954,
+-16728261,
+16778120,
+-33551898,
+16776304,
+33551898,
+-16777208,
+17717639,
+-33543811,
+15828698,
+33543811,
+-16769121,
+18739501,
+-33535016,
+14798040,
+33535016,
+-16760325,
+19933534,
+-33524738,
+13593729,
+33524738,
+-16750047,
+16747397,
+-33484705,
+16747396,
+33484705,
+-16717577,
+5883112,
+-11762335,
+5882767,
+11762335,
+5011337,
+3448701,
+-6894903,
+3448279,
+6894903,
+9880236,
+2324286,
+-4646714,
+2323828,
+4646714,
+12129102,
+16760665,
+-33511232,
+16760663,
+33511232,
+-16744112,
+8276984,
+-16548106,
+8276108,
+16548106,
+224124,
+5337400,
+-10670406,
+5336221,
+10670406,
+6103596,
+3771525,
+-7539439,
+3770185,
+7539439,
+9235506,
+16768033,
+-33525963,
+16768030,
+33525963,
+-16758848,
+10689564,
+-21370649,
+10687524,
+21370649,
+-4599872,
+7666068,
+-15324466,
+7663015,
+15324466,
+1448133,
+5761266,
+-11515371,
+5757575,
+11515371,
+5258376,
+16772124,
+-33534139,
+16772118,
+33534139,
+-16767026,
+12751423,
+-25490780,
+12747036,
+25490780,
+-8721243,
+10113942,
+-20214533,
+10106682,
+20214533,
+-3443407,
+8145025,
+-16275741,
+8135620,
+16275741,
+496571,
+16774395,
+-33538675,
+16774385,
+33538675,
+-16771564,
+14280137,
+-28542819,
+14271281,
+28542819,
+-11774202,
+12292391,
+-24561476,
+12276485,
+24561476,
+-7791660,
+10572949,
+-21117532,
+10550945,
+21117532,
+-4346678,
+16775657,
+-33541192,
+16775639,
+33541192,
+-16774081,
+15299683,
+-30573051,
+15282579,
+30573051,
+-13805046,
+13964251,
+-27887539,
+13931690,
+27887539,
+-11118724,
+12672686,
+-25290241,
+12625174,
+25290241,
+-8520644,
+16776363,
+-33542588,
+16776330,
+33542588,
+-16775477,
+15935196,
+-31828699,
+15903092,
+31828699,
+-15061072,
+15112356,
+-30152153,
+15048881,
+30152153,
+-13384021,
+14253857,
+-28402950,
+14157649,
+28402950,
+-11634291,
+16776763,
+-33543362,
+16776704,
+33543362,
+-16776252,
+16319830,
+-32570615,
+16260598,
+32570615,
+-15803212,
+15851783,
+-31574208,
+15731938,
+31574208,
+-14806505,
+15339614,
+-30483871,
+15153441,
+30483871,
+-13715838,
+16777001,
+-33543791,
+16776896,
+33543791,
+-16776681,
+16557673,
+-32997208,
+16449476,
+32997208,
+-16229933,
+16326977,
+-32422299,
+16105089,
+32422299,
+-15654851,
+16067244,
+-31775024,
+15717353,
+31775024,
+-15007381,
+16777163,
+-33544029,
+16776972,
+33544029,
+-16776919,
+16722590,
+-33238660,
+16526083,
+33238660,
+-16471458,
+16664322,
+-32912610,
+16258203,
+32912610,
+-16145310,
+16597629,
+-32539419,
+15951593,
+32539419,
+-15772007,
+16777306,
+-33544162,
+16776962,
+33544162,
+-16777051,
+16869955,
+-33374105,
+16514205,
+33374105,
+-16606944,
+16969714,
+-33190996,
+16231282,
+33190996,
+-16423780,
+17084972,
+-32979442,
+15904406,
+32979442,
+-16212162,
+16777480,
+-33544235,
+16776860,
+33544235,
+-16777125,
+17051328,
+-33449703,
+16408452,
+33449703,
+-16682565,
+17347583,
+-33347437,
+16009901,
+33347437,
+-16580267,
+17691668,
+-33228659,
+15547002,
+33228659,
+-16461454,
+16777750,
+-33544275,
+16776632,
+33544275,
+-16777165,
+17331222,
+-33491780,
+16170648,
+33491780,
+-16724654,
+17931550,
+-33434840,
+15513363,
+33434840,
+-16667697,
+18630855,
+-33368512,
+14747710,
+33368512,
+-16601349,
+16778210,
+-33544298,
+16776194,
+33544298,
+-16777188,
+17809628,
+-33515162,
+15715631,
+33515162,
+-16748043,
+18929991,
+-33483514,
+14563611,
+33483514,
+-16716385,
+20237212,
+-33446587,
+13219451,
+33446587,
+-16679448,
+16779025,
+-33544310,
+16775392,
+33544310,
+-16777200,
+18657612,
+-33528145,
+14880634,
+33528145,
+-16761030,
+20699844,
+-33510571,
+12820822,
+33510571,
+-16743451,
+23084863,
+-33490047,
+10415274,
+33490047,
+-16722921,
+16717684,
+-33395091,
+16717682,
+33395091,
+-16658149,
+3567009,
+-7125006,
+3566590,
+7125006,
+9643617,
+1921926,
+-3838751,
+1921455,
+3838751,
+12933835,
+1248662,
+-2493824,
+1248170,
+2493824,
+14280384,
+16744147,
+-33447952,
+16744143,
+33447952,
+-16711074,
+5493785,
+-10973174,
+5492622,
+10973174,
+5790808,
+3173694,
+-6338342,
+3172292,
+6338342,
+10431230,
+2124754,
+-4242881,
+2123244,
+4242881,
+12529218,
+16758861,
+-33477342,
+16758855,
+33477342,
+-16740500,
+7843885,
+-15665884,
+7840892,
+15665884,
+1092439,
+4968649,
+-9921376,
+4964692,
+9921376,
+6843875,
+3478437,
+-6944043,
+3473981,
+6944043,
+9824798,
+16767035,
+-33493665,
+16767024,
+33493665,
+-16756842,
+10284421,
+-20536999,
+10277346,
+20536999,
+-3784550,
+7240254,
+-14452686,
+7229862,
+14452686,
+2307100,
+5379798,
+-10734231,
+5367379,
+10734231,
+6030039,
+16771575,
+-33502725,
+16771555,
+33502725,
+-16765913,
+12431046,
+-24816749,
+12415632,
+24816749,
+-8069462,
+9702049,
+-19355664,
+9676957,
+19355664,
+-2601790,
+7722611,
+-15394544,
+7690499,
+15394544,
+1364106,
+16774099,
+-33507752,
+16774063,
+33507752,
+-16770946,
+14062583,
+-28059903,
+14031160,
+28059903,
+-11316527,
+11962999,
+-23841519,
+11907273,
+23841519,
+-7093056,
+10188929,
+-20277142,
+10112667,
+20277142,
+-3524380,
+16775510,
+-33510541,
+16775445,
+33510541,
+-16773738,
+15175102,
+-30252637,
+15114019,
+30252637,
+-13511905,
+13753207,
+-27358123,
+13637911,
+27358123,
+-10613901,
+12400971,
+-24605416,
+12234119,
+24605416,
+-7857874,
+16776310,
+-33512088,
+16776193,
+33512088,
+-16775287,
+15888242,
+-31623221,
+15773117,
+31623221,
+-14884143,
+15028972,
+-29795608,
+14802570,
+29795608,
+-13054325,
+14142237,
+-27909578,
+13801000,
+27909578,
+-11166021,
+16776787,
+-33512946,
+16776575,
+33512946,
+-16776146,
+16345172,
+-32438302,
+16132251,
+32438302,
+-15700207,
+15905856,
+-31344484,
+15476429,
+31344484,
+-14605069,
+15428324,
+-30155514,
+14763558,
+30155514,
+-13414665,
+16777110,
+-33513422,
+16776729,
+33513422,
+-16776623,
+16668950,
+-32908744,
+16279482,
+32908744,
+-16171216,
+16555594,
+-32275015,
+15758344,
+32275015,
+-15536722,
+16428465,
+-31564284,
+15173886,
+31564284,
+-14825134,
+16777395,
+-33513686,
+16776708,
+33513686,
+-16776887,
+16961758,
+-33175594,
+16253845,
+33175594,
+-16438387,
+17158212,
+-32815329,
+15696692,
+32815329,
+-16077688,
+17382578,
+-32403880,
+15060381,
+32403880,
+-15665743,
+16777745,
+-33513832,
+16776505,
+33513832,
+-16777033,
+17323903,
+-33325470,
+16041757,
+33325470,
+-16588444,
+17911332,
+-33122874,
+15251488,
+33122874,
+-16385604,
+18589203,
+-32889086,
+14339546,
+32889086,
+-16151534,
+16778283,
+-33513913,
+16776048,
+33513913,
+-16777115,
+17883505,
+-33409180,
+15565966,
+33409180,
+-16672255,
+19078451,
+-33295944,
+14257648,
+33295944,
+-16558883,
+20465440,
+-33164510,
+12739067,
+33164510,
+-16427290,
+16779203,
+-33513958,
+16775173,
+33513958,
+-16777160,
+18840265,
+-33455789,
+14655871,
+33455789,
+-16718921,
+21075121,
+-33392715,
+12357866,
+33392715,
+-16655771,
+23677621,
+-33319266,
+9681828,
+33319266,
+-16582233,
+16780834,
+-33513983,
+16773567,
+33513983,
+-16777185,
+20536227,
+-33481696,
+12985848,
+33481696,
+-16744859,
+24614855,
+-33446630,
+8872112,
+33446630,
+-16709751,
+29373075,
+-33405721,
+4072934,
+33405721,
+-16668793,
+16658572,
+-33156710,
+16658568,
+33156710,
+-16539925,
+1995694,
+-3971702,
+1995225,
+3971702,
+12786296,
+1019334,
+-2028355,
+1018835,
+2028355,
+14739047,
+648397,
+-1290041,
+647886,
+1290041,
+15480933,
+16711208,
+-33261470,
+16711201,
+33261470,
+-16645192,
+3284873,
+-6536727,
+3283483,
+6536727,
+10208860,
+1752746,
+-3487071,
+1751198,
+3487071,
+13273272,
+1134254,
+-2255981,
+1132642,
+2255981,
+14510319,
+16740546,
+-33319859,
+16740534,
+33319859,
+-16703864,
+5119019,
+-10184853,
+5115113,
+10184853,
+6543083,
+2916766,
+-5800820,
+2912122,
+5800820,
+10948329,
+1940950,
+-3858260,
+1935979,
+3858260,
+12900288,
+16756866,
+-33352332,
+16756844,
+33352332,
+-16736493,
+7416141,
+-14750709,
+7405941,
+14750709,
+1955134,
+4618132,
+-9178604,
+4604884,
+9178604,
+7554200,
+3205731,
+-6365873,
+3190944,
+6365873,
+10380541,
+16765937,
+-33370369,
+16765897,
+33370369,
+-16754618,
+9875714,
+-19631961,
+9851238,
+19631961,
+-2949736,
+6828874,
+-13556870,
+6793592,
+13556870,
+3154751,
+5021920,
+-9953987,
+4980230,
+9953987,
+6775066,
+16770983,
+-33380381,
+16770911,
+33380381,
+-16764679,
+12107731,
+-24045066,
+12053679,
+24045066,
+-7384194,
+9304697,
+-18433704,
+9218200,
+18433704,
+-1745681,
+7330173,
+-14480925,
+7220819,
+14480925,
+2226224,
+16773804,
+-33385937,
+16773674,
+33385937,
+-16770261,
+13857067,
+-27469883,
+13745731,
+27469883,
+-10825583,
+11667230,
+-23028209,
+11472403,
+23028209,
+-6362417,
+9861509,
+-19365642,
+9597835,
+19365642,
+-2682128,
+16775405,
+-33389019,
+16775170,
+33389019,
+-16773358,
+15094166,
+-29826057,
+14876207,
+29826057,
+-13193157,
+13629575,
+-26722225,
+13221948,
+26722225,
+-10074307,
+12261304,
+-23822520,
+11676482,
+23822520,
+-7160571,
+16776358,
+-33390729,
+16775935,
+33390729,
+-16775076,
+15939973,
+-31315809,
+15527360,
+31315809,
+-14690117,
+15140254,
+-29331850,
+14333520,
+29331850,
+-12696558,
+14324552,
+-27308240,
+13115821,
+27308240,
+-10663157,
+16777004,
+-33391677,
+16776241,
+33391677,
+-16776029,
+16564519,
+-32208051,
+15799374,
+32208051,
+-15586676,
+16349720,
+-31011538,
+14811870,
+31011538,
+-14384374,
+16117884,
+-29720119,
+13746038,
+29720119,
+-13086705,
+16777574,
+-33392203,
+16776199,
+33392203,
+-16776558,
+17142623,
+-32725183,
+15740903,
+32725183,
+-16106310,
+17523746,
+-32028793,
+14660021,
+32028793,
+-15406551,
+17949452,
+-31250941,
+13452699,
+31250941,
+-14624935,
+16778273,
+-33392495,
+16775794,
+33392495,
+-16776851,
+17864511,
+-33019221,
+15314476,
+33019221,
+-16401771,
+19019582,
+-32622294,
+13760557,
+32622294,
+-16002923,
+20335886,
+-32169961,
+11989731,
+32169961,
+-15548401,
+16779350,
+-33392657,
+16774879,
+33392657,
+-16777014,
+18982972,
+-33184592,
+14362186,
+33184592,
+-16567942,
+21350554,
+-32961046,
+11769976,
+32961046,
+-16343314,
+24079688,
+-32703362,
+8781912,
+32703362,
+-16084383,
+16781190,
+-33392746,
+16773130,
+33392746,
+-16777104,
+20896303,
+-33277026,
+12541737,
+33277026,
+-16660824,
+25343199,
+-33151977,
+7969185,
+33151977,
+-16535169,
+30502384,
+-33006896,
+2664219,
+33006896,
+-16389387,
+16784451,
+-33392796,
+16769918,
+33392796,
+-16777154,
+24288258,
+-33328516,
+9201520,
+33328516,
+-16712562,
+32423187,
+-33258828,
+996567,
+33258828,
+-16642538,
+41895320,
+-33177686,
+-8557101,
+33177686,
+-16561003,
+16541595,
+-32447498,
+16541587,
+32447498,
+-16305966,
+1060925,
+-2080590,
+1060426,
+2080590,
+14655865,
+525478,
+-1030256,
+524962,
+1030256,
+15726776,
+330321,
+-647437,
+329800,
+647437,
+16117095,
+16645717,
+-32651734,
+16645703,
+32651734,
+-16514203,
+1820789,
+-3570095,
+1819248,
+3570095,
+13137179,
+924575,
+-1812018,
+922942,
+1812018,
+14929699,
+586684,
+-1149186,
+585016,
+1149186,
+15605516,
+16704036,
+-32766121,
+16704011,
+32766121,
+-16630831,
+3020875,
+-5921138,
+3016266,
+5921138,
+10740076,
+1597573,
+-3128764,
+1592487,
+3128764,
+13587156,
+1030124,
+-2015487,
+1024848,
+2015487,
+14722244,
+16736565,
+-32829909,
+16736521,
+32829909,
+-16695869,
+4762013,
+-9328185,
+4748922,
+9328185,
+7266281,
+2679566,
+-5241091,
+2664205,
+5241091,
+11433446,
+1773912,
+-3463620,
+1757564,
+3463620,
+13245740,
+16754673,
+-32865395,
+16754593,
+32865395,
+-16732050,
+7001772,
+-13700468,
+6967104,
+13700468,
+2808340,
+4293363,
+-8378312,
+4249089,
+8378312,
+8234764,
+2960061,
+-5758307,
+2911058,
+5758307,
+10906097,
+16764756,
+-32885110,
+16764611,
+32885110,
+-16752151,
+9480188,
+-18513215,
+9395722,
+18513215,
+-2098694,
+6453693,
+-12542171,
+6334194,
+12542171,
+3989330,
+4710641,
+-9103264,
+4570966,
+9103264,
+7495609,
+16770393,
+-32896054,
+16770133,
+32896054,
+-16763310,
+11816276,
+-22992949,
+11627131,
+22992949,
+-6666191,
+8975726,
+-17314789,
+8678280,
+17314789,
+-876790,
+7032408,
+-13430164,
+6660869,
+13430164,
+3083940,
+16773593,
+-32902127,
+16773124,
+32902127,
+-16769502,
+13735615,
+-26557052,
+13341720,
+26557052,
+-10300120,
+11528165,
+-21946606,
+10848400,
+21946606,
+-5599349,
+9752563,
+-18238110,
+8842853,
+18238110,
+-1818200,
+16775499,
+-32905496,
+16774654,
+32905496,
+-16772937,
+15200588,
+-29054957,
+14423589,
+29054957,
+-12846961,
+13857004,
+-25769995,
+12417855,
+25769995,
+-9497643,
+12624453,
+-22756500,
+10577873,
+22756500,
+-6425111,
+16776792,
+-32907365,
+16775267,
+32907365,
+-16774843,
+16366344,
+-30654089,
+14888294,
+30654089,
+-14477422,
+15978753,
+-28526295,
+13106406,
+28526295,
+-12307942,
+15588057,
+-26381456,
+11310242,
+26381456,
+-10121083,
+16777933,
+-32908402,
+16775183,
+32908402,
+-16775900,
+17493802,
+-31619287,
+14744943,
+31619287,
+-15461529,
+18212414,
+-30325234,
+12706927,
+30325234,
+-14142124,
+18982725,
+-28938081,
+10522286,
+28938081,
+-12727795,
+16779330,
+-32908977,
+16774372,
+32908977,
+-16776486,
+18928041,
+-32181280,
+13883707,
+32181280,
+-16034532,
+21163118,
+-31424334,
+10876855,
+31424334,
+-15262757,
+23650871,
+-30581814,
+7530076,
+30581814,
+-14403731,
+16781484,
+-32909296,
+16772543,
+32909296,
+-16776811,
+21161996,
+-32501674,
+11976424,
+32501674,
+-16361204,
+25812009,
+-32068975,
+6885234,
+32068975,
+-15920027,
+31103385,
+-31576594,
+1091831,
+31576594,
+-15418000,
+16785164,
+-32909473,
+16769043,
+32909473,
+-16776991,
+24988064,
+-32682139,
+8334356,
+32682139,
+-16545204,
+33795794,
+-32438043,
+-722252,
+32438043,
+-16296325,
+43946128,
+-32156738,
+-11159403,
+32156738,
+-16009510,
+16791687,
+-32909571,
+16762620,
+32909571,
+-16777091,
+31772521,
+-32783096,
+1652834,
+32783096,
+-16648139,
+47961229,
+-32646423,
+-14675225,
+32646423,
+-16508788,
+66751682,
+-32487785,
+-33627423,
+32487785,
+-16347043,
+16312500,
+-30141556,
+16312485,
+30141556,
+-15847769,
+547598,
+-1011354,
+547084,
+1011354,
+15682534,
+266448,
+-491849,
+265925,
+491849,
+16244843,
+166111,
+-306446,
+165584,
+306446,
+16445521,
+16516262,
+-30518049,
+16516236,
+30518049,
+-16255282,
+962487,
+-1776938,
+960857,
+1776938,
+14853872,
+474742,
+-875656,
+473062,
+875656,
+15829413,
+297520,
+-548176,
+295821,
+548176,
+16183875,
+16631492,
+-30730944,
+16631443,
+30730944,
+-16485719,
+1660146,
+-3062870,
+1655081,
+3062870,
+13461989,
+838172,
+-1543806,
+832831,
+1543806,
+15106213,
+530135,
+-974532,
+524691,
+974532,
+15722390,
+16696110,
+-30850307,
+16696022,
+30850307,
+-16614916,
+2776642,
+-5116472,
+2761387,
+5116472,
+11239187,
+1456845,
+-2676477,
+1440152,
+2676477,
+13880219,
+936151,
+-1713835,
+918891,
+1713835,
+14922174,
+16732191,
+-30916910,
+16732031,
+30916910,
+-16687006,
+4430219,
+-8145523,
+4386431,
+8145523,
+7960566,
+2467715,
+-4512857,
+2416966,
+4512857,
+11892535,
+1628113,
+-2958725,
+1574387,
+2958725,
+13574716,
+16752314,
+-30953973,
+16752025,
+30953973,
+-16727123,
+6622193,
+-12127616,
+6504644,
+12127616,
+3650379,
+4016541,
+-7285135,
+3868831,
+7285135,
+8891843,
+2762675,
+-4954883,
+2600451,
+4954883,
+11414089,
+16763575,
+-30974568,
+16763055,
+30974568,
+-16749415,
+9150431,
+-16639142,
+8859646,
+16639142,
+-1232861,
+6182181,
+-11049974,
+5778225,
+11049974,
+4816810,
+4518629,
+-7917532,
+4051247,
+7917532,
+8207341,
+16769973,
+-30986002,
+16769034,
+30986002,
+-16761791,
+11676269,
+-20964630,
+11015683,
+20964630,
+-5914736,
+8893418,
+-15489638,
+7872446,
+15489638,
+11352,
+7041383,
+-11845939,
+5780568,
+11845939,
+3955265,
+16773783,
+-30992347,
+16772092,
+30992347,
+-16768659,
+13953280,
+-24496534,
+12561577,
+24496534,
+-9737641,
+11970921,
+-19931025,
+9602265,
+19931025,
+-4795970,
+10413172,
+-16343421,
+7276820,
+16343421,
+-912775,
+16776368,
+-30995868,
+16773318,
+30995868,
+-16772470,
+16007790,
+-27021343,
+13239901,
+27021343,
+-12470475,
+15365527,
+-23700024,
+10287194,
+23700024,
+-8875505,
+14785947,
+-20702857,
+7622664,
+20702857,
+-5631395,
+16778650,
+-30997821,
+16773150,
+30997821,
+-16774583,
+18157056,
+-28659649,
+12863925,
+28659649,
+-14243764,
+19443806,
+-26476950,
+9214638,
+26476950,
+-11881228,
+20728681,
+-24297433,
+5570671,
+24297433,
+-9522136,
+16781445,
+-30998904,
+16771527,
+30998904,
+-16775756,
+20988060,
+-29656921,
+11112361,
+29656921,
+-15323204,
+25187743,
+-28317150,
+5462520,
+28317150,
+-13873047,
+29672124,
+-26886556,
+-570326,
+26886556,
+-12324582,
+16785752,
+-30999505,
+16767870,
+30999505,
+-16776406,
+25444300,
+-30240545,
+7287830,
+30240545,
+-15954914,
+34434980,
+-29452472,
+-2555854,
+29452472,
+-15101910,
+44441242,
+-28575379,
+-13511474,
+28575379,
+-14152552,
+16793112,
+-30999838,
+16760871,
+30999838,
+-16776767,
+33095506,
+-30574250,
+-2177,
+30574250,
+-16316113,
+50408034,
+-30122291,
+-17803902,
+30122291,
+-15826917,
+70153765,
+-29606811,
+-38107583,
+29606811,
+-15268966,
+16806158,
+-31000023,
+16748025,
+31000023,
+-16776967,
+46670155,
+-30762526,
+-13373037,
+30762526,
+-16519902,
+78789544,
+-30507092,
+-45768905,
+30507092,
+-16243423,
+115942747,
+-30211627,
+-83241918,
+30211627,
+-15923613,
+15872835,
+-22447559,
+15872807,
+22447559,
+-14968426,
+277754,
+-392434,
+277231,
+392434,
+16222231,
+133061,
+-187804,
+132533,
+187804,
+16511622,
+81763,
+-115256,
+81233,
+115256,
+16614220,
+16263303,
+-22999746,
+16263250,
+22999746,
+-15749337,
+494605,
+-698290,
+492927,
+698290,
+15789685,
+238776,
+-336475,
+237071,
+336475,
+16301369,
+147228,
+-207000,
+145514,
+207000,
+16484473,
+16488278,
+-23317877,
+16488181,
+23317877,
+-16199242,
+872378,
+-1229961,
+867049,
+1229961,
+15037788,
+426889,
+-599839,
+421411,
+599839,
+15928916,
+264840,
+-370629,
+259308,
+370629,
+16253068,
+16615785,
+-23498145,
+16615609,
+23498145,
+-16454179,
+1513757,
+-2129016,
+1497126,
+2129016,
+13766333,
+758261,
+-1060001,
+740806,
+1060001,
+15278149,
+475551,
+-659971,
+457789,
+659971,
+15843875,
+16687407,
+-23599332,
+16687089,
+23599332,
+-16597280,
+2557116,
+-3580647,
+2506684,
+3580647,
+11713416,
+1332007,
+-1845009,
+1277230,
+1845009,
+14167979,
+851272,
+-1163942,
+794791,
+1163942,
+15131154,
+16727486,
+-23655830,
+16726910,
+23655830,
+-16677180,
+4144749,
+-5758163,
+3998523,
+5758163,
+8633944,
+2297803,
+-3131069,
+2130198,
+3131069,
+12349216,
+1516025,
+-2019070,
+1339371,
+2019070,
+13921820,
+16749957,
+-23687282,
+16748918,
+23687282,
+-16721660,
+6342807,
+-8688774,
+5944975,
+8688774,
+4489434,
+3855722,
+-5104454,
+3363066,
+5104454,
+9558428,
+2678286,
+-3407564,
+2140738,
+3407564,
+11958192,
+16762736,
+-23704762,
+16760861,
+23704762,
+-16746380,
+9059948,
+-12106014,
+8060542,
+12106014,
+-343274,
+6231959,
+-7847669,
+4866322,
+7847669,
+5678936,
+4678573,
+-5508603,
+3111768,
+5508603,
+8986875,
+16770353,
+-23714468,
+16766970,
+23714468,
+-16760107,
+12100768,
+-15483427,
+9796104,
+15483427,
+-5119656,
+9659401,
+-11180047,
+6151573,
+11180047,
+966242,
+8066003,
+-8371376,
+3772911,
+8371376,
+4938302,
+16775520,
+-23719855,
+16769420,
+23719855,
+-16767725,
+15410647,
+-18317794,
+10494626,
+18317794,
+-9128056,
+14477439,
+-14624233,
+6204350,
+14624233,
+-3904573,
+13754127,
+-11761419,
+2879032,
+11761419,
+144058,
+16780083,
+-23722844,
+16769084,
+23722844,
+-16771951,
+19348947,
+-20387735,
+9483664,
+20387735,
+-12055395,
+21467038,
+-17637855,
+3476656,
+17637855,
+-8166478,
+23369301,
+-15168181,
+-1918253,
+15168181,
+-4673832,
+16785673,
+-23724501,
+16765839,
+23724501,
+-16774296,
+24868547,
+-21750945,
+5891934,
+21750945,
+-13983265,
+32392543,
+-19913847,
+-4230110,
+19913847,
+-11385217,
+39938641,
+-18071353,
+-14381888,
+18071353,
+-8779537,
+16794288,
+-23725421,
+16758525,
+23725421,
+-16775596,
+33739025,
+-22588636,
+-1793870,
+22588636,
+-15167940,
+50727371,
+-21448926,
+-20394010,
+21448926,
+-13556146,
+69082218,
+-20217540,
+-40490298,
+20217540,
+-11814703,
+16809008,
+-23725931,
+16744526,
+23725931,
+-16776318,
+49053594,
+-23081666,
+-16411189,
+23081666,
+-15865189,
+82824296,
+-22406908,
+-51136143,
+22406908,
+-14910937,
+121049915,
+-21643138,
+-90441895,
+21643138,
+-13830803,
+16835099,
+-23726214,
+16718835,
+23726214,
+-16776718,
+76261468,
+-23364505,
+-43219068,
+23364505,
+-16265184,
+140080603,
+-22976059,
+-107587549,
+22976059,
+-15715838,
+214348557,
+-22524014,
+-182494791,
+22524014,
+-15076550,
+15060971,
+0,
+15060916,
+0,
+-13344671,
+137715,
+0,
+137188,
+0,
+16502313,
+62494,
+0,
+61964,
+0,
+16652757,
+35499,
+0,
+34969,
+0,
+16706748,
+15779939,
+0,
+15779837,
+0,
+-14782560,
+247059,
+0,
+245356,
+0,
+16284801,
+112726,
+0,
+111009,
+0,
+16553481,
+64282,
+0,
+62560,
+0,
+16650375,
+16209124,
+0,
+16208934,
+0,
+-15640842,
+441483,
+0,
+436010,
+0,
+15899723,
+203401,
+0,
+197848,
+0,
+16375967,
+116794,
+0,
+111212,
+0,
+16549211,
+16457433,
+0,
+16457085,
+0,
+-16137302,
+783510,
+0,
+766083,
+0,
+15227623,
+367229,
+0,
+349349,
+0,
+16060638,
+213457,
+0,
+195409,
+0,
+16368349,
+16598556,
+0,
+16597923,
+0,
+-16419263,
+1374332,
+0,
+1319705,
+0,
+14083179,
+663683,
+0,
+606536,
+0,
+15506996,
+394077,
+0,
+335974,
+0,
+16047166,
+16678051,
+0,
+16676903,
+0,
+-16577738,
+2365010,
+0,
+2198183,
+0,
+12214023,
+1201479,
+0,
+1021183,
+0,
+14554554,
+739666,
+0,
+554025,
+0,
+15483525,
+16722789,
+0,
+16720714,
+0,
+-16666287,
+3953214,
+0,
+3464275,
+0,
+9359728,
+2180807,
+0,
+1624291,
+0,
+12972118,
+1423936,
+0,
+838564,
+0,
+14514716,
+16748282,
+0,
+16744535,
+0,
+-16715601,
+6353786,
+0,
+5003926,
+0,
+5419504,
+3973108,
+0,
+2314944,
+0,
+10489165,
+2837511,
+0,
+1032284,
+0,
+12907421,
+16763496,
+0,
+16756735,
+0,
+-16743015,
+9775978,
+0,
+6325602,
+0,
+675636,
+7269959,
+0,
+2584558,
+0,
+6922698,
+5878520,
+0,
+507384,
+0,
+10391313,
+16773826,
+0,
+16761629,
+0,
+-16758239,
+14526462,
+0,
+6429723,
+0,
+-4178968,
+13351086,
+0,
+1026117,
+0,
+2400012,
+12566846,
+0,
+-2579306,
+0,
+6789676,
+16782950,
+0,
+16760954,
+0,
+-16766688,
+21346996,
+0,
+3817102,
+0,
+-8386881,
+24548257,
+0,
+-5261828,
+0,
+-2509212,
+27136746,
+0,
+-12602908,
+0,
+2243378,
+16794129,
+0,
+16754463,
+0,
+-16771376,
+31942756,
+0,
+-3625011,
+0,
+-11540529,
+45048673,
+0,
+-21256423,
+0,
+-7015034,
+57646140,
+0,
+-38203817,
+0,
+-2665107,
+16811358,
+0,
+16739835,
+0,
+-16773977,
+49676415,
+0,
+-19243342,
+0,
+-13655857,
+82339984,
+0,
+-55005915,
+0,
+-10556853,
+118287496,
+0,
+-94363999,
+0,
+-7146281,
+16840799,
+0,
+16711837,
+0,
+-16775419,
+80691383,
+0,
+-48942961,
+0,
+-14971206,
+149858505,
+0,
+-120064524,
+0,
+-13016765,
+233520652,
+0,
+-206090695,
+0,
+-10652741,
+16892981,
+0,
+16660455,
+0,
+-16776220,
+136000868,
+0,
+-103472696,
+0,
+-15750956,
+271801469,
+0,
+-240442250,
+0,
+-14582003,
+446309601,
+0,
+-416452524,
+0,
+-13079862,
diff --git a/media/libeffects/testlibs/AudioShelvingFilter.cpp b/media/libeffects/testlibs/AudioShelvingFilter.cpp
new file mode 100644
index 0000000..b8650ba
--- /dev/null
+++ b/media/libeffects/testlibs/AudioShelvingFilter.cpp
@@ -0,0 +1,109 @@
+/* /android/src/frameworks/base/libs/audioflinger/AudioShelvingFilter.cpp
+**
+** Copyright 2009, 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 "AudioShelvingFilter.h"
+#include "AudioCommon.h"
+#include "EffectsMath.h"
+
+#include <new>
+#include <assert.h>
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+// Format of the coefficient tables:
+// kCoefTable[freq][gain][coef]
+// freq - cutoff frequency, in octaves below Nyquist,from -10 to -6 in low
+// shelf, -2 to 0 in high shelf.
+// gain - gain, in millibel, starting at -9600, jumps of 1024, to 4736 millibel.
+// coef - 0: b0
+// 1: b1
+// 2: b2
+// 3: -a1
+// 4: -a2
+static const size_t kHiInDims[2] = {3, 15};
+static const audio_coef_t kHiCoefTable[3*15*5] = {
+#include "AudioHighShelfFilterCoef.inl"
+};
+static const size_t kLoInDims[2] = {5, 15};
+static const audio_coef_t kLoCoefTable[5*15*5] = {
+#include "AudioLowShelfFilterCoef.inl"
+};
+
+AudioCoefInterpolator AudioShelvingFilter::mHiCoefInterp(2, kHiInDims, 5, (const audio_coef_t*) kHiCoefTable);
+AudioCoefInterpolator AudioShelvingFilter::mLoCoefInterp(2, kLoInDims, 5, (const audio_coef_t*) kLoCoefTable);
+
+AudioShelvingFilter::AudioShelvingFilter(ShelfType type, int nChannels,
+ int sampleRate)
+ : mType(type),
+ mBiquad(nChannels, sampleRate) {
+ configure(nChannels, sampleRate);
+}
+
+void AudioShelvingFilter::configure(int nChannels, int sampleRate) {
+ mNiquistFreq = sampleRate * 500;
+ mFrequencyFactor = ((1ull) << 42) / mNiquistFreq;
+ mBiquad.configure(nChannels, sampleRate);
+ setFrequency(mNominalFrequency);
+ commit(true);
+}
+
+void AudioShelvingFilter::reset() {
+ setGain(0);
+ setFrequency(mType == kLowShelf ? 0 : mNiquistFreq);
+ commit(true);
+}
+
+void AudioShelvingFilter::setFrequency(uint32_t millihertz) {
+ mNominalFrequency = millihertz;
+ if (UNLIKELY(millihertz > mNiquistFreq / 2)) {
+ millihertz = mNiquistFreq / 2;
+ }
+ uint32_t normFreq = static_cast<uint32_t>(
+ (static_cast<uint64_t>(millihertz) * mFrequencyFactor) >> 10);
+ uint32_t log2minFreq = (mType == kLowShelf ? (32-10) : (32-2));
+ if (LIKELY(normFreq > (1U << log2minFreq))) {
+ mFrequency = (Effects_log2(normFreq) - (log2minFreq << 15)) << (FREQ_PRECISION_BITS - 15);
+ } else {
+ mFrequency = 0;
+ }
+}
+
+void AudioShelvingFilter::setGain(int32_t millibel) {
+ mGain = millibel + 9600;
+}
+
+void AudioShelvingFilter::commit(bool immediate) {
+ audio_coef_t coefs[5];
+ int intCoord[2] = {
+ mFrequency >> FREQ_PRECISION_BITS,
+ mGain >> GAIN_PRECISION_BITS
+ };
+ uint32_t fracCoord[2] = {
+ mFrequency << (32 - FREQ_PRECISION_BITS),
+ static_cast<uint32_t>(mGain) << (32 - GAIN_PRECISION_BITS)
+ };
+ if (mType == kHighShelf) {
+ mHiCoefInterp.getCoef(intCoord, fracCoord, coefs);
+ } else {
+ mLoCoefInterp.getCoef(intCoord, fracCoord, coefs);
+ }
+ mBiquad.setCoefs(coefs, immediate);
+}
+
+}
diff --git a/media/libeffects/testlibs/AudioShelvingFilter.h b/media/libeffects/testlibs/AudioShelvingFilter.h
new file mode 100644
index 0000000..f72d793
--- /dev/null
+++ b/media/libeffects/testlibs/AudioShelvingFilter.h
@@ -0,0 +1,146 @@
+/* /android/src/frameworks/base/libs/audioflinger/AudioShelvingFilter.h
+**
+** Copyright 2009, 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 AUDIO_SHELVING_FILTER_H
+#define AUDIO_SHELVING_FILTER_H
+
+#include "AudioBiquadFilter.h"
+#include "AudioCoefInterpolator.h"
+
+namespace android {
+
+// A shelving audio filter, with unity skirt gain, and controllable cutoff
+// frequency and gain.
+// This filter is able to suppress introduce discontinuities and other artifacts
+// in the output, even when changing parameters abruptly.
+// Parameters can be set to any value - this class will make sure to clip them
+// when they are out of supported range.
+//
+// Implementation notes:
+// This class uses an underlying biquad filter whose parameters are determined
+// using a linear interpolation from a coefficient table, using a
+// AudioCoefInterpolator.
+// All is left for this class to do is mapping between high-level parameters to
+// fractional indices into the coefficient table.
+class AudioShelvingFilter {
+public:
+ // Shelf type
+ enum ShelfType {
+ kLowShelf,
+ kHighShelf
+ };
+
+ // Constructor. Resets the filter (see reset()).
+ // type Type of the filter (high shelf or low shelf).
+ // nChannels Number of input/output channels (interlaced).
+ // sampleRate The input/output sample rate, in Hz.
+ AudioShelvingFilter(ShelfType type, int nChannels, int sampleRate);
+
+ // Reconfiguration of the filter. Changes input/output format, but does not
+ // alter current parameter values. Clears delay lines.
+ // nChannels Number of input/output channels (interlaced).
+ // sampleRate The input/output sample rate, in Hz.
+ void configure(int nChannels, int sampleRate);
+
+ // Resets the filter parameters to the following values:
+ // frequency: 0
+ // gain: 0
+ // It also disables the filter. Does not clear the delay lines.
+ void reset();
+
+ // Clears delay lines. Does not alter parameter values.
+ void clear() { mBiquad.clear(); }
+
+ // Sets gain value. Actual change will only take place upon commit().
+ // This value will be remembered even if the filter is in disabled() state.
+ // millibel Gain value in millibel (1/100 of decibel).
+ void setGain(int32_t millibel);
+
+ // Gets the gain, in millibel, as set.
+ int32_t getGain() const { return mGain - 9600; }
+
+ // Sets cutoff frequency value. Actual change will only take place upon
+ // commit().
+ // This value will be remembered even if the filter is in disabled() state.
+ // millihertz Frequency value in mHz.
+ void setFrequency(uint32_t millihertz);
+
+ // Gets the frequency, in mHz, as set.
+ uint32_t getFrequency() const { return mNominalFrequency; }
+
+ // Applies all parameter changes done to this point in time.
+ // If the filter is disabled, the new parameters will take place when it is
+ // enabled again. Does not introduce artifacts, unless immediate is set.
+ // immediate Whether to apply change abruptly (ignored if filter is
+ // disabled).
+ void commit(bool immediate = false);
+
+ // Process a buffer of input data. The input and output should contain
+ // frameCount * nChannels interlaced samples. Processing can be done
+ // in-place, by passing the same buffer as both arguments.
+ // in Input buffer.
+ // out Output buffer.
+ // frameCount Number of frames to produce.
+ void process(const audio_sample_t in[], audio_sample_t out[],
+ int frameCount) { mBiquad.process(in, out, frameCount); }
+
+ // Enables the filter, so it would start processing input. Does not
+ // introduce artifacts, unless immediate is set.
+ // immediate Whether to apply change abruptly.
+ void enable(bool immediate = false) { mBiquad.enable(immediate); }
+
+ // Disabled (bypasses) the filter. Does not introduce artifacts, unless
+ // immediate is set.
+ // immediate Whether to apply change abruptly.
+ void disable(bool immediate = false) { mBiquad.disable(immediate); }
+
+private:
+ // Precision for the mFrequency member.
+ static const int FREQ_PRECISION_BITS = 26;
+ // Precision for the mGain member.
+ static const int GAIN_PRECISION_BITS = 10;
+
+ // Shelf type.
+ ShelfType mType;
+ // Nyquist, in mHz.
+ uint32_t mNiquistFreq;
+ // Fractional index into the gain dimension of the coef table in
+ // GAIN_PRECISION_BITS precision.
+ int32_t mGain;
+ // Fractional index into the frequency dimension of the coef table in
+ // FREQ_PRECISION_BITS precision.
+ uint32_t mFrequency;
+ // Nominal value of frequency, as set.
+ uint32_t mNominalFrequency;
+ // 1/Nyquist[mHz], in 42-bit precision (very small).
+ // Used for scaling the frequency.
+ uint32_t mFrequencyFactor;
+
+ // A biquad filter, used for the actual processing.
+ AudioBiquadFilter mBiquad;
+ // A coefficient interpolator, used for mapping the high level parameters to
+ // the low-level biquad coefficients. This one is used for the high shelf.
+ static AudioCoefInterpolator mHiCoefInterp;
+ // A coefficient interpolator, used for mapping the high level parameters to
+ // the low-level biquad coefficients. This one is used for the low shelf.
+ static AudioCoefInterpolator mLoCoefInterp;
+};
+
+}
+
+
+#endif // AUDIO_SHELVING_FILTER_H
diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp
new file mode 100644
index 0000000..0eb2bdf
--- /dev/null
+++ b/media/libeffects/testlibs/EffectEqualizer.cpp
@@ -0,0 +1,654 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#define LOG_TAG "Equalizer"
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+//
+#define LOG_NDEBUG 0
+#include <cutils/log.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <new>
+#include "AudioEqualizer.h"
+#include "AudioBiquadFilter.h"
+#include "AudioFormatAdapter.h"
+#include <media/EffectEqualizerApi.h>
+
+// effect_interface_t interface implementation for equalizer effect
+extern "C" const struct effect_interface_s gEqualizerInterface;
+
+enum equalizer_state_e {
+ EQUALIZER_STATE_UNINITIALIZED,
+ EQUALIZER_STATE_INITIALIZED,
+ EQUALIZER_STATE_ACTIVE,
+};
+
+namespace android {
+namespace {
+
+// Google Graphic Equalizer UUID: e25aa840-543b-11df-98a5-0002a5d5c51b
+const effect_descriptor_t gEqualizerDescriptor = {
+ {0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
+ {0xe25aa840, 0x543b, 0x11df, 0x98a5, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+ EFFECT_API_VERSION,
+ (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST),
+ 0, // TODO
+ 1,
+ "Graphic Equalizer",
+ "Google Inc.",
+};
+
+/////////////////// BEGIN EQ PRESETS ///////////////////////////////////////////
+const int kNumBands = 5;
+const uint32_t gFreqs[kNumBands] = { 50000, 125000, 900000, 3200000, 6300000 };
+const uint32_t gBandwidths[kNumBands] = { 0, 3600, 3600, 2400, 0 };
+
+const AudioEqualizer::BandConfig gBandsClassic[kNumBands] = {
+ { 300, gFreqs[0], gBandwidths[0] },
+ { 400, gFreqs[1], gBandwidths[1] },
+ { 0, gFreqs[2], gBandwidths[2] },
+ { 200, gFreqs[3], gBandwidths[3] },
+ { -300, gFreqs[4], gBandwidths[4] }
+};
+
+const AudioEqualizer::BandConfig gBandsJazz[kNumBands] = {
+ { -600, gFreqs[0], gBandwidths[0] },
+ { 200, gFreqs[1], gBandwidths[1] },
+ { 400, gFreqs[2], gBandwidths[2] },
+ { -400, gFreqs[3], gBandwidths[3] },
+ { -600, gFreqs[4], gBandwidths[4] }
+};
+
+const AudioEqualizer::BandConfig gBandsPop[kNumBands] = {
+ { 400, gFreqs[0], gBandwidths[0] },
+ { -400, gFreqs[1], gBandwidths[1] },
+ { 300, gFreqs[2], gBandwidths[2] },
+ { -400, gFreqs[3], gBandwidths[3] },
+ { 600, gFreqs[4], gBandwidths[4] }
+};
+
+const AudioEqualizer::BandConfig gBandsRock[kNumBands] = {
+ { 700, gFreqs[0], gBandwidths[0] },
+ { 400, gFreqs[1], gBandwidths[1] },
+ { -400, gFreqs[2], gBandwidths[2] },
+ { 400, gFreqs[3], gBandwidths[3] },
+ { 200, gFreqs[4], gBandwidths[4] }
+};
+
+const AudioEqualizer::PresetConfig gEqualizerPresets[] = {
+ { "Classic", gBandsClassic },
+ { "Jazz", gBandsJazz },
+ { "Pop", gBandsPop },
+ { "Rock", gBandsRock }
+};
+
+/////////////////// END EQ PRESETS /////////////////////////////////////////////
+
+static const size_t kBufferSize = 32;
+
+typedef AudioFormatAdapter<AudioEqualizer, kBufferSize> FormatAdapter;
+
+struct EqualizerContext {
+ const struct effect_interface_s *itfe;
+ effect_config_t config;
+ FormatAdapter adapter;
+ AudioEqualizer * pEqualizer;
+ uint32_t state;
+};
+
+//--- local function prototypes
+
+int Equalizer_init(EqualizerContext *pContext);
+int Equalizer_configure(EqualizerContext *pContext, effect_config_t *pConfig);
+int Equalizer_getParameter(AudioEqualizer * pEqualizer, int32_t *pParam, size_t *pValueSize, void *pValue);
+int Equalizer_setParameter(AudioEqualizer * pEqualizer, int32_t *pParam, void *pValue);
+
+
+//
+//--- Effect Library Interface Implementation
+//
+
+extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects) {
+ *pNumEffects = 1;
+ return 0;
+} /* end EffectQueryNumberEffects */
+
+extern "C" int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) {
+ if (pDescriptor == NULL) {
+ return -EINVAL;
+ }
+ if (index > 0) {
+ return -EINVAL;
+ }
+ memcpy(pDescriptor, &gEqualizerDescriptor, sizeof(effect_descriptor_t));
+ return 0;
+} /* end EffectQueryNext */
+
+extern "C" int EffectCreate(effect_uuid_t *uuid,
+ int32_t sessionId,
+ int32_t ioId,
+ effect_interface_t *pInterface) {
+ int ret;
+ int i;
+
+ LOGV("EffectLibCreateEffect start");
+
+ if (pInterface == NULL || uuid == NULL) {
+ return -EINVAL;
+ }
+
+ if (memcmp(uuid, &gEqualizerDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
+ return -EINVAL;
+ }
+
+ EqualizerContext *pContext = new EqualizerContext;
+
+ pContext->itfe = &gEqualizerInterface;
+ pContext->pEqualizer = NULL;
+ pContext->state = EQUALIZER_STATE_UNINITIALIZED;
+
+ ret = Equalizer_init(pContext);
+ if (ret < 0) {
+ LOGW("EffectLibCreateEffect() init failed");
+ delete pContext;
+ return ret;
+ }
+
+ *pInterface = (effect_interface_t)pContext;
+ pContext->state = EQUALIZER_STATE_INITIALIZED;
+
+ LOGV("EffectLibCreateEffect %p, size %d", pContext, AudioEqualizer::GetInstanceSize(kNumBands)+sizeof(EqualizerContext));
+
+ return 0;
+
+} /* end EffectCreate */
+
+extern "C" int EffectRelease(effect_interface_t interface) {
+ EqualizerContext * pContext = (EqualizerContext *)interface;
+
+ LOGV("EffectLibReleaseEffect %p", interface);
+ if (pContext == NULL) {
+ return -EINVAL;
+ }
+
+ pContext->state = EQUALIZER_STATE_UNINITIALIZED;
+ pContext->pEqualizer->free();
+ delete pContext;
+
+ return 0;
+} /* end EffectRelease */
+
+
+//
+//--- local functions
+//
+
+#define CHECK_ARG(cond) { \
+ if (!(cond)) { \
+ LOGV("Invalid argument: "#cond); \
+ return -EINVAL; \
+ } \
+}
+
+//----------------------------------------------------------------------------
+// Equalizer_configure()
+//----------------------------------------------------------------------------
+// Purpose: Set input and output audio configuration.
+//
+// Inputs:
+// pContext: effect engine context
+// pConfig: pointer to effect_config_t structure holding input and output
+// configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int Equalizer_configure(EqualizerContext *pContext, effect_config_t *pConfig)
+{
+ LOGV("Equalizer_configure start");
+
+ CHECK_ARG(pContext != NULL);
+ CHECK_ARG(pConfig != NULL);
+
+ CHECK_ARG(pConfig->inputCfg.samplingRate == pConfig->outputCfg.samplingRate);
+ CHECK_ARG(pConfig->inputCfg.channels == pConfig->outputCfg.channels);
+ CHECK_ARG(pConfig->inputCfg.format == pConfig->outputCfg.format);
+ CHECK_ARG((pConfig->inputCfg.channels == CHANNEL_MONO) || (pConfig->inputCfg.channels == CHANNEL_STEREO));
+ CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE
+ || pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
+ CHECK_ARG(pConfig->inputCfg.format == SAMPLE_FORMAT_PCM_S7_24
+ || pConfig->inputCfg.format == SAMPLE_FORMAT_PCM_S15);
+
+ int channelCount;
+ if (pConfig->inputCfg.channels == CHANNEL_MONO) {
+ channelCount = 1;
+ } else {
+ channelCount = 2;
+ }
+ CHECK_ARG(channelCount <= AudioBiquadFilter::MAX_CHANNELS);
+
+ memcpy(&pContext->config, pConfig, sizeof(effect_config_t));
+
+ pContext->pEqualizer->configure(channelCount,
+ pConfig->inputCfg.samplingRate);
+
+ pContext->adapter.configure(*pContext->pEqualizer, channelCount,
+ pConfig->inputCfg.format,
+ pConfig->outputCfg.accessMode);
+
+ return 0;
+} // end Equalizer_configure
+
+
+//----------------------------------------------------------------------------
+// Equalizer_init()
+//----------------------------------------------------------------------------
+// Purpose: Initialize engine with default configuration and creates
+// AudioEqualizer instance.
+//
+// Inputs:
+// pContext: effect engine context
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int Equalizer_init(EqualizerContext *pContext)
+{
+ int status;
+
+ LOGV("Equalizer_init start");
+
+ CHECK_ARG(pContext != NULL);
+
+ if (pContext->pEqualizer != NULL) {
+ pContext->pEqualizer->free();
+ }
+
+ pContext->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ pContext->config.inputCfg.channels = CHANNEL_STEREO;
+ pContext->config.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
+ pContext->config.inputCfg.samplingRate = 44100;
+ pContext->config.inputCfg.bufferProvider.getBuffer = NULL;
+ pContext->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+ pContext->config.inputCfg.bufferProvider.cookie = NULL;
+ pContext->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+ pContext->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ pContext->config.outputCfg.channels = CHANNEL_STEREO;
+ pContext->config.outputCfg.format = SAMPLE_FORMAT_PCM_S15;
+ pContext->config.outputCfg.samplingRate = 44100;
+ pContext->config.outputCfg.bufferProvider.getBuffer = NULL;
+ pContext->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+ pContext->config.outputCfg.bufferProvider.cookie = NULL;
+ pContext->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ pContext->pEqualizer = AudioEqualizer::CreateInstance(
+ NULL,
+ kNumBands,
+ AudioBiquadFilter::MAX_CHANNELS,
+ 44100,
+ gEqualizerPresets,
+ ARRAY_SIZE(gEqualizerPresets));
+
+ for (int i = 0; i < kNumBands; ++i) {
+ pContext->pEqualizer->setFrequency(i, gFreqs[i]);
+ pContext->pEqualizer->setBandwidth(i, gBandwidths[i]);
+ }
+
+ pContext->pEqualizer->enable(true);
+
+ Equalizer_configure(pContext, &pContext->config);
+
+ return 0;
+} // end Equalizer_init
+
+
+//----------------------------------------------------------------------------
+// Equalizer_getParameter()
+//----------------------------------------------------------------------------
+// Purpose:
+// Get a Equalizer parameter
+//
+// Inputs:
+// pEqualizer - handle to instance data
+// pParam - pointer to parameter
+// pValue - pointer to variable to hold retrieved value
+// pValueSize - pointer to value size: maximum size as input
+//
+// Outputs:
+// *pValue updated with parameter value
+// *pValueSize updated with actual value size
+//
+//
+// Side Effects:
+//
+//----------------------------------------------------------------------------
+
+int Equalizer_getParameter(AudioEqualizer * pEqualizer, int32_t *pParam, size_t *pValueSize, void *pValue)
+{
+ int status = 0;
+ int32_t param = *pParam++;
+ int32_t param2;
+ char *name;
+
+ switch (param) {
+ case EQ_PARAM_NUM_BANDS:
+ case EQ_PARAM_CUR_PRESET:
+ case EQ_PARAM_GET_NUM_OF_PRESETS:
+ if (*pValueSize < sizeof(int16_t)) {
+ return -EINVAL;
+ }
+ *pValueSize = sizeof(int16_t);
+ break;
+
+ case EQ_PARAM_LEVEL_RANGE:
+ case EQ_PARAM_BAND_FREQ_RANGE:
+ if (*pValueSize < 2 * sizeof(int32_t)) {
+ return -EINVAL;
+ }
+ *pValueSize = 2 * sizeof(int32_t);
+ break;
+ case EQ_PARAM_BAND_LEVEL:
+ case EQ_PARAM_GET_BAND:
+ case EQ_PARAM_CENTER_FREQ:
+ if (*pValueSize < sizeof(int32_t)) {
+ return -EINVAL;
+ }
+ *pValueSize = sizeof(int32_t);
+ break;
+
+ case EQ_PARAM_GET_PRESET_NAME:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (param) {
+ case EQ_PARAM_NUM_BANDS:
+ *(int16_t *)pValue = kNumBands;
+ LOGV("Equalizer_getParameter() EQ_PARAM_NUM_BANDS %d", *(int16_t *)pValue);
+ break;
+
+ case EQ_PARAM_LEVEL_RANGE:
+ *(int32_t *)pValue = -9600;
+ *((int32_t *)pValue + 1) = 4800;
+ LOGV("Equalizer_getParameter() EQ_PARAM_LEVEL_RANGE min %d, max %d", *(int32_t *)pValue, *((int32_t *)pValue + 1));
+ break;
+
+ case EQ_PARAM_BAND_LEVEL:
+ param2 = *pParam;
+ if (param2 >= kNumBands) {
+ status = -EINVAL;
+ break;
+ }
+ *(int32_t *)pValue = pEqualizer->getGain(param2);
+ LOGV("Equalizer_getParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", param2, *(int32_t *)pValue);
+ break;
+
+ case EQ_PARAM_CENTER_FREQ:
+ param2 = *pParam;
+ if (param2 >= kNumBands) {
+ status = -EINVAL;
+ break;
+ }
+ *(int32_t *)pValue = pEqualizer->getFrequency(param2);
+ LOGV("Equalizer_getParameter() EQ_PARAM_CENTER_FREQ band %d, frequency %d", param2, *(int32_t *)pValue);
+ break;
+
+ case EQ_PARAM_BAND_FREQ_RANGE:
+ param2 = *pParam;
+ if (param2 >= kNumBands) {
+ status = -EINVAL;
+ break;
+ }
+ pEqualizer->getBandRange(param2, *(uint32_t *)pValue, *((uint32_t *)pValue + 1));
+ LOGV("Equalizer_getParameter() EQ_PARAM_BAND_FREQ_RANGE band %d, min %d, max %d", param2, *(int32_t *)pValue, *((int32_t *)pValue + 1));
+ break;
+
+ case EQ_PARAM_GET_BAND:
+ param2 = *pParam;
+ *(int32_t *)pValue = pEqualizer->getMostRelevantBand(param2);
+ LOGV("Equalizer_getParameter() EQ_PARAM_GET_BAND frequency %d, band %d", param2, *(int32_t *)pValue);
+ break;
+
+ case EQ_PARAM_CUR_PRESET:
+ *(int16_t *)pValue = pEqualizer->getPreset();
+ LOGV("Equalizer_getParameter() EQ_PARAM_CUR_PRESET %d", *(int32_t *)pValue);
+ break;
+
+ case EQ_PARAM_GET_NUM_OF_PRESETS:
+ *(int16_t *)pValue = pEqualizer->getNumPresets();
+ LOGV("Equalizer_getParameter() EQ_PARAM_GET_NUM_OF_PRESETS %d", *(int16_t *)pValue);
+ break;
+
+ case EQ_PARAM_GET_PRESET_NAME:
+ param2 = *pParam;
+ if (param2 >= pEqualizer->getNumPresets()) {
+ status = -EINVAL;
+ break;
+ }
+ name = (char *)pValue;
+ strncpy(name, pEqualizer->getPresetName(param2), *pValueSize - 1);
+ name[*pValueSize - 1] = 0;
+ *pValueSize = strlen(name) + 1;
+ LOGV("Equalizer_getParameter() EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d", param2, gEqualizerPresets[param2].name, *pValueSize);
+ break;
+
+ default:
+ LOGV("Equalizer_getParameter() invalid param %d", param);
+ status = -EINVAL;
+ break;
+ }
+
+ return status;
+} // end Equalizer_getParameter
+
+
+//----------------------------------------------------------------------------
+// Equalizer_setParameter()
+//----------------------------------------------------------------------------
+// Purpose:
+// Set a Equalizer parameter
+//
+// Inputs:
+// pEqualizer - handle to instance data
+// pParam - pointer to parameter
+// pValue - pointer to value
+//
+// Outputs:
+//
+//
+// Side Effects:
+//
+//----------------------------------------------------------------------------
+
+int Equalizer_setParameter (AudioEqualizer * pEqualizer, int32_t *pParam, void *pValue)
+{
+ int status = 0;
+ int32_t preset;
+ int32_t band;
+ int32_t level;
+ int32_t param = *pParam++;
+
+
+ switch (param) {
+ case EQ_PARAM_CUR_PRESET:
+ preset = *(int16_t *)pValue;
+
+ LOGV("setParameter() EQ_PARAM_CUR_PRESET %d", preset);
+ if (preset >= pEqualizer->getNumPresets()) {
+ status = -EINVAL;
+ break;
+ }
+ pEqualizer->setPreset(preset);
+ pEqualizer->commit(true);
+ break;
+ case EQ_PARAM_BAND_LEVEL:
+ band = *pParam;
+ level = *(int32_t *)pValue;
+ LOGV("setParameter() EQ_PARAM_BAND_LEVEL band %d, level %d", band, level);
+ if (band >= kNumBands) {
+ status = -EINVAL;
+ break;
+ }
+ pEqualizer->setGain(band, level);
+ pEqualizer->commit(true);
+ break;
+ default:
+ LOGV("setParameter() invalid param %d", param);
+ break;
+ }
+
+ return status;
+} // end Equalizer_setParameter
+
+} // namespace
+} // namespace
+
+
+//
+//--- Effect Control Interface Implementation
+//
+
+extern "C" int Equalizer_process(effect_interface_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
+{
+ android::EqualizerContext * pContext = (android::EqualizerContext *) self;
+
+ if (pContext == NULL) {
+ return -EINVAL;
+ }
+ if (inBuffer == NULL || inBuffer->raw == NULL ||
+ outBuffer == NULL || outBuffer->raw == NULL ||
+ inBuffer->frameCount != outBuffer->frameCount) {
+ return -EINVAL;
+ }
+
+ if (pContext->state == EQUALIZER_STATE_UNINITIALIZED) {
+ return -EINVAL;
+ }
+ if (pContext->state == EQUALIZER_STATE_INITIALIZED) {
+ return -ENODATA;
+ }
+
+ pContext->adapter.process(inBuffer->raw, outBuffer->raw, outBuffer->frameCount);
+
+ return 0;
+} // end Equalizer_process
+
+extern "C" int Equalizer_command(effect_interface_t self, int cmdCode, int cmdSize,
+ void *pCmdData, int *replySize, void *pReplyData) {
+
+ android::EqualizerContext * pContext = (android::EqualizerContext *) self;
+ int retsize;
+
+ if (pContext == NULL || pContext->state == EQUALIZER_STATE_UNINITIALIZED) {
+ return -EINVAL;
+ }
+
+ android::AudioEqualizer * pEqualizer = pContext->pEqualizer;
+
+ LOGV("Equalizer_command command %d cmdSize %d",cmdCode, cmdSize);
+
+ switch (cmdCode) {
+ case EFFECT_CMD_INIT:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ *(int *) pReplyData = Equalizer_init(pContext);
+ break;
+ case EFFECT_CMD_CONFIGURE:
+ if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
+ || pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ *(int *) pReplyData = Equalizer_configure(pContext,
+ (effect_config_t *) pCmdData);
+ break;
+ case EFFECT_CMD_RESET:
+ Equalizer_configure(pContext, &pContext->config);
+ break;
+ case EFFECT_CMD_GET_PARAM: {
+ if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
+ pReplyData == NULL || *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))) {
+ return -EINVAL;
+ }
+ effect_param_t *p = (effect_param_t *)pCmdData;
+ memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
+ p = (effect_param_t *)pReplyData;
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+ p->status = android::Equalizer_getParameter(pEqualizer, (int32_t *)p->data, &p->vsize,
+ p->data + voffset);
+ *replySize = sizeof(effect_param_t) + voffset + p->vsize;
+ LOGV("Equalizer_command EFFECT_CMD_GET_PARAM *pCmdData %d, *replySize %d, *pReplyData %08x %08x",
+ *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)), *replySize,
+ *(int32_t *)((char *)pReplyData + sizeof(effect_param_t) + voffset),
+ *(int32_t *)((char *)pReplyData + sizeof(effect_param_t) + voffset + sizeof(int32_t)));
+
+ } break;
+ case EFFECT_CMD_SET_PARAM: {
+ LOGV("Equalizer_command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %d, pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData);
+ if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
+ pReplyData == NULL || *replySize != sizeof(int32_t)) {
+ return -EINVAL;
+ }
+ effect_param_t *p = (effect_param_t *) pCmdData;
+ *(int *)pReplyData = android::Equalizer_setParameter(pEqualizer, (int32_t *)p->data,
+ p->data + p->psize);
+ } break;
+ case EFFECT_CMD_ENABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ if (pContext->state != EQUALIZER_STATE_INITIALIZED) {
+ return -ENOSYS;
+ }
+ pContext->state = EQUALIZER_STATE_ACTIVE;
+ LOGV("EFFECT_CMD_ENABLE() OK");
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_DISABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ if (pContext->state != EQUALIZER_STATE_ACTIVE) {
+ return -ENOSYS;
+ }
+ pContext->state = EQUALIZER_STATE_INITIALIZED;
+ LOGV("EFFECT_CMD_DISABLE() OK");
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_SET_DEVICE:
+ case EFFECT_CMD_SET_VOLUME:
+ case EFFECT_CMD_SET_AUDIO_MODE:
+ break;
+ default:
+ LOGW("Equalizer_command invalid command %d",cmdCode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+// effect_interface_t interface implementation for equalizer effect
+const struct effect_interface_s gEqualizerInterface = {
+ Equalizer_process,
+ Equalizer_command
+};
+
+
diff --git a/media/libeffects/testlibs/EffectReverb.c b/media/libeffects/testlibs/EffectReverb.c
new file mode 100644
index 0000000..2ce7558
--- /dev/null
+++ b/media/libeffects/testlibs/EffectReverb.c
@@ -0,0 +1,2135 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#define LOG_TAG "EffectReverb"
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include "EffectReverb.h"
+#include "EffectsMath.h"
+
+// effect_interface_t interface implementation for reverb effect
+const struct effect_interface_s gReverbInterface = {
+ Reverb_Process,
+ Reverb_Command
+};
+
+// Google auxiliary environmental reverb UUID: 1f0ae2e0-4ef7-11df-bc09-0002a5d5c51b
+static const effect_descriptor_t gAuxEnvReverbDescriptor = {
+ {0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}},
+ {0x1f0ae2e0, 0x4ef7, 0x11df, 0xbc09, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_API_VERSION,
+ // flags other than EFFECT_FLAG_TYPE_AUXILIARY set for test purpose
+ EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_AUDIO_MODE_IND,
+ 0, // TODO
+ 33,
+ "Aux Environmental Reverb",
+ "Google Inc."
+};
+
+// Google insert environmental reverb UUID: aa476040-6342-11df-91a4-0002a5d5c51b
+static const effect_descriptor_t gInsertEnvReverbDescriptor = {
+ {0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}},
+ {0xaa476040, 0x6342, 0x11df, 0x91a4, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_API_VERSION,
+ EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
+ 0, // TODO
+ 33,
+ "Insert Environmental reverb",
+ "Google Inc."
+};
+
+// Google auxiliary preset reverb UUID: 63909320-53a6-11df-bdbd-0002a5d5c51b
+static const effect_descriptor_t gAuxPresetReverbDescriptor = {
+ {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0x63909320, 0x53a6, 0x11df, 0xbdbd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_API_VERSION,
+ EFFECT_FLAG_TYPE_AUXILIARY,
+ 0, // TODO
+ 33,
+ "Aux Preset Reverb",
+ "Google Inc."
+};
+
+// Google insert preset reverb UUID: d93dc6a0-6342-11df-b128-0002a5d5c51b
+static const effect_descriptor_t gInsertPresetReverbDescriptor = {
+ {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ {0xd93dc6a0, 0x6342, 0x11df, 0xb128, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ EFFECT_API_VERSION,
+ EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
+ 0, // TODO
+ 33,
+ "Insert Preset Reverb",
+ "Google Inc."
+};
+
+// gDescriptors contains pointers to all defined effect descriptor in this library
+static const effect_descriptor_t * const gDescriptors[] = {
+ &gAuxEnvReverbDescriptor,
+ &gInsertEnvReverbDescriptor,
+ &gAuxPresetReverbDescriptor,
+ &gInsertPresetReverbDescriptor
+};
+
+/*----------------------------------------------------------------------------
+ * Effect API implementation
+ *--------------------------------------------------------------------------*/
+
+/*--- Effect Library Interface Implementation ---*/
+
+int EffectQueryNumberEffects(uint32_t *pNumEffects) {
+ *pNumEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
+ return 0;
+}
+
+int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) {
+ if (pDescriptor == NULL) {
+ return -EINVAL;
+ }
+ if (index >= sizeof(gDescriptors) / sizeof(const effect_descriptor_t *)) {
+ return -EINVAL;
+ }
+ memcpy(pDescriptor, gDescriptors[index],
+ sizeof(effect_descriptor_t));
+ return 0;
+}
+
+int EffectCreate(effect_uuid_t *uuid,
+ int32_t sessionId,
+ int32_t ioId,
+ effect_interface_t *pInterface) {
+ int ret;
+ int i;
+ reverb_module_t *module;
+ const effect_descriptor_t *desc;
+ int aux = 0;
+ int preset = 0;
+
+ LOGV("EffectLibCreateEffect start");
+
+ if (pInterface == NULL || uuid == NULL) {
+ return -EINVAL;
+ }
+
+ for (i = 0; gDescriptors[i] != NULL; i++) {
+ desc = gDescriptors[i];
+ if (memcmp(uuid, &desc->uuid, sizeof(effect_uuid_t))
+ == 0) {
+ break;
+ }
+ }
+
+ if (gDescriptors[i] == NULL) {
+ return -ENOENT;
+ }
+
+ module = malloc(sizeof(reverb_module_t));
+
+ module->itfe = &gReverbInterface;
+
+ module->context.mState = REVERB_STATE_UNINITIALIZED;
+
+ if (memcmp(&desc->type, SL_IID_PRESETREVERB, sizeof(effect_uuid_t)) == 0) {
+ preset = 1;
+ }
+ if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+ aux = 1;
+ }
+ ret = Reverb_Init(module, aux, preset);
+ if (ret < 0) {
+ LOGW("EffectLibCreateEffect() init failed");
+ free(module);
+ return ret;
+ }
+
+ *pInterface = (effect_interface_t) module;
+
+ module->context.mState = REVERB_STATE_INITIALIZED;
+
+ LOGV("EffectLibCreateEffect %p ,size %d", module, sizeof(reverb_module_t));
+
+ return 0;
+}
+
+int EffectRelease(effect_interface_t interface) {
+ reverb_module_t *pRvbModule = (reverb_module_t *)interface;
+
+ LOGV("EffectLibReleaseEffect %p", interface);
+ if (interface == NULL) {
+ return -EINVAL;
+ }
+
+ pRvbModule->context.mState = REVERB_STATE_UNINITIALIZED;
+
+ free(pRvbModule);
+ return 0;
+}
+
+
+/*--- Effect Control Interface Implementation ---*/
+
+static int Reverb_Process(effect_interface_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {
+ reverb_object_t *pReverb;
+ int16_t *pSrc, *pDst;
+ reverb_module_t *pRvbModule = (reverb_module_t *)self;
+
+ if (pRvbModule == NULL) {
+ return -EINVAL;
+ }
+
+ if (inBuffer == NULL || inBuffer->raw == NULL ||
+ outBuffer == NULL || outBuffer->raw == NULL ||
+ inBuffer->frameCount != outBuffer->frameCount) {
+ return -EINVAL;
+ }
+
+ pReverb = (reverb_object_t*) &pRvbModule->context;
+
+ if (pReverb->mState == REVERB_STATE_UNINITIALIZED) {
+ return -EINVAL;
+ }
+ if (pReverb->mState == REVERB_STATE_INITIALIZED) {
+ return -ENODATA;
+ }
+
+ //if bypassed or the preset forces the signal to be completely dry
+ if (pReverb->m_bBypass != 0) {
+ if (inBuffer->raw != outBuffer->raw) {
+ int16_t smp;
+ pSrc = inBuffer->s16;
+ pDst = outBuffer->s16;
+ size_t count = inBuffer->frameCount;
+ if (pRvbModule->config.inputCfg.channels == pRvbModule->config.outputCfg.channels) {
+ count *= 2;
+ while (count--) {
+ *pDst++ = *pSrc++;
+ }
+ } else {
+ while (count--) {
+ smp = *pSrc++;
+ *pDst++ = smp;
+ *pDst++ = smp;
+ }
+ }
+ }
+ return 0;
+ }
+
+ if (pReverb->m_nNextRoom != pReverb->m_nCurrentRoom) {
+ ReverbUpdateRoom(pReverb, true);
+ }
+
+ pSrc = inBuffer->s16;
+ pDst = outBuffer->s16;
+ size_t numSamples = outBuffer->frameCount;
+ while (numSamples) {
+ uint32_t processedSamples;
+ if (numSamples > (uint32_t) pReverb->m_nUpdatePeriodInSamples) {
+ processedSamples = (uint32_t) pReverb->m_nUpdatePeriodInSamples;
+ } else {
+ processedSamples = numSamples;
+ }
+
+ /* increment update counter */
+ pReverb->m_nUpdateCounter += (int16_t) processedSamples;
+ /* check if update counter needs to be reset */
+ if (pReverb->m_nUpdateCounter >= pReverb->m_nUpdatePeriodInSamples) {
+ /* update interval has elapsed, so reset counter */
+ pReverb->m_nUpdateCounter -= pReverb->m_nUpdatePeriodInSamples;
+ ReverbUpdateXfade(pReverb, pReverb->m_nUpdatePeriodInSamples);
+
+ } /* end if m_nUpdateCounter >= update interval */
+
+ Reverb(pReverb, processedSamples, pDst, pSrc);
+
+ numSamples -= processedSamples;
+ if (pReverb->m_Aux) {
+ pSrc += processedSamples;
+ } else {
+ pSrc += processedSamples * NUM_OUTPUT_CHANNELS;
+ }
+ pDst += processedSamples * NUM_OUTPUT_CHANNELS;
+ }
+
+ return 0;
+}
+
+
+static int Reverb_Command(effect_interface_t self, int cmdCode, int cmdSize,
+ void *pCmdData, int *replySize, void *pReplyData) {
+ reverb_module_t *pRvbModule = (reverb_module_t *) self;
+ reverb_object_t *pReverb;
+ int retsize;
+
+ if (pRvbModule == NULL ||
+ pRvbModule->context.mState == REVERB_STATE_UNINITIALIZED) {
+ return -EINVAL;
+ }
+
+ pReverb = (reverb_object_t*) &pRvbModule->context;
+
+ LOGV("Reverb_Command command %d cmdSize %d",cmdCode, cmdSize);
+
+ switch (cmdCode) {
+ case EFFECT_CMD_INIT:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ *(int *) pReplyData = Reverb_Init(pRvbModule, pReverb->m_Aux, pReverb->m_Preset);
+ if (*(int *) pReplyData == 0) {
+ pRvbModule->context.mState = REVERB_STATE_INITIALIZED;
+ }
+ break;
+ case EFFECT_CMD_CONFIGURE:
+ if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
+ || pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ *(int *) pReplyData = Reverb_Configure(pRvbModule,
+ (effect_config_t *)pCmdData, false);
+ break;
+ case EFFECT_CMD_RESET:
+ Reverb_Reset(pReverb, false);
+ break;
+ case EFFECT_CMD_GET_PARAM:
+ LOGV("Reverb_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %d, pReplyData: %p",pCmdData, *replySize, pReplyData);
+
+ if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
+ pReplyData == NULL || *replySize < (int) sizeof(effect_param_t)) {
+ return -EINVAL;
+ }
+ effect_param_t *rep = (effect_param_t *) pReplyData;
+ memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(int32_t));
+ LOGV("Reverb_Command EFFECT_CMD_GET_PARAM param %d, replySize %d",*(int32_t *)rep->data, rep->vsize);
+ rep->status = Reverb_getParameter(pReverb, *(int32_t *)rep->data, &rep->vsize,
+ rep->data + sizeof(int32_t));
+ *replySize = sizeof(effect_param_t) + sizeof(int32_t) + rep->vsize;
+ break;
+ case EFFECT_CMD_SET_PARAM:
+ LOGV("Reverb_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
+ cmdSize, pCmdData, *replySize, pReplyData);
+ if (pCmdData == NULL || (cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)))
+ || pReplyData == NULL || *replySize != (int)sizeof(int32_t)) {
+ return -EINVAL;
+ }
+ effect_param_t *cmd = (effect_param_t *) pCmdData;
+ *(int *)pReplyData = Reverb_setParameter(pReverb, *(int32_t *)cmd->data,
+ cmd->vsize, cmd->data + sizeof(int32_t));
+ break;
+ case EFFECT_CMD_ENABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ if (pReverb->mState != REVERB_STATE_INITIALIZED) {
+ return -ENOSYS;
+ }
+ pReverb->mState = REVERB_STATE_ACTIVE;
+ LOGV("EFFECT_CMD_ENABLE() OK");
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_DISABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)) {
+ return -EINVAL;
+ }
+ if (pReverb->mState != REVERB_STATE_ACTIVE) {
+ return -ENOSYS;
+ }
+ pReverb->mState = REVERB_STATE_INITIALIZED;
+ LOGV("EFFECT_CMD_DISABLE() OK");
+ *(int *)pReplyData = 0;
+ break;
+ case EFFECT_CMD_SET_DEVICE:
+ if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
+ return -EINVAL;
+ }
+ LOGV("Reverb_Command EFFECT_CMD_SET_DEVICE: 0x%08x", *(uint32_t *)pCmdData);
+ break;
+ case EFFECT_CMD_SET_VOLUME: {
+ // audio output is always stereo => 2 channel volumes
+ if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t) * 2) {
+ return -EINVAL;
+ }
+ float left = (float)(*(uint32_t *)pCmdData) / (1 << 24);
+ float right = (float)(*((uint32_t *)pCmdData + 1)) / (1 << 24);
+ LOGV("Reverb_Command EFFECT_CMD_SET_VOLUME: left %f, right %f ", left, right);
+ break;
+ }
+ case EFFECT_CMD_SET_AUDIO_MODE:
+ if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
+ return -EINVAL;
+ }
+ LOGV("Reverb_Command EFFECT_CMD_SET_AUDIO_MODE: %d", *(uint32_t *)pCmdData);
+ break;
+ default:
+ LOGW("Reverb_Command invalid command %d",cmdCode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Reverb internal functions
+ *--------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ * Reverb_Init()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Initialize reverb context and apply default parameters
+ *
+ * Inputs:
+ * pRvbModule - pointer to reverb effect module
+ * aux - indicates if the reverb is used as auxiliary (1) or insert (0)
+ * preset - indicates if the reverb is used in preset (1) or environmental (0) mode
+ *
+ * Outputs:
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int Reverb_Init(reverb_module_t *pRvbModule, int aux, int preset) {
+ int ret;
+
+ LOGV("Reverb_Init module %p, aux: %d, preset: %d", pRvbModule,aux, preset);
+
+ memset(&pRvbModule->context, 0, sizeof(reverb_object_t));
+
+ pRvbModule->context.m_Aux = (uint16_t)aux;
+ pRvbModule->context.m_Preset = (uint16_t)preset;
+
+ pRvbModule->config.inputCfg.samplingRate = 44100;
+ if (aux) {
+ pRvbModule->config.inputCfg.channels = CHANNEL_MONO;
+ } else {
+ pRvbModule->config.inputCfg.channels = CHANNEL_STEREO;
+ }
+ pRvbModule->config.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
+ pRvbModule->config.inputCfg.bufferProvider.getBuffer = NULL;
+ pRvbModule->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+ pRvbModule->config.inputCfg.bufferProvider.cookie = NULL;
+ pRvbModule->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+ pRvbModule->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+ pRvbModule->config.outputCfg.samplingRate = 44100;
+ pRvbModule->config.outputCfg.channels = CHANNEL_STEREO;
+ pRvbModule->config.outputCfg.format = SAMPLE_FORMAT_PCM_S15;
+ pRvbModule->config.outputCfg.bufferProvider.getBuffer = NULL;
+ pRvbModule->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+ pRvbModule->config.outputCfg.bufferProvider.cookie = NULL;
+ pRvbModule->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+ pRvbModule->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+ ret = Reverb_Configure(pRvbModule, &pRvbModule->config, true);
+ if (ret < 0) {
+ LOGV("Reverb_Init error %d on module %p", ret, pRvbModule);
+ }
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------
+ * Reverb_Init()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Set input and output audio configuration.
+ *
+ * Inputs:
+ * pRvbModule - pointer to reverb effect module
+ * pConfig - pointer to effect_config_t structure containing input
+ * and output audio parameters configuration
+ * init - true if called from init function
+ * Outputs:
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig,
+ bool init) {
+ reverb_object_t *pReverb = &pRvbModule->context;
+ int bufferSizeInSamples;
+ int updatePeriodInSamples;
+ int xfadePeriodInSamples;
+
+ // Check configuration compatibility with build options
+ if (pConfig->inputCfg.samplingRate
+ != pConfig->outputCfg.samplingRate
+ || pConfig->outputCfg.channels != OUTPUT_CHANNELS
+ || pConfig->inputCfg.format != SAMPLE_FORMAT_PCM_S15
+ || pConfig->outputCfg.format != SAMPLE_FORMAT_PCM_S15) {
+ LOGV("Reverb_Configure invalid config");
+ return -EINVAL;
+ }
+ if ((pReverb->m_Aux && (pConfig->inputCfg.channels != CHANNEL_MONO)) ||
+ (!pReverb->m_Aux && (pConfig->inputCfg.channels != CHANNEL_STEREO))) {
+ LOGV("Reverb_Configure invalid config");
+ return -EINVAL;
+ }
+
+ memcpy(&pRvbModule->config, pConfig, sizeof(effect_config_t));
+
+ pReverb->m_nSamplingRate = pRvbModule->config.outputCfg.samplingRate;
+
+ switch (pReverb->m_nSamplingRate) {
+ case 8000:
+ pReverb->m_nUpdatePeriodInBits = 5;
+ bufferSizeInSamples = 4096;
+ pReverb->m_nCosWT_5KHz = -23170;
+ break;
+ case 16000:
+ pReverb->m_nUpdatePeriodInBits = 6;
+ bufferSizeInSamples = 8192;
+ pReverb->m_nCosWT_5KHz = -12540;
+ break;
+ case 22050:
+ pReverb->m_nUpdatePeriodInBits = 7;
+ bufferSizeInSamples = 8192;
+ pReverb->m_nCosWT_5KHz = 4768;
+ break;
+ case 32000:
+ pReverb->m_nUpdatePeriodInBits = 7;
+ bufferSizeInSamples = 16384;
+ pReverb->m_nCosWT_5KHz = 18205;
+ break;
+ case 44100:
+ pReverb->m_nUpdatePeriodInBits = 8;
+ bufferSizeInSamples = 16384;
+ pReverb->m_nCosWT_5KHz = 24799;
+ break;
+ case 48000:
+ pReverb->m_nUpdatePeriodInBits = 8;
+ bufferSizeInSamples = 16384;
+ pReverb->m_nCosWT_5KHz = 25997;
+ break;
+ default:
+ LOGV("Reverb_Configure invalid sampling rate %d", pReverb->m_nSamplingRate);
+ return -EINVAL;
+ }
+
+ // Define a mask for circular addressing, so that array index
+ // can wraparound and stay in array boundary of 0, 1, ..., (buffer size -1)
+ // The buffer size MUST be a power of two
+ pReverb->m_nBufferMask = (int32_t) (bufferSizeInSamples - 1);
+ /* reverb parameters are updated every 2^(pReverb->m_nUpdatePeriodInBits) samples */
+ updatePeriodInSamples = (int32_t) (0x1L << pReverb->m_nUpdatePeriodInBits);
+ /*
+ calculate the update counter by bitwise ANDING with this value to
+ generate a 2^n modulo value
+ */
+ pReverb->m_nUpdatePeriodInSamples = (int32_t) updatePeriodInSamples;
+
+ xfadePeriodInSamples = (int32_t) (REVERB_XFADE_PERIOD_IN_SECONDS
+ * (double) pReverb->m_nSamplingRate);
+
+ // set xfade parameters
+ pReverb->m_nPhaseIncrement
+ = (int16_t) (65536 / ((int16_t) xfadePeriodInSamples
+ / (int16_t) updatePeriodInSamples));
+
+ if (init) {
+ ReverbReadInPresets(pReverb);
+
+ // for debugging purposes, allow noise generator
+ pReverb->m_bUseNoise = true;
+
+ // for debugging purposes, allow bypass
+ pReverb->m_bBypass = 0;
+
+ pReverb->m_nNextRoom = 1;
+
+ pReverb->m_nNoise = (int16_t) 0xABCD;
+ }
+
+ Reverb_Reset(pReverb, init);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------
+ * Reverb_Reset()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Reset internal states and clear delay lines.
+ *
+ * Inputs:
+ * pReverb - pointer to reverb context
+ * init - true if called from init function
+ *
+ * Outputs:
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void Reverb_Reset(reverb_object_t *pReverb, bool init) {
+ int bufferSizeInSamples = (int32_t) (pReverb->m_nBufferMask + 1);
+ int maxApSamples;
+ int maxDelaySamples;
+ int maxEarlySamples;
+ int ap1In;
+ int delay0In;
+ int delay1In;
+ int32_t i;
+ uint16_t nOffset;
+
+ maxApSamples = ((int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16);
+ maxDelaySamples = ((int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
+ >> 16);
+ maxEarlySamples = ((int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
+ >> 16);
+
+ ap1In = (AP0_IN + maxApSamples + GUARD);
+ delay0In = (ap1In + maxApSamples + GUARD);
+ delay1In = (delay0In + maxDelaySamples + GUARD);
+ // Define the max offsets for the end points of each section
+ // i.e., we don't expect a given section's taps to go beyond
+ // the following limits
+
+ pReverb->m_nEarly0in = (delay1In + maxDelaySamples + GUARD);
+ pReverb->m_nEarly1in = (pReverb->m_nEarly0in + maxEarlySamples + GUARD);
+
+ pReverb->m_sAp0.m_zApIn = AP0_IN;
+
+ pReverb->m_zD0In = delay0In;
+
+ pReverb->m_sAp1.m_zApIn = ap1In;
+
+ pReverb->m_zD1In = delay1In;
+
+ pReverb->m_zOutLpfL = 0;
+ pReverb->m_zOutLpfR = 0;
+
+ pReverb->m_nRevFbkR = 0;
+ pReverb->m_nRevFbkL = 0;
+
+ // set base index into circular buffer
+ pReverb->m_nBaseIndex = 0;
+
+ // clear the reverb delay line
+ for (i = 0; i < bufferSizeInSamples; i++) {
+ pReverb->m_nDelayLine[i] = 0;
+ }
+
+ ReverbUpdateRoom(pReverb, init);
+
+ pReverb->m_nUpdateCounter = 0;
+
+ pReverb->m_nPhase = -32768;
+
+ pReverb->m_nSin = 0;
+ pReverb->m_nCos = 0;
+ pReverb->m_nSinIncrement = 0;
+ pReverb->m_nCosIncrement = 0;
+
+ // set delay tap lengths
+ nOffset = ReverbCalculateNoise(pReverb);
+
+ pReverb->m_zD1Cross = pReverb->m_nDelay1Out - pReverb->m_nMaxExcursion
+ + nOffset;
+
+ nOffset = ReverbCalculateNoise(pReverb);
+
+ pReverb->m_zD0Cross = pReverb->m_nDelay0Out - pReverb->m_nMaxExcursion
+ - nOffset;
+
+ nOffset = ReverbCalculateNoise(pReverb);
+
+ pReverb->m_zD0Self = pReverb->m_nDelay0Out - pReverb->m_nMaxExcursion
+ - nOffset;
+
+ nOffset = ReverbCalculateNoise(pReverb);
+
+ pReverb->m_zD1Self = pReverb->m_nDelay1Out - pReverb->m_nMaxExcursion
+ + nOffset;
+}
+
+/*----------------------------------------------------------------------------
+ * Reverb_getParameter()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Get a Reverb parameter
+ *
+ * Inputs:
+ * pReverb - handle to instance data
+ * param - parameter
+ * pValue - pointer to variable to hold retrieved value
+ * pSize - pointer to value size: maximum size as input
+ *
+ * Outputs:
+ * *pValue updated with parameter value
+ * *pSize updated with actual value size
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+ */
+int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize,
+ void *pValue) {
+ int32_t *pValue32;
+ int16_t *pValue16;
+ t_reverb_properties *pProperties;
+ int32_t i;
+ int32_t temp;
+ int32_t temp2;
+ size_t size;
+
+ if (pReverb->m_Preset) {
+ if (param != REVERB_PARAM_PRESET || *pSize < sizeof(int16_t)) {
+ return -EINVAL;
+ }
+ size = sizeof(int16_t);
+ pValue16 = (int16_t *)pValue;
+ // REVERB_PRESET_NONE is mapped to bypass
+ if (pReverb->m_bBypass != 0) {
+ *pValue16 = (int16_t)REVERB_PRESET_NONE;
+ } else {
+ *pValue16 = (int16_t)(pReverb->m_nNextRoom + 1);
+ }
+ LOGV("get REVERB_PARAM_PRESET, preset %d", *pValue16);
+ } else {
+ switch (param) {
+ case REVERB_PARAM_ROOM_LEVEL:
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ case REVERB_PARAM_REVERB_LEVEL:
+ case REVERB_PARAM_DIFFUSION:
+ case REVERB_PARAM_DENSITY:
+ size = sizeof(int16_t);
+ break;
+
+ case REVERB_PARAM_BYPASS:
+ case REVERB_PARAM_DECAY_TIME:
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ case REVERB_PARAM_REVERB_DELAY:
+ size = sizeof(int32_t);
+ break;
+
+ case REVERB_PARAM_PROPERTIES:
+ size = sizeof(t_reverb_properties);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (*pSize < size) {
+ return -EINVAL;
+ }
+
+ pValue32 = (int32_t *) pValue;
+ pValue16 = (int16_t *) pValue;
+ pProperties = (t_reverb_properties *) pValue;
+
+ switch (param) {
+ case REVERB_PARAM_BYPASS:
+ *pValue32 = (int32_t) pReverb->m_bBypass;
+ break;
+
+ case REVERB_PARAM_PROPERTIES:
+ pValue16 = &pProperties->roomLevel;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_ROOM_LEVEL:
+ // Convert m_nRoomLpfFwd to millibels
+ temp = (pReverb->m_nRoomLpfFwd << 15)
+ / (32767 - pReverb->m_nRoomLpfFbk);
+ *pValue16 = Effects_Linear16ToMillibels(temp);
+
+ LOGV("get REVERB_PARAM_ROOM_LEVEL %d, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", *pValue16, temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+
+ if (param == REVERB_PARAM_ROOM_LEVEL) {
+ break;
+ }
+ pValue16 = &pProperties->roomHFLevel;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ // The ratio between linear gain at 0Hz and at 5000Hz for the room low pass is:
+ // (1 + a1) / sqrt(a1^2 + 2*C*a1 + 1) where:
+ // - a1 is minus the LP feedback gain: -pReverb->m_nRoomLpfFbk
+ // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
+
+ temp = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFbk);
+ LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 %d", temp);
+ temp2 = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nCosWT_5KHz)
+ << 1;
+ LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, 2 Cos a1 %d", temp2);
+ temp = 32767 + temp - temp2;
+ LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 + 2 Cos a1 + 1 %d", temp);
+ temp = Effects_Sqrt(temp) * 181;
+ LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, SQRT(a1^2 + 2 Cos a1 + 1) %d", temp);
+ temp = ((32767 - pReverb->m_nRoomLpfFbk) << 15) / temp;
+
+ LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+
+ *pValue16 = Effects_Linear16ToMillibels(temp);
+
+ if (param == REVERB_PARAM_ROOM_HF_LEVEL) {
+ break;
+ }
+ pValue32 = &pProperties->decayTime;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_DECAY_TIME:
+ // Calculate reverb feedback path gain
+ temp = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
+ temp = Effects_Linear16ToMillibels(temp);
+
+ // Calculate decay time: g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
+ temp = (-6000 * pReverb->m_nLateDelay) / temp;
+
+ // Convert samples to ms
+ *pValue32 = (temp * 1000) / pReverb->m_nSamplingRate;
+
+ LOGV("get REVERB_PARAM_DECAY_TIME, samples %d, ms %d", temp, *pValue32);
+
+ if (param == REVERB_PARAM_DECAY_TIME) {
+ break;
+ }
+ pValue16 = &pProperties->decayHFRatio;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ // If r is the decay HF ratio (r = REVERB_PARAM_DECAY_HF_RATIO/1000) we have:
+ // DT_5000Hz = DT_0Hz * r
+ // and G_5000Hz = -6000 * d / DT_5000Hz and G_0Hz = -6000 * d / DT_0Hz in millibels so :
+ // r = G_0Hz/G_5000Hz in millibels
+ // The linear gain at 5000Hz is b0 / sqrt(a1^2 + 2*C*a1 + 1) where:
+ // - a1 is minus the LP feedback gain: -pReverb->m_nRvbLpfFbk
+ // - b0 is the LP forward gain: pReverb->m_nRvbLpfFwd
+ // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
+ if (pReverb->m_nRvbLpfFbk == 0) {
+ *pValue16 = 1000;
+ LOGV("get REVERB_PARAM_DECAY_HF_RATIO, pReverb->m_nRvbLpfFbk == 0, ratio %d", *pValue16);
+ } else {
+ temp = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFbk);
+ temp2 = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nCosWT_5KHz)
+ << 1;
+ temp = 32767 + temp - temp2;
+ temp = Effects_Sqrt(temp) * 181;
+ temp = (pReverb->m_nRvbLpfFwd << 15) / temp;
+ // The linear gain at 0Hz is b0 / (a1 + 1)
+ temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767
+ - pReverb->m_nRvbLpfFbk);
+
+ temp = Effects_Linear16ToMillibels(temp);
+ temp2 = Effects_Linear16ToMillibels(temp2);
+ LOGV("get REVERB_PARAM_DECAY_HF_RATIO, gain 5KHz %d mB, gain DC %d mB", temp, temp2);
+
+ if (temp == 0)
+ temp = 1;
+ temp = (int16_t) ((1000 * temp2) / temp);
+ if (temp > 1000)
+ temp = 1000;
+
+ *pValue16 = temp;
+ LOGV("get REVERB_PARAM_DECAY_HF_RATIO, ratio %d", *pValue16);
+ }
+
+ if (param == REVERB_PARAM_DECAY_HF_RATIO) {
+ break;
+ }
+ pValue16 = &pProperties->reflectionsLevel;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nEarlyGain);
+
+ LOGV("get REVERB_PARAM_REFLECTIONS_LEVEL, %d", *pValue16);
+ if (param == REVERB_PARAM_REFLECTIONS_LEVEL) {
+ break;
+ }
+ pValue32 = &pProperties->reflectionsDelay;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ // convert samples to ms
+ *pValue32 = (pReverb->m_nEarlyDelay * 1000) / pReverb->m_nSamplingRate;
+
+ LOGV("get REVERB_PARAM_REFLECTIONS_DELAY, samples %d, ms %d", pReverb->m_nEarlyDelay, *pValue32);
+
+ if (param == REVERB_PARAM_REFLECTIONS_DELAY) {
+ break;
+ }
+ pValue16 = &pProperties->reverbLevel;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_REVERB_LEVEL:
+ // Convert linear gain to millibels
+ *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nLateGain << 2);
+
+ LOGV("get REVERB_PARAM_REVERB_LEVEL %d", *pValue16);
+
+ if (param == REVERB_PARAM_REVERB_LEVEL) {
+ break;
+ }
+ pValue32 = &pProperties->reverbDelay;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_REVERB_DELAY:
+ // convert samples to ms
+ *pValue32 = (pReverb->m_nLateDelay * 1000) / pReverb->m_nSamplingRate;
+
+ LOGV("get REVERB_PARAM_REVERB_DELAY, samples %d, ms %d", pReverb->m_nLateDelay, *pValue32);
+
+ if (param == REVERB_PARAM_REVERB_DELAY) {
+ break;
+ }
+ pValue16 = &pProperties->diffusion;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_DIFFUSION:
+ temp = (int16_t) ((1000 * (pReverb->m_sAp0.m_nApGain - AP0_GAIN_BASE))
+ / AP0_GAIN_RANGE);
+
+ if (temp < 0)
+ temp = 0;
+ if (temp > 1000)
+ temp = 1000;
+
+ *pValue16 = temp;
+ LOGV("get REVERB_PARAM_DIFFUSION, %d, AP0 gain %d", *pValue16, pReverb->m_sAp0.m_nApGain);
+
+ if (param == REVERB_PARAM_DIFFUSION) {
+ break;
+ }
+ pValue16 = &pProperties->density;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_DENSITY:
+ // Calculate AP delay in time units
+ temp = ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn) << 16)
+ / pReverb->m_nSamplingRate;
+
+ temp = (int16_t) ((1000 * (temp - AP0_TIME_BASE)) / AP0_TIME_RANGE);
+
+ if (temp < 0)
+ temp = 0;
+ if (temp > 1000)
+ temp = 1000;
+
+ *pValue16 = temp;
+
+ LOGV("get REVERB_PARAM_DENSITY, %d, AP0 delay smps %d", *pValue16, pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ *pSize = size;
+
+ LOGV("Reverb_getParameter, context %p, param %d, value %d",
+ pReverb, param, *(int *)pValue);
+
+ return 0;
+} /* end Reverb_getParameter */
+
+/*----------------------------------------------------------------------------
+ * Reverb_setParameter()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Set a Reverb parameter
+ *
+ * Inputs:
+ * pReverb - handle to instance data
+ * param - parameter
+ * pValue - pointer to parameter value
+ * size - value size
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+ */
+int Reverb_setParameter(reverb_object_t *pReverb, int32_t param, size_t size,
+ void *pValue) {
+ int32_t value32;
+ int16_t value16;
+ t_reverb_properties *pProperties;
+ int32_t i;
+ int32_t temp;
+ int32_t temp2;
+ reverb_preset_t *pPreset;
+ int maxSamples;
+ int32_t averageDelay;
+ size_t paramSize;
+
+ LOGV("Reverb_setParameter, context %p, param %d, value16 %d, value32 %d",
+ pReverb, param, *(int16_t *)pValue, *(int32_t *)pValue);
+
+ if (pReverb->m_Preset) {
+ if (param != REVERB_PARAM_PRESET || size != sizeof(int16_t)) {
+ return -EINVAL;
+ }
+ value16 = *(int16_t *)pValue;
+ LOGV("set REVERB_PARAM_PRESET, preset %d", value16);
+ if (value16 < REVERB_PRESET_NONE || value16 > REVERB_PRESET_PLATE) {
+ return -EINVAL;
+ }
+ // REVERB_PRESET_NONE is mapped to bypass
+ if (value16 == REVERB_PRESET_NONE) {
+ pReverb->m_bBypass = 1;
+ } else {
+ pReverb->m_bBypass = 0;
+ pReverb->m_nNextRoom = value16 - 1;
+ }
+ } else {
+ switch (param) {
+ case REVERB_PARAM_ROOM_LEVEL:
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+ case REVERB_PARAM_DECAY_HF_RATIO:
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ case REVERB_PARAM_REVERB_LEVEL:
+ case REVERB_PARAM_DIFFUSION:
+ case REVERB_PARAM_DENSITY:
+ paramSize = sizeof(int16_t);
+ break;
+
+ case REVERB_PARAM_BYPASS:
+ case REVERB_PARAM_DECAY_TIME:
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ case REVERB_PARAM_REVERB_DELAY:
+ paramSize = sizeof(int32_t);
+ break;
+
+ case REVERB_PARAM_PROPERTIES:
+ paramSize = sizeof(t_reverb_properties);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (size != paramSize) {
+ return -EINVAL;
+ }
+
+ if (paramSize == sizeof(int16_t)) {
+ value16 = *(int16_t *) pValue;
+ } else if (paramSize == sizeof(int32_t)) {
+ value32 = *(int32_t *) pValue;
+ } else {
+ pProperties = (t_reverb_properties *) pValue;
+ }
+
+ pPreset = &pReverb->m_sPreset.m_sPreset[pReverb->m_nNextRoom];
+
+ switch (param) {
+ case REVERB_PARAM_BYPASS:
+ pReverb->m_bBypass = (uint16_t)value32;
+ break;
+
+ case REVERB_PARAM_PROPERTIES:
+ value16 = pProperties->roomLevel;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_ROOM_LEVEL:
+ // Convert millibels to linear 16 bit signed => m_nRoomLpfFwd
+ if (value16 > 0)
+ return -EINVAL;
+
+ temp = Effects_MillibelsToLinear16(value16);
+
+ pReverb->m_nRoomLpfFwd
+ = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRoomLpfFbk));
+
+ LOGV("REVERB_PARAM_ROOM_LEVEL, gain %d, new m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+ if (param == REVERB_PARAM_ROOM_LEVEL)
+ break;
+ value16 = pProperties->roomHFLevel;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_ROOM_HF_LEVEL:
+
+ // Limit to 0 , -40dB range because of low pass implementation
+ if (value16 > 0 || value16 < -4000)
+ return -EINVAL;
+ // Convert attenuation @ 5000H expressed in millibels to => m_nRoomLpfFbk
+ // m_nRoomLpfFbk is -a1 where a1 is the solution of:
+ // a1^2 + 2*(C-dG^2)/(1-dG^2)*a1 + 1 = 0 where:
+ // - C is cos(2*pi*5000/Fs) (pReverb->m_nCosWT_5KHz)
+ // - dG is G0/Gf (G0 is the linear gain at DC and Gf is the wanted gain at 5000Hz)
+
+ // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
+ // while changing HF level
+ temp2 = (pReverb->m_nRoomLpfFwd << 15) / (32767
+ - pReverb->m_nRoomLpfFbk);
+ if (value16 == 0) {
+ pReverb->m_nRoomLpfFbk = 0;
+ } else {
+ int32_t dG2, b, delta;
+
+ // dG^2
+ temp = Effects_MillibelsToLinear16(value16);
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, HF gain %d", temp);
+ temp = (1 << 30) / temp;
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain %d", temp);
+ dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain ^ 2 %d", dG2);
+ // b = 2*(C-dG^2)/(1-dG^2)
+ b = (int32_t) ((((int64_t) 1 << (15 + 1))
+ * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
+ / ((int64_t) 32767 - (int64_t) dG2));
+
+ // delta = b^2 - 4
+ delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
+ + 2)));
+
+ LOGV_IF(delta > (1<<30), " delta overflow %d", delta);
+
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, dG2 %d, b %d, delta %d, m_nCosWT_5KHz %d", dG2, b, delta, pReverb->m_nCosWT_5KHz);
+ // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
+ pReverb->m_nRoomLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+ }
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, olg DC gain %d new m_nRoomLpfFbk %d, old m_nRoomLpfFwd %d",
+ temp2, pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFwd);
+
+ pReverb->m_nRoomLpfFwd
+ = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRoomLpfFbk));
+ LOGV("REVERB_PARAM_ROOM_HF_LEVEL, new m_nRoomLpfFwd %d", pReverb->m_nRoomLpfFwd);
+
+ if (param == REVERB_PARAM_ROOM_HF_LEVEL)
+ break;
+ value32 = pProperties->decayTime;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_DECAY_TIME:
+
+ // Convert milliseconds to => m_nRvbLpfFwd (function of m_nRvbLpfFbk)
+ // convert ms to samples
+ value32 = (value32 * pReverb->m_nSamplingRate) / 1000;
+
+ // calculate valid decay time range as a function of current reverb delay and
+ // max feed back gain. Min value <=> -40dB in one pass, Max value <=> feedback gain = -1 dB
+ // Calculate attenuation for each round in late reverb given a total attenuation of -6000 millibels.
+ // g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
+ averageDelay = pReverb->m_nLateDelay - pReverb->m_nMaxExcursion;
+ averageDelay += ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn)
+ + (pReverb->m_sAp1.m_zApOut - pReverb->m_sAp1.m_zApIn)) >> 1;
+
+ temp = (-6000 * averageDelay) / value32;
+ LOGV("REVERB_PARAM_DECAY_TIME, delay smps %d, DT smps %d, gain mB %d",averageDelay, value32, temp);
+ if (temp < -4000 || temp > -100)
+ return -EINVAL;
+
+ // calculate low pass gain by adding reverb input attenuation (pReverb->m_nLateGain) and substrating output
+ // xfade and sum gain (max +9dB)
+ temp -= Effects_Linear16ToMillibels(pReverb->m_nLateGain) + 900;
+ temp = Effects_MillibelsToLinear16(temp);
+
+ // DC gain (temp) = b0 / (1 + a1) = pReverb->m_nRvbLpfFwd / (32767 - pReverb->m_nRvbLpfFbk)
+ pReverb->m_nRvbLpfFwd
+ = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRvbLpfFbk));
+
+ LOGV("REVERB_PARAM_DECAY_TIME, gain %d, new m_nRvbLpfFwd %d, old m_nRvbLpfFbk %d, reverb gain %d", temp, pReverb->m_nRvbLpfFwd, pReverb->m_nRvbLpfFbk, Effects_Linear16ToMillibels(pReverb->m_nLateGain));
+
+ if (param == REVERB_PARAM_DECAY_TIME)
+ break;
+ value16 = pProperties->decayHFRatio;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_DECAY_HF_RATIO:
+
+ // We limit max value to 1000 because reverb filter is lowpass only
+ if (value16 < 100 || value16 > 1000)
+ return -EINVAL;
+ // Convert per mille to => m_nLpfFwd, m_nLpfFbk
+
+ // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
+ // while changing HF level
+ temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
+
+ if (value16 == 1000) {
+ pReverb->m_nRvbLpfFbk = 0;
+ } else {
+ int32_t dG2, b, delta;
+
+ temp = Effects_Linear16ToMillibels(temp2);
+ // G_5000Hz = G_DC * (1000/REVERB_PARAM_DECAY_HF_RATIO) in millibels
+
+ value32 = ((int32_t) 1000 << 15) / (int32_t) value16;
+ LOGV("REVERB_PARAM_DECAY_HF_RATIO, DC gain %d, DC gain mB %d, 1000/R %d", temp2, temp, value32);
+
+ temp = (int32_t) (((int64_t) temp * (int64_t) value32) >> 15);
+
+ if (temp < -4000) {
+ LOGV("REVERB_PARAM_DECAY_HF_RATIO HF gain overflow %d mB", temp);
+ temp = -4000;
+ }
+
+ temp = Effects_MillibelsToLinear16(temp);
+ LOGV("REVERB_PARAM_DECAY_HF_RATIO, HF gain %d", temp);
+ // dG^2
+ temp = (temp2 << 15) / temp;
+ dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+
+ // b = 2*(C-dG^2)/(1-dG^2)
+ b = (int32_t) ((((int64_t) 1 << (15 + 1))
+ * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
+ / ((int64_t) 32767 - (int64_t) dG2));
+
+ // delta = b^2 - 4
+ delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
+ + 2)));
+
+ // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
+ pReverb->m_nRvbLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+
+ LOGV("REVERB_PARAM_DECAY_HF_RATIO, dG2 %d, b %d, delta %d", dG2, b, delta);
+
+ }
+
+ LOGV("REVERB_PARAM_DECAY_HF_RATIO, gain %d, m_nRvbLpfFbk %d, m_nRvbLpfFwd %d", temp2, pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFwd);
+
+ pReverb->m_nRvbLpfFwd
+ = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRvbLpfFbk));
+
+ if (param == REVERB_PARAM_DECAY_HF_RATIO)
+ break;
+ value16 = pProperties->reflectionsLevel;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_REFLECTIONS_LEVEL:
+ // We limit max value to 0 because gain is limited to 0dB
+ if (value16 > 0 || value16 < -6000)
+ return -EINVAL;
+
+ // Convert millibels to linear 16 bit signed and recompute m_sEarlyL.m_nGain[i] and m_sEarlyR.m_nGain[i].
+ value16 = Effects_MillibelsToLinear16(value16);
+ for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+ pReverb->m_sEarlyL.m_nGain[i]
+ = MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],value16);
+ pReverb->m_sEarlyR.m_nGain[i]
+ = MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],value16);
+ }
+ pReverb->m_nEarlyGain = value16;
+ LOGV("REVERB_PARAM_REFLECTIONS_LEVEL, m_nEarlyGain %d", pReverb->m_nEarlyGain);
+
+ if (param == REVERB_PARAM_REFLECTIONS_LEVEL)
+ break;
+ value32 = pProperties->reflectionsDelay;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_REFLECTIONS_DELAY:
+ // We limit max value MAX_EARLY_TIME
+ // convert ms to time units
+ temp = (value32 * 65536) / 1000;
+ if (temp < 0 || temp > MAX_EARLY_TIME)
+ return -EINVAL;
+
+ maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
+ >> 16;
+ temp = (temp * pReverb->m_nSamplingRate) >> 16;
+ for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+ temp2 = temp + (((int32_t) pPreset->m_sEarlyL.m_zDelay[i]
+ * pReverb->m_nSamplingRate) >> 16);
+ if (temp2 > maxSamples)
+ temp2 = maxSamples;
+ pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp2;
+ temp2 = temp + (((int32_t) pPreset->m_sEarlyR.m_zDelay[i]
+ * pReverb->m_nSamplingRate) >> 16);
+ if (temp2 > maxSamples)
+ temp2 = maxSamples;
+ pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp2;
+ }
+ pReverb->m_nEarlyDelay = temp;
+
+ LOGV("REVERB_PARAM_REFLECTIONS_DELAY, m_nEarlyDelay smps %d max smp delay %d", pReverb->m_nEarlyDelay, maxSamples);
+
+ // Convert milliseconds to sample count => m_nEarlyDelay
+ if (param == REVERB_PARAM_REFLECTIONS_DELAY)
+ break;
+ value16 = pProperties->reverbLevel;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_REVERB_LEVEL:
+ // We limit max value to 0 because gain is limited to 0dB
+ if (value16 > 0 || value16 < -6000)
+ return -EINVAL;
+ // Convert millibels to linear 16 bits (gange 0 - 8191) => m_nLateGain.
+ pReverb->m_nLateGain = Effects_MillibelsToLinear16(value16) >> 2;
+
+ LOGV("REVERB_PARAM_REVERB_LEVEL, m_nLateGain %d", pReverb->m_nLateGain);
+
+ if (param == REVERB_PARAM_REVERB_LEVEL)
+ break;
+ value32 = pProperties->reverbDelay;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_REVERB_DELAY:
+ // We limit max value to MAX_DELAY_TIME
+ // convert ms to time units
+ temp = (value32 * 65536) / 1000;
+ if (temp < 0 || temp > MAX_DELAY_TIME)
+ return -EINVAL;
+
+ maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
+ >> 16;
+ temp = (temp * pReverb->m_nSamplingRate) >> 16;
+ if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
+ temp = maxSamples - pReverb->m_nMaxExcursion;
+ }
+ if (temp < pReverb->m_nMaxExcursion) {
+ temp = pReverb->m_nMaxExcursion;
+ }
+
+ temp -= pReverb->m_nLateDelay;
+ pReverb->m_nDelay0Out += temp;
+ pReverb->m_nDelay1Out += temp;
+ pReverb->m_nLateDelay += temp;
+
+ LOGV("REVERB_PARAM_REVERB_DELAY, m_nLateDelay smps %d max smp delay %d", pReverb->m_nLateDelay, maxSamples);
+
+ // Convert milliseconds to sample count => m_nDelay1Out + m_nMaxExcursion
+ if (param == REVERB_PARAM_REVERB_DELAY)
+ break;
+
+ value16 = pProperties->diffusion;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_DIFFUSION:
+ if (value16 < 0 || value16 > 1000)
+ return -EINVAL;
+
+ // Convert per mille to m_sAp0.m_nApGain, m_sAp1.m_nApGain
+ pReverb->m_sAp0.m_nApGain = AP0_GAIN_BASE + ((int32_t) value16
+ * AP0_GAIN_RANGE) / 1000;
+ pReverb->m_sAp1.m_nApGain = AP1_GAIN_BASE + ((int32_t) value16
+ * AP1_GAIN_RANGE) / 1000;
+
+ LOGV("REVERB_PARAM_DIFFUSION, m_sAp0.m_nApGain %d m_sAp1.m_nApGain %d", pReverb->m_sAp0.m_nApGain, pReverb->m_sAp1.m_nApGain);
+
+ if (param == REVERB_PARAM_DIFFUSION)
+ break;
+
+ value16 = pProperties->density;
+ /* FALL THROUGH */
+
+ case REVERB_PARAM_DENSITY:
+ if (value16 < 0 || value16 > 1000)
+ return -EINVAL;
+
+ // Convert per mille to m_sAp0.m_zApOut, m_sAp1.m_zApOut
+ maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
+
+ temp = AP0_TIME_BASE + ((int32_t) value16 * AP0_TIME_RANGE) / 1000;
+ /*lint -e{702} shift for performance */
+ temp = (temp * pReverb->m_nSamplingRate) >> 16;
+ if (temp > maxSamples)
+ temp = maxSamples;
+ pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
+
+ LOGV("REVERB_PARAM_DENSITY, Ap0 delay smps %d", temp);
+
+ temp = AP1_TIME_BASE + ((int32_t) value16 * AP1_TIME_RANGE) / 1000;
+ /*lint -e{702} shift for performance */
+ temp = (temp * pReverb->m_nSamplingRate) >> 16;
+ if (temp > maxSamples)
+ temp = maxSamples;
+ pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
+
+ LOGV("Ap1 delay smps %d", temp);
+
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return 0;
+} /* end Reverb_setParameter */
+
+/*----------------------------------------------------------------------------
+ * ReverbUpdateXfade
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Update the xfade parameters as required
+ *
+ * Inputs:
+ * nNumSamplesToAdd - number of samples to write to buffer
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ * - xfade parameters will be changed
+ *
+ *----------------------------------------------------------------------------
+ */
+static int ReverbUpdateXfade(reverb_object_t *pReverb, int nNumSamplesToAdd) {
+ uint16_t nOffset;
+ int16_t tempCos;
+ int16_t tempSin;
+
+ if (pReverb->m_nXfadeCounter >= pReverb->m_nXfadeInterval) {
+ /* update interval has elapsed, so reset counter */
+ pReverb->m_nXfadeCounter = 0;
+
+ // Pin the sin,cos values to min / max values to ensure that the
+ // modulated taps' coefs are zero (thus no clicks)
+ if (pReverb->m_nPhaseIncrement > 0) {
+ // if phase increment > 0, then sin -> 1, cos -> 0
+ pReverb->m_nSin = 32767;
+ pReverb->m_nCos = 0;
+
+ // reset the phase to match the sin, cos values
+ pReverb->m_nPhase = 32767;
+
+ // modulate the cross taps because their tap coefs are zero
+ nOffset = ReverbCalculateNoise(pReverb);
+
+ pReverb->m_zD1Cross = pReverb->m_nDelay1Out
+ - pReverb->m_nMaxExcursion + nOffset;
+
+ nOffset = ReverbCalculateNoise(pReverb);
+
+ pReverb->m_zD0Cross = pReverb->m_nDelay0Out
+ - pReverb->m_nMaxExcursion - nOffset;
+ } else {
+ // if phase increment < 0, then sin -> 0, cos -> 1
+ pReverb->m_nSin = 0;
+ pReverb->m_nCos = 32767;
+
+ // reset the phase to match the sin, cos values
+ pReverb->m_nPhase = -32768;
+
+ // modulate the self taps because their tap coefs are zero
+ nOffset = ReverbCalculateNoise(pReverb);
+
+ pReverb->m_zD0Self = pReverb->m_nDelay0Out
+ - pReverb->m_nMaxExcursion - nOffset;
+
+ nOffset = ReverbCalculateNoise(pReverb);
+
+ pReverb->m_zD1Self = pReverb->m_nDelay1Out
+ - pReverb->m_nMaxExcursion + nOffset;
+
+ } // end if-else (pReverb->m_nPhaseIncrement > 0)
+
+ // Reverse the direction of the sin,cos so that the
+ // tap whose coef was previously increasing now decreases
+ // and vice versa
+ pReverb->m_nPhaseIncrement = -pReverb->m_nPhaseIncrement;
+
+ } // end if counter >= update interval
+
+ //compute what phase will be next time
+ pReverb->m_nPhase += pReverb->m_nPhaseIncrement;
+
+ //calculate what the new sin and cos need to reach by the next update
+ ReverbCalculateSinCos(pReverb->m_nPhase, &tempSin, &tempCos);
+
+ //calculate the per-sample increment required to get there by the next update
+ /*lint -e{702} shift for performance */
+ pReverb->m_nSinIncrement = (tempSin - pReverb->m_nSin)
+ >> pReverb->m_nUpdatePeriodInBits;
+
+ /*lint -e{702} shift for performance */
+ pReverb->m_nCosIncrement = (tempCos - pReverb->m_nCos)
+ >> pReverb->m_nUpdatePeriodInBits;
+
+ /* increment update counter */
+ pReverb->m_nXfadeCounter += (uint16_t) nNumSamplesToAdd;
+
+ return 0;
+
+} /* end ReverbUpdateXfade */
+
+/*----------------------------------------------------------------------------
+ * ReverbCalculateNoise
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Calculate a noise sample and limit its value
+ *
+ * Inputs:
+ * nMaxExcursion - noise value is limited to this value
+ * pnNoise - return new noise sample in this (not limited)
+ *
+ * Outputs:
+ * new limited noise value
+ *
+ * Side Effects:
+ * - *pnNoise noise value is updated
+ *
+ *----------------------------------------------------------------------------
+ */
+static uint16_t ReverbCalculateNoise(reverb_object_t *pReverb) {
+ int16_t nNoise = pReverb->m_nNoise;
+
+ // calculate new noise value
+ if (pReverb->m_bUseNoise) {
+ nNoise = (int16_t) (nNoise * 5 + 1);
+ } else {
+ nNoise = 0;
+ }
+
+ pReverb->m_nNoise = nNoise;
+ // return the limited noise value
+ return (pReverb->m_nMaxExcursion & nNoise);
+
+} /* end ReverbCalculateNoise */
+
+/*----------------------------------------------------------------------------
+ * ReverbCalculateSinCos
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Calculate a new sin and cosine value based on the given phase
+ *
+ * Inputs:
+ * nPhase - phase angle
+ * pnSin - input old value, output new value
+ * pnCos - input old value, output new value
+ *
+ * Outputs:
+ *
+ * Side Effects:
+ * - *pnSin, *pnCos are updated
+ *
+ *----------------------------------------------------------------------------
+ */
+static int ReverbCalculateSinCos(int16_t nPhase, int16_t *pnSin, int16_t *pnCos) {
+ int32_t nTemp;
+ int32_t nNetAngle;
+
+ // -1 <= nPhase < 1
+ // However, for the calculation, we need a value
+ // that ranges from -1/2 to +1/2, so divide the phase by 2
+ /*lint -e{702} shift for performance */
+ nNetAngle = nPhase >> 1;
+
+ /*
+ Implement the following
+ sin(x) = (2-4*c)*x^2 + c + x
+ cos(x) = (2-4*c)*x^2 + c - x
+
+ where c = 1/sqrt(2)
+ using the a0 + x*(a1 + x*a2) approach
+ */
+
+ /* limit the input "angle" to be between -0.5 and +0.5 */
+ if (nNetAngle > EG1_HALF) {
+ nNetAngle = EG1_HALF;
+ } else if (nNetAngle < EG1_MINUS_HALF) {
+ nNetAngle = EG1_MINUS_HALF;
+ }
+
+ /* calculate sin */
+ nTemp = EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle);
+ nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle);
+ *pnSin = (int16_t) SATURATE_EG1(nTemp);
+
+ /* calculate cos */
+ nTemp = -EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle);
+ nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle);
+ *pnCos = (int16_t) SATURATE_EG1(nTemp);
+
+ return 0;
+} /* end ReverbCalculateSinCos */
+
+/*----------------------------------------------------------------------------
+ * Reverb
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * apply reverb to the given signal
+ *
+ * Inputs:
+ * nNu
+ * pnSin - input old value, output new value
+ * pnCos - input old value, output new value
+ *
+ * Outputs:
+ * number of samples actually reverberated
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+ */
+static int Reverb(reverb_object_t *pReverb, int nNumSamplesToAdd,
+ short *pOutputBuffer, short *pInputBuffer) {
+ int32_t i;
+ int32_t nDelayOut0;
+ int32_t nDelayOut1;
+ uint16_t nBase;
+
+ uint32_t nAddr;
+ int32_t nTemp1;
+ int32_t nTemp2;
+ int32_t nApIn;
+ int32_t nApOut;
+
+ int32_t j;
+ int32_t nEarlyOut;
+
+ int32_t tempValue;
+
+ // get the base address
+ nBase = pReverb->m_nBaseIndex;
+
+ for (i = 0; i < nNumSamplesToAdd; i++) {
+ // ********** Left Allpass - start
+ nApIn = *pInputBuffer;
+ if (!pReverb->m_Aux) {
+ pInputBuffer++;
+ }
+ // store to early delay line
+ nAddr = CIRCULAR(nBase, pReverb->m_nEarly0in, pReverb->m_nBufferMask);
+ pReverb->m_nDelayLine[nAddr] = (short) nApIn;
+
+ // left input = (left dry * m_nLateGain) + right feedback from previous period
+
+ nApIn = SATURATE(nApIn + pReverb->m_nRevFbkR);
+ nApIn = MULT_EG1_EG1(nApIn, pReverb->m_nLateGain);
+
+ // fetch allpass delay line out
+ //nAddr = CIRCULAR(nBase, psAp0->m_zApOut, pReverb->m_nBufferMask);
+ nAddr
+ = CIRCULAR(nBase, pReverb->m_sAp0.m_zApOut, pReverb->m_nBufferMask);
+ nDelayOut0 = pReverb->m_nDelayLine[nAddr];
+
+ // calculate allpass feedforward; subtract the feedforward result
+ nTemp1 = MULT_EG1_EG1(nApIn, pReverb->m_sAp0.m_nApGain);
+ nApOut = SATURATE(nDelayOut0 - nTemp1); // allpass output
+
+ // calculate allpass feedback; add the feedback result
+ nTemp1 = MULT_EG1_EG1(nApOut, pReverb->m_sAp0.m_nApGain);
+ nTemp1 = SATURATE(nApIn + nTemp1);
+
+ // inject into allpass delay
+ nAddr
+ = CIRCULAR(nBase, pReverb->m_sAp0.m_zApIn, pReverb->m_nBufferMask);
+ pReverb->m_nDelayLine[nAddr] = (short) nTemp1;
+
+ // inject allpass output into delay line
+ nAddr = CIRCULAR(nBase, pReverb->m_zD0In, pReverb->m_nBufferMask);
+ pReverb->m_nDelayLine[nAddr] = (short) nApOut;
+
+ // ********** Left Allpass - end
+
+ // ********** Right Allpass - start
+ nApIn = (*pInputBuffer++);
+ // store to early delay line
+ nAddr = CIRCULAR(nBase, pReverb->m_nEarly1in, pReverb->m_nBufferMask);
+ pReverb->m_nDelayLine[nAddr] = (short) nApIn;
+
+ // right input = (right dry * m_nLateGain) + left feedback from previous period
+ /*lint -e{702} use shift for performance */
+ nApIn = SATURATE(nApIn + pReverb->m_nRevFbkL);
+ nApIn = MULT_EG1_EG1(nApIn, pReverb->m_nLateGain);
+
+ // fetch allpass delay line out
+ nAddr
+ = CIRCULAR(nBase, pReverb->m_sAp1.m_zApOut, pReverb->m_nBufferMask);
+ nDelayOut1 = pReverb->m_nDelayLine[nAddr];
+
+ // calculate allpass feedforward; subtract the feedforward result
+ nTemp1 = MULT_EG1_EG1(nApIn, pReverb->m_sAp1.m_nApGain);
+ nApOut = SATURATE(nDelayOut1 - nTemp1); // allpass output
+
+ // calculate allpass feedback; add the feedback result
+ nTemp1 = MULT_EG1_EG1(nApOut, pReverb->m_sAp1.m_nApGain);
+ nTemp1 = SATURATE(nApIn + nTemp1);
+
+ // inject into allpass delay
+ nAddr
+ = CIRCULAR(nBase, pReverb->m_sAp1.m_zApIn, pReverb->m_nBufferMask);
+ pReverb->m_nDelayLine[nAddr] = (short) nTemp1;
+
+ // inject allpass output into delay line
+ nAddr = CIRCULAR(nBase, pReverb->m_zD1In, pReverb->m_nBufferMask);
+ pReverb->m_nDelayLine[nAddr] = (short) nApOut;
+
+ // ********** Right Allpass - end
+
+ // ********** D0 output - start
+ // fetch delay line self out
+ nAddr = CIRCULAR(nBase, pReverb->m_zD0Self, pReverb->m_nBufferMask);
+ nDelayOut0 = pReverb->m_nDelayLine[nAddr];
+
+ // calculate delay line self out
+ nTemp1 = MULT_EG1_EG1(nDelayOut0, pReverb->m_nSin);
+
+ // fetch delay line cross out
+ nAddr = CIRCULAR(nBase, pReverb->m_zD1Cross, pReverb->m_nBufferMask);
+ nDelayOut0 = pReverb->m_nDelayLine[nAddr];
+
+ // calculate delay line self out
+ nTemp2 = MULT_EG1_EG1(nDelayOut0, pReverb->m_nCos);
+
+ // calculate unfiltered delay out
+ nDelayOut0 = SATURATE(nTemp1 + nTemp2);
+
+ // ********** D0 output - end
+
+ // ********** D1 output - start
+ // fetch delay line self out
+ nAddr = CIRCULAR(nBase, pReverb->m_zD1Self, pReverb->m_nBufferMask);
+ nDelayOut1 = pReverb->m_nDelayLine[nAddr];
+
+ // calculate delay line self out
+ nTemp1 = MULT_EG1_EG1(nDelayOut1, pReverb->m_nSin);
+
+ // fetch delay line cross out
+ nAddr = CIRCULAR(nBase, pReverb->m_zD0Cross, pReverb->m_nBufferMask);
+ nDelayOut1 = pReverb->m_nDelayLine[nAddr];
+
+ // calculate delay line self out
+ nTemp2 = MULT_EG1_EG1(nDelayOut1, pReverb->m_nCos);
+
+ // calculate unfiltered delay out
+ nDelayOut1 = SATURATE(nTemp1 + nTemp2);
+
+ // ********** D1 output - end
+
+ // ********** mixer and feedback - start
+ // sum is fedback to right input (R + L)
+ nDelayOut0 = (short) SATURATE(nDelayOut0 + nDelayOut1);
+
+ // difference is feedback to left input (R - L)
+ /*lint -e{685} lint complains that it can't saturate negative */
+ nDelayOut1 = (short) SATURATE(nDelayOut1 - nDelayOut0);
+
+ // ********** mixer and feedback - end
+
+ // calculate lowpass filter (mixer scale factor included in LPF feedforward)
+ nTemp1 = MULT_EG1_EG1(nDelayOut0, pReverb->m_nRvbLpfFwd);
+
+ nTemp2 = MULT_EG1_EG1(pReverb->m_nRevFbkL, pReverb->m_nRvbLpfFbk);
+
+ // calculate filtered delay out and simultaneously update LPF state variable
+ // filtered delay output is stored in m_nRevFbkL
+ pReverb->m_nRevFbkL = (short) SATURATE(nTemp1 + nTemp2);
+
+ // calculate lowpass filter (mixer scale factor included in LPF feedforward)
+ nTemp1 = MULT_EG1_EG1(nDelayOut1, pReverb->m_nRvbLpfFwd);
+
+ nTemp2 = MULT_EG1_EG1(pReverb->m_nRevFbkR, pReverb->m_nRvbLpfFbk);
+
+ // calculate filtered delay out and simultaneously update LPF state variable
+ // filtered delay output is stored in m_nRevFbkR
+ pReverb->m_nRevFbkR = (short) SATURATE(nTemp1 + nTemp2);
+
+ // ********** start early reflection generator, left
+ //psEarly = &(pReverb->m_sEarlyL);
+
+
+ for (j = 0; j < REVERB_MAX_NUM_REFLECTIONS; j++) {
+ // fetch delay line out
+ //nAddr = CIRCULAR(nBase, psEarly->m_zDelay[j], pReverb->m_nBufferMask);
+ nAddr
+ = CIRCULAR(nBase, pReverb->m_sEarlyL.m_zDelay[j], pReverb->m_nBufferMask);
+
+ nTemp1 = pReverb->m_nDelayLine[nAddr];
+
+ // calculate reflection
+ //nTemp1 = MULT_EG1_EG1(nDelayOut0, psEarly->m_nGain[j]);
+ nTemp1 = MULT_EG1_EG1(nTemp1, pReverb->m_sEarlyL.m_nGain[j]);
+
+ nDelayOut0 = SATURATE(nDelayOut0 + nTemp1);
+
+ } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++)
+
+ // apply lowpass to early reflections and reverb output
+ //nTemp1 = MULT_EG1_EG1(nEarlyOut, psEarly->m_nRvbLpfFwd);
+ nTemp1 = MULT_EG1_EG1(nDelayOut0, pReverb->m_nRoomLpfFwd);
+
+ //nTemp2 = MULT_EG1_EG1(psEarly->m_zLpf, psEarly->m_nLpfFbk);
+ nTemp2 = MULT_EG1_EG1(pReverb->m_zOutLpfL, pReverb->m_nRoomLpfFbk);
+
+ // calculate filtered out and simultaneously update LPF state variable
+ // filtered output is stored in m_zOutLpfL
+ pReverb->m_zOutLpfL = (short) SATURATE(nTemp1 + nTemp2);
+
+ //sum with output buffer
+ tempValue = *pOutputBuffer;
+ *pOutputBuffer++ = (short) SATURATE(tempValue+pReverb->m_zOutLpfL);
+
+ // ********** end early reflection generator, left
+
+ // ********** start early reflection generator, right
+ //psEarly = &(pReverb->m_sEarlyR);
+
+ for (j = 0; j < REVERB_MAX_NUM_REFLECTIONS; j++) {
+ // fetch delay line out
+ nAddr
+ = CIRCULAR(nBase, pReverb->m_sEarlyR.m_zDelay[j], pReverb->m_nBufferMask);
+ nTemp1 = pReverb->m_nDelayLine[nAddr];
+
+ // calculate reflection
+ nTemp1 = MULT_EG1_EG1(nTemp1, pReverb->m_sEarlyR.m_nGain[j]);
+
+ nDelayOut1 = SATURATE(nDelayOut1 + nTemp1);
+
+ } // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++)
+
+ // apply lowpass to early reflections
+ nTemp1 = MULT_EG1_EG1(nDelayOut1, pReverb->m_nRoomLpfFwd);
+
+ nTemp2 = MULT_EG1_EG1(pReverb->m_zOutLpfR, pReverb->m_nRoomLpfFbk);
+
+ // calculate filtered out and simultaneously update LPF state variable
+ // filtered output is stored in m_zOutLpfR
+ pReverb->m_zOutLpfR = (short) SATURATE(nTemp1 + nTemp2);
+
+ //sum with output buffer
+ tempValue = *pOutputBuffer;
+ *pOutputBuffer++ = (short) SATURATE(tempValue + pReverb->m_zOutLpfR);
+
+ // ********** end early reflection generator, right
+
+ // decrement base addr for next sample period
+ nBase--;
+
+ pReverb->m_nSin += pReverb->m_nSinIncrement;
+ pReverb->m_nCos += pReverb->m_nCosIncrement;
+
+ } // end for (i=0; i < nNumSamplesToAdd; i++)
+
+ // store the most up to date version
+ pReverb->m_nBaseIndex = nBase;
+
+ return 0;
+} /* end Reverb */
+
+/*----------------------------------------------------------------------------
+ * ReverbUpdateRoom
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Update the room's preset parameters as required
+ *
+ * Inputs:
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ * - reverb paramters (fbk, fwd, etc) will be changed
+ * - m_nCurrentRoom := m_nNextRoom
+ *----------------------------------------------------------------------------
+ */
+static int ReverbUpdateRoom(reverb_object_t *pReverb, bool fullUpdate) {
+ int temp;
+ int i;
+ int maxSamples;
+ int earlyDelay;
+ int earlyGain;
+
+ reverb_preset_t *pPreset =
+ &pReverb->m_sPreset.m_sPreset[pReverb->m_nNextRoom];
+
+ if (fullUpdate) {
+ pReverb->m_nRvbLpfFwd = pPreset->m_nRvbLpfFwd;
+ pReverb->m_nRvbLpfFbk = pPreset->m_nRvbLpfFbk;
+
+ pReverb->m_nEarlyGain = pPreset->m_nEarlyGain;
+ //stored as time based, convert to sample based
+ pReverb->m_nLateGain = pPreset->m_nLateGain;
+ pReverb->m_nRoomLpfFbk = pPreset->m_nRoomLpfFbk;
+ pReverb->m_nRoomLpfFwd = pPreset->m_nRoomLpfFwd;
+
+ // set the early reflections gains
+ earlyGain = pPreset->m_nEarlyGain;
+ for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+ pReverb->m_sEarlyL.m_nGain[i]
+ = MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],earlyGain);
+ pReverb->m_sEarlyR.m_nGain[i]
+ = MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],earlyGain);
+ }
+
+ pReverb->m_nMaxExcursion = pPreset->m_nMaxExcursion;
+
+ pReverb->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain;
+ pReverb->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain;
+
+ // set the early reflections delay
+ earlyDelay = ((int) pPreset->m_nEarlyDelay * pReverb->m_nSamplingRate)
+ >> 16;
+ pReverb->m_nEarlyDelay = earlyDelay;
+ maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
+ >> 16;
+ for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+ //stored as time based, convert to sample based
+ temp = earlyDelay + (((int) pPreset->m_sEarlyL.m_zDelay[i]
+ * pReverb->m_nSamplingRate) >> 16);
+ if (temp > maxSamples)
+ temp = maxSamples;
+ pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp;
+ //stored as time based, convert to sample based
+ temp = earlyDelay + (((int) pPreset->m_sEarlyR.m_zDelay[i]
+ * pReverb->m_nSamplingRate) >> 16);
+ if (temp > maxSamples)
+ temp = maxSamples;
+ pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp;
+ }
+
+ maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
+ >> 16;
+ //stored as time based, convert to sample based
+ /*lint -e{702} shift for performance */
+ temp = (pPreset->m_nLateDelay * pReverb->m_nSamplingRate) >> 16;
+ if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
+ temp = maxSamples - pReverb->m_nMaxExcursion;
+ }
+ temp -= pReverb->m_nLateDelay;
+ pReverb->m_nDelay0Out += temp;
+ pReverb->m_nDelay1Out += temp;
+ pReverb->m_nLateDelay += temp;
+
+ maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
+ //stored as time based, convert to absolute sample value
+ temp = pPreset->m_nAp0_ApOut;
+ /*lint -e{702} shift for performance */
+ temp = (temp * pReverb->m_nSamplingRate) >> 16;
+ if (temp > maxSamples)
+ temp = maxSamples;
+ pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
+
+ //stored as time based, convert to absolute sample value
+ temp = pPreset->m_nAp1_ApOut;
+ /*lint -e{702} shift for performance */
+ temp = (temp * pReverb->m_nSamplingRate) >> 16;
+ if (temp > maxSamples)
+ temp = maxSamples;
+ pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
+ //gpsReverbObject->m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut;
+ }
+
+ //stored as time based, convert to sample based
+ temp = pPreset->m_nXfadeInterval;
+ /*lint -e{702} shift for performance */
+ temp = (temp * pReverb->m_nSamplingRate) >> 16;
+ pReverb->m_nXfadeInterval = (uint16_t) temp;
+ //gsReverbObject.m_nXfadeInterval = pPreset->m_nXfadeInterval;
+ pReverb->m_nXfadeCounter = pReverb->m_nXfadeInterval + 1; // force update on first iteration
+
+ pReverb->m_nCurrentRoom = pReverb->m_nNextRoom;
+
+ return 0;
+
+} /* end ReverbUpdateRoom */
+
+/*----------------------------------------------------------------------------
+ * ReverbReadInPresets()
+ *----------------------------------------------------------------------------
+ * Purpose: sets global reverb preset bank to defaults
+ *
+ * Inputs:
+ *
+ * Outputs:
+ *
+ *----------------------------------------------------------------------------
+ */
+static int ReverbReadInPresets(reverb_object_t *pReverb) {
+
+ int preset;
+
+ // this is for test only. OpenSL ES presets are mapped to 4 presets.
+ // REVERB_PRESET_NONE is mapped to bypass
+ for (preset = 0; preset < REVERB_NUM_PRESETS; preset++) {
+ reverb_preset_t *pPreset = &pReverb->m_sPreset.m_sPreset[preset];
+ switch (preset + 1) {
+ case REVERB_PRESET_PLATE:
+ case REVERB_PRESET_SMALLROOM:
+ pPreset->m_nRvbLpfFbk = 5077;
+ pPreset->m_nRvbLpfFwd = 11076;
+ pPreset->m_nEarlyGain = 27690;
+ pPreset->m_nEarlyDelay = 1311;
+ pPreset->m_nLateGain = 8191;
+ pPreset->m_nLateDelay = 3932;
+ pPreset->m_nRoomLpfFbk = 3692;
+ pPreset->m_nRoomLpfFwd = 20474;
+ pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+ pPreset->m_sEarlyL.m_nGain[0] = 22152;
+ pPreset->m_sEarlyL.m_zDelay[1] = 1462;
+ pPreset->m_sEarlyL.m_nGain[1] = 17537;
+ pPreset->m_sEarlyL.m_zDelay[2] = 0;
+ pPreset->m_sEarlyL.m_nGain[2] = 14768;
+ pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+ pPreset->m_sEarlyL.m_nGain[3] = 14307;
+ pPreset->m_sEarlyL.m_zDelay[4] = 0;
+ pPreset->m_sEarlyL.m_nGain[4] = 13384;
+ pPreset->m_sEarlyR.m_zDelay[0] = 721;
+ pPreset->m_sEarlyR.m_nGain[0] = 20306;
+ pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+ pPreset->m_sEarlyR.m_nGain[1] = 17537;
+ pPreset->m_sEarlyR.m_zDelay[2] = 0;
+ pPreset->m_sEarlyR.m_nGain[2] = 14768;
+ pPreset->m_sEarlyR.m_zDelay[3] = 0;
+ pPreset->m_sEarlyR.m_nGain[3] = 16153;
+ pPreset->m_sEarlyR.m_zDelay[4] = 0;
+ pPreset->m_sEarlyR.m_nGain[4] = 13384;
+ pPreset->m_nMaxExcursion = 127;
+ pPreset->m_nXfadeInterval = 6470; //6483;
+ pPreset->m_nAp0_ApGain = 14768;
+ pPreset->m_nAp0_ApOut = 792;
+ pPreset->m_nAp1_ApGain = 14777;
+ pPreset->m_nAp1_ApOut = 1191;
+ pPreset->m_rfu4 = 0;
+ pPreset->m_rfu5 = 0;
+ pPreset->m_rfu6 = 0;
+ pPreset->m_rfu7 = 0;
+ pPreset->m_rfu8 = 0;
+ pPreset->m_rfu9 = 0;
+ pPreset->m_rfu10 = 0;
+ break;
+ case REVERB_PRESET_MEDIUMROOM:
+ case REVERB_PRESET_LARGEROOM:
+ pPreset->m_nRvbLpfFbk = 5077;
+ pPreset->m_nRvbLpfFwd = 12922;
+ pPreset->m_nEarlyGain = 27690;
+ pPreset->m_nEarlyDelay = 1311;
+ pPreset->m_nLateGain = 8191;
+ pPreset->m_nLateDelay = 3932;
+ pPreset->m_nRoomLpfFbk = 3692;
+ pPreset->m_nRoomLpfFwd = 21703;
+ pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+ pPreset->m_sEarlyL.m_nGain[0] = 22152;
+ pPreset->m_sEarlyL.m_zDelay[1] = 1462;
+ pPreset->m_sEarlyL.m_nGain[1] = 17537;
+ pPreset->m_sEarlyL.m_zDelay[2] = 0;
+ pPreset->m_sEarlyL.m_nGain[2] = 14768;
+ pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+ pPreset->m_sEarlyL.m_nGain[3] = 14307;
+ pPreset->m_sEarlyL.m_zDelay[4] = 0;
+ pPreset->m_sEarlyL.m_nGain[4] = 13384;
+ pPreset->m_sEarlyR.m_zDelay[0] = 721;
+ pPreset->m_sEarlyR.m_nGain[0] = 20306;
+ pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+ pPreset->m_sEarlyR.m_nGain[1] = 17537;
+ pPreset->m_sEarlyR.m_zDelay[2] = 0;
+ pPreset->m_sEarlyR.m_nGain[2] = 14768;
+ pPreset->m_sEarlyR.m_zDelay[3] = 0;
+ pPreset->m_sEarlyR.m_nGain[3] = 16153;
+ pPreset->m_sEarlyR.m_zDelay[4] = 0;
+ pPreset->m_sEarlyR.m_nGain[4] = 13384;
+ pPreset->m_nMaxExcursion = 127;
+ pPreset->m_nXfadeInterval = 6449;
+ pPreset->m_nAp0_ApGain = 15691;
+ pPreset->m_nAp0_ApOut = 774;
+ pPreset->m_nAp1_ApGain = 16317;
+ pPreset->m_nAp1_ApOut = 1155;
+ pPreset->m_rfu4 = 0;
+ pPreset->m_rfu5 = 0;
+ pPreset->m_rfu6 = 0;
+ pPreset->m_rfu7 = 0;
+ pPreset->m_rfu8 = 0;
+ pPreset->m_rfu9 = 0;
+ pPreset->m_rfu10 = 0;
+ break;
+ case REVERB_PRESET_MEDIUMHALL:
+ pPreset->m_nRvbLpfFbk = 6461;
+ pPreset->m_nRvbLpfFwd = 14307;
+ pPreset->m_nEarlyGain = 27690;
+ pPreset->m_nEarlyDelay = 1311;
+ pPreset->m_nLateGain = 8191;
+ pPreset->m_nLateDelay = 3932;
+ pPreset->m_nRoomLpfFbk = 3692;
+ pPreset->m_nRoomLpfFwd = 24569;
+ pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+ pPreset->m_sEarlyL.m_nGain[0] = 22152;
+ pPreset->m_sEarlyL.m_zDelay[1] = 1462;
+ pPreset->m_sEarlyL.m_nGain[1] = 17537;
+ pPreset->m_sEarlyL.m_zDelay[2] = 0;
+ pPreset->m_sEarlyL.m_nGain[2] = 14768;
+ pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+ pPreset->m_sEarlyL.m_nGain[3] = 14307;
+ pPreset->m_sEarlyL.m_zDelay[4] = 0;
+ pPreset->m_sEarlyL.m_nGain[4] = 13384;
+ pPreset->m_sEarlyR.m_zDelay[0] = 721;
+ pPreset->m_sEarlyR.m_nGain[0] = 20306;
+ pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+ pPreset->m_sEarlyR.m_nGain[1] = 17537;
+ pPreset->m_sEarlyR.m_zDelay[2] = 0;
+ pPreset->m_sEarlyR.m_nGain[2] = 14768;
+ pPreset->m_sEarlyR.m_zDelay[3] = 0;
+ pPreset->m_sEarlyR.m_nGain[3] = 16153;
+ pPreset->m_sEarlyR.m_zDelay[4] = 0;
+ pPreset->m_sEarlyR.m_nGain[4] = 13384;
+ pPreset->m_nMaxExcursion = 127;
+ pPreset->m_nXfadeInterval = 6391;
+ pPreset->m_nAp0_ApGain = 15230;
+ pPreset->m_nAp0_ApOut = 708;
+ pPreset->m_nAp1_ApGain = 15547;
+ pPreset->m_nAp1_ApOut = 1023;
+ pPreset->m_rfu4 = 0;
+ pPreset->m_rfu5 = 0;
+ pPreset->m_rfu6 = 0;
+ pPreset->m_rfu7 = 0;
+ pPreset->m_rfu8 = 0;
+ pPreset->m_rfu9 = 0;
+ pPreset->m_rfu10 = 0;
+ break;
+ case REVERB_PRESET_LARGEHALL:
+ pPreset->m_nRvbLpfFbk = 8307;
+ pPreset->m_nRvbLpfFwd = 14768;
+ pPreset->m_nEarlyGain = 27690;
+ pPreset->m_nEarlyDelay = 1311;
+ pPreset->m_nLateGain = 8191;
+ pPreset->m_nLateDelay = 3932;
+ pPreset->m_nRoomLpfFbk = 3692;
+ pPreset->m_nRoomLpfFwd = 24569;
+ pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+ pPreset->m_sEarlyL.m_nGain[0] = 22152;
+ pPreset->m_sEarlyL.m_zDelay[1] = 2163;
+ pPreset->m_sEarlyL.m_nGain[1] = 17537;
+ pPreset->m_sEarlyL.m_zDelay[2] = 0;
+ pPreset->m_sEarlyL.m_nGain[2] = 14768;
+ pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+ pPreset->m_sEarlyL.m_nGain[3] = 14307;
+ pPreset->m_sEarlyL.m_zDelay[4] = 0;
+ pPreset->m_sEarlyL.m_nGain[4] = 13384;
+ pPreset->m_sEarlyR.m_zDelay[0] = 721;
+ pPreset->m_sEarlyR.m_nGain[0] = 20306;
+ pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+ pPreset->m_sEarlyR.m_nGain[1] = 17537;
+ pPreset->m_sEarlyR.m_zDelay[2] = 0;
+ pPreset->m_sEarlyR.m_nGain[2] = 14768;
+ pPreset->m_sEarlyR.m_zDelay[3] = 0;
+ pPreset->m_sEarlyR.m_nGain[3] = 16153;
+ pPreset->m_sEarlyR.m_zDelay[4] = 0;
+ pPreset->m_sEarlyR.m_nGain[4] = 13384;
+ pPreset->m_nMaxExcursion = 127;
+ pPreset->m_nXfadeInterval = 6388;
+ pPreset->m_nAp0_ApGain = 15691;
+ pPreset->m_nAp0_ApOut = 711;
+ pPreset->m_nAp1_ApGain = 16317;
+ pPreset->m_nAp1_ApOut = 1029;
+ pPreset->m_rfu4 = 0;
+ pPreset->m_rfu5 = 0;
+ pPreset->m_rfu6 = 0;
+ pPreset->m_rfu7 = 0;
+ pPreset->m_rfu8 = 0;
+ pPreset->m_rfu9 = 0;
+ pPreset->m_rfu10 = 0;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/media/libeffects/testlibs/EffectReverb.h b/media/libeffects/testlibs/EffectReverb.h
new file mode 100644
index 0000000..ee8e390
--- /dev/null
+++ b/media/libeffects/testlibs/EffectReverb.h
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2008 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 ANDROID_EFFECTREVERB_H_
+#define ANDROID_EFFECTREVERB_H_
+
+#include <media/EffectEnvironmentalReverbApi.h>
+#include <media/EffectPresetReverbApi.h>
+
+
+/*------------------------------------
+ * defines
+ *------------------------------------
+*/
+
+/*
+CIRCULAR() calculates the array index using modulo arithmetic.
+The "trick" is that modulo arithmetic is simplified by masking
+the effective address where the mask is (2^n)-1. This only works
+if the buffer size is a power of two.
+*/
+#define CIRCULAR(base,offset,size) (uint32_t)( \
+ ( \
+ ((int32_t)(base)) + ((int32_t)(offset)) \
+ ) \
+ & size \
+ )
+
+#define NUM_OUTPUT_CHANNELS 2
+#define OUTPUT_CHANNELS CHANNEL_STEREO
+
+#define REVERB_BUFFER_SIZE_IN_SAMPLES_MAX 16384
+
+#define REVERB_NUM_PRESETS REVERB_PRESET_PLATE // REVERB_PRESET_NONE is not included
+#define REVERB_MAX_NUM_REFLECTIONS 5 // max num reflections per channel
+
+
+// xfade parameters
+#define REVERB_XFADE_PERIOD_IN_SECONDS (double) (100.0 / 1000.0) // xfade once every this many seconds
+
+
+/**********/
+/* the entire synth uses various flags in a bit field */
+
+/* if flag is set, synth reset has been requested */
+#define REVERB_FLAG_RESET_IS_REQUESTED 0x01 /* bit 0 */
+#define MASK_REVERB_RESET_IS_REQUESTED 0x01
+#define MASK_REVERB_RESET_IS_NOT_REQUESTED (uint32_t)(~MASK_REVERB_RESET_IS_REQUESTED)
+
+/*
+by default, we always want to update ALL channel parameters
+when we reset the synth (e.g., during GM ON)
+*/
+#define DEFAULT_REVERB_FLAGS 0x0
+
+/* coefficients for generating sin, cos */
+#define REVERB_PAN_G2 4294940151 /* -0.82842712474619 = 2 - 4/sqrt(2) */
+/*
+int32_t nPanG1 = +1.0 for sin
+int32_t nPanG1 = -1.0 for cos
+*/
+#define REVERB_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */
+
+/*************************************************************/
+// define the input injection points
+#define GUARD 5 // safety guard of this many samples
+
+#define MAX_AP_TIME (int) ((20*65536)/1000) // delay time in time units (65536th of sec)
+#define MAX_DELAY_TIME (int) ((65*65536)/1000) // delay time in time units
+#define MAX_EARLY_TIME (int) ((65*65536)/1000) // delay time in time units
+
+#define AP0_IN 0
+
+
+#define REVERB_DEFAULT_ROOM_NUMBER 1 // default preset number
+#define DEFAULT_AP0_GAIN 19400
+#define DEFAULT_AP1_GAIN -19400
+
+#define REVERB_DEFAULT_WET 32767
+#define REVERB_DEFAULT_DRY 0
+
+#define REVERB_WET_MAX 32767
+#define REVERB_WET_MIN 0
+#define REVERB_DRY_MAX 32767
+#define REVERB_DRY_MIN 0
+
+// constants for reverb density
+// The density expressed in permilles changes the Allpass delay in a linear manner in the range defined by
+// AP0_TIME_BASE to AP0_TIME_BASE + AP0_TIME_RANGE
+#define AP0_TIME_BASE (int)((9*65536)/1000)
+#define AP0_TIME_RANGE (int)((4*65536)/1000)
+#define AP1_TIME_BASE (int)((12*65536)/1000)
+#define AP1_TIME_RANGE (int)((8*65536)/1000)
+
+// constants for reverb diffusion
+// The diffusion expressed in permilles changes the Allpass gain in a linear manner in the range defined by
+// AP0_GAIN_BASE to AP0_GAIN_BASE + AP0_GAIN_RANGE
+#define AP0_GAIN_BASE (int)(9830)
+#define AP0_GAIN_RANGE (int)(19660-9830)
+#define AP1_GAIN_BASE (int)(6553)
+#define AP1_GAIN_RANGE (int)(22936-6553)
+
+
+enum reverb_state_e {
+ REVERB_STATE_UNINITIALIZED,
+ REVERB_STATE_INITIALIZED,
+ REVERB_STATE_ACTIVE,
+};
+
+/* parameters for each allpass */
+typedef struct
+{
+ uint16_t m_zApOut; // delay offset for ap out
+
+ int16_t m_nApGain; // gain for ap
+
+ uint16_t m_zApIn; // delay offset for ap in
+
+} allpass_object_t;
+
+
+/* parameters for early reflections */
+typedef struct
+{
+ uint16_t m_zDelay[REVERB_MAX_NUM_REFLECTIONS]; // delay offset for ap out
+
+ int16_t m_nGain[REVERB_MAX_NUM_REFLECTIONS]; // gain for ap
+
+} early_reflection_object_t;
+
+//demo
+typedef struct
+{
+ int16_t m_nRvbLpfFbk;
+ int16_t m_nRvbLpfFwd;
+ int16_t m_nRoomLpfFbk;
+ int16_t m_nRoomLpfFwd;
+
+ int16_t m_nEarlyGain;
+ int16_t m_nEarlyDelay;
+ int16_t m_nLateGain;
+ int16_t m_nLateDelay;
+
+ early_reflection_object_t m_sEarlyL;
+ early_reflection_object_t m_sEarlyR;
+
+ uint16_t m_nMaxExcursion; //28
+ int16_t m_nXfadeInterval;
+
+ int16_t m_nAp0_ApGain; //30
+ int16_t m_nAp0_ApOut;
+ int16_t m_nAp1_ApGain;
+ int16_t m_nAp1_ApOut;
+ int16_t m_nDiffusion;
+
+ int16_t m_rfu4;
+ int16_t m_rfu5;
+ int16_t m_rfu6;
+ int16_t m_rfu7;
+ int16_t m_rfu8;
+ int16_t m_rfu9;
+ int16_t m_rfu10; //43
+
+} reverb_preset_t;
+
+typedef struct
+{
+ reverb_preset_t m_sPreset[REVERB_NUM_PRESETS]; // array of presets(does not include REVERB_PRESET_NONE)
+
+} reverb_preset_bank_t;
+
+
+/* parameters for each reverb */
+typedef struct
+{
+ /* update counter keeps track of when synth params need updating */
+ /* only needs to be as large as REVERB_UPDATE_PERIOD_IN_SAMPLES */
+ int16_t m_nUpdateCounter;
+
+ uint16_t m_nBaseIndex; // base index for circular buffer
+
+ // reverb delay line offsets, allpass parameters, etc:
+
+ short m_nRevFbkR; // combine feedback reverb right out with dry left in
+ short m_zOutLpfL; // left reverb output
+
+ allpass_object_t m_sAp0; // allpass 0 (left channel)
+
+ uint16_t m_zD0In; // delay offset for delay line D0 in
+
+ short m_nRevFbkL; // combine feedback reverb left out with dry right in
+ short m_zOutLpfR; // right reverb output
+
+ allpass_object_t m_sAp1; // allpass 1 (right channel)
+
+ uint16_t m_zD1In; // delay offset for delay line D1 in
+
+ // delay output taps, notice criss cross order
+ uint16_t m_zD0Self; // self feeds forward d0 --> d0
+
+ uint16_t m_zD1Cross; // cross feeds across d1 --> d0
+
+ uint16_t m_zD1Self; // self feeds forward d1 --> d1
+
+ uint16_t m_zD0Cross; // cross feeds across d0 --> d1
+
+ int16_t m_nSin; // gain for self taps
+
+ int16_t m_nCos; // gain for cross taps
+
+ int16_t m_nSinIncrement; // increment for gain
+
+ int16_t m_nCosIncrement; // increment for gain
+
+ int16_t m_nRvbLpfFwd; // reverb feedback lpf forward gain (includes scaling for mixer)
+
+ int16_t m_nRvbLpfFbk; // reverb feedback lpf feedback gain
+
+ int16_t m_nRoomLpfFwd; // room lpf forward gain (includes scaling for mixer)
+
+ int16_t m_nRoomLpfFbk; // room lpf feedback gain
+
+ uint16_t m_nXfadeInterval; // update/xfade after this many samples
+
+ uint16_t m_nXfadeCounter; // keep track of when to xfade
+
+ int16_t m_nPhase; // -1 <= m_nPhase < 1
+ // but during sin,cos calculations
+ // use m_nPhase/2
+
+ int16_t m_nPhaseIncrement; // add this to m_nPhase each frame
+
+ int16_t m_nNoise; // random noise sample
+
+ uint16_t m_nMaxExcursion; // the taps can excurse +/- this amount
+
+ uint16_t m_bUseNoise; // if TRUE, use noise as input signal
+
+ uint16_t m_bBypass; // if TRUE, then bypass reverb and copy input to output
+
+ int16_t m_nCurrentRoom; // preset number for current room
+
+ int16_t m_nNextRoom; // preset number for next room
+
+ int16_t m_nEarlyGain; // gain for early (widen) signal
+ int16_t m_nEarlyDelay; // initial dealy for early (widen) signal
+ int16_t m_nEarly0in;
+ int16_t m_nEarly1in;
+ int16_t m_nLateGain; // gain for late reverb
+ int16_t m_nLateDelay;
+
+ int16_t m_nDiffusion;
+
+ early_reflection_object_t m_sEarlyL; // left channel early reflections
+ early_reflection_object_t m_sEarlyR; // right channel early reflections
+
+ short m_nDelayLine[REVERB_BUFFER_SIZE_IN_SAMPLES_MAX]; // one large delay line for all reverb elements
+
+ reverb_preset_t pPreset;
+
+ reverb_preset_bank_t m_sPreset;
+
+ //int8_t preset;
+ uint32_t m_nSamplingRate;
+ int32_t m_nUpdatePeriodInBits;
+ int32_t m_nBufferMask;
+ int32_t m_nUpdatePeriodInSamples;
+ int32_t m_nDelay0Out;
+ int32_t m_nDelay1Out;
+ int16_t m_nCosWT_5KHz;
+
+ uint16_t m_Aux; // if TRUE, is connected as auxiliary effect
+ uint16_t m_Preset; // if TRUE, expose preset revert interface
+
+ uint32_t mState;
+} reverb_object_t;
+
+
+
+typedef struct reverb_module_s {
+ const struct effect_interface_s *itfe;
+ effect_config_t config;
+ reverb_object_t context;
+} reverb_module_t;
+
+/*------------------------------------
+ * Effect API
+ *------------------------------------
+*/
+int EffectQueryNumberEffects(uint32_t *pNumEffects);
+int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor);
+int EffectCreate(effect_uuid_t *effectUID, int32_t sessionId, int32_t ioId, effect_interface_t *pInterface);
+int EffectRelease(effect_interface_t interface);
+
+static int Reverb_Process(effect_interface_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer);
+static int Reverb_Command(effect_interface_t self, int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
+
+
+/*------------------------------------
+ * internal functions
+ *------------------------------------
+*/
+
+int Reverb_Init(reverb_module_t *pRvbModule, int aux, int preset);
+int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig, bool init);
+void Reverb_Reset(reverb_object_t *pReverb, bool init);
+
+int Reverb_setParameter (reverb_object_t *pReverb, int32_t param, size_t size, void *pValue);
+int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize, void *pValue);
+
+/*----------------------------------------------------------------------------
+ * ReverbUpdateXfade
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Update the xfade parameters as required
+ *
+ * Inputs:
+ * nNumSamplesToAdd - number of samples to write to buffer
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ * - xfade parameters will be changed
+ *
+ *----------------------------------------------------------------------------
+*/
+static int ReverbUpdateXfade(reverb_object_t* pReverbData, int nNumSamplesToAdd);
+
+/*----------------------------------------------------------------------------
+ * ReverbCalculateNoise
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Calculate a noise sample and limit its value
+ *
+ * Inputs:
+ * Pointer to reverb context
+ *
+ * Outputs:
+ * new limited noise value
+ *
+ * Side Effects:
+ * - pReverbData->m_nNoise value is updated
+ *
+ *----------------------------------------------------------------------------
+*/
+static uint16_t ReverbCalculateNoise(reverb_object_t *pReverbData);
+
+/*----------------------------------------------------------------------------
+ * ReverbCalculateSinCos
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Calculate a new sin and cosine value based on the given phase
+ *
+ * Inputs:
+ * nPhase - phase angle
+ * pnSin - input old value, output new value
+ * pnCos - input old value, output new value
+ *
+ * Outputs:
+ *
+ * Side Effects:
+ * - *pnSin, *pnCos are updated
+ *
+ *----------------------------------------------------------------------------
+*/
+static int ReverbCalculateSinCos(int16_t nPhase, int16_t *pnSin, int16_t *pnCos);
+
+/*----------------------------------------------------------------------------
+ * Reverb
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * apply reverb to the given signal
+ *
+ * Inputs:
+ * nNu
+ * pnSin - input old value, output new value
+ * pnCos - input old value, output new value
+ *
+ * Outputs:
+ * number of samples actually reverberated
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static int Reverb(reverb_object_t* pReverbData, int nNumSamplesToAdd, short *pOutputBuffer, short *pInputBuffer);
+
+/*----------------------------------------------------------------------------
+ * ReverbReadInPresets()
+ *----------------------------------------------------------------------------
+ * Purpose: sets global reverb preset bank to defaults
+ *
+ * Inputs:
+ *
+ * Outputs:
+ *
+ *----------------------------------------------------------------------------
+*/
+static int ReverbReadInPresets(reverb_object_t* pReverbData);
+
+
+/*----------------------------------------------------------------------------
+ * ReverbUpdateRoom
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Update the room's preset parameters as required
+ *
+ * Inputs:
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ * - reverb paramters (fbk, fwd, etc) will be changed
+ * - m_nCurrentRoom := m_nNextRoom
+ *----------------------------------------------------------------------------
+*/
+static int ReverbUpdateRoom(reverb_object_t* pReverbData, bool fullUpdate);
+
+
+static int ReverbComputeConstants(reverb_object_t *pReverbData, uint32_t samplingRate);
+
+#endif /*ANDROID_EFFECTREVERB_H_*/
diff --git a/media/libeffects/testlibs/EffectsMath.c b/media/libeffects/testlibs/EffectsMath.c
new file mode 100644
index 0000000..41ec662
--- /dev/null
+++ b/media/libeffects/testlibs/EffectsMath.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+#define LOG_TAG "EFFECTSMATH"
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+#include <assert.h>
+
+#include "EffectsMath.h"
+
+// gLogTab contains pre-calculated values of log2(1 + ai5*2^-1 + ai4*2^-2 + ai3*2^-3 + ai2*2^-4 + ai1*2^-5 + ai0*2^-6)
+// for integers in the range 0 to 63 (i = ai5*2^5 + ai4*2^4 + ai3*2^3 + ai2*2^2 + ai1*2^1 + ai0*2^0)
+// It is used for a better than piece wise approximation of lin to log2 conversion
+
+static const uint16_t gLogTab[] =
+{
+ 0, 733, 1455, 2166,
+ 2866, 3556, 4236, 4907,
+ 5568, 6220, 6863, 7498,
+ 8124, 8742, 9352, 9954,
+ 10549, 11136, 11716, 12289,
+ 12855, 13415, 13968, 14514,
+ 15055, 15589, 16117, 16639,
+ 17156, 17667, 18173, 18673,
+ 19168, 19658, 20143, 20623,
+ 21098, 21568, 22034, 22495,
+ 22952, 23404, 23852, 24296,
+ 24736, 25172, 25604, 26031,
+ 26455, 26876, 27292, 27705,
+ 28114, 28520, 28922, 29321,
+ 29717, 30109, 30498, 30884,
+ 31267, 31647, 32024, 32397,
+ 32768
+};
+
+int32_t Effects_log2(uint32_t x) {
+ int32_t exp = 31 - __builtin_clz(x);
+ uint32_t segStart = x >> (exp - 6);
+ uint32_t i = segStart & 0x3F;
+ int32_t log = (int32_t)gLogTab[i];
+ int32_t logEnd = (int32_t)gLogTab[i+1];
+ segStart <<= exp - 6;
+
+ return (exp << 15) + log + (((x - segStart) * (logEnd - log)) >> (exp - 6));
+}
+
+// gExpTab[i] = (2^(i>>6)) << 22
+static const uint32_t gExpTab[] = {
+ 4194304, 4239977, 4286147, 4332820,
+ 4380002, 4427697, 4475911, 4524651,
+ 4573921, 4623728, 4674077, 4724974,
+ 4776426, 4828438, 4881016, 4934167,
+ 4987896, 5042211, 5097117, 5152621,
+ 5208729, 5265449, 5322786, 5380747,
+ 5439339, 5498570, 5558445, 5618973,
+ 5680159, 5742012, 5804539, 5867746,
+ 5931642, 5996233, 6061528, 6127533,
+ 6194258, 6261709, 6329894, 6398822,
+ 6468501, 6538938, 6610143, 6682122,
+ 6754886, 6828442, 6902799, 6977965,
+ 7053950, 7130763, 7208412, 7286906,
+ 7366255, 7446469, 7527555, 7609525,
+ 7692387, 7776152, 7860829, 7946428,
+ 8032959, 8120432, 8208857, 8298246,
+ 8388608
+};
+
+
+uint32_t Effects_exp2(int32_t x) {
+ int32_t i = x >> 15;
+ assert(i < 32);
+ x &= (1 << 15) - 1;
+ int32_t j = x >> 9;
+ x &= (1 << 9) - 1;
+ uint32_t exp = gExpTab[j];
+ uint32_t expEnd = gExpTab[j+1];
+
+ return ((exp << 9) + (expEnd - exp) * x) >> (31 - i);
+}
+
+
+int16_t Effects_MillibelsToLinear16 (int32_t nGain)
+{
+ nGain = ((nGain + MB_TO_LIN_K1) << 15 ) / MB_TO_LIN_K2;
+ uint32_t exp2 = Effects_exp2(nGain);
+
+ if (exp2 > 32767) exp2 = 32767;
+
+ return (int16_t)exp2;
+}
+
+
+int16_t Effects_Linear16ToMillibels (int32_t nGain)
+{
+ return (int16_t)(((MB_TO_LIN_K2*Effects_log2(nGain))>>15)-MB_TO_LIN_K1);
+}
+
+
+int32_t Effects_Sqrt(int32_t in)
+{
+ int32_t tmp;
+ int32_t out = 0;
+ int32_t i;
+ int32_t j;
+
+
+ if (in == 0) return 0;
+
+ if (in >= 0x10000000)
+ {
+ out = 0x4000;
+ in -= 0x10000000;
+ }
+
+ j = 32 - __builtin_clz(in);
+
+ if (j & 1) j++;
+ j >>= 1;
+
+ for (i = j; i > 0; i--) {
+ tmp = (out << i) + (1 << ((i - 1)*2));
+ if (in >= tmp)
+ {
+ out += 1 << (i-1);
+ in -= tmp;
+ }
+ }
+
+ return out;
+}
+
diff --git a/media/libeffects/testlibs/EffectsMath.h b/media/libeffects/testlibs/EffectsMath.h
new file mode 100644
index 0000000..2a44399
--- /dev/null
+++ b/media/libeffects/testlibs/EffectsMath.h
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2008 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 ANDROID_EFFECTSMATH_H_
+#define ANDROID_EFFECTSMATH_H_
+
+#include <stdint.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+/** coefs for pan, generates sin, cos */
+#define COEFF_PAN_G2 -27146 /* -0.82842712474619 = 2 - 4/sqrt(2) */
+#define COEFF_PAN_G0 23170 /* 0.707106781186547 = 1/sqrt(2) */
+
+/*
+coefficients for approximating
+2^x = gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3
+where x is a int.frac number representing number of octaves.
+Actually, we approximate only the 2^(frac) using the power series
+and implement the 2^(int) as a shift, so that
+2^x == 2^(int.frac) == 2^(int) * 2^(fract)
+ == (gn2toX0 + gn2toX1*x + gn2toX2*x^2 + gn2toX3*x^3) << (int)
+
+The gn2toX.. were generated using a best fit for a 3rd
+order polynomial, instead of taking the coefficients from
+a truncated Taylor (or Maclaurin?) series.
+*/
+
+#define GN2_TO_X0 32768 /* 1 */
+#define GN2_TO_X1 22833 /* 0.696807861328125 */
+#define GN2_TO_X2 7344 /* 0.22412109375 */
+#define GN2_TO_X3 2588 /* 0.0789794921875 */
+
+/*----------------------------------------------------------------------------
+ * Fixed Point Math
+ *----------------------------------------------------------------------------
+ * These macros are used for fixed point multiplies. If the processor
+ * supports fixed point multiplies, replace these macros with inline
+ * assembly code to improve performance.
+ *----------------------------------------------------------------------------
+*/
+
+/* Fixed point multiply 0.15 x 0.15 = 0.15 returned as 32-bits */
+#define FMUL_15x15(a,b) \
+ /*lint -e(704) <avoid multiply for performance>*/ \
+ (((int32_t)(a) * (int32_t)(b)) >> 15)
+
+/* Fixed point multiply 0.7 x 0.7 = 0.15 returned as 32-bits */
+#define FMUL_7x7(a,b) \
+ /*lint -e(704) <avoid multiply for performance>*/ \
+ (((int32_t)(a) * (int32_t)(b) ) << 1)
+
+/* Fixed point multiply 0.8 x 0.8 = 0.15 returned as 32-bits */
+#define FMUL_8x8(a,b) \
+ /*lint -e(704) <avoid multiply for performance>*/ \
+ (((int32_t)(a) * (int32_t)(b) ) >> 1)
+
+/* Fixed point multiply 0.8 x 1.15 = 0.15 returned as 32-bits */
+#define FMUL_8x15(a,b) \
+ /*lint -e(704) <avoid divide for performance>*/ \
+ (((int32_t)((a) << 7) * (int32_t)(b)) >> 15)
+
+/* macros for fractional phase accumulator */
+/*
+Note: changed the _U32 to _I32 on 03/14/02. This should not
+affect the phase calculations, and should allow us to reuse these
+macros for other audio sample related math.
+*/
+#define HARDWARE_BIT_WIDTH 32
+
+#define NUM_PHASE_INT_BITS 1
+#define NUM_PHASE_FRAC_BITS 15
+
+#define PHASE_FRAC_MASK (uint32_t) ((0x1L << NUM_PHASE_FRAC_BITS) -1)
+
+#define GET_PHASE_INT_PART(x) (uint32_t)((uint32_t)(x) >> NUM_PHASE_FRAC_BITS)
+#define GET_PHASE_FRAC_PART(x) (uint32_t)((uint32_t)(x) & PHASE_FRAC_MASK)
+
+#define DEFAULT_PHASE_FRAC 0
+#define DEFAULT_PHASE_INT 0
+
+/*
+Linear interpolation calculates:
+output = (1-frac) * sample[n] + (frac) * sample[n+1]
+
+where conceptually 0 <= frac < 1
+
+For a fixed point implementation, frac is actually an integer value
+with an implied binary point one position to the left. The value of
+one (unity) is given by PHASE_ONE
+one half and one quarter are useful for 4-point linear interp.
+*/
+#define PHASE_ONE (int32_t) (0x1L << NUM_PHASE_FRAC_BITS)
+
+/*
+ Multiply the signed audio sample by the unsigned fraction.
+- a is the signed audio sample
+- b is the unsigned fraction (cast to signed int as long as coef
+ uses (n-1) or less bits, where n == hardware bit width)
+*/
+#define MULT_AUDIO_COEF(audio,coef) /*lint -e704 <avoid divide for performance>*/ \
+ (int32_t)( \
+ ( \
+ ((int32_t)(audio)) * ((int32_t)(coef)) \
+ ) \
+ >> NUM_PHASE_FRAC_BITS \
+ ) \
+ /* lint +704 <restore checking>*/
+
+/* wet / dry calculation macros */
+#define NUM_WET_DRY_FRAC_BITS 7 // 15
+#define NUM_WET_DRY_INT_BITS 9 // 1
+
+/* define a 1.0 */
+#define WET_DRY_ONE (int32_t) ((0x1L << NUM_WET_DRY_FRAC_BITS))
+#define WET_DRY_MINUS_ONE (int32_t) (~WET_DRY_ONE)
+#define WET_DRY_FULL_SCALE (int32_t) (WET_DRY_ONE - 1)
+
+#define MULT_AUDIO_WET_DRY_COEF(audio,coef) /*lint -e(702) <avoid divide for performance>*/ \
+ (int32_t)( \
+ ( \
+ ((int32_t)(audio)) * ((int32_t)(coef)) \
+ ) \
+ >> NUM_WET_DRY_FRAC_BITS \
+ )
+
+/* Envelope 1 (EG1) calculation macros */
+#define NUM_EG1_INT_BITS 1
+#define NUM_EG1_FRAC_BITS 15
+
+/* the max positive gain used in the synth for EG1 */
+/* SYNTH_FULL_SCALE_EG1_GAIN must match the value in the dls2eas
+converter, otherwise, the values we read from the .eas file are bogus. */
+#define SYNTH_FULL_SCALE_EG1_GAIN (int32_t) ((0x1L << NUM_EG1_FRAC_BITS) -1)
+
+/* define a 1.0 */
+#define EG1_ONE (int32_t) ((0x1L << NUM_EG1_FRAC_BITS))
+#define EG1_MINUS_ONE (int32_t) (~SYNTH_FULL_SCALE_EG1_GAIN)
+
+#define EG1_HALF (int32_t) (EG1_ONE/2)
+#define EG1_MINUS_HALF (int32_t) (EG1_MINUS_ONE/2)
+
+/*
+We implement the EG1 using a linear gain value, which means that the
+attack segment is handled by incrementing (adding) the linear gain.
+However, EG1 treats the Decay, Sustain, and Release differently than
+the Attack portion. For Decay, Sustain, and Release, the gain is
+linear on dB scale, which is equivalent to exponential damping on
+a linear scale. Because we use a linear gain for EG1, we implement
+the Decay and Release as multiplication (instead of incrementing
+as we did for the attack segment).
+Therefore, we need the following macro to implement the multiplication
+(i.e., exponential damping) during the Decay and Release segments of
+the EG1
+*/
+#define MULT_EG1_EG1(gain,damping) /*lint -e(704) <avoid divide for performance>*/ \
+ (int32_t)( \
+ ( \
+ ((int32_t)(gain)) * ((int32_t)(damping)) \
+ ) \
+ >> NUM_EG1_FRAC_BITS \
+ )
+
+// Use the following macro specifically for the filter, when multiplying
+// the b1 coefficient. The 0 <= |b1| < 2, which therefore might overflow
+// in certain conditions because we store b1 as a 1.15 value.
+// Instead, we could store b1 as b1p (b1' == b1 "prime") where
+// b1p == b1/2, thus ensuring no potential overflow for b1p because
+// 0 <= |b1p| < 1
+// However, during the filter calculation, we must account for the fact
+// that we are using b1p instead of b1, and thereby multiply by
+// an extra factor of 2. Rather than multiply by an extra factor of 2,
+// we can instead shift the result right by one less, hence the
+// modified shift right value of (NUM_EG1_FRAC_BITS -1)
+#define MULT_EG1_EG1_X2(gain,damping) /*lint -e(702) <avoid divide for performance>*/ \
+ (int32_t)( \
+ ( \
+ ((int32_t)(gain)) * ((int32_t)(damping)) \
+ ) \
+ >> (NUM_EG1_FRAC_BITS -1) \
+ )
+
+#define SATURATE_EG1(x) /*lint -e{734} saturation operation */ \
+ ((int32_t)(x) > SYNTH_FULL_SCALE_EG1_GAIN) ? (SYNTH_FULL_SCALE_EG1_GAIN) : \
+ ((int32_t)(x) < EG1_MINUS_ONE) ? (EG1_MINUS_ONE) : (x);
+
+
+/* use "digital cents" == "dents" instead of cents */
+/* we coudl re-use the phase frac macros, but if we do,
+we must change the phase macros to cast to _I32 instead of _U32,
+because using a _U32 cast causes problems when shifting the exponent
+for the 2^x calculation, because right shift a negative values MUST
+be sign extended, or else the 2^x calculation is wrong */
+
+/* use "digital cents" == "dents" instead of cents */
+#define NUM_DENTS_FRAC_BITS 12
+#define NUM_DENTS_INT_BITS (HARDWARE_BIT_WIDTH - NUM_DENTS_FRAC_BITS)
+
+#define DENTS_FRAC_MASK (int32_t) ((0x1L << NUM_DENTS_FRAC_BITS) -1)
+
+#define GET_DENTS_INT_PART(x) /*lint -e(704) <avoid divide for performance>*/ \
+ (int32_t)((int32_t)(x) >> NUM_DENTS_FRAC_BITS)
+
+#define GET_DENTS_FRAC_PART(x) (int32_t)((int32_t)(x) & DENTS_FRAC_MASK)
+
+#define DENTS_ONE (int32_t) (0x1L << NUM_DENTS_FRAC_BITS)
+
+/* use CENTS_TO_DENTS to convert a value in cents to dents */
+#define CENTS_TO_DENTS (int32_t) (DENTS_ONE * (0x1L << NUM_EG1_FRAC_BITS) / 1200L) \
+
+
+/*
+For gain, the LFO generates a value that modulates in terms
+of dB. However, we use a linear gain value, so we must convert
+the LFO value in dB to a linear gain. Normally, we would use
+linear gain = 10^x, where x = LFO value in dB / 20.
+Instead, we implement 10^x using our 2^x approximation.
+because
+
+ 10^x = 2^(log2(10^x)) = 2^(x * log2(10))
+
+so we need to multiply by log2(10) which is just a constant.
+Ah, but just wait -- our 2^x actually doesn't exactly implement
+2^x, but it actually assumes that the input is in cents, and within
+the 2^x approximation converts its input from cents to octaves
+by dividing its input by 1200.
+
+So, in order to convert the LFO gain value in dB to something
+that our existing 2^x approximation can use, multiply the LFO gain
+by log2(10) * 1200 / 20
+
+The divide by 20 helps convert dB to linear gain, and we might
+as well incorporate that operation into this conversion.
+Of course, we need to keep some fractional bits, so multiply
+the constant by NUM_EG1_FRAC_BITS
+*/
+
+/* use LFO_GAIN_TO_CENTS to convert the LFO gain value to cents */
+#if 0
+#define DOUBLE_LOG2_10 (double) (3.32192809488736) /* log2(10) */
+
+#define DOUBLE_LFO_GAIN_TO_CENTS (double) \
+ ( \
+ (DOUBLE_LOG2_10) * \
+ 1200.0 / \
+ 20.0 \
+ )
+
+#define LFO_GAIN_TO_CENTS (int32_t) \
+ ( \
+ DOUBLE_LFO_GAIN_TO_CENTS * \
+ (0x1L << NUM_EG1_FRAC_BITS) \
+ )
+#endif
+
+#define LFO_GAIN_TO_CENTS (int32_t) (1671981156L >> (23 - NUM_EG1_FRAC_BITS))
+
+
+#define MULT_DENTS_COEF(dents,coef) /*lint -e704 <avoid divide for performance>*/ \
+ (int32_t)( \
+ ( \
+ ((int32_t)(dents)) * ((int32_t)(coef)) \
+ ) \
+ >> NUM_DENTS_FRAC_BITS \
+ ) \
+ /* lint +e704 <restore checking>*/
+
+
+/* we use 16-bits in the PC per audio sample */
+#define BITS_PER_AUDIO_SAMPLE 16
+
+/* we define 1 as 1.0 - 1 LSbit */
+#define DISTORTION_ONE (int32_t)((0x1L << (BITS_PER_AUDIO_SAMPLE-1)) -1)
+#define DISTORTION_MINUS_ONE (int32_t)(~DISTORTION_ONE)
+
+/* drive coef is given as int.frac */
+#define NUM_DRIVE_COEF_INT_BITS 1
+#define NUM_DRIVE_COEF_FRAC_BITS 4
+
+#define MULT_AUDIO_DRIVE(audio,drive) /*lint -e(702) <avoid divide for performance>*/ \
+ (int32_t) ( \
+ ( \
+ ((int32_t)(audio)) * ((int32_t)(drive)) \
+ ) \
+ >> NUM_DRIVE_COEF_FRAC_BITS \
+ )
+
+#define MULT_AUDIO_AUDIO(audio1,audio2) /*lint -e(702) <avoid divide for performance>*/ \
+ (int32_t) ( \
+ ( \
+ ((int32_t)(audio1)) * ((int32_t)(audio2)) \
+ ) \
+ >> (BITS_PER_AUDIO_SAMPLE-1) \
+ )
+
+#define SATURATE(x) \
+ ((((int32_t)(x)) > DISTORTION_ONE) ? (DISTORTION_ONE) : \
+ (((int32_t)(x)) < DISTORTION_MINUS_ONE) ? (DISTORTION_MINUS_ONE) : ((int32_t)(x)));
+
+
+/*----------------------------------------------------------------------------
+ * Effects_log2()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Fixed-point log2 function.
+ *
+ * Inputs:
+ * Input is interpreted as an integer (should not be 0).
+ *
+ * Outputs:
+ * Output is in 15-bit precision.
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+int32_t Effects_log2(uint32_t x);
+
+/*----------------------------------------------------------------------------
+ * Effects_exp2()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Fixed-point radix-2 exponent.
+ *
+ * Inputs:
+ * Input is in 15-bit precision. Must be non-negative and less than 32.
+ *
+ * Outputs:
+ * Output is an integer.
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+uint32_t Effects_exp2(int32_t x);
+
+/*----------------------------------------------------------------------------
+ * Effects_MillibelsToLinear16()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Transform gain in millibels to linear gain multiplier:
+ *
+ * mB = 2000*log(lin/32767)
+ * => lin = 2^((mB+2000*log(32767))/2000*log(2))
+ * => lin = Effects_exp2(((mB + K1) << 15) / K2)
+ * with:
+ * K1 = 2000*log(32767) and K2 = 2000*log(2)
+ *
+ * Inputs:
+ * nGain - log scale value in millibels.
+ *
+ * Outputs:
+ * Returns a 16-bit linear value approximately equal to 2^(nGain/1024)
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+#define MB_TO_LIN_K1 9031
+#define MB_TO_LIN_K2 602
+int16_t Effects_MillibelsToLinear16 (int32_t nGain);
+
+/*----------------------------------------------------------------------------
+ * Effects_Linear16ToMillibels()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Transform linear gain multiplier to millibels
+ * mB = 2000*log(lin/32767)
+ * = 2000*log(2)*log2(lin)-2000*log(32767)
+ * => mB = K1*Effects_log2(lin) + K2
+ * with:
+ * K1 = 2000*log(2) and K2 = -2000*log(32767)
+ *
+ * Inputs:
+ * nGain - linear multiplier ranging form 0 to 32767 (corresponding to [0 1] gain range).
+ *
+ * Outputs:
+ * Returns a 16-bit log value expressed in milllibels.
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+int16_t Effects_Linear16ToMillibels (int32_t nGain);
+
+/*----------------------------------------------------------------------------
+ * Effects_Sqrt()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Returns the square root of the argument given.
+ *
+ * Inputs:
+ * in - positive number in the range 0 - 2^28
+ *
+ * Outputs:
+ * Returned value: square root of in.
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+int32_t Effects_Sqrt(int32_t in);
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif /*ANDROID_EFFECTSMATH_H_*/
+