我正在尝试使用Java生成蜂鸣声。我在SO上找到了this回答。
我正在使用该答案的代码来产生哔哔声。代码是:
import javax.sound.sampled.*;
public class Sound
{
public static float SAMPLE_RATE = 8000f;
public static void tone(int hz, int msecs)
throws LineUnavailableException
{
tone(hz, msecs, 1.0);
}
public static void tone(int hz, int msecs, double vol)
throws LineUnavailableException
{
byte[] buf = new byte[1];
AudioFormat af = new AudioFormat(SAMPLE_RATE,8,1,true,false);
SourceDataLine sdl = AudioSystem.getSourceDataLine(af);
sdl.open(af);
sdl.start();
for (int i=0; i < msecs*8; i++) {
double angle = i / (SAMPLE_RATE / hz) * 2.0 * Math.PI;
buf[0] = (byte)(Math.sin(angle) * 127.0 * vol);
sdl.write(buf,0,1);
}
sdl.drain();
sdl.stop();
sdl.close();
}
public static void main(String[] args) throws Exception {
Sound.tone(15000,1000);
}
}
在main
方法中,我使用Sound.tone(15000,1000);
产生频率 15000 Hz 的声音来播放 1000 ms
但是,如果我将其更改为:
,我可以听到声音Sound.tone(1,1000);
,。Sound.tone(19999,1000);
科学地说,这是不可能的。
此外,我听不到:
Sound.tone(0,1000);
(有点像预期的那样)Sound.tone(20000,1000);
那么,如何制作某些特定频率的声音?
我在网上搜索过,但找不到任何关于它的信息。
在此编辑之前给出的答案解释了为什么会发生,但不提供我想要的答案。
答案 0 :(得分:8)
您遇到的是一种称为锯齿现象。您可能已经在视频中看到了这样的示例,其中旋转轮似乎缓慢旋转或甚至反向旋转。这是因为车轮仅旋转了略多于或小于每个视频帧完整匝数的倍数。同样,如果车轮每帧旋转一个精确的圈数,它将显得静止不动。这称为混叠的原因是没有办法知道如何它实际旋转了多少次。
音频采样具有相同的伪像,被称为奈奎斯特采样定理,它基本上表明您只能表示高达采样率(奈奎斯特频率)一半的频率。超出此频率,音调开始向下折叠(例如向后转)。
在8kHz采样率下,0Hz至4kHz的频率将恢复正常(4 kHz正弦波每个周期将有2个样本)。超过4kHz时,频率将开始向后折叠,以便听到4001Hz为3999,5000Hz为3000Hz,最终为8000Hz为0Hz(因此为静音)。超过8kHz时,它将再次开始折叠,以便8001Hz为1Hz,依此类推。
需要注意的是,您需要选择的采样率至少是您计划播放的最高频率的两倍。
答案 1 :(得分:3)
只需在我的扬声器前面使用吉他调音器重新检查 - 您提供的方法对于低频率是准确的。
然而,如果你太低,你可能听到泛音或“口吃”的声音,因为扬声器在次声中不能工作得太厉害(至少我知道了)
在高频率上,您的代码计算得不太好 - 采样率为每秒8000个样本,您将为更高频率快速创建“无效”音调 - 正弦波振荡将只是意外地与您的采样率保持一致。因此,您可以听到一些高频率(主要是因为您的样本总是达到非零值)或听不到(所有样本都出现在wave通过null时。
检查此循环(开启扬声器):
public static void main(String[] args) throws Exception {
for(int freq = 400; freq < 20000; freq *= 2) {
Sound.tone(freq,500);
}
}
由于上述原因,你最后会听到低 - 高 - 低 - 高。
另一项测试:
Sound.tone(8000,500);
绝对安静,
Sound.tone(8001,500);
产生非常时髦的声音。