biquad filter实现

原始频谱:

LPF:

HPF:

代码:

#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 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 >> 1;
}

#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);
    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]);
        }
    }
}

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);
}

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
    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);
    pthread_create(&readThreadId, NULL, readThread, argv[1]);
    pthread_create(&ppThreadId, NULL, ppThread, argv[2]);
    while(!fgEnd)
    {
        sleep(1);
    }
#endif
    return 0;
}
原文地址:https://www.cnblogs.com/fellow1988/p/9689005.html