通过 SourceDataLine 播放音频时发出一致的爆音

Consistent popping sound while playing audio through a SourceDataLine

我目前正在编写一个基本的合成器,运行遇到了一个奇怪的问题。通过 SourceDataLine 播放代表 16 位单声道音频的字节数组时,我听到持续不断的爆裂声。

流行音乐以恒定的速度播放,据我所知,音高。尽管流行音乐的频率确实略有不同(同样,据我所知),一些音符具有低通听起来流行音乐,而其他音符听起来高通。虽然流行音乐并没有压倒一切,但您仍然可以在背景中听到想要的声音。

除了采样率之外,没有任何东西会改变爆破音的速率,音符音高,SourceDataLine 缓冲区大小,我一次写入的字节数。

降低采样率会降低 pops 的速率,反之亦然。

为了测试我这边的程序,我用了大约半秒的时间打印出正在写入 SourceDataLine 的数据,并查看了播放的正弦波的大约 15 个周期,结果完全没问题;没有突然的跳跃、剪辑或其他任何东西。

我唯一使用采样率值的两件事是一些基本数学来帮助我的采样器以正确的频率采样,每个音符只计算一次,并且绝对可以作为完美的音高,并用于创建 SourceDataLine。

这是我启动 SourceDataLine 的方式(取自主要方法的多个部分):

AudioFormat format = new AudioFormat(AudioEnvironment.SAMPLE_RATE, AudioEnvironment.BIT_DEPTH, 1, true, true);

SourceDataLine line = AudioSystem.getSourceDataLine(format);
line.open(format, 8000);
line.start();

我的数据是正确的 big-endian,我在构造函数中更改了 endian 标志并让我的耳朵被白噪声炸毁。

程序设置好后,在这个无限循环中不断向SourceDataLine写入数据:

while (true) {              
    for (Channel channel : channelSystem.getChannels()) {
        if (channel.pitch != 0) {
            wave.sample(channel, buffer);

            line.write(buffer, 0, AudioEnvironment.SUB_BUFFER_SIZE * 2);
        }
    }
}

(A Channel 是我创建的 class,它包含单个音符的所有数据(虽然显然程序目前没有正确设置复音),buffer 是字节数组,wave.sample() 是我将数据采样到 buffer 的位置,AudioEnvironment.SUB_BUFFER_SIZE * 2buffer)

的大小

我不一定需要一个示例来说明如何在代码中解决此问题,但解释为什么会发生这种情况会很好。

编辑:我还应该补充的是,我已经尝试在无限写循环中放置一个打印语句来打印出 SourceDataLine 中的可用字节数,它偶尔会一直保持在 500 - 2000 左右上升到 5000 左右,但永远不会接近 8000,因此缓冲区永远不会 运行没有数据。

事实证明,问题与我的想法完全无关。

事实证明,我在采样器中写的一个方程明显是错误的。

播放完 2048 个样本后,我会有点循环回到波形的开头,导致爆音。

老实说,我不知道为什么要这样写,但是嘿,现在可以用了。