libGDX/Android:如何循环背景音乐而不产生可怕的间隙?
我正在使用libGDX,但我面临的问题是,背景音乐无法在各种Android设备上完美循环(例如运行棒棒糖的Nexus7)。每当轨道循环(即从末端跳到起点)时,可听到明显的间隙。现在我想知道背景音乐如何能在没有令人不安的间隙的情况下循环播放 我已经尝试过各种方法,如:libGDX/Android:如何循环背景音乐而不产生可怕的间隙?,android,audio,libgdx,background-music,Android,Audio,Libgdx,Background Music,我正在使用libGDX,但我面临的问题是,背景音乐无法在各种Android设备上完美循环(例如运行棒棒糖的Nexus7)。每当轨道循环(即从末端跳到起点)时,可听到明显的间隙。现在我想知道背景音乐如何能在没有令人不安的间隙的情况下循环播放 我已经尝试过各种方法,如: 确保轨迹中的采样数是轨迹采样率的精确倍数(如本文某处所述) 各种音频格式,如.ogg、.m4a、.mp3和.wav(.ogg似乎是目前选择的解决方案,但不幸的是,它在我的情况下不起作用) 使用带setLooping(true)的A
- 确保轨迹中的采样数是轨迹采样率的精确倍数(如本文某处所述)
- 各种音频格式,如.ogg、.m4a、.mp3和.wav(.ogg似乎是目前选择的解决方案,但不幸的是,它在我的情况下不起作用)
- 使用带setLooping(true)的Androids MediaPlayer代替libGDX音乐类李>
- 已使用Androids MediaPlayer.setNextMediaPlayer()。代码如下所示,它播放两首曲目之间没有间隙,但不幸的是,一旦第二首MediaPlayer完成,第一首就不会再次开始
/* 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(); } }
结果证明这是无法解决的。最后,我们在文件中多次循环播放背景音乐。这样,差距就不那么频繁了。这不是问题的真正解决办法,但却是我们能找到的最好的解决办法。这是一个老问题,但我会给出我的解决方案,以防有人遇到同样的问题 该解决方案需要使用音频扩展(已弃用,但效果很好),如果您无法在线找到链接,则我正在使用的JAR也需要一些外部存储空间 摘要如下
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();
创建一个缓冲区,这样我们就可以将从文件中读取的字节转换为一个短数组,该数组将馈送到音频设备
public byte[] rafbufferBytes=new byte[length*2];
public short[] rafbuffer=new short[length];
public ShortBuffer sBuffer=ByteBuffer.wrap(rafbufferBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
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();
当我们想要播放这个文件时,我们会创建一个音频设备和一个新的线程,在这里我们不断地从raf文件中读取并将其提供给音频设备
public byte[] rafbufferBytes=new byte[length*2];
public short[] rafbuffer=new short[length];
public ShortBuffer sBuffer=ByteBuffer.wrap(rafbufferBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
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();
看看这个:ExoPlayer。请看这里的重复问题:哇,2021年,这个问题得到了投票。真令人惊讶。好吧,2015年libGDX和RoboVM很有趣,但到2021年,你和Godot的关系会更好:你是如何得出这是无法解决的结论的?有什么特别的,或者只是因为你尝试了所有的东西,但都没有效果?Android bug tracker中有一个问题-是的,我尝试了所有可能的选项来循环背景音乐,然后放弃了。谢谢你的帮助。我没有试过,但无论如何我会接受你的回答。抱歉耽搁了五年半;-)