我正在使用music21来处理MIDI和mXML文件,并将它们转换为我在项目中使用的钢琴卷。
我的钢琴卷由88维向量序列组成,其中向量中的每个元素代表一个音高。一个向量是一个时间步长,可以是第16,第8,第4等,依此类推。元素可以获得三个值{0,1,2}。 0表示音符已关闭。 1表示备注。 2表示音符已打开,但始终跟随1 - 这就是我区分同一音符的多个按键的方式。例如,让时间步长为8,这两个音高为C和E:
[0 0 0 ... 1 0 0 0 1 ... 0]
[0 0 0 ... 1 0 0 0 1 ... 0]
[0 0 0 ... 2 0 0 0 2 ... 0]
[0 0 0 ... 2 0 0 0 2 ... 0]
[0 0 0 ... 1 0 0 0 0 ... 0]
[0 0 0 ... 1 0 0 0 0 ... 0]
我们看到C和E同时播放四分音符,然后再播放四分音符,我们以C持续四分音符结束。
现在,我正在为每个音符创建Stream()
,并在音符到来时填充它。这给了我88个流,当我将它转换为MIDI时,用MuseScore打开那个MIDI,这让我感到一团无法阅读。
我的问题是,有没有更好的方法将这种钢琴音乐转换为MIDI?我会赞赏一些算法或想法。
答案 0 :(得分:0)
在我看来,music21是一个很好的库,但对于 这个工作。没有流,四分音符或和弦之类的东西 在MIDI中-仅消息。尝试 Mido库。这里 是示例代码:
from mido import Message, MidiFile, MidiTrack
def stop_note(note, time):
return Message('note_off', note = note,
velocity = 0, time = time)
def start_note(note, time):
return Message('note_on', note = note,
velocity = 127, time = time)
def roll_to_track(roll):
delta = 0
# State of the notes in the roll.
notes = [False] * len(roll[0])
# MIDI note for first column.
midi_base = 60
for row in roll:
for i, col in enumerate(row):
note = midi_base + i
if col == 1:
if notes[i]:
# First stop the ringing note
yield stop_note(note, delta)
delta = 0
yield start_note(note, delta)
delta = 0
notes[i] = True
elif col == 0:
if notes[i]:
# Stop the ringing note
yield stop_note(note, delta)
delta = 0
notes[i] = False
# ms per row
delta += 500
roll = [[0, 0, 0, 1, 0, 0, 0, 1, 0],
[0, 0, 0, 1, 0, 0, 0, 1, 0],
[0, 0, 0, 2, 0, 0, 0, 2, 0],
[0, 1, 0, 2, 0, 0, 0, 2, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0]]
midi = MidiFile(type = 1)
midi.tracks.append(MidiTrack(roll_to_track(roll)))
midi.save('test.mid')