pymididefs 0.2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pymididefs/__init__.py +34 -0
- pymididefs/cc.py +284 -0
- pymididefs/ci.py +79 -0
- pymididefs/drums.py +221 -0
- pymididefs/gm.py +470 -0
- pymididefs/meta.py +46 -0
- pymididefs/notes.py +389 -0
- pymididefs/py.typed +0 -0
- pymididefs/rpn.py +64 -0
- pymididefs/status.py +56 -0
- pymididefs/ump.py +128 -0
- pymididefs-0.2.4.dist-info/METADATA +189 -0
- pymididefs-0.2.4.dist-info/RECORD +15 -0
- pymididefs-0.2.4.dist-info/WHEEL +4 -0
- pymididefs-0.2.4.dist-info/licenses/LICENSE +21 -0
pymididefs/__init__.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""PyMidiDefs — comprehensive MIDI 1.0 and 2.0 constant definitions for Python.
|
|
2
|
+
|
|
3
|
+
A zero-dependency reference library covering the MIDI 1.0 Detailed Specification,
|
|
4
|
+
General MIDI Level 1, Universal MIDI Packet (UMP) format, and MIDI-CI.
|
|
5
|
+
|
|
6
|
+
Modules
|
|
7
|
+
-------
|
|
8
|
+
notes — MIDI note numbers and name/number conversion.
|
|
9
|
+
cc — Control Change number assignments and 14-bit pack/unpack helpers.
|
|
10
|
+
rpn — Standard Registered Parameter Numbers and the 14-bit parameter conventions shared with NRPN.
|
|
11
|
+
drums — General MIDI Level 1 percussion key map.
|
|
12
|
+
gm — General MIDI Level 1 instrument program numbers and families.
|
|
13
|
+
status — MIDI 1.0 status bytes (channel voice, system common, system real-time).
|
|
14
|
+
meta — Standard MIDI File meta-event type bytes.
|
|
15
|
+
ump — MIDI 2.0 Universal MIDI Packet message types and constants.
|
|
16
|
+
ci — MIDI 2.0 Capability Inquiry (MIDI-CI) constants.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import importlib.metadata
|
|
20
|
+
|
|
21
|
+
import pymididefs.notes
|
|
22
|
+
|
|
23
|
+
# Version is derived from the latest git tag at build time via hatch-vcs;
|
|
24
|
+
# `importlib.metadata` then reads it from the installed package metadata.
|
|
25
|
+
# The fallback only fires if someone runs from a raw source checkout without
|
|
26
|
+
# installing the package (e.g. directly from a git clone with no `pip install`).
|
|
27
|
+
try:
|
|
28
|
+
__version__ = importlib.metadata.version("pymididefs")
|
|
29
|
+
except importlib.metadata.PackageNotFoundError:
|
|
30
|
+
__version__ = "0.0.0+unknown"
|
|
31
|
+
|
|
32
|
+
# Convenience re-exports for the most common operations.
|
|
33
|
+
note_to_name = pymididefs.notes.note_to_name
|
|
34
|
+
name_to_note = pymididefs.notes.name_to_note
|
pymididefs/cc.py
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"""MIDI Control Change (CC) number assignments.
|
|
2
|
+
|
|
3
|
+
The MIDI specification defines 128 controller numbers (0–127). This module
|
|
4
|
+
provides named constants for all controllers that have a defined function in
|
|
5
|
+
the MIDI 1.0 Detailed Specification. Undefined/reserved numbers (3, 9, 14–15,
|
|
6
|
+
20–31, 85–90, 102–119) are omitted — they are available for general-purpose
|
|
7
|
+
use and do not have standard names.
|
|
8
|
+
|
|
9
|
+
Two ways to use this module::
|
|
10
|
+
|
|
11
|
+
import pymididefs.cc
|
|
12
|
+
|
|
13
|
+
# As named constants
|
|
14
|
+
pymididefs.cc.SUSTAIN_PEDAL # 64
|
|
15
|
+
|
|
16
|
+
# As a lookup dictionary
|
|
17
|
+
pymididefs.cc.CC_MAP["sustain_pedal"] # 64
|
|
18
|
+
|
|
19
|
+
Source: MIDI 1.0 Detailed Specification, Table III — Control Change Messages.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import typing
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ── MSB Controllers (0–31) ───────────────────────────────────────────────────
|
|
26
|
+
# High-resolution continuous controllers — most significant byte.
|
|
27
|
+
# Controllers 0–31 each have a corresponding LSB at CC 32–63.
|
|
28
|
+
|
|
29
|
+
BANK_SELECT_MSB = 0 # Bank Select
|
|
30
|
+
MODULATION_WHEEL = 1 # Modulation Wheel or Lever
|
|
31
|
+
BREATH_CONTROLLER = 2 # Breath Controller
|
|
32
|
+
# CC 3: Undefined
|
|
33
|
+
FOOT_CONTROLLER = 4 # Foot Controller
|
|
34
|
+
PORTAMENTO_TIME = 5 # Portamento Time
|
|
35
|
+
DATA_ENTRY_MSB = 6 # Data Entry MSB
|
|
36
|
+
VOLUME = 7 # Channel Volume (formerly Main Volume)
|
|
37
|
+
BALANCE = 8 # Balance
|
|
38
|
+
# CC 9: Undefined
|
|
39
|
+
PAN = 10 # Pan
|
|
40
|
+
EXPRESSION = 11 # Expression Controller
|
|
41
|
+
EFFECT_CONTROL_1 = 12 # Effect Control 1
|
|
42
|
+
EFFECT_CONTROL_2 = 13 # Effect Control 2
|
|
43
|
+
# CC 14–15: Undefined
|
|
44
|
+
GENERAL_PURPOSE_1 = 16 # General Purpose Controller 1
|
|
45
|
+
GENERAL_PURPOSE_2 = 17 # General Purpose Controller 2
|
|
46
|
+
GENERAL_PURPOSE_3 = 18 # General Purpose Controller 3
|
|
47
|
+
GENERAL_PURPOSE_4 = 19 # General Purpose Controller 4
|
|
48
|
+
# CC 20–31: Undefined
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# ── LSB Controllers (32–63) ──────────────────────────────────────────────────
|
|
52
|
+
# Low-resolution counterparts for CC 0–31.
|
|
53
|
+
# Only the most commonly referenced LSB values are named here.
|
|
54
|
+
|
|
55
|
+
BANK_SELECT_LSB = 32 # Bank Select LSB
|
|
56
|
+
MODULATION_WHEEL_LSB = 33 # Modulation Wheel LSB
|
|
57
|
+
BREATH_CONTROLLER_LSB = 34 # Breath Controller LSB
|
|
58
|
+
# CC 35: Undefined LSB
|
|
59
|
+
FOOT_CONTROLLER_LSB = 36 # Foot Controller LSB
|
|
60
|
+
PORTAMENTO_TIME_LSB = 37 # Portamento Time LSB
|
|
61
|
+
DATA_ENTRY_LSB = 38 # Data Entry LSB
|
|
62
|
+
VOLUME_LSB = 39 # Channel Volume LSB
|
|
63
|
+
BALANCE_LSB = 40 # Balance LSB
|
|
64
|
+
# CC 41: Undefined LSB
|
|
65
|
+
PAN_LSB = 42 # Pan LSB
|
|
66
|
+
EXPRESSION_LSB = 43 # Expression LSB
|
|
67
|
+
EFFECT_CONTROL_1_LSB = 44 # Effect Control 1 LSB
|
|
68
|
+
EFFECT_CONTROL_2_LSB = 45 # Effect Control 2 LSB
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# ── Switch Controllers (64–69) ───────────────────────────────────────────────
|
|
72
|
+
# On/off pedals and switches. Values 0–63 = Off, 64–127 = On.
|
|
73
|
+
|
|
74
|
+
SUSTAIN_PEDAL = 64 # Damper Pedal (Sustain)
|
|
75
|
+
PORTAMENTO_ON_OFF = 65 # Portamento On/Off
|
|
76
|
+
SOSTENUTO_PEDAL = 66 # Sostenuto
|
|
77
|
+
SOFT_PEDAL = 67 # Soft Pedal
|
|
78
|
+
LEGATO_PEDAL = 68 # Legato Footswitch
|
|
79
|
+
HOLD_2 = 69 # Hold 2
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# ── Sound Controllers (70–79) ────────────────────────────────────────────────
|
|
83
|
+
# Defined by General MIDI Level 2 for real-time timbre adjustment.
|
|
84
|
+
|
|
85
|
+
SOUND_VARIATION = 70 # Sound Controller 1 (default: Sound Variation)
|
|
86
|
+
FILTER_RESONANCE = 71 # Sound Controller 2 (default: Timbre / Filter Resonance)
|
|
87
|
+
RELEASE_TIME = 72 # Sound Controller 3 (default: Release Time)
|
|
88
|
+
ATTACK_TIME = 73 # Sound Controller 4 (default: Attack Time)
|
|
89
|
+
FILTER_CUTOFF = 74 # Sound Controller 5 (default: Brightness / Filter Cutoff)
|
|
90
|
+
SOUND_CONTROL_6 = 75 # Sound Controller 6 (default: Decay Time — GM2)
|
|
91
|
+
SOUND_CONTROL_7 = 76 # Sound Controller 7 (default: Vibrato Rate — GM2)
|
|
92
|
+
SOUND_CONTROL_8 = 77 # Sound Controller 8 (default: Vibrato Depth — GM2)
|
|
93
|
+
SOUND_CONTROL_9 = 78 # Sound Controller 9 (default: Vibrato Delay — GM2)
|
|
94
|
+
SOUND_CONTROL_10 = 79 # Sound Controller 10 (default: undefined)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# ── General Purpose Controllers (80–83) ──────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
GENERAL_PURPOSE_5 = 80 # General Purpose Controller 5
|
|
100
|
+
GENERAL_PURPOSE_6 = 81 # General Purpose Controller 6
|
|
101
|
+
GENERAL_PURPOSE_7 = 82 # General Purpose Controller 7
|
|
102
|
+
GENERAL_PURPOSE_8 = 83 # General Purpose Controller 8
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# ── Effects Send Levels (91–95) ──────────────────────────────────────────────
|
|
106
|
+
# CC 84 is Portamento Control; CC 85–90 are undefined.
|
|
107
|
+
|
|
108
|
+
PORTAMENTO_CONTROL = 84 # Portamento Control (source note for portamento)
|
|
109
|
+
# CC 85–90: Undefined
|
|
110
|
+
REVERB_DEPTH = 91 # Effects 1 Depth (default: Reverb Send Level)
|
|
111
|
+
TREMOLO_DEPTH = 92 # Effects 2 Depth (default: Tremolo Depth)
|
|
112
|
+
CHORUS_DEPTH = 93 # Effects 3 Depth (default: Chorus Send Level)
|
|
113
|
+
CELESTE_DEPTH = 94 # Effects 4 Depth (default: Celeste / Detune Depth)
|
|
114
|
+
PHASER_DEPTH = 95 # Effects 5 Depth (default: Phaser Depth)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# ── Parameter Control (96–101) ───────────────────────────────────────────────
|
|
118
|
+
# Used for RPN / NRPN parameter addressing and data manipulation.
|
|
119
|
+
|
|
120
|
+
DATA_INCREMENT = 96 # Data Increment (Data Entry +1)
|
|
121
|
+
DATA_DECREMENT = 97 # Data Decrement (Data Entry -1)
|
|
122
|
+
NRPN_LSB = 98 # Non-Registered Parameter Number LSB
|
|
123
|
+
NRPN_MSB = 99 # Non-Registered Parameter Number MSB
|
|
124
|
+
RPN_LSB = 100 # Registered Parameter Number LSB
|
|
125
|
+
RPN_MSB = 101 # Registered Parameter Number MSB
|
|
126
|
+
|
|
127
|
+
# CC 102–119: Undefined
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# ── Channel Mode Messages (120–127) ─────────────────────────────────────────
|
|
131
|
+
# These use the Control Change status byte but function as channel mode
|
|
132
|
+
# commands rather than continuous controllers.
|
|
133
|
+
|
|
134
|
+
ALL_SOUND_OFF = 120 # All Sound Off (value = 0)
|
|
135
|
+
RESET_ALL_CONTROLLERS = 121 # Reset All Controllers (value = 0)
|
|
136
|
+
LOCAL_CONTROL_ON_OFF = 122 # Local Control On/Off (0 = Off, 127 = On)
|
|
137
|
+
ALL_NOTES_OFF = 123 # All Notes Off (value = 0)
|
|
138
|
+
OMNI_MODE_OFF = 124 # Omni Mode Off (+ All Notes Off)
|
|
139
|
+
OMNI_MODE_ON = 125 # Omni Mode On (+ All Notes Off)
|
|
140
|
+
MONO_MODE_ON = 126 # Mono Mode On (+ All Notes Off)
|
|
141
|
+
POLY_MODE_ON = 127 # Poly Mode On (+ All Notes Off)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# ── Lookup dictionary ────────────────────────────────────────────────────────
|
|
145
|
+
# Maps snake_case names to CC numbers for string-based access.
|
|
146
|
+
|
|
147
|
+
CC_MAP: typing.Final[dict[str, int]] = {
|
|
148
|
+
# MSB controllers
|
|
149
|
+
"bank_select_msb": BANK_SELECT_MSB,
|
|
150
|
+
"modulation_wheel": MODULATION_WHEEL,
|
|
151
|
+
"breath_controller": BREATH_CONTROLLER,
|
|
152
|
+
"foot_controller": FOOT_CONTROLLER,
|
|
153
|
+
"portamento_time": PORTAMENTO_TIME,
|
|
154
|
+
"data_entry_msb": DATA_ENTRY_MSB,
|
|
155
|
+
"volume": VOLUME,
|
|
156
|
+
"balance": BALANCE,
|
|
157
|
+
"pan": PAN,
|
|
158
|
+
"expression": EXPRESSION,
|
|
159
|
+
"effect_control_1": EFFECT_CONTROL_1,
|
|
160
|
+
"effect_control_2": EFFECT_CONTROL_2,
|
|
161
|
+
"general_purpose_1": GENERAL_PURPOSE_1,
|
|
162
|
+
"general_purpose_2": GENERAL_PURPOSE_2,
|
|
163
|
+
"general_purpose_3": GENERAL_PURPOSE_3,
|
|
164
|
+
"general_purpose_4": GENERAL_PURPOSE_4,
|
|
165
|
+
|
|
166
|
+
# LSB controllers
|
|
167
|
+
"bank_select_lsb": BANK_SELECT_LSB,
|
|
168
|
+
"modulation_wheel_lsb": MODULATION_WHEEL_LSB,
|
|
169
|
+
"breath_controller_lsb": BREATH_CONTROLLER_LSB,
|
|
170
|
+
"foot_controller_lsb": FOOT_CONTROLLER_LSB,
|
|
171
|
+
"portamento_time_lsb": PORTAMENTO_TIME_LSB,
|
|
172
|
+
"data_entry_lsb": DATA_ENTRY_LSB,
|
|
173
|
+
"volume_lsb": VOLUME_LSB,
|
|
174
|
+
"balance_lsb": BALANCE_LSB,
|
|
175
|
+
"pan_lsb": PAN_LSB,
|
|
176
|
+
"expression_lsb": EXPRESSION_LSB,
|
|
177
|
+
"effect_control_1_lsb": EFFECT_CONTROL_1_LSB,
|
|
178
|
+
"effect_control_2_lsb": EFFECT_CONTROL_2_LSB,
|
|
179
|
+
|
|
180
|
+
# Switch controllers
|
|
181
|
+
"sustain_pedal": SUSTAIN_PEDAL,
|
|
182
|
+
"portamento_on_off": PORTAMENTO_ON_OFF,
|
|
183
|
+
"sostenuto_pedal": SOSTENUTO_PEDAL,
|
|
184
|
+
"soft_pedal": SOFT_PEDAL,
|
|
185
|
+
"legato_pedal": LEGATO_PEDAL,
|
|
186
|
+
"hold_2": HOLD_2,
|
|
187
|
+
|
|
188
|
+
# Sound controllers
|
|
189
|
+
"sound_variation": SOUND_VARIATION,
|
|
190
|
+
"filter_resonance": FILTER_RESONANCE,
|
|
191
|
+
"release_time": RELEASE_TIME,
|
|
192
|
+
"attack_time": ATTACK_TIME,
|
|
193
|
+
"filter_cutoff": FILTER_CUTOFF,
|
|
194
|
+
"sound_control_6": SOUND_CONTROL_6,
|
|
195
|
+
"sound_control_7": SOUND_CONTROL_7,
|
|
196
|
+
"sound_control_8": SOUND_CONTROL_8,
|
|
197
|
+
"sound_control_9": SOUND_CONTROL_9,
|
|
198
|
+
"sound_control_10": SOUND_CONTROL_10,
|
|
199
|
+
|
|
200
|
+
# General purpose controllers
|
|
201
|
+
"general_purpose_5": GENERAL_PURPOSE_5,
|
|
202
|
+
"general_purpose_6": GENERAL_PURPOSE_6,
|
|
203
|
+
"general_purpose_7": GENERAL_PURPOSE_7,
|
|
204
|
+
"general_purpose_8": GENERAL_PURPOSE_8,
|
|
205
|
+
|
|
206
|
+
# Effects send levels
|
|
207
|
+
"portamento_control": PORTAMENTO_CONTROL,
|
|
208
|
+
"reverb_depth": REVERB_DEPTH,
|
|
209
|
+
"tremolo_depth": TREMOLO_DEPTH,
|
|
210
|
+
"chorus_depth": CHORUS_DEPTH,
|
|
211
|
+
"celeste_depth": CELESTE_DEPTH,
|
|
212
|
+
"phaser_depth": PHASER_DEPTH,
|
|
213
|
+
|
|
214
|
+
# Parameter control
|
|
215
|
+
"data_increment": DATA_INCREMENT,
|
|
216
|
+
"data_decrement": DATA_DECREMENT,
|
|
217
|
+
"nrpn_lsb": NRPN_LSB,
|
|
218
|
+
"nrpn_msb": NRPN_MSB,
|
|
219
|
+
"rpn_lsb": RPN_LSB,
|
|
220
|
+
"rpn_msb": RPN_MSB,
|
|
221
|
+
|
|
222
|
+
# Channel mode messages
|
|
223
|
+
"all_sound_off": ALL_SOUND_OFF,
|
|
224
|
+
"reset_all_controllers": RESET_ALL_CONTROLLERS,
|
|
225
|
+
"local_control_on_off": LOCAL_CONTROL_ON_OFF,
|
|
226
|
+
"all_notes_off": ALL_NOTES_OFF,
|
|
227
|
+
"omni_mode_off": OMNI_MODE_OFF,
|
|
228
|
+
"omni_mode_on": OMNI_MODE_ON,
|
|
229
|
+
"mono_mode_on": MONO_MODE_ON,
|
|
230
|
+
"poly_mode_on": POLY_MODE_ON,
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# ── 14-bit value pack/unpack ─────────────────────────────────────────────────
|
|
235
|
+
# Many MIDI 1.0 message types — Bank Select, Data Entry, RPN/NRPN parameter
|
|
236
|
+
# numbers, pitch bend, song position pointer — split a 14-bit value across
|
|
237
|
+
# two 7-bit MSB/LSB bytes. These helpers convert between the integer form
|
|
238
|
+
# and the wire-format byte pair.
|
|
239
|
+
|
|
240
|
+
def pack_14bit (value: int) -> tuple[int, int]:
|
|
241
|
+
|
|
242
|
+
"""Split a 14-bit integer (0–16383) into ``(MSB, LSB)`` bytes.
|
|
243
|
+
|
|
244
|
+
Each returned byte is in the 7-bit range 0–127. The tuple ordering
|
|
245
|
+
``(MSB, LSB)`` is the logical pairing — wire-transmission order is
|
|
246
|
+
message-dependent (Bank Select and RPN/NRPN parameter selection send MSB
|
|
247
|
+
first, but pitch bend sends LSB first).
|
|
248
|
+
|
|
249
|
+
>>> pack_14bit(0)
|
|
250
|
+
(0, 0)
|
|
251
|
+
>>> pack_14bit(16383)
|
|
252
|
+
(127, 127)
|
|
253
|
+
>>> pack_14bit(8192)
|
|
254
|
+
(64, 0)
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
if not 0 <= value <= 16383:
|
|
258
|
+
raise ValueError(
|
|
259
|
+
f"14-bit value must be 0–16383, got {value}"
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
return (value >> 7) & 0x7F, value & 0x7F
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def unpack_14bit (msb: int, lsb: int) -> int:
|
|
266
|
+
|
|
267
|
+
"""Combine an ``(MSB, LSB)`` byte pair into a 14-bit integer (0–16383).
|
|
268
|
+
|
|
269
|
+
Both inputs must be in the 7-bit range 0–127.
|
|
270
|
+
|
|
271
|
+
>>> unpack_14bit(0, 0)
|
|
272
|
+
0
|
|
273
|
+
>>> unpack_14bit(127, 127)
|
|
274
|
+
16383
|
|
275
|
+
>>> unpack_14bit(64, 0)
|
|
276
|
+
8192
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
if not 0 <= msb <= 127:
|
|
280
|
+
raise ValueError(f"MSB must be 0–127, got {msb}")
|
|
281
|
+
if not 0 <= lsb <= 127:
|
|
282
|
+
raise ValueError(f"LSB must be 0–127, got {lsb}")
|
|
283
|
+
|
|
284
|
+
return (msb << 7) | lsb
|
pymididefs/ci.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""MIDI 2.0 Capability Inquiry (MIDI-CI) constants.
|
|
2
|
+
|
|
3
|
+
MIDI-CI enables bidirectional communication between MIDI devices for
|
|
4
|
+
capability discovery, profile configuration, and property exchange.
|
|
5
|
+
MIDI-CI messages are transported as Universal System Exclusive (Non-Real-Time).
|
|
6
|
+
|
|
7
|
+
::
|
|
8
|
+
|
|
9
|
+
import pymididefs.ci
|
|
10
|
+
pymididefs.ci.DISCOVERY # 0x70
|
|
11
|
+
pymididefs.ci.CI_SUB_ID # 0x0D
|
|
12
|
+
|
|
13
|
+
Source: M2-101-UM v1.2 — MIDI-CI Specification.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# ── Universal SysEx Framing ──────────────────────────────────────────────────
|
|
18
|
+
# MIDI-CI messages are wrapped in Universal Non-Real-Time SysEx:
|
|
19
|
+
# F0 7E <device_id> 0D <sub_id_2> <data...> F7
|
|
20
|
+
|
|
21
|
+
UNIVERSAL_NON_REALTIME = 0x7E # Universal Non-Real-Time SysEx ID byte
|
|
22
|
+
UNIVERSAL_REALTIME = 0x7F # Universal Real-Time SysEx ID byte
|
|
23
|
+
CI_SUB_ID = 0x0D # MIDI-CI Sub-ID #1 (identifies CI messages)
|
|
24
|
+
BROADCAST_ADDRESS = 0x7F # Device ID for broadcast (all devices on port)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# ── MIDI-CI Message Types (Sub-ID #2) ────────────────────────────────────────
|
|
28
|
+
# These identify the specific MIDI-CI message within the SysEx payload.
|
|
29
|
+
|
|
30
|
+
# Management messages
|
|
31
|
+
DISCOVERY = 0x70 # Discovery Inquiry
|
|
32
|
+
DISCOVERY_REPLY = 0x71 # Reply to Discovery
|
|
33
|
+
INVALIDATE_MUID = 0x7E # Invalidate MUID (device going offline)
|
|
34
|
+
NAK = 0x7F # NAK (negative acknowledgement)
|
|
35
|
+
|
|
36
|
+
# Profile Configuration messages
|
|
37
|
+
PROFILE_INQUIRY = 0x20 # Profile Inquiry
|
|
38
|
+
PROFILE_INQUIRY_REPLY = 0x21 # Reply to Profile Inquiry
|
|
39
|
+
SET_PROFILE_ON = 0x22 # Set Profile On
|
|
40
|
+
SET_PROFILE_OFF = 0x23 # Set Profile Off
|
|
41
|
+
PROFILE_ENABLED = 0x24 # Profile Enabled Report
|
|
42
|
+
PROFILE_DISABLED = 0x25 # Profile Disabled Report
|
|
43
|
+
PROFILE_ADDED = 0x26 # Profile Added Report
|
|
44
|
+
PROFILE_REMOVED = 0x27 # Profile Removed Report
|
|
45
|
+
PROFILE_DETAILS_INQUIRY = 0x28 # Profile Details Inquiry
|
|
46
|
+
PROFILE_DETAILS_REPLY = 0x29 # Reply to Profile Details Inquiry
|
|
47
|
+
PROFILE_SPECIFIC_DATA = 0x2F # Profile Specific Data
|
|
48
|
+
|
|
49
|
+
# Property Exchange messages
|
|
50
|
+
PROPERTY_CAPABILITIES = 0x30 # Inquiry: Property Exchange Capabilities
|
|
51
|
+
PROPERTY_CAPABILITIES_REPLY = 0x31 # Reply to Property Exchange Capabilities
|
|
52
|
+
PROPERTY_GET = 0x34 # Get Property Data Inquiry
|
|
53
|
+
PROPERTY_GET_REPLY = 0x35 # Reply to Get Property Data
|
|
54
|
+
PROPERTY_SET = 0x36 # Set Property Data Inquiry
|
|
55
|
+
PROPERTY_SET_REPLY = 0x37 # Reply to Set Property Data
|
|
56
|
+
PROPERTY_SUBSCRIBE = 0x38 # Subscription Inquiry
|
|
57
|
+
PROPERTY_SUBSCRIBE_REPLY = 0x39 # Reply to Subscription
|
|
58
|
+
PROPERTY_NOTIFY = 0x3F # Notify (subscription update)
|
|
59
|
+
|
|
60
|
+
# Process Inquiry messages (MIDI-CI 1.2)
|
|
61
|
+
PROCESS_INQUIRY = 0x40 # Process Inquiry
|
|
62
|
+
PROCESS_INQUIRY_REPLY = 0x41 # Reply to Process Inquiry
|
|
63
|
+
PROCESS_MIDI_REPORT = 0x42 # MIDI Message Report
|
|
64
|
+
PROCESS_MIDI_REPORT_REPLY = 0x43 # Reply to MIDI Message Report
|
|
65
|
+
PROCESS_MIDI_REPORT_END = 0x44 # End of MIDI Message Report
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# ── Broadcast MUID ───────────────────────────────────────────────────────────
|
|
69
|
+
# 28-bit MUID (Message Unique Identifier) value used for broadcast discovery.
|
|
70
|
+
# Sent as 4 bytes in the SysEx payload (7 bits each, totalling 28 bits).
|
|
71
|
+
|
|
72
|
+
BROADCAST_MUID = 0x0FFFFFFF # All-ones 28-bit MUID (broadcast)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# ── MIDI-CI Version ──────────────────────────────────────────────────────────
|
|
76
|
+
# Version byte included in Discovery and Reply to Discovery messages.
|
|
77
|
+
|
|
78
|
+
CI_VERSION_1_1 = 0x01 # MIDI-CI version 1.1
|
|
79
|
+
CI_VERSION_1_2 = 0x02 # MIDI-CI version 1.2
|
pymididefs/drums.py
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""General MIDI Level 1 percussion key map.
|
|
2
|
+
|
|
3
|
+
Standard MIDI percussion assignments for channel 10 (0-indexed channel 9).
|
|
4
|
+
These note numbers are defined by the General MIDI Level 1 specification and
|
|
5
|
+
are supported by virtually all GM-compatible instruments, drum machines, and
|
|
6
|
+
DAWs.
|
|
7
|
+
|
|
8
|
+
Two ways to use this module::
|
|
9
|
+
|
|
10
|
+
import pymididefs.drums
|
|
11
|
+
|
|
12
|
+
# As named constants
|
|
13
|
+
pymididefs.drums.KICK_1 # 36
|
|
14
|
+
pymididefs.drums.HI_HAT_CLOSED # 42
|
|
15
|
+
|
|
16
|
+
# As a lookup dictionary
|
|
17
|
+
pymididefs.drums.GM_DRUM_MAP["kick_1"] # 36
|
|
18
|
+
|
|
19
|
+
The four instruments GM defines in numbered pairs — kick, snare, crash, ride —
|
|
20
|
+
also have unnumbered *primary aliases* pointing to the "1" variant: the
|
|
21
|
+
``KICK`` / ``SNARE`` / ``CRASH`` / ``RIDE`` constants and the
|
|
22
|
+
``GM_DRUM_PRIMARY_ALIASES`` lookup, kept separate from ``GM_DRUM_MAP`` so the
|
|
23
|
+
canonical key map stays one name per note.
|
|
24
|
+
|
|
25
|
+
Source: General MIDI Level 1 Specification — Percussion Key Map.
|
|
26
|
+
Note range: 27 (High Q) through 87 (Open Surdo).
|
|
27
|
+
Channel: 10 (1-indexed) / 9 (0-indexed).
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
import typing
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# ── GM Level 1 Percussion Key Map (notes 27–87) ─────────────────────────────
|
|
34
|
+
# Organised by instrument family for readability.
|
|
35
|
+
|
|
36
|
+
# Electronic percussion / effects (27–34)
|
|
37
|
+
HIGH_Q = 27 # High Q
|
|
38
|
+
SLAP = 28 # Slap
|
|
39
|
+
SCRATCH_PUSH = 29 # Scratch Push
|
|
40
|
+
SCRATCH_PULL = 30 # Scratch Pull
|
|
41
|
+
STICKS = 31 # Sticks
|
|
42
|
+
SQUARE_CLICK = 32 # Square Click
|
|
43
|
+
METRONOME_CLICK = 33 # Metronome Click
|
|
44
|
+
METRONOME_BELL = 34 # Metronome Bell
|
|
45
|
+
|
|
46
|
+
# Kick drums (35–36)
|
|
47
|
+
KICK_2 = 35 # Acoustic Bass Drum
|
|
48
|
+
KICK_1 = 36 # Bass Drum 1
|
|
49
|
+
|
|
50
|
+
# Snare and side stick (37–40)
|
|
51
|
+
SIDE_STICK = 37 # Side Stick
|
|
52
|
+
SNARE_1 = 38 # Acoustic Snare
|
|
53
|
+
HAND_CLAP = 39 # Hand Clap
|
|
54
|
+
SNARE_2 = 40 # Electric Snare
|
|
55
|
+
|
|
56
|
+
# Toms (41, 43, 45, 47, 48, 50)
|
|
57
|
+
LOW_FLOOR_TOM = 41 # Low Floor Tom
|
|
58
|
+
HI_HAT_CLOSED = 42 # Closed Hi-Hat
|
|
59
|
+
HIGH_FLOOR_TOM = 43 # High Floor Tom
|
|
60
|
+
HI_HAT_PEDAL = 44 # Pedal Hi-Hat
|
|
61
|
+
LOW_TOM = 45 # Low Tom
|
|
62
|
+
HI_HAT_OPEN = 46 # Open Hi-Hat
|
|
63
|
+
LOW_MID_TOM = 47 # Low-Mid Tom
|
|
64
|
+
HIGH_MID_TOM = 48 # Hi-Mid Tom
|
|
65
|
+
CRASH_1 = 49 # Crash Cymbal 1
|
|
66
|
+
HIGH_TOM = 50 # High Tom
|
|
67
|
+
|
|
68
|
+
# Cymbals (51–53, 55, 57, 59)
|
|
69
|
+
RIDE_1 = 51 # Ride Cymbal 1
|
|
70
|
+
CHINESE_CYMBAL = 52 # Chinese Cymbal
|
|
71
|
+
RIDE_BELL = 53 # Ride Bell
|
|
72
|
+
TAMBOURINE = 54 # Tambourine
|
|
73
|
+
SPLASH_CYMBAL = 55 # Splash Cymbal
|
|
74
|
+
COWBELL = 56 # Cowbell
|
|
75
|
+
CRASH_2 = 57 # Crash Cymbal 2
|
|
76
|
+
VIBRASLAP = 58 # Vibraslap
|
|
77
|
+
RIDE_2 = 59 # Ride Cymbal 2
|
|
78
|
+
|
|
79
|
+
# Latin percussion (60–69)
|
|
80
|
+
HIGH_BONGO = 60 # Hi Bongo
|
|
81
|
+
LOW_BONGO = 61 # Low Bongo
|
|
82
|
+
MUTE_HIGH_CONGA = 62 # Mute Hi Conga
|
|
83
|
+
OPEN_HIGH_CONGA = 63 # Open Hi Conga
|
|
84
|
+
LOW_CONGA = 64 # Low Conga
|
|
85
|
+
HIGH_TIMBALE = 65 # High Timbale
|
|
86
|
+
LOW_TIMBALE = 66 # Low Timbale
|
|
87
|
+
HIGH_AGOGO = 67 # High Agogo
|
|
88
|
+
LOW_AGOGO = 68 # Low Agogo
|
|
89
|
+
CABASA = 69 # Cabasa
|
|
90
|
+
|
|
91
|
+
# Shakers and small percussion (70–79)
|
|
92
|
+
MARACAS = 70 # Maracas
|
|
93
|
+
SHORT_WHISTLE = 71 # Short Whistle
|
|
94
|
+
LONG_WHISTLE = 72 # Long Whistle
|
|
95
|
+
SHORT_GUIRO = 73 # Short Guiro
|
|
96
|
+
LONG_GUIRO = 74 # Long Guiro
|
|
97
|
+
CLAVES = 75 # Claves
|
|
98
|
+
HIGH_WOODBLOCK = 76 # Hi Wood Block
|
|
99
|
+
LOW_WOODBLOCK = 77 # Low Wood Block
|
|
100
|
+
MUTE_CUICA = 78 # Mute Cuica
|
|
101
|
+
OPEN_CUICA = 79 # Open Cuica
|
|
102
|
+
|
|
103
|
+
# Triangle and bells (80–87)
|
|
104
|
+
MUTE_TRIANGLE = 80 # Mute Triangle
|
|
105
|
+
OPEN_TRIANGLE = 81 # Open Triangle
|
|
106
|
+
SHAKER = 82 # Shaker
|
|
107
|
+
JINGLE_BELL = 83 # Jingle Bell
|
|
108
|
+
BELL_TREE = 84 # Bell Tree
|
|
109
|
+
CASTANETS = 85 # Castanets
|
|
110
|
+
MUTE_SURDO = 86 # Mute Surdo
|
|
111
|
+
OPEN_SURDO = 87 # Open Surdo
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# ── Lookup dictionary ────────────────────────────────────────────────────────
|
|
115
|
+
# Maps snake_case names to MIDI note numbers for string-based access.
|
|
116
|
+
|
|
117
|
+
GM_DRUM_MAP: typing.Final[dict[str, int]] = {
|
|
118
|
+
# Electronic percussion / effects
|
|
119
|
+
"high_q": HIGH_Q,
|
|
120
|
+
"slap": SLAP,
|
|
121
|
+
"scratch_push": SCRATCH_PUSH,
|
|
122
|
+
"scratch_pull": SCRATCH_PULL,
|
|
123
|
+
"sticks": STICKS,
|
|
124
|
+
"square_click": SQUARE_CLICK,
|
|
125
|
+
"metronome_click": METRONOME_CLICK,
|
|
126
|
+
"metronome_bell": METRONOME_BELL,
|
|
127
|
+
|
|
128
|
+
# Kick drums
|
|
129
|
+
"kick_2": KICK_2,
|
|
130
|
+
"kick_1": KICK_1,
|
|
131
|
+
|
|
132
|
+
# Snare and side stick
|
|
133
|
+
"side_stick": SIDE_STICK,
|
|
134
|
+
"snare_1": SNARE_1,
|
|
135
|
+
"hand_clap": HAND_CLAP,
|
|
136
|
+
"snare_2": SNARE_2,
|
|
137
|
+
|
|
138
|
+
# Toms and hi-hats
|
|
139
|
+
"low_floor_tom": LOW_FLOOR_TOM,
|
|
140
|
+
"hi_hat_closed": HI_HAT_CLOSED,
|
|
141
|
+
"high_floor_tom": HIGH_FLOOR_TOM,
|
|
142
|
+
"hi_hat_pedal": HI_HAT_PEDAL,
|
|
143
|
+
"low_tom": LOW_TOM,
|
|
144
|
+
"hi_hat_open": HI_HAT_OPEN,
|
|
145
|
+
"low_mid_tom": LOW_MID_TOM,
|
|
146
|
+
"high_mid_tom": HIGH_MID_TOM,
|
|
147
|
+
"high_tom": HIGH_TOM,
|
|
148
|
+
|
|
149
|
+
# Cymbals
|
|
150
|
+
"crash_1": CRASH_1,
|
|
151
|
+
"ride_1": RIDE_1,
|
|
152
|
+
"chinese_cymbal": CHINESE_CYMBAL,
|
|
153
|
+
"ride_bell": RIDE_BELL,
|
|
154
|
+
"tambourine": TAMBOURINE,
|
|
155
|
+
"splash_cymbal": SPLASH_CYMBAL,
|
|
156
|
+
"cowbell": COWBELL,
|
|
157
|
+
"crash_2": CRASH_2,
|
|
158
|
+
"vibraslap": VIBRASLAP,
|
|
159
|
+
"ride_2": RIDE_2,
|
|
160
|
+
|
|
161
|
+
# Latin percussion
|
|
162
|
+
"high_bongo": HIGH_BONGO,
|
|
163
|
+
"low_bongo": LOW_BONGO,
|
|
164
|
+
"mute_high_conga": MUTE_HIGH_CONGA,
|
|
165
|
+
"open_high_conga": OPEN_HIGH_CONGA,
|
|
166
|
+
"low_conga": LOW_CONGA,
|
|
167
|
+
"high_timbale": HIGH_TIMBALE,
|
|
168
|
+
"low_timbale": LOW_TIMBALE,
|
|
169
|
+
"high_agogo": HIGH_AGOGO,
|
|
170
|
+
"low_agogo": LOW_AGOGO,
|
|
171
|
+
"cabasa": CABASA,
|
|
172
|
+
|
|
173
|
+
# Shakers and small percussion
|
|
174
|
+
"maracas": MARACAS,
|
|
175
|
+
"short_whistle": SHORT_WHISTLE,
|
|
176
|
+
"long_whistle": LONG_WHISTLE,
|
|
177
|
+
"short_guiro": SHORT_GUIRO,
|
|
178
|
+
"long_guiro": LONG_GUIRO,
|
|
179
|
+
"claves": CLAVES,
|
|
180
|
+
"high_woodblock": HIGH_WOODBLOCK,
|
|
181
|
+
"low_woodblock": LOW_WOODBLOCK,
|
|
182
|
+
"mute_cuica": MUTE_CUICA,
|
|
183
|
+
"open_cuica": OPEN_CUICA,
|
|
184
|
+
|
|
185
|
+
# Triangle and bells
|
|
186
|
+
"mute_triangle": MUTE_TRIANGLE,
|
|
187
|
+
"open_triangle": OPEN_TRIANGLE,
|
|
188
|
+
"shaker": SHAKER,
|
|
189
|
+
"jingle_bell": JINGLE_BELL,
|
|
190
|
+
"bell_tree": BELL_TREE,
|
|
191
|
+
"castanets": CASTANETS,
|
|
192
|
+
"mute_surdo": MUTE_SURDO,
|
|
193
|
+
"open_surdo": OPEN_SURDO,
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# ── Primary aliases ──────────────────────────────────────────────────────────
|
|
198
|
+
# General MIDI defines four instruments in numbered pairs — two kicks, two
|
|
199
|
+
# snares, two crashes, two rides. These unnumbered aliases point to the
|
|
200
|
+
# GM-designated *primary* (the "1" variant): Bass Drum 1, Acoustic Snare,
|
|
201
|
+
# Crash Cymbal 1, Ride Cymbal 1 — the notes every GM kit treats as the main
|
|
202
|
+
# kick / snare / crash / ride. Use ``KICK`` when you just want "the kick"
|
|
203
|
+
# rather than choosing between the two.
|
|
204
|
+
#
|
|
205
|
+
# Kept separate from GM_DRUM_MAP, which stays one name per note (the canonical
|
|
206
|
+
# percussion key map). Only these four instruments come in numbered pairs; the
|
|
207
|
+
# single-instance voices (closed/open/pedal hi-hat, side stick, cowbell, …) are
|
|
208
|
+
# already unnumbered. Ambiguous cases with no clear primary (e.g. the six toms)
|
|
209
|
+
# are deliberately not aliased.
|
|
210
|
+
|
|
211
|
+
KICK = KICK_1 # Bass Drum 1 (36)
|
|
212
|
+
SNARE = SNARE_1 # Acoustic Snare (38)
|
|
213
|
+
CRASH = CRASH_1 # Crash Cymbal 1 (49)
|
|
214
|
+
RIDE = RIDE_1 # Ride Cymbal 1 (51)
|
|
215
|
+
|
|
216
|
+
GM_DRUM_PRIMARY_ALIASES: typing.Final[dict[str, int]] = {
|
|
217
|
+
"kick": KICK_1,
|
|
218
|
+
"snare": SNARE_1,
|
|
219
|
+
"crash": CRASH_1,
|
|
220
|
+
"ride": RIDE_1,
|
|
221
|
+
}
|