Java无缝音频过渡/循环

时间:2019-01-27 21:05:46

标签: java audio javafx java-8 audio-player

如何确保两个音频之间的过渡是无缝的?

在JavaFX应用程序中,我正在使用javafx.scene.media.MediaPlayer来播放前奏,该前奏由主奏/循环奏开始。媒体播放的很好,但是问题是过渡和循环。

这是我目前正在做的事情:

private static void foo(final Media intro, final Media loop) {
        final MediaPlayer introPlayer = new MediaPlayer(intro);
        introPlayer.play();

        final MediaPlayer loopPlayer = new MediaPlayer(loop);
        loopPlayer.pause(); //  An attempt to load the media so it will be ready to be played.

        introPlayer.setOnEndOfMedia(loopPlayer::play());

        loopPlayer.setOnEndOfMedia(() -> loopPlayer.seek(Duration.ZERO));
        //loopPlayer.setCycleCount(Integer.MAX_VALUE); // Similar to the above line, but there is still a delay between loops.
    }

MediaPlayer :: pause确实有所帮助,但是在介绍性媒体结束与循环媒体开始之间存在非常明显的延迟。此外,循环媒体的结束与重复之间还有另一个明显的延迟。

我还尝试使用javafx.scene.media.AudioClip,因为它据说比javafx.scene.media.MediaPlayer的开销少。我写了自己的听众来告诉曲目何时结束(并在此之后立即开始循环播放),但是我仍然看到类似的延迟。

以下是我找到的一些类似帖子,但没有提供解决问题的方法:

  

JavaFX MediaPlayer playing background music loop with small intro music

     

这绝对是相关的(巧合的是,几乎   该帖子的周年纪念日),但我已经在使用.wav格式   媒体文件,但仍然会延迟。

     

JavaFX AudioClip.play()

     

与我使用Audioclip尝试过的类似,例如我使用了   安排执行者定时重播音频。 (我还在哪里   经历了延迟)。

最后,我在Audacity中测试了我的音频,使它们无缝过渡和循环。

针对这些类型的问题,有哪些推荐的解决方案?

编辑:

  1. 在代码块中添加了附录,提到了MediaPlayer :: setCycleCount(Integer)

2 个答案:

答案 0 :(得分:0)

AudioClip Javadocs状态,一个AudioClip表示一段音频,可以以最小的延迟播放并立即可用。但是,它也指出

  

但是,媒体对象更适合长时间播放的声音。这主要是因为AudioClip在内存中存储了整个声音的原始,未压缩的音频数据,这对于较长的音频剪辑而言可能会很大。 MediaPlayer将仅在内存中预滚动足够的解压缩音频数据以在短时间内播放,因此对于较长的剪辑(特别是压缩后的剪辑),其存储效率要高得多。

根据循环媒体的长度,AudioClip可能更适合您。无需使用ScheduledExecutorService来重放音频,您可以使用AudioClip.setCycleCount(AudioClip.INDEFINITE)进行永久循环。

使用此信息,我相信您最好的选择是对介绍使用MediaPlayer,然后利用MediaPlayer#setOnEndOfMedia调用循环AudioClip;简介和循环过渡之间的延迟可能很小,但此后是无缝的。

答案 1 :(得分:0)

我知道距您发布已经有一段时间了。找到答案了吗?我想知道您是否在玩loopPlayer之前加载了introPlayer,是否有帮助。

如果MediaPlayer的“监听器”有点呆板,也许切换到使用Java的SourceDataLineLineListener来触发循环提示会更无缝地工作吗? (我将使用Clip进行循环播放。)

最后的建议是,我有一个音频库AudioCue可用于此目的。库中包含一个AudioCueListener,当提示结束时,该AudioCue可以触发事件(例如开始播放另一个arr1 = [1,2,3,4,5,8,9,0,7,8,6] arr2 = [6,5,7,2,3,4,5,9,1,22] arr3 = [6,2,3,4,5,7] )。但是该库的局限性要求您将音乐保存在内存中,并且源文件必须是.wav。