16cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi/*
26cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * Copyright (C) 2013 The Android Open Source Project
36cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi *
46cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License");
56cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * you may not use this file except in compliance with the License.
66cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * You may obtain a copy of the License at
76cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi *
86cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi *      http://www.apache.org/licenses/LICENSE-2.0
96cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi *
106cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * Unless required by applicable law or agreed to in writing, software
116cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS,
126cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * See the License for the specific language governing permissions and
146cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi * limitations under the License.
156cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi */
166cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
176cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#define LOG_TAG "EffectLE"
186cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//#define LOG_NDEBUG 0
196cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include <cutils/log.h>
206cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include <assert.h>
216cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include <stdlib.h>
226cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include <string.h>
236cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include <new>
246cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include <time.h>
256cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include <math.h>
266cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include <audio_effects/effect_loudnessenhancer.h>
276cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi#include "dsp/core/dynamic_range_compression.h"
286cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
296cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviextern "C" {
306cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
316cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// effect_handle_t interface implementation for LE effect
326cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviextern const struct effect_interface_s gLEInterface;
336cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
346cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// AOSP Loudness Enhancer UUID: fa415329-2034-4bea-b5dc-5b381c8d1e2c
356cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviconst effect_descriptor_t gLEDescriptor = {
366cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        {0xfe3199be, 0xaed0, 0x413f, 0x87bb, {0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}, // type
376cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        {0xfa415329, 0x2034, 0x4bea, 0xb5dc, {0x5b, 0x38, 0x1c, 0x8d, 0x1e, 0x2c}}, // uuid
386cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        EFFECT_CONTROL_API_VERSION,
396cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
406cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        0, // TODO
416cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        1,
426cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        "Loudness Enhancer",
436cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        "The Android Open Source Project",
446cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi};
456cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
466cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivienum le_state_e {
476cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    LOUDNESS_ENHANCER_STATE_UNINITIALIZED,
486cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    LOUDNESS_ENHANCER_STATE_INITIALIZED,
496cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    LOUDNESS_ENHANCER_STATE_ACTIVE,
506cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi};
516cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
526cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivistruct LoudnessEnhancerContext {
536cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    const struct effect_interface_s *mItfe;
546cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    effect_config_t mConfig;
556cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    uint8_t mState;
566cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    int32_t mTargetGainmB;// target gain in mB
576cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // in this implementation, there is no coupling between the compression on the left and right
586cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    // channels
59cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi    le_fx::AdaptiveDynamicRangeCompression* mCompressor;
606cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi};
616cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
626cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
636cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//--- Local functions (not directly used by effect interface)
646cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
656cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
666cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivivoid LE_reset(LoudnessEnhancerContext *pContext)
676cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi{
686cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    ALOGV("  > LE_reset(%p)", pContext);
696cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
70cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi    if (pContext->mCompressor != NULL) {
716cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
726cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        ALOGV("LE_reset(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
73cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi        pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
746cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    } else {
756cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        ALOGE("LE_reset(%p): null compressors, can't apply target gain", pContext);
766cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
776cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}
786cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
796cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivistatic inline int16_t clamp16(int32_t sample)
806cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi{
816cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if ((sample>>15) ^ (sample>>31))
826cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        sample = 0x7FFF ^ (sample>>31);
836cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    return sample;
846cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}
856cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
866cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//----------------------------------------------------------------------------
876cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// LE_setConfig()
886cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//----------------------------------------------------------------------------
896cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// Purpose: Set input and output audio configuration.
906cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
916cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// Inputs:
926cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//  pContext:   effect engine context
936cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//  pConfig:    pointer to effect_config_t structure holding input and output
946cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//      configuration parameters
956cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
966cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// Outputs:
976cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
986cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//----------------------------------------------------------------------------
996cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1006cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviint LE_setConfig(LoudnessEnhancerContext *pContext, effect_config_t *pConfig)
1016cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi{
1026cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    ALOGV("LE_setConfig(%p)", pContext);
1036cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1046cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
1056cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
1066cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
1076cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
1086cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
1096cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
1106cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
1116cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1126cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig = *pConfig;
1136cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1146cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    LE_reset(pContext);
1156cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1166cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    return 0;
1176cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}
1186cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1196cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1206cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//----------------------------------------------------------------------------
1216cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// LE_getConfig()
1226cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//----------------------------------------------------------------------------
1236cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// Purpose: Get input and output audio configuration.
1246cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
1256cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// Inputs:
1266cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//  pContext:   effect engine context
1276cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//  pConfig:    pointer to effect_config_t structure holding input and output
1286cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//      configuration parameters
1296cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
1306cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// Outputs:
1316cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
1326cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//----------------------------------------------------------------------------
1336cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1346cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivivoid LE_getConfig(LoudnessEnhancerContext *pContext, effect_config_t *pConfig)
1356cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi{
1366cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    *pConfig = pContext->mConfig;
1376cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}
1386cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1396cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1406cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//----------------------------------------------------------------------------
1416cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// LE_init()
1426cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//----------------------------------------------------------------------------
1436cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// Purpose: Initialize engine with default configuration.
1446cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
1456cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// Inputs:
1466cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//  pContext:   effect engine context
1476cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
1486cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// Outputs:
1496cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
1506cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//----------------------------------------------------------------------------
1516cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1526cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviint LE_init(LoudnessEnhancerContext *pContext)
1536cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi{
1546cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    ALOGV("LE_init(%p)", pContext);
1556cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1566cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
1576cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
1586cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
1596cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.inputCfg.samplingRate = 44100;
1606cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
1616cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
1626cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
1636cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
1646cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
1656cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
1666cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
1676cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.outputCfg.samplingRate = 44100;
1686cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
1696cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
1706cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
1716cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
1726cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1736cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mTargetGainmB = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB;
1746cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
1756cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    ALOGV("LE_init(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
1766cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
177cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi    if (pContext->mCompressor == NULL) {
178cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi        pContext->mCompressor = new le_fx::AdaptiveDynamicRangeCompression();
179cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi        pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
1806cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
1816cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1826cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    LE_setConfig(pContext, &pContext->mConfig);
1836cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1846cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    return 0;
1856cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}
1866cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1876cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
1886cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//--- Effect Library Interface Implementation
1896cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
1906cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1916cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviint LELib_Create(const effect_uuid_t *uuid,
1926cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi                         int32_t sessionId,
1936cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi                         int32_t ioId,
1946cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi                         effect_handle_t *pHandle) {
1956cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    ALOGV("LELib_Create()");
1966cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    int ret;
1976cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    int i;
1986cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
1996cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pHandle == NULL || uuid == NULL) {
2006cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return -EINVAL;
2016cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
2026cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2036cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (memcmp(uuid, &gLEDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
2046cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return -EINVAL;
2056cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
2066cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2076cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    LoudnessEnhancerContext *pContext = new LoudnessEnhancerContext;
2086cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2096cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mItfe = &gLEInterface;
2106cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
2116cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
212cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi    pContext->mCompressor = NULL;
2136cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    ret = LE_init(pContext);
2146cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (ret < 0) {
2156cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        ALOGW("LELib_Create() init failed");
2166cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        delete pContext;
2176cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return ret;
2186cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
2196cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2206cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    *pHandle = (effect_handle_t)pContext;
2216cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2226cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mState = LOUDNESS_ENHANCER_STATE_INITIALIZED;
2236cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2246cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    ALOGV("  LELib_Create context is %p", pContext);
2256cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2266cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    return 0;
2276cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2286cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}
2296cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2306cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviint LELib_Release(effect_handle_t handle) {
2316cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)handle;
2326cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2336cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    ALOGV("LELib_Release %p", handle);
2346cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pContext == NULL) {
2356cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return -EINVAL;
2366cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
2376cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
238cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi    if (pContext->mCompressor != NULL) {
239cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi        delete pContext->mCompressor;
240cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi        pContext->mCompressor = NULL;
2416cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
2426cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    delete pContext;
2436cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2446cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    return 0;
2456cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}
2466cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2476cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviint LELib_GetDescriptor(const effect_uuid_t *uuid,
2486cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi                                effect_descriptor_t *pDescriptor) {
2496cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2506cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pDescriptor == NULL || uuid == NULL){
2516cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        ALOGV("LELib_GetDescriptor() called with NULL pointer");
2526cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return -EINVAL;
2536cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
2546cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2556cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (memcmp(uuid, &gLEDescriptor.uuid, sizeof(effect_uuid_t)) == 0) {
2566cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        *pDescriptor = gLEDescriptor;
2576cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return 0;
2586cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
2596cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2606cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    return  -EINVAL;
2616cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi} /* end LELib_GetDescriptor */
2626cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2636cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
2646cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//--- Effect Control Interface Implementation
2656cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//
2666cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviint LE_process(
2676cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
2686cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi{
2696cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)self;
2706cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2716cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pContext == NULL) {
2726cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return -EINVAL;
2736cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
2746cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2756cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (inBuffer == NULL || inBuffer->raw == NULL ||
2766cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        outBuffer == NULL || outBuffer->raw == NULL ||
2776cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        inBuffer->frameCount != outBuffer->frameCount ||
2786cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        inBuffer->frameCount == 0) {
2796cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return -EINVAL;
2806cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
2816cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2826cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    //ALOGV("LE about to process %d samples", inBuffer->frameCount);
2836cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    uint16_t inIdx;
2846cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f);
285cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi    float leftSample, rightSample;
2866cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) {
287cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi        // makeup gain is applied on the input of the compressor
288cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi        leftSample  = inputAmp * (float)inBuffer->s16[2*inIdx];
289cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi        rightSample = inputAmp * (float)inBuffer->s16[2*inIdx +1];
290cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi        pContext->mCompressor->Compress(&leftSample, &rightSample);
291cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi        inBuffer->s16[2*inIdx]    = (int16_t) leftSample;
292cd0c4683947231a7d3dc7811bedb75c5a965103cJean-Michel Trivi        inBuffer->s16[2*inIdx +1] = (int16_t) rightSample;
2936cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
2946cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
2956cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (inBuffer->raw != outBuffer->raw) {
2966cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
2976cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
2986cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi                outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
2996cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            }
3006cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        } else {
3016cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
3026cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
3036cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
3046cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) {
3056cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return -ENODATA;
3066cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
3076cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    return 0;
3086cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}
3096cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
3106cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviint LE_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
3116cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        void *pCmdData, uint32_t *replySize, void *pReplyData) {
3126cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
3136cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)self;
3146cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    int retsize;
3156cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
3166cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pContext == NULL || pContext->mState == LOUDNESS_ENHANCER_STATE_UNINITIALIZED) {
3176cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return -EINVAL;
3186cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
3196cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
3206cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi//    ALOGV("LE_command command %d cmdSize %d",cmdCode, cmdSize);
3216cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    switch (cmdCode) {
3226cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    case EFFECT_CMD_INIT:
3236cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (pReplyData == NULL || *replySize != sizeof(int)) {
3246cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            return -EINVAL;
3256cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
3266cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        *(int *) pReplyData = LE_init(pContext);
3276cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        break;
3286cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    case EFFECT_CMD_SET_CONFIG:
3296cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
3306cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi                || pReplyData == NULL || *replySize != sizeof(int)) {
3316cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            return -EINVAL;
3326cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
3336cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        *(int *) pReplyData = LE_setConfig(pContext,
3346cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi                (effect_config_t *) pCmdData);
3356cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        break;
3366cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    case EFFECT_CMD_GET_CONFIG:
3376cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (pReplyData == NULL ||
3386cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            *replySize != sizeof(effect_config_t)) {
3396cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            return -EINVAL;
3406cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
3416cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        LE_getConfig(pContext, (effect_config_t *)pReplyData);
3426cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        break;
3436cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    case EFFECT_CMD_RESET:
3446cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        LE_reset(pContext);
3456cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        break;
3466cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    case EFFECT_CMD_ENABLE:
3476cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (pReplyData == NULL || *replySize != sizeof(int)) {
3486cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            return -EINVAL;
3496cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
3506cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (pContext->mState != LOUDNESS_ENHANCER_STATE_INITIALIZED) {
3516cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            return -ENOSYS;
3526cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
3536cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        pContext->mState = LOUDNESS_ENHANCER_STATE_ACTIVE;
3546cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        ALOGV("EFFECT_CMD_ENABLE() OK");
3556cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        *(int *)pReplyData = 0;
3566cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        break;
3576cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    case EFFECT_CMD_DISABLE:
3586cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (pReplyData == NULL || *replySize != sizeof(int)) {
3596cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            return -EINVAL;
3606cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
3616cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) {
3626cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            return -ENOSYS;
3636cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
3646cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        pContext->mState = LOUDNESS_ENHANCER_STATE_INITIALIZED;
3656cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        ALOGV("EFFECT_CMD_DISABLE() OK");
3666cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        *(int *)pReplyData = 0;
3676cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        break;
3686cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    case EFFECT_CMD_GET_PARAM: {
3696cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (pCmdData == NULL ||
3706cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
3716cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            pReplyData == NULL ||
3726cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
3736cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            return -EINVAL;
3746cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
3756cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
3766cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        effect_param_t *p = (effect_param_t *)pReplyData;
3776cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        p->status = 0;
3786cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
3796cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (p->psize != sizeof(uint32_t)) {
3806cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            p->status = -EINVAL;
3816cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            break;
3826cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
3836cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        switch (*(uint32_t *)p->data) {
3846cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        case LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB:
3856cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            ALOGV("get target gain(mB) = %d", pContext->mTargetGainmB);
3866cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            *((int32_t *)p->data + 1) = pContext->mTargetGainmB;
3876cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            p->vsize = sizeof(int32_t);
3886cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            *replySize += sizeof(int32_t);
3896cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            break;
3906cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        default:
3916cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            p->status = -EINVAL;
3926cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
3936cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        } break;
3946cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    case EFFECT_CMD_SET_PARAM: {
3956cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (pCmdData == NULL ||
3966cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
3976cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            pReplyData == NULL || *replySize != sizeof(int32_t)) {
3986cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            return -EINVAL;
3996cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
4006cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        *(int32_t *)pReplyData = 0;
4016cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        effect_param_t *p = (effect_param_t *)pCmdData;
4026cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) {
4036cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            *(int32_t *)pReplyData = -EINVAL;
4046cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            break;
4056cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
4066cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        switch (*(uint32_t *)p->data) {
4076cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        case LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB:
4086cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            pContext->mTargetGainmB = *((int32_t *)p->data + 1);
4096cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            ALOGV("set target gain(mB) = %d", pContext->mTargetGainmB);
4106cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            LE_reset(pContext); // apply parameter update
4116cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            break;
4126cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        default:
4136cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi            *(int32_t *)pReplyData = -EINVAL;
4146cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        }
4156cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        } break;
4166cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    case EFFECT_CMD_SET_DEVICE:
4176cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    case EFFECT_CMD_SET_VOLUME:
4186cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    case EFFECT_CMD_SET_AUDIO_MODE:
4196cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        break;
4206cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
4216cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    default:
4226cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        ALOGW("LE_command invalid command %d",cmdCode);
4236cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return -EINVAL;
4246cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
4256cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
4266cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    return 0;
4276cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}
4286cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
4296cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi/* Effect Control Interface Implementation: get_descriptor */
4306cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviint LE_getDescriptor(effect_handle_t   self,
4316cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi                                    effect_descriptor_t *pDescriptor)
4326cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi{
4336cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *) self;
4346cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
4356cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    if (pContext == NULL || pDescriptor == NULL) {
4366cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        ALOGV("LE_getDescriptor() invalid param");
4376cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        return -EINVAL;
4386cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    }
4396cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
4406cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    *pDescriptor = gLEDescriptor;
4416cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
4426cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi    return 0;
4436cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}   /* end LE_getDescriptor */
4446cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
4456cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// effect_handle_t interface implementation for DRC effect
4466cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviconst struct effect_interface_s gLEInterface = {
4476cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        LE_process,
4486cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        LE_command,
4496cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        LE_getDescriptor,
4506cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi        NULL,
4516cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi};
4526cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
4536cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi// This is the only symbol that needs to be exported
4546cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi__attribute__ ((visibility ("default")))
4556cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Triviaudio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
4569803acb6b2c1b9c01444e0c8c0124adbe9a7157asynergy dev    .tag = AUDIO_EFFECT_LIBRARY_TAG,
4579803acb6b2c1b9c01444e0c8c0124adbe9a7157asynergy dev    .version = EFFECT_LIBRARY_API_VERSION,
4589803acb6b2c1b9c01444e0c8c0124adbe9a7157asynergy dev    .name = "Loudness Enhancer Library",
4599803acb6b2c1b9c01444e0c8c0124adbe9a7157asynergy dev    .implementor = "The Android Open Source Project",
4609803acb6b2c1b9c01444e0c8c0124adbe9a7157asynergy dev    .create_effect = LELib_Create,
4619803acb6b2c1b9c01444e0c8c0124adbe9a7157asynergy dev    .release_effect = LELib_Release,
4629803acb6b2c1b9c01444e0c8c0124adbe9a7157asynergy dev    .get_descriptor = LELib_GetDescriptor,
4636cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi};
4646cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
4656cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi}; // extern "C"
4666cc3a9948b51193dfdcb0c3527d7f3d1ca38aa3cJean-Michel Trivi
467