在钢琴21中将钢琴卷转换为MIDI?

时间:2017-06-20 19:38:16

标签: python music21

我正在使用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?我会赞赏一些算法或想法。

1 个答案:

答案 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')