fader
Posted fellow1988
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了fader相关的知识,希望对你有一定的参考价值。
fader在音频处理中是比较基础的处理。通常用于平滑的调节音量,或是音频的渐入和渐出效果。
比较常见的fader有line和cubic线型的fader。
line fader即fader的渐变过程是线性的。cubic的渐变过程是三次曲线。
line fader:
5s内衰减5db
5s时间fader in
实现代码如下:
#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 256 #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; }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; 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) { printf("faderCalcGain "); 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 ", pFaderHandle->curGain, pFaderHandle->curSample, pFaderHandle->timeInSample); } 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)); } } } 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); 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); } 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; 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; initPpBuf(6, 3, PP_SAMPLES, 2); memset(&gFaderHandle, 0, sizeof(FADER_HANDLE_T)); float curVolumDb = -96; float attuationDb = 96; FADER_TYPE_E type = FADER_TYPE_LINE; unsigned long timeMs = 5000; unsigned long sampleRate = 48000; faderInit(&gFaderHandle, attuationDb, type, timeMs, sampleRate, curVolumDb); pthread_create(&readThreadId, NULL, readThread, argv[1]); pthread_create(&ppThreadId, NULL, ppThread, argv[2]); while(!fgEnd) { sleep(1); } #endif return 0; }
以上是关于fader的主要内容,如果未能解决你的问题,请参考以下文章
python 从“如何设计客户保留”中实现移位β几何(sBG)模型(Fader and Hardie 2006)http://www.bruc
python 从“如何设计客户保留”中实现移位β几何(sBG)模型(Fader and Hardie 2006)http://www.bruc