2013-04-06 28 views
1

我有一个wav音频文件。我知道如何在java中使用AudioImputStream播放它。我学会了创建一个jslider。现在,我必须将滑块用作音频的进度条,例如音频播放,因此滑块向前移动。如果用户改变滑块的位置,则音频文件必须从该位置播放。如何用音频文件更新jslider作为进度条

我是新来的java,可能会有一些错误,我可能不会在帖子中。请忽略它们

所以我被困在更新音轨时滑块得到更新。我尝试添加changeListner滑块,但我无法让它工作。

下面的代码

import java.io.File; 
import java.util.Timer; 
import java.util.TimerTask; 

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.swing.JFrame; 
import javax.swing.JSlider; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 


public class audio { 

public static void main(String args[]) 
{ 

try { 
final JFrame f=new JFrame(); 
File yourFile; 
AudioInputStream stream; 
AudioFormat format; 
DataLine.Info info; 
final Clip clip; 
yourFile = new File(fileName); 

stream = AudioSystem.getAudioInputStream(yourFile); 
format = stream.getFormat(); 
final long frames =stream.getFrameLength(); 
final double durationInSeconds = (frames+0.0)/format.getFrameRate(); 
final JSlider slider=new JSlider(0,(int) Math.round(durationInSeconds),0); 
info = new DataLine.Info(Clip.class, format); 
clip = (Clip) AudioSystem.getLine(info); 
clip.open(stream); 
clip.start(); 

f.add(slider); 
f.pack(); 
f.setLocationRelativeTo(null); 
f.setVisible(true); 
TimerTask timerTask=new TimerTask(){ 

@Override 
public void run() { 
// TODO Auto-generated method stub 
{ 
double timeNow=(durationInSeconds*clip.getFramePosition())/frames; 
slider.setValue((int)Math.round(timeNow)); 
f.repaint(); 
} 

} 
}; 
Timer timer = new Timer("MyTimer");//create a new Timer 

timer.scheduleAtFixedRate(timerTask, 30, 30);//this line starts the timer at the same time its executed 


} 

catch (Exception e) { 
System.out.println(e); 
} 


} 
} 
+0

你有没有试过至少有的东西?如果是这样,请在此发布代码,以便可以改进。我们不会为你做所有的**工作。 – D180 2013-04-06 20:16:17

+0

我不知道你到目前为止有什么,但我会假设你使用DataLine而不是Clip来在线程中播放音频。从那里它简单的数学。你从0%开始,声音文件的结尾是100%。查找音频文件的长度,然后在音频文件播放时跟踪您所在音频文件的距离,并相应地从线程调整滑块。我相信它会是currentPositionInTrack/totalLengthOfTrack * 100之类的东西,希望我没有错,但是应该给你完成的比例。如果你需要更多的帮助,你必须更具体。 – 2013-04-06 20:28:23

+0

因此解决了更新滑块的问题。我使用了一个定时器,在该定时器中,我获取当前音轨的帧,将其转换为持续时间并每30毫秒更新一次定时器。 – jas 2013-04-06 21:29:45

回答

0

所以更新滑块的问题就解决了。我使用了一个定时器,在该定时器中,我获取当前音轨的帧,将其转换为持续时间并每30毫秒更新一次定时器。

但我仍然坚持如何更新滑块的更新轨道。

我不明白你为什么要手动更新曲目:如果你已经可以获得音轨的当前帧,它必须更新。所以,解决你可能会面临的问题:

如果滑块没有更新正确,我发现从组件删除它,然后更新它,然后重新添加它的工作:

@Override 
public void run() { 
// TODO Auto-generated method stub 
{ 
f.remove(slider); 
double timeNow=(durationInSeconds*clip.getFramePosition())/frames; 
slider.setValue((int)Math.round(timeNow)); 
f.add(slider); 
f.repaint(); 
} 

如果你想手动更新您的剪辑,使用clip.setFramePosition(int frames)

0

什么我观察,当我运行代码如下:JSlider的该会更新,但只有每秒一次(或稍快)。

我不知道这是否是答案,但也许值得考虑。有时调用重画是“折叠”。 EDT可能是这样的情况,即对每次重绘呼叫都没有反应,而是决定相邻的呼叫足够相似以致它们可以折叠成更少的重绘。我注意到,如果我在TimerTask中放置一个System.out.println(timeNow),则每秒钟会在控制台上打印大约33个timeNow,我认为这是您希望JSlider更新的速率。

我发现,如果我有一个单独的类中的计时器(以及它的TimerTask),并从那里调用重绘,那么EDT崩溃重绘的可能性会更小。我记得在JPanel上放置一个定时器之前,曾经称之为“自己的”重绘给了我一个类似的“崩溃的EDT”结果。

我不知道背后的确切机制或理论。所以这可能不是最好的建议。但是将计时器代码分离出来可能还是值得的。要做到这一点,你还必须传递给这个类的JFrame和Clip副本。