如何用C语言生成频率可切换的立体声警笛WAV音频文件
实现方案说明
现有代码问题梳理
- 缺少
<string.h>头文件引用,memcpy函数编译会报错 - 路径字符串中的反斜杠未转义,
D:\test.wav会被识别为转义字符导致文件创建失败,需要改为D:\\test.wav - 宏定义末尾多余分号,会引发编译异常
- 未实现0.65秒的频率切换逻辑,当前代码左声道固定输出960Hz、右声道固定输出770Hz,不符合需求
- 你疑惑的
y[0]/y[1]对应逻辑是正确的:WAV立体声PCM数据就是按照左声道采样→右声道采样的顺序交错存储,y[0]对应左声道、y[1]对应右声道。
调整后的核心逻辑
- 计算0.65秒对应的采样数作为频率切换周期,每累计到对应采样数就切换当前使用的频率值
- 左右声道使用相同的频率生成正弦波,仅通过振幅系数控制声道渐变:左声道振幅随时间从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
相关产品推荐
相关产品推荐

