Is this event possible to implement in a JSlider or not? Also, can one be able to move the slider to a certain point in the audio file? To Elaborate, the user can drag the slider to any point in the JSlider which causes the playback to "rewind" or "skip".
In situation like this, you google. No I'm serious.
I used the answer from java wav player adding pause and continue. and How do I get a sound file's total time in Java? and combined them into a solution which allows a JSlider
to display the current playback position AND change the current playback position.
The important thing to remember when trying to solve problems like this is - it's unlikely you will find an exact matching solution and you're going to have to adapt a number of ideas to meet your needs.
While the following "might" look like a fully fledge system, it's just a demonstration - it needs a lot of additional work and management to make it flexible and robust - this is something I'll leave you to figure out.
The core functionality is as follows...
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();
}
This basically loads a audio file, obtains the frameCount
and uses it to calculate the duration in seconds. It then creates a Clip
which can be used play the audio file.
From there, the reset is just about monitoring the framePosition
while the audio is been played (I use a Swing Timer
) and updating the state.
When the JSlider
is changed by the user, this simply sets the framePosition
to the desired frame
For example...
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;
}
}
}