简体   繁体   中英

How to stop a sound played in a new thread?

I'm making a simple tank game and it has its background music. I need the music to stop whenever the player dies (players health int becomes 0). How do i do it?

I tried stopping the thread by declraring the thread outside of the play() function and stopping it with t.stop() but it didn't work.

package com.company;

import java.io.File;
import java.io.IOException;

import javax.sound.sampled.*;

public class Sound implements Runnable
{

    private String fileLocation;
    public String getFileLocation() {
        return fileLocation;
    }

    public Sound() {
    }



    public void play(String fileLocation)
    {
        Thread t = new Thread(this);
        this.fileLocation = fileLocation;
        t.start();
    }

    public void run ()
    {
        playSound(fileLocation);
    }



    public void playSound(String fileName)
    {
        File soundFile = new File(fileName);
        AudioInputStream audioInputStream = null;
        try
        {
            audioInputStream = AudioSystem.getAudioInputStream(soundFile);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        AudioFormat audioFormat = audioInputStream.getFormat();
        SourceDataLine line = null;
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
        try
        {
            line = (SourceDataLine) AudioSystem.getLine(info);
            line.open(audioFormat);
        }
        catch (LineUnavailableException e)
        {
            e.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        line.start();
        int nBytesRead = 0;
        byte[] abData = new byte[128000];
        while (nBytesRead != -1)
        {
            try
            {
                nBytesRead = audioInputStream.read(abData, 0, abData.length);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            if (nBytesRead >= 0)
            {
                int nBytesWritten = line.write(abData, 0, nBytesRead);
            }
        }
        line.drain();
        line.close();
    }
}

Declare a volatile boolean. Why volatile? Because it needs to update across threads.

private volatile boolean playing;

Include the boolean in the while clause.

while(playing && nBytesRead != -1)

Make the boolean accessible from outside the playback thread.

public void setPlaying(boolean) {
    this.playing = playing;
}

When you want to turn off the sound, call setPlaying(false) . Don't forget to make the boolean true before the sound is started.

The only drawback here is that the sound may end with a click, since it will be instant. Adding a fade involves setting up and invoking a javax.sound.sampled.Control object (I've had dubious luck with these), or fiddling with the PCM data itself.

At least with a SourceDataLine , we have access to the bytes (in your abData array). The data can be assembled into PCM according to your audio format, then multiplied by a fader value that goes from 1 to 0 over the course of something like 64 frames, dialing the PCM values down to 0 gradually, and then taking these new PCM values and converting them back to bytes and writing that. Yes, a lot of trouble just to get rid of a click. But worth it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM