Java中可靠的声音API,用于简单的数字样本播放
Posted
技术标签:
【中文标题】Java中可靠的声音API,用于简单的数字样本播放【英文标题】:Reliable sound API in Java for simple digital samples playback 【发布时间】: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) 上,列出 MixerInfo
s 并尝试使用其中任何一个获取 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) 上初始化几个不同的 Clip
s 并尝试播放它们只会使最后加载的 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 OpenAL 或paulscode.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
【参考方案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
的循环中总结来自PFMixerTrack
s 的数据 - 这很好,但在我看来它遗漏了一些重要的点: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 中所述以上是关于Java中可靠的声音API,用于简单的数字样本播放的主要内容,如果未能解决你的问题,请参考以下文章