zoukankan      html  css  js  c++  java
  • EQ实现

    原理参考:

    https://www.cnblogs.com/fellow1988/p/9189338.html

    https://www.cnblogs.com/fellow1988/p/9136346.html

    实现代码:

    #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
    ", 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
    ", 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
    ",
            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
    ");
    }
    
    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
    ", 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
    ", pWaveInfo->fileName);
        printf("riff chunk:
    ");
        printf("chunkId:%c%c%c%c
    ", pWaveInfo->riffChunk.chunkId[0], pWaveInfo->riffChunk.chunkId[1], pWaveInfo->riffChunk.chunkId[2], pWaveInfo->riffChunk.chunkId[3]);
        printf("chunkSize:%ld
    ", pWaveInfo->riffChunk.chunkSize);
        printf("format:%c%c%c%c
    ", pWaveInfo->riffChunk.format[0], pWaveInfo->riffChunk.format[1], pWaveInfo->riffChunk.format[2], pWaveInfo->riffChunk.format[3]);
        printf("fmt chunk:
    ");
        printf("chunkId:%c%c%c
    ", pWaveInfo->fmtChunk.chunkId[0], pWaveInfo->fmtChunk.chunkId[1], pWaveInfo->fmtChunk.chunkId[2]);
        printf("chunkSize:%ld
    ", pWaveInfo->fmtChunk.chunkSize);
        printf("audioFormat:%d
    ", pWaveInfo->fmtChunk.audioFormat);
        printf("chNum:%d
    ", pWaveInfo->fmtChunk.chNum);
        printf("sampleRate:%ld
    ", pWaveInfo->fmtChunk.sampleRate);
        printf("byteRate:%ld
    ", pWaveInfo->fmtChunk.byteRate);
        printf("blockAlign:%d
    ", pWaveInfo->fmtChunk.blockAlign);
        printf("bitsPerSample:%d
    ", pWaveInfo->fmtChunk.bitsPerSample);
        printf("data chunk:
    ");
        printf("chunkId:%c%c%c%c
    ", pWaveInfo->dataChunk.chunkId[0], pWaveInfo->dataChunk.chunkId[1], pWaveInfo->dataChunk.chunkId[2], pWaveInfo->dataChunk.chunkId[3]);
        printf("chunkSize:%ld
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", (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
    ", 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;
    }
  • 相关阅读:
    POJ1486 Sorting Slides 二分图or贪心
    POJ2060 Taxi Cab Scheme 最小路径覆盖
    POJ3083 Children of the Candy Corn 解题报告
    以前的文章
    POJ2449 Remmarguts' Date K短路经典题
    这一年的acm路
    POJ3014 Asteroids 最小点覆盖
    POJ2594 Treasure Exploration 最小路径覆盖
    POJ3009 Curling 2.0 解题报告
    POJ2226 Muddy Fields 最小点集覆盖
  • 原文地址:https://www.cnblogs.com/fellow1988/p/9747448.html
Copyright © 2011-2022 走看看