如何将 midi 文件转换为按键(在 Python 中)?

How to convert midi files to keypresses (in Python)?

我正在尝试读取 MIDI 文件,然后将每个音符(MIDI 编号)转换为键盘上的模拟按键(A、f、h、J、t...)。

我可以像这样使用 python-midi 库读取任何 MIDI 文件:

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

而且我还可以像这样用 pywin32 模拟按键:

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

但我不知道如何将 midi 数字(在 midi 文件中)实际转换为按键。

更准确地说,我正在尝试将 MIDI 数字转换为音符,然后根据 virtualpiano.net(61 键)将音符转换为按键,以便程序可以通过按下相应的按钮来弹奏钢琴键盘(你可以在钢琴的设置中按下按键辅助来查看哪个键是哪个按钮)

当然我也必须在按键之间等待,但这很容易。

感谢任何帮助。 (Windows 10 64 位 (32 位 Python 2.7))

先检查this个问题。这是关于如何模拟按键的一般思路,它可能看起来很多,但它只是一大堆按键。然后将 midi 转换为键盘按钮,您将在音符和键盘按钮之间创建字典映射。

我知道您真正需要的是一种将 MIDI 音符编号转换为标准记谱法音符的方法。

以下是来自维基百科的一些元素:

... GM specifies that note number 69 plays A440, which in turn fixes middle C as note number 60 ...

(来自 MIDI - General MIDI

Converting from midi note number (d) to frequency (f) is given by the following formula:
f = 2 (d-69)/12 * 440 Hz

(来自 MIDI Tuning Standard - Frequency values

最后来自 C (musical note) - Designation by octave

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

所以C4是midi音符69,midi音符之间用半音(*)隔开。由于一个八度音阶有 12 个半音,因此在 midi note 81 处会得到 C5,而著名的 A440(midi note 69)是 A4 科学记数法。

以table

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

你会在 midi 66 处得到 F♯4...

(*)在音乐上就是所谓的平均律。 Midi 允许更精细的音高定义,但它会远远超出这个答案。

如果您看一下您正在使用的 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

打开一个带有 read_midifile() returns 一个 Pattern 对象的 MIDI 文件,它看起来像这样(取自示例):

>>> 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 number/pitch 和速度,您可以检索:

>>> 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/ 使用的该音符的键盘键即可。

Middle C 等于 MIDI 60,此音符对应虚拟钢琴键盘上的第 25 个键,通过按字母 t 激活。下一个音符 Cs_5 是大写的 MIDI 61 T (<shift>-t)。从那里你可以计算出 MIDI 数字到支持的虚拟钢琴键的映射;是这样的:

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

您将面临的下一个问题是发送按键事件。请注意,在 MIDI 中,多个音符可以同时播放,也可以及时重叠。这意味着您可能需要能够同时发送多个按键事件。

我认为您无法使用计算机键盘处理速度。还有就是时间问题,你说这对你来说不是问题。