Java 同时播放多个 Clips

Posted

技术标签:

【中文标题】Java 同时播放多个 Clips【英文标题】:Java play multiple Clips simultaneously 【发布时间】:2014-01-18 23:14:26 【问题描述】:

所以我的应用程序应该在我每次点击面板时播放 WAV 文件。但现在的问题是,它要等待第一个完成,然后再播放第二个。我希望能够让它们同时播放。

我放 Thread.sleep(500) 的原因是因为如果我不放,那么它根本不会播放声音:(

    import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.Audiosystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JFrame;

@SuppressWarnings("serial")
public class SoundEffectPlayer extends JFrame 

    /*
     * Jframe stuff
     */
    public SoundEffectPlayer() 
        this.setSize(400, 400);
        this.setTitle("Mouse Clicker");
        this.addMouseListener(new Clicker());


        this.setVisible(true);
    

    private class Clicker extends MouseAdapter 
        public void mouseClicked(MouseEvent e) 
            try 
                playSound(1);
             catch (InterruptedException e1) 
                // TODO Auto-generated catch block
                e1.printStackTrace();
            
        
    

    /*
     * Directory of your sound files
     * format is WAV
     */
    private static final String DIRECTORY = "file:///C:/Users/Jessica/Desktop/audio/effects/sound 1.wav";

    /*
     * The volume for sound effects
     */
    public static float soundEffectsVolume = 0.00f;

    /*
     * Loads the sound effect files from cache
     * into the soundEffects array.
     */
    public void playSound(int ID) throws InterruptedException 

        try 
            System.out.println("playing");
            Clip clip;
            URL url = new URL(DIRECTORY);
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
            clip = AudioSystem.getClip();
            clip.open(audioInputStream);
            clip.setFramePosition(0);
            FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
            gainControl.setValue(soundEffectsVolume);

            clip.start();   
            System.out.println("played");
            Thread.sleep(3000);
            System.out.println("closing");

         catch (MalformedURLException e) 
            System.out.println("Sound effect not found: "+ID);
            e.printStackTrace();
            return;
         catch (UnsupportedAudioFileException e) 
            System.out.println("Unsupported format for sound: "+ID);
            return;
         catch (LineUnavailableException e) 
            e.printStackTrace();
            return;
         catch (IOException e) 
            e.printStackTrace();
            return;
           
    
    public static void main(String[] args) throws InterruptedException 
        new SoundEffectPlayer();
    

更新:好的,所以我让它们同时播放,但我想在 Clip 播放完毕后关闭线程,而不是让线程等待 500 毫秒

我该怎么做?

【问题讨论】:

看起来您正在事件调度线程上播放音频,这基本上会冻结应用程序,直到音频完成。是这样吗?您可能想创建一个新线程来播放音频。你知道怎么做吗? How do I play two sounds at once?的可能重复 不,我是线程新手:c 我看到你是intending to ignore me。请注意,可以双向.. 对不起,安德鲁,我的帖子冒犯了你,我没有回复,因为帖子被锁定了,我意识到这里不允许人们回答这个问题:| 【参考方案1】:

我总是像这样运行多个声音。我没有产生新线程,因为我猜 javaSound 已经在另一个线程中运行剪辑。主要的“游戏循环”可能会继续做自己的事情。应用可以注册回调监听器或使用 getter 来查看剪辑在做什么。

有时,如果我们要让多媒体或游戏应用程序更容易使用 getter。运行 gameloop 30-60fps 为大多数情况提供了足够的粒度,我们可以完全控制发生的事情和时间。这个小测试应用程序播放两个 wav 文件,第一个运行一次,第二个在 3 秒后启动,第二个循环。

// java -cp ./classes SoundTest1 clip1=sound1.wav clip2=sound2.wav
import java.util.*;
import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;

public class SoundTest1 

    public Clip play(String filename, boolean autostart, float gain) throws Exception 
        AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(filename));
        Clip clip = AudioSystem.getClip();
        clip.open(audioInputStream);
        clip.setFramePosition(0);

        // values have min/max values, for now don't check for outOfBounds values
        FloatControl gainControl = (FloatControl)clip.getControl(FloatControl.Type.MASTER_GAIN);
        gainControl.setValue(gain);

        if(autostart) clip.start();
        return clip;
    

    public static void main(String[] args) throws Exception 
        Map<String,String> params = parseParams(args);
        SoundTest1 test1 = new SoundTest1();

        Clip clip1 = test1.play(params.get("clip1"), true, -5.0f);
        Clip clip2 = test1.play(params.get("clip2"), false, 5.0f);

        final long duration=Long.MAX_VALUE;
        final int interval=500;
        float clip2IncGain=0.4f;
        for(long ts=0; ts<duration; ts+=interval) 
            System.out.println(String.format("clip1=%d/%d(%.2f), clip2=%d/%d(%.2f)"
                ,clip1.getFramePosition(), clip1.getFrameLength()
                ,((FloatControl)clip1.getControl(FloatControl.Type.MASTER_GAIN)).getValue()
                ,clip2.getFramePosition(), clip2.getFrameLength()
                ,((FloatControl)clip2.getControl(FloatControl.Type.MASTER_GAIN)).getValue()
            ));
            if (ts>6000 && !clip2.isRunning()) 
                clip2.setFramePosition(0);
                clip2.start();
            
            if (!clip1.isRunning()) 
                clip1.close();
            

            if(ts % 2000 == 0) 
                // values have min/max values, for now don't check for outOfBounds values
                FloatControl gainControl = (FloatControl)clip2.getControl(FloatControl.Type.MASTER_GAIN);
                float oldVal=gainControl.getValue();
                clip2IncGain = oldVal>=5.5 ? clip2IncGain*-1
                    : oldVal<=-5.5 ? clip2IncGain*-1
                    : clip2IncGain;
                gainControl.setValue(oldVal+clip2IncGain);
            

            Thread.sleep(interval);
        
    

    private static Map<String,String> parseParams(String[] args) 
        Map<String,String> params = new HashMap<String,String>();
        for(String arg : args) 
            int delim = arg.indexOf('=');
            if (delim<0) params.put("", arg.trim());
            else if (delim==0) params.put("", arg.substring(1).trim());
            else params.put(arg.substring(0, delim).trim(), arg.substring(delim+1).trim() );
        
        return params;
    


更多信息请参见JavaSound documentation。

【讨论】:

真的很好,但请您强调一下核心,好吗?所以更容易理解需要什么。 @user7185318 你的意思是添加一个关于发生了什么的 cmets 吗?我不确定这是否会增加真正的价值,因为这个测试应用程序真的已经很简单了。我也不知道JavaSound系统的内部细节。 是否需要所有这些代码?也许只需要同时播放两个声音文件。 @user7185318 是的,这就是您所需要的,实际上,如果您删除命令行参数,那就更少了。 : 一定不是 Clip clip=(Clip)AudioSystem.getLine(new DataLine.Info(Clip.class,audioInputStream.getFormat()));【参考方案2】:

尝试查看这个开源音板程序的源代码:DBoard。

您对使用MediaPlayer 类特别感兴趣。您可以使用

调用它
(new Thread(new MediaPlayer(PATHTOFILE)).start();

【讨论】:

以上是关于Java 同时播放多个 Clips的主要内容,如果未能解决你的问题,请参考以下文章

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

如何同时播放多个音频文件

Qt/C++ Multimedia Player Video Clips,多个视频小部件

在javascript中同时播放多个声音

同时播放多个音频

同时播放多个 SoundPool