用C语言对.wav文件做低通滤波并保存输出的问题求助
问题解答
现有代码先修正几个明显错误
- 你已经通过
fread(&wav, 1, sizeof(wav), fp);读取了全部44字节的WAV头,此时文件指针已经偏移到音频数据起始位置,不需要再从缓冲区复制前44字节头,直接把已读取的wav结构体写入输出文件即可。 - 你定义的
buffIn是int类型数组,单个元素占4字节,循环条件用sizeof(buffIn)会遍历4*1024=4096次,直接超出数组边界,会触发内存访问错误。 - 你使用的单字节滤波逻辑不符合WAV采样存储规则:WAV的音频采样是按位宽打包的,比如常见的16位PCM是2字节存一个采样值,按单字节叠加会直接破坏采样结构,导致输出音频无法正常播放。
- 代码里
printf("0x%02x",buffOut[x]);的变量x未定义,属于语法错误。
正确写入输出文件的实现步骤
第一步:先写入WAV头
直接把你已经读取解析好的WAV头写入输出文件,不需要额外复制缓冲区内容:
// 写入WAV头到输出文件 fwrite(&wav, sizeof(Wav), 1, outfile);
第二步:按采样位宽处理音频数据并写入
这里以最常见的16位PCM格式为例,修正缓冲区和滤波逻辑,处理后直接写入输出文件:
// 按16位采样定义缓冲区,每次处理1024个采样 int16_t buffIn[1024]; int16_t buffOut[1024]; size_t readCnt; // 循环读取直到文件读完 while((readCnt = fread(buffIn, sizeof(int16_t), 1024, fp)) > 0) { // 一阶低通滤波 y[n] = α*x[n] + (1-α)*y[n-1] 比相邻叠加效果更好,也不会溢出 // 这里α取0.5,等效于相邻采样平滑,和你预期的最简低通效果一致 static int16_t prevOut = 0; for(int i=0; i<readCnt; i++) { buffOut[i] = 0.5 * buffIn[i] + 0.5 * prevOut; prevOut = buffOut[i]; } // 把处理完的缓冲区数据写入输出文件 fwrite(buffOut, sizeof(int16_t), readCnt, outfile); }
第三步:关闭文件释放资源
所有读写完成后一定要关闭文件,避免数据没刷入磁盘:
fclose(fp); fclose(outfile);
额外注意事项
- 如果你的WAV是立体声,采样是按左、右声道交替存储的,上述滤波逻辑会自动对两个声道都生效,不需要额外调整。
- 如果需要实现高通滤波,把滤波公式换成
y[n] = 0.5*(y[n-1] + x[n] - x[n-1])即可。 - 如果你一定要保留你原来的相邻采样叠加逻辑,记得叠加后除以2,避免采样值溢出16位的取值范围,导致爆音。
内容的提问来源于stack exchange,提问作者Robert Gutu
相关产品推荐
相关产品推荐

