I'm in the process of rewriting some tutorial code that plays back OggVorbis files. Instead of playing back the file, I my goal is to save the data as a .WAV file.

I progressively read the decoded file into a ByteArrayOutputStream baos. Then, I use boas to make a ByteArrayInputStream bais. Then, I try to use bais in the constructor for an AudioInputStream. The plan is to then use the AudioInputStream in an AudioSystem.write() method.

The second statement above throws this exception: "UnsupportedAudioFileException: could not get audio input stream from input stream at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)"

So, here is the question: is the plan itself reasonable? In the tutorial, the OggVorbis file is progressively read into a SourceDataLine that was generated as follows, where the variable audioFormat is a typical .WAVE format:

You ask why I don't wrap an AudioInputStream around the original input stream.

The answer is that the original input stream is encoded as OggVorbis, and unusable until it is decoded.

The innermost loop where the decoding occurs reads the data one frame channel at a time from a multidimensional array, converting it to WAV format (16-bit, little endian, etc.) and places this data in a byte buffer. The buffer is then progressively read into a SourceDataLine (in the original code).

There is no way to wrap a SourceDataLine with an AudioInputStream, is there? Or to extract or generate an AudioInputStream from a SourceDataLine? So, I thought I'd try to read into a ByteArrayOutputStream and work from there. (I can't imagine how I'd convert the multidim array to a stream, especially since it is repeatedly loaded with the decoded data.)

The tutorial code that I am trying to rewrite makes use of the JOrbis.jar provided by ... ah, the name of the coders escapes me. But believe me, the code in that jar is wild, unlike anything I've ever seen written in Java before. I'm talking public variables, all sorts of OOP no-no's.

But thanks for the feedback that the path I decided to try is valid, even if it is very inefficient. I will continue to look for bugs in the code. I've verfied that the bais is showing that it has something very close to the expect number of bytes (haven't nailed down the exact expected yet).

I think I would write the OggVorbis decoding code as a class that extends FilterInputStream, wrap it around the original stream, and wrap the AudioInputStream around that, rather than have all that latency and memory usage. That way you can get some audio through the system almost immediately.

807197 wrote:
I'm in the process of rewriting some tutorial code that plays back OggVorbis files. Instead of playing back the file, I my goal is to save the data as a .WAV file.

I progressively read the decoded file into a ByteArrayOutputStream baos. Then, I use boas to make a ByteArrayInputStream bais. Then, I try to use bais in the constructor for an AudioInputStream. The plan is to then use the AudioInputStream in an AudioSystem.write() method.

Since you have decoded the 'ogg' file the content of the ByteArrayInputStream is now big or little endian (I can never remember which way round one gets using OggVorbis decoder) raw PCM samples so the construction of the AudioInputStream is bound to fail. You just need a normal InputStream using these PCM samples when using AudioSystem.write().

As EJP says, you don't need to create the byte array in the first place. Just use the InputStream obtained from the OGG decoder.

I think something similar to your idea would be to write the OggVorbis decoder to subclass TargetDataLine. I know I can wrap a TargetDataLine in an AudioInputStream. (Haven't done it with FilterInputStream.) But this decoder isn't exactly well-behaved. The data is stored in pages and packets that vary in size, and there is a header to decode, and I'll have to figure out how to stop and start in order to break it up into a series of reads...how to keep track of progress through the decode. Hmmmm.

At least, there is no need to play the file back--I don't wish to do that. And the files won't be very large, they will be only a few seconds long each, maybe 30 seconds max. I just want to store them as WAV instead of OGG, for use at a later stage.

@sabre150
"You just need a normal InputStream using these PCM samples when using AudioSystem.write()."

I'm afraid I don't follow. How would a "normal InputStream" differ from the data I have already (the raw PCM in bais )? Is there a step or two less that I should do to leave the byte array something that CAN be made into AIS?

Or are you saying the AudioSystem.write can use an InputStream? Unfortunately, that doesn't seem to be an option. AudioSystem.write insists the first argument be an AIS.

AH -- just found the constructor new AudioInputStream(InputStream, AudioFormat, long)! I mistakenly thought I was restricted to AudioSystem methods to build the new AudioInputStream. So, all I have to do is grab the file length (can get from boas ) and I should be good to go. (I can make an InputStream from the ByteArrayInputStream.)

Curious, three of the five ogg files were saved as .wav files. Two of those are playable but with truncated ends. One gives the WindowsMediaPlayer an "unrecognized format". OK, let me mess with this some more. In the morning...

I am following up with the "solution" that I am accepting to the question.

I must have a different starting point than +@sabre150+. I've been rewriting the ExamplePlayer code that is given as a contributed tutorial. It does not provide an AudioInputStream hook, but simply routes the output directly to a SourceDataLine. So, I'm curious what the source code is that you ( +@sabre150+ ) are using! Perhaps you wrote your own code to directly interface with JOrbis?

Because I cannot find a path from a SourceDataLine to an AudioInputStream, and because the example code I'm rewriting does not lend itself to progressive reads (needed for subclassing as a TargetDataLine or other streaming structures), I'm doing the following and it does the job, albeit with an extra step. This can be revisited if there turns out to be a "business need" or clear "business benefit" to do so.

1) reading the entire decoded file into a ByteArrayOutputStream,
2) using ByteArrayOutputStream.size() and dividing by the frame size to obtain the number of frames,
3) creating a ByteArrayInputStream via ByteArrayOutputStream.toByteArray(),
4) creating an InputStream from the ByteArrayInputStream,
5) creating an AudioInputStream via the constructor(InputStream, AudioFormat, framelength)

Then, I am able to save the file via the usual AudioSystem.write() method.

Steps 2 through 5 are pretty minimal, afaik, e.g., basically a "wrapper" action. The main cost is the act of reading in and decoding the entire file. As the files are relatively small in this case, and handled one-at-a-time, the memory requirements should be no more than if one held the largest of the batch in memory as a Clip.

Playbacks of the newly saved .WAV files have been successful. There is another bug to track down, in that two of my five test cases bombed out during the decoding and never reached the above rigamarole, but that is another issue.

I think we must be talking at cross purposes. I'm talking of the Ogg Vorbis SPI for Java Sound ( http://www.javazoom.net/vorbisspi/vorbisspi.htm) which wraps JOrbis (http://www.jcraft.com/jorbis/ ) to allow one to read '.ogg' files as an AudioInputStream. There is a similar SPI for MP3 ( http://www.javazoom.net/mp3spi/mp3spi.html ) which wraps JLayer ( http://www.javazoom.net/javalayer/javalayer.html ).