如何從Deemo遊戲中提取音樂的midi文件?

想請問deemo中的midi提取方法為何?


17.6.16更新

python版程序: vaporized/deemo-to-midi

----------

說一下當時我解決這個問題的思路。

使用的語言是Mathematica,只是因為個人使用習慣。

首先通過iTunes下載Deemo2.0的ipa,解壓縮,找到數據包文件,然後用disunity提取,具體指令如下。

經過觀察發現TextAsset文件夾內存有Deemo的譜面文件,就把那個文件夾複製出來刪掉其他的無關文件。

這些譜面文件看起來是這樣的

打開是這樣的

基本可以確定如下信息:
1.每首曲子對應不同難度有不同文件
deemo的鋼琴反饋系統中,無論什麼難度,都有一部分譜面note和一部分背景note,目前還無法確定信息是否完整及如何分配。
但後來經過驗證,每一首歌信息都是完整的並且完全相同的,具體兩種note是在後面links的差別,在這裡就不詳說了。
2.數據的格式為JavaScript Object Notation。
最開始的時候我不知道json是什麼,就自己寫了一個parser,然而後來發現mma可以直接Import,所以還是用內置的Import來減少代碼量。
3.裡面信息的大致含義
我當時先聽寫了一首曲子,方便了理解這裡面數據的含義。$id就是編號,忽略,sounds裡面的d是duration,為note的長度;p是pitch,音高;v是velocity,強度;size應該是譜面note的大小,無關,忽略;pos應該是譜面note的中心位置,無關,忽略;_time是note開始的時間。這些也是我用來構造midi的全部信息。唯一的遺憾是在某些文件裡面的sounds會有w的參數,並沒有猜出來是什麼含義,然而這樣的midi聽起來也和原曲沒什麼差別。當然如果有誰猜出來請告訴我,萬分感激。

mma內置了播放midi歌曲的函數,用Sound套起來一個由SoundNote組成的list就可以播放並且可以導出midi,而其中Sound[pitch_,{starttime_,endtime},SoundVolume-&>v_}]正好對應了剛才需要的四種數據,這樣就省去了自己讀寫midi file的麻煩。所以剩餘的任務就是通過list manipulation把原數據文件轉化為Sound的形式就搞定了。

首先Import[file,"JSON"]導入文件,得到了一堆rules,只想要notes,apply 一下 replacement rule就可以,

"notes" /. Import[file, "JSON"]

然後刪除不想要的那些元素:

("notes" /.
Import[file, "JSON"]) /. ((# -&> _) -&> Sequence[] /@ {"pos", "size", "w", "$id", "shift"})

這裡我沒有用DeleteCases,因為list的level不一樣,刪起來很麻煩,而替換就沒這個問題。

下一步打算把list裡面的rule變成values,並且整理為規整的list,就在2,4層執行Values,並且最後做一些特殊情況的處理,包括time為0沒有time元素的補全,電音並不對應琴鍵的刪除,和小狗圓舞曲中某個note沒有長度的修復:

(Fold[Map[
Values, #1, #2] , ("notes" /.
Import[file, "JSON"]) /. ((# -&> _) -&> Sequence[] /@ {"pos",
"size", "w", "$id",
"shift"}), {{2}, {4}}] /. {{{a__List}} :&> {{a}, 0}, {a_Real} :&>
Sequence[], {a_Integer, b_Integer} :&> {0, a, b}})

最後把list整理為每個音符的四元素為一個sublist,直接套入SoundNote格式。其中pitch在源文件中為0-127,C4對應60,mma中C4對應0,所以減去60即可,time直接使用,原來的velocity為0-127,mma中的為0-1,除以127就可以。最後的code如下:

DeemoToMidiv2[file_] :=
Sound[Function[
SoundNote[#2 - 60, {#4, #4 + #1},
SoundVolume -&> #3/127.]] @@ # /@ (Flatten /@
Flatten[Thread /@ (Fold[
Map[Values, #1, #2] , ("notes" /.
Import[file,
"JSON"]) /. ((# -&> _) -&> Sequence[] /@ {"pos", "size",
"w", "$id",
"shift"}), {{2}, {4}}] /. {{{a__List}} :&> {{a},
0}, {a_Real} :&>
Sequence[], {a_Integer, b_Integer} :&> {0, a, b}}), 1])]

可以試驗一下:

SetDirectory[$HomeDirectory &<&> "/Desktop/TextAsset"]
DeemoToMidiv2["v20anima.hard.json.txt"]

下一步可以處理全部文件了

既然三個難度內容一樣,留一個就好了(例如easy):

MapThread[
Export[#1, DeemoToMidiv2[#2]] , {StringReplace[FileNames[],
".easy.json.txt" -&> ".mid"], FileNames[]}]

可以看到除了因為heyboy的空文件報錯之外沒有任何問題。(OSX用戶要小心.DS_Store)
之後就可以由logic pro x打開欣賞或者繼續處理為五線譜啦。


我這就有大量的midi音樂,隨便聽櫻桃社區海量midi音樂


推薦閱讀:

如何看待「Mathematica 只是一個高級計算器」的說法?
如何找到mathmatica最新幾版的學習教材教程?
這張圖中能數出多少個三角形?
Mathematica還有哪些美麗的地方?

TAG:編程 | WolframMathematica | 古樹旋律Deemo |