原理参考之前转载的matlab上关于DRC的描述。
目前主要实现了compressor和expander.
compressor:
Limit:
expander:
实现代码:
#include#include #include #include<string.h> #include #include 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\n", maxSampleValue, pSampleInfo->sampleValue, db); return db; } float drcComputeGainDb(DRC_HANDLE_T *pDrcHandle, float sampleDb) { if (pDrcHandle == NULL) return 0; float staticChract; switch (pDrcHandle->eDrcType) { case DRC_TYPE_COMPRESSOR: if (sampleDb < pDrcHandle->uDrcParams.compressorParams.thresholdDb) { staticChract = sampleDb; } else { staticChract = pDrcHandle->uDrcParams.compressorParams.thresholdDb + (sampleDb - pDrcHandle->uDrcParams.compressorParams.thresholdDb) / pDrcHandle->uDrcParams.compressorParams.ratio; } break; case DRC_TYPE_LIMITER: if (sampleDb < pDrcHandle->uDrcParams.limiterParams.thresholdDb) { staticChract = sampleDb; } else { staticChract = pDrcHandle->uDrcParams.limiterParams.thresholdDb; } break; case DRC_TYPE_EXPANDER: if (sampleDb >= pDrcHandle->uDrcParams.expanderParams.thresholdDb) { staticChract = sampleDb; } else { staticChract = pDrcHandle->uDrcParams.expanderParams.thresholdDb + (sampleDb - pDrcHandle->uDrcParams.expanderParams.thresholdDb) / pDrcHandle->uDrcParams.expanderParams.ratio; } break; case DRC_TYPE_AUTO: break; } //printf("staticChract:%f, sampleDb:%f\n", staticChract, sampleDb); return staticChract - sampleDb; } float drcCompressorSmoothGain(DRC_HANDLE_T *pDrcHandle, float computeGainDb) { float smoothGainDb; if (computeGainDb < pDrcHandle->curSmoothGainDb) { smoothGainDb = pDrcHandle->alphaAttack * pDrcHandle->curSmoothGainDb + (1 - pDrcHandle->alphaAttack) * computeGainDb; } else { smoothGainDb = pDrcHandle->alphaRelease * pDrcHandle->curSmoothGainDb + (1 - pDrcHandle->alphaRelease) * computeGainDb; } return smoothGainDb; } float drcExpanderSmoothGain(DRC_HANDLE_T *pDrcHandle, float computeGainDb) { float smoothGainDb; unsigned long holdTimeInSample = pDrcHandle->uDrcParams.expanderParams.holdTimeMs * 48000 / 1000; if (pDrcHandle->attackHoldCounter >= holdTimeInSample && computeGainDb > pDrcHandle->curSmoothGainDb) { smoothGainDb = pDrcHandle->alphaAttack * pDrcHandle->curSmoothGainDb + (1 - pDrcHandle->alphaAttack) * computeGainDb; } else if (pDrcHandle->attackHoldCounter < holdTimeInSample && computeGainDb > pDrcHandle->curSmoothGainDb) { smoothGainDb = pDrcHandle->curSmoothGainDb; pDrcHandle->attackHoldCounter++; pDrcHandle->releaseHoldCounter = 0; } else if (pDrcHandle->releaseHoldCounter >= holdTimeInSample && computeGainDb <= pDrcHandle->curSmoothGainDb) { smoothGainDb = pDrcHandle->alphaRelease * pDrcHandle->curSmoothGainDb + (1 - pDrcHandle->alphaRelease) * computeGainDb; } else if (pDrcHandle->releaseHoldCounter < holdTimeInSample && computeGainDb <= pDrcHandle->curSmoothGainDb) { smoothGainDb = pDrcHandle->curSmoothGainDb; pDrcHandle->releaseHoldCounter++; pDrcHandle->attackHoldCounter = 0; } return smoothGainDb; } float drcSmoothGain(DRC_HANDLE_T *pDrcHandle, float computeGainDb) { if (pDrcHandle == NULL) return 0; float smoothGainDb; switch (pDrcHandle->eDrcType) { case DRC_TYPE_COMPRESSOR: case DRC_TYPE_LIMITER: smoothGainDb = drcCompressorSmoothGain(pDrcHandle, computeGainDb); break; case DRC_TYPE_EXPANDER: smoothGainDb = drcExpanderSmoothGain(pDrcHandle, computeGainDb); break; case DRC_TYPE_AUTO: break; } return smoothGainDb; } void drcCalGain(DRC_HANDLE_T *pDrcHandle, SAMPLE_INFO_T *pSampleInfo) { if (pDrcHandle == NULL || pSampleInfo == NULL) return; float sampleDb = sampleValueToDb(pSampleInfo); float computeGainDb = drcComputeGainDb(pDrcHandle, sampleDb); pDrcHandle->curSmoothGainDb = drcSmoothGain(pDrcHandle, computeGainDb); pDrcHandle->curGain = dbToGain(pDrcHandle->curSmoothGainDb); printf("sampleDb:%f, computeGainDb:%f, smoothGainDb:%f, curGain:%f\n", sampleDb, computeGainDb, pDrcHandle->curSmoothGainDb, pDrcHandle->curGain); } void drc(DRC_HANDLE_T *pDrcHandle, DATA_INFO_T *pDataInfo) { unsigned short sampleIdx, chIdx; SAMPLE_INFO_T sampleInfo; for (chIdx = 0; chIdx < pDataInfo->chNum; chIdx++) { for (sampleIdx = 0; sampleIdx < pDataInfo->samples; sampleIdx++) { sampleInfo.bytesPerSample = 2; sampleInfo.sampleValue = pDataInfo->pData[chIdx][sampleIdx]; drcCalGain(pDrcHandle, &sampleInfo); pDataInfo->pData[chIdx][sampleIdx] *= pDrcHandle->curGain; } } } float mapSegGainToRealGain(FADER_HANDLE_T *pFaderHandle, float segGain) { float deltaGain = pFaderHandle->targetGain - pFaderHandle->startGain; float realGain = deltaGain * segGain + pFaderHandle->startGain; return realGain; } void faderPrepareShape(FADER_HANDLE_T *pFaderHandle, unsigned short segNum) { unsigned short segIdx; pFaderHandle->segGain = (float *)malloc((segNum + 1) * sizeof(float)); pFaderHandle->segNum = segNum; float tmp; if (pFaderHandle->faderParams.type != FADER_TYPE_CUBIC) return; //0~1 divide into N seg. for (segIdx = 0; segIdx < segNum + 1; segIdx++) { tmp = (float)segIdx / segNum; pFaderHandle->segGain[segIdx] = tmp * tmp * tmp; pFaderHandle->segGain[segIdx] = mapSegGainToRealGain(pFaderHandle, pFaderHandle->segGain[segIdx]); } } float dbToGain(float db) { return pow(10, db/20); } void faderInit(FADER_HANDLE_T *pFaderHandle, float attuationDb, FADER_TYPE_E type, unsigned long timeMs, unsigned long sampleRate, float curVolumDb) { pFaderHandle->faderParams.attuationDb = attuationDb; pFaderHandle->faderParams.type = type; pFaderHandle->faderParams.timeMs = timeMs; pFaderHandle->timeInSample = timeMs * sampleRate / 1000; pFaderHandle->curGain = pFaderHandle->startGain = dbToGain(curVolumDb); pFaderHandle->targetGain = dbToGain(curVolumDb + attuationDb); pFaderHandle->curSample = 0; faderPrepareShape(pFaderHandle, 20); printf("faderInit\n"); } void faderCalGain(FADER_HANDLE_T *pFaderHandle) { float startGainInCurSeg, endGainInCurSeg, step; float deltaGain = pFaderHandle->targetGain - pFaderHandle->startGain; unsigned long samplesInSeg = pFaderHandle->timeInSample / pFaderHandle->segNum; unsigned short curSeg = (float)pFaderHandle->curSample / samplesInSeg; unsigned long startSampleInCurSeg = samplesInSeg * curSeg; switch (pFaderHandle->faderParams.type) { case FADER_TYPE_LINE: step = deltaGain / pFaderHandle->timeInSample; pFaderHandle->curGain += deltaGain / pFaderHandle->timeInSample; //pFaderHandle->curGain = pFaderHandle->startGain + deltaGain * pFaderHandle->curSample / pFaderHandle->timeInSample; break; case FADER_TYPE_CUBIC: startGainInCurSeg = pFaderHandle->segGain[curSeg]; endGainInCurSeg = pFaderHandle->segGain[curSeg + 1]; step = (endGainInCurSeg - startGainInCurSeg) / samplesInSeg; if (pFaderHandle->curSample == startSampleInCurSeg) pFaderHandle->curGain = startGainInCurSeg; else pFaderHandle->curGain += step; break; } printf("curGain:%f, curSample:%ld, timeInSample:%ld, curSeg:%d, startGain:%f, endGain:%f\n", pFaderHandle->curGain, pFaderHandle->curSample, pFaderHandle->timeInSample, curSeg, startGainInCurSeg, endGainInCurSeg); } void fader(FADER_HANDLE_T *pFaderHandle, DATA_INFO_T *pDataInfo) { unsigned short sampleIdx, chIdx; for (sampleIdx = 0; sampleIdx < pDataInfo->samples; sampleIdx++) { if (pFaderHandle->curSample != pFaderHandle->timeInSample) { faderCalGain(pFaderHandle); pFaderHandle->curSample++; } for (chIdx = 0; chIdx < pDataInfo->chNum; chIdx++) { pDataInfo->pData[chIdx][sampleIdx] *= pFaderHandle->curGain; } } } void printWaveHeader(WAVE_INFO *pWaveInfo) { printf("fileName:%s\n", pWaveInfo->fileName); printf("riff chunk:\n"); printf("chunkId:%c%c%c%c\n", pWaveInfo->riffChunk.chunkId[0], pWaveInfo->riffChunk.chunkId[1], pWaveInfo->riffChunk.chunkId[2], pWaveInfo->riffChunk.chunkId[3]); printf("chunkSize:%ld\n", pWaveInfo->riffChunk.chunkSize); printf("format:%c%c%c%c\n", pWaveInfo->riffChunk.format[0], pWaveInfo->riffChunk.format[1], pWaveInfo->riffChunk.format[2], pWaveInfo->riffChunk.format[3]); printf("fmt chunk:\n"); printf("chunkId:%c%c%c\n", pWaveInfo->fmtChunk.chunkId[0], pWaveInfo->fmtChunk.chunkId[1], pWaveInfo->fmtChunk.chunkId[2]); printf("chunkSize:%ld\n", pWaveInfo->fmtChunk.chunkSize); printf("audioFormat:%d\n", pWaveInfo->fmtChunk.audioFormat); printf("chNum:%d\n", pWaveInfo->fmtChunk.chNum); printf("sampleRate:%ld\n", pWaveInfo->fmtChunk.sampleRate); printf("byteRate:%ld\n", pWaveInfo->fmtChunk.byteRate); printf("blockAlign:%d\n", pWaveInfo->fmtChunk.blockAlign); printf("bitsPerSample:%d\n", pWaveInfo->fmtChunk.bitsPerSample); printf("data chunk:\n"); printf("chunkId:%c%c%c%c\n", pWaveInfo->dataChunk.chunkId[0], pWaveInfo->dataChunk.chunkId[1], pWaveInfo->dataChunk.chunkId[2], pWaveInfo->dataChunk.chunkId[3]); printf("chunkSize:%ld\n", pWaveInfo->dataChunk.chunkSize); } void initWaveInfo(WAVE_INFO *pWaveInfo, unsigned short chNum, unsigned long sampleRate, unsigned short bitsPerSample) { //strncpy(pWaveInfo->riffChunk.chunkId, "RIFF", 4); pWaveInfo->riffChunk.chunkId[0] = 'R'; pWaveInfo->riffChunk.chunkId[1] = 'I'; pWaveInfo->riffChunk.chunkId[2] = 'F'; pWaveInfo->riffChunk.chunkId[3] = 'F'; pWaveInfo->riffChunk.chunkSize = 0; //strncpy(pWaveInfo->riffChunk.format, "WAVE", 4); pWaveInfo->riffChunk.format[0] = 'W'; pWaveInfo->riffChunk.format[1] = 'A'; pWaveInfo->riffChunk.format[2] = 'V'; pWaveInfo->riffChunk.format[3] = 'E'; //strncpy(pWaveInfo->fmtChunk.chunkId, "fmt", 3); pWaveInfo->fmtChunk.chunkId[0] = 'f'; pWaveInfo->fmtChunk.chunkId[1] = 'm'; pWaveInfo->fmtChunk.chunkId[2] = 't'; pWaveInfo->fmtChunk.chunkId[3] = ' '; pWaveInfo->fmtChunk.chunkSize = 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\n", errno); return; } #if 0 retSize = fread((char *)&pWaveInfo->riffChunk, sizeof(WAVE_RIFF), 1, pWaveInfo->fp); retSize = fread((char *)&pWaveInfo->fmtChunk, sizeof(WAVE_FMT), 1, pWaveInfo->fp); retSize = fread((char *)&pWaveInfo->dataChunk, sizeof(WAVE_DATA), 1, pWaveInfo->fp); #endif rwRiffChunk(pWaveInfo, 1); rwFmtChunk(pWaveInfo, 1); rwDataChunk(pWaveInfo, 1); pWaveInfo->pos = ftell(pWaveInfo->fp); pWaveInfo->totalSampleNum = pWaveInfo->dataChunk.chunkSize / (pWaveInfo->fmtChunk.bitsPerSample / 8); fclose(pWaveInfo->fp); printWaveHeader(pWaveInfo); } void initPpBuf(unsigned short chNum, unsigned short bankNum, unsigned long samplesPerBank, unsigned short bytesPerSample) { unsigned short chIdx, bankIdx; gPpBuf.chNum = chNum; gPpBuf.bankNum = bankNum; gPpBuf.samplesPerBank = samplesPerBank; gPpBuf.bytesPerSample = bytesPerSample; gPpBuf.bankRp = gPpBuf.bankWp = 0; gPpBuf.fgEos = 0; gPpBuf.pData = (unsigned char ***)malloc(chNum * sizeof(unsigned char **)); for (chIdx = 0; chIdx < chNum; chIdx++) { gPpBuf.pData[chIdx] = (unsigned char **)malloc(bankNum * sizeof(unsigned char *)); for (bankIdx =0; bankIdx < bankNum; bankIdx++) { gPpBuf.pData[chIdx][bankIdx] = (unsigned char *) malloc(samplesPerBank * bytesPerSample * sizeof(unsigned char)); } } gPpBuf.fgInited = 1; } int sendData(unsigned char *writeBuffer, unsigned short chNum) { unsigned short sampleIdx, chIdx, byteIdx; //printf("sendData, wp:%d, rp:%d\n", gPpBuf.bankWp, gPpBuf.bankRp); if ((gPpBuf.bankWp + 1 ) % gPpBuf.bankNum == gPpBuf.bankRp) { //full return 1; } else { for (sampleIdx = 0; sampleIdx < PP_SAMPLES; sampleIdx++) { for (chIdx =0; chIdx < chNum; chIdx++) { for (byteIdx = 0; byteIdx < gPpBuf.bytesPerSample; byteIdx++) { gPpBuf.pData[chIdx][gPpBuf.bankWp][sampleIdx * gPpBuf.bytesPerSample + byteIdx] = writeBuffer[(chIdx + sampleIdx * chNum) * gPpBuf.bytesPerSample + byteIdx]; } } } gPpBuf.bankWp = (gPpBuf.bankWp + 1) % gPpBuf.bankNum; } return 0; } int recvData(unsigned char **readBuffer) { unsigned short chIdx; //printf("recvData, wp:%d, rp:%d\n", gPpBuf.bankWp, gPpBuf.bankRp); if (gPpBuf.bankWp == gPpBuf.bankRp) { //empty return 1; } else { for (chIdx = 0; chIdx < gPpBuf.chNum; chIdx++) { memcpy(&readBuffer[chIdx][0], &gPpBuf.pData[chIdx][gPpBuf.bankRp][0], PP_SAMPLES * gPpBuf.bytesPerSample * sizeof(unsigned char)); } gPpBuf.bankRp = (gPpBuf.bankRp + 1) % gPpBuf.bankNum; } return 0; } void *readThread(void *arg) { char *fileName = (char *)arg; size_t retSize; WAVE_INFO waveInfo; memset(&waveInfo, 0, sizeof(WAVE_INFO)); unsigned long bytesPerLoop; unsigned short loopIdx, loop; unsigned long readCount = 0; readWaveHeader(fileName, &waveInfo); initPpBuf(waveInfo.fmtChunk.chNum, 3, PP_SAMPLES, 2); unsigned long readSize = READ_SAMPLES * waveInfo.fmtChunk.chNum * waveInfo.fmtChunk.bitsPerSample / 8; printf("readSize:%ld\n", readSize); unsigned char *readBuffer = (unsigned char *)malloc(readSize * sizeof(unsigned char)); waveInfo.fp = fopen(fileName, "rb"); fseek(waveInfo.fp, waveInfo.pos, SEEK_SET); while (1) { retSize = fread(readBuffer, readSize, 1, waveInfo.fp); if (retSize <= 0) { printf("fread fail,retSize:%d, %s, eof:%d, readCount:%ld\n", (int) retSize, strerror(errno), feof(waveInfo.fp), readCount); gPpBuf.fgEos = 1; break; } else { bytesPerLoop = PP_SAMPLES *waveInfo.fmtChunk.chNum * waveInfo.fmtChunk.bitsPerSample / 8; loop = readSize / bytesPerLoop; loopIdx = 0; while (loopIdx < loop) { if (0 != sendData(readBuffer + loopIdx * bytesPerLoop, waveInfo.fmtChunk.chNum)) { usleep(1000); } else { loopIdx++; } } readCount++; } } return NULL; } void pp(DATA_INFO_T *pDataInfo) { //fader(&gFaderHandle, pDataInfo); drc(&gDrcHandle, pDataInfo); } void saveOneChInWave(unsigned char *pData, unsigned long size, WAVE_INFO *pWaveInfo) { size_t retSize = 0; if (pWaveInfo->fp == NULL) { pWaveInfo->fp = fopen(pWaveInfo->fileName, "wb"); #if 0 retSize = fwrite((char *)&pWaveInfo->riffChunk, sizeof(WAVE_RIFF), 1, pWaveInfo->fp); retSize = fwrite((char *)&pWaveInfo->fmtChunk, sizeof(WAVE_FMT), 1, pWaveInfo->fp); retSize = fwrite((char *)&pWaveInfo->dataChunk, sizeof(WAVE_DATA), 1, pWaveInfo->fp); #endif rwRiffChunk(pWaveInfo, 0); rwFmtChunk(pWaveInfo, 0); rwDataChunk(pWaveInfo, 0); } retSize = fwrite(pData, size, 1, pWaveInfo->fp); pWaveInfo->totalSampleNum += (size / pWaveInfo->fmtChunk.chNum / (pWaveInfo->fmtChunk.bitsPerSample / 8)); pWaveInfo->pos = ftell(pWaveInfo->fp); } void updateWaveHeader(WAVE_INFO *pWaveInfo) { size_t retSize; pWaveInfo->riffChunk.chunkSize = pWaveInfo->pos - 8; pWaveInfo->dataChunk.chunkSize = pWaveInfo->totalSampleNum * pWaveInfo->fmtChunk.chNum * pWaveInfo->fmtChunk.bitsPerSample / 8; fseek(pWaveInfo->fp, 0, SEEK_SET); #if 0 retSize = fwrite((char *)&pWaveInfo->riffChunk, sizeof(WAVE_RIFF), 1, pWaveInfo->fp); retSize = fwrite((char *)&pWaveInfo->fmtChunk, sizeof(WAVE_FMT), 1, pWaveInfo->fp); retSize = fwrite((char *)&pWaveInfo->dataChunk, sizeof(WAVE_DATA), 1, pWaveInfo->fp); #endif rwRiffChunk(pWaveInfo, 0); rwFmtChunk(pWaveInfo, 0); rwDataChunk(pWaveInfo, 0); fclose(pWaveInfo->fp); printWaveHeader(pWaveInfo); } void *ppThread(void *arg) { char *fileName = (char *)arg; WAVE_INFO waveInfo; memset(&waveInfo, 0, sizeof(waveInfo)); strncpy(waveInfo.fileName, fileName, strlen(fileName)); printf("out file:%s\n", waveInfo.fileName); waveInfo.fp = NULL; while(!gPpBuf.fgInited) { usleep(1000); } initWaveInfo(&waveInfo, 1, 48000, 16); unsigned char **readBuffer = (unsigned char **)malloc(gPpBuf.chNum * sizeof(unsigned char *)); unsigned short chIdx; for(chIdx = 0; chIdx < gPpBuf.chNum; chIdx++) { readBuffer[chIdx] = (unsigned char *)malloc(PP_SAMPLES * gPpBuf.bytesPerSample * sizeof(unsigned char)); } while (1) { if (0 != recvData(readBuffer)) { if (gPpBuf.fgEos) break; usleep(1000); } else { DATA_INFO_T dataInfo; dataInfo.chNum = gPpBuf.chNum; dataInfo.samples = PP_SAMPLES; dataInfo.bytesPerSample = gPpBuf.bytesPerSample; dataInfo.pData = (short **)readBuffer; pp(&dataInfo); saveOneChInWave(readBuffer[0], PP_SAMPLES * gPpBuf.bytesPerSample, &waveInfo); } } updateWaveHeader(&waveInfo); fgEnd = 1; } int main(int argc, char **argv) { #if 0 WAVE_INFO inputWaveInfo, outputWaveInfo; readWaveHeader(argv[1], &inputWaveInfo); //initWaveInfo(&outputWaveInfo, 2, 48000, 16); #endif #if 1 pthread_t readThreadId, ppThreadId; memset(&gPpBuf, 0, sizeof(PP_BUF_T)); // initPpBuf(6, 3, PP_SAMPLES, 2); #if 0 memset(&gFaderHandle, 0, sizeof(FADER_HANDLE_T)); float curVolumDb = 0; float attuationDb = -5; FADER_TYPE_E type = FADER_TYPE_CUBIC; unsigned long timeMs = 5000; unsigned long sampleRate = 48000; faderInit(&gFaderHandle, attuationDb, type, timeMs, sampleRate, curVolumDb); #endif memset(&gDrcHandle, 0, sizeof(DRC_HANDLE_T)); #if 0 DRC_COMPRESSOR_PARAM_T compressorParams; compressorParams.thresholdDb = -15; compressorParams.attackTimeMs = 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; }