24位音频的Java播放不正确

时间:2010-06-11 16:50:16

标签: java audio 24-bit

我正在使用javax声音API来实现基于http://www.jsresources.org/examples/AudioPlayer.html的简单控制台播放程序。

使用24位斜坡文件对其进行测试(每个样本是最后一个样本加上整个24位范围内的1),很明显在回放期间发生了奇怪的事情。录制的输出不是文件的内容(我有一个数字环回来验证这一点)。

似乎是以某种方式误解了样本,导致左声道看起来像是应用了一些增益,而右声道似乎正在衰减。

我已经研究过PAN和BALANCE控件是否需要设置但这些都不可用,我已经检查了windows xp音响系统设置。此斜坡文件的任何其他形式的播放都可以。

如果我使用16位文件执行相同的测试,它会正确执行而不会损坏流。

那么有没有人知道为什么Java Sound API正在修改我的音频流?

1 个答案:

答案 0 :(得分:3)

Java播放24位音频的问题实际上是使用Microsoft DirectSound和/或Windows Java Sound实现的。使用Linux与Java Sound和ALSA,24位音频完美播放(录制输出显示与输入文件完美匹配)。

要了解它在Windows中无法运行的原因,您可以使用(lineInfoLine.Info查询要在Java中播放的输出行支持的音频格式输出线):

DataLine.Info dataLineInfo = (DataLine.Info) lineInfo;

然后循环支持的格式:

for (AudioFormat lineFormat : dataLineInfo.getFormats())

对于Windows,我得到类似的内容:

Format #1: PCM_UNSIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
Format #2: PCM_SIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
Format #3: PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, little-endian
Format #4: PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, big-endian
Format #5: PCM_UNSIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
Format #6: PCM_SIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
Format #7: PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, little-endian
Format #8: PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian

其中24位不支持格式。但是在Windows XP中它仍然允许我播放24位音频,但可能是由Java / DirectSound处理到16位,然后通过声卡返回到24位。因此数据输出不正确的原因。在Windows 7中,我发现它只是拒绝播放24位音频(如果它所做的一切都降到16位,可能更明智。)

对于Linux(Fedora 17)我在同一台PC上得到类似的东西(使用完全相同的声卡,ESI Juli @):

Format #1: PCM_SIGNED unknown sample rate, 32 bit, mono, 4 bytes/frame, little-endian
Format #2: PCM_SIGNED unknown sample rate, 32 bit, mono, 4 bytes/frame, big-endian
Format #3: PCM_SIGNED unknown sample rate, 32 bit, stereo, 8 bytes/frame, little-endian
Format #4: PCM_SIGNED unknown sample rate, 32 bit, stereo, 8 bytes/frame, big-endian
Format #5: PCM_SIGNED unknown sample rate, 24 bit, mono, 4 bytes/frame, little-endian
Format #6: PCM_SIGNED unknown sample rate, 24 bit, mono, 4 bytes/frame, big-endian
Format #7: PCM_SIGNED unknown sample rate, 24 bit, stereo, 8 bytes/frame, little-endian
Format #8: PCM_SIGNED unknown sample rate, 24 bit, stereo, 8 bytes/frame, big-endian
Format #9: PCM_SIGNED unknown sample rate, 24 bit, mono, 3 bytes/frame, little-endian
Format #10: PCM_SIGNED unknown sample rate, 24 bit, mono, 3 bytes/frame, big-endian
Format #11: PCM_SIGNED unknown sample rate, 24 bit, stereo, 6 bytes/frame, little-endian
Format #12: PCM_SIGNED unknown sample rate, 24 bit, stereo, 6 bytes/frame, big-endian
Format #13: PCM_SIGNED unknown sample rate, 20 bit, mono, 3 bytes/frame, little-endian
Format #14: PCM_SIGNED unknown sample rate, 20 bit, mono, 3 bytes/frame, big-endian
Format #15: PCM_SIGNED unknown sample rate, 20 bit, stereo, 6 bytes/frame, little-endian
Format #16: PCM_SIGNED unknown sample rate, 20 bit, stereo, 6 bytes/frame, big-endian
Format #17: PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, little-endian
Format #18: PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, big-endian
Format #19: PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, little-endian
Format #20: PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian
Format #21: PCM_SIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
Format #22: PCM_UNSIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame,
Format #23: PCM_SIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame,
Format #24: PCM_UNSIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame, 

哪个支持24位格式。因此,这可以按预期工作,没有不必要的额外处理。

所以似乎24位播放可以与Java Sound一起使用,前提是特定于操作系统(也许是特定于设备的,但我还没有发现到目前为止我尝试过的设备之间存在任何差异) )它的实现将其列为支持的音频格式。我的测试表明Linux(ALSA)支持它,而Windows(DirectSound)则不支持。

希望这对某人有帮助;我无法在网上找到任何其他相关内容,这就是我在这么老问题上发布的原因。

以下是我最初的问题,我刚刚回答(我已将其留待参考):


我不确定这是否是解决旧问题的正确程序,但是从阅读常见问题解答看起来这是首选发布新问题。我已经在其他几个地方(包括Oracle Java Sound论坛)发布了这个问题,但到目前为止还没有回复,这个问题与我遇到的问题完全一样:

我使用Java Sound播放音频文件(标准PCM格式),但我注意到它没有正确播放24位数据,因为声卡的数据输出与从文件输入。它适用于16位(甚至8位)音频数据,但不适用于24位(可能是32位,但我没有真正要测试的32位音频文件)文件。从输出看来,Java Sound在将音频数据传递给声卡之前对音频数据进行了一些额外的(和不需要的)处理。我可以肯定地说,Java Sound是这样做的,因为如果我使用ASIO运行相同的测试来播放文件,那么没有问题,数据会按预期匹配。

有关设置的更多信息: - Java JRE最新版本(我认为7u7),在Windows XP SP3上运行。 - 在jsresources.org上使用AudioPlayer示例(如主要问题中所述)播放的声音(我首先尝试使用我自己的代码,但是在我犯了错误的情况下切换到这个,结果两者都相同)。 - 通过数字(S / PDIF)输出在M-Audio声卡上播放音频,该数字(S / PDIF)输出直接连接(通过外部电缆)到Lynx声卡(在同一台PC中)的数字输入,在那里它是录制(使用Sony Sound Forge)。 - 然后将录制的文件与输入波形文件进行比较。

对于测试,使用了四个不同的输入Wave文件(从同一源文件生成): - 16位,44.1 kHz; - 16位,48 kHz; - 24位,44.1 kHz; - 24位,48 kHz。

使用ASIO回放测试文件,所有四个文件都产生了正确的输出(记录的数据与输入的Wave文件数据字节匹配,对齐按下记录和按下播放之间的时间的起始位置)

使用Java回放测试文件,16位(44.1 kHz和48 kHz)产生正确的输出,而24位(44.1 kHz和48 kHz)则不能。不仅如此,输出不正确的方式是不一致的(如果我运行测试两次,它每次产生不同的输出,它们都不接近匹配输入文件)。因此,Java不仅错误地播放24位文件,而且每次都以不同的方式错误地播放。如果它有助于我可以获取与输入文件(预期输出)相比的Java声音输出的屏幕截图。

重现这一点的最简单方法是使用上面提到的AudioPlayer示例,播放24位文件并记录输出(如果您只有一个声卡,则可以使用其混音器来适当地路由数据以允许它被捕获)。虽然我没有错,但我听不到任何差异,如果数据以某种意想不到的方式被改变,它确实会破坏高分辨率音频的目的(你可能会因使用24位超过16而失去任何收益)有点,虽然我不想在这里讨论这个论点。)

所以说这是一个问题 - 我怎样才能让Java Sound正确播放24位音频?