3

我正在使用 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?一些我可以使用的算法或想法将不胜感激。

4

1 回答 1

1

在我看来,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')
于 2020-05-21T21:10:27.343 回答