Java 哔声:产生某些特定频率的声音
Posted
技术标签:
【中文标题】Java 哔声:产生某些特定频率的声音【英文标题】:Java beep sound: Produce sound of some specific frequencies 【发布时间】:2016-01-05 11:54:47 【问题描述】:我正在尝试使用 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);
从科学上讲,这是不可能的。
在第一种情况下,声音应该是次声波,我应该无法感知。 在第二种情况下,我应该还是听不到声音,因为随着年龄的增长,听力会下降,我这个年龄的人应该只能听到大约16000 赫兹。此外,我听不见:
Sound.tone(0,1000);
(有点符合预期)
Sound.tone(20000,1000);
那么,我怎样才能产生某些特定频率的声音? 我在互联网上搜索,但找不到任何相关信息。
在此编辑之前给出的答案解释了它发生的原因,但没有给出我想要的答案。
【问题讨论】:
但我当然听不到次声,根据这个程序我显然可以。 @SureshAtta 我建议用耳朵代替眼睛。 @Arc676 我猜你误解了我的问题。如果计算机不是为产生次声/超声波而制造的,那么我怎么能用这个程序听到它。我的意思是说如果我写Sound.tone(10,1000);
,我可以听到声音,这应该是次声波。
您的硬件可能无法产生如此低或高的频率并且不会引发任何异常,而是尝试尽可能接近您传递给硬件的值.这些值可能是人类可以听到的。
如何使用麦克风并对录制的声音进行频率分析。如果您手头有智能手机,那么您最喜欢的应用商店中应该有一个可用的应用。
【参考方案1】:
您遇到的是一种称为混叠的现象。您可能已经在视频中目睹了这样的例子,其中纺车似乎旋转缓慢甚至反向旋转。这是因为***的旋转仅比每个视频帧的完整转数的倍数多一点或少一点。同样,如果***每帧旋转准确的圈数,它将看起来是静止的。这被称为混叠的原因是无法知道它实际旋转了多少圈。
音频采样具有相同的伪影,被称为奈奎斯特采样定理,它基本上表明您只能表示高达采样率一半的频率(奈奎斯特频率)。超出这个频率,音调开始向下折叠(例如向后转)。
在 8kHz 采样率下,0Hz 到 4kHz 的频率可以正常播放(4 kHz 正弦波每个周期有 2 个采样)。超过 4kHz 频率将开始折返,这样 4001Hz 被听到为 3999,5000Hz 被听到为 3000Hz,最终 8000Hz 被听到为 0Hz(因此静音)。超过 8kHz 时,它将再次开始折叠,因此 8001Hz 为 1Hz,依此类推。
关键是您需要选择一个至少是您计划播放的最高频率两倍的采样率。
【讨论】:
如果我再留在这个帖子里,我可能会成为一名音响工程师! 但是将采样率设为 40000 仍然不能解决问题。我仍然可以听到低于 20 赫兹和最高 19999 赫兹的声音。 您的正弦生成有点可疑,因为 8 位音频通常是无符号的 (0-255)。您应该听一个 1kHz 的音调并与youtube.com/watch?v=3yQcXlvccCI 进行比较。如果您的听起来不一样,那么您需要将此位(byte)(Math.sin(angle) * 127.0 * vol);
更改为 (byte)((Math.sin(angle) * 127.0 + 127) * vol);
@jaket 将其更改为 (byte)((Math.sin(angle) * 127.0 + 127) * vol);
不起作用。【参考方案2】:
刚刚在我的扬声器前用吉他调音器重新检查过 - 您提供的方法对于低频是准确的。
但是,如果您的音量太低,您可能会听到泛音或“断断续续”的声音,因为扬声器在次声波中的工作不太好(至少我明白了)
在 高 频率上,您的代码计算得不太好 - 每秒 8000 个样本的采样率,您将很快为较高频率创建“无效”音调 - 正弦波振荡只会不小心与您的采样率对齐。所以你会得到一些你可以听到的高频(基本上是因为你的样本总是达到一些非零值)或听不到(你的所有样本都发生在波通过空值的时候。
检查此循环(打开扬声器):
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);
发出非常时髦的声音。
【讨论】:
这取决于你想用它做什么。对于提醒用户,20-3000 Hz 的范围可能就足够了。对于更高的采样率,虽然角度计算似乎也无效。将不得不多考虑一下这个低谷。 Jan,如何从罪恶波中获得泛音?我在计算中看不到任何会导致播放开始/停止(断断续续)的内容。即使使用整数除法,角度的进展看起来也会很平滑。以上是关于Java 哔声:产生某些特定频率的声音的主要内容,如果未能解决你的问题,请参考以下文章