【问题标题】:I Have A Problem With Playing Multiple Audios At Once我在一次播放多个音频时遇到问题
【发布时间】:2020-10-21 01:03:42
【问题描述】:
package me.Warrior;
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
public class SoundPlayer {
    static URL path=null;
    static AudioInputStream inputStream; 
    public static Clip clip;
    public static synchronized void Play(final String url,float Volume) { 
          new Thread(new Runnable() {
            public void run() {
              try {
                  clip = AudioSystem.getClip();
                  URL resource = getClass().getClassLoader().getResource(url);
                path=resource;
                inputStream = AudioSystem.getAudioInputStream(path);
                clip.open(inputStream);
                setVolume(Volume,clip);
                clip.start();
              } catch (Exception e) {
              }
            }
          }).start();
        }

    public static void setVolume(float Volume,Clip clip) {
         FloatControl gainControl = 
                    (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
         float dB=(float)(Math.log(Volume)/Math.log(10)*20);
                gainControl.setValue(dB);
    }
}

**所以我在我的游戏中播放了很多音频,我认为有问题,而如果我在同一 60 秒内播放两个音频,则会弹出错误并冻结游戏半秒

  1. 我能否以某种方式确定剪辑何时开始播放,以便我可以停止下一个剪辑 (我想查看剪辑何时开始播放,而不是何时播放) (但这对我来说也很有趣)

  2. 有没有比这更好的播放音频的方法

【问题讨论】:

    标签: java audio


    【解决方案1】:

    剪辑并非设计为同时打开和开始。在从磁盘加载整个文件之前,它们甚至不会开始播放。我猜如果您尝试使用所显示的代码几乎同时播放两个文件,文件加载延迟问题将会更加复杂。

    相反,您可以(并且应该)做的是预先初始化您的 Clips,包括打开它们,并将它们保存在内存中,以备不时之需。当需要播放它们时,您应该只执行以下操作:

    public void playMyAudioFX() {
        myAudioFX.setFramePosition(0);
        myAudioFX.start();
    }
    

    通过将帧位置设置为开始,您可以重复使用Clip,而无需反复加载。

    但是,如果您不想用完保存音频的内存,请使用SourceDataLine 进行播放。在SourceDataLine 开始播放之前,只从磁盘加载一个缓冲区的数据(而不是等待整个文件加载)。

    这两种文件类型都不能很好地用于并发播放(同时播放两次或更多次),但如果您正确执行上述操作,声音应该可以正常开始。如果仍然存在问题,或者您对 MASTER_GAIN 行的笨拙不满意,可以尝试几个简单的库。一个叫TinySound,另一个叫AudioCue。我偏爱后者(因为我写了它),它确实可以处理并发播放,并且比Clip具有更细粒度的实时音量控制。

    这是一个非常普遍的问题,其中很多原因是关于音频的 Java 教程很难阅读,所以人们会错过这些重要的细节。我想许多其他的志愿教程作者在强调最佳实践方面做得并不好,他们只满足于播放声音然后就这样了。

    编辑:重新阅读您的问题——如果您想进一步研究该方面,有一个名为 LineListener 的类可以接收关于 Clip 何时开始或停止的通知。

    另外,如果您收到实际的错误消息,请发布它们!这将有助于确定原因和解决方案。

    【讨论】:

    • 谢谢,我不知道,我试试
    • 是的,我不介意浪费一点内存,毕竟这是一个小游戏
    • 这意味着我应该预先打开/加载所有音频并在必要时从头开始播放(因为加载需要很多时间,这就是我的游戏冻结的原因,如果我理解正确的话)跨度>
    • 很难确定,但根据您的描述,在我看来这可能是问题所在。你必须尝试一下,看看它是否有帮助。剪辑被设计为在内存中保持打开状态,因此您将更改为更好的练习。我会考虑将 FloatControl 设为类级字段变量,而不是本地变量。但重新初始化它的成本远不及重新初始化剪辑的成本。此外,我还添加了一些与跟踪音频事件和错误消息有关的小修改。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多