Looping sound Java

末鹿安然 提交于 2020-01-16 10:54:46

问题


I am using a class that I cobbled together myself based on a sound playing method and then some custom code. The only problem is that I'm not 100% sure how the while loop that copies to the output stream in the playSoundFile() method works. I would be extremely grateful for a quick explanation of it, as well as any suggestions on how to set it up to loop (preferably without setting up a timer to repeatedly call it at the length of the sound file)

'My' Code:

import java.io.File;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

// Plays sounds passed to it. Loop stop etc to be supported later, maybe...
public  class SoundPlayer {

    File filSound;
    boolean isFileThere;

    public void loop() {
        throw new UnsupportedOperationException("Create something first... DUH");//http://stackoverflow.com/questions/2205565/java-clean-way-to-automatically-throw-unsupportedoperationexception-when-calling
    }

    public void play() {
        if (isFileThere) {
            playSoundFile(filSound);
        }
    }

    public void play(File file) {

        playSoundFile(file);

    }
    public static void playSoundFile(String sFile) {
        playSoundFile(new File(sFile));
    }

    public static void playSoundFile(final File file) {//http://java.ittoolbox.com/groups/technical-functional/java-l/sound-in-an-application-90681
        new Thread(//http://stackoverflow.com/questions/4708254/how-to-play-audio-in-java-application
                new Runnable() {

            public void run() {

                try {
//get an AudioInputStream
                    AudioInputStream ais = AudioSystem.getAudioInputStream(file);
//get the AudioFormat for the AudioInputStream
                    AudioFormat audioformat = ais.getFormat();

//ULAW format to PCM format conversion
                    if ((audioformat.getEncoding() == AudioFormat.Encoding.ULAW)
                            || (audioformat.getEncoding() == AudioFormat.Encoding.ALAW)) {
                        AudioFormat newformat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                                audioformat.getSampleRate(),
                                audioformat.getSampleSizeInBits() * 2,
                                audioformat.getChannels(),
                                audioformat.getFrameSize() * 2,
                                audioformat.getFrameRate(), true);
                        ais = AudioSystem.getAudioInputStream(newformat, ais);
                        audioformat = newformat;
                    }

//checking for a supported output line
                    DataLine.Info datalineinfo = new DataLine.Info(SourceDataLine.class, audioformat);
                    if (!AudioSystem.isLineSupported(datalineinfo)) {
                        //System.out.println("Line matching " + datalineinfo + " is not supported.");
                    } else {
                        //System.out.println("Line matching " + datalineinfo + " is supported.");
//opening the sound output line
                        SourceDataLine sourcedataline = (SourceDataLine) AudioSystem.getLine(datalineinfo);
                        sourcedataline.open(audioformat);
                        sourcedataline.start();
//Copy data from the input stream to the output data line
                        int framesizeinbytes = audioformat.getFrameSize();
                        int bufferlengthinframes = sourcedataline.getBufferSize() / 8;
                        int bufferlengthinbytes = bufferlengthinframes * framesizeinbytes;
                        byte[] sounddata = new byte[bufferlengthinbytes];
                        int numberofbytesread = 0;
                        while ((numberofbytesread = ais.read(sounddata)) != -1) {
                            int numberofbytesremaining = numberofbytesread;
                            System.out.println(numberofbytesread);
                            sourcedataline.write(sounddata, 0, numberofbytesread);
                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public void stop() {
        throw new UnsupportedOperationException("Create something first... DUH");//http://stackoverflow.com/questions/2205565/java-clean-way-to-automatically-throw-unsupportedoperationexception-when-calling

    }

    public void setSoundFile(File file) {
        isFileThere = true;
        filSound = file;
    }
    public void setSoundFile(String sFile) {
        isFileThere = true;
        filSound = new File(sFile);
    }
}

回答1:


You should restart music's playing after previous ends. How you can define when music stop playing?

//...
                        System.out.println(numberofbytesread);
                        sourcedataline.write(sounddata, 0, numberofbytesread);
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {   //added
                 /*here it stops*/
            }             //added

The esyest way will be restart it by putting in that block smt likeplaySoundFile(file).

But this code smells. You should think about refactoring;)

Also, I think, you can try put this block in infinitive loop

while(true){
                    SourceDataLine sourcedataline = (SourceDataLine) AudioSystem.getLine(datalineinfo);
                    sourcedataline.open(audioformat);
        /...
                        sourcedataline.write(sounddata, 0, numberofbytesread);
                    }
}

But, it isn't best solution too.




回答2:


For looping simple (short) sounds, I would avoid all the more complex javax.sound classes and use Clip. Some sample code using Clip.




回答3:


The problem is the buffer size.

so you need to let "finish" the playing thread before "reseting it" otherwise you would have overlaping sound with really small audio (exactly or smaller than buffer size e.g. 0:01)

so in your playing thread

class SomeLoopPlayer implements Runnable
{
  private boolean loop=true;

  public void play()
  {
    new Thread(this).start();
  }

  public void run()
  {
    try
    {
      while(true)
      {
        try //eos catch
        {
           //init sourcedataline or aif if null
          //read or drain the source buffer in cycle
        }
        catch(IOException e)
       { /* stream ended or other exception -> ignore for now */ }
       finally
       {
         if(loop)
           play();
         return;// terminate current thread
       }
    }
  }
}


来源:https://stackoverflow.com/questions/4786654/looping-sound-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!