我正在尝试用 Java 编写一个非常简单的 DAW,但在播放序列中的音频剪辑时遇到问题。我研究了 Java Sound 中的采样类和 MIDI 类,但我真正需要的是两者的混合。
似乎对于 MIDI 类,您无法使用音序器来播放您自己的音频剪辑。 我尝试使用调度来编写自己的音序器,以按顺序播放 javax.sound.sampled.Clip,但时间变化太大。这实际上并不是一个可行的选择,因为它不节省时间。
有人对我如何解决这个问题有任何建议吗?
最佳答案
我可以证明,可以用 Java 编写结合了 MIDI 和样本方面的音频混合系统,就像我自己编写的一样,它目前可以与我也编写的样本和几个实时合成器一起使用。
关键是使样本的音频数据在每帧的基础上可用,并且帧计数命令处理器/音频混合器既管理“命令”的执行,又收集和混合音频帧数据。在 44100 fps 下,精度约为 0.02 毫秒。如果需要,我可以更详细地描述。
另一种可能更明智的方法是使用Java bridge,尽管我个人没有这样做过。到诸如Jack之类的系统.
<小时/>编辑:回答评论中的问题(2019 年 12 月 8 日)。
Java 中的音频样本数据通常保存在内存中(Java 使用 Clip
)或从 .wav 文件读取。因为 Clip
不会公开各个帧,所以我编写了一个替代方案,并使用它来将数据保存为范围 -1 到 1 的有符号 float 。有符号 float 是保存音频数据的常用方法,我们可以使用它来保存音频数据。将执行多项操作。
对于.wav音频的播放,Java结合使用AudioInputStream
读取数据和使用SourceDataLine
输出。您的系统必须位于中间,拦截 AudioInputStream
,转换为 PCM float 帧,并在运行过程中对帧进行计数。
可以同时处理多个源或轨道,并将其合并(简单添加归一化 float )到单个信号。该信号可以转换回字节并通过单个 SourceDataLine
发送出去进行播放。
从单个 SourceDataLine
中的任意第 0 帧计算输出帧将有助于保持组成的传入轨道协调,并将提供帧编号引用,用于安排您希望之前执行的任何其他命令到正在输出的帧(例如,更改源的音量/声像,或合成器上的设置)。
我个人的剪辑替代方案与 AudioCue 非常相似欢迎您检查和使用。主要区别在于,无论好坏,我在系统中一次一帧地处理所有内容,并且 AudioCue
及其“混合器”处理缓冲区加载。有几个非常可信的人批评我个人的每帧系统效率低下,因此当我为 AudioCue
提供公共(public) API 时,我屈服于这种先入之见。 [有多种方法可以向每帧系统添加缓冲以重新获得效率,并且每帧使调度变得更简单。所以我坚持我的每帧逻辑方案。]
关于java - 如何在 Java 中以 (MIDI) 序列播放音频剪辑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59143055/