修正C语言正弦波生成代码:解决频率减半时长翻倍问题
问题分析与解决方案
你的代码出现频率减半、时长翻倍的问题,核心原因是样本格式不匹配,还有一处循环条件的小问题,具体修正如下:
问题根源
- 样本字节数不匹配:
你在代码中使用int类型(通常为4字节)存储样本并写入文件,但播放时用aplay -f S16_LE指定的是16位有符号小端整数(仅2字节)。这导致播放器把每个4字节的int拆成两个独立的16位样本,相当于样本总数翻倍,因此频率变为原来的1/2(220Hz),时长变为原来的2倍(20秒)。 - 循环条件冗余:
while (i <= sample_rate * duration)会多生成1个样本,虽然对时长影响极小,但不符合预期的10秒样本数。
修改后的代码
#include <stdio.h> #include <math.h> #include <stdint.h> // 用于int16_t类型 double sine(double amp, double freq, double time); int main(int argc, char *argv[]) { int sample_rate = 48000; double freq = 440; double amp = 1; double duration = 10; double time = 0; double val = 0; int16_t temp = 0; // 使用明确的16位有符号整数,匹配S16_LE格式 int i = 0; FILE *fp = fopen("sine.bin", "wb"); if (fp == NULL) { return -1; } // 修正循环条件,生成恰好sample_rate*duration个样本 while (i < sample_rate * duration) { val = 32767.0 * sine(amp, freq, time); temp = (int16_t) val; // 转换为16位有符号整数 // 写入2字节的样本,匹配S16_LE格式 fwrite((const void*) &temp, sizeof(int16_t), 1, fp); i++; time = i / (1.0 * sample_rate); // 调整顺序,先递增i再计算时间,逻辑更直观 } fclose(fp); // 别忘了关闭文件,避免资源泄漏 } double sine(double amp, double freq, double time) { return amp * sin(2.0 * M_PI * freq * time); }
关键修改点
- 使用
int16_t类型(来自<stdint.h>)替代int,确保样本是16位有符号整数,完全匹配S16_LE格式。 - 调整
fwrite的第二个参数为sizeof(int16_t),保证每个样本只写入2字节。 - 修正循环条件为
i < sample_rate * duration,生成精确的10秒样本(48000*10=480000个样本)。 - 添加
fclose(fp),避免文件资源泄漏。
编译与播放
保持原命令不变即可:
gcc sound.c -Wall -Wextra -lm -o sound && ./sound aplay -r 48000 -f S16_LE sine.bin
内容的提问来源于stack exchange,提问作者Ishaan Vatus
相关产品推荐
相关产品推荐

