You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何用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;
}

关键修正点说明

  1. 文件打开逻辑:改用w+模式,直接创建或覆盖文件,避免对NULL指针执行非法操作。
  2. DATA块处理:拆分数据块的头信息与实际音频数据,先写入DATA块的ID和大小,再单独写入音频数组内容。
  3. 结构体对齐:通过#pragma pack指令强制取消结构体字节对齐,保证WAV头的字节数严格符合标准格式。
  4. 角度精度优化:添加角度范围限制,防止长时间累加导致的浮点数精度损失。
  5. 类型转换:明确将正弦计算结果转换为short类型,避免隐式转换可能引发的问题。

内容的提问来源于stack exchange,提问作者mantaflow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 18:09:17