Question

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?

Was it helpful?

Solution

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 the Line.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:

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

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):

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, 

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?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top