我正在使用一个类,我根据声音播放方法和一些自定义代码拼凑自己。唯一的问题是我不能100%确定在playSoundFile()方法中复制到输出流的while循环是如何工作的。我非常感谢快速解释它,以及有关如何设置循环的任何建议(最好不要设置计时器以在声音文件的长度重复调用它)
'我的'代码:
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);
}
}
答案 0 :(得分:2)
对于循环简单(短)声音,我会避免使用所有更复杂的javax.sound类并使用Clip。一些sample code using Clip。
答案 1 :(得分:1)
您应该在上一次结束后重新开始播放音乐。如何定义音乐何时停止播放?
//...
System.out.println(numberofbytesread);
sourcedataline.write(sounddata, 0, numberofbytesread);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally { //added
/*here it stops*/
} //added
最简单的方法是通过放入像playSoundFile(file)
这样的块smt来重启它。
但这段代码闻起来。你应该考虑重构;)
另外,我认为,您可以尝试将此块放在不定式循环中
while(true){
SourceDataLine sourcedataline = (SourceDataLine) AudioSystem.getLine(datalineinfo);
sourcedataline.open(audioformat);
/...
sourcedataline.write(sounddata, 0, numberofbytesread);
}
}
但是,这也不是最佳解决方案。
答案 2 :(得分:0)
问题是缓冲区大小。
所以你需要在“重新设置”之前“完成”播放线程,否则你会将声音与真正小的音频重叠(完全或小于缓冲区大小,例如0:01)
所以在你的演奏线程中
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
}
}
}
}