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 哔声:产生某些特定频率的声音的主要内容,如果未能解决你的问题,请参考以下文章

如何产生特定的声音频率?

如何产生具有特定频率的声音(并且能够改变频率)

如何在 Java 中播放除哔哔声以外的声音?

在 C、MacOS 中播放哔声

如何使用 SDL 制作哔声功能?

C++ 特定的声音输出? [关闭]