Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
189 views
in Technique[技术] by (71.8m points)

java - How to set a JSlider to the duration of an audio file?

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".

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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;
        }

    }

}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...