xref: /aosp_15_r20/frameworks/av/media/libeffects/loudness/EffectLoudnessEnhancer.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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