有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java无法播放整个音频片段

我用javax.sound.sampled.Clip在游戏中播放音效(WAV文件)。但是,有2秒的效果并不是全部播放,只是部分播放。如果添加clip.loop(2),则声音会正确播放多次,即整整2秒钟。有什么问题,如何解决

package com.zetcode;

import java.io.IOException;
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JOptionPane;

public enum SoundEffect {

    EXPLODE("resources/explosion.wav"),
    HITGROUND("resources/impact.wav"),
    CANNON("resources/cannon.wav");

    private Clip clip;

    SoundEffect(String soundFileName) {
        try {
            URL url = this.getClass().getClassLoader().getResource(soundFileName);

            try (AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url)) {
                clip = AudioSystem.getClip();
                clip.open(audioInputStream);
            }
        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
            JOptionPane.showMessageDialog(null, "Cannot play sound", "Error",
                    JOptionPane.ERROR_MESSAGE);
        }
    }

    public void play() {

        if (clip.isRunning()) {
            clip.stop();
        }
        clip.setFramePosition(0);
        clip.start();
    }

    static void init() {
        values();
    }    
}

共 (1) 个答案

  1. # 1 楼答案

    您是否知道并解释了这样一个事实:当播放片段时(通过start()方法),播放代码的线程是一个守护进程?与常规线程不同,守护进程线程不会阻止Java程序关闭。如果程序在声音完成执行之前结束,则守护进程状态线程也会结束,即使它尚未完成

    您是否正在尝试运行示例代码SoundClipTest或SoundEffectDemo?在我看来,SoundClipTest将在程序执行start()方法后立即退出,而SoundEffectDemo将保持并允许声音完成播放


    **编辑1**


    我刚才注意到您已经将SoundEffect设置为枚举。我以前从未见过这种方法

    我使用的一种方法是创建一个名为GameSound的类,让它的构造函数分别预加载每个片段,并将它们保存在内存中,以便播放。然后,我创建了一个或多个播放方法

    gameSound.playExplosion();
    

    GameSound类将为每个声音效果提供实例变量

    private Clip explosion;
    private Clip cannon;
    

    游戏声音构造器应该有:

    URL url = this.getClass().getResource("resources/explosion.wav");
    AudioInputStream ais = AudioSystem.getAudioInputStream(url); 
    explosion = AudioSystem.getClip();
    explosion.open(ais);
    

    游戏声音会有一个方法:

    public void playExplosion()
    {
        if (explosion.isRunning()) {
            explosion.stop();
        }
        explosion.setFramePosition(0);
        explosion.start();
    }
    

    如果您喜欢让play方法获取一个参数,并在switch结构上使用该参数来选择要播放的声音,这也很好,特别是因为它消除了一些代码重复

    这种方法可能会更好(随着代码变得更复杂,很容易添加到游戏声音中),而且编写代码也不会太难。我很想知道改变这个计划是否能解决这个问题


    **编辑2**


    对不起,上面的代码有错误。我在制作以下示例时修复了它们。不过,有一种想法是,当我去听你链接的音效时,有几次爆炸一开始就被截断了。您是否在其他应用程序(如Windows Groove Music,或从您获得这些声音的网站)中播放了这些声音,并在代码中播放时验证了它们是否不同

    这是一个快速的“游戏声音”。我下载了爆炸+2。wav文件来自您的参考,因为它比其他文件长,并且有一个清晰的结尾,我正在参考它

    package stackoverflow.janbodnar;
    
    import java.io.IOException;
    import java.net.URL;
    
    import javax.sound.sampled.AudioInputStream;
    import javax.sound.sampled.AudioSystem;
    import javax.sound.sampled.Clip;
    import javax.sound.sampled.LineUnavailableException;
    import javax.sound.sampled.UnsupportedAudioFileException;
    
    public class GameSound {
    
        private final Clip explosion;
    
        public GameSound() throws LineUnavailableException, 
        IOException, UnsupportedAudioFileException
        {
            URL url = this.getClass().getResource(
                    "resources/Explosion+2.wav");
            AudioInputStream ais = AudioSystem.getAudioInputStream(url);
            explosion = AudioSystem.getClip();
            explosion.open(ais);
        }
    
        public void playExplosion()
        {
            if (explosion.isRunning()) {
                explosion.stop();
            }
            explosion.setFramePosition(0);
            explosion.start();
        }
    }
    

    这里有一个简单的Swing按钮,可以调用GameSound

    package stackoverflow.janbodnar;
    
    import java.io.IOException;
    
    import javax.sound.sampled.LineUnavailableException;
    import javax.sound.sampled.UnsupportedAudioFileException;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.SwingUtilities;
    
    public class GameSoundTest extends JFrame
    {
        private static final long serialVersionUID = 1L;
    
        private final GameSound gameSound;
    
        public GameSoundTest() throws LineUnavailableException,
        IOException, UnsupportedAudioFileException
        {
            gameSound = new GameSound();
    
            JButton button = new JButton("Play Explosion");
            button.addActionListener(e -> gameSound.playExplosion());
            getContentPane().add(button);
        }
    
        private static void createAndShowGUI()
        {
            JFrame frame;
            try 
            {
                frame = new GameSoundTest();
                frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
                frame.setBounds(0, 0, 200, 200);
                frame.setVisible(true);
            } 
            catch (LineUnavailableException | IOException 
                    | UnsupportedAudioFileException e) 
            {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args)
        {
            SwingUtilities.invokeLater(() -> createAndShowGUI());
        }
    }
    

    当然,所有这些都假设有一个名为“resources”的子文件夹,其中包含爆炸式SFX