有没有一个好的方法可以在 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
听到 - 没有给出错误/警告,但只有play
在最后一次Clip
加载时使用才会发出任何声音 - 所有其他人都是沉默的: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,所以没有 oggs 甚至 mp3s :(似乎没有简单的方法可以同时制作相同
Clip
声音的两个副本而不将第二个副本加载为 distinctClip
。
所以,问题是 - 是否有一个好的解决方案/解决方法来补救所有这些东西并使其更可靠?切换到其他音响系统(如LWJGL OpenAL或paulscode.com 音响系统)会有帮助吗?或者是否可以将 Java Sound API 包装在一些安全措施中并且它会正常工作?
我做了一个小应用程序来测试以上所有内容,但它有点长,所以我想我会把它作为一个要点发布,但不幸的是,GitHub 现在有一些网络问题。所以,我想,我稍后会发布它。