转载:WAV header
Posted fellow_jing
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了转载:WAV header相关的知识,希望对你有一定的参考价值。
转自:http://www.cnblogs.com/CoderTian/p/6657844.html
WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持。WAVE文件通常只是一个具有单个“WAVE”块的RIFF文件,该块由两个子块(”fmt”子数据块和”data”子数据块),它的格式如下图所示
该格式的实质就是在PCM文件的前面加了一个文件头,每个字段的的含义为
typedef struct{
char ChunkID[4];//内容为"RIFF"
unsigned long ChunkSize;//存储文件的字节数(不包含ChunkID和ChunkSize这8个字节)
char Format[4];//内容为"WAVE"
}WAVE_HEADER;
typedef struct{
char Subchunk1ID[4];//内容为"fmt"
unsigned long Subchunk1Size;//存储该子块的字节数(不含前面的Subchunk1ID和Subchunk1Size这8个字节)
unsigned short AudioFormat;//存储音频文件的编码格式,例如若为PCM则其存储值为1,若为其他非PCM格式的则有一定的压缩。
unsigned short NumChannels;//通道数,单通道(Mono)值为1,双通道(Stereo)值为2,等等
unsigned long SampleRate;//采样率,如8k,44.1k等
unsigned long ByteRate;//每秒存储的bit数,其值=SampleRate * NumChannels * BitsPerSample/8
unsigned short BlockAlign;//块对齐大小,其值=NumChannels * BitsPerSample/8
unsigned short BitsPerSample;//每个采样点的bit数,一般为8,16,32等。
}WAVE_FMT;
typedef struct{
char Subchunk2ID[4];//内容为“data”
unsigned long Subchunk2Size;//内容为接下来的正式的数据部分的字节数,其值=NumSamples * NumChannels * BitsPerSample/8
}WAVE_DATA;
比如下面的例子
这里是一个WAVE文件的开头72字节,字节显示为十六进制数字:
52 49 46 46 24 08 00 00 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 02 00
22 56 00 00 88 58 01 00 04 00 10 00 64 61 74 61 00 08 00 00 00 00 00 00
24 17 1e f3 3c 13 3c 14 16 f9 18 f9 34 e7 23 a6 3c f2 24 f2 11 ce 1a 0d
字段解析:
pcm 加上WAV header的代码实现为
int simplest_pcm16le_to_wave(const char *pcmpath,int channels,int sample_rate,const char *wavepath)
{
typedef struct WAVE_HEADER{
char fccID[4];
unsigned long dwSize;
char fccType[4];
}WAVE_HEADER;
typedef struct WAVE_FMT{
char fccID[4];
unsigned long dwSize;
unsigned short wFormatTag;
unsigned short wChannels;
unsigned long dwSamplesPerSec;
unsigned long dwAvgBytesPerSec;
unsigned short wBlockAlign;
unsigned short uiBitsPerSample;
}WAVE_FMT;
typedef struct WAVE_DATA{
char fccID[4];
unsigned long dwSize;
}WAVE_DATA;
if(channels==0||sample_rate==0){
channels = 2;
sample_rate = 44100;
}
int bits = 16;
WAVE_HEADER pcmHEADER;
WAVE_FMT pcmFMT;
WAVE_DATA pcmDATA;
unsigned short m_pcmData;
FILE *fp,*fpout;
fp=fopen(pcmpath, "rb");
if(fp == NULL) {
printf("open pcm file error\\n");
return -1;
}
fpout=fopen(wavepath, "wb+");
if(fpout == NULL) {
printf("create wav file error\\n");
return -1;
}
//WAVE_HEADER
memcpy(pcmHEADER.fccID,"RIFF",strlen("RIFF"));
memcpy(pcmHEADER.fccType,"WAVE",strlen("WAVE"));
fseek(fpout,sizeof(WAVE_HEADER),1);
//WAVE_FMT
pcmFMT.dwSamplesPerSec=sample_rate;
pcmFMT.dwAvgBytesPerSec=pcmFMT.dwSamplesPerSec*sizeof(m_pcmData);
pcmFMT.uiBitsPerSample=bits;
memcpy(pcmFMT.fccID,"fmt ",strlen("fmt "));
pcmFMT.dwSize=16;
pcmFMT.wBlockAlign=2;
pcmFMT.wChannels=channels;
pcmFMT.wFormatTag=1;
fwrite(&pcmFMT,sizeof(WAVE_FMT),1,fpout);
//WAVE_DATA;
memcpy(pcmDATA.fccID,"data",strlen("data"));
pcmDATA.dwSize=0;
fseek(fpout,sizeof(WAVE_DATA),SEEK_CUR);
fread(&m_pcmData,sizeof(unsigned short),1,fp);
while(!feof(fp)){
pcmDATA.dwSize+=2;
fwrite(&m_pcmData,sizeof(unsigned short),1,fpout);
fread(&m_pcmData,sizeof(unsigned short),1,fp);
}
pcmHEADER.dwSize=44+pcmDATA.dwSize;
rewind(fpout);
fwrite(&pcmHEADER,sizeof(WAVE_HEADER),1,fpout);
fseek(fpout,sizeof(WAVE_FMT),SEEK_CUR);
fwrite(&pcmDATA,sizeof(WAVE_DATA),1,fpout);
fclose(fp);
fclose(fpout);
return 0;
}
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<pthread.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; PP_BUF_T gPpBuf; unsigned char fgEnd = 0; 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 = 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)); } } } 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); 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() { } 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; 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 { saveOneChInWave(readBuffer[0], PP_SAMPLES * gPpBuf.bytesPerSample, &waveInfo); pp(); } } 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); pthread_create(&readThreadId, NULL, readThread, argv[1]); pthread_create(&ppThreadId, NULL, ppThread, argv[2]); while(!fgEnd) { sleep(1); } #endif return 0; }
以上是关于转载:WAV header的主要内容,如果未能解决你的问题,请参考以下文章
如果它尝试播放 mp3 文件,我的代码会崩溃,适用于 wav 文件