简体   繁体   English

在music21中将钢琴卷帘转换为MIDI?

[英]Converting piano roll to MIDI in music21?

I am using music21 for handling MIDI and mXML files and converting them to a piano roll I am using in my project.我正在使用 music21 来处理 MIDI 和 mXML 文件,并将它们转换为我在项目中使用的钢琴卷帘。

My piano roll is made up of sequence of 88-dimensional vectors where each element in a vector represents one pitch.我的钢琴卷由 88 维向量序列组成,其中向量中的每个元素代表一个音高。 One vector is one time step that can be 16th, 8th, 4th, and so on.一个向量是一个时间步长,可以是第 16 次、第 8 次、第 4 次等。 Elements can obtain three values {0, 1, 2}.元素可以获得三个值 {0, 1, 2}。 0 means note is off. 0 表示音符关闭。 1 means note is on. 1 表示注释已打开。 2 means also that note is on but it always follows 1 - that is how I distinguish multiple key presses of same note. 2 也表示该音符已打开,但它始终跟随 1 - 这就是我区分同一音符的多个按键的方式。 Eg, let time step be 8th and these two pitches be C and E:例如,让时间步长为 8th,这两个音高为 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]

We see that C and E are simultaneously played for quarter note, then again for quarter note, and we end with a C that lasts quarter note.我们看到 C 和 E 同时演奏四分音符,然后再次演奏四分音符,最后以持续四分音符的 C 结束。

Right now, I am creating Stream() for every note and fill it as notes come.现在,我正在为每个音符创建Stream()并在音符出现时填充它。 That gives me 88 streams and when I convert that to MIDI, and open that MIDI with MuseScore, that leaves me with a mess that is not readable.这给了我 88 个流,当我将其转换为 MIDI 并使用 MuseScore 打开该 MIDI 时,这给我留下了无法读取的混乱局面。

My question is, is there some nicer way to transform this kind of piano roll to MIDI?我的问题是,有没有更好的方法可以将这种钢琴卷帘转换为 MIDI? Some algorithm, or idea which I could use would be appreciated.一些我可以使用的算法或想法将不胜感激。

In my opinion music21 is a very good library but too high-level for this job.在我看来,music21 是一个非常好的库,但对于这项工作来说太高级了。 There is no such thing as streams, quarter notes or chords in MIDI -- only messages. MIDI 中没有流、四分音符或和弦之类的东西——只有消息。 Try the Mido library instead.请尝试使用Mido库。 Here is sample code:这是示例代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM