我现在正在写一个基本的合成器,遇到了一个奇怪的问题。通过SourceDataLine播放代表16位单声道音频的字节数组时,我会得到恒定的弹出声音。
流行音乐以固定的速率播放,据我所知,音调是。流行音乐的频率确实略有不同(再次,据我所听到的),某些音符具有低通听起来的流行音乐,而其他音符则具有高通的声音。流行音乐没有被覆盖,您仍然可以在后台听到所需的声音。
除了采样率外,没有改变弹出声的速率,没有提示音高,没有SourceDataLine缓冲区的大小,没有一次写入的字节数。
降低采样率会降低爆裂声的发生率,反之亦然。
为了测试程序,我将写入SourceDataLine的数据打印了大约半秒钟,并查看了播放的正弦波的大约15个周期,这完全没问题;没有突然跳动,削波或其他任何情况。
我使用采样率值的唯一两件事是一些基本数学运算,以帮助我的采样器以正确的频率采样,该频率仅针对每个音符计算一次,并且在音高完美的情况下绝对可以工作,并且SourceDataLine。
这是我启动SourceDataLine的方式(取自main方法的多个部分):
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);
}
}
}
(Channel
是我创建的一个类,其中包含单个音符的所有数据(尽管目前显然该程序未针对复音进行正确设置),buffer
是字节数组,wave.sample()
是我将数据采样到buffer
的位置,AudioEnvironment.SUB_BUFFER_SIZE * 2
是buffer
的大小)
我并不一定需要如何在代码中解决此问题的示例,但对为什么会发生这种情况的解释会很好。
编辑:我还可能要补充的一点是,我已经尝试将打印语句放入无限写入循环中,以打印出SourceDataLine中的可用字节数,并且该值始终保持在500-2000左右,偶尔会上升到大约5000,但永远不会接近8000,因此缓冲区永远不会耗尽数据。
事实证明,这个问题与我认为的完全无关。
结果是,我在采样器中编写的一个方程式显然是错误的。
播放了2048个样本后,我会有点循环回到波形的开头,从而导致弹出。
老实说,我不知道为什么要用它写,但是嘿,现在可以用了。