当前位置: 首页 > 知识库问答 >
问题:

播放整个音频剪辑时出现问题

岳杜吟
2023-03-14

我在带有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个答案

楚修为
2023-03-14

你是否意识到并考虑到这样一个事实:当一个剪辑被播放时(通过start()方法),播放代码的线程是一个守护进程?与普通线程不同,守护线程不会阻止Java程序关闭。如果你的程序在声音执行完之前就结束了,守护进程状态线程也会结束,即使它没有结束。

您是否尝试运行示例代码SoundClipTest或SoundeffectDemo?在我看来,一旦程序执行start()方法,SoundClipTest就会退出,而SoundeffectDemo将持续存在并允许声音完成播放。

**编辑1**

我刚刚注意到你把你的音效变成了enum。我以前从未见过这种方法。

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

gameSound.playExplosion();

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

private Clip explosion;
private Clip cannon;

GameSound构造函数将具有:

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

和GameSound将有方法:

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

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

这种方法可能会更好(随着代码变得越来越复杂,很容易添加到GameSound中),并且应该不会太难编码。我很想知道改变这个计划是否能解决问题。

** 编辑 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();
    }
}

这是一个简单的摆动按钮,调用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());
    }
}

当然,这一切都假设有一个名为“资源”的子文件夹,其中包含爆炸式 SFX。

 类似资料:
  • 问题内容: 我编写了一个简单的类,可以在一个简单的游戏中播放音频文件。它适用于诸如枪声或爆炸声之类的小声音,但是当我尝试将其用于背景音乐时,出现以下错误:“未能分配剪辑数据:请求的缓冲区太大。” 我假设这意味着文件太大,但是如何解决呢?资源: 问题答案: 使用。这是我玩12-18分钟(或更多1分钟)的MP3的课堂。 它要求在运行时类路径上实际加载MP3格式的声音,但这不是重点。重点是: 会将声音文

  • 我有一个计划线程,大约每半秒运行一次,每次播放一个音频剪辑,在每个循环之前对剪辑调用,以便再次: 但第一次之后就不再播放了。代码运行,但声音不播放。有什么想法吗?

  • 我有一个iOS应用程序,它用一个AVPlayer播放背景配乐,用第二个AVPlayer“在顶部”播放其他声音剪辑。(声音剪辑是从互联网上流式传输的,因此需要AVPlayer。)问题是,当第二个AVPlayer开始播放时,它会导致背景AVPlayer停止几分之一秒,类似于此评论中描述的: 使用 AV 播放器播放多个音频文件 我正在用这种方法准备音频剪辑: …然后调用当我想听到每个声音时。 当我设置音

  • 好吧,标题说明了一切,我尝试使用javax播放wav文件。声音,什么也没有发生。我试过很多不同的文件,但没有任何运气。

  • 本文向大家介绍Android MediaPlayer 音频倍速播放 调整播放速度问题,包括了Android MediaPlayer 音频倍速播放 调整播放速度问题的使用技巧和注意事项,需要的朋友参考一下 现在市面上的很多音视频App都有倍速播放的功能,例如把播放速度调整为0.5、1.5、2倍等等。 从Android API 23 (Android M)开始,MediaPlayer支持调整播放速度。

  • 我正在开发一个具有许多JButton对象的程序,我希望每个对象都对应于自己的文件。另外,我希望声音的工作方式是,它们可以与其他按钮的声音重叠,但它不能与自身重叠(在播放声音时单击按钮将重新启动声音)。 我尝试使用单个Clip对象,但我无法完成上面所述的内容。因此,我不得不为每个按钮声明一个新的Clip对象,但我觉得这对我的问题来说是一个相当低效的解决方案。 我怎样才能以最有效的方式完成我在第一段中