LibGDX / Android: How to loop background music without a terrible break?

I use libGDX and I am faced with the problem that background music does not loop flawlessly on different Android devices (for example, Nexus 7 works with Lollipop). Whenever the outline of a track (that is, jumping from end to beginning), a noticeable gap is heard. Now I wonder how background music can be played in a loop without a disturbing break?

I have already tried various approaches like:

  • Providing the number of samples per track is an exact multiple of the sample rate of the tracks (as mentioned here in SO).
  • Various sound formats such as .ogg, .m4a, .mp3 and .wav (.ogg seems to be the solution of choice here in SO, but unfortunately this does not work in my case).
  • Used by Androids MediaPlayer with setLooping (true) instead of the LibGDX music class.
  • Used by Androids MediaPlayer.setNextMediaPlayer (). The code is as follows: it plays two tracks without a gap between them, but, unfortunately, as soon as the second MediaPlayer ends, the first does not start again!

        /* initialization */
        afd = context.getAssets().openFd(filename);
        firstBackgroundMusic.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
        firstBackgroundMusic.prepare();
        firstBackgroundMusic.setOnCompletionListener(this);
    
        secondBackgroundMusic.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
        secondBackgroundMusic.prepare();
        secondBackgroundMusic.setOnCompletionListener(this);
    
        firstBackgroundMusic.setNextMediaPlayer(secondBackgroundMusic);
        secondBackgroundMusic.setNextMediaPlayer(firstBackgroundMusic);
    
        firstBackgroundMusic.start();
    
    
    
        @Override
        public void onCompletion(MediaPlayer mp) {
            mp.stop();
            try {
                mp.prepare();
            } catch (IOException e) { e.printStackTrace(); }
        }
    

Any ideas what is wrong with the code snippet?

+4
source share
2 answers

For entries only: It is set to unsolvability. In the end, we looped the background music once in a file. Thus, a gap occurs less frequently. This is not a real solution to the problem, but the best workaround we could find.

+3
source

This is an old question, but I will give my solution if someone has the same problem.

Audio- (, ), , , .

  • ( VorbisDecoder ogg Mpg123Decoder mp3) ( , , , , ).
  • RandomAccessFile, , .
  • RandomAccessFile
  • AudioDevice

, - FileHandle , ogg, VorbisDecoder

    FileHandle external=Gdx.files.external("data/com.package.name/music/"+file.name());
    file.copyTo(external);
    VorbisDecoder decoder = new VorbisDecoder(external);
    FileHandle extreactedDataFile=Gdx.files.external("data/com.package.name/music/"+file.nameWithoutExtension()+".mdata");
    if(extreactedDataFile.exists())extreactedDataFile.delete();
    ShortBuffer sbuffer=ByteBuffer.wrap(shortBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
    while(true){
        if(LogoScreen.shouldBreakMusicLoad)break;
        int num=decoder.readSamples(samples, 0,samples.length);
        sbuffer.put(samples,0,num);
        sbuffer.position(0);
        extreactedDataFile.writeBytes(shortBytes,0,num*2, true);
        if(num<=0)break;
    }
    external.delete();

RandomAccessFile,

    if(extreactedDataFile.exists()){
        try {
            raf=new RandomAccessFile(Gdx.files.external(extreactedDataFile.path()).file(), "r");
            raf.seek(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

, , , , AudioDevice

public byte[] rafbufferBytes=new byte[length*2];
public short[] rafbuffer=new short[length];
public ShortBuffer sBuffer=ByteBuffer.wrap(rafbufferBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();

, AudioDevice , raf AudioDevice

    device = Gdx.audio.newAudioDevice((int)rate/*the hrz of the music e.g 44100*/,isthemusicMONO?);
    currentBytes=0;//set the file to the beggining
    playbackThread = new Thread(new Runnable() {
        @Override
        public synchronized  void run() {
                while (playing) {
                        if(raf!=null){
                            int length=raf.read(rafbufferBytes);
                            if(length<=0){
                                ocl.onCompletion(DecodedMusic.this);
                                length=raf.read(rafbufferBytes);
                            }
                            sBuffer.get(rafbuffer);
                            sBuffer.position(0);
                            if(length>20){
                                try{
                                    device.writeSamples(rafbuffer,0,length/2);
                                    fft.spectrum(rafbuffer, spectrum);
                                    currentBytes+=length;
                                }catch(com.badlogic.gdx.utils.GdxRuntimeException ex){
                                    ex.printStackTrace();
                                    device = Gdx.audio.newAudioDevice((int)(rate),MusicPlayer.mono);
                                }
                            }
                        }
                    }
                }
    });
    playbackThread.setDaemon(true);
    playbackThread.start();

public void seek(float pos){
    currentBytes=(int) (rate*pos);
    try {
        raf.seek(currentBytes*4);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
0

All Articles