Создание MIDI файла
생성일: 2025년 1월 10일
생성일: 2025년 1월 10일
Создай midi файл
import rtmidi
import time
import random
def generate_midi(filename="rhythm.mid", tempo=260, num_repeats=2):
"""
Генерирует MIDI-файл с простым ритмическим рисунком.
textArgs: filename: Имя выходного MIDI-файла. tempo: Темп (ударов в минуту). num_repeats: Сколько раз повторить ритм. """ midiout = rtmidi.MidiOut() midiout.open_virtual_port("Python MIDI Output") # Конвертируем темп в микросекунды tempo_us = int(60000000 / tempo) # Создаем заголовки header = [0xFF, 0x51, 0x03, (tempo_us >> 16) & 0xFF, (tempo_us >> 8) & 0xFF, tempo_us & 0xFF] midiout.send_message(header) # Задаем темп midiout.send_message([0xC0, 0x00, 0x00]) # Задаем инструмент: пианино current_time = 0 # Текущее время в тактах # Ритм rhythm = [ (0, 0.25, 60), # 1 четвертная нота, нота "До" (0.25, 0.25, 62), # 2 четвертная нота, нота "Ре" (0.5, 0.25, 64), # 3 четвертная нота, нота "Ми" (0.75, 0.25, 65), # 4 четвертная нота, нота "Фа" (1, 0.125, None) # 1 восьмая пауза ] # Генерация MIDI-событий на основе ритма for _ in range(num_repeats): for start, duration, note in rhythm: start_time = current_time + start end_time = current_time + start + duration if note is not None: # Включаем ноту midiout.send_message([0x90, note, 100]) # Note on time.sleep(duration) # Длительность ноты midiout.send_message([0x80, note, 0]) # Note off current_time += 1 # Вспомогательная функция для вывода текущего времени def sleep_until_next_event(current_time, next_event_time, tempo): time_to_wait = (next_event_time - current_time) * (60/tempo) time.sleep(time_to_wait) # Закрываем порт midiout.close_port() del midiout
generate_midi(filename="my_rhythm.mid", num_repeats=10)
print("MIDI-файл 'my_rhythm.mid' успешно создан")
Ниже приведён пример кода на Python с использованием библиотеки mido, который действительно создаёт MIDI-файл на диск (а не просто выводит MIDI-сообщения в виртуальный порт). Этот пример повторяет логику «ритмического рисунка» из вашего кода, но сохраняет результат в файл:
pythonimport mido from mido import Message, MidiFile, MidiTrack, MetaMessage, bpm2tempo def generate_midi(filename="rhythm.mid", tempo=260, num_repeats=2): """ Генерирует MIDI-файл с простым ритмическим рисунком. Args: filename: Имя выходного MIDI-файла. tempo: Темп (ударов в минуту). num_repeats: Сколько раз повторить ритм. """ # Создаем объект MidiFile и добавляем в него один трек mid = MidiFile() track = MidiTrack() mid.tracks.append(track) # Устанавливаем количество «тиков» (шагов) на четвертную ноту # По умолчанию mido ставит 480, можно оставить как есть или изменить mid.ticks_per_beat = 480 # Задаём темп (перевод bpm -> микросекунды на четверть) track.append(MetaMessage('set_tempo', tempo=bpm2tempo(tempo), time=0)) # Устанавливаем инструмент (программа 0 — акустическое пианино) track.append(Message('program_change', program=0, time=0)) # Пояснение к расчёту длительностей: # - По умолчанию mid.ticks_per_beat = 480 означает, что # 1 четвертная нота = 480 тиков. # - В вашем коде каждая «четверть» описана как duration=0.25 (т.к. 1 такт = 1.0), # значит 0.25 такта — это и есть 1 четверть. Но для удобства мы просто будем # интерпретировать duration, умножая её на (4 * 480), если хотим считать 1.0 за полный такт из 4 четвертей. # # Однако ваш код фактически игнорировал start и просто проигрывал ноты подряд. # Поэтому ниже мы делаем так: # - Если note != None, то включаем ноту (note_on) и через (duration) «долю» времени даём note_off. # - Если note == None, то это пауза (rest): никаких note_on/note_off, просто ждём (duration). # Пример ритмического рисунка: # (start, duration, note) # start duration note # 0.00 0.25 60 (четверть) # 0.25 0.25 62 (четверть) # 0.50 0.25 64 (четверть) # 0.75 0.25 65 (четверть) # 1.00 0.125 None (пауза на восьмую) # В исходном коде start никак не использовался для «запаздывания» начала, # поэтому здесь тоже будем играть их подряд. rhythm = [ (0, 0.25, 60), # четверть, нота "До" (0.25, 0.25, 62), # четверть, нота "Ре" (0.5, 0.25, 64), # четверть, нота "Ми" (0.75, 0.25, 65), # четверть, нота "Фа" (1, 0.125, None) # восьмая пауза ] # Определим, сколько «тиков» считать за один полный такт (4 четверти) ticks_per_measure = mid.ticks_per_beat * 4 # 4 четверти в такте for _ in range(num_repeats): for (start, duration, note) in rhythm: # Считаем, что duration — это доля от полного такта (1.0 = весь такт), # значит реальная длительность в тиках будет: duration_ticks = int(duration * ticks_per_measure) if note is not None: # Включаем ноту (с time=0, т.к. нота начинается сразу # после предыдущего события) track.append(Message('note_on', note=note, velocity=100, time=0)) # Выключаем ноту через duration_ticks track.append(Message('note_off', note=note, velocity=0, time=duration_ticks)) else: # Если note=None, то это пауза: просто "пропускаем" нужное кол-во тиков # (никаких событий note_on/note_off), # поэтому вставим пустое событие с тем же интервалом. # Обычно делают MetaMessage('skip'), но проще — # сдвинуть всё на duration_ticks до следующего события. # Реализуется через time в следующем событии. А раз тут нет note_on, # даём временной интервал «в пустоту». track.append(Message('note_off', note=0, velocity=0, time=duration_ticks)) # Сохраняем результат в файл mid.save(filename) # Запуск функции if __name__ == "__main__": generate_midi("my_rhythm.mid", tempo=260, num_repeats=10) print("MIDI-файл 'my_rhythm.mid' успешно создан.")
Установка темпа
С помощью MetaMessage('set_tempo', tempo=bpm2tempo(tempo))
указываем число микросекунд на четвертную ноту, переводя BPM (удары в минуту) в соответствующее значение.
ticks_per_beat
По умолчанию в Mido 1 четверть = 480 «тиков» (шагов). Если хотите, можете изменить это число, например, на 960 и т.д.
Добавление событий (Messages)
note_on
со start_time=0
означает, что нота включится сразу после предыдущего события.note_off
с нужным time
указывает через сколько «тиков» завершить предыдущую ноту (или сделать паузу, если ноты не было).Повтор ритма
В цикле for _ in range(num_repeats)
мы многократно проигрываем один и тот же фрагмент.
Таким образом, при запуске этого скрипта вы получите файл my_rhythm.mid
, который можно открыть любым MIDI-секвенсором или проигрывателем.