生成WAV文件音

时间:2014-10-21 15:38:37

标签: c# audio wav sin

我正在尝试以编程方式构建一个音频WAV文件,其中包含您拨打电话号码时听到的标准英国铃声的 n 秒。

我有found a source来记录音调的频率和持续时间,它是两个频率的正弦波:400Hz和450Hz。

我编写的代码以正确的格式生成PCM WAV文件,我可以使用Windows Media Player等音频播放器播放,但是它生成的音调听起来比它应该的频率要低得多,所以不要以为我的论坛很合适。

目前我正在做的事情:

var duration = 10;
var bitsPerSample = 8;
var samplesPerSec = 8000;
var f1 = 400;
var f2 = 450;
var pattern = new[] {
            TimeSpan.FromMilliseconds(400),
            TimeSpan.FromMilliseconds(200),
            TimeSpan.FromMilliseconds(400),
            TimeSpan.FromMilliseconds(2000)
        };

var wavdata = new byte[duration * samplesPerSec]; // 10 seconds of wav data @ 8000 samples per sec, 8 bits per sample, 1 channel 

// Loop through each sample
for (var i = 0; i < wavdata.Length; i = i + (bitsPerSample / 8)) {

    // Get time in seconds of the current sample
    var time = Convert.ToDouble(i) / (Convert.ToDouble(bitsPerSample) / 8) / samplesPerSec;

    // Calculate the on off pattern
    var onoff = 0;
    var timeMilliseconds = time * 1000;
    var p = 0;
    while (timeMilliseconds >= 0) {
        timeMilliseconds = timeMilliseconds - pattern[p].TotalMilliseconds;
        onoff = onoff == 1 ? 0 : 1;
        if (++p >= pattern.Length) p = 0;
    }

    // Calculate the sample: (sin(time * 400) * 128 + sin(time * 450) * 128)) / 2
    var sample = onoff * (((Math.Sin(time * f1) * 128) + (Math.Sin(time * f2) * 128)) / 2);

    // Store sample
    wavdata[i] = Convert.ToByte(sample + 128);

}

正如您所看到的,我正在使用的公式是:

sin(time-of-sample * frequency) * amplitude

我对两个组合频率使用了两次:

sin(time * 400) * 128
sin(time * 450) * 128

然后我将它们加在一起并除以2得到平均值。然后我乘以1或0以使音调之间保持静音以获得铃声。最后,当我将值存储在数据数组中时,我将样本偏移128,因为WAV文件数据表示为正数或负数。

我做错了什么?为什么音调产生的音调低于预期?

1 个答案:

答案 0 :(得分:4)

你忘了皮了。正弦周期从0 ...2π开始,而不是0..1:

var sample = onoff * (((Math.Sin(2 * Math.Pi * time * f1) * 127) + (Math.Sin(2 * Math.Pi * time * f2) * 127)) / 2);

另外,请注意我将128s更改为127s,因为如果Sin太接近1或-1,则浮点到字节的转换将会溢出。可能有一种更好的方法可以做到这一点,不会牺牲范围,但它可能与你正在做的事情无关。

如果我可以评论:代码执行的单位转换次数过多。在几秒和几毫秒内都有时间令人困惑。并且“sample”的范围应为-1到1,然后将转换为byte作为单独的步骤。通过在该行内乘以128,它将字节的概念与音频计算混合在一起,这有点令人困惑。