disable other sounds in java

2019-07-19 23:20发布

I wrote a program in Java using the pi4j lib to make sound whenever a (physical) button is clicked. This program works, but it now plays all the sounds interchangeably. I want that when you click on 2,3,4 or more buttons you only hear one sound.

This is the code I hope you can help.

public class ButtonSoundsProject{
public static void main(String args[]) throws InterruptedException {
    System.out.println("Toy has been started!");

    // create gpio controller
    final GpioController gpio = GpioFactory.getInstance();

    // provision gpio pin #02 as an input pin with its internal pull down resistor enabled
    GpioPinDigitalInput[] pins = {
        gpio.provisionDigitalInputPin(RaspiPin.GPIO_00, PinPullResistance.PULL_DOWN),
        gpio.provisionDigitalInputPin(RaspiPin.GPIO_01, PinPullResistance.PULL_DOWN),
        gpio.provisionDigitalInputPin(RaspiPin.GPIO_02, PinPullResistance.PULL_DOWN),
        gpio.provisionDigitalInputPin(RaspiPin.GPIO_03, PinPullResistance.PULL_DOWN),
        gpio.provisionDigitalInputPin(RaspiPin.GPIO_04, PinPullResistance.PULL_DOWN),
        gpio.provisionDigitalInputPin(RaspiPin.GPIO_05, PinPullResistance.PULL_DOWN),};

    final ArrayList<String> soundList = new ArrayList<String>();
    soundList.add("/home/pi/Sounds/Sound1.wav");
    soundList.add("/home/pi/Sounds/Sound2.wav");
    soundList.add("/home/pi/Sounds/Sound3.wav");
    soundList.add("/home/pi/Sounds/Sound4.wav");
    soundList.add("/home/pi/Sounds/Sound5.wav");
    soundList.add("/home/pi/Sounds/Sound6.wav");
    soundList.add("/home/pi/Sounds/Sound7.wav");
    soundList.add("/home/pi/Sounds/Sound8.wav");
    soundList.add("/home/pi/Sounds/Sound9.wav");
    soundList.add("/home/pi/Sounds/Sound10.wav");
    soundList.add("/home/pi/Sounds/Sound11.wav");
    soundList.add("/home/pi/Sounds/Sound12.wav");


    // create and register gpio pin listener
    GpioPinListenerDigital listener = new GpioPinListenerDigital() {
        @Override
        public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
            // display pin state on console

            final int randomNum = 0 + (int) (Math.random() * 12);
            System.out.println(randomNum);

            System.out.println(" --> GPIO PIN STATE CHANGE: " + event.getPin() + " = " + event.getState());
            InputStream in;
            try {
                System.out.println(soundList.get(randomNum).toString());
                String filepath = soundList.get(randomNum).toString();
                in = new FileInputStream(new File(filepath));
                AudioStream as = new AudioStream(in);
                AudioPlayer.player.start(as);

            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

    };

    gpio.addListener(listener, pins);


    for (;;) {
        Thread.sleep(500);
    }
}

}    

1条回答
一纸荒年 Trace。
2楼-- · 2019-07-19 23:59

As stated in the comments, I can't give you advise regarding the AudioStream and AudioPlayer classes because I don't seem to have those in my JDK. Since my method is similar, I'll give you what I have, and you can hopefully take it from there.

Basically, the solution is to stop and/or "mute" that audio clip. This is how I accomplish it using the javax.sound package.:

private Clip currentAudioClip; // Keep a reference to the current clip being played

public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {

    // Call this every time regardless.
    // If nothing is playing, this will do nothing.
    stopAudio();

    String filepath = soundList.get(randomNum)
    URL soundFileUrl = new File(filePath).toURI().toURL();

    AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(soundFileUrl);

    Line.Info lineInfo = new Line.Info(Clip.class);
    Line line = AudioSystem.getLine(lineInfo);

    currentAudioClip = (Clip) line;
    currentAudioClip.open(audioInputStream);
    audioClip.start();

    // Alternative if you want to loop continuously. Comment out the `.start` line to use this.
    // audioClip.loop(Clip.LOOP_CONTINUOUSLY);
}

public void stopAudio(){
    if(audioClip != null){
        muteLine(); // A gotcha I discovered (see explanation below)
        audioClip.stop();

        // audioClip.loop(0); // if you chose to loop, use this instead of `.stop()`
        audioClip.flush();
        audioClip = null;
    }
}

public void muteLine(){
    BooleanControl muteControl = (BooleanControl) audioClip.getControl(BooleanControl.Type.MUTE);
    if(muteControl != null){
        muteControl.setValue(true); // True to mute the line, false to unmute
    }       
}

In short, every time a pin state change event is fired, the previous audio clip will be ceased, and a new one should play. You shouldn't get any sound overlapping with this.

Also note that this is a slight modification of my original code, so let me know if there are any issues

Note about the GOTCHA

I wrote a question over on the Raspberry PI Stackexchange about an odd problem I encountered. The problem was that I discovered my audio clip would not cease playing on command. It would continue playing for a seemingly arbitrary amount of time. The stranger thing is that I only observed this while testing the app on the raspberry; it worked perfectly fine on my local machine (and even on several other machines).

It is possible my issue is related to the "looping" of my clip; if that is the case, and you simply want the clip to play for its length and no further, you may not encounter that issue, and you can probably dispense with the "muting" code I included. However, if you do observe the same issue, at least you have a solution.

Hope this helps, let me know if you have any questions.

查看更多
登录 后发表回答