为何用C语言生成的WAV格式正弦音存在杂音?
解决WAV文件生成正弦波杂音的问题
问题根源分析
你的代码存在几个关键错误,直接导致WAV文件格式损坏,进而出现杂音:
- 错误的文件打开逻辑:当
fopen("r+")失败时,对NULL指针调用fclose会触发崩溃,后续文件操作完全失效。 - DATA块写入错误:
DATA_t中的data是指针,直接写入结构体只会把指针地址写入文件,而非实际音频数据。 - 未定义变量的非法操作:
fclose(test)中的test未定义,会导致编译失败或运行时崩溃。 - 结构体字节对齐问题:默认编译对齐会让WAV头的字节数不符合规范,播放器无法正确解析。
修正后的完整代码
#include <stdio.h> #include <math.h> #include <stdint.h> // 取消结构体字节对齐,确保WAV头格式严格符合规范 #pragma pack(push, 1) // RIFF Header typedef struct HEADER_s{ char chunkID[4]; uint32_t chunkSize; char format[4]; }HEADER_t; // FMT (Format) Subchunk typedef struct FMT_s{ char subChunk1ID[4]; uint32_t subChunk1Size; uint16_t format; uint16_t channel; uint32_t smplRate; uint32_t byteRate; uint16_t blockAlign; uint16_t bitsPerSample; }FMT_t; // Data Subchunk(仅存储头信息,不包含数据指针) typedef struct DATA_s{ char subChunk2ID[4]; uint32_t subChunk2Size; }DATA_t; #pragma pack(pop) // 常量定义 #define M_PI 3.14159265358979323846 const float freq = 440.f; #define SUBCHUNK1_size 16 #define DURATION 2 #define SAMPLE_RATE 44100 #define CHANNELS 1 #define bytes_per_sample 2 #define SUBCHUNK2_size DURATION*SAMPLE_RATE*CHANNELS*bytes_per_sample #define BYTE_RATE SAMPLE_RATE*CHANNELS*bytes_per_sample #define BLOCK_ALIGN CHANNELS*bytes_per_sample const int chunkSize=4+(8+SUBCHUNK1_size)+(8+SUBCHUNK2_size); int main() { FILE *fptr; char path[] ="sin400.wav"; // 直接用w+模式创建/覆盖文件,简化错误处理 fptr = fopen(path, "w+"); if (fptr == NULL) { printf("无法创建文件 %s\n", path); return 1; } HEADER_t header = {"RIFF", chunkSize, "WAVE"}; FMT_t format = {"fmt ", SUBCHUNK1_size, 1, CHANNELS, SAMPLE_RATE, BYTE_RATE, BLOCK_ALIGN, 8 * bytes_per_sample}; DATA_t data = {"data", SUBCHUNK2_size}; // 依次写入WAV头部信息 fwrite(&header, sizeof(header), 1, fptr); fwrite(&format, sizeof(format), 1, fptr); fwrite(&data, sizeof(data), 1, fptr); // 生成正弦波数据 float amp = 0.5 * 32767; int bufSize = SAMPLE_RATE * DURATION; float T = (2.0 * M_PI) * freq / SAMPLE_RATE; float angle = 0; short buf[SAMPLE_RATE * DURATION]; for (int i = 0; i < bufSize; i++) { buf[i] = (short)(amp * sin(angle)); angle += T; // 可选:限制角度范围,避免浮点数累加精度漂移 if (angle > 2*M_PI) { angle -= 2*M_PI; } } // 写入实际音频数据 fwrite(buf, sizeof(short), bufSize, fptr); fclose(fptr); return 0; }
关键修正点说明
- 文件打开逻辑:改用
w+模式,直接创建或覆盖文件,避免对NULL指针执行非法操作。 - DATA块处理:拆分数据块的头信息与实际音频数据,先写入DATA块的ID和大小,再单独写入音频数组内容。
- 结构体对齐:通过
#pragma pack指令强制取消结构体字节对齐,保证WAV头的字节数严格符合标准格式。 - 角度精度优化:添加角度范围限制,防止长时间累加导致的浮点数精度损失。
- 类型转换:明确将正弦计算结果转换为
short类型,避免隐式转换可能引发的问题。
内容的提问来源于stack exchange,提问作者mantaflow
相关产品推荐
相关产品推荐

