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

    原理参考之前转载的matlab上关于DRC的描述。

    目前主要实现了compressor和expander.

    compressor:

    Limit:

    expander:

    实现代码:

    #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
    {
        short sampleValue;
        short bytesPerSample;
    }SAMPLE_INFO_T;
    
    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 = 16;//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);
    }
    
    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 = 20;
        compressorParams.releaseTimeMs = 200;
        compressorParams.ratio = 4;
        drcInit(&gDrcHandle, &compressorParams, DRC_TYPE_COMPRESSOR);    
    #endif
        DRC_LIMITER_PARAM_T limiterParams;
        limiterParams.thresholdDb = -15;
        limiterParams.attackTimeMs = 1;
        limiterParams.releaseTimeMs = 10;
        drcInit(&gDrcHandle, &limiterParams, DRC_TYPE_LIMITER);
    #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
        pthread_create(&readThreadId, NULL, readThread, argv[1]);
        pthread_create(&ppThreadId, NULL, ppThread, argv[2]);
        while(!fgEnd)
        {
            sleep(1);
        }
    #endif
        return 0;
    }
  • 相关阅读:
    SharePoint 2013 图文开发系列之自定义字段
    SharePoint 2013 图文开发系列之Visual Studio 创建母版页
    SharePoint 2013 图文开发系列之代码定义列表
    SharePoint 2013 图文开发系列之计时器任务
    SharePoint 2013 图文开发系列之应用程序页
    SharePoint 2013 图文开发系列之事件接收器
    SharePoint 2013 图文开发系列之可视化WebPart
    SharePoint 2013 图文开发系列之WebPart
    SharePoint 2013 对二进制大型对象(BLOB)进行爬网
    SharePoint 2013 状态机工作流之日常报销示例
  • 原文地址:https://www.cnblogs.com/fellow1988/p/9631617.html
Copyright © 2011-2022 走看看