Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
517 views
in Technique[技术] by (71.8m points)

audio - Java play multiple Clips simultaneously

So my application should play the WAV file every time I click on the panel. But the problem right now is, it waits for the first one to finish before it plays the second one. I want to be able to have them play simultaneously.

The reason I put Thread.sleep(500) is because if I don't, then it won't play the sound at all :(

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

Update: Okay so I got them to play simeutaneously, but I want to make the the thread close when the Clip is done playing, instead of making the thread wait 500ms

How can I do that?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I have always run multiple sounds like this. I don't spawn a new thread as I guess javaSound already runs clips in an another threads. Main "game loop" may continue doing its own stuff. App may register listeners for callbacks or use getters to see what clips are doing.

Sometimes if we are to make multimedia or game application its easier to just use getters. Running gameloop 30-60fps gives enough granularity for most cases and we have a total control of what happens and when. This little testapp playbacks two wav files, first is run once, second is started after 3sec, second loops.

// 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;
    }

}

See JavaSound documentation for more information.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...