Results 1 to 7 of 7
- 02-28-2009, 05:28 PM #1
Member
- Join Date
- Feb 2009
- Posts
- 6
- Rep Power
- 0
Playing an AudioInputStream multiple times
I'm making a program that loads audio files and mix them together, producing an AudioInputStream object. I'd like to play the sound as many times as the user wants it, but I found that the AudioInputStream is emptied once is read, so I'm not able to replay it.
I solved the problem writing the content of the AudioInputStream into a temp file, and reading the file each time I want to play the sound. Is there any other better way to play an AudioInputStream more than once? Note that ais.markSupported() returns false, so I can't use reset().
If you need to see some code please ask me. Thanks in advance.
- 02-28-2009, 05:40 PM #2
You don't need to use a file, just copy the data into an array in memory. For repeated playback of sound data try using a Clip instead.
- 02-28-2009, 10:06 PM #3
Member
- Join Date
- Feb 2009
- Posts
- 6
- Rep Power
- 0
Thanks for the reply OrangeDog. What's easy to say it's usually harder to do... :D I'll explain you now.
Initially, I was using a Clip instead a SourceDataLine. But Clip has its limitations, and I got a Java heap error when reading large files. I am using SourceDataLine with buffers and is working perfectly, that's not a problem.
What I want to do is to play a sound multiple times, as in a Sound Player. When the user press stop and then play again, the song is replayed. The problem is that the AudioInputStream is emptied while playing the sound, so I have to reload the song each time. Now I'm using a temp file for that, but I'd like to do it in memory.
Yes, this is what I want! The problem is... how? This is my guess, but I get an Java.io.EOFException when executing getAudioInputStream(bais) (the last statement):
Java Code:ais = getAudioInputStreamFromFiles(); //ArrayInputStream to bytes int nBytesRead = 0; ArrayList<Byte> byteList = new ArrayList<Byte>(); byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; while (nBytesRead != -1) { try { nBytesRead = ais.read(abData, 0, abData.length); } catch (IOException e) { e.printStackTrace(); } if (nBytesRead >= 0) { for(int i=0;i<nBytesRead;i++) { byteList.add(abData[i]); } } } byte[] bytes = new byte[byteList.size()]; for(int i=0;i<byteList.size();i++) { bytes[i] = byteList.get(i); } //bytes to ArrayInputStream ByteArrayInputStream bais = new ByteArrayInputStream(bytes); try { ais = AudioSystem.getAudioInputStream(bais); //JAVA.IO.EOFEXCEPTION } catch (UnsupportedAudioFileException ex) { e.printStackTrace(); } catch (IOException ex) { e.printStackTrace(); }
- 03-01-2009, 05:12 PM #4
Hmm, can't quite see what you're doing there - things seem a little over complicated. Although, if you're getting heap errors, the audio is probably too large to hold in memory by any method. The way I'd do it (omitting error handling and some refinements) is:
Java Code:byte[] data; InputStream in = ClassLoader.getSystemResourceAsStream(filename); //in an applet AudioInputStream ais = AudioSystem.getAudioInputStream(in); data = new byte[(int)ais.getFrameLength() * format.getFrameSize()]; byte[] buf = new byte[BUFSIZE]; for (int i=0; i<data.length; i+=BUFSIZE) { int r = ais.read(buf, 0, BUFSIZE); if (i+r >= data.length) { r = i + r - data.length; } System.arraycopy(buf, 0, data, i, r); } ais.close();
Java Code:line.start(); for (int i=0; i<data.length; i+=BUFSIZE) { line.write(data, i, BUFSIZE); } line.drain(); line.stop();
Hope that helps.
- 03-01-2009, 05:18 PM #5
If heap overflow is a relatively rare problem, try splitting the data into smaller chunks and building a memory-sensitive cache with java.lang.ref.SoftReference. Then you wouldn't have to reload as much data. Whether this would work depends entirely on the rest of your application of course.
- 03-02-2009, 01:18 AM #6
Member
- Join Date
- Feb 2009
- Posts
- 6
- Rep Power
- 0
Thanks for the answer!! :)
I discovered the reason for the heap overflow: when I was trying to obtain the stream duration (getFrameLength / getFrameRate), it came out that the actual duration was longer than 24000 secs. :eek: It meant that the sound I was playing lasted more than 6 hours... The sound file actually lasted only 4 seconds, so I suppose it's a problem with the file format. I recorded it in WAV format with gnome-sound-recorder, if someone is needed to be blamed. :P
So it looks like the impediment to work with Clips has disappeared. However, there's always a limitation: as the jsresources FAQ states (three messages more and I'll be allowed to put links, I promise), Clip can't handle files bigger than 5 Mb. So it is more than probable that I'll come back to SourceDataLine and I'll put into practice your pieces of advices. I'll post as soon as I have any result, thanks again for your help.
- 03-09-2009, 05:29 PM #7
Member
- Join Date
- Feb 2009
- Posts
- 6
- Rep Power
- 0
I just adapted your code and it worked perfectly, thanks OrangeDog! :D
I only had to do the small correction I show in the following code:
Java Code:byte[] data; InputStream in = ClassLoader.getSystemResourceAsStream(filename); //in an applet AudioInputStream ais = AudioSystem.getAudioInputStream(in); data = new byte[(int)ais.getFrameLength() * format.getFrameSize()]; byte[] buf = new byte[BUFSIZE]; for (int i=0; i<data.length; i+=BUFSIZE) { int r = ais.read(buf, 0, BUFSIZE); if (i+r >= data.length) { [b]r = data.length - i;[/b] } System.arraycopy(buf, 0, data, i, r); } ais.close();
Similar Threads
-
playing audio in J-App??
By ashton in forum New To JavaReplies: 3Last Post: 01-30-2009, 09:50 AM -
SwingWorker problem!!! How can I run it 2 times or more?
By davigre in forum AWT / SwingReplies: 3Last Post: 10-02-2008, 06:48 AM -
Recursive Method ==> find how many times a value is repeated in an array
By NatNat in forum New To JavaReplies: 2Last Post: 02-16-2008, 09:52 PM -
Re-playing sound
By JSK in forum CLDC and MIDPReplies: 0Last Post: 02-06-2008, 12:34 PM -
presse 1 menuitem execute 4 times the same JFrame
By marcvb in forum New To JavaReplies: 0Last Post: 12-27-2007, 10:48 PM
Bookmarks