java - 如何在 Java Sound API 中重新启动播放音频?

标签 java swing audio enums

我编写了这两个类来测试如何使用 Java Sound API:

enum SoundEffect:枚举封装了我使用的所有声音。

Class SoundEffectDemo :在 Swing 应用程序中测试 SoundEffect 枚举

当我单击 SoundEffectDemo 的任何按钮(调用、响铃、忙碌)时,声音开始播放。当我单击“停止声音”按钮时,声音就会停止。 但是当我第二次点击SoundEffectDemo的任意按钮(CALLING、RING、BUSY)时,没有任何声音。

import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;

public enum SoundEffect  {

    BUSY("resources/phone-busy.wav"),   
    CALLING("resources/phone-calling.wav"),         
    DISCONNECT("resources/phone-disconnect.wav"),
    RING("resources/telephone-ring.wav");  

    // Each sound effect has its own clip, loaded with its own sound file.
    private Clip clip;
    private URL url;
    private AudioInputStream audioInputStream;

    // Constructor to construct each element of the enum with its own sound file.
    SoundEffect(String soundFileName) {
        try {
            // Use URL (instead of File) to read from disk and JAR.
            this.url = this.getClass().getClassLoader().getResource(soundFileName);
            // Set up an audio input stream piped from the sound file.
            this.audioInputStream = AudioSystem.getAudioInputStream(url);
            // Get a clip resource.
            clip = AudioSystem.getClip();
            // Open audio clip and load samples from the audio input stream.
            clip.open(audioInputStream);
            clip.addLineListener( new LineListener() {
                public void update(LineEvent evt) {
                    if (evt.getType() == LineEvent.Type.STOP) {
                        evt.getLine().close();
                    }
                }
            });
        } catch (UnsupportedAudioFileException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
    }

    // Play or Re-play the sound effect from the beginning, by rewinding.
    public void play() {

        clip.loop(Clip.LOOP_CONTINUOUSLY); 

    }

    public void stop(){

        clip.stop();   // Stop the player if it is still running
    }

    // Optional static method to pre-load all the sound files.
    static void init() {
        values(); // calls the constructor for all the elements
    }

    public boolean isActive(){

        return clip.isActive();
    }

    public boolean isOpen() {

        return clip.isOpen();
    }

    public void setFramePosition() {
        clip.setFramePosition(0);

    }

}




import java.awt.*;
import java.awt.event.*;

import javax.sound.sampled.LineEvent;
import javax.swing.*;

// Testing the SoundEffect enum in a Swing application
@SuppressWarnings("serial")
public class SoundEffectDemo extends JFrame {


    // Constructor
    public SoundEffectDemo() {
        // Pre-load all the sound files


        // Set up UI components
        Container cp = this.getContentPane();
        cp.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));

        JButton btnSound1 = new JButton("CALLING");
        btnSound1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                SoundEffect.CALLING.play(); 
            }
        });
        cp.add(btnSound1);

        JButton btnSound2 = new JButton("RING");
        btnSound2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                SoundEffect.RING.play();
            }
        });
        cp.add(btnSound2);

        JButton btnSound3 = new JButton("BUSY");
        btnSound3.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                SoundEffect.BUSY.play();
            }
        });
        cp.add(btnSound3);

        JButton btnSound4 = new JButton("Stop Sound ");
        btnSound4.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                for(SoundEffect value : SoundEffect.values()){
                    if(value.isActive()){
                        value.stop();
                    }
                }

            }
        });
        cp.add(btnSound4);


        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("Test SoundEffct");
        this.pack();
        this.setVisible(true);
    }

    public static void main(String[] args) {
        new SoundEffectDemo();
    }
}

最佳答案

clip.addLineListener( new LineListener() {
    public void update(LineEvent evt) {
        if (evt.getType() == LineEvent.Type.STOP) {
            evt.getLine().close();
        }
    }
});

这可能不是您想要做的事情,在收到停止事件时关闭线路。关闭剪辑后,您需要重新打开它才能再次播放。

考虑到您正在做的事情,您可能根本不需要关闭线路。调用 close 表示您已经完成了。

参见Line#closeAutoCloseable#close .

对于您的停止事件,更合适的临时操作是 drainflush 。如果您想“重置”它,则可以将帧位置设置为 0。

因此删除对 close 的调用并执行类似的操作

public void stop() {
    clip.stop();
    clip.flush();
    clip.setFramePosition(0);
}

顺便说一句,我注意到您没有在事件调度线程上启动 Swing 应用程序。您应该始终initialize your GUI with a call to invokeLater ,例如:

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            new SoundEffectDemo();
        }
    });
}

Swing 的线程安全非常重要,因为不这样做可能会导致难以诊断的细微错误。

关于java - 如何在 Java Sound API 中重新启动播放音频?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23029098/

相关文章:

java - 从流中获取最后 n 个元素

java - Java 和 PHP 之间带盐的 SHA-512 不匹配

java - 在 BorderLayout.CENTER 中保留 JButton 的大小

java - Web 界面或图形用户界面

javascript - 如何在浏览页面时保持音频播放?

java - float Action 按钮点击时会跳转

java - 重现javaFX焦点效果

java - 将 JscrollPane 添加到 Matlab 内的 JSPlitPane 中时,JscrollPane 不会收到 mousewheelevent

javascript - MediaRecorder API - 自动录制

javascript - 在客户端使用 NodeJs 播放音频文件