You need to enable JavaScript to run this app. 如何用C语言生成频率可切换的立体声警笛WAV音频文件
优惠活动
大模型
产品
解决方案
定价
更多

如何用C语言生成频率可切换的立体声警笛WAV音频文件

实现方案说明

现有代码问题梳理

  1. 缺少<string.h>头文件引用,memcpy函数编译会报错
  2. 路径字符串中的反斜杠未转义,D:\test.wav会被识别为转义字符导致文件创建失败,需要改为D:\\test.wav
  3. 宏定义末尾多余分号,会引发编译异常
  4. 未实现0.65秒的频率切换逻辑,当前代码左声道固定输出960Hz、右声道固定输出770Hz,不符合需求
  5. 你疑惑的y[0]/y[1]对应逻辑是正确的:WAV立体声PCM数据就是按照左声道采样→右声道采样的顺序交错存储,y[0]对应左声道、y[1]对应右声道。

调整后的核心逻辑

  1. 计算0.65秒对应的采样数作为频率切换周期,每累计到对应采样数就切换当前使用的频率值
  2. 左右声道使用相同的频率生成正弦波,仅通过振幅系数控制声道渐变:左声道振幅随时间从0线性升到1,右声道振幅从1线性降到0,实现音效整体从右到左平移的效果

完整修正代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

#define WAVE_FORMAT_UNKNOWN 0X0000
#define WAVE_FORMAT_PCM 0X0001
#define WAVE_FORMAT_MS_ADPCM 0X0002
#define WAVE_FORMAT_IEEE_FLOAT 0X0003
#define WAVE_FORMAT_ALAW 0X0006
#define WAVE_FORMAT_MULAW 0X0007
#define WAVE_FORMAT_IMA_ADPCM 0X0011
#define WAVE_FORMAT_YAMAHA_ADPCM 0X0016
#define WAVE_FORMAT_GSM 0X0031
#define WAVE_FORMAT_ITU_ADPCM 0X0040
#define WAVE_FORMAT_MPEG 0X0050
#define WAVE_FORMAT_EXTENSIBLE 0XFFFE

#define DURATION 8 
#define SAMPLE_RATE 48000
#define CHANNEL 2
#define BIT_RATE 16
#define SWITCH_INTERVAL 0.65 // 频率切换间隔,单位秒

typedef struct {
    unsigned char ChunkID[4];
    unsigned int ChunkSize;
    unsigned char Format[4];
} RIFF;

typedef struct {
    unsigned char ChunkID[4];
    unsigned int ChunkSize;
    unsigned short AudioFormat;
    unsigned short NumChannels;
    unsigned int SampleRate;
    unsigned int AvgByteRate;
    unsigned short BlockAlign;
    unsigned short BitPerSample;
} FMT;

typedef struct {
    char ChunkID[4];
    unsigned int ChunkSize;
} DATA;

typedef struct {
    RIFF Riff;
    FMT Fmt;
    DATA Data;
} WAVE_HEADER;

int main() {
    FILE* f_out = fopen("D:\\test.wav", "wb");
    if (!f_out) {
        printf("文件创建失败");
        return -1;
    }

    WAVE_HEADER header;
    memcpy(header.Riff.ChunkID, "RIFF", 4);
    header.Riff.ChunkSize = DURATION * SAMPLE_RATE * CHANNEL * BIT_RATE / 8 + 36;
    memcpy(header.Riff.Format, "WAVE", 4);

    memcpy(header.Fmt.ChunkID, "fmt ", 4);
    header.Fmt.ChunkSize = 0x10;
    header.Fmt.AudioFormat = WAVE_FORMAT_PCM;
    header.Fmt.NumChannels = CHANNEL;
    header.Fmt.SampleRate = SAMPLE_RATE;
    header.Fmt.AvgByteRate = SAMPLE_RATE * CHANNEL * BIT_RATE / 8;
    header.Fmt.BlockAlign = CHANNEL * BIT_RATE / 8;
    header.Fmt.BitPerSample = BIT_RATE;

    memcpy(header.Data.ChunkID, "data", 4);
    header.Data.ChunkSize = DURATION * SAMPLE_RATE * CHANNEL * BIT_RATE / 8;

    fwrite(&header, sizeof(header), 1, f_out);

    short y[2]; 
    double high_freq = 960;
    double low_freq = 770;
    double current_freq = high_freq;
    int switch_sample_cnt = SWITCH_INTERVAL * SAMPLE_RATE;
    int last_switch_pos = 0;
    const double PI = 3.1415926535;

    for (int i = 0; i < SAMPLE_RATE * DURATION; i++) {
        // 频率切换逻辑
        if (i - last_switch_pos >= switch_sample_cnt) {
            current_freq = current_freq == high_freq ? low_freq : high_freq;
            last_switch_pos = i;
        }
        // 声道渐变系数
        double level_l = (double)i / (SAMPLE_RATE * DURATION);
        double level_r = 1.0 - level_l;
        // 生成采样值,左右声道使用相同频率,振幅跟随渐变系数
        double sin_val = sin(2 * PI * i * current_freq / SAMPLE_RATE);
        y[0] = (short)(30000 * sin_val * level_l);
        y[1] = (short)(30000 * sin_val * level_r);

        fwrite(&y[0], sizeof(short), 1, f_out);
        fwrite(&y[1], sizeof(short), 1, f_out);
    }

    fclose(f_out);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 16:15:11