Проблемы с созданием midi - файла (Python)
Нижеуказанный код создаёт файл, в котором ноты первого аккорда звучат одновременно, последующих - поочерёдно.
import mido
from mido import MidiFile, MidiTrack
mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)
track.append(mido.Message('program_change', program=36, time=0, channel=0))
track.append(mido.Message('note_on', note=48, velocity=64, time=0))
track.append(mido.Message('note_on', note=52, velocity=64, time=0))
track.append(mido.Message('note_on', note=55, velocity=64, time=0))
track.append(mido.Message('note_off', note=48, velocity=64, time=64))
track.append(mido.Message('note_off', note=52, velocity=64, time=64))
track.append(mido.Message('note_off', note=55, velocity=64, time=64))
track.append(mido.Message('note_on', note=48, velocity=64, time=192))
track.append(mido.Message('note_on', note=52, velocity=64, time=192))
track.append(mido.Message('note_on', note=55, velocity=64, time=192))
track.append(mido.Message('note_off', note=48, velocity=64, time=256))
track.append(mido.Message('note_off', note=52, velocity=64, time=256))
track.append(mido.Message('note_off', note=55, velocity=64, time=256))
track.append(mido.Message('note_on', note=48, velocity=64, time=384))
track.append(mido.Message('note_on', note=52, velocity=64, time=384))
track.append(mido.Message('note_on', note=55, velocity=64, time=384))
track.append(mido.Message('note_off', note=48, velocity=64, time=448))
track.append(mido.Message('note_off', note=52, velocity=64, time=448))
track.append(mido.Message('note_off', note=55, velocity=64, time=448))
mid.save('output.mid')
Как решить эту проблему?
Ответы (3 шт):
Впервые вижу эту библиотеку, но подметил, что track.append очень похож по своей логике на инструменты по написанию макросов. А в макросах, есть такая особенность, что параметр time - это время с момента предыдущего события, а не абсолютное время от начало программы.
import mido
from mido import MidiFile, MidiTrack
mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)
track.append(mido.Message("program_change", program=36, time=0, channel=0))
track.append(mido.Message("note_on", note=48, velocity=64, time=0))
track.append(mido.Message("note_on", note=52, velocity=64, time=0))
track.append(mido.Message("note_on", note=55, velocity=64, time=0))
track.append(mido.Message("note_off", note=48, velocity=64, time=192))
track.append(mido.Message("note_off", note=52, velocity=64, time=0))
track.append(mido.Message("note_off", note=55, velocity=64, time=0))
track.append(mido.Message("note_on", note=48, velocity=64, time=192))
track.append(mido.Message("note_on", note=52, velocity=64, time=0))
track.append(mido.Message("note_on", note=55, velocity=64, time=0))
track.append(mido.Message("note_off", note=48, velocity=64, time=192))
track.append(mido.Message("note_off", note=52, velocity=64, time=0))
track.append(mido.Message("note_off", note=55, velocity=64, time=0))
track.append(mido.Message("note_on", note=48, velocity=64, time=192))
track.append(mido.Message("note_on", note=52, velocity=64, time=0))
track.append(mido.Message("note_on", note=55, velocity=64, time=0))
track.append(mido.Message("note_off", note=48, velocity=64, time=192))
track.append(mido.Message("note_off", note=52, velocity=64, time=0))
track.append(mido.Message("note_off", note=55, velocity=64, time=0))
mid.save("output.mid")
Собственно что выходит? Зажимаем аккорд:
track.append(mido.Message("note_on", note=48, velocity=64, time=0))
track.append(mido.Message("note_on", note=52, velocity=64, time=0))
track.append(mido.Message("note_on", note=55, velocity=64, time=0))
Так как у всех нот параметр time=0, они звучат одновременно.
Далее мы удерживаем аккорд:
track.append(mido.Message("note_off", note=48, velocity=64, time=192))
track.append(mido.Message("note_off", note=52, velocity=64, time=0))
track.append(mido.Message("note_off", note=55, velocity=64, time=0))
Удерживаем мы его time=192 от предыдущего события. Первая нота отпускается, а за ней отпускаются и остальные, а так как от предыдущего действия у них задержка time=0 - всё выходит одновременно.
Собственно дальше подбирайте нужные тайминги, аккорды и просто держите в голове, что параметр time - это время с момента предыдущего события.
В дополнение к ответу Amgarak я бы ещё предложил сократить код за счёт выноса повторяющихся действий в отдельную функцию. Код не проверял, но как-то так должно получиться:
import mido
from mido import MidiFile, MidiTrack
def add_accord(track, accord, velocity, time1, time2):
for i, note in enumerate(accord):
track.append(mido.Message("note_on", note=note, velocity=velocity, time=(0 if i else time1)))
for i, note in enumerate(accord):
track.append(mido.Message("note_of", note=note, velocity=velocity, time=(0 if i else time2)))
mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)
accord = (48, 52, 55)
velocity = 64
time_shift = 192
add_accord(track, accord, velocity, 0, time_shift)
add_accord(track, accord, velocity, time_shift, time_shift)
add_accord(track, accord, velocity, time_shift, time_shift)
mid.save("output.mid")
Логика рабочего кода (создан на основе ответа Amgarak):
import mido
from mido import MidiFile, MidiTrack
mid = MidiFile()
track = MidiTrack()
mid.tracks.append(track)
track.append(mido.Message("note_on", note=48, velocity=64, time=0))
track.append(mido.Message("note_on", note=52, velocity=64, time=0))
track.append(mido.Message("note_on", note=55, velocity=64, time=0))
track.append(mido.Message("note_off", note=48, velocity=64, time=64))
track.append(mido.Message("note_off", note=52, velocity=64, time=64))
track.append(mido.Message("note_off", note=55, velocity=64, time=64))
track.append(mido.Message("note_on", note=48, velocity=64, time=0))
track.append(mido.Message("note_on", note=52, velocity=64, time=0))
track.append(mido.Message("note_on", note=55, velocity=64, time=0))
track.append(mido.Message("note_off", note=48, velocity=64, time=64))
track.append(mido.Message("note_off", note=52, velocity=64, time=64))
track.append(mido.Message("note_off", note=55, velocity=64, time=64))
Данный код создаст midi - файл с повторяющимся аккордом.