为什么有多个 set_tempo 元 MIDI 消息? (以及如何处理)

Why are there multiple set_tempo meta midi messages? (and how to deal)

我目前正在为 midi 文件编写一个解析器,这样我就可以使用马尔可夫链生成我自己的音乐。

我有点困惑为什么每个文件有这么多 set_tempo midi 元信息(在音轨 0 元信息部分)。如果将它们设置为不同的增量时间,我会理解,但有些不是。还有一些似乎为相同的增量时间设置了相同的速度,这似乎奇怪地多余。

这是一个例子...

<meta message set_tempo tempo=857139 time=0>
<meta message set_tempo tempo=857139 time=0>
<meta message set_tempo tempo=857632 time=0>
<meta message set_tempo tempo=857632 time=180224>
<meta message set_tempo tempo=895896 time=438>
<meta message set_tempo tempo=930917 time=438>
<meta message set_tempo tempo=967865 time=438>
<meta message set_tempo tempo=1008868 time=438>
<meta message set_tempo tempo=1053514 time=438>
<meta message set_tempo tempo=1101084 time=438>
<meta message set_tempo tempo=2403785 time=438>
<meta message set_tempo tempo=857632 time=1030>
<meta message set_tempo tempo=895896 time=292>
<meta message set_tempo tempo=930917 time=292>
<meta message set_tempo tempo=967865 time=292>
<meta message set_tempo tempo=1008868 time=292>
<meta message set_tempo tempo=1053514 time=292>
<meta message set_tempo tempo=1101084 time=292>
<meta message set_tempo tempo=2403785 time=292>
<meta message set_tempo tempo=2403785 time=1028>
<meta message end_of_track time=5119>

所以,

(1) 为什么会有重复?
(2) 不同增量时间的速度变化是否重要? (也就是说,这是因为音乐在各个部分速度 up/slows 变慢
(3) 是否值得为我的生成器实现一个处理速度变化的隐藏马尔可夫链

如有任何帮助,我们将不胜感激。 N.B。我对乐理知之甚少

干杯

这是我的解决方案,我是不是做错了什么(在下面的回答中回复评论)。


import mido

all_mid = [' (Yiruma).mid']

# add time from start to message data (for sorting and adjusted delta time purposes)
def add_cumulative_time(msg, current_time):
    add_on = msg.time
    current_time += add_on
    return current_time, add_on

def clean(mid, all_messages):  # for each track (then message) do the following
    msgwithtempos = []
    for i, track in enumerate(mid.tracks):
        current_time = 0
        for msg in track:
            current_time = add_cumulative_time(msg, current_time)[0]
            allowed_types = ["note_on", "note_off", "program_change", "set_tempo"] 
            if msg.type in allowed_types:
                all_messages.append([msg, current_time])
            else:
                pass
    return all_messages, msgwithtempos


def main():  # for each midi file do the following
    all_lists = []
    for i in range(0, len(all_mid)):
        all_messages = []
        mid = mido.MidiFile(all_mid[i])
        ticksperbeat = mid.ticks_per_beat
        all_messages, msgwithtempos = clean(mid, all_messages)
        final_messages = all_messages + msgwithtempos
        final_messages = sorted(final_messages, key=lambda x: x[1])
        all_lists += final_messages
    for i, item in enumerate(all_lists):
        if all_lists[i][0].type == "set_tempo":
            while all_lists[i+1][0].type == "set_tempo": # talk about this as an error with i-1 being logical but not working
                all_lists.pop(i+1)
    return all_lists, ticksperbeat


if __name__ == '__main__':
    main()

  1. 我想这些复制品只是真实乐器或类似乐器录音的产物。不重要。
  2. 是的,节奏的变化导致音乐播放速度变慢或变快。
  3. 您绝对必须尊重所有 速度变化。这是上一句的结果。

如果您使用的是格式 0 文件,MIDI 1.0 规范说明如下:

For a format 0 file, the tempo will be scattered through the track and the tempo map reader should ignore the intervening events

我认为这意味着要使用第一个速度。我已经将具有多个速度事件的 MIDI 文件拖到多个程序中,它们倾向于选择第一个速度,尽管 Ableton 有时似乎对选择哪个速度有点随机。

我的 midi 文件也有一长串“设定速度”信息。它们似乎是虚拟消息,仅用于其 'time' 字段值。

时间字段用于在第一轨道的特定时间放置“标记”和“key_signature”消息。第一首曲目中没有音符。见下文。第二个和第三个音轨在这个midi文件中有音符(下面没有显示这两个音轨)。

    MIDI-MESSAGE KEY:VALUE pairs ...
 
    track_name name:Clair de Lune, time:0
    ...
    time_signature numerator:9, denominator:8, clocks_per_click:12, notated_32nd_notes_per_beat:8, time:0
    key_signature key:Db, time:0
    set_tempo tempo:600000, time:0
    marker text:Andante tres expressif, time:0
    set_tempo tempo:1875000, time:240
    set_tempo tempo:888889, time:240
    set_tempo tempo:821918, time:1680
    ...
    set_tempo tempo:789474, time:240
    set_tempo tempo:863309, time:240
    set_tempo tempo:909091, time:460
    ...
    set_tempo tempo:1846154, time:740
    set_tempo tempo:863309, time:240
    marker text:Tempo rubato, time:0
    set_tempo tempo:857756, time:40
    ...
    set_tempo tempo:571429, time:40
    set_tempo tempo:585366, time:600
    set_tempo tempo:535714, time:120
    set_tempo tempo:515818, time:480
    key_signature key:E, time:240
    set_tempo tempo:524017, time:0
    marker text:En animant, time:0
    set_tempo tempo:481618, time:480
    set_tempo tempo:498132, time:240
    ...
    end_of_track