1

我有一个 wav 音频文件。我知道如何在 java 中使用 AudioImputStream 播放它。我学会了创建一个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);
}


}
}
4

2 回答 2

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)

于 2013-11-11T23:46:35.373 回答
0

当我运行您的代码时,我观察到以下内容:JSlider 确实更新,但每秒只有一次(或稍快)。

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

我发现如果我在一个单独的类中有一个 Timer(连同它的 TimerTask)并从那里调用重绘,EDT 折叠重绘的可能性会更小。我记得有一次在 JPanel 上放置 Timer 之前,将它称为“它自己的”重绘给了我类似的“折叠 EDT”结果。

我不知道这背后的确切机制或理论。所以这可能不是最好的建议。但是仍然值得将计时器代码分离到自己的类中。为此,您还必须将 JFrame 和 Clip 的副本传递给此类。

于 2013-11-12T01:12:33.383 回答