简体   繁体   中英

Cache a sound and create instaces of it

I am currently programming a game and now I also want to add sound. My current method works fine but I am not happy with it.

new Sound(new Resource().readAndGetStream("small_click.wav")).play();

This line of code reads the file small_click.wav whenever it is getting executed. But I think it is not very efficient to always read the resource file when it's needed. So what I want to do now is caching a sound in a variable or something to not have to load the sound from file again. But I also want to create a new object from the sound, so I can play it mutiple times and it overlaps in the speakers.

I can't find a way to do this. I already tried to use Threads but.. this code works without any threads.

If you want to know, here is the code of the Sound class:

public Sound(InputStream audioSrc) {
    try {
        InputStream bufferedIn = new BufferedInputStream(audioSrc);
        AudioInputStream audioStream = AudioSystem.getAudioInputStream(bufferedIn);
        clip = AudioSystem.getClip();
        clip.open(audioStream);
    } catch {
        ...exception handling...
    }

}

public void play() {
    clip.setFramePosition(0);
    clip.start();
}

And If you want to know what the "new Resource().readAndGetStream()" does: It basically loads a resource and returns an InputStream of that resource with getResourceAsStream() .

With the Sound class that you have, you can easily create a "cache". For example, create an array of type Sound[] soundCache and execute the first part of the code line you gave in your example.

soundCache[0] = new Sound(new Resource().readAndGetStream("small_click.wav"));

You could even consider making constants to correspond to each sound.

final int SMALL_CLICK = 0;

Then, when it is time to play the sound, execute your play function.

soundCache[SMALL_CLICK].play();

Going from here to having concurrent playbacks of a given sound is quite a bit more involved. If continuing to work with Clip as your basis, I don't know of any way to get overlapping playbacks of the same sound resource except by making and managing as many copies of the Clip as you might want to allow to be heard at once.

When faced with this coding challenge, I ended up writing my own library, AudioCue . It is available on Github, and has a very permissive license.

The basic concept is to store the audio data in an array of signed PCM floats, and manage the concurrent playback by having multiple "cursors" that can independently iterate through the PCM data and feed it to a SourceDataLine .

These cursors can be managed in real time. You can change the rate at which they travel through the data and scale the volume level of the data, allowing frequency and volume changes.

I did my best to keep the API as similar to a Clip as practical, so that the class would be easy to use for coders familiar with Java's Clip .

Feel free to examine the code for ideas/examples or make use of this library in your project.

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