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