C语言降低WAV文件信号幅度后输出文件无法正常播放问题求助
问题原因及解决方案
核心原因
- 结构体字节对齐错误:C 语言编译器默认会对结构体成员做内存对齐优化,在成员之间插入无意义的填充字节,你定义的
header_file结构体实际占用的内存大小远大于标准WAV头的44字节,直接fread/fwrite整个结构体时,读取到的头字段全部错位,写入输出文件的WAV头本身就是非法的,播放器自然无法识别。 - WAV子块兼容性问题:不是所有WAV文件的子块顺序都严格匹配你定义的结构体顺序,很多WAV会在fmt块和data块之间插入LIST、INFO等额外元数据块,硬读固定大小的结构体会直接把这些额外块的内容错当成头字段或者采样数据,进一步破坏头结构。
- 读写逻辑错误:
feof的使用逻辑错误:feof只会在读操作命中文件末尾后才会置位,你当前的循环逻辑会在文件读完后多执行一次读写,写入无效数据。- 每次循环不管实际读到多少采样,都强制写入
BUFFSIZE个采样,最后一次读操作没读满缓冲区时,会把缓冲区里的垃圾值也写入输出文件,导致输出文件的采样数据长度和WAV头里记录的subchunk2_size、chunk_size不匹配。
修复方案
- 取消结构体的字节填充,保证结构体大小和标准WAV头一致:
如果你用GCC/Clang编译器,结构体定义改成:
MSVC编译器则在结构体定义前加struct __attribute__((packed)) header_file { char chunk_id[4]; int chunk_size; char format[4]; char subchunk1_id[4]; int subchunk1_size; short int audio_format; short int num_channels; int sample_rate; int byte_rate; short int block_align; short int bits_per_sample; char subchunk2_id[4]; int subchunk2_size; };#pragma pack(1),定义后加#pragma pack()。 - 增加头字段校验逻辑,读取头后先判断
chunk_id是否为RIFF、format是否为WAVE、subchunk1_id是否为fmt,如果不符合,说明有额外子块,需要遍历跳过所有非data的子块直到找到data块再开始读采样。 - 重构读写循环,根据
fread的返回值判断实际读到的采样数,仅处理、写入实际有效数据,示例逻辑:size_t read_cnt; while ((read_cnt = fread(inputBuffer, sizeof(short int), BUFFSIZE, inputfile)) > 0) { for (int z = 0; z < read_cnt; z++) { outputBuffer[z] = 0.5 * inputBuffer[z]; } fwrite(outputBuffer, sizeof(short int), read_cnt, outputfile); count++; } - 如果你的处理逻辑改变了采样数据长度,需要手动更新头里的两个长度字段:
// 总采样字节数 = 采样个数 * 每个采样的字节数 header.subchunk2_size = 实际采样总个数 * sizeof(short int); header.chunk_size = 36 + header.subchunk2_size; // 要在fwrite头之前更新这两个字段
内容的提问来源于stack exchange,提问作者Razvan Secarea
相关产品推荐
相关产品推荐

