0

I'm using a AudioInputStream to feed bytes to a SourceDataLine to play a PCM file. I want to give the user the ability to move a slider to jump to some point in the file.

Issues I'm having:

  • markSupported() returns false on my AudioInputStream. So I cannot use my initial approach to call reset() then skip() (which I already thought was kind of ugly...)
  • I would really prefer not to tear down the InputStream and create a new one just to jump to a position prior to my current mark.
  • SourceLineData.getLongFramePosition() does not seem to be very reliable... I know it has a buffer, but even if account for the bytes left in the buffer, i do not understand the behavior

I have considered using a Memory-Mapped File to feed bytes to the line that way I can jump wherever I want, but I don't want to add complexity to the function if I don't have to. Is there a good way to do this that I'm missing? also can anyone explain what the frame number returned by getLongFramePosition() actually means? is it number of frames passed through speakers (does not appear to be)?

sethro
  • 2,127
  • 1
  • 14
  • 30
  • because the file I'm playing can be of an unspecified length. It is my understanding that clips are for very short sounds. – sethro Aug 18 '11 at 21:24
  • 'unspecified' or 'large'? The distinction is very important. E.G. [BigClip](http://stackoverflow.com/questions/5667454/playing-audio-file-in-java-application/5668510#5668510) can handle **large** clips. (Yes, your understanding about `Clip` is correct.) – Andrew Thompson Aug 19 '11 at 05:43

2 Answers2

1

Did the BigClip work for you?

If not, here's something that could work. Warning, it is a little convoluted. http://hexara.com/VSL/VSL2.htm

With this Applet, you can load a wav -- I've loaded wavs longer than 5 minutes and it has worked fine, but audio data does take up a lot of RAM.

Once the WAV is loaded, you can mouse to any point and playback via holding the mouse down and dragging. Obviously, that's not exactly what YOU want to do, since you want to play back from a point, and not worry about dragging or dragging speed. But the path I take to get the data in a playable state should still work for you.

If you have a working AudioInputStream and AudioFileFormat, you can set up an internal array and read the data directly into it. The audio file format gives you the encoding and the length in frames which you can use to calculate your array dimension.

Then, make a TargetDataLine that gets its audio data from the array you made. A TDL has to have a variable that marks where the next read will start. You can use your JSlider to change the contents of that variable to point to whatever frame you want.

If you don't have a working AudioInputStream, there are ways to get one...but it is more convoluted, involving ByteArrayOutput & Input Stream objects. Probably no need to go there. (I use them to read client data in the above Applet.)

As to your question about the current Frame location, the key problem is that the JVM processes audio data in chunks, and it tends to run ahead of what is heard in bursts. I banged my head against this problem for a long while, then came up with this: http://www.java-gaming.org/index.php/topic,24605.0.html

Phil Freihofner
  • 7,645
  • 1
  • 20
  • 41
  • Thanks for the example, I have actually already come up with a solution, I just forgot to post it. – sethro Sep 15 '11 at 18:14
1

The cleanest way I could come up with was to use a FileChannel to read the bytes into the SourceDataLine this way based on the user moving a slider I could determine the byte position in the file (making sure to adjust or round it to line up with a frame) and then set that position in the FileChannel and then continue playback. I flushed the line when this happened to keep from playing remaining bytes.

sethro
  • 2,127
  • 1
  • 14
  • 30