Results 1 to 7 of 7
  1. #1
    pmgallardo is offline Member
    Join Date
    Feb 2009
    Posts
    6
    Rep Power
    0

    Default 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.

  2. #2
    OrangeDog's Avatar
    OrangeDog is offline Senior Member
    Join Date
    Jan 2009
    Location
    Cambridge, UK
    Posts
    838
    Rep Power
    6

    Default

    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.

  3. #3
    pmgallardo is offline Member
    Join Date
    Feb 2009
    Posts
    6
    Rep Power
    0

    Default

    Quote Originally Posted by OrangeDog View Post
    For repeated playback of sound data try using a Clip instead.
    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.

    Quote Originally Posted by OrangeDog View Post
    You don't need to use a file, just copy the data into an array 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();
            }

  4. #4
    OrangeDog's Avatar
    OrangeDog is offline Senior Member
    Join Date
    Jan 2009
    Location
    Cambridge, UK
    Posts
    838
    Rep Power
    6

    Default

    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();
    which will load the audio bytes into data. Playback is done something like:
    Java Code:
    line.start();
    for (int i=0; i<data.length; i+=BUFSIZE) {
        line.write(data, i, BUFSIZE);
    }
    line.drain();
    line.stop();
    where line is an open SourceDataLine.
    Hope that helps.

  5. #5
    OrangeDog's Avatar
    OrangeDog is offline Senior Member
    Join Date
    Jan 2009
    Location
    Cambridge, UK
    Posts
    838
    Rep Power
    6

    Default

    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.

  6. #6
    pmgallardo is offline Member
    Join Date
    Feb 2009
    Posts
    6
    Rep Power
    0

    Default

    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.

  7. #7
    pmgallardo is offline Member
    Join Date
    Feb 2009
    Posts
    6
    Rep Power
    0

    Default

    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

  1. playing audio in J-App??
    By ashton in forum New To Java
    Replies: 3
    Last Post: 01-30-2009, 08:50 AM
  2. Replies: 3
    Last Post: 10-02-2008, 05:48 AM
  3. Replies: 2
    Last Post: 02-16-2008, 08:52 PM
  4. Re-playing sound
    By JSK in forum CLDC and MIDP
    Replies: 0
    Last Post: 02-06-2008, 11:34 AM
  5. presse 1 menuitem execute 4 times the same JFrame
    By marcvb in forum New To Java
    Replies: 0
    Last Post: 12-27-2007, 09:48 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •