1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2013 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "EffectLE"
18*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
19*ec779b8eSAndroid Build Coastguard Worker
20*ec779b8eSAndroid Build Coastguard Worker #include <assert.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <math.h>
22*ec779b8eSAndroid Build Coastguard Worker #include <stdlib.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <string.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <time.h>
25*ec779b8eSAndroid Build Coastguard Worker
26*ec779b8eSAndroid Build Coastguard Worker #include <new>
27*ec779b8eSAndroid Build Coastguard Worker
28*ec779b8eSAndroid Build Coastguard Worker #include <log/log.h>
29*ec779b8eSAndroid Build Coastguard Worker
30*ec779b8eSAndroid Build Coastguard Worker #include <audio_effects/effect_loudnessenhancer.h>
31*ec779b8eSAndroid Build Coastguard Worker #include "dsp/core/dynamic_range_compression.h"
32*ec779b8eSAndroid Build Coastguard Worker
33*ec779b8eSAndroid Build Coastguard Worker // BUILD_FLOAT targets building a float effect instead of the legacy int16_t effect.
34*ec779b8eSAndroid Build Coastguard Worker #define BUILD_FLOAT
35*ec779b8eSAndroid Build Coastguard Worker
36*ec779b8eSAndroid Build Coastguard Worker #ifdef BUILD_FLOAT
37*ec779b8eSAndroid Build Coastguard Worker
38*ec779b8eSAndroid Build Coastguard Worker static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_FLOAT;
39*ec779b8eSAndroid Build Coastguard Worker
40*ec779b8eSAndroid Build Coastguard Worker #else
41*ec779b8eSAndroid Build Coastguard Worker
42*ec779b8eSAndroid Build Coastguard Worker static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_16_BIT;
43*ec779b8eSAndroid Build Coastguard Worker
clamp16(int32_t sample)44*ec779b8eSAndroid Build Coastguard Worker static inline int16_t clamp16(int32_t sample)
45*ec779b8eSAndroid Build Coastguard Worker {
46*ec779b8eSAndroid Build Coastguard Worker if ((sample>>15) ^ (sample>>31))
47*ec779b8eSAndroid Build Coastguard Worker sample = 0x7FFF ^ (sample>>31);
48*ec779b8eSAndroid Build Coastguard Worker return sample;
49*ec779b8eSAndroid Build Coastguard Worker }
50*ec779b8eSAndroid Build Coastguard Worker
51*ec779b8eSAndroid Build Coastguard Worker #endif // BUILD_FLOAT
52*ec779b8eSAndroid Build Coastguard Worker
53*ec779b8eSAndroid Build Coastguard Worker extern "C" {
54*ec779b8eSAndroid Build Coastguard Worker
55*ec779b8eSAndroid Build Coastguard Worker // effect_handle_t interface implementation for LE effect
56*ec779b8eSAndroid Build Coastguard Worker extern const struct effect_interface_s gLEInterface;
57*ec779b8eSAndroid Build Coastguard Worker
58*ec779b8eSAndroid Build Coastguard Worker // AOSP Loudness Enhancer UUID: fa415329-2034-4bea-b5dc-5b381c8d1e2c
59*ec779b8eSAndroid Build Coastguard Worker const effect_descriptor_t gLEDescriptor = {
60*ec779b8eSAndroid Build Coastguard Worker {0xfe3199be, 0xaed0, 0x413f, 0x87bb, {0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}, // type
61*ec779b8eSAndroid Build Coastguard Worker {0xfa415329, 0x2034, 0x4bea, 0xb5dc, {0x5b, 0x38, 0x1c, 0x8d, 0x1e, 0x2c}}, // uuid
62*ec779b8eSAndroid Build Coastguard Worker EFFECT_CONTROL_API_VERSION,
63*ec779b8eSAndroid Build Coastguard Worker (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
64*ec779b8eSAndroid Build Coastguard Worker 0, // TODO
65*ec779b8eSAndroid Build Coastguard Worker 1,
66*ec779b8eSAndroid Build Coastguard Worker "Loudness Enhancer",
67*ec779b8eSAndroid Build Coastguard Worker "The Android Open Source Project",
68*ec779b8eSAndroid Build Coastguard Worker };
69*ec779b8eSAndroid Build Coastguard Worker
70*ec779b8eSAndroid Build Coastguard Worker enum le_state_e {
71*ec779b8eSAndroid Build Coastguard Worker LOUDNESS_ENHANCER_STATE_UNINITIALIZED,
72*ec779b8eSAndroid Build Coastguard Worker LOUDNESS_ENHANCER_STATE_INITIALIZED,
73*ec779b8eSAndroid Build Coastguard Worker LOUDNESS_ENHANCER_STATE_ACTIVE,
74*ec779b8eSAndroid Build Coastguard Worker };
75*ec779b8eSAndroid Build Coastguard Worker
76*ec779b8eSAndroid Build Coastguard Worker struct LoudnessEnhancerContext {
77*ec779b8eSAndroid Build Coastguard Worker const struct effect_interface_s *mItfe;
78*ec779b8eSAndroid Build Coastguard Worker effect_config_t mConfig;
79*ec779b8eSAndroid Build Coastguard Worker uint8_t mState;
80*ec779b8eSAndroid Build Coastguard Worker int32_t mTargetGainmB;// target gain in mB
81*ec779b8eSAndroid Build Coastguard Worker // in this implementation, there is no coupling between the compression on the left and right
82*ec779b8eSAndroid Build Coastguard Worker // channels
83*ec779b8eSAndroid Build Coastguard Worker le_fx::AdaptiveDynamicRangeCompression* mCompressor;
84*ec779b8eSAndroid Build Coastguard Worker };
85*ec779b8eSAndroid Build Coastguard Worker
86*ec779b8eSAndroid Build Coastguard Worker //
87*ec779b8eSAndroid Build Coastguard Worker //--- Local functions (not directly used by effect interface)
88*ec779b8eSAndroid Build Coastguard Worker //
89*ec779b8eSAndroid Build Coastguard Worker
LE_reset(LoudnessEnhancerContext * pContext)90*ec779b8eSAndroid Build Coastguard Worker void LE_reset(LoudnessEnhancerContext *pContext)
91*ec779b8eSAndroid Build Coastguard Worker {
92*ec779b8eSAndroid Build Coastguard Worker ALOGV(" > LE_reset(%p)", pContext);
93*ec779b8eSAndroid Build Coastguard Worker
94*ec779b8eSAndroid Build Coastguard Worker if (pContext->mCompressor != NULL) {
95*ec779b8eSAndroid Build Coastguard Worker float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
96*ec779b8eSAndroid Build Coastguard Worker ALOGV("LE_reset(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
97*ec779b8eSAndroid Build Coastguard Worker pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
98*ec779b8eSAndroid Build Coastguard Worker } else {
99*ec779b8eSAndroid Build Coastguard Worker ALOGE("LE_reset(%p): null compressors, can't apply target gain", pContext);
100*ec779b8eSAndroid Build Coastguard Worker }
101*ec779b8eSAndroid Build Coastguard Worker }
102*ec779b8eSAndroid Build Coastguard Worker
103*ec779b8eSAndroid Build Coastguard Worker //----------------------------------------------------------------------------
104*ec779b8eSAndroid Build Coastguard Worker // LE_setConfig()
105*ec779b8eSAndroid Build Coastguard Worker //----------------------------------------------------------------------------
106*ec779b8eSAndroid Build Coastguard Worker // Purpose: Set input and output audio configuration.
107*ec779b8eSAndroid Build Coastguard Worker //
108*ec779b8eSAndroid Build Coastguard Worker // Inputs:
109*ec779b8eSAndroid Build Coastguard Worker // pContext: effect engine context
110*ec779b8eSAndroid Build Coastguard Worker // pConfig: pointer to effect_config_t structure holding input and output
111*ec779b8eSAndroid Build Coastguard Worker // configuration parameters
112*ec779b8eSAndroid Build Coastguard Worker //
113*ec779b8eSAndroid Build Coastguard Worker // Outputs:
114*ec779b8eSAndroid Build Coastguard Worker //
115*ec779b8eSAndroid Build Coastguard Worker //----------------------------------------------------------------------------
116*ec779b8eSAndroid Build Coastguard Worker
LE_setConfig(LoudnessEnhancerContext * pContext,effect_config_t * pConfig)117*ec779b8eSAndroid Build Coastguard Worker int LE_setConfig(LoudnessEnhancerContext *pContext, effect_config_t *pConfig)
118*ec779b8eSAndroid Build Coastguard Worker {
119*ec779b8eSAndroid Build Coastguard Worker ALOGV("LE_setConfig(%p)", pContext);
120*ec779b8eSAndroid Build Coastguard Worker
121*ec779b8eSAndroid Build Coastguard Worker if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
122*ec779b8eSAndroid Build Coastguard Worker if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
123*ec779b8eSAndroid Build Coastguard Worker if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
124*ec779b8eSAndroid Build Coastguard Worker if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
125*ec779b8eSAndroid Build Coastguard Worker if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
126*ec779b8eSAndroid Build Coastguard Worker pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
127*ec779b8eSAndroid Build Coastguard Worker if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
128*ec779b8eSAndroid Build Coastguard Worker
129*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig = *pConfig;
130*ec779b8eSAndroid Build Coastguard Worker
131*ec779b8eSAndroid Build Coastguard Worker LE_reset(pContext);
132*ec779b8eSAndroid Build Coastguard Worker
133*ec779b8eSAndroid Build Coastguard Worker return 0;
134*ec779b8eSAndroid Build Coastguard Worker }
135*ec779b8eSAndroid Build Coastguard Worker
136*ec779b8eSAndroid Build Coastguard Worker
137*ec779b8eSAndroid Build Coastguard Worker //----------------------------------------------------------------------------
138*ec779b8eSAndroid Build Coastguard Worker // LE_getConfig()
139*ec779b8eSAndroid Build Coastguard Worker //----------------------------------------------------------------------------
140*ec779b8eSAndroid Build Coastguard Worker // Purpose: Get input and output audio configuration.
141*ec779b8eSAndroid Build Coastguard Worker //
142*ec779b8eSAndroid Build Coastguard Worker // Inputs:
143*ec779b8eSAndroid Build Coastguard Worker // pContext: effect engine context
144*ec779b8eSAndroid Build Coastguard Worker // pConfig: pointer to effect_config_t structure holding input and output
145*ec779b8eSAndroid Build Coastguard Worker // configuration parameters
146*ec779b8eSAndroid Build Coastguard Worker //
147*ec779b8eSAndroid Build Coastguard Worker // Outputs:
148*ec779b8eSAndroid Build Coastguard Worker //
149*ec779b8eSAndroid Build Coastguard Worker //----------------------------------------------------------------------------
150*ec779b8eSAndroid Build Coastguard Worker
LE_getConfig(LoudnessEnhancerContext * pContext,effect_config_t * pConfig)151*ec779b8eSAndroid Build Coastguard Worker void LE_getConfig(LoudnessEnhancerContext *pContext, effect_config_t *pConfig)
152*ec779b8eSAndroid Build Coastguard Worker {
153*ec779b8eSAndroid Build Coastguard Worker *pConfig = pContext->mConfig;
154*ec779b8eSAndroid Build Coastguard Worker }
155*ec779b8eSAndroid Build Coastguard Worker
156*ec779b8eSAndroid Build Coastguard Worker
157*ec779b8eSAndroid Build Coastguard Worker //----------------------------------------------------------------------------
158*ec779b8eSAndroid Build Coastguard Worker // LE_init()
159*ec779b8eSAndroid Build Coastguard Worker //----------------------------------------------------------------------------
160*ec779b8eSAndroid Build Coastguard Worker // Purpose: Initialize engine with default configuration.
161*ec779b8eSAndroid Build Coastguard Worker //
162*ec779b8eSAndroid Build Coastguard Worker // Inputs:
163*ec779b8eSAndroid Build Coastguard Worker // pContext: effect engine context
164*ec779b8eSAndroid Build Coastguard Worker //
165*ec779b8eSAndroid Build Coastguard Worker // Outputs:
166*ec779b8eSAndroid Build Coastguard Worker //
167*ec779b8eSAndroid Build Coastguard Worker //----------------------------------------------------------------------------
168*ec779b8eSAndroid Build Coastguard Worker
LE_init(LoudnessEnhancerContext * pContext)169*ec779b8eSAndroid Build Coastguard Worker int LE_init(LoudnessEnhancerContext *pContext)
170*ec779b8eSAndroid Build Coastguard Worker {
171*ec779b8eSAndroid Build Coastguard Worker ALOGV("LE_init(%p)", pContext);
172*ec779b8eSAndroid Build Coastguard Worker
173*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
174*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
175*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.inputCfg.format = kProcessFormat;
176*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.inputCfg.samplingRate = 44100;
177*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
178*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
179*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
180*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
181*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
182*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
183*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.outputCfg.format = kProcessFormat;
184*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.outputCfg.samplingRate = 44100;
185*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
186*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
187*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
188*ec779b8eSAndroid Build Coastguard Worker pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
189*ec779b8eSAndroid Build Coastguard Worker
190*ec779b8eSAndroid Build Coastguard Worker pContext->mTargetGainmB = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB;
191*ec779b8eSAndroid Build Coastguard Worker float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
192*ec779b8eSAndroid Build Coastguard Worker ALOGV("LE_init(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
193*ec779b8eSAndroid Build Coastguard Worker
194*ec779b8eSAndroid Build Coastguard Worker if (pContext->mCompressor == NULL) {
195*ec779b8eSAndroid Build Coastguard Worker pContext->mCompressor = new le_fx::AdaptiveDynamicRangeCompression();
196*ec779b8eSAndroid Build Coastguard Worker pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
197*ec779b8eSAndroid Build Coastguard Worker }
198*ec779b8eSAndroid Build Coastguard Worker
199*ec779b8eSAndroid Build Coastguard Worker LE_setConfig(pContext, &pContext->mConfig);
200*ec779b8eSAndroid Build Coastguard Worker
201*ec779b8eSAndroid Build Coastguard Worker return 0;
202*ec779b8eSAndroid Build Coastguard Worker }
203*ec779b8eSAndroid Build Coastguard Worker
204*ec779b8eSAndroid Build Coastguard Worker //
205*ec779b8eSAndroid Build Coastguard Worker //--- Effect Library Interface Implementation
206*ec779b8eSAndroid Build Coastguard Worker //
207*ec779b8eSAndroid Build Coastguard Worker
LELib_Create(const effect_uuid_t * uuid,int32_t sessionId __unused,int32_t ioId __unused,effect_handle_t * pHandle)208*ec779b8eSAndroid Build Coastguard Worker int LELib_Create(const effect_uuid_t *uuid,
209*ec779b8eSAndroid Build Coastguard Worker int32_t sessionId __unused,
210*ec779b8eSAndroid Build Coastguard Worker int32_t ioId __unused,
211*ec779b8eSAndroid Build Coastguard Worker effect_handle_t *pHandle) {
212*ec779b8eSAndroid Build Coastguard Worker ALOGV("LELib_Create()");
213*ec779b8eSAndroid Build Coastguard Worker int ret;
214*ec779b8eSAndroid Build Coastguard Worker
215*ec779b8eSAndroid Build Coastguard Worker if (pHandle == NULL || uuid == NULL) {
216*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
217*ec779b8eSAndroid Build Coastguard Worker }
218*ec779b8eSAndroid Build Coastguard Worker
219*ec779b8eSAndroid Build Coastguard Worker if (memcmp(uuid, &gLEDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
220*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
221*ec779b8eSAndroid Build Coastguard Worker }
222*ec779b8eSAndroid Build Coastguard Worker
223*ec779b8eSAndroid Build Coastguard Worker LoudnessEnhancerContext *pContext = new LoudnessEnhancerContext;
224*ec779b8eSAndroid Build Coastguard Worker
225*ec779b8eSAndroid Build Coastguard Worker pContext->mItfe = &gLEInterface;
226*ec779b8eSAndroid Build Coastguard Worker pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
227*ec779b8eSAndroid Build Coastguard Worker
228*ec779b8eSAndroid Build Coastguard Worker pContext->mCompressor = NULL;
229*ec779b8eSAndroid Build Coastguard Worker ret = LE_init(pContext);
230*ec779b8eSAndroid Build Coastguard Worker if (ret < 0) {
231*ec779b8eSAndroid Build Coastguard Worker ALOGW("LELib_Create() init failed");
232*ec779b8eSAndroid Build Coastguard Worker delete pContext;
233*ec779b8eSAndroid Build Coastguard Worker return ret;
234*ec779b8eSAndroid Build Coastguard Worker }
235*ec779b8eSAndroid Build Coastguard Worker
236*ec779b8eSAndroid Build Coastguard Worker *pHandle = (effect_handle_t)pContext;
237*ec779b8eSAndroid Build Coastguard Worker
238*ec779b8eSAndroid Build Coastguard Worker pContext->mState = LOUDNESS_ENHANCER_STATE_INITIALIZED;
239*ec779b8eSAndroid Build Coastguard Worker
240*ec779b8eSAndroid Build Coastguard Worker ALOGV(" LELib_Create context is %p", pContext);
241*ec779b8eSAndroid Build Coastguard Worker
242*ec779b8eSAndroid Build Coastguard Worker return 0;
243*ec779b8eSAndroid Build Coastguard Worker
244*ec779b8eSAndroid Build Coastguard Worker }
245*ec779b8eSAndroid Build Coastguard Worker
LELib_Release(effect_handle_t handle)246*ec779b8eSAndroid Build Coastguard Worker int LELib_Release(effect_handle_t handle) {
247*ec779b8eSAndroid Build Coastguard Worker LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)handle;
248*ec779b8eSAndroid Build Coastguard Worker
249*ec779b8eSAndroid Build Coastguard Worker ALOGV("LELib_Release %p", handle);
250*ec779b8eSAndroid Build Coastguard Worker if (pContext == NULL) {
251*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
252*ec779b8eSAndroid Build Coastguard Worker }
253*ec779b8eSAndroid Build Coastguard Worker pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
254*ec779b8eSAndroid Build Coastguard Worker if (pContext->mCompressor != NULL) {
255*ec779b8eSAndroid Build Coastguard Worker delete pContext->mCompressor;
256*ec779b8eSAndroid Build Coastguard Worker pContext->mCompressor = NULL;
257*ec779b8eSAndroid Build Coastguard Worker }
258*ec779b8eSAndroid Build Coastguard Worker delete pContext;
259*ec779b8eSAndroid Build Coastguard Worker
260*ec779b8eSAndroid Build Coastguard Worker return 0;
261*ec779b8eSAndroid Build Coastguard Worker }
262*ec779b8eSAndroid Build Coastguard Worker
LELib_GetDescriptor(const effect_uuid_t * uuid,effect_descriptor_t * pDescriptor)263*ec779b8eSAndroid Build Coastguard Worker int LELib_GetDescriptor(const effect_uuid_t *uuid,
264*ec779b8eSAndroid Build Coastguard Worker effect_descriptor_t *pDescriptor) {
265*ec779b8eSAndroid Build Coastguard Worker
266*ec779b8eSAndroid Build Coastguard Worker if (pDescriptor == NULL || uuid == NULL){
267*ec779b8eSAndroid Build Coastguard Worker ALOGV("LELib_GetDescriptor() called with NULL pointer");
268*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
269*ec779b8eSAndroid Build Coastguard Worker }
270*ec779b8eSAndroid Build Coastguard Worker
271*ec779b8eSAndroid Build Coastguard Worker if (memcmp(uuid, &gLEDescriptor.uuid, sizeof(effect_uuid_t)) == 0) {
272*ec779b8eSAndroid Build Coastguard Worker *pDescriptor = gLEDescriptor;
273*ec779b8eSAndroid Build Coastguard Worker return 0;
274*ec779b8eSAndroid Build Coastguard Worker }
275*ec779b8eSAndroid Build Coastguard Worker
276*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
277*ec779b8eSAndroid Build Coastguard Worker } /* end LELib_GetDescriptor */
278*ec779b8eSAndroid Build Coastguard Worker
279*ec779b8eSAndroid Build Coastguard Worker //
280*ec779b8eSAndroid Build Coastguard Worker //--- Effect Control Interface Implementation
281*ec779b8eSAndroid Build Coastguard Worker //
LE_process(effect_handle_t self,audio_buffer_t * inBuffer,audio_buffer_t * outBuffer)282*ec779b8eSAndroid Build Coastguard Worker int LE_process(
283*ec779b8eSAndroid Build Coastguard Worker effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
284*ec779b8eSAndroid Build Coastguard Worker {
285*ec779b8eSAndroid Build Coastguard Worker LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)self;
286*ec779b8eSAndroid Build Coastguard Worker
287*ec779b8eSAndroid Build Coastguard Worker if (pContext == NULL) {
288*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
289*ec779b8eSAndroid Build Coastguard Worker }
290*ec779b8eSAndroid Build Coastguard Worker
291*ec779b8eSAndroid Build Coastguard Worker if (inBuffer == NULL || inBuffer->raw == NULL ||
292*ec779b8eSAndroid Build Coastguard Worker outBuffer == NULL || outBuffer->raw == NULL ||
293*ec779b8eSAndroid Build Coastguard Worker inBuffer->frameCount != outBuffer->frameCount ||
294*ec779b8eSAndroid Build Coastguard Worker inBuffer->frameCount == 0) {
295*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
296*ec779b8eSAndroid Build Coastguard Worker }
297*ec779b8eSAndroid Build Coastguard Worker
298*ec779b8eSAndroid Build Coastguard Worker //ALOGV("LE about to process %d samples", inBuffer->frameCount);
299*ec779b8eSAndroid Build Coastguard Worker uint16_t inIdx;
300*ec779b8eSAndroid Build Coastguard Worker #ifdef BUILD_FLOAT
301*ec779b8eSAndroid Build Coastguard Worker constexpr float scale = 1 << 15; // power of 2 is lossless conversion to int16_t range
302*ec779b8eSAndroid Build Coastguard Worker constexpr float inverseScale = 1.f / scale;
303*ec779b8eSAndroid Build Coastguard Worker const float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f) * scale;
304*ec779b8eSAndroid Build Coastguard Worker #else
305*ec779b8eSAndroid Build Coastguard Worker float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f);
306*ec779b8eSAndroid Build Coastguard Worker #endif
307*ec779b8eSAndroid Build Coastguard Worker float leftSample, rightSample;
308*ec779b8eSAndroid Build Coastguard Worker for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) {
309*ec779b8eSAndroid Build Coastguard Worker // makeup gain is applied on the input of the compressor
310*ec779b8eSAndroid Build Coastguard Worker #ifdef BUILD_FLOAT
311*ec779b8eSAndroid Build Coastguard Worker leftSample = inputAmp * inBuffer->f32[2*inIdx];
312*ec779b8eSAndroid Build Coastguard Worker rightSample = inputAmp * inBuffer->f32[2*inIdx +1];
313*ec779b8eSAndroid Build Coastguard Worker pContext->mCompressor->Compress(&leftSample, &rightSample);
314*ec779b8eSAndroid Build Coastguard Worker inBuffer->f32[2*inIdx] = leftSample * inverseScale;
315*ec779b8eSAndroid Build Coastguard Worker inBuffer->f32[2*inIdx +1] = rightSample * inverseScale;
316*ec779b8eSAndroid Build Coastguard Worker #else
317*ec779b8eSAndroid Build Coastguard Worker leftSample = inputAmp * (float)inBuffer->s16[2*inIdx];
318*ec779b8eSAndroid Build Coastguard Worker rightSample = inputAmp * (float)inBuffer->s16[2*inIdx +1];
319*ec779b8eSAndroid Build Coastguard Worker pContext->mCompressor->Compress(&leftSample, &rightSample);
320*ec779b8eSAndroid Build Coastguard Worker inBuffer->s16[2*inIdx] = (int16_t) leftSample;
321*ec779b8eSAndroid Build Coastguard Worker inBuffer->s16[2*inIdx +1] = (int16_t) rightSample;
322*ec779b8eSAndroid Build Coastguard Worker #endif // BUILD_FLOAT
323*ec779b8eSAndroid Build Coastguard Worker }
324*ec779b8eSAndroid Build Coastguard Worker
325*ec779b8eSAndroid Build Coastguard Worker if (inBuffer->raw != outBuffer->raw) {
326*ec779b8eSAndroid Build Coastguard Worker #ifdef BUILD_FLOAT
327*ec779b8eSAndroid Build Coastguard Worker if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
328*ec779b8eSAndroid Build Coastguard Worker for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
329*ec779b8eSAndroid Build Coastguard Worker outBuffer->f32[i] += inBuffer->f32[i];
330*ec779b8eSAndroid Build Coastguard Worker }
331*ec779b8eSAndroid Build Coastguard Worker } else {
332*ec779b8eSAndroid Build Coastguard Worker memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(float));
333*ec779b8eSAndroid Build Coastguard Worker }
334*ec779b8eSAndroid Build Coastguard Worker #else
335*ec779b8eSAndroid Build Coastguard Worker if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
336*ec779b8eSAndroid Build Coastguard Worker for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
337*ec779b8eSAndroid Build Coastguard Worker outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
338*ec779b8eSAndroid Build Coastguard Worker }
339*ec779b8eSAndroid Build Coastguard Worker } else {
340*ec779b8eSAndroid Build Coastguard Worker memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
341*ec779b8eSAndroid Build Coastguard Worker }
342*ec779b8eSAndroid Build Coastguard Worker #endif // BUILD_FLOAT
343*ec779b8eSAndroid Build Coastguard Worker }
344*ec779b8eSAndroid Build Coastguard Worker if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) {
345*ec779b8eSAndroid Build Coastguard Worker return -ENODATA;
346*ec779b8eSAndroid Build Coastguard Worker }
347*ec779b8eSAndroid Build Coastguard Worker return 0;
348*ec779b8eSAndroid Build Coastguard Worker }
349*ec779b8eSAndroid Build Coastguard Worker
LE_command(effect_handle_t self,uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)350*ec779b8eSAndroid Build Coastguard Worker int LE_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
351*ec779b8eSAndroid Build Coastguard Worker void *pCmdData, uint32_t *replySize, void *pReplyData) {
352*ec779b8eSAndroid Build Coastguard Worker
353*ec779b8eSAndroid Build Coastguard Worker LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)self;
354*ec779b8eSAndroid Build Coastguard Worker
355*ec779b8eSAndroid Build Coastguard Worker if (pContext == NULL || pContext->mState == LOUDNESS_ENHANCER_STATE_UNINITIALIZED) {
356*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
357*ec779b8eSAndroid Build Coastguard Worker }
358*ec779b8eSAndroid Build Coastguard Worker
359*ec779b8eSAndroid Build Coastguard Worker // ALOGV("LE_command command %d cmdSize %d",cmdCode, cmdSize);
360*ec779b8eSAndroid Build Coastguard Worker switch (cmdCode) {
361*ec779b8eSAndroid Build Coastguard Worker case EFFECT_CMD_INIT:
362*ec779b8eSAndroid Build Coastguard Worker if (pReplyData == NULL || *replySize != sizeof(int)) {
363*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
364*ec779b8eSAndroid Build Coastguard Worker }
365*ec779b8eSAndroid Build Coastguard Worker *(int *) pReplyData = LE_init(pContext);
366*ec779b8eSAndroid Build Coastguard Worker break;
367*ec779b8eSAndroid Build Coastguard Worker case EFFECT_CMD_SET_CONFIG:
368*ec779b8eSAndroid Build Coastguard Worker if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
369*ec779b8eSAndroid Build Coastguard Worker || pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
370*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
371*ec779b8eSAndroid Build Coastguard Worker }
372*ec779b8eSAndroid Build Coastguard Worker *(int *) pReplyData = LE_setConfig(pContext,
373*ec779b8eSAndroid Build Coastguard Worker (effect_config_t *) pCmdData);
374*ec779b8eSAndroid Build Coastguard Worker break;
375*ec779b8eSAndroid Build Coastguard Worker case EFFECT_CMD_GET_CONFIG:
376*ec779b8eSAndroid Build Coastguard Worker if (pReplyData == NULL ||
377*ec779b8eSAndroid Build Coastguard Worker *replySize != sizeof(effect_config_t)) {
378*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
379*ec779b8eSAndroid Build Coastguard Worker }
380*ec779b8eSAndroid Build Coastguard Worker LE_getConfig(pContext, (effect_config_t *)pReplyData);
381*ec779b8eSAndroid Build Coastguard Worker break;
382*ec779b8eSAndroid Build Coastguard Worker case EFFECT_CMD_RESET:
383*ec779b8eSAndroid Build Coastguard Worker LE_reset(pContext);
384*ec779b8eSAndroid Build Coastguard Worker break;
385*ec779b8eSAndroid Build Coastguard Worker case EFFECT_CMD_ENABLE:
386*ec779b8eSAndroid Build Coastguard Worker if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
387*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
388*ec779b8eSAndroid Build Coastguard Worker }
389*ec779b8eSAndroid Build Coastguard Worker if (pContext->mState != LOUDNESS_ENHANCER_STATE_INITIALIZED) {
390*ec779b8eSAndroid Build Coastguard Worker return -ENOSYS;
391*ec779b8eSAndroid Build Coastguard Worker }
392*ec779b8eSAndroid Build Coastguard Worker pContext->mState = LOUDNESS_ENHANCER_STATE_ACTIVE;
393*ec779b8eSAndroid Build Coastguard Worker ALOGV("EFFECT_CMD_ENABLE() OK");
394*ec779b8eSAndroid Build Coastguard Worker *(int *)pReplyData = 0;
395*ec779b8eSAndroid Build Coastguard Worker break;
396*ec779b8eSAndroid Build Coastguard Worker case EFFECT_CMD_DISABLE:
397*ec779b8eSAndroid Build Coastguard Worker if (pReplyData == NULL || *replySize != sizeof(int)) {
398*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
399*ec779b8eSAndroid Build Coastguard Worker }
400*ec779b8eSAndroid Build Coastguard Worker if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) {
401*ec779b8eSAndroid Build Coastguard Worker return -ENOSYS;
402*ec779b8eSAndroid Build Coastguard Worker }
403*ec779b8eSAndroid Build Coastguard Worker pContext->mState = LOUDNESS_ENHANCER_STATE_INITIALIZED;
404*ec779b8eSAndroid Build Coastguard Worker ALOGV("EFFECT_CMD_DISABLE() OK");
405*ec779b8eSAndroid Build Coastguard Worker *(int *)pReplyData = 0;
406*ec779b8eSAndroid Build Coastguard Worker break;
407*ec779b8eSAndroid Build Coastguard Worker case EFFECT_CMD_GET_PARAM: {
408*ec779b8eSAndroid Build Coastguard Worker if (pCmdData == NULL ||
409*ec779b8eSAndroid Build Coastguard Worker cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
410*ec779b8eSAndroid Build Coastguard Worker pReplyData == NULL || replySize == NULL ||
411*ec779b8eSAndroid Build Coastguard Worker *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
412*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
413*ec779b8eSAndroid Build Coastguard Worker }
414*ec779b8eSAndroid Build Coastguard Worker memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
415*ec779b8eSAndroid Build Coastguard Worker effect_param_t *p = (effect_param_t *)pReplyData;
416*ec779b8eSAndroid Build Coastguard Worker p->status = 0;
417*ec779b8eSAndroid Build Coastguard Worker *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
418*ec779b8eSAndroid Build Coastguard Worker if (p->psize != sizeof(uint32_t)) {
419*ec779b8eSAndroid Build Coastguard Worker p->status = -EINVAL;
420*ec779b8eSAndroid Build Coastguard Worker break;
421*ec779b8eSAndroid Build Coastguard Worker }
422*ec779b8eSAndroid Build Coastguard Worker switch (*(uint32_t *)p->data) {
423*ec779b8eSAndroid Build Coastguard Worker case LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB:
424*ec779b8eSAndroid Build Coastguard Worker ALOGV("get target gain(mB) = %d", pContext->mTargetGainmB);
425*ec779b8eSAndroid Build Coastguard Worker *((int32_t *)p->data + 1) = pContext->mTargetGainmB;
426*ec779b8eSAndroid Build Coastguard Worker p->vsize = sizeof(int32_t);
427*ec779b8eSAndroid Build Coastguard Worker *replySize += sizeof(int32_t);
428*ec779b8eSAndroid Build Coastguard Worker break;
429*ec779b8eSAndroid Build Coastguard Worker default:
430*ec779b8eSAndroid Build Coastguard Worker p->status = -EINVAL;
431*ec779b8eSAndroid Build Coastguard Worker }
432*ec779b8eSAndroid Build Coastguard Worker } break;
433*ec779b8eSAndroid Build Coastguard Worker case EFFECT_CMD_SET_PARAM: {
434*ec779b8eSAndroid Build Coastguard Worker if (pCmdData == NULL ||
435*ec779b8eSAndroid Build Coastguard Worker cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
436*ec779b8eSAndroid Build Coastguard Worker pReplyData == NULL || replySize == NULL || *replySize != sizeof(int32_t)) {
437*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
438*ec779b8eSAndroid Build Coastguard Worker }
439*ec779b8eSAndroid Build Coastguard Worker *(int32_t *)pReplyData = 0;
440*ec779b8eSAndroid Build Coastguard Worker effect_param_t *p = (effect_param_t *)pCmdData;
441*ec779b8eSAndroid Build Coastguard Worker if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) {
442*ec779b8eSAndroid Build Coastguard Worker *(int32_t *)pReplyData = -EINVAL;
443*ec779b8eSAndroid Build Coastguard Worker break;
444*ec779b8eSAndroid Build Coastguard Worker }
445*ec779b8eSAndroid Build Coastguard Worker switch (*(uint32_t *)p->data) {
446*ec779b8eSAndroid Build Coastguard Worker case LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB:
447*ec779b8eSAndroid Build Coastguard Worker pContext->mTargetGainmB = *((int32_t *)p->data + 1);
448*ec779b8eSAndroid Build Coastguard Worker ALOGV("set target gain(mB) = %d", pContext->mTargetGainmB);
449*ec779b8eSAndroid Build Coastguard Worker LE_reset(pContext); // apply parameter update
450*ec779b8eSAndroid Build Coastguard Worker break;
451*ec779b8eSAndroid Build Coastguard Worker default:
452*ec779b8eSAndroid Build Coastguard Worker *(int32_t *)pReplyData = -EINVAL;
453*ec779b8eSAndroid Build Coastguard Worker }
454*ec779b8eSAndroid Build Coastguard Worker } break;
455*ec779b8eSAndroid Build Coastguard Worker case EFFECT_CMD_SET_DEVICE:
456*ec779b8eSAndroid Build Coastguard Worker case EFFECT_CMD_SET_VOLUME:
457*ec779b8eSAndroid Build Coastguard Worker case EFFECT_CMD_SET_AUDIO_MODE:
458*ec779b8eSAndroid Build Coastguard Worker break;
459*ec779b8eSAndroid Build Coastguard Worker
460*ec779b8eSAndroid Build Coastguard Worker default:
461*ec779b8eSAndroid Build Coastguard Worker ALOGW("LE_command invalid command %d",cmdCode);
462*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
463*ec779b8eSAndroid Build Coastguard Worker }
464*ec779b8eSAndroid Build Coastguard Worker
465*ec779b8eSAndroid Build Coastguard Worker return 0;
466*ec779b8eSAndroid Build Coastguard Worker }
467*ec779b8eSAndroid Build Coastguard Worker
468*ec779b8eSAndroid Build Coastguard Worker /* Effect Control Interface Implementation: get_descriptor */
LE_getDescriptor(effect_handle_t self,effect_descriptor_t * pDescriptor)469*ec779b8eSAndroid Build Coastguard Worker int LE_getDescriptor(effect_handle_t self,
470*ec779b8eSAndroid Build Coastguard Worker effect_descriptor_t *pDescriptor)
471*ec779b8eSAndroid Build Coastguard Worker {
472*ec779b8eSAndroid Build Coastguard Worker LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *) self;
473*ec779b8eSAndroid Build Coastguard Worker
474*ec779b8eSAndroid Build Coastguard Worker if (pContext == NULL || pDescriptor == NULL) {
475*ec779b8eSAndroid Build Coastguard Worker ALOGV("LE_getDescriptor() invalid param");
476*ec779b8eSAndroid Build Coastguard Worker return -EINVAL;
477*ec779b8eSAndroid Build Coastguard Worker }
478*ec779b8eSAndroid Build Coastguard Worker
479*ec779b8eSAndroid Build Coastguard Worker *pDescriptor = gLEDescriptor;
480*ec779b8eSAndroid Build Coastguard Worker
481*ec779b8eSAndroid Build Coastguard Worker return 0;
482*ec779b8eSAndroid Build Coastguard Worker } /* end LE_getDescriptor */
483*ec779b8eSAndroid Build Coastguard Worker
484*ec779b8eSAndroid Build Coastguard Worker // effect_handle_t interface implementation for DRC effect
485*ec779b8eSAndroid Build Coastguard Worker const struct effect_interface_s gLEInterface = {
486*ec779b8eSAndroid Build Coastguard Worker LE_process,
487*ec779b8eSAndroid Build Coastguard Worker LE_command,
488*ec779b8eSAndroid Build Coastguard Worker LE_getDescriptor,
489*ec779b8eSAndroid Build Coastguard Worker NULL,
490*ec779b8eSAndroid Build Coastguard Worker };
491*ec779b8eSAndroid Build Coastguard Worker
492*ec779b8eSAndroid Build Coastguard Worker // This is the only symbol that needs to be exported
493*ec779b8eSAndroid Build Coastguard Worker __attribute__ ((visibility ("default")))
494*ec779b8eSAndroid Build Coastguard Worker audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
495*ec779b8eSAndroid Build Coastguard Worker .tag = AUDIO_EFFECT_LIBRARY_TAG,
496*ec779b8eSAndroid Build Coastguard Worker .version = EFFECT_LIBRARY_API_VERSION,
497*ec779b8eSAndroid Build Coastguard Worker .name = "Loudness Enhancer Library",
498*ec779b8eSAndroid Build Coastguard Worker .implementor = "The Android Open Source Project",
499*ec779b8eSAndroid Build Coastguard Worker .create_effect = LELib_Create,
500*ec779b8eSAndroid Build Coastguard Worker .release_effect = LELib_Release,
501*ec779b8eSAndroid Build Coastguard Worker .get_descriptor = LELib_GetDescriptor,
502*ec779b8eSAndroid Build Coastguard Worker };
503*ec779b8eSAndroid Build Coastguard Worker
504*ec779b8eSAndroid Build Coastguard Worker }; // extern "C"
505*ec779b8eSAndroid Build Coastguard Worker
506