【问题标题】:Reliable sound API in Java for simple digital samples playbackJava中可靠的声音API,用于简单的数字样本播放
【发布时间】:2012-12-10 01:57:01
【问题描述】:

有没有一个好的方法可以在 Java 中获得体面、可靠的数字采样声音播放?

我的请求列表很短:

  • 从 .wav 文件之类的文件加载内存中的数字化样本(例如,从 jar 中捆绑的资源)
  • 以非阻塞方式播放它们
  • 当我同时播放多个样本并且它们在时间上相交时,它们应该得到适当的混合

如果有以下内容会很好,但事实上我可以没有它:

  • 从 .ogg 或类似的压缩格式播放(显然没有在 Java 中实现占用大量 CPU 的解码器)
  • 在播放同一样本时再次播放它不应停止给定样本的先前播放,但应开始第二个副本并与第一个正确混合

我尝试了臭名昭著的Java Sound API,但发现它完全不可靠,似乎无法满足我最小的愿望清单。我遇到的问题:

  • 在带有 ALSA dmix (OpenJDK 6) 的 Linux 上,让任何其他应用程序在初始化 Java Sound API 时使用音频只会使 Java 应用程序中的所有声音消失,而不会出现任何错误/警告。

  • 在 Linux (OpenJDK 6) 上,列出 MixerInfos 并尝试使用其中任何一个获取 Clip 对象会在尝试加载 wav 文件时引发以下异常:

    java.lang.IllegalArgumentException: Line unsupported: interface Clip supporting format PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian
    

    因此,AudioSystem.getClip(anySortOfMixer) 似乎根本不起作用。只有AudioSystem.getClip() 有效。

  • 使用Clip 加载具有不同采样率/位/格式的文件失败并显示LineUnavailableException。似乎第一次调用clip.open 将声音系统设置为特定的声音选项,然后调用以加载采样率略有不同的文件(例如,第一个是 44100,第二个是 48000)

    李>
  • 在 Linux (OpenJDK 6) 上初始化几个不同的 Clips 并尝试播放它们只会使最后加载的 Clip 可听 - 没有给出错误/警告,但仅在最后加载的 Clip 上使用 play任何声音都没有 - 所有其他人都是沉默的:

    Clip loadSound(String name) {
        URL url = this.getClass().getResource("/" + name + ".wav");
        Clip clip = AudioSystem.getClip();
        AudioInputStream ais = AudioSystem.getAudioInputStream(url);
        clip.open(ais);
        return clip;
    }
    
    void playSound(Clip) {
        if (clip.isRunning())
            clip.stop();
        clip.setFramePosition(0);
        clip.start();
    }
    ...
    Clip c1 = loadSound("foo");
    Clip c2 = loadSound("bar");
    ...
    playSound(c1); // silence
    ...
    playSound(c2); // audible
    

    使用此代码在 Windows 上一切正常 - 所有剪辑都可以正常播放、播放和混音。没有在 Mac 上测试过。

  • 支持的文件格式(使用AudioSystem.getAudioFileTypes 分析)在 Linux/OpenJDK6 和 Windows/Oracle JDK 7 上都返回 wav / au / aif,因此没有 ogg 甚至 mp3 :(

  • 如果不将第二个副本加载为不同的 Clip,似乎没有简单的方法可以同时制作相同 Clip 声音的两个副本。

所以,问题是 - 是否有一个好的解决方案/解决方法来补救所有这些问题并使其更可靠?切换到其他声音系统(例如LWJGL OpenALpaulscode.com sound system)会有帮助吗?或者是否可以将 Java Sound API 包装在一些安全防护中并且它会正常工作?

我已经制作了一个小应用程序来测试以上所有内容,但它有点长,所以我想将它发布为gist,但不幸的是,GitHub 现在遇到了一些网络问题。所以,我想,我会稍后发布它。

【问题讨论】:

  • “简单的数字样本” “.ogg 或类似的压缩格式” 压缩的声音格式并不简单。 -- 也许JavaFX 提供了合适的控件或API。好问题顺便说一句。 +1
  • 这取决于 simple 的定义 ;) 一般来说,如果我理解正确,即使在 Java Sound API 中,也可以为 mp3 或ogg,但我什至没有探索过这个机会,因为这对我的案子来说太麻烦了。我肯定会对只使用 wavs 感到满意。
  • “我肯定只对 wav 感到满意。”(耸耸肩)如果你能找到一个听起来可靠的 API,我怀疑它会支持压缩格式。我之前添加了 JMF 的 mp3plugin.jar 以在 Java 声音应用程序中支持 MP3。我建议使用 JavaFX,希望它使用一些完全替代的 API 来替代 Java Sound(正如您所注意到的,它并不完全可靠)。但是说到 Linux 和声音,Linux 缺乏声音支持是导致Jamie Zawinski 为 Mac 折腾 Linux(为此他写了很多代码)的原因。 ;)
  • 我个人喜欢通过 LWJGL 使用 OpenAL
  • 您可以尝试使用 gstreamer for Java。我过去使用过它,理解如何设置音频管道需要一些努力,但是一旦你让它运行它应该能够处理你扔给它的几乎任何东西。 code.google.com/p/gstreamer-java

标签: java lwjgl javasound openal alsa


【解决方案1】:

我在 Java-gaming.org 上发布了一个相当简单、有限的混音器,欢迎您通过以下网址查看: http://www.java-gaming.org/topics/simple-audio-mixer-2nd-pass/27943/view.html

第一篇文章中列出的 jar 有源代码和示例用法,我投入了一些精力来制作 javadoc cmets。 (98% 的下载是我包含的单个样本 wav。)此外,线程上有很多 api 信息。

它仍然存在 Linux 问题。但是您的分析给我留下了深刻的印象,我想分享一下尝试解决问题并解决此问题的努力!

关于你的观点:

  • 我记得听说在某些 Linux 系统中,单一输出是可能的,并且某些应用程序无法公平播放,并在发生争用时将音频释放到 Java。如果这是准确的,那么很难将其称为 Java 问题,而可能是 Linux 操作系统问题?

  • 第二点:我还没有尝试从 Linux 中的 Mixer 加载,但我知道有些人已经能够通过我的 Web 应用 Java Theremin 做到这一点。在那个应用程序(链接在上面的线程中)中,我包含一个允许用户选择混音器的下拉菜单。至少有一些 Linux 用户在这方面取得了成功。

  • 我没有使用过 Big-Endian wavs -- 但只使用了 little-endian wavs。您必须翻转 Audacity 中的字节或类似的东西才能使用我目前的混音器。

  • 我的系统可以处理并发。您将 wav 加载到 PFClipData 对象中。然后,您可以通过 PFClipShooter(可以处理并发播放——20 或 30,以及不同的音高)或 PFClipLooper(将使用结尾的可选重叠模式循环剪辑以帮助平滑循环点)。所有输出都在后台汇集到单个 SourceDataLine。

  • 我还没有实现 ogg 或 mp3,只有 16 位、44100fps 立体声 little-endian wav 文件。

  • 如果有其他人愿意分享,我很乐意考虑将其作为开源 git 项目。

--我最近成功地在我的 PC 上的双启动分区中安装了 Linux(Ubuntu 桌面),并且正准备安装声卡,看看我是否重新创建并希望能解决所描述的一些问题。 Ubuntu 同时具有 OpenJDK 和 Oracle 的 JDK,所以我希望看看 Java 实现是否可能是问题的一部分。正在进行中...

【讨论】:

  • 谢谢,菲尔!我一定会查看您的解决方案,稍后会报告。
  • 我看了一下,基本上,我看到您自己实现了一个软件混音器。您在PFAudioMixer 的循环中总结来自PFMixerTracks 的数据 - 这很好,但在我看来它遗漏了一些重要的点:1)良好的信号混合比仅仅总结所有内容要复杂得多(并且得到奇怪的剪辑伪影),2)信号混合主要在现代声卡上的硬件中完成,3)即使它不是硬件混合,在纯 Java 中执行这种 CPU 密集型工作也不是最佳选择。
  • 我明白你的意思:你正在做所有的事情,没有额外的依赖和复杂性,所以它会在任何地方工作的解决方案。但是,我不确定回归到纯 Java 中的软件混合是否值得。我会记住您的解决方案,如果我找不到一组解决方法来提高 JavaSound 自身的可靠性,我会使用它。
  • 如果您遇到答案,请在此处回复!我认为在您的第二条评论中,您会了解我的实现的偏差:我不担心剪辑,因为可以/应该由程序员在发布应用程序之前对级别进行基本质量控制来处理。我同意硬件混合会更好。最后一点,我认为 CPU 的成本比通常想象的要低,很多事情可以用它的容量的 2% 来完成。感谢您查看并评论代码。
  • 从技术上讲,正确的音频信号混合比仅仅添加单个样本要困难得多。有十几种方法,其中大多数都非常消耗 CPU(例如进行高分辨率 FFT,将频谱相加,然后对结果进行逆 FFT)。大多数方法都可以在没有削波的情况下达到不错的声级,甚至不需要采取额外的削波去除方法,例如限制。例如,您可以使用res = A + B - A * B 技术改进求和,如vttoth.com/CMS/index.php/technical-notes/68 中所述
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-17
  • 2011-08-26
相关资源
最近更新 更多