在開發(fā)音樂游戲的過程中肛炮,經(jīng)常需要進(jìn)行譜子的創(chuàng)作褂傀,如果人工手打,很容易造成不準(zhǔn)和效率低下的情況引颈。而通過音頻人員做的midi文件中提取指定的信號诵冒,然后自動生成譜子凯肋,將大大提高效率和準(zhǔn)確度。
本篇文章將解釋使用 Python
從 midi
文件中提取指定信號汽馋,然后生成譜子的邏輯侮东。
1. 與 midi
文件相關(guān)的東西
midi 文件中有一個(gè)信號的概念圈盔,例如 note_on
, note_off
,為了做譜子悄雅,我們?yōu)椴煌男盘栙x予不同的數(shù)值驱敲,然后以此來生成不同的譜子。
2. 使用 midi 文件生成譜子的邏輯
以 QQ 炫舞為例宽闲,游戲中有多種點(diǎn)
众眨,例如點(diǎn)擊的,滑動的容诬,需要按住的娩梨,等等。這里我們用 midi 中的note_on
事件做邏輯览徒。首先狈定,一首歌在不同的地方有重音,音頻人員只要在對應(yīng)的時(shí)間點(diǎn)上的 note_on
事件設(shè)定我們約定好的值习蓬,例如這里用10
作為點(diǎn)擊的點(diǎn)掸冤,11
作為滑動的點(diǎn),12
作為長按的點(diǎn)友雳。
拿到作好的 midi 文件后,我們只需要掃描整個(gè) midi 文件中的 note_on
事件铅匹,然后取出里面的時(shí)間點(diǎn)押赊,和對應(yīng)的值,就可以生成一個(gè)可以在游戲中用的譜子包斑。一個(gè)譜子是什么樣子的流礁,完全由音頻人員與策劃去決定,程序這邊只需要生成就可以罗丰。
3. 使用 Python 解析 midi 文件數(shù)據(jù)
這里要用的幾個(gè) Python 庫神帅,所以需要先安裝,運(yùn)行下面的命令安裝 mido萌抵。(這里假設(shè)開發(fā)人員對 Python 有基本的了解)
pip3 install mido
import mido
from mido import MidiFile
import os
midi_file_path = './test.mid'
bpm = 121 # BPM 是必須的找御,這一個(gè)音頻人員知道是什么
tap_value = 10 # 定義點(diǎn)擊的值
wipe_value = 11 # 定義滑動的值
hold_value = 12 # 定義按住的值
# 這一個(gè)是為了適應(yīng)人的聽感,而加的偏移值绍填,midi 文件的時(shí)間是準(zhǔn)的
# 但是人耳朵聽起來可能不是很準(zhǔn)霎桅,最終是以人耳聽起來準(zhǔn)為目標(biāo)
# 這個(gè)值不固定,根據(jù)自己游戲的音樂類型不同讨永,以及做音頻的人的聽感不同滔驶,而設(shè)定,可以是正的卿闹,可以是負(fù)的
time_offset = 0.25
def get_base_notes_data(_midi_file_path, _bpm):
mid = MidiFile(_midi_file_path)
tempo = mido.bpm2tempo(_bpm)
_note_list = []
for i, track in enumerate(mid.tracks):
print('Track {}: {}'.format(i, track.name))
passed_time = 0
for msg in track:
ab_time = mido.tick2second(msg.time, mid.ticks_per_beat, tempo)
real_time = ab_time + passed_time
passed_time += ab_time
# print(msg, " passed time=" + str(ab_time), " read time=" + str(round(real_time, 3)))
if msg.type == "note_on":
note_value = msg.note
if note_value == tap_value:
note_name = "tap"
elif note_value == wipe_value:
note_name = "wipe"
elif note_value == hold_value:
note_name = "hold"
else:
note_name = ""
if note_name != "":
note_data = {"note_name": note_name, "time": round(real_time + time_offset, 3)}
_note_list.append(note_data)
print(note_data)
return _note_list
get_base_notes_data(midi_file_path, bpm)
運(yùn)行代碼 python3 xxx.py
(xxx 是你保存的 python 文件的名字)
這段代碼只實(shí)現(xiàn)了最核心的 midi 數(shù)據(jù)提取揭糕,具體的自動化邏輯需要使用者自己寫萝快,例如當(dāng)前有100個(gè) midi 文件,不可能手動一個(gè)一個(gè)生成著角。