这个事件是否可以在JSlider中实现?此外,是否可以将滑块移动到音频文件中的某个点?为了精心设计,用户可以将滑块拖动到JSlider中的任何一点,这会导致回放到"倒带"或"跳过"。
答案 0 :(得分:1)
在这种情况下,你谷歌。不,我是认真的。
我使用了来自java wav player adding pause and continue.和How do I get a sound file's total time in Java?的答案,并将它们组合成一个解决方案,允许JSlider
显示当前播放位置并更改当前播放位置。
在尝试解决此类问题时要记住的重要事项是 - 您不太可能找到完全匹配的解决方案,并且您将不得不调整一些想法以满足您的需求。
以下"可能"看起来像一个完全承诺的系统,它只是一个示范 - 它需要大量额外的工作和管理才能使其灵活和健壮 - 这是我要让你弄清楚的。
核心功能如下......
AudioInputStream ais = null;
try {
File file = new File(...);
ais = AudioSystem.getAudioInputStream(file);
format = ais.getFormat();
frameCount = ais.getFrameLength();
duration = ((double) frameCount) / format.getFrameRate();
clip = AudioSystem.getClip();
clip.open(ais);
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
ex.printStackTrace();
}
这基本上加载音频文件,获取frameCount
并使用它来计算持续时间(以秒为单位)。然后创建一个Clip
,可用于播放音频文件。
从那里开始,重置只是在播放音频时监听framePosition
(我使用Swing Timer
)并更新状态。
当用户更改JSlider
时,只需将framePosition
设置为所需的框架
例如......
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineEvent.Type;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JSlider slider = new JSlider(0, 100);
private long frameCount;
private double duration;
private AudioFormat format;
private Clip clip;
private JLabel currentFrame;
private JLabel currentDuration;
private boolean playing = false;
private Timer playTimer;
private boolean ignoreStateChange = false;
public TestPane() {
AudioInputStream ais = null;
try {
File file = new File(System.getProperty("user.home") + "/Library/Application Support/Steam/Steam.AppBundle/Steam/Contents/MacOS/friends/voice_hang_up.wav");
ais = AudioSystem.getAudioInputStream(file);
format = ais.getFormat();
frameCount = ais.getFrameLength();
duration = ((double) frameCount) / format.getFrameRate();
clip = AudioSystem.getClip();
clip.open(ais);
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {
ex.printStackTrace();
}
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
setLayout(new GridBagLayout());
add(slider, gbc);
slider.setValue(0);
add(new JLabel("Total Frames: " + frameCount), gbc);
add(new JLabel("Total Duration: " + duration), gbc);
currentFrame = new JLabel("Current frame: 0");
currentDuration = new JLabel("Current duration: 0");
add(currentFrame, gbc);
add(currentDuration, gbc);
JButton action = new JButton("Play");
action.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (!playing) {
int frame = getDesiredFrame();
if (frame >= frameCount) {
frame = 0;
}
clip.setFramePosition(frame);
clip.start();
action.setText("Stop");
playing = true;
playTimer.start();
} else {
clip.stop();
action.setText("Play");
playing = false;
playTimer.stop();
}
}
});
clip.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType().equals(Type.STOP)
|| event.getType().equals(Type.CLOSE)) {
action.setText("Play");
playing = false;
playTimer.stop();
updateState();
}
}
});
add(action, gbc);
playTimer = new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateState();
}
});
Timer delayedUpdate = new Timer(250, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int frame = getDesiredFrame();
clip.setFramePosition(frame);
double time = getCurrentTime();
currentFrame.setText("Current frame: " + frame);
currentDuration.setText("Current duration: " + time);
}
});
delayedUpdate.setRepeats(false);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if (ignoreStateChange) {
return;
}
delayedUpdate.restart();
}
});
}
public void updateState() {
ignoreStateChange = true;
int frame = clip.getFramePosition();
int progress = (int) (((double) frame / (double) frameCount) * 100);
slider.setValue(progress);
currentFrame.setText("Current frame: " + getDesiredFrame());
currentDuration.setText("Current duration: " + getCurrentTime());
ignoreStateChange = false;
}
public double getCurrentTime() {
int currentFrame = clip.getFramePosition();
double time = (double) currentFrame / format.getFrameRate();
return time;
}
public int getDesiredFrame() {
int progress = slider.getValue();
double frame = ((double) frameCount * ((double) progress / 100.0));
return (int) frame;
}
}
}