/*
 * Copyright (C) 2004-2010 NXP Software
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/************************************************************************************/
/*                                                                                  */
/*  Includes                                                                        */
/*                                                                                  */
/************************************************************************************/

#include "LVCS.h"
#include "LVCS_Private.h"
#include "LVCS_Tables.h"

/************************************************************************************/
/*                                                                                  */
/* FUNCTION:                 LVCS_GetParameters                                     */
/*                                                                                  */
/* DESCRIPTION:                                                                     */
/*  Request the Concert Sound parameters. The current parameter set is returned     */
/*  via the parameter pointer.                                                      */
/*                                                                                  */
/* PARAMETERS:                                                                      */
/*  hInstance                Instance handle                                        */
/*  pParams                  Pointer to an empty parameter structure                */
/*                                                                                  */
/* RETURNS:                                                                         */
/*  LVCS_Success             Always succeeds                                        */
/*                                                                                  */
/* NOTES:                                                                           */
/*  1.  This function may be interrupted by the LVCS_Process function               */
/*                                                                                  */
/************************************************************************************/

LVCS_ReturnStatus_en LVCS_GetParameters(LVCS_Handle_t   hInstance,
                                        LVCS_Params_t   *pParams)
{

    LVCS_Instance_t     *pInstance =(LVCS_Instance_t  *)hInstance;

    *pParams = pInstance->Params;

    return(LVCS_SUCCESS);
}


/************************************************************************************/
/*                                                                                  */
/* FUNCTION:                LVCS_Control                                            */
/*                                                                                  */
/* DESCRIPTION:                                                                     */
/*  Sets or changes the Concert Sound parameters.                                   */
/*                                                                                  */
/* PARAMETERS:                                                                      */
/*  hInstance               Instance handle                                         */
/*  pParams                 Pointer to a parameter structure                        */
/*                                                                                  */
/* RETURNS:                                                                         */
/*  LVCS_Success            Succeeded                                               */
/*                                                                                  */
/* NOTES:                                                                           */
/*  1.  This function must not be interrupted by the LVCS_Process function          */
/*                                                                                  */
/************************************************************************************/

LVCS_ReturnStatus_en LVCS_Control(LVCS_Handle_t      hInstance,
                                  LVCS_Params_t      *pParams)
{
    LVM_INT16                   Offset;
    LVCS_Instance_t             *pInstance =(LVCS_Instance_t  *)hInstance;
    LVCS_ReturnStatus_en        err;
    LVCS_Modes_en               OperatingModeSave = pInstance->Params.OperatingMode;

    if (pParams->SampleRate != pInstance->Params.SampleRate)
    {
        pInstance->TimerParams.SamplingRate = LVCS_SampleRateTable[pParams->SampleRate];
    }

    /*
     * If the reverb level has changed
     */
    if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
    {
        err=LVCS_ReverbGeneratorInit(hInstance,pParams);
    }

    /*
     * If the sample rate or speaker has changed then perform a full re-initialisation
     */
    if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
       (pInstance->Params.SpeakerType != pParams->SpeakerType))
    {
        const LVCS_VolCorrect_t *pLVCS_VolCorrectTable;

        /*
         * Output device
         */
        pInstance->OutputDevice = LVCS_HEADPHONE;

        /*
         * Get the volume correction parameters
         */
        /* Use internal coefficient table */
        pLVCS_VolCorrectTable = (LVCS_VolCorrect_t*)&LVCS_VolCorrectTable[0];
        Offset = (LVM_INT16)(pParams->SpeakerType + pParams->SourceFormat*(1+LVCS_EX_HEADPHONES));

        pInstance->VolCorrect = pLVCS_VolCorrectTable[Offset];

        pInstance->CompressGain = pInstance->VolCorrect.CompMin;
#ifdef BUILD_FLOAT
        LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[0], 0, 0);
#else
        LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],0,0);
#endif
        {
#ifndef BUILD_FLOAT
            LVM_UINT32          Gain;
            const Gain_t        *pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
            Gain = (LVM_UINT32)(pOutputGainTable[Offset].Loss * LVM_MAXINT_16);
            Gain = (LVM_UINT32)pOutputGainTable[Offset].UnprocLoss * (Gain >> 15);
            Gain=Gain>>15;
            /*
             * Apply the gain correction and shift, note the result is in Q3.13 format
             */
            Gain = (Gain * pInstance->VolCorrect.GainMin) >>12;

            LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[1],0,Gain);
            LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],
                    LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
            LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[1],
                    LVCS_BYPASS_MIXER_TC,pParams->SampleRate,2);
#else
            LVM_FLOAT          Gain;
            const Gain_t        *pOutputGainTable = (Gain_t*)&LVCS_OutputGainTable[0];
            Gain = (LVM_FLOAT)(pOutputGainTable[Offset].Loss);
            Gain = (LVM_FLOAT)pOutputGainTable[Offset].UnprocLoss * (Gain);

            /*
             * Apply the gain correction
             */
            Gain = (Gain * pInstance->VolCorrect.GainMin);

            LVC_Mixer_Init(&pInstance->BypassMix.Mixer_Instance.MixerStream[1], 0, Gain);
            LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[0],
                    LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
            LVC_Mixer_VarSlope_SetTimeConstant(&pInstance->BypassMix.Mixer_Instance.MixerStream[1],
                    LVCS_BYPASS_MIXER_TC, pParams->SampleRate, 2);
#endif
        }


        err=LVCS_SEnhancerInit(hInstance,
                           pParams);

        err=LVCS_ReverbGeneratorInit(hInstance,
                                 pParams);

        err=LVCS_EqualiserInit(hInstance,
                           pParams);

        err=LVCS_BypassMixInit(hInstance,
                           pParams);

    }


    /*
     * Check if the effect level or source format has changed
     */
    else if ((pInstance->Params.EffectLevel != pParams->EffectLevel) ||
            (pInstance->Params.SourceFormat != pParams->SourceFormat))
    {
        const LVCS_VolCorrect_t *pLVCS_VolCorrectTable;

        /*
         * Get the volume correction parameters
         */
        /* Use internal coefficient table */
        pLVCS_VolCorrectTable = (LVCS_VolCorrect_t*)&LVCS_VolCorrectTable[0];
        Offset = (LVM_INT16)(pParams->SpeakerType + pParams->SourceFormat*(1+LVCS_EX_HEADPHONES));

        pInstance->VolCorrect = pLVCS_VolCorrectTable[Offset];

        /* Update the effect level and alpha-mixer gains */
        err=LVCS_BypassMixInit(hInstance,
                           pParams);

        if(err != LVCS_SUCCESS)
        {
            return err;
        }
    }
    else
    {
        pInstance->Params = *pParams;
    }

    /*
     * Update the instance parameters
     */
    pInstance->Params = *pParams;

    /* Stay on the current operating mode until the transition is done */
    if((pParams->OperatingMode != OperatingModeSave) ||
       (pInstance->bInOperatingModeTransition == LVM_TRUE)){

        /* Set the reverb delay timeout */
        if(pInstance->bInOperatingModeTransition != LVM_TRUE){
            pInstance->bTimerDone = LVM_FALSE;
            pInstance->TimerParams.TimeInMs =
            (LVM_INT16)(((pInstance->Reverberation.DelaySize << 2)
            /pInstance->TimerParams.SamplingRate) + 1);
            LVM_Timer_Init ( &pInstance->TimerInstance,
                             &pInstance->TimerParams);
        }

        /* Update the effect level and alpha-mixer gains */
        err=LVCS_BypassMixInit(hInstance,
                           pParams);

        /* Change transition bypass mixer settings if needed depending on transition type */
        if(pParams->OperatingMode != LVCS_OFF){
            pInstance->MSTarget0=LVM_MAXINT_16;
            pInstance->MSTarget1=0;
        }
        else
        {
            pInstance->Params.OperatingMode = OperatingModeSave;
            pInstance->MSTarget1=LVM_MAXINT_16;
            pInstance->MSTarget0=0;
        }


        /* Set transition flag */
        pInstance->bInOperatingModeTransition = LVM_TRUE;
    }

    return(LVCS_SUCCESS);
}

/****************************************************************************************/
/*                                                                                      */
/* FUNCTION:                LVCS_TimerCallBack                                          */
/*                                                                                      */
/* DESCRIPTION:                                                                         */
/*  CallBack function of the Timer.                                                     */
/*                                                                                      */
/****************************************************************************************/
void LVCS_TimerCallBack (void* hInstance, void* pCallBackParams, LVM_INT32 CallbackParam)
{
    LVCS_Instance_t     *pInstance  = (LVCS_Instance_t  *)hInstance;

    /* Avoid warnings because pCallBackParams and CallbackParam are not used*/
    if((pCallBackParams != LVM_NULL) || (CallbackParam != 0)){
        pCallBackParams = hInstance;
        CallbackParam = 0;
        return;
    }

    pInstance->bTimerDone = LVM_TRUE;


    return;
}

