java - 是否有一致的方法来跟踪 Java 中剪辑(或音频文件)中的位置?
问题描述
我正在尝试用 Java 编写节奏游戏。我正在播放带有 a 的音频文件,javax.sound.sampled.Clip
我想知道我所在的确切位置。
根据我的研究,节奏游戏的一个好习惯是使用音乐播放中的位置而不是系统时间来跟踪时间(以避免音频和游戏之间的转换)。
System.nanoTime()
我已经编写了一个用于保持一致帧速率的主循环。但是当我尝试获取剪辑的时间时,我有几帧返回相同的时间。这是我的代码的摘录:
while (running) {
// Get a consistent frame rate
now = System.nanoTime();
delta += (now - lastTime) / timePerTick;
timer += now - lastTime;
lastTime = now;
if (delta >= 1) {
if(!paused) {
tick((long) Math.floor(delta * timePerTick / 1000000));
}
display.render();
ticks++;
delta--;
}
// Show FPS ...
}
// ...
private void tick(long frameTime) {
// Doing some stuff ...
System.out.println(clip.getMicrosecondPosition());
}
我期待一个一致的输出(120 fps 的每帧增量约为 8,333 µs),但我在几帧中得到了相同的时间。
控制台返回:
0
0
748
748
748
10748
10748
10748
20748
20748
20748
30748
我怎样才能始终如一地准确地跟踪我在歌曲中的位置?javax Clip 有什么替代品吗?
解决方案
有许多困难需要处理。首先,Java 不提供实时保证,因此处理部分声音数据的时间不一定对应于听到它的时间。其次,操作系统系统时钟缺乏粒度很容易搞砸,我猜这是导致您看到多次出现时间的原因。几年前,我们在 java-gaming.org 上对此进行了多次讨论。[编辑:现在我认为您的检查循环速度比剪辑使用的缓冲区大小的粒度更快。]
我知道处理获得真正精确时间的唯一方法是Clip
完全放弃使用,而是在输出时计算帧数SourceDataLine
。我在这方面取得了很好的成功。它是输出到本机声音渲染代码之前的最后一点,因此具有最佳时机。
也就是说,有可能以固定间隔(对应于四分音符或十六分音符)实现某种脉冲(例如,使用 util.Timer)并让 TimerTask 启动Clip
对象的播放。我自己没有尝试过,但这对于节奏游戏来说已经足够了。为此,您将使用Clip
objects 而不是 SourceDataLine
. 但请确保每个Clip
都已满载并在播放时准备就绪。不要犯为每次播放重新加载它们的常见错误。
但是当我最后一次尝试做这样的事情时,使用一个常见的游戏循环,结果并不那么热。
JavaFX 非常适合游戏编写!我发现图形比 AWT 更容易处理。我写了一个开始使用 JavaFX 进行游戏编程的教程。如果您使用的是 JavaFX 11,就使用 Eclipse 进行设置而言,它已经过时了。但如果您使用的是 Java 8,我认为它仍然涵盖了基础知识。
在 JGO,人们处于几个不同的阵营。许多人喜欢使用 Libgdx,一个库,我们中的一些人继续使用 JavaFX 或 AWT/Swing。还有另外几个图书馆也受到不同成员的支持。
JavaFX有自己的声音输出,但我没有玩过,不知道它是否比Clip更好的节奏精度。提示都很好,但是鉴于 Java 的线程之间不断切换的系统,从提示中获取可用的时间信息总是很困难。
只是在审查JGO上的内容。您可能会发现这个线程很有趣,OP 试图在其中制作节拍器。 http://www.java-gaming.org/topics/java-audio-metronome-timing-and-speed-problems/33591/view.html
[编辑:PS,我写了一个可靠的节拍器,并且有一个足够可靠的事件回放系统,可以以无缝的节奏将音乐事件串在一起,并且听众可以实时跟踪正在播放的音符的音量包络等内容. 最终应该可以做你想做的事。]
推荐阅读
- c - 与 Pthread 和互斥锁共享有界缓冲区,忙等待
- java - How to remove item from firebase list
- javascript - 有条件渲染项目的排序列表
- python - 普通数据集的训练数据的keras输入维度是多少?
- css - React maskImage 内联不起作用 - 与 backgroundImage 相同的图像
- javascript - 通过单击按钮显示消息,但我如何通过单击按钮隐藏此消息
- swift - Struct 将不符合 equatable,即使设置了 ==
- verilog - 如果一个输入与一个输出具有相同的值,如何编写verilog代码
- amp-html - 来自 d-xxx.ampproject.net 的推荐流量(例如 d-104013771329548540.ampproject.net)
- delphi - IdTcpServer 有时不会在 Disconnect 事件中检索信息