繁体   English   中英

如何使用音频文件作为进度条更新jslider

[英]How to update jslider with an audio file as progress bar

我有一个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);
}


}
}

因此解决了更新滑块的问题。 我使用了一个计时器,在该计时器中,我可以获取当前的音轨帧,将其转换为持续时间,并每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)

运行您的代码时,我观察到的内容如下:JSlider可以更新,但每秒仅更新一次(或稍快一点)。

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

我发现如果我在单独的类中有一个Timer(及其TimerTask)并从那里调用重绘,那么EDT折叠重绘的可能性就较小。 我记得在将Timer放置在JPanel上之前曾经有一次,它在调用它的“自己的”重新绘制时得到了类似的“折叠的EDT”结果。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM