/*
 * 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.
 */

#ifndef ANDROID_EFFECTBUNDLE_H_
#define ANDROID_EFFECTBUNDLE_H_

#include <audio_effects/effect_bassboost.h>
#include <audio_effects/effect_equalizer.h>
#include <audio_effects/effect_virtualizer.h>
#include <LVM.h>
#include <limits.h>

#define FIVEBAND_NUMBANDS 5
#define MAX_NUM_BANDS 5
#define MAX_CALL_SIZE 256
#define LVM_MAX_SESSIONS 32
#define LVM_UNUSED_SESSION INT_MAX
#define BASS_BOOST_CUP_LOAD_ARM9E 150   // Expressed in 0.1 MIPS
#define VIRTUALIZER_CUP_LOAD_ARM9E 120  // Expressed in 0.1 MIPS
#define EQUALIZER_CUP_LOAD_ARM9E 220    // Expressed in 0.1 MIPS
#define VOLUME_CUP_LOAD_ARM9E 0         // Expressed in 0.1 MIPS
#define BUNDLE_MEM_USAGE 25             // Expressed in kB

#ifndef OPENSL_ES_H_
static const effect_uuid_t SL_IID_VOLUME_ = {
        0x09e8ede0, 0xddde, 0x11db, 0xb4f6, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
const effect_uuid_t* const SL_IID_VOLUME = &SL_IID_VOLUME_;
#endif  // OPENSL_ES_H_

typedef enum { LVM_BASS_BOOST, LVM_VIRTUALIZER, LVM_EQUALIZER, LVM_VOLUME } lvm_effect_en;

// Preset configuration.
struct PresetConfig {
    // Human-readable name.
    const char* name;
    // An array of size nBands where each element is a configuration for the
    // corresponding band.
    // const BandConfig * bandConfigs;
};

/* BundledEffectContext : One per session */
struct BundledEffectContext {
    LVM_Handle_t hInstance;                   /* Instance handle */
    int SessionNo;                            /* Current session number */
    int SessionId;                            /* Current session id */
    bool bVolumeEnabled;                      /* Flag for Volume */
    bool bEqualizerEnabled;                   /* Flag for EQ */
    bool bBassEnabled;                        /* Flag for Bass */
    bool bBassTempDisabled;                   /* Flag for Bass to be re-enabled */
    bool bVirtualizerEnabled;                 /* Flag for Virtualizer */
    bool bVirtualizerTempDisabled;            /* Flag for effect to be re-enabled */
    audio_devices_t nOutputDevice;            /* Output device for the effect */
    audio_devices_t nVirtualizerForcedDevice; /* Forced device virtualization mode*/
    int NumberEffectsEnabled;                 /* Effects in this session */
    int NumberEffectsCalled;                  /* Effects called so far */
    bool firstVolume;                         /* No smoothing on first Vol change */
    // Saved parameters for each effect */
    // Bass Boost
    int BassStrengthSaved; /* Conversion between Get/Set */
    // Equalizer
    int CurPreset; /* Current preset being used */
    // Virtualzer
    int VirtStrengthSaved; /* Conversion between Get/Set */
    // Volume
    int levelSaved; /* for when mute is set, level must be saved */
    int positionSaved;
    bool bMuteEnabled; /* Must store as mute = -96dB level */
    bool bStereoPositionEnabled;
    LVM_Fs_en SampleRate;
    int SamplesPerSecond;
    int SamplesToExitCountEq;
    int SamplesToExitCountBb;
    int SamplesToExitCountVirt;
    effect_buffer_t* workBuffer;
    int frameCount;
    int32_t bandGaindB[FIVEBAND_NUMBANDS];
    int volume;
    LVM_INT32 ChMask;

    /* Bitmask whether drain is in progress due to disabling the effect.
       The corresponding bit to an effect is set by 1 << lvm_effect_en. */
    int effectInDrain;

    /* Bitmask whether process() was called for a particular effect.
       The corresponding bit to an effect is set by 1 << lvm_effect_en. */
    int effectProcessCalled;
};

/* SessionContext : One session */
struct SessionContext {
    bool bBundledEffectsEnabled;
    bool bVolumeInstantiated;
    bool bEqualizerInstantiated;
    bool bBassInstantiated;
    bool bVirtualizerInstantiated;
    BundledEffectContext* pBundledContext;
};

struct EffectContext {
    const struct effect_interface_s* itfe;
    effect_config_t config;
    lvm_effect_en EffectType;
    BundledEffectContext* pBundledContext;
};

/* enumerated parameter settings for Volume effect */
typedef enum {
    VOLUME_PARAM_LEVEL,                 // type SLmillibel = typedef SLuint16 (set & get)
    VOLUME_PARAM_MAXLEVEL,              // type SLmillibel = typedef SLuint16 (get)
    VOLUME_PARAM_MUTE,                  // type SLboolean  = typedef SLuint32 (set & get)
    VOLUME_PARAM_ENABLESTEREOPOSITION,  // type SLboolean  = typedef SLuint32 (set & get)
    VOLUME_PARAM_STEREOPOSITION,        // type SLpermille = typedef SLuint16 (set & get)
} t_volume_params;

static const int PRESET_CUSTOM = -1;

static const uint32_t bandFreqRange[FIVEBAND_NUMBANDS][2] = {{30000, 120000},
                                                             {120001, 460000},
                                                             {460001, 1800000},
                                                             {1800001, 7000000},
                                                             {7000001, 20000000}};

// Note: If these frequencies change, please update LimitLevel values accordingly.
static const LVM_UINT16 EQNB_5BandPresetsFrequencies[] = {60, /* Frequencies in Hz */
                                                          230, 910, 3600, 14000};

static const LVM_UINT16 EQNB_5BandPresetsQFactors[] = {96, /* Q factor multiplied by 100 */
                                                       96, 96, 96, 96};

static const LVM_INT16 EQNB_5BandNormalPresets[] = {3,  0,  0,  0,  3,   /* Normal Preset */
                                                    8,  5,  -3, 5,  6,   /* Classical Preset */
                                                    15, -6, 7,  13, 10,  /* Dance Preset */
                                                    0,  0,  0,  0,  0,   /* Flat Preset */
                                                    6,  -2, -2, 6,  -3,  /* Folk Preset */
                                                    8,  -8, 13, -1, -4,  /* Heavy Metal Preset */
                                                    10, 6,  -4, 5,  8,   /* Hip Hop Preset */
                                                    8,  5,  -4, 5,  9,   /* Jazz Preset */
                                                    -6, 4,  9,  4,  -5,  /* Pop Preset */
                                                    10, 6,  -1, 8,  10}; /* Rock Preset */

static const LVM_INT16 EQNB_5BandSoftPresets[] = {3,  0, 0,  0, 3,  /* Normal Preset */
                                                  5,  3, -2, 4, 4,  /* Classical Preset */
                                                  6,  0, 2,  4, 1,  /* Dance Preset */
                                                  0,  0, 0,  0, 0,  /* Flat Preset */
                                                  3,  0, 0,  2, -1, /* Folk Preset */
                                                  4,  1, 9,  3, 0,  /* Heavy Metal Preset */
                                                  5,  3, 0,  1, 3,  /* Hip Hop Preset */
                                                  4,  2, -2, 2, 5,  /* Jazz Preset */
                                                  -1, 2, 5,  1, -2, /* Pop Preset */
                                                  5,  3, -1, 3, 5}; /* Rock Preset */

static const PresetConfig gEqualizerPresets[] = {{"Normal"}, {"Classical"},   {"Dance"},   {"Flat"},
                                                 {"Folk"},   {"Heavy Metal"}, {"Hip Hop"}, {"Jazz"},
                                                 {"Pop"},    {"Rock"}};

/* The following tables have been computed using the actual levels measured by the output of
 * white noise or pink noise (IEC268-1) for the EQ and BassBoost Effects. These are estimates of
 * the actual energy that 'could' be present in the given band.
 * If the frequency values in EQNB_5BandPresetsFrequencies change, these values might need to be
 * updated.
 */

static const float LimitLevel_bandEnergyCoefficient[FIVEBAND_NUMBANDS] = {7.56, 9.69, 9.59, 7.37,
                                                                          2.88};

static const float LimitLevel_bandEnergyCrossCoefficient[FIVEBAND_NUMBANDS - 1] = {126.0, 115.0,
                                                                                   125.0, 104.0};

static const float LimitLevel_bassBoostEnergyCrossCoefficient[FIVEBAND_NUMBANDS] = {
        221.21, 208.10, 28.16, 0.0, 0.0};

static const float LimitLevel_bassBoostEnergyCoefficient = 9.00;

static const float LimitLevel_virtualizerContribution = 1.9;

#endif /*ANDROID_EFFECTBUNDLE_H_*/