我是JAVA领域的新手,我正试着读一段片段。这是我的代码:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
public class TestClipBis {
protected static AudioFormat audioFormat;
public static void main(String[] args) throws Exception {
// Specification of the sound to play
// No control. We assume that the sound can be played on audio system
//File soundFile = new File("chimes.wav");
File soundFile = new File("test.wav");
InputStream is = new FileInputStream(soundFile);
InputStream bufferedIn = new BufferedInputStream(is);
//AudioInputStream sound = AudioSystem.getAudioInputStream(soundFile);
AudioInputStream sound = AudioSystem.getAudioInputStream(bufferedIn);
audioFormat = sound.getFormat();
System.out.println(audioFormat);
// Loading the sound into the memory (a Clip)
DataLine.Info info = new DataLine.Info(Clip.class, sound.getFormat());
System.out.println(info);
//Clip clip = (Clip) AudioSystem.getClip();
Clip clip = (Clip) AudioSystem.getLine(info);
System.out.println("Sound frame lenght : "+sound.getFrameLength());
System.out.println("Clip FrameLength before opening : "+clip.getFrameLength());
System.out.println("Clip will open - "+info);
System.out.println("Info format : "+info.getLineClass());
// Check before this line that everything is in memory
// Yes, but how ?
clip.open(sound);
System.out.println("Clip is open");
System.out.println("Clip FrameLength after opening : "+clip.getFrameLength());
// Due to a bug in Java Sound,
// we explicitly out of the VM when the sounds stop
clip.addLineListener(new LineListener() {
public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP) {
System.out.println("Methode de sortie");
event.getLine().close();
System.exit(0);
}
}
});
// Playing the clip
clip.start();
System.out.println("IsActive : "+clip.isActive());
//clip.close();
}
} 我的问题是如何确保剪辑在打开和播放之前加载到内存中?使用上面的代码,当我打开并播放声音文件时,我有几秒钟的播放时间,但没有相同的长度,随机,也没有完整的歌曲。
或者我应该用一个剪辑以外的其他东西来播放一首歌?但我想“移动”到歌曲,而不仅仅是从一开始到结束它流。
编辑:
好吧,我试了几样东西。首先,我试着看看"ByteArrayOuptputStream“是否已经写好了。我在循环中有一个"println“,是的,所有的都是写的,但它不能解决问题。
然后,当我打开剪辑时,我尝试添加参数:音频格式、字节数组、起始点、缓冲区长度。没有比这更好的了。
然后,我注意到当声音停止时,使用了退出的方法。因此,我试图“沉默”这个方法(带有注释符号)。结果是不同的:它读取文件,但声音不稳定。当我检查CPU的使用情况时,大约是100%。这是猜测问题所在的第一条线索吗?
我试着做一个循环,指示开始后的帧位置:所有的帧都被读取,但是声音仍然不稳定。我还在开始方法之前和之后尝试了thead.sleep :没有比这更好的了。
下面是我使用的代码。许多代码部分在“注释引号”之间,因为它们是尝试的,没有成功的.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
public class TestBufferedClip {
protected static AudioFormat audioFormat;
public static ByteBuffer buffer;
public static void main(String[] args) throws Exception {
// Specification of the sound to play
// No control. We assume that the sound can be played on audio system
//File soundFile = new File("chimes.wav");
File soundFile = new File("test.wav");
FileInputStream fis = new FileInputStream(soundFile);
ByteArrayOutputStream baos = new ByteArrayOutputStream((int)soundFile.length());
byte[] buf = new byte[1024];
int n = 0;
int loop = 0;
while ((n=fis.read(buf))>=0) {
baos.write(buf);
buf=new byte[1024];
System.out.println("Loop = "+loop);
loop+=1;
}
byte[] ba = baos.toByteArray();
System.out.println("ByteArray size : "+ba.length);
ByteArrayInputStream bais = new ByteArrayInputStream(ba);
//AudioInputStream sound = AudioSystem.getAudioInputStream(soundFile);
AudioInputStream sound = AudioSystem.getAudioInputStream(bais);
audioFormat = sound.getFormat();
System.out.println(audioFormat);
// Loading the sound into the memory (a Clip)
DataLine.Info info = new DataLine.Info(Clip.class, sound.getFormat());
System.out.println("Info :"+info);
//Clip clip = (Clip) AudioSystem.getClip();
Clip clip = (Clip) AudioSystem.getLine(info);
System.out.println("Sound frame lenght : "+sound.getFrameLength());
System.out.println("Info format : "+info.getLineClass());
// Check before this line that everything is in memory
// Yes, but how ?
clip.open(audioFormat, ba, 0, ba.length);
//clip.open(sound);
System.out.println("Clip is open");
System.out.println("Clip FrameLength after opening : "+clip.getFrameLength());
// Due to a bug in Java Sound,
// we explicitly out of the VM when the sounds stop
/*
clip.addLineListener(new LineListener() {
public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP) {
System.out.println("Methode de sortie");
event.getLine().close();
System.exit(0);
}
}
});
*/
// Playing the clip
System.out.println("Before thread sleep");
try {
Thread.sleep(31000);
} catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("After thread sleep");
clip.start();
System.out.println("IsActive : "+clip.isActive());
/*
while (clip.isActive()==true) {
System.out.println("Position = "+clip.getFramePosition());
}
*/
//clip.close();
}
} @:
我考虑了你的解决方案,去读取和丢弃数据,直到我到达“开始”点。您编写了“为了从音频文件中的某个点开始,使用SourceDataLine,您必须从音频输入行读取和丢弃数据,直到到达所需的起始位置”。你是怎么做到的?当我使用"SourceDataLine“方法时,我的start方法是一个带有line.write(字节,0,bytesread)的循环;将声音指向扬声器。
那么,你是如何阅读和丢弃的呢?我没有找到任何“读”的方法与这一行。
发布于 2015-03-03 18:16:43
javax.sound.sampled支持两个对象来播放音频。正如您所使用的那样,剪辑必须完全加载到内存中,然后才能播放它。在积极的一面,它也是很容易定位的回放开始从剪辑,无论是使用微秒或帧的位置。
我认为第一次将声音加载到字节缓冲区没有好处。这是剪辑缓冲的冗余级别。我只会这样做,如果你试图做DSP或其他需要获取数据,一些超出剪辑内置的能力,以设置一个起点。
如果您能够在选择之前将可能的音频选项作为剪辑预加载,这可能是最好的解决方案,只要您没有耗尽RAM。
回放的另一个选项是SourceDataLine。它在每个缓冲区的基础上读取和回放文件。因此,它可以比卸载的剪辑更快地启动(不需要首先将整个文件加载到内存中)。然而,一旦剪辑被预先加载,剪辑将回放,而不必做重复的文件加载。
为了从音频文件中的某个点开始,使用SourceDataLine,您必须从音频输入行读取和丢弃数据,直到到达所需的起始点为止。您可以通过计数帧来做到这一点(格式将告诉您每个帧的字节数)。这种读取和丢弃会干扰定时,但我的经验是,读取和丢弃音频数据比回放快几个数量级,因为回放涉及阻塞队列以保持所需的帧速率。
查看Java声音教程以获得更多信息,其中包括剪辑和SourceDataLine API的链接。
下面是一个加载剪辑的示例:
File soundFile = new File("test.wav");
AudioInputStream sound = AudioSystem.getAudioInputStream(soundFile);
DataLine.Info info = new DataLine.Info(Clip.class, sound.getFormat());
Clip clip = (Clip) AudioSystem.getLine(info);
clip.open(sound);来自test.wav的数据现在应该在内存中。使用字节缓冲区和缓冲行的所有其他东西都是不必要的。
准备播放时,使用clip.setMicrosecondPosition(长毫秒)将声音设置为从所需位置开始(如果从一开始就开始播放,则不需要,除非您已经播放了剪辑,在这种情况下,该位置将位于停止时的位置)。然后使用clip.start()开始播放。
重要注意:如果运行程序退出,回放将过早结束。测试这一点的一种方法是在Thread.sleep()之后放置一个clip.start(长毫秒)命令,其中毫秒的值大于剪辑的长度。但这不是一个真正的解决方案,只是一个诊断,以防止程序关闭剪辑回放线程。您应该处理保持程序运行从主线程,而不是线程与音频回放。
发布于 2015-03-02 15:27:52
首先将整个读入一个字节缓冲区。通过将所有内容从文件复制到ByteArrayOutputStream来做到这一点。这样,您将在内存中拥有整个媒体内容。现在,您可以将数组从ByteArrayOutputStream.toByteArray()包装到ByteArrayInputStream中,并将该纯内存流作为音频输入流提供。
https://stackoverflow.com/questions/28813330
复制相似问题