Java播放24位音频不正确
我正在使用 javax sound API 来实现一个基于 http://www.javax sound API 的简单控制台播放程序。 jsresources.org/examples/AudioPlayer.html。
使用 24 位斜坡文件对其进行测试(每个样本是整个 24 位范围内的最后一个样本加 1),很明显在播放过程中发生了一些奇怪的情况。记录的输出不是文件的内容(我有一个数字环回来验证这一点)。
它似乎以某种方式误解了样本,导致左通道看起来像是应用了一些增益,而右通道看起来像是被衰减了。
我已经研究过 PAN 和 BALANCE 控件是否需要设置,但这些不可用,并且我检查了 Windows XP 声音系统设置。此斜坡文件的任何其他形式的播放都可以。
如果我用 16 位文件进行相同的测试,它会正确执行,不会损坏流。
那么有人知道为什么 Java Sound API 正在修改我的音频流吗?
I am using the javax sound API to implement a simple console playback program based on http://www.jsresources.org/examples/AudioPlayer.html.
Having tested it using a 24 bit ramp file (each sample is the last sample plus 1 over the full 24 bit range) it is evident that something odd is happening during playback. The recorded output is not the contents of the file (I have a digital loopback to verify this).
It seems to be misinterpreting the samples in some way that causes the left channel to look like it is having some gain applied to it and the right channel looks like it is being attenuated.
I have looked into whether the PAN and BALANCE controls need setting but these aren't available and I have checked the windows xp sound system settings. Any other form of playback of this ramp file is fine.
If I do the same test with a 16bit file it performs correctly with no corruption of the stream.
So does anyone have any idea why the Java Sound API is modifying my audio stream?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Java 播放 24 位音频的问题实际上是 Microsoft DirectSound 和/或 Windows Java Sound 实现的问题。使用带有 Java Sound 和 ALSA 的 Linux,可以完美播放 24 位音频(录制输出显示与输入文件的位完美匹配)。
要了解它在 Windows 中不起作用的原因,您可以使用 Java 查询要播放的输出行支持的音频格式(其中
lineInfo
是Line.Info< /code> 的输出行):
DataLine.Info dataLineInfo = (DataLine.Info) lineInfo;
然后循环遍历支持的格式:
for (AudioFormat lineFormat : dataLineInfo.getFormats())
对于 Windows,我得到类似这样的信息:
Which does not have 24 bit as a support format.但在 Windows XP 中,它仍然让我播放 24 位音频,但大概是通过 Java/DirectSound 处理为 16 位,然后由声卡恢复为 24 位。这就是为什么数据输出不正确的原因。在 Windows 7 中,我发现它只是拒绝播放 24 位音频(如果它要做的只是降到 16 位,可能更明智)。
对于 Linux (Fedora 17),我得到类似的信息(在同一台 PC 上使用完全相同的声卡、ESI Juli@):
其中确实支持 24 位格式。因此,这按预期工作,并且没有不需要的额外处理。
因此,看来 24 位播放确实可以与 Java Sound 配合使用,前提是特定于操作系统(也可能是特定于设备,但到目前为止我尝试过的设备之间没有发现任何变化)的实现将其列为支持的音频格式。我的测试表明 Linux (ALSA) 确实支持它,而 Windows (DirectSound) 则不支持。
希望这对某人有帮助;我在网上找不到任何关于此问题的信息,这就是为什么我发布了这样一个老问题。
以下是我刚刚回答的最初问题(我已将其留作参考):
我不确定这是否是解决旧问题的正确程序,但从阅读常见问题解答来看,这似乎是首选发布新的。我已经在其他几个地方(包括 Oracle Java Sound 论坛)发布了这个问题,但到目前为止没有任何回应,这个问题听起来与我遇到的问题完全相同:
I'm using Java Sound to play音频文件(标准 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 声卡上播放,该输出直接连接(通过外部电缆)到 Lynx 声卡(在同一台 PC 中)的数字输入,其中录制(使用 Sony Sound Forge)。
- 然后将录制的文件与输入波形文件进行比较。
为了进行测试,使用了四个不同的输入 Wave 文件(从同一源文件生成):
- 16 位,44.1 kHz;
- 16 位,48 kHz;
- 24 位,44.1 kHz;
- 24 位,48 kHz。
使用 ASIO 回放测试文件,所有四个文件都产生了正确的输出(在对齐按下录制和按下播放之间的时间的起始位置后,录制的数据与输入波形文件数据逐字节匹配)。
使用 Java 播放测试文件,16 位文件(44.1 kHz 和 48 kHz)产生正确的输出,而 24 位文件(44.1 kHz 和 48 kHz)则不能。不仅如此,输出不正确的方式也是不一致的(如果我运行测试两次,它每次都会产生不同的输出,两者都无法接近匹配输入文件)。因此,Java 声音不仅错误地播放 24 位文件,而且每次都以不同的方式执行错误。如果有帮助的话,我可以截取 Java 声音输出与输入文件(预期输出)进行比较的屏幕截图。
重现这种情况的最简单方法是使用上面提到的 AudioPlayer 示例,播放 24 位文件并记录输出(如果您只有一张声卡,则可以使用其混音器适当地路由数据,以使其能够被捕获)。虽然我能听到任何差异并没有错,但如果数据以某种意想不到的方式被改变,它确实有点违背了高分辨率音频的目的(你可能会失去使用 24 位而不是 16 位带来的任何收益,尽管我我真的不想在这里陷入争论)。
因此,将这个问题表述为 - 如何让 Java Sound 正确播放 24 位音频?
The problem with Java playback of 24 bit audio is actually with Microsoft DirectSound and/or the Windows Java Sound implementation of it. Using Linux with Java Sound and ALSA, 24 bit audio plays back perfectly (recording the output shows a bit-perfect match with the input file).
To see why it doesn't work in Windows, you can query the supported audio formats of the output line you want to play back on in Java using (where
lineInfo
is theLine.Info
of the output line):DataLine.Info dataLineInfo = (DataLine.Info) lineInfo;
and then looping through the supported formats:
for (AudioFormat lineFormat : dataLineInfo.getFormats())
For Windows I get something like:
Which doesn't have 24 bit as a supported format. But in Windows XP it still let me play 24 bit audio, but presumably processed down to 16 bit by Java / DirectSound and then back up to 24 bit by the soundcard. Hence why the data output is incorrect. In Windows 7 I found it just refused to play 24 bit audio (probably more sensible if all its going to do is drop to 16 bit anyway).
For Linux (Fedora 17) I get something like (with the exact same soundcard, an ESI Juli@, on the same PC):
Which does have 24 bit as a supported format. And as such this works as expected and without the unwanted extra processing.
So it seems that 24 bit playback does work with Java Sound, provided that the OS-specific (and maybe device-specific, but I haven't found any variation between the devices I've tried so far) implementation of it lists it as a supported audio format. My tests suggests that Linux (ALSA) does support it, whereas Windows (DirectSound) does not.
Hope this is helpful to someone; I couldn't find anything else about this online which is why I've posted on such an old question.
The following was my initial question, which I've just answered (I've left it for reference):
I'm not sure if this is the right procedure to bump old questions but from reading the FAQ it looks like that this is preferred to posting a new one. I've already posted this problem on a couple of other places (including the Oracle Java Sound forum) but with no responses so far and this question sounds exactly the same as the problem I'm having:
I'm using Java Sound to play audio files (in standard PCM format) but I've noticed that it does not correctly play 24 bit data, in that the data output from the soundcard does not match the input from the file. It works fine for 16 bit (and even 8 bit) audio data, but not for 24 bit (and presumably 32 bit, but I have no real 32 bit audio files to test) files. From the output it appears that Java Sound is doing some extra (and unwanted) processing to the audio data before passing it to the soundcard. I can say for certain that it is Java Sound doing this because if I run the same test using ASIO to play the file then there is no problem and the data matches as expected.
A bit more information on the setup:
- Java JRE latest version (7u7 I think), running on Windows XP SP3.
- Sound played using AudioPlayer example (as mentioned in the main question) on jsresources.org (I firstly tried using my own code, but switched to this in case I had made a mistake, the results are the same on both).
- The audio is played is on an M-Audio soundcard via the digital (S/PDIF) out, which is directly connected (via an external cable) to a digital in on a Lynx soundcard (in the same PC), where it is recorded (using Sony Sound Forge).
- The recorded file is then compared with the input Wave file.
For the test, four different input Wave files are used (generated from the same source file):
- 16 bit, 44.1 kHz;
- 16 bit, 48 kHz;
- 24 bit, 44.1 kHz;
- 24 bit, 48 kHz.
Using ASIO to play back the test files, all four of the files produced the correct output (the recorded data matches the input Wave file data byte for byte, after aligning the starting positions for the time between pressing record and pressing play).
Using Java to play back the test files, the 16 bit ones (both the 44.1 kHz and 48 kHz) produce the correct output, whereas the 24 bit ones (both the 44.1 kHz and 48 kHz) do not. Not only that, but the way in which the output is incorrect is inconsistent (if I run the test two times, it produces a different output each time, neither of which comes close to matching the input file). So not only is Java sound playing the 24 bit files wrongly, it is doing so wrongly in a different way each time. If it will help I can take screenshots of the Java sound output compared to the input file (expected output).
The easiest way to reproduce this would be to use the AudioPlayer example mentioned above, play a 24 bit file and record the output (if you only have one soundcard it might be possible to use its mixer to route the data appropriately to allow it to be captured). While it's not wrong enough that I can hear any difference, it does kind of defeat the purpose of hi-resolution audio if the data is being altered in some unexpected way (you risk losing any gains from using 24 bit over 16 bit, though I don't really want to get into that argument here).
So to phrase this as a question - how can I get Java Sound to play back 24 bit audio correctly?