老调重谈的话题。
基本上标准的44个字节的头,对照这个表格就可以了
两个记录大小的地方是 相差36 2084 = 2048 +36
但也有较少的超过44个字节头的,比如这个:
这篇文章说的很清楚
https://sites.google.com/site/musicgapi/technical-documents/wav-file-format
还有其他的chunkID
多出来的,非44个自己的头,就是这些ID搞的鬼。我们搞信号处理的,不是很在乎其他的额外信息,那么直接对这些数据跳过去即可
他们都遵循着 4个字节的 chunkID,4个字节的 Chunk DATAsize,我们fread读到这里,直接过去即可
if(!((header->data_tag[0]=='d')
&&(header->data_tag[1]=='a')
&&(header->data_tag[2]=='t')
&&(header->data_tag[3]=='a')))
{
printf("Chunck ID: %s detected\n",header->data_tag);
printf("Non-Data Chunk detected\n");
fseek(fp,-4,SEEK_CUR);
do{
fread(&ChunkLen,1,4,fp);//读出来 长度
fseek(fp,ChunkLen,SEEK_CUR);//直接跳过拉倒
fread(&c1,1,1,fp);
fread(&c2,1,1,fp);
fread(&c3,1,1,fp);
fread(&c4,1,1,fp);
printf("Chunck ID: %c%c%c%c detected\n",c1,c2,c3,c4);
}
while(!((c1=='d')&&(c2=='a')&&(c3=='t')&&(c4=='a')));
header->data_tag[0] = 'd';
header->data_tag[1] = 'a';
header->data_tag[2] = 't';
header->data_tag[3] = 'a';
fread(&header->data_length,sizeof(header->data_length),1,fp);
}
对应Matlab有一个wavread2专门处理这个
处理一下上述文件
附加信息被记录到info里面
//wave 写
typedef struct WaveHeader
{
char riff_id[4]; //"RIFF"
int riff_datasize; // RIFF chunk data size,exclude riff_id[4] and riff_datasize,total - 8
char riff_type[4]; // "WAVE"
char fmt_id[4]; // "fmt "
int fmt_datasize; // fmt chunk data size,16 for pcm
short fmt_compression_code; // 1 for PCM
short fmt_channels; // 1(mono) or 2(stereo)
int fmt_sample_rate; // samples per second
int fmt_avg_bytes_per_sec; // sample_rate * channels * bit_per_sample / 8
short fmt_block_align; // number bytes per sample, bit_per_sample * channels / 8
short fmt_bit_per_sample; // bits of each sample(8,16,32).
char data_id[4]; // "data"
int data_datasize; // data chunk size,pcm_size - 44
}WaveHeader_t;
//快速写wav文件,单声道16khz
char header[]= {82,73,70,70, //"RIFF"
0x37,0x00,0x00,0x00,//FileSize-8
87,65,86,69,//"WAVE"
102,109,116,32,//"fmt "
16,0,0,0,//数据段16bit
1,0,//PCM格式
1,0,//单声道
0x80,0x3e,0x00,0x00,//采样率16kHz
0x00,0x7d,0x00,0x00,//音频码率=采样率*通道数*bit数/8
2,0,//采样一次占2个字节
16,0,//每一个通道16bit数据
100,97,116,97,//"data"
0x01,0x00,0x00,0x00//数据长度 6s
};
FILE *fp1,*fp2; // File pointers
int i;
printf("Exp. 1.2 --- file IO\n");
fp1 = fopen("1.wav", "rb"); // Open input file
fp2 = fopen("2.wav","wb");
if (fp1 == NULL) // Check if the input file exists
{
printf("Failed to open input file \n");
exit(0);
}
fseek(fp1, 44, 0);
fwrite(header,sizeof(header),1,fp2);
i=0;
while (fread(ch, sizeof(Uint8), SIZE, fp1) == SIZE) // Read in SIZE of input data bytes
{
fread(ch, sizeof(Uint8), SIZE, fp1);
fwrite(ch, sizeof(Uint8), SIZE, fp2); // Write SIZE of data bytes to output file
i += SIZE;
printf("%ld bytes processed\n", i); // Show the number of data is processed
}
waveHeader[40] = (Uint8)(i&0xff); // Update the size parameter into WAV header
waveHeader[41] = (Uint8)(i>>8)&0xff;
waveHeader[42] = (Uint8)(i>>16)&0xff;
waveHeader[43] = (Uint8)(i>>24)&0xff;
i = i +36;
waveHeader[4] = (Uint8)(i&0xff);
waveHeader[5] = (Uint8)(i>>8)&0xff;
waveHeader[6] = (Uint8)(i>>16)&0xff;
waveHeader[7] = (Uint8)(i>>24)&0xff;
rewind(fp2); // Adjust output file point to beginning
fwrite(waveHeader, sizeof(Uint8), 44, fp2); // Write 44 bytes of WAV header to output file
fclose(fp1); // Close input file
fclose(fp2); // Close output file
printf("\nExp --- completed\n");
//--------------------------- 简化写法
char header[] = { 82,73,70,70, //"RIFF"
0x37,0x00,0x00,0x00,//FileSize-8
87,65,86,69,//"WAVE"
102,109,116,32,//"fmt "
16,0,0,0,//数据段16bit
1,0,//PCM格式
1,0,//单声道
0x80,0x3e,0x00,0x00,//采样率16kHz
0x00,0x7d,0x00,0x00,//音频码率=采样率*通道数*bit数/8
2,0,//采样一次占2个字节
16,0,//每一个通道16bit数据
100,97,116,97,//"data"
0x01,0x00,0x00,0x00//数据长度 6s
};
//打开
FILE* fp = fopen(wavfile,"wb");
if (!fp) return;
//写头
fwrite(header, sizeof(header), 1, fp);
//写数据,len 是长度(字节数)
fwrite(data,sizeof(data),1,fp);........
//重新写入数据长度字节数,
int len = size;
fseek(fp, 40, SEEK_SET);
fwrite(&len, sizeof(int), 1, fp);
len = size + 36;
fseek(fp, 4, SEEK_SET);
fwrite(&len,sizeof(int),1,fp);
//关闭文件
fclose(fp);
/---------------------------------------------------------------------------/
简单读wav文件的代码,尤其对付 不是标准44字节头的wav
if( filename == NULL) return false;
FILE* fp_wave = fopen(filename,"rb");
if(fp_wave == NULL) return false;
fseek(fp_wave,22L,0);//移动到声道数位置
short temp1;
fread(&temp1,1,sizeof(short),fp_wave);
if(!(temp1 == REC_CHANNEL_NUM)) return false;
fseek(fp_wave,24L,0);//移动到采样率位置
long temp2;
fread(&temp2,1,sizeof(long),fp_wave);
if(temp2 != SAMPLE_RATE) return false;
rewind(fp_wave);
//专门死磕wave的头不是标准44个字节的情况
while(!feof(fp_wave))//seek到data后面的真实数据
{
short temp;
fread(&temp,1,sizeof(short),fp_wave);
if(temp==24932)//'data'的‘d’‘a’
{
fread(&temp,1,sizeof(short),fp_wave);// 把‘t’’a‘也读了
fread(&temp,1,sizeof(short),fp_wave);//把后面的data-len也读了
fread(&temp,1,sizeof(short),fp_wave);
break;
}
}
//它其实可以直接用下面的这句代替,当然必须是标准头
//fseek(fp_wave,44L,0);//标准44字节头
short TmpXChframe[FIFO_LEN*REC_CHANNEL_NUM];
int n_frame =0;
while(!feof(fp_wave))//读入真实的pcm数据
{
//每次读入 FIFO_LEN 个数据,1 帧 chanN 声道的数据
//读取指定长度的数据
fread(TmpXChframe,REC_CHANNEL_NUM * FIFO_LEN,sizeof(short),fp_wave);
//处理
n_frame++;
}
fclose(fp_wav);