tags:

views:

1576

answers:

4

Is it possible to create a temporary file that contains a "loop" of a wav file?

Or is it possible to manipulate the stream sent to a stream reader/writer?

Basically I want to play some wav file for a period of time and if that time is greater than the length of time that the wav file provides I want to loop.

A: 

I'm not sure I understand the exact limitations you have for implementing a solution, but it seems that the cleanest way to do this would be to store the audio data in a buffer the first time you play through the file. Then, if there are more iterations (full or partial) wanted by the user, just rewrite the data you have cached back out to the SourceDataLine the desired number of times.

Here is a link to a sample sound file player (PCM) that has code that should be very easy to modify (or just learn from). I also hacked up some (note: untested) code that just shows the logic I described above: (You probably also want to modify what I have below to conform to the rules concerning only writing chunks of data that have a size that is a multiple of the frame size.)

public void playSoundFile(SourceDataLine line, InputStream inputStream, AudioFormat format, long length, float times)
{
    int index = 0;
    int size = length * format.getFrameSize();
    int currentSize = 0;
    byte[] buffer = new byte[size];
    AudioInputStream audioInputStream = new AudioInputStream(inputStream, format, length);
    while (index < size)
    {
        currentSize = audioInputStream.read(buffer, index, size - index);
        line.write(buffer, index, currentSize);
        index += currentSize;
    }

    float currentTimes = 1.0;
    while (currentTimes < times)
    {
        float timesLeft = times - currentTimes;
        int writeBlockSize = line.available();
        index = 0;

        if (timesLeft >= 1.0)
        {
            while (index < size)
            {
                currentSize = ((size - index) < writeBlockSize) ? size - index : writeBlockSize;
                line.write(buffer, index, currentSize);
                index += currentSize;
            }
            currentTimes += 1.0;
        }
        else
        {
            int partialSize = (int)(timesLeft * ((float) size) + 0.5f);
            while (index < partialSize)
            {
                currentSize = ((partialSize - index) < writeBlockSize) ? partialSize - index : writeBlockSize;
                line.write(buffer, index, currentSize);
                index += currentSize;
            }
            currentTimes += timesLeft;
        }
    }
}

Hope that helps!

that is a possibility, but it is not quite what I am looking for - the data is sent asynchronously to a player and the calling thread has no idea how long the file/sound is.
Tim
Could you give a bit more information regarding the specifics of the situation? There are a couple of things that are not specified (e.g. who knows the length of the file/sound and how long it should be played? If it is the player, then the player could perform the caching method I described above.)
A: 

I think I'll use the frames per second and framesize information in the audio input stream to figure this out. Other useful information is in getMicrosecondPosition() method of the SourceDataLine object to determine the time/duration played so far.

this along with mark and reset methods in the audio input stream probably take care of it all.

Tim
+4  A: 
     AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
     Clip clip = AudioSystem.getClip();
     clip.loop((int)(Math.ceil(timeRequested / audioIn.getFrameLength())));
M. Utku ALTINKAYA
I have a few questions - how do I "attach" the loop to my existing DataLine that I am using? What to do with the clip? - how to send that to a SourceDataLine?
Tim
It will automatically be attached to your current active DataLine, clip is just like another player instance, you can start, or stop it whenever you want.You can query caps to see how many of them can be played simultaneously, If needed you can define a queue. But I do not recommend mixing yourself.
M. Utku ALTINKAYA
I'll try it out, but not sure if it will work with the dataline the way my code exists. Thanks
Tim
A: 

i came up with a function that we can use in a loop to itterate different sound files and append them into 1 file, ie concatenate them. but the output file is having some problems. only the first sound file that we enter to concatenate is played. can anyone please tell me what am i doing wrong?

public static void saveFile(byte[] bytes) throws FileNotFoundException, IOException
{      
  if(flag==0)
  {
      File savedFile = new File("trial1.wav");
      FileOutputStream fos=new FileOutputStream(savedFile);
      fos.write(bytes);
      fos.close();
  }
  else
  {
      File savedFile = new File("trial1.wav");
      System.out.println("in else of savedFile method");

      FileOutputStream fos=new FileOutputStream(savedFile,true);

      fos.write(bytes);
      fos.close();
  }
}
Mugdha