![](/img/trans.png)
[英]In Java, how can I play the same audio clip multiple times simultaneously?
[英]How can I play an audio clip in a (MIDI) sequence in Java?
我正在嘗試用 Java 編寫一個非常簡單的 DAW,但無法按順序播放音頻剪輯。 我已經研究了 Java Sound 中的采樣類和 MIDI 類,但我真正需要的是兩者的混合。
例如,對於 MIDI 類,您似乎無法使用音序器來播放自己的音頻剪輯。 我曾嘗試使用調度來編寫我自己的音序器以在序列中播放 javax.sound.sampled.Clip 但時間變化太大了。 這不是一個真正可行的選擇,因為它沒有時間。
有人對我如何解決這個問題有任何建議嗎?
不,您不能使用音序器直接播放您自己的剪輯。 在 MIDI 世界中,您必須處理樣本、樂器和音庫。
很快,樣本就是音頻數據+信息,例如循環點、樣本覆蓋的音符范圍、基本音量和包絡等。樂器是一組樣本,音庫包含一組樂器。 如果你想用你自己的聲音來播放一些音樂,你必須用它們制作一個音庫。
您還需要使用 Java 提供的默認設置以外的其他實現,因為該默認設置僅讀取專有格式的音庫,這種格式至少 15 年甚至 20 年已經消失。 早在 2008-2009 年,就存在例如 Gervill。 它能夠讀取 SF2 和 DLS 音庫。 SF2 和 DLS 是兩種流行的音庫格式,市場上有幾種免費或付費的程序來編輯它們。
如果你想反過來,從采樣開始,這也正如你所注意到的那樣,你不能依靠計時器、任務計划、Thread.sleep 等來獲得足夠的精度。 使用它們可以達到的最佳精度約為 10 毫秒,這對於音樂來說當然太少了。
通常的方法是通過將自己的音頻剪輯混合到最終剪輯中來生成音樂的音頻。 所以你可以達到幀精度。 事實上,這是非常粗略的 MIDI 合成器。
我可以證明結合 MIDI 和樣本方面的音頻混合系統可以用 Java 編寫,就像我自己寫的那樣,它目前可以與我也編寫的樣本和幾個實時合成器一起使用。
關鍵是使樣本的音頻數據在每幀的基礎上可用,以及一個幀計數命令處理器/音頻混合器,它既管理“命令”的執行,又收集和混合音頻幀數據。 44100 fps 的精度接近 0.02 毫秒。 如果需要,我可以更詳細地描述。
另一種可能更明智的方法是使用Java 橋接系統,例如Jack 。
編輯:回答評論中的問題 (12/8/19)。
Java 中的音頻樣本數據通常保存在內存中(Java 使用Clip
)或從 .wav 文件中讀取。 因為單個幀沒有被Clip
暴露,我寫了一個替代,並使用它來保存數據作為范圍 -1 到 1 的有符號浮點數。有符號浮點數是保存音頻數據的常用方法,我們將對其執行多個操作.
對於 .wav 音頻的播放,Java 結合使用AudioInputStream
讀取數據和使用SourceDataLine
輸出。 您的系統必須位於中間,攔截AudioInputStream
,轉換為 PCM 浮動幀,並在進行時計算幀數。
可以同時處理多個源或軌道,並合並(簡單地添加歸一化浮點數)到單個信號。 該信號可以轉換回字節並通過單個SourceDataLine
發送出去進行播放。
對來自單個SourceDataLine
的任意第 0 幀的輸出幀進行計數將有助於保持組成輸入軌道的協調,並將提供幀編號參考,用於安排您希望在輸出該幀之前執行的任何其他命令(例如,更改音源的音量/聲相,或合成器上的設置)。
我個人的 Clip 替代品與AudioCue非常相似,歡迎您檢查和使用。 主要區別在於,無論好壞,我都在我的系統中一次處理一幀的所有內容,並且AudioCue
及其“混合器”處理緩沖區加載。 我有幾個非常可信的人批評我個人的每幀系統效率低下,所以當我為AudioCue
制作公共 API 時,我屈服於這種先入之見。 [有一些方法可以為每幀系統添加緩沖以重新獲得這種效率,而每幀使調度更簡單。 所以我堅持我的每幀邏輯方案。]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.