Skip to content Skip to sidebar Skip to footer

Libgdx,change Pitch In Music

I want to implement a cool effect, when there is an explosion the music gets slightly slower for a moment. The Music class of libgdx doesn't allow changing the pitch of the sound,

Solution 1:

After some searching I found a way by editing the libgdx source code.

You need to use the AudioDevice object to play your music sample by sample ,to do that you need to include the audio-extension of libgdx.

We gonna edit the libgdx source code so you need to download it and replace the gdx.jar , gdx-backend-android.jar and gdx-backend-lwjgl.jar with the correct libgdx projects(they have the same name without the jar extension)

1)Edit the AudioDevice.java inside com.badlogic.gdx.audio package of the gdx project

add the following code inside the interface

publicvoidsetSpeed(float val);

2)Edit the AndroidAudioDevice.java inside com.badlogic.gdx.backends.android package of the gdx-backend-android project

The Android side of the AudioDevice class relies on the AudioTrack class of the Android sdk ,this class has a setPlaybackRate(..) method.

add the following code inside the class

@OverridepublicvoidsetSpeed(float speed) {
    track.setPlaybackRate((int)(track.getSampleRate()*speed));
}

3)Edit the OpenALAudioDevice.java inside com.badlogic.gdx.backends.lwjgl.audio package of the gdx-backend-lwjgl project

The Desktop side of the AudioDevice relies on OpenAL (the opengl of audio) which has a handy set pitch method

add the following inside the class

@OverridepublicvoidsetSpeed(float speed) {
    alSourcef(sourceID, AL_PITCH, speed);
}

4)Play the audio

Here is the code for loading and playing the sound file

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.AudioDevice;
import com.badlogic.gdx.audio.io.Mpg123Decoder;
import com.badlogic.gdx.files.FileHandle;

publicclassMusicBeat {

staticshort[] samples = newshort[2048];
Mpg123Decoder decoder;
AudioDevice device;
static FileHandle externalFile;
publicboolean playing=true;
publicMusicBeat(String name )
{
        FileHandle file=Gdx.files.internal(name);
        FileHandle external=Gdx.files.external("myappname/"+name);
        if(!external.exists())file.copyTo(external); //copy the file to the external storage only if it doesnt exists yet
        decoder = newMpg123Decoder(external);
        device = Gdx.audio.newAudioDevice(decoder.getRate(),decoder.getChannels() == 1 ? true : false);
        playing=false;
        externalFile=file;
}

voidplay()
{
    playing=true;
    ThreadplaybackThread=newThread(newRunnable() {
        @Overridepublicsynchronizedvoidrun() {
            intreadSamples=0;
            while ( playing) {
                if(decoder!=null){
                    if((readSamples = decoder.readSamples(samples, 0,samples.length))<=0){
                        decoder.dispose();
                        decoder = newMpg123Decoder(externalFile);
                        playing=false;
                    }
                    device.writeSamples(samples, 0, readSamples);
                }
            }
        }
    });
    playbackThread.setDaemon(true);
    playbackThread.start();
}

publicvoidstop(){
    playing=false;
    decoder.dispose();
}
publicvoidsetVolume(float vol){
    device.setVolume(vol);
}
publicvoidsetSpeed(float speed){
    device.setSpeed(speed);
}

}

Where to get the audio extension?(required for the AudioDevice)

The audio extension seems to have been deprecated and the jars cant be found easily, I have uploaded them here, its an old version but should work just fine.

Easier way?

If your game is only intent to run on desktop ,the Music class of libgdx on desktop relies again on OpenAL which gives as the power to play with the pitch ,so you just need to edit the Music interface(OpenALMusic on desktop) instead of the AudioDevice and get out the whole play sample by sample thing out of the equation,unfortunately as dawez said the Music class on android relies on MediaPlayer which is not giving us the pitch change option.

Conclusion :This method doesnt seem nice to me ,If your game really needs the pitch thing and it doesn't makes sense without it then go with it ,otherwise its just too much effort for such a small detail .

Solution 2:

It seems that you cannot change the pitch of Music in Android.

To play music in libgdx you refer to the Interface Music:

publicinterfaceMusicextendsDisposable {

This is implemented by

package com.badlogic.gdx.backends.android;
publicclassAndroidMusicimplementsMusic, MediaPlayer.OnCompletionListener {
        private MediaPlayer player;

You are interested in the player object. That is of type MediaPlayer

package android.media;
publicclassMediaPlayer {

So now it boils down to the question if android is able to support pitching on the MediaPlayer class. Short answer no, long answer:Speed Control of MediaPlayer in Android

A workaround that you can do is to use a SoundPool even if that is slow, the loading can be started while the user is the loading screen. Otherwise you can try can split the music files in chunks and load them as you go still using a SoundPool. So you would do something like a lazy loading when the current part is coming to its end.

If you manage to find a suitable a solution, please post the relative code!

Solution 3:

With the release of Android 6.0 (API level 23), "PlaybackParams" can be added to the MediaPlayer. These include playback speed and pitch among others.

Post a Comment for "Libgdx,change Pitch In Music"