EQ实现(C语言)

2020-01-29 15:42:01 广州普斯格智能科技有限公司 534

#include<stdio.h>

#include<stdlib.h>

#include<errno.h>

#include<string.h>

#include<pthread.h>

#include<math.h>

typedef struct{

char chunkId[4];//"RIFF"

unsigned long chunkSize;

char format[4];//"WAVE"

}WAVE_RIFF;

typedef struct{

char chunkId[4];//"fmt"

unsigned long chunkSize;

unsigned short audioFormat;

unsigned short chNum;

unsigned long sampleRate;

unsigned long byteRate;//SampleRate * NumChannels * BitsPerSample/8

unsigned short blockAlign;//NumChannels * BitsPerSample/8

unsigned short bitsPerSample;//8,16,32

}WAVE_FMT;

typedef struct{

char chunkId[4];//"data"

unsigned long chunkSize;//NumSamples * NumChannels * BitsPerSample/8

}WAVE_DATA;

typedef struct

{

    char fileName[256];

    FILE *fp;

    long pos;

    unsigned long totalSampleNum;

    WAVE_RIFF riffChunk;

    WAVE_FMT fmtChunk;

    WAVE_DATA dataChunk;

}WAVE_INFO;


#define READ_SAMPLES 1024

#define PP_SAMPLES 64

typedef struct

{

    unsigned short chNum;

    unsigned short bankNum;

    unsigned long samplesPerBank;

    unsigned short bytesPerSample;

    unsigned short bankRp;

    unsigned short bankWp;

    unsigned char ***pData;

    unsigned char fgEos;

    unsigned char fgInited;

}PP_BUF_T;


typedef enum

{

    FADER_TYPE_LINE,

    FADER_TYPE_CUBIC,

}FADER_TYPE_E;

typedef struct

{

    float attuationDb;

    FADER_TYPE_E type;

    unsigned long timeMs;

}FADER_PARAM_T;


typedef struct

{

    FADER_PARAM_T faderParams;

    unsigned long timeInSample;

    float curVolumDb;

    float curGain;

    float startGain;

    float targetGain;

    unsigned long curSample;

    unsigned long sampleRate;

    float *segGain;

    unsigned short segNum;

}FADER_HANDLE_T;

typedef struct

{

    short **pData;

    unsigned short chNum;

    unsigned short samples;

    unsigned short bytesPerSample;

}DATA_INFO_T;

PP_BUF_T gPpBuf;

FADER_HANDLE_T gFaderHandle;

unsigned char fgEnd = 0;


typedef struct

{

    unsigned long attackTimeMs;

    unsigned long releaseTimeMs;

    unsigned short ratio;

    float thresholdDb;

}DRC_COMPRESSOR_PARAM_T;

typedef struct

{

    unsigned long attackTimeMs;

    unsigned long releaseTimeMs;

    float thresholdDb;

}DRC_LIMITER_PARAM_T;

typedef struct

{

    unsigned long attackTimeMs;

    unsigned long releaseTimeMs;

    unsigned long holdTimeMs;

    unsigned short ratio;

    float thresholdDb;

}DRC_EXPANDER_PARAM_T;

typedef enum

{

    DRC_TYPE_COMPRESSOR,

    DRC_TYPE_LIMITER,

    DRC_TYPE_EXPANDER,

    DRC_TYPE_AUTO,

}DRC_TYPE_E;

typedef struct

{

    DRC_TYPE_E eDrcType;

    union {

        DRC_COMPRESSOR_PARAM_T compressorParams;

        DRC_LIMITER_PARAM_T limiterParams;

        DRC_EXPANDER_PARAM_T expanderParams;

    }uDrcParams;

    float curGain;

    float curSmoothGainDb;

    float alphaAttack;

    float alphaRelease;

    unsigned long attackHoldCounter;

    unsigned long releaseHoldCounter;

}DRC_HANDLE_T;


typedef struct

{

    float a[3];

    float b[3];

}FILTER_COEFF_T;


typedef enum

{

    FILTER_TYPE_LPF,

    FILTER_TYPE_HPF,

    FILTER_TYPE_LSF,

    FILTER_TYPE_HSF,

    FILTER_TYPE_PEF,

    FILTER_TYPE_MAX,

}FILTER_TYPE_E;


typedef struct

{

    unsigned long fs;

    unsigned long f0;

    float Q;

    float gainDb;

}FILTER_PARAM_T;


#define FILTER_MAX_CH 2

typedef struct

{

    unsigned short xHistory[FILTER_MAX_CH][3];

    unsigned short yHistory[FILTER_MAX_CH][3];

}FILTER_HISTORY_T;


typedef struct

{

    FILTER_TYPE_E eFilterType;

    FILTER_PARAM_T filterParams;

    FILTER_COEFF_T filterCoeff;

    FILTER_HISTORY_T filterHistory;

}FILTER_HANDLE_T;

FILTER_HANDLE_T gFilterHandle;


typedef enum

{

    EQ_MODE_ROCK,

    EQ_MODE_POP,

    EQ_MODE_MAX

}EQ_MODE_E;


#define EQ_MAX_BAND 6

typedef struct

{

    EQ_MODE_E eEqMode;

    FILTER_HANDLE_T filterHandles[EQ_MAX_BAND];

}EQ_HANDLE_T;


FILTER_TYPE_E gEqFilterTypes[EQ_MAX_BAND] =

{

    FILTER_TYPE_LSF,

    FILTER_TYPE_PEF,

    FILTER_TYPE_PEF,

    FILTER_TYPE_PEF,

    FILTER_TYPE_PEF,

    FILTER_TYPE_HSF

};


FILTER_PARAM_T gEqFilterParams[EQ_MODE_MAX][EQ_MAX_BAND] =

{

    {

        {48000, 100, 2, 9},

        {48000, 600, 8, 3},

        {48000, 1000, 8, -1},

        {48000, 3000, 8, 3},

        {48000, 5000, 8, 6},

        {48000, 10000, 2, 9},

    },

    {

        {48000, 100, 2, -1},

        {48000, 600, 8, 6},

        {48000, 1000, 8, 9},

        {48000, 3000, 8, 6},

        {48000, 3000, 8, 3},

        {48000, 10000, 2, -2},

    }

};


EQ_HANDLE_T gEqHandle;

typedef struct

{

    short sampleValue;

    short bytesPerSample;

}SAMPLE_INFO_T;


void filterInit(FILTER_HANDLE_T *pFilterHandle, FILTER_TYPE_E eFilterType, FILTER_PARAM_T *pFilterParams)

{

    float A = pow(10, pFilterParams->gainDb / 40);

    float w0 = 2 * 3.1415926 * pFilterParams->f0 / pFilterParams->fs;

    float cos_w0 = cos(w0);

    float sin_w0 = sin(w0);

    float alpha = sin_w0 / (2 * pFilterParams->Q);

    float *a = pFilterHandle->filterCoeff.a;

    float *b = pFilterHandle->filterCoeff.b;

    pFilterHandle->eFilterType = eFilterType;

    memcpy(&(pFilterHandle->filterParams), pFilterParams, sizeof(FILTER_PARAM_T));

    memset(&(pFilterHandle->filterHistory), 0, sizeof(FILTER_HISTORY_T));

    switch(eFilterType)

    {

        case FILTER_TYPE_LPF:

            b[0] = (1 - cos_w0) / 2;

            b[1] = 1 - cos_w0;

            b[2] = (1 - cos_w0) / 2;

            a[0] = 1 + alpha;

            a[1] =  -2 * cos_w0;

            a[2] = 1- alpha;

            break;

        case FILTER_TYPE_HPF:

            b[0] = (1 + cos_w0) / 2;

            b[1] = -(1 + cos_w0);

            b[2] = (1 + cos_w0) / 2;

            a[0] = 1 + alpha;

            a[1] =  -2 * cos_w0;

            a[2] = 1- alpha;

            break;

        case FILTER_TYPE_LSF:

            b[0] = A * ( (A + 1) - (A - 1) * cos_w0 + 2 * sqrt(A) * alpha);

            b[1] = 2 * A * ((A - 1) - (A + 1) * cos_w0);

            b[2] = A * ((A + 1) - (A - 1) * cos_w0 - 2 * sqrt(A) * alpha);

            a[0] = (A + 1) + (A - 1) * cos_w0 + 2 * sqrt(A) * alpha;

            a[1] = -2 * ((A - 1) + (A + 1) * cos_w0);

            a[2] = (A + 1) + (A - 1) * cos_w0 - 2 * sqrt(A) * alpha;

            break;

        case FILTER_TYPE_HSF:

            b[0] = A * ( (A + 1) + (A - 1) * cos_w0 + 2 * sqrt(A) * alpha);

            b[1] = -2 * A * ((A - 1) + (A + 1) * cos_w0);

            b[2] = A * ((A + 1) + (A - 1) * cos_w0 - 2 * sqrt(A) * alpha);

            a[0] = (A + 1) - (A - 1) * cos_w0 + 2 * sqrt(A) * alpha;

            a[1] = 2 * ((A - 1) - (A + 1) * cos_w0);

            a[2] = (A + 1) - (A - 1) * cos_w0 - 2 * sqrt(A) * alpha;

            break;

        case FILTER_TYPE_PEF:

            b[0] = 1 + alpha * A;

            b[1] = -2 * cos_w0;

            b[2] = 1 - alpha * A;

            a[0] = 1 + alpha / A;

            a[1] = -2 * cos_w0;

            a[2] = 1 - alpha / A;

            break;

        default:

            break;

    }

    b[0] /= a[0];

    b[1] /= a[0];

    b[2] /= a[0];

    a[1] /= a[0];

    a[2] /= a[0];

    a[0] = 1;

    

}


short filterCore(FILTER_HANDLE_T *pFilterHandle, short curSampleValue, short curChIdx)

{

    short *x, *y;

    float *a, *b;

    long sum = 0;

    x = pFilterHandle->filterHistory.xHistory[curChIdx];

    y = pFilterHandle->filterHistory.yHistory[curChIdx];

    a = pFilterHandle->filterCoeff.a;

    b = pFilterHandle->filterCoeff.b;

    x[0] = curSampleValue;

    //y[0] = (b[0] * x[0] + b[1] * x[1] + b[2] * x[2] - a[1] * y[1] - a[2] * y[2]) / a[0];

    sum += b[0] * (long)x[0];

    sum += b[1] * (long)x[1];

    sum += b[2] * (long)x[2];

    sum += -a[1] * (long)y[1];

    sum += -a[2] * (long)y[2];

    y[0] = (short)sum;

    x[2] = x[1];

    x[1] = x[0];

    y[2] = y[1];

    y[1] = y[0];

    return y[0];

}


short levelDown(short sampleValue)

{

    return sampleValue >> 2;

}


#define MAX(a, b) (a > b ? a : b)

#define MIN(a, b) (a < b ? a : b)


short overflowAdd(short a, short b)

{

    long sum = 0;

    sum = a + b;

    sum = MAX(sum, -32727);

    sum = MIN(sum, 32727);

    return (short)sum;

}


short levelUp(short sampleValue)

{

    short sum = 0;

    sum = overflowAdd(sampleValue, sampleValue);

    sum = overflowAdd(sum, sum);

    return sum;

}

void filter(FILTER_HANDLE_T *pFilterHandle, DATA_INFO_T *pDataInfo)

{

    unsigned short sampleIdx, chIdx;

    for (chIdx = 0; chIdx < pDataInfo->chNum; chIdx++)

    {

        for (sampleIdx = 0; sampleIdx < pDataInfo->samples; sampleIdx++)

        {

            pDataInfo->pData[chIdx][sampleIdx] = levelDown(pDataInfo->pData[chIdx][sampleIdx]);

            pDataInfo->pData[chIdx][sampleIdx] = filterCore(pFilterHandle, pDataInfo->pData[chIdx][sampleIdx], chIdx);

            pDataInfo->pData[chIdx][sampleIdx] = levelUp(pDataInfo->pData[chIdx][sampleIdx]);

        }

    }

}


void eqFilterInit(EQ_HANDLE_T *pEqHandle, EQ_MODE_E eEqMode)

{

    if (pEqHandle == NULL || eEqMode >= EQ_MODE_MAX || eEqMode < 0)

        return;

    FILTER_HANDLE_T *pFilterHandle;

    FILTER_PARAM_T *pFilterParam;

    short bandIdx;

    for (bandIdx = 0; bandIdx < EQ_MAX_BAND; bandIdx++)

    {

        pFilterHandle = &pEqHandle->filterHandles[bandIdx];

        pFilterParam = &gEqFilterParams[eEqMode][bandIdx];

        filterInit(pFilterHandle, gEqFilterTypes[eEqMode], pFilterParam);

    }

}


void eqInit(EQ_HANDLE_T *pEqHandle, EQ_MODE_E eEqMode)

{

    if (pEqHandle == NULL || eEqMode >= EQ_MODE_MAX || eEqMode < 0)

        return;

    pEqHandle->eEqMode = eEqMode;

    eqFilterInit(pEqHandle, eEqMode);

}


void eq(EQ_HANDLE_T *pEqHandle, DATA_INFO_T *pDataInfo)

{

    unsigned short sampleIdx, chIdx, bandIdx;

    if (pEqHandle == NULL || pEqHandle->eEqMode >= EQ_MODE_MAX || pEqHandle->eEqMode < 0)

        return ;

    FILTER_HANDLE_T *pFilterHandle;

    for (bandIdx = 0; bandIdx < EQ_MAX_BAND; bandIdx++)

    {

        pFilterHandle = &(pEqHandle->filterHandles[bandIdx]);

        for (chIdx = 0; chIdx < pDataInfo->chNum; chIdx++)

        {

            for (sampleIdx = 0; sampleIdx < pDataInfo->samples; sampleIdx++)

            {

                pDataInfo->pData[chIdx][sampleIdx] = levelDown(pDataInfo->pData[chIdx][sampleIdx]);

                pDataInfo->pData[chIdx][sampleIdx] = filterCore(pFilterHandle, pDataInfo->pData[chIdx][sampleIdx], chIdx);

                pDataInfo->pData[chIdx][sampleIdx] = levelUp(pDataInfo->pData[chIdx][sampleIdx]);

            }

        }

    }

}

float dbToGain(float db);

DRC_HANDLE_T gDrcHandle;

void drcInit(DRC_HANDLE_T *pDrcHandle, void * pDrcParams, DRC_TYPE_E eDrcType)

{

    DRC_COMPRESSOR_PARAM_T *pCompressorParams;

    DRC_LIMITER_PARAM_T *pLimiterParams;

    DRC_EXPANDER_PARAM_T *pExpanderParams;

    if (pDrcHandle == NULL || pDrcParams == NULL || eDrcType > DRC_TYPE_AUTO)

        return;

    pDrcHandle->eDrcType = eDrcType;

    switch (eDrcType)

    {

        case DRC_TYPE_COMPRESSOR:

            pCompressorParams = (DRC_COMPRESSOR_PARAM_T *)pDrcParams;

            memcpy(&pDrcHandle->uDrcParams.compressorParams, pCompressorParams, sizeof(DRC_COMPRESSOR_PARAM_T));

            pDrcHandle->alphaAttack = expf(-logf(9) / (48000 * pCompressorParams->attackTimeMs / 1000));

            pDrcHandle->alphaRelease = expf(-logf(9) / (48000 * pCompressorParams->releaseTimeMs / 1000));

            break;

        case DRC_TYPE_LIMITER:

            pLimiterParams = (DRC_LIMITER_PARAM_T *)pDrcParams;

            memcpy(&pDrcHandle->uDrcParams.limiterParams, pLimiterParams, sizeof(DRC_LIMITER_PARAM_T));

            pDrcHandle->alphaAttack = expf(-logf(9) / (48000 * pLimiterParams->attackTimeMs / 1000));

            pDrcHandle->alphaRelease = expf(-logf(9) / (48000 * pLimiterParams->releaseTimeMs / 1000));

            break;

        case DRC_TYPE_EXPANDER:

            pExpanderParams = (DRC_EXPANDER_PARAM_T *)pDrcParams;

            memcpy(&pDrcHandle->uDrcParams.expanderParams, pExpanderParams, sizeof(DRC_EXPANDER_PARAM_T));

            pDrcHandle->alphaAttack = expf(-logf(9) / (48000 * pExpanderParams->attackTimeMs / 1000));

            pDrcHandle->alphaRelease = expf(-logf(9) / (48000 * pExpanderParams->releaseTimeMs /1000));

            break;

        case DRC_TYPE_AUTO:

            break;

    }

    pDrcHandle->curGain = 1;

    pDrcHandle->curSmoothGainDb = 0;

    pDrcHandle->attackHoldCounter = 0;

    pDrcHandle->releaseHoldCounter = 0;

}


float sampleValueToDb(SAMPLE_INFO_T *pSampleInfo)

{

    if (pSampleInfo == NULL)

        return 0;

    if (pSampleInfo->sampleValue == 0)

        pSampleInfo->sampleValue = 1;

    short maxSampleValue = ((1 << (pSampleInfo->bytesPerSample * 8)) - 1) / 2;

    float db = 20 * log10f((float)abs(pSampleInfo->sampleValue) / maxSampleValue);

    //printf("maxSampleValue:%d, sampleValue:%d, db:%f\n", maxSampleValue, pSampleInfo->sampleValue, db);

    return db;

}


float drcComputeGainDb(DRC_HANDLE_T *pDrcHandle, float sampleDb)

{

    if (pDrcHandle == NULL)

        return 0;

    float staticChract;

    switch (pDrcHandle->eDrcType)

    {

        case DRC_TYPE_COMPRESSOR:

            if (sampleDb < pDrcHandle->uDrcParams.compressorParams.thresholdDb)

            {

                staticChract = sampleDb;

            }

            else

            {

                staticChract = pDrcHandle->uDrcParams.compressorParams.thresholdDb + (sampleDb - pDrcHandle->uDrcParams.compressorParams.thresholdDb) / pDrcHandle->uDrcParams.compressorParams.ratio;

            }

            break;

        case DRC_TYPE_LIMITER:

            if (sampleDb < pDrcHandle->uDrcParams.limiterParams.thresholdDb)

            {

                staticChract = sampleDb;

            }

            else

            {

                staticChract = pDrcHandle->uDrcParams.limiterParams.thresholdDb;

            }

            break;

        case DRC_TYPE_EXPANDER:

            if (sampleDb >= pDrcHandle->uDrcParams.expanderParams.thresholdDb)

            {

                staticChract = sampleDb;

            }

            else

            {

                staticChract = pDrcHandle->uDrcParams.expanderParams.thresholdDb + (sampleDb - pDrcHandle->uDrcParams.expanderParams.thresholdDb) / pDrcHandle->uDrcParams.expanderParams.ratio;

            }

            break;

        case DRC_TYPE_AUTO:

            break;

    }

    //printf("staticChract:%f, sampleDb:%f\n", staticChract, sampleDb); 

    return staticChract - sampleDb;

    

}


float drcCompressorSmoothGain(DRC_HANDLE_T *pDrcHandle, float computeGainDb)

{

    float smoothGainDb;

    if (computeGainDb < pDrcHandle->curSmoothGainDb)

    {

        smoothGainDb = pDrcHandle->alphaAttack * pDrcHandle->curSmoothGainDb + (1 - pDrcHandle->alphaAttack) * computeGainDb;

    }

    else

    {

        smoothGainDb = pDrcHandle->alphaRelease * pDrcHandle->curSmoothGainDb + (1 - pDrcHandle->alphaRelease) * computeGainDb;

    }

    return smoothGainDb;

}


float drcExpanderSmoothGain(DRC_HANDLE_T *pDrcHandle, float computeGainDb)

{

    float smoothGainDb;

    unsigned long holdTimeInSample = pDrcHandle->uDrcParams.expanderParams.holdTimeMs * 48000 / 1000;

    if (pDrcHandle->attackHoldCounter >= holdTimeInSample && computeGainDb > pDrcHandle->curSmoothGainDb)

    {

        smoothGainDb = pDrcHandle->alphaAttack * pDrcHandle->curSmoothGainDb + (1 - pDrcHandle->alphaAttack) * computeGainDb;

    }

    else if (pDrcHandle->attackHoldCounter < holdTimeInSample && computeGainDb > pDrcHandle->curSmoothGainDb)

    {

        smoothGainDb = pDrcHandle->curSmoothGainDb;

        pDrcHandle->attackHoldCounter++;

        pDrcHandle->releaseHoldCounter = 0;

    }

    else if (pDrcHandle->releaseHoldCounter >= holdTimeInSample && computeGainDb <= pDrcHandle->curSmoothGainDb)

    {

        smoothGainDb = pDrcHandle->alphaRelease * pDrcHandle->curSmoothGainDb + (1 - pDrcHandle->alphaRelease) * computeGainDb;

    }

    else if (pDrcHandle->releaseHoldCounter < holdTimeInSample && computeGainDb <= pDrcHandle->curSmoothGainDb)

    {

        smoothGainDb = pDrcHandle->curSmoothGainDb;

        pDrcHandle->releaseHoldCounter++;

        pDrcHandle->attackHoldCounter = 0;

    }

    return smoothGainDb;

}

float drcSmoothGain(DRC_HANDLE_T *pDrcHandle, float computeGainDb)

{

    if (pDrcHandle == NULL)

        return 0;

    float smoothGainDb;

    switch (pDrcHandle->eDrcType)

    {

        case DRC_TYPE_COMPRESSOR:

        case DRC_TYPE_LIMITER:

            smoothGainDb = drcCompressorSmoothGain(pDrcHandle, computeGainDb);

            break;

        case DRC_TYPE_EXPANDER:

            smoothGainDb = drcExpanderSmoothGain(pDrcHandle, computeGainDb);

            break;

        case DRC_TYPE_AUTO:

            break;

    }

    return smoothGainDb;

}

void drcCalGain(DRC_HANDLE_T *pDrcHandle, SAMPLE_INFO_T *pSampleInfo)

{

    if (pDrcHandle == NULL || pSampleInfo == NULL)

        return;

    float sampleDb = sampleValueToDb(pSampleInfo);

    float computeGainDb = drcComputeGainDb(pDrcHandle, sampleDb);

    pDrcHandle->curSmoothGainDb = drcSmoothGain(pDrcHandle, computeGainDb);

    pDrcHandle->curGain = dbToGain(pDrcHandle->curSmoothGainDb);

    printf("sampleDb:%f, computeGainDb:%f, smoothGainDb:%f, curGain:%f\n",

        sampleDb, computeGainDb, pDrcHandle->curSmoothGainDb, pDrcHandle->curGain);

}


void drc(DRC_HANDLE_T *pDrcHandle, DATA_INFO_T *pDataInfo)

{

    unsigned short sampleIdx, chIdx;

    SAMPLE_INFO_T sampleInfo;

    for (chIdx = 0; chIdx < pDataInfo->chNum; chIdx++)

    {

        for (sampleIdx = 0; sampleIdx < pDataInfo->samples; sampleIdx++)

        {

            sampleInfo.bytesPerSample = 2;

            sampleInfo.sampleValue = pDataInfo->pData[chIdx][sampleIdx];

            drcCalGain(pDrcHandle, &sampleInfo);

            pDataInfo->pData[chIdx][sampleIdx] *= pDrcHandle->curGain;

        }

    }

}



float mapSegGainToRealGain(FADER_HANDLE_T *pFaderHandle, float segGain)

{

    float deltaGain = pFaderHandle->targetGain - pFaderHandle->startGain;

    float realGain = deltaGain * segGain + pFaderHandle->startGain;

    return realGain;

}

void faderPrepareShape(FADER_HANDLE_T *pFaderHandle, unsigned short segNum)

{

    unsigned short segIdx;

    pFaderHandle->segGain = (float *)malloc((segNum + 1) * sizeof(float));

    pFaderHandle->segNum = segNum;

    float tmp;

    if (pFaderHandle->faderParams.type != FADER_TYPE_CUBIC)

         return;

    //0~1 divide into N seg.

    for (segIdx = 0; segIdx < segNum + 1; segIdx++)

    {

        tmp = (float)segIdx / segNum;

        pFaderHandle->segGain[segIdx] = tmp * tmp * tmp;

        pFaderHandle->segGain[segIdx] = mapSegGainToRealGain(pFaderHandle, pFaderHandle->segGain[segIdx]);

    }

}

float dbToGain(float db)

{

    return pow(10, db/20);

}

void faderInit(FADER_HANDLE_T *pFaderHandle, float attuationDb, FADER_TYPE_E type, unsigned long timeMs, unsigned long sampleRate, float curVolumDb)

{

    pFaderHandle->faderParams.attuationDb = attuationDb;

    pFaderHandle->faderParams.type = type;

    pFaderHandle->faderParams.timeMs = timeMs;

    pFaderHandle->timeInSample = timeMs * sampleRate / 1000;

    pFaderHandle->curGain = pFaderHandle->startGain = dbToGain(curVolumDb);

    pFaderHandle->targetGain = dbToGain(curVolumDb + attuationDb);

    pFaderHandle->curSample = 0;

    faderPrepareShape(pFaderHandle, 20);

    printf("faderInit\n");

}


void faderCalGain(FADER_HANDLE_T *pFaderHandle)

{

    float startGainInCurSeg, endGainInCurSeg, step;

    float deltaGain = pFaderHandle->targetGain - pFaderHandle->startGain;

    unsigned long samplesInSeg = pFaderHandle->timeInSample / pFaderHandle->segNum;

    unsigned short curSeg = (float)pFaderHandle->curSample / samplesInSeg;

    unsigned long startSampleInCurSeg = samplesInSeg * curSeg;

    switch (pFaderHandle->faderParams.type)

    {

        case FADER_TYPE_LINE:

            step = deltaGain / pFaderHandle->timeInSample;

            pFaderHandle->curGain += deltaGain / pFaderHandle->timeInSample;

            //pFaderHandle->curGain = pFaderHandle->startGain + deltaGain * pFaderHandle->curSample / pFaderHandle->timeInSample;

            break;

        case FADER_TYPE_CUBIC:

            startGainInCurSeg = pFaderHandle->segGain[curSeg];

            endGainInCurSeg = pFaderHandle->segGain[curSeg + 1];

            step = (endGainInCurSeg - startGainInCurSeg) / samplesInSeg;

            if (pFaderHandle->curSample == startSampleInCurSeg)

                pFaderHandle->curGain = startGainInCurSeg;

            else

                pFaderHandle->curGain += step;

            break;

    }

    printf("curGain:%f, curSample:%ld, timeInSample:%ld, curSeg:%d, startGain:%f, endGain:%f\n", pFaderHandle->curGain, pFaderHandle->curSample, pFaderHandle->timeInSample, curSeg, startGainInCurSeg, endGainInCurSeg);

}


void fader(FADER_HANDLE_T *pFaderHandle, DATA_INFO_T *pDataInfo)

{

    unsigned short sampleIdx, chIdx;

    for (sampleIdx = 0; sampleIdx < pDataInfo->samples; sampleIdx++)

    {

        if (pFaderHandle->curSample != pFaderHandle->timeInSample)

        {

            faderCalGain(pFaderHandle);

            pFaderHandle->curSample++;

        }

        for (chIdx = 0; chIdx < pDataInfo->chNum; chIdx++)

        {

            pDataInfo->pData[chIdx][sampleIdx] *= pFaderHandle->curGain;

        }

    }

}

void printWaveHeader(WAVE_INFO *pWaveInfo)

{

    printf("fileName:%s\n", pWaveInfo->fileName);

    printf("riff chunk:\n");

    printf("chunkId:%c%c%c%c\n", pWaveInfo->riffChunk.chunkId[0], pWaveInfo->riffChunk.chunkId[1], pWaveInfo->riffChunk.chunkId[2], pWaveInfo->riffChunk.chunkId[3]);

    printf("chunkSize:%ld\n", pWaveInfo->riffChunk.chunkSize);

    printf("format:%c%c%c%c\n", pWaveInfo->riffChunk.format[0], pWaveInfo->riffChunk.format[1], pWaveInfo->riffChunk.format[2], pWaveInfo->riffChunk.format[3]);

    printf("fmt chunk:\n");

    printf("chunkId:%c%c%c\n", pWaveInfo->fmtChunk.chunkId[0], pWaveInfo->fmtChunk.chunkId[1], pWaveInfo->fmtChunk.chunkId[2]);

    printf("chunkSize:%ld\n", pWaveInfo->fmtChunk.chunkSize);

    printf("audioFormat:%d\n", pWaveInfo->fmtChunk.audioFormat);

    printf("chNum:%d\n", pWaveInfo->fmtChunk.chNum);

    printf("sampleRate:%ld\n", pWaveInfo->fmtChunk.sampleRate);

    printf("byteRate:%ld\n", pWaveInfo->fmtChunk.byteRate);

    printf("blockAlign:%d\n", pWaveInfo->fmtChunk.blockAlign);

    printf("bitsPerSample:%d\n", pWaveInfo->fmtChunk.bitsPerSample);

    printf("data chunk:\n");

    printf("chunkId:%c%c%c%c\n", pWaveInfo->dataChunk.chunkId[0], pWaveInfo->dataChunk.chunkId[1], pWaveInfo->dataChunk.chunkId[2], pWaveInfo->dataChunk.chunkId[3]);

    printf("chunkSize:%ld\n", pWaveInfo->dataChunk.chunkSize);

    

}

void initWaveInfo(WAVE_INFO *pWaveInfo, unsigned short chNum, unsigned long sampleRate, unsigned short bitsPerSample)

{

    //strncpy(pWaveInfo->riffChunk.chunkId, "RIFF", 4);

    pWaveInfo->riffChunk.chunkId[0] = 'R';

    pWaveInfo->riffChunk.chunkId[1] = 'I';

    pWaveInfo->riffChunk.chunkId[2] = 'F';

    pWaveInfo->riffChunk.chunkId[3] = 'F';

    pWaveInfo->riffChunk.chunkSize = 0;

    //strncpy(pWaveInfo->riffChunk.format, "WAVE", 4);

    pWaveInfo->riffChunk.format[0] = 'W';

    pWaveInfo->riffChunk.format[1] = 'A';

    pWaveInfo->riffChunk.format[2] = 'V';

    pWaveInfo->riffChunk.format[3] = 'E';

    //strncpy(pWaveInfo->fmtChunk.chunkId, "fmt", 3);

    pWaveInfo->fmtChunk.chunkId[0] = 'f';

    pWaveInfo->fmtChunk.chunkId[1] = 'm';

    pWaveInfo->fmtChunk.chunkId[2] = 't';

    pWaveInfo->fmtChunk.chunkId[3] = ' ';

    pWaveInfo->fmtChunk.chunkSize = sizeof(WAVE_FMT) - 8;

    pWaveInfo->fmtChunk.audioFormat = 1;

    pWaveInfo->fmtChunk.chNum = chNum;

    pWaveInfo->fmtChunk.sampleRate = sampleRate;

    pWaveInfo->fmtChunk.byteRate = sampleRate * chNum * bitsPerSample / 8;

    pWaveInfo->fmtChunk.blockAlign = chNum * bitsPerSample / 8;

    pWaveInfo->fmtChunk.bitsPerSample = bitsPerSample;

    //strncpy(pWaveInfo->dataChunk.chunkId, "data", 4);

    pWaveInfo->dataChunk.chunkId[0] = 'd';

    pWaveInfo->dataChunk.chunkId[1] = 'a';

    pWaveInfo->dataChunk.chunkId[2] = 't';

    pWaveInfo->dataChunk.chunkId[3] = 'a';

    

    pWaveInfo->dataChunk.chunkSize = 0;

    pWaveInfo->totalSampleNum = 0;

    ///printWaveHeader(pWaveInfo);

}


void rwRiffChunk(WAVE_INFO *pWaveInfo, unsigned char fgRead)

{

    if (fgRead)

    {

        fread((char *)&pWaveInfo->riffChunk.chunkId, 4, 1, pWaveInfo->fp);

        fread((char *)&pWaveInfo->riffChunk.chunkSize, 4, 1, pWaveInfo->fp);

        fread((char *)&pWaveInfo->riffChunk.format, 4, 1, pWaveInfo->fp);

    }

    else

    {

        fwrite((char *)&pWaveInfo->riffChunk.chunkId, 4, 1, pWaveInfo->fp);

        fwrite((char *)&pWaveInfo->riffChunk.chunkSize, 4, 1, pWaveInfo->fp);

        fwrite((char *)&pWaveInfo->riffChunk.format, 4, 1, pWaveInfo->fp);

    }

}

void rwFmtChunk(WAVE_INFO *pWaveInfo, unsigned char fgRead)

{

    if (fgRead)

    {

        fread((char *)&pWaveInfo->fmtChunk.chunkId, 4, 1, pWaveInfo->fp);

        fread((char *)&pWaveInfo->fmtChunk.chunkSize, 4, 1, pWaveInfo->fp);

        fread((char *)&pWaveInfo->fmtChunk.audioFormat, 2, 1, pWaveInfo->fp);

        fread((char *)&pWaveInfo->fmtChunk.chNum, 2, 1, pWaveInfo->fp);

        fread((char *)&pWaveInfo->fmtChunk.sampleRate, 4, 1, pWaveInfo->fp);

        fread((char *)&pWaveInfo->fmtChunk.byteRate, 4, 1, pWaveInfo->fp);

        fread((char *)&pWaveInfo->fmtChunk.blockAlign, 2, 1, pWaveInfo->fp);

        fread((char *)&pWaveInfo->fmtChunk.bitsPerSample, 2, 1, pWaveInfo->fp);

    }

    else

    {

        fwrite((char *)&pWaveInfo->fmtChunk.chunkId, 4, 1, pWaveInfo->fp);

        fwrite((char *)&pWaveInfo->fmtChunk.chunkSize, 4, 1, pWaveInfo->fp);

        fwrite((char *)&pWaveInfo->fmtChunk.audioFormat, 2, 1, pWaveInfo->fp);

        fwrite((char *)&pWaveInfo->fmtChunk.chNum, 2, 1, pWaveInfo->fp);

        fwrite((char *)&pWaveInfo->fmtChunk.sampleRate, 4, 1, pWaveInfo->fp);

        fwrite((char *)&pWaveInfo->fmtChunk.byteRate, 4, 1, pWaveInfo->fp);

        fwrite((char *)&pWaveInfo->fmtChunk.blockAlign, 2, 1, pWaveInfo->fp);

        fwrite((char *)&pWaveInfo->fmtChunk.bitsPerSample, 2, 1, pWaveInfo->fp);

        

    }

}

void rwDataChunk(WAVE_INFO *pWaveInfo, unsigned char fgRead)

{

    if (fgRead)

    {

        fread((char *)&pWaveInfo->dataChunk.chunkId, 4, 1, pWaveInfo->fp);

        fread((char *)&pWaveInfo->dataChunk.chunkSize, 4, 1, pWaveInfo->fp);

    }

    else

    {

        fwrite((char *)&pWaveInfo->dataChunk.chunkId, 4, 1, pWaveInfo->fp);

        fwrite((char *)&pWaveInfo->dataChunk.chunkSize, 4, 1, pWaveInfo->fp);

    }

}


void readWaveHeader(char *fileName, WAVE_INFO *pWaveInfo)

{

    size_t retSize;

    strncpy(pWaveInfo->fileName, fileName, strlen(fileName));

    pWaveInfo->fp = fopen(fileName, "rb");

    if (pWaveInfo->fp == NULL)

    {

        printf("fopen fail, errno:%d\n", errno);

        return;

    }

    #if 0

    retSize = fread((char *)&pWaveInfo->riffChunk, sizeof(WAVE_RIFF), 1, pWaveInfo->fp);

    retSize = fread((char *)&pWaveInfo->fmtChunk, sizeof(WAVE_FMT), 1, pWaveInfo->fp);

    retSize = fread((char *)&pWaveInfo->dataChunk, sizeof(WAVE_DATA), 1, pWaveInfo->fp);

    #endif

    rwRiffChunk(pWaveInfo, 1);

    rwFmtChunk(pWaveInfo, 1);

    rwDataChunk(pWaveInfo, 1);

    pWaveInfo->pos = ftell(pWaveInfo->fp);

    pWaveInfo->totalSampleNum = pWaveInfo->dataChunk.chunkSize / (pWaveInfo->fmtChunk.bitsPerSample / 8);

    fclose(pWaveInfo->fp);

    printWaveHeader(pWaveInfo);

}


void initPpBuf(unsigned short chNum, unsigned short bankNum, unsigned long samplesPerBank, unsigned short bytesPerSample)

{

    unsigned short chIdx, bankIdx;

    gPpBuf.chNum = chNum;    

    gPpBuf.bankNum = bankNum;    

    gPpBuf.samplesPerBank = samplesPerBank;

    gPpBuf.bytesPerSample = bytesPerSample;


    gPpBuf.bankRp = gPpBuf.bankWp = 0;

    gPpBuf.fgEos = 0;

    gPpBuf.pData = (unsigned char ***)malloc(chNum * sizeof(unsigned char **));

    for (chIdx = 0; chIdx < chNum; chIdx++)

    {

        gPpBuf.pData[chIdx] = (unsigned char **)malloc(bankNum * sizeof(unsigned char *));

        for (bankIdx =0; bankIdx < bankNum; bankIdx++)

        {

            gPpBuf.pData[chIdx][bankIdx] = (unsigned char *) malloc(samplesPerBank * bytesPerSample * sizeof(unsigned char));

        }

    }

    gPpBuf.fgInited = 1;

}


int sendData(unsigned char *writeBuffer, unsigned short chNum)

{

    unsigned short sampleIdx, chIdx, byteIdx;

    //printf("sendData, wp:%d, rp:%d\n", gPpBuf.bankWp, gPpBuf.bankRp);

    if ((gPpBuf.bankWp + 1 ) % gPpBuf.bankNum == gPpBuf.bankRp)

    {

        //full

        return 1;

    }

    else

    {

        for (sampleIdx = 0; sampleIdx < PP_SAMPLES; sampleIdx++)

        {

            for (chIdx =0; chIdx < chNum; chIdx++)

            {

                for (byteIdx = 0; byteIdx < gPpBuf.bytesPerSample; byteIdx++)

                {

               gPpBuf.pData[chIdx][gPpBuf.bankWp][sampleIdx * gPpBuf.bytesPerSample + byteIdx] = writeBuffer[(chIdx + sampleIdx * chNum) * gPpBuf.bytesPerSample + byteIdx];  

          }

            }

        }

        gPpBuf.bankWp = (gPpBuf.bankWp + 1) % gPpBuf.bankNum;

    }

    return 0;

}


int recvData(unsigned char **readBuffer)

{

    unsigned short chIdx;

    //printf("recvData, wp:%d, rp:%d\n", gPpBuf.bankWp, gPpBuf.bankRp);

    if (gPpBuf.bankWp == gPpBuf.bankRp)

    {

        //empty

        return 1;

    }

    else

    {

        for (chIdx = 0; chIdx < gPpBuf.chNum; chIdx++)

        {

            memcpy(&readBuffer[chIdx][0], &gPpBuf.pData[chIdx][gPpBuf.bankRp][0], PP_SAMPLES * gPpBuf.bytesPerSample * sizeof(unsigned char));

        }

        gPpBuf.bankRp = (gPpBuf.bankRp + 1) % gPpBuf.bankNum;

    }

    return 0;

}

void *readThread(void *arg)

{

    char *fileName = (char *)arg;

    size_t retSize;

    WAVE_INFO waveInfo;

    memset(&waveInfo, 0, sizeof(WAVE_INFO));

    unsigned long bytesPerLoop;

    unsigned short loopIdx, loop;

    unsigned long readCount = 0;

    readWaveHeader(fileName, &waveInfo);

    initPpBuf(waveInfo.fmtChunk.chNum, 3, PP_SAMPLES, 2);


    unsigned long readSize = READ_SAMPLES * waveInfo.fmtChunk.chNum * waveInfo.fmtChunk.bitsPerSample / 8;

    printf("readSize:%ld\n", readSize);

    unsigned char *readBuffer = (unsigned char *)malloc(readSize * sizeof(unsigned char));

    waveInfo.fp = fopen(fileName, "rb");

    fseek(waveInfo.fp,  waveInfo.pos, SEEK_SET);

    while (1)

    {

        retSize = fread(readBuffer, readSize, 1, waveInfo.fp);

        if (retSize <= 0)

        {

             printf("fread fail,retSize:%d, %s, eof:%d, readCount:%ld\n", (int) retSize, strerror(errno), feof(waveInfo.fp), readCount);

             gPpBuf.fgEos = 1;

             break;

        }

        else

        {

             bytesPerLoop = PP_SAMPLES *waveInfo.fmtChunk.chNum * waveInfo.fmtChunk.bitsPerSample / 8;

             loop = readSize / bytesPerLoop;

             loopIdx = 0;

             while (loopIdx < loop)

             {

                 if (0 != sendData(readBuffer + loopIdx * bytesPerLoop, waveInfo.fmtChunk.chNum))

                 {

                     usleep(1000);

                 }

                 else

                 {

                     loopIdx++;

                 }

             }

             readCount++; 

        }

    }

    return NULL;

}

void pp(DATA_INFO_T *pDataInfo)

{

    //fader(&gFaderHandle, pDataInfo);

    //drc(&gDrcHandle, pDataInfo);

    //filter(&gFilterHandle, pDataInfo);

    eq(&gEqHandle, pDataInfo);

}


void saveOneChInWave(unsigned char *pData, unsigned long size, WAVE_INFO *pWaveInfo)

{

   size_t retSize = 0;

   if (pWaveInfo->fp == NULL)

   {

       pWaveInfo->fp = fopen(pWaveInfo->fileName, "wb");

       #if 0

       retSize = fwrite((char *)&pWaveInfo->riffChunk, sizeof(WAVE_RIFF), 1, pWaveInfo->fp);

       retSize = fwrite((char *)&pWaveInfo->fmtChunk, sizeof(WAVE_FMT), 1, pWaveInfo->fp);

        retSize = fwrite((char *)&pWaveInfo->dataChunk, sizeof(WAVE_DATA), 1, pWaveInfo->fp);

        #endif

        rwRiffChunk(pWaveInfo, 0);

        rwFmtChunk(pWaveInfo, 0);

        rwDataChunk(pWaveInfo, 0);   

    } 

    retSize = fwrite(pData, size, 1, pWaveInfo->fp);

    pWaveInfo->totalSampleNum += (size / pWaveInfo->fmtChunk.chNum / (pWaveInfo->fmtChunk.bitsPerSample / 8));

    pWaveInfo->pos = ftell(pWaveInfo->fp);

}


void updateWaveHeader(WAVE_INFO *pWaveInfo)

{

    size_t retSize;

    pWaveInfo->riffChunk.chunkSize = pWaveInfo->pos - 8;

    pWaveInfo->dataChunk.chunkSize = pWaveInfo->totalSampleNum * pWaveInfo->fmtChunk.chNum * pWaveInfo->fmtChunk.bitsPerSample / 8;

    fseek(pWaveInfo->fp,  0, SEEK_SET);

    #if 0

    retSize = fwrite((char *)&pWaveInfo->riffChunk, sizeof(WAVE_RIFF), 1, pWaveInfo->fp);

    retSize = fwrite((char *)&pWaveInfo->fmtChunk, sizeof(WAVE_FMT), 1, pWaveInfo->fp);

    retSize = fwrite((char *)&pWaveInfo->dataChunk, sizeof(WAVE_DATA), 1, pWaveInfo->fp);

    #endif    

    rwRiffChunk(pWaveInfo, 0);

    rwFmtChunk(pWaveInfo, 0);

    rwDataChunk(pWaveInfo, 0);   

    fclose(pWaveInfo->fp);

    

    printWaveHeader(pWaveInfo);

}

void *ppThread(void *arg)

{

    char *fileName = (char *)arg;

    WAVE_INFO waveInfo;

    memset(&waveInfo, 0, sizeof(waveInfo));

    strncpy(waveInfo.fileName, fileName, strlen(fileName));

    printf("out file:%s\n", waveInfo.fileName);

    waveInfo.fp = NULL;

    while(!gPpBuf.fgInited)

    {

        usleep(1000);

    }

    initWaveInfo(&waveInfo, 1, 48000, 16);

    unsigned char **readBuffer = (unsigned char **)malloc(gPpBuf.chNum * sizeof(unsigned char *));

    unsigned short chIdx;

    for(chIdx = 0; chIdx < gPpBuf.chNum; chIdx++)

    {

        readBuffer[chIdx] = (unsigned char *)malloc(PP_SAMPLES * gPpBuf.bytesPerSample * sizeof(unsigned char));

    }

    while (1)

    {

        if (0 != recvData(readBuffer))

        {

            if (gPpBuf.fgEos)

                break;

            usleep(1000);

        }

        else

        {

            DATA_INFO_T dataInfo;

            dataInfo.chNum = gPpBuf.chNum;

            dataInfo.samples = PP_SAMPLES;

            dataInfo.bytesPerSample = gPpBuf.bytesPerSample;

            dataInfo.pData = (short **)readBuffer;

            pp(&dataInfo);

            saveOneChInWave(readBuffer[0], PP_SAMPLES * gPpBuf.bytesPerSample, &waveInfo);

        }

    }

    updateWaveHeader(&waveInfo);

    fgEnd = 1;

}


int main(int argc, char **argv)

{

#if 0

    WAVE_INFO inputWaveInfo, outputWaveInfo;

    readWaveHeader(argv[1], &inputWaveInfo);

    //initWaveInfo(&outputWaveInfo, 2, 48000, 16);

#endif

    

#if 1

    pthread_t readThreadId, ppThreadId;

    memset(&gPpBuf, 0, sizeof(PP_BUF_T));

   // initPpBuf(6, 3, PP_SAMPLES, 2);

    #if 0

    memset(&gFaderHandle, 0, sizeof(FADER_HANDLE_T));

    float curVolumDb = 0;

    float attuationDb = -5;

    FADER_TYPE_E type = FADER_TYPE_CUBIC;

    unsigned long timeMs = 5000;

    unsigned long sampleRate = 48000;

    faderInit(&gFaderHandle, attuationDb, type, timeMs, sampleRate, curVolumDb);

    #endif

    memset(&gDrcHandle, 0, sizeof(DRC_HANDLE_T));

#if 0

    DRC_COMPRESSOR_PARAM_T compressorParams;

    compressorParams.thresholdDb = -15;

    compressorParams.attackTimeMs = 1;

    compressorParams.releaseTimeMs = 10;

    compressorParams.ratio = 4;

    drcInit(&gDrcHandle, &compressorParams, DRC_TYPE_COMPRESSOR);    

#endif

#if 0

    DRC_LIMITER_PARAM_T limiterParams;

    limiterParams.thresholdDb = -15;

    limiterParams.attackTimeMs = 20;

    limiterParams.releaseTimeMs = 200;

    drcInit(&gDrcHandle, &limiterParams, DRC_TYPE_LIMITER);

#endif

#if 0 

    DRC_EXPANDER_PARAM_T expanderParams;

    expanderParams.thresholdDb = -30;

    expanderParams.attackTimeMs = 10;

    expanderParams.releaseTimeMs = 100;

    expanderParams.ratio = 4;

    expanderParams.holdTimeMs = 0;

    drcInit(&gDrcHandle, &expanderParams, DRC_TYPE_EXPANDER);

#endif

#if 0

    FILTER_PARAM_T filterParams;

    memset(&filterParams, 0, sizeof(FILTER_PARAM_T));

    filterParams.fs = 48000;

    filterParams.f0 = 500;

    filterParams.Q = 0.707;

    filterInit(&gFilterHandle, FILTER_TYPE_LPF, &filterParams);

#endif

#if 0

    FILTER_PARAM_T filterParams;

    memset(&filterParams, 0, sizeof(FILTER_PARAM_T));

    filterParams.fs = 48000;

    filterParams.f0 = 4000;

    filterParams.Q = 0.707;

    filterParams.gainDb = 6;

    filterInit(&gFilterHandle, FILTER_TYPE_LSF, &filterParams);

#endif

#if 0

    FILTER_PARAM_T filterParams;

    memset(&filterParams, 0, sizeof(FILTER_PARAM_T));

    filterParams.fs = 48000;

    filterParams.f0 = 8000;

    filterParams.Q = 0.707;

    filterInit(&gFilterHandle, FILTER_TYPE_HPF, &filterParams);

#endif

#if 0

    FILTER_PARAM_T filterParams;

    memset(&filterParams, 0, sizeof(FILTER_PARAM_T));

    filterParams.fs = 48000;

    filterParams.f0 = 8000;

    filterParams.Q = 0.707;

    filterParams.gainDb = 6;

    filterInit(&gFilterHandle, FILTER_TYPE_HSF, &filterParams);

#endif

    eqInit(&gEqHandle, EQ_MODE_POP);

    pthread_create(&readThreadId, NULL, readThread, argv[1]);

    pthread_create(&ppThreadId, NULL, ppThread, argv[2]);

    while(!fgEnd)

    {

        sleep(1);

    }

#endif

    return 0;

}