Java:使用 AudioClips 或 Clips 一次播放 multibleSounds

Posted

技术标签:

【中文标题】Java:使用 AudioClips 或 Clips 一次播放 multibleSounds【英文标题】:Java: Using AudioClips or Clips to play multibleSounds at once 【发布时间】:2016-10-14 21:56:11 【问题描述】:

我想要一个****单独的班级****来播放声音,我想调用那个班级来播放声音,但是如果有更好的方法,请告诉我。


故事(可跳过):

首先,我使用了存储在最终静态中的 AudioClip,每次我需要播放声音时都会调用它。对于像背景音乐这样的单一的东西,这是完美的,但如果我想一次多次使用声音,比如我的炮塔射击,他们有时会完美地播放声音,有时会重新启动或完全取消。 然后我在阅读了一些帖子后切换到 Clips,并且有人在使用教程后通过 doin Clips 找到了解决方案。


声音等级:

package Game.main;

import java.net.URL;

import javax.sound.sampled.AudioInputStream;

import javax.sound.sampled.Audiosystem;

import javax.sound.sampled.Clip;

import javax.sound.sampled.DataLine;

import javax.sound.sampled.Mixer;

public class Sound 
    public static final Sound backgroundMusic4 = new Sound("/backgroundMusic4.wav");
    public static final Sound blockDestroy = new Sound("/blockDestroy.wav");
    public static final Sound bulletHit = new Sound("/bulletHit.wav");
    public static final Sound button = new Sound("/button.wav");
    public static final Sound camera = new Sound("/camera.wav");
    public static final Sound teleporter = new Sound("/teleporter.wav");
    public static final Sound turretShot = new Sound("/turretShot.wav");
    public static final Sound walking = new Sound("/walking.wav");

    public static Clip clip;

    public Sound(String fileLocation)
        Mixer.Info[] mixInfos = AudioSystem.getMixerInfo();

        Mixer mixer = AudioSystem.getMixer(mixInfos[0]);

        DataLine.Info dataInfo = new DataLine.Info(Clip.class, null);

        try
            clip =(Clip) mixer.getLine(dataInfo);
        catch(Exception e)
            e.printStackTrace();
        

        try
            URL soundURL = getClass().getResource(fileLocation);
            AudioInputStream audioStream = AudioSystem.getAudioInputStream(soundURL);
            clip.open(audioStream);
        catch(Exception e)
            e.printStackTrace();
        
    

    public void play()
        clip.loop(clip.LOOP_CONTINUOUSLY);
    

    public void playOnce()
        clip.start();
    

    public void stop()
        clip.stop();
    


炮塔类(例如)[只有最后一个方法“shoot()”重要]:

package Game.main.IngameObjects;

import java.applet.AudioClip;
import java.awt.Graphics;
import java.awt.Rectangle;

import Game.main.Controller;
import Game.main.Game;
import Game.main.GameObject;
import Game.main.Sound;
import Game.main.Textures;
import Game.main.classes.EntityC;

public class Turret extends GameObject implements EntityC

    private boolean activated;
    private String direction;
    private Game game;
    private Textures tex;
    private Camera activationCam;
    private Controller c;

    private long lastShot=0;

    public Turret (double x, double y, Textures tex, Game game, Controller c, String direction)
        super(x,y);
        this.game=game;
        this.tex=tex;
        this.c=c;
        if(!direction.equalsIgnoreCase("up") && !direction.equalsIgnoreCase("down") && !direction.equalsIgnoreCase("left") && !direction.equalsIgnoreCase("right"))
            System.err.println("ERROR 1: Wrong Direction in Constructor in Class \"java.Game.main.IngameObjects.Camera\"");
            System.exit(1);
        else
            this.direction=direction;
        
    

    public Turret (double x, double y, Textures tex, Game game, Controller c , Camera cam, String direction)
        super(x,y);
        this.game=game;
        this.tex=tex;
        this.c=c;
        if(!direction.equalsIgnoreCase("up") && !direction.equalsIgnoreCase("down") && !direction.equalsIgnoreCase("left") && !direction.equalsIgnoreCase("right"))
            System.err.println("ERROR 1: Wrong Direction in Constructor in Class \"java.Game.main.IngameObjects.Camera\"");
            System.exit(1);
        else
            this.direction=direction;
        
        this.activationCam=cam;
    

    public void tick() 
        if(activationCam==null)
            shoot();
        else if(activationCam.getActivated())
            shoot();
        
    

    public void render(Graphics g) 
        if(activated)
            if(direction.equalsIgnoreCase("up"))
                g.drawImage(tex.turretActi.get(0), (int)x, (int)y, null);
            else if(direction.equalsIgnoreCase("down"))
                g.drawImage(tex.turretActi.get(1), (int)x, (int)y, null);
            else if(direction.equalsIgnoreCase("left"))
                g.drawImage(tex.turretActi.get(2), (int)x, (int)y, null);
            else if(direction.equalsIgnoreCase("right"))
                g.drawImage(tex.turretActi.get(3), (int)x, (int)y, null);
            
        else
            if(direction.equalsIgnoreCase("up"))
                g.drawImage(tex.turretDeac.get(0), (int)x, (int)y, null);
            else if(direction.equalsIgnoreCase("down"))
                g.drawImage(tex.turretDeac.get(1), (int)x, (int)y, null);
            else if(direction.equalsIgnoreCase("left"))
                g.drawImage(tex.turretDeac.get(2), (int)x, (int)y, null);
            else if(direction.equalsIgnoreCase("right"))
                g.drawImage(tex.turretDeac.get(3), (int)x, (int)y, null);
            
        
    

    public Rectangle getBounds() 
        return new Rectangle((int)x, (int)y, 32, 32);
    

    public double getX() 
        return x;
    

    public double getY() 
        return y;
    

    public void activate() 
        activated=true;
    

    public void deactivate() 
        activated=false;
    

    public boolean getActivated() 
        return activated;
    

    public void setX(double x) 
        this.x=x;
    

    public void setY(double y) 
        this.y=y;
    

    public void shoot()
        if(System.currentTimeMillis() - lastShot >= 1000)
            Sound.turretShot.playOnce();
            lastShot = System.currentTimeMillis();
            c.addEntity(new Bullet(x,y,game,tex,c,direction));
        
    

现在我遇到的问题是炮塔射击一次,声音播放然后消失(示例视频:https://youtu.be/q8TR2nR8hUI)。我试图给每个对象自己的声音剪辑,但这非常浪费,上次它把我的滴答声和 fps 减少到每 5 秒左右 1 次。

这就是为什么我想寻求解决方案或一些有用的想法和代码。

我对字节数组和 dataStreamOutput 进行了修改,或者我可以克隆剪辑,但我无法让其中任何一个工作。

对不起,我的英语有点糟糕,我是德国人,所以请忽略任何错误(除非你看不懂)

【问题讨论】:

"只有最后一个方法 "shoot()" 很重要" 只有 minimal reproducible example 得到了很好的关注。删除不相关的代码并将其全部压缩到一个源文件中。 Generate some simple sounds at run-time. 如果你想同时多次播放同一个声音,你必须创建多个Clip对象。没有办法解决这个问题。 【参考方案1】:

Java 剪辑未设置为并发播放。充其量,这通常是这样做的,你可以拿一个正在播放的剪辑并将其重置为开始并重新启动它(即,在它完成之前中断它)。下一个合乎逻辑的选择是实例化 Clip 的多个副本(正如 VGR 的评论中所建议的那样)并编写一层代码来管理这些实例。

有几个库允许同时播放等效剪辑。 TinySound 可通过 github 公开获得。开发人员在 java-gaming.org 上有一个关于它的主要线程。那里的一些成员成功地使用了这个库。

我一直在开发自己的声音库,它包括对等价剪辑的并发播放。不过,我还没有打开我的资源。但是,如果您想探索编写自己的代码来执行此操作,我很高兴在这里或 java-gaming.org 上的一个线程上回复。基本计划是将数据存储在一个数组中(可以是字节,也可以是 PCM 法线或其他形式),并通过设置为从该数据文件读取的 SourceDataLine (SDL) 进行播放。还可以选择通过单个 SDL 输出线运行其中的几个(在输出之前将它们混合在一起)或为每个提供自己的 SDL。设置这一切需要一些工作,因此许多人更喜欢找到一个库。

【讨论】:

以上是关于Java:使用 AudioClips 或 Clips 一次播放 multibleSounds的主要内容,如果未能解决你的问题,请参考以下文章

我们可以使用java中的Clip库以不同的频率播放歌曲吗

播放声音剪辑的 Java 问题

Java 使用 Clip 和 Try - with - resources 块,结果没有声音

Java:快速淡入淡出 javax.sound.sampled.Clip 的增益

打开stable diffusion webui时,提示缺少clip或clip安装不上的解决方案(windows下的操作)

设置 Java Clip 的音量