Python:从 type 0 转换为 type 1 midi

Posted

技术标签:

【中文标题】Python:从 type 0 转换为 type 1 midi【英文标题】:Python: Convert from type 0 to type 1 midi 【发布时间】:2020-06-05 21:31:29 【问题描述】:

类型 0 的 midi 文件 (example) 将所有乐器都挤在一个轨道上。

Type 1 MIDI 文件将乐器分离成不同的轨道。

有没有好办法把0型转换成1型?如果有任何资源可以运行此转换,我很想听听它们!

【问题讨论】:

我猜这需要 ~100 LOC 并且有些人认为这样做是正确的,因为 midi 时间戳是相对的,所以我希望像 mido 这样的库包含像 unmerge_tracks 这样的方法 看起来你想要一个库。也许this 很有用。在这里帮不上什么忙。可能还有更现代的库,搜索pypi。 【参考方案1】:

这就是我处理这个问题的方法。重要的见解是,midi 文件中的channel 指定了发送某些信息的设备端口(例如,某些 midi 键盘输入),而program 是乐器声音(例如锯齿导联,cajun banjo...)。

这意味着可以创建一个字典,其中每个语音一个键,以及一个包含以该语音播放的音符的值列表。时间最初应存储在全局坐标中(如在 type-0 文件中,相对时间坐标在所有声部中表示,但我们现在将声部分成不同的音符列表)。

然后可以转换回相对时间单位,存储来自输入类型 0 音轨的 bpm 和时间分辨率值,然后哇哦——这是你的类型 1 MIDI。

from collections import defaultdict
import mido, os

def subdivide_midi_tracks(path):
  '''Convert a type 0 midi file to a type 1 midi file'''
  m = mido.MidiFile(path) # load the original type-0 midi file
  messages = [] # a list of message dicts, one per track
  for track in m.tracks:
    time = 0 # store time in aggregate units
    track_messages = []
    for idx, i in enumerate(track):
      i = i.dict()
      if i.get('time', None): time += i.get('time')
      i['time'] = time
      track_messages.append(i)
    messages.append(track_messages)
  # build a dictionary of the events for each channel
  d = defaultdict(list) # d[channel_id] = [notes]
  for track_idx, track in enumerate(messages):
    for i in track:
      channel = i.get('channel', -1)
      d[channel].append(i)
  # covert time units in each program back to relative units
  for channel in d:
    total_time = 0
    for i in sorted(d[channel], key=lambda i: i['time']):
      t = i['time']
      i['time'] = t - total_time
      total_time = t
  # create a midi file and add a track for each channel
  m2 = mido.MidiFile()
  for channel in sorted(d.keys()):
    track = mido.midifiles.tracks.MidiTrack()
    # add the notes to this track
    for note in d[channel]:
      note_type = note['type']
      del note['type']
      # if this is a meta message, append a meta message else a messaege
      try:
        track.append(mido.MetaMessage(note_type, **note))
      except:
        track.append(mido.Message(note_type, **note))
    m2.tracks.append(track)
  # ensure the time quantization is the same in the new midi file
  m2.ticks_per_beat = m.ticks_per_beat
  return m2

m = midi.load("data/nes/'Bomb_Man's_Stage'_Mega_Man_I_by_Mark_Richardson.mid")
m2 = subdivide_midi_tracks(m.path)
m2.save('whoop.mid')
os.system('open whoop.mid')

【讨论】:

以上是关于Python:从 type 0 转换为 type 1 midi的主要内容,如果未能解决你的问题,请参考以下文章

将许多字段的 data_type 从 bit 转换为 tinyint

Python 数据类型到 pyspark.sql.types 的自动转换

Python 数字类型之 int float

如何将类型 <class 'pyspark.sql.types.Row'> 转换为 Vector

python入门6 python查看数据类型及类型转换

python中eval函数作用