-
Notifications
You must be signed in to change notification settings - Fork 31
SoundBuffers and Sounds
Most visual aspects of JSFML were covered in the previous chapters. This chapter will introduce the audio functionality that JSFML offers.
A SoundBuffer represents a sound sample stored in the RAM. For this reason, it should generally be used for moderately short audio samples, those that do not take up too much memory. For a background music, for instance, streaming is the weapon of choice, which will be presented in the next tutorial chapter.
SoundBuffers are ready to be played using a Sound. Thus, a sound buffer is to a sound what a texture is to a sprite - multiple sprites can be created from one texture, and multiple sounds can be played (simultaneously) using the same sound buffer.
The following example class loads a sound sample from a WAV file and plays it when the user presses the F key:
//... (create window)
//Create the sound buffer and load a sound from a file
SoundBuffer soundBuffer = new SoundBuffer();
try {
soundBuffer.loadFromFile(Paths.get("sound.wav"));
System.out.println("Sound duration: " + soundBuffer.getDuration().asSeconds() + " seconds");
} catch(IOException ex) {
//Something went wrong
System.err.println("Failed to load the sound:");
ex.printStackTrace();
}
//Create a sound and set its buffer
Sound sound = new Sound();
sound.setBuffer(soundBuffer);
//Main loop
while(window.isOpen()) {
//... (drawing and displaying)
//Process events
for(Event e : window.pollEvents()) {
if(e.type == Event.Type.KEY_PRESSED && e.asKeyEvent().key == Keyboard.Key.F) {
//The F key was pressed
sound.play();
}
//... (other events)
}
}
The SoundBuffer class, much like other resource classes, has a method called [loadFromFile](http://jsfml.org/javadoc/org/jsfml/audio/SoundBuffer.html#loadFromFile(java.nio.file.Path\)), which may throw an IOException if anything goes wrong.
The following audio file formats are supported: ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam, w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64
.
A SoundBuffer holds different kinds of information about the contained audio sample.
The most simple piece of information is the duration of the sound, which can be retrieved using the [getDuration](http://jsfml.org/javadoc/org/jsfml/audio/SoundBuffer.html#getDuration(\)) method.
Access to the raw sample data is provided via the [getSamples](http://jsfml.org/javadoc/org/jsfml/audio/SoundBuffer.html#getSamples(\)) method and getters for retrieving the sample rate and channel count. The data is available as 16-bit samples and be used for any kind of custom processing.
Using the [loadFromSamples](http://jsfml.org/javadoc/org/jsfml/audio/SoundBuffer.html#loadFromSamples(short[], int, int)) method, a sound buffer can also be created from any sample data.
To play a sound, simply create a new Sound objects, set its buffer using the [setBuffer](http://jsfml.org/javadoc/org/jsfml/audio/Sound.html#setBuffer(org.jsfml.audio.ConstSoundBuffer\)) method and play it using [play](http://jsfml.org/javadoc/org/jsfml/audio/Sound.html#play(\)).
However, there is a common pitfall that will cause a sound not to play. Consider the following change to the example above:
if(e.type == Event.Type.KEY_PRESSED && e.asKeyEvent().key == Keyboard.Key.F) {
//The F key was pressed
Sound sound = new Sound(soundBuffer);
sound.play();
}
Technically, doing this is fine, but you will not hear anything, or maybe only a split second of it. This is because the variable sound
is local to the conditional if
block. After the code leaves that block, the sound
variable no longer exists. Then, there are no more references to the Sound that was created and it is [garbage collected](http://en.wikipedia.org/wiki/Garbage_collection_(computer_science\)), which also means that it is stopped.
This issue has to be kept in mind when working with sounds. Always make sure that there is a reference to any sound that is stil playing. A common solution is making the sound a member of the classes that uses it. Another approach would be a sound pool where every sound that is being played will be added to, and which regularly gets cleaned up by removing sounds that are no longer playing.
To find out if a sound is currently playing or not, the [getStatus](http://jsfml.org/javadoc/org/jsfml/audio/Sound.html#getStatus(\)) will report the current state.
The returned status is covered by the SoundSource.Status enumeration. A sound that is currently playing will report PLAYING
.
When a sound has finished playing or it was stopped using the [stop](http://jsfml.org/javadoc/org/jsfml/audio/Sound.html#stop(\)) method, the status is STOPPED
.
Additionally, a sound can be paused using the [pause](http://jsfml.org/javadoc/org/jsfml/audio/Sound.html#pause(\)) method. If a sound is paused and the play method is used, the sound will continue playing from the point at which it was paused, much like on a CD player. A paused sound's status is PAUSED
.
Sounds can be looped infinitely (until stopped) by using [setLoop](http://jsfml.org/javadoc/org/jsfml/audio/Sound.html#setLoop(boolean\))(`true`) before it is played. The sound will then restart playing from the beginning everytime it reaches the end. This is useful for ambient sounds, to name an example.
The sound's volume can be adjusted using the [setVolume](http://jsfml.org/javadoc/org/jsfml/audio/SoundSource.html#setVolume(float\)) method, which excepts a volume level between 0 (silence) and 100 (full volume).
The pitch of the sound can be modified using the [setPitch](http://jsfml.org/javadoc/org/jsfml/audio/SoundSource.html#setPitch(float\)) method, which expects a pitch factor. The sound's default pitch is 1. Any value greater than 1 will cause the sound to be pitched up (and become "faster"), a value between 0 and 1 will pitch the sound down (and make it become "slower").