Как преобразовать файлы midi в нажатия клавиш (в Python)?

Я пытаюсь прочитать MIDI-файл, а затем преобразовать каждую ноту (миди-номер) в имитацию нажатия клавиши на клавиатуре (A,f,h,J,t...).

Я могу прочитать любой файл MIDI с библиотекой python-midi следующим образом:

pattern = midi.read_midifile("example.mid")

и я также могу имитировать нажатия клавиш с помощью pywin32 следующим образом:

shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys(key)

Но я понятия не имею, как на самом деле преобразовать миди-номера (которые находятся в миди-файлах) в нажатия клавиш.

Чтобы быть более точным, я пытаюсь преобразовать числа MIDI в ноты, а затем ноты в нажатия клавиш в соответствии с virtualpiano.net ( 61-клавиша), чтобы программа играла на этом фортепиано, нажав соответствующую кнопку на клавиатуре (вы можете нажать клавишу помощи в настройках фортепиано, чтобы увидеть, какая клавиша какая кнопка)

Конечно, мне также пришлось бы ждать между нажатиями клавиш, но это достаточно просто.

Любая помощь приветствуется. (64-разрядная версия Windows 10 (32-разрядная версия Python 2.7))


person alaswhu    schedule 26.01.2016    source источник


Ответы (3)


Если вы посмотрите на модуль midi, который вы используете, вы увидите, что есть некоторые константы, которые можно использовать для преобразования нот в их MIDI-номер и наоборот.

>>> import midi
>>> midi.C_0    # note C octave 0
0
>>> midi.G_3    # G octave 3
43
>>> midi.Gs_4   # G# octave 4
56
>>> midi.A_8    # A octave 8
105

>>> midi.NOTE_VALUE_MAP_SHARP[0]
C_0
>>> midi.NOTE_VALUE_MAP_SHARP[56]
Gs_4
>>> midi.NOTE_VALUE_MAP_SHARP[105]
A_8

Открытие MIDI-файла с помощью read_midifile() возвращает объект Pattern, который выглядит следующим образом (взято из примеров):

>>> midi.read_midifile('example.mid')
midi.Pattern(format=1, resolution=220, tracks=\
[midi.Track(\
  [midi.NoteOnEvent(tick=0, channel=0, data=[43, 20]),
   midi.NoteOffEvent(tick=100, channel=0, data=[43, 0]),
   midi.EndOfTrackEvent(tick=1, data=[])])])

NoteOnEvent содержит синхронизацию, номер MIDI/высоту и скорость, которые вы можете получить:

>>> on = midi.NoteOnEvent(tick=0, channel=0, data=[43, 20])
>>> on.pitch
43
>>> midi.NOTE_VALUE_MAP_SHARP[on.pitch]
'G_3'

Все это интересно, но на самом деле вам не нужно преобразовывать номер MIDI в ноту, вам просто нужно преобразовать его в клавишу клавиатуры для этой ноты, используемую http://virtualpiano.net/.

Средняя C равна MIDI 60, и эта нота соответствует 25-й клавише на клавиатуре виртуального пианино, которая активируется нажатием буквы t. Следующая нота, Cs_5, представляет собой MIDI 61, заглавные буквы T (<shift>-t). Оттуда вы можете определить сопоставление номеров MIDI с поддерживаемыми клавишами виртуального пианино; это:

midi_to_vk = (
    [None]*36 +
    list('1!2@34$5%6^78*9(0qQwWeErtTyYuiIoOpPasSdDfgGhHjJklLzZxcCvVbBnm') +
    [None]*31
)

Следующая проблема, с которой вы столкнетесь, — это отправка ключевых событий. Обратите внимание, что в MIDI несколько нот могут воспроизводиться одновременно или перекрываться во времени. Это означает, что вам может потребоваться отправить более одного события нажатия клавиши одновременно.

Я не думаю, что вы можете управлять скоростью, используя компьютерную клавиатуру. Есть еще вопрос времени, но вы сказали, что для вас это не проблема.

person mhawke    schedule 27.01.2016

Сначала проверьте этот вопрос. Это общая идея о том, как имитировать нажатия клавиш, может показаться, что это много, но это просто большой список клавиш. Затем, чтобы преобразовать миди в кнопки клавиатуры, вы должны создать сопоставление словаря между нотами и кнопками клавиатуры.

person T.Chmelevskij    schedule 26.01.2016
comment
Я знаю, как имитировать нажатия клавиш. Словарь, о котором вы говорите, - это проблема. На всех веб-сайтах, посвященных преобразованию миди в ноты, есть таблица клавиш, которые я не понимаю. Типа: нота A#, октава 4, это то и то миди-число, но на самом деле. C-5, A#-2 и других «обычных» нот нет на виртуальном пианино, у него есть такие ноты, как C-61 и A#-45, которые намного выше любой таблицы на любом веб-сайте. - person alaswhu; 26.01.2016

Я понимаю, что вам действительно нужен способ конвертировать номер миди-ноты в ноту в стандартной нотации.

Вот некоторые элементы из Википедии:

... GM указывает, что нота номер 69 воспроизводит A440, что, в свою очередь, фиксирует среднюю ноту C как ноту номер 60 ...

(из MIDI — General MIDI

Преобразование номера миди-ноты (d) в частоту (f) выполняется по следующей формуле:
f = 2 (d-69)/12 * 440 Гц

(из Стандарт настройки MIDI — значения частоты)

И, наконец, из C (музыкальная нота) - Обозначение по октаве

Scientific designation  |Octave name |    Frequency (Hz) |    Other names
C4                      | One-lined  |           261.626 |    Middle C

Изображение C4 на перегородке и фортепианной клавиатуре из Википедии

Итак, C4 — это миди-нота 69, а миди-ноты разделены полутоном (*). Так как у вас 12 полутонов в одной октаве, вы получите C5 на миди-ноте 81, а знаменитая A440 (миди-нота 69) — это A4 в экспоненциальном представлении.

В качестве примера для таблицы

Midi note | Scientific notation
60        | C4
62        | D4
64        | E4
65        | F4
67        | G4
69        | A4
70        | B4
71        | C5

И вы получите F♯4 на миди 66...

(*) в музыкальном плане это то, что называется равным темпераментом. Midi допускает более точное определение высоты тона, но это выходит далеко за рамки этого ответа.

person Serge Ballesta    schedule 27.01.2016
comment
Я думаю, что отображение номеров нот MIDI отличается в отношении модуля python-midi. Если я правильно понимаю, этот модуль отображает MIDI 60 на C_5 вместо C_4. import midi; print midi.C_5 отображает 60, что должно равняться среднему C. Но, как указано в en.wikipedia. org/wiki/, средний C — это C4 в научном обозначении. Возможно, я что-то упускаю? Может ли быть так, что одни начинаются с октавы -1, а другие с октавы 1? - person mhawke; 27.01.2016