【发布时间】:2015-03-02 15:23:39
【问题描述】:
我是 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();
}
}
我的问题是如何确保剪辑在打开和播放之前加载到内存中?使用上面的代码,当我打开并播放声音文件时,我有几秒钟的播放时间,但长度不一样,随机的,也不完整的歌曲。
或者我应该使用剪辑以外的其他东西来播放歌曲?但我想“移动”到歌曲中,而不仅仅是从头到尾播放。
编辑:
好的,我尝试了几件事。首先,我尝试查看是否写入了“ByteArrayOutputStream”。我在循环中有一个“println”,是的,所有内容都已写入,但它不能解决问题。
然后,当我打开剪辑时,我尝试添加参数:audioformat、bytearray、startpoint、bufferlength。没有比这更好的了。
然后,我注意到当声音停止时,使用了退出方法。所以,我试图“静音”该方法(带有注释符号)。结果不同:它读取了文件,但声音很生涩。当我检查 CPU 使用率时,它大约是 100%。这是猜测问题所在的第一条线索吗?
我尝试创建一个循环来指示开始后的帧位置:所有帧都已读取,但声音仍然很生涩。 我还尝试了 start 方法之前和之后的 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();
}
}
@Phil Freihofner:
我考虑了您的解决方案来读取和丢弃数据,直到我达到我的“开始”点。您写道:“为了从音频文件中的某个点开始,使用 SourceDataLine,您必须从音频输入行读取并丢弃数据,直到到达所需的起始点”。你是怎样做的 ?当我使用“SourceDataLine”方法时,我的启动方法是一个带有 line.write(bytes, 0, bytesreads); 的循环。将声音指向扬声器。
那么,您如何阅读和丢弃?我没有找到任何“读取”方法。
【问题讨论】:
-
可以从 AudioInputStream 中逐步读取声音数据吗?当您以这种方式读取数据时,只需一遍又一遍地将其读入变量(覆盖),直到到达所需的起点。然后才开始将数据从 AIS 传送到 SourceDataLine 写入命令。此链接的 Java 教程中有 AudioInputStream -> SourceDataLine 的代码示例。 docs.oracle.com/javase/tutorial/sound/converters.html 搜索短语“做一些有用的事情”,它应该会让您进入一个好的代码示例的评论(页面上的第一个完整代码示例)。
-
太棒了!!!你的解决方案是完美的。我将放弃音频剪辑的解决方案。当我在 Linux 上使用 openJDK 时,它似乎太复杂了。而且您的解决方案效果很好。所以,谢谢!