Skip to content

Commit 9682d76

Browse files
add frequency_to_note_cents function; update docs
1 parent 0851594 commit 9682d76

File tree

1 file changed

+176
-159
lines changed

1 file changed

+176
-159
lines changed

cedargrove_midi_tools.py

Lines changed: 176 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2022 JG for Cedar Grove Maker Studios
1+
# SPDX-FileCopyrightText: Copyright (c) 2023 JG for Cedar Grove Maker Studios
22
#
33
# SPDX-License-Identifier: MIT
44
"""
@@ -31,15 +31,14 @@
3131

3232
def note_or_name(value):
3333
"""Bidirectionally translates a MIDI sequential note value to a note name
34-
or a note name to a MIDI sequential note value. Note values are
35-
of integer type in the range of 0 to 127 (inclusive). Note names are
36-
character strings expressed in the format NoteOctave, such as
37-
'C4' or 'G#7'. Note names can range from 'C-1' (note value 0) to
38-
'F#9' (note value 127). If the input value is outside of the note
39-
value or name range, the value of None is returned.
34+
or a note name to a MIDI sequential note value. Note values are integers in
35+
the range of 0 to 127 (inclusive). Note names are character strings
36+
expressed in the format NoteOctave such as 'C4' or 'G#7'. Note names range
37+
from 'C-1' (note value 0) to 'F#9' (note value 127). If the input value is
38+
outside the note value or name range, the value of `None` is returned.
4039
4140
:param union(int, str) value: The note name or note value input. Note value
42-
is an integer; note name is a string. No default value.
41+
is an integer Note name is a string. No default value.
4342
"""
4443
if isinstance(value, str):
4544
# Input is a string, so it's a note name
@@ -52,11 +51,10 @@ def note_or_name(value):
5251

5352
def note_to_name(note):
5453
"""Translates a MIDI sequential note value to a note name. Note values are
55-
of integer type in the range of 0 to 127 (inclusive). Note names are
56-
character strings expressed in the format NoteOctave, such as
57-
'C4' or 'G#7'. Note names can range from 'C-1' (note value 0) to
58-
'F#9' (note value 127). If the input value is outside of that range,
59-
the value of None is returned.
54+
integers in the range of 0 to 127 (inclusive). Note names are character
55+
strings expressed in the format NoteOctave such as 'C4' or 'G#7'. Note
56+
names range from 'C-1' (note value 0) to 'F#9' (note value 127). If the
57+
input value is outside that range, the value of `None` is returned.
6058
6159
:param int note: The note value input in the range of 0 to 127 (inclusive).
6260
No default value.
@@ -68,11 +66,10 @@ def note_to_name(note):
6866

6967
def name_to_note(name):
7068
"""Translates a note name to a MIDI sequential note value. Note names are
71-
character strings expressed in the NoteOctave format, such as
72-
'C4' or 'G#7'. Note names can range from 'C-1' (note value 0) to
73-
'F#9' (note value 127). Note values are of integer type in the range
74-
of 0 to 127 (inclusive). If the input value is outside of that range,
75-
the value of None is returned.
69+
character strings expressed in the NoteOctave format such as 'C4' or 'G#7'.
70+
Note names range from 'C-1' (note value 0) to 'F#9' (note value 127). Note
71+
values are of integer type in the range of 0 to 127 (inclusive). If the
72+
input value is outside that range, the value of `None` is returned.
7673
7774
:param str name: The note name input in NoteOctave format. No default value.
7875
"""
@@ -92,12 +89,12 @@ def name_to_note(name):
9289

9390

9491
def note_to_frequency(note):
95-
"""Translates a MIDI sequential note value to its corresponding frequency
96-
in Hertz (Hz). Note values are of integer type in the range of 0 to
97-
127 (inclusive). Frequency values are floating point. If the input
98-
note value is less than 0 or greater than 127, the input is
99-
invalid and the value of None is returned. Ref: MIDI Tuning Standard
100-
formula: https://en.wikipedia.org/wiki/MIDI_tuning_standard
92+
"""Translates a MIDI sequential note value to a corresponding frequency in
93+
Hertz (Hz). Note values are integers in the range of 0 to 127 (inclusive).
94+
Frequency values are floating point. If the input note value is less than
95+
0 or greater than 127, the input is invalid and the value of `None` is
96+
returned. Ref: MIDI Tuning Standard formula:
97+
https://en.wikipedia.org/wiki/MIDI_tuning_standard
10198
10299
:param int note: The MIDI note value input in the range of 0 to 127
103100
(inclusive). No default.
@@ -108,152 +105,172 @@ def note_to_frequency(note):
108105

109106

110107
def frequency_to_note(frequency):
111-
"""Translates a frequency in Hertz (Hz) to the closest MIDI sequential
112-
note value. Frequency values are floating point. Note values are of
113-
integer type in the range of 0 to 127 (inclusive). If the input
114-
frequency is less than the corresponding frequency for note 0 or
115-
greater than note 127, the input is invalid and the value of None
116-
is returned. Ref: MIDI Tuning Standard formula:
108+
"""Translates a frequency in Hertz (Hz) to a MIDI sequential note value.
109+
Frequency values are floating point. Note values are integers in the range
110+
of 0 to 127 (inclusive). If the input frequency is less than the
111+
corresponding frequency for note 0 or greater than note 127, the note value
112+
cannot be determined and `None` is returned. Ref: MIDI Tuning Standard
113+
formula:
117114
https://en.wikipedia.org/wiki/MIDI_tuning_standard
118115
119116
:param float frequency: The frequency value input in Hz. No default.
120117
"""
121-
if (pow(2, (0 - 69) / 12) * 440) <= frequency <= (pow(2, (127 - 69) / 12) * 440):
118+
if (pow(2, (0 - 69) / 12) * 440) <= frequency <= (pow(2, (128 - 69) / 12) * 440):
122119
return int(69 + (12 * log(frequency / 440, 2)))
123120
return None # Frequency outside valid range
124121

125122

123+
def frequency_to_note_cents(frequency):
124+
"""Translates a frequency in Hertz (Hz) to a MIDI sequential note value and
125+
positive offset in cents. Frequency values are floating point. Note values
126+
are integers in the range of 0 to 127 (inclusive). Cent values range from
127+
0 to +100 cents. If the input frequency is less than the corresponding
128+
frequency for note 0 or greater than note 127, the note value cannot be
129+
determined and `None` is returned. Ref: MIDI Tuning Standard and cent
130+
formulae:
131+
https://en.wikipedia.org/wiki/MIDI_tuning_standard
132+
https://en.wikipedia.org/wiki/Cent_(music)
133+
134+
:param float frequency: The frequency value input in Hz. No default.
135+
"""
136+
if (pow(2, (0 - 69) / 12) * 440) <= frequency <= (pow(2, (128 - 69) / 12) * 440):
137+
note = int(69 + (12 * log(frequency / 440, 2)))
138+
note_freq = pow(2, (note - 69) / 12) * 440
139+
return note, int(1200 * log(frequency / note_freq))
140+
return None, None # Frequency outside valid range
141+
142+
126143
# Controller descriptions -- no list offset
127144
# 0-63 continuous, 64-121 switch, 122-127 channel mode
128145
CONTROLLERS = [
129-
("Bank_Select"),
130-
("Modulation"),
131-
("Breath_Ctrl"),
132-
("Ctrl_3"),
133-
("Foot_Ctrl"),
134-
("Portamento_Time"),
135-
("Data_Entry_MSB"),
136-
("Chan_Vol"),
137-
("Balance"),
138-
("Ctrl_9"),
139-
("Pan_Ctrl"),
140-
("Exp_Pedal"),
141-
("FX_Ctrl_1"),
142-
("FX_Ctrl_2"),
143-
("Ctrl_14"),
144-
("Ctrl_15"),
145-
("Gen_Pur_1"),
146-
("Gen_Pur_2"),
147-
("Gen_Pur_3"),
148-
("Gen_Pur_4"),
149-
("Ctrl_20"),
150-
("Ctrl_21"),
151-
("Ctrl_22"),
152-
("Ctrl_23"),
153-
("Ctrl_24"),
154-
("Ctrl_25"),
155-
("Ctrl_26"),
156-
("Ctrl_27"),
157-
("Ctrl_28"),
158-
("Ctrl_29"),
159-
("Ctrl_30"),
160-
("Ctrl_31"),
161-
("Bank_Sel_LSB"),
162-
("Modulation_LSB"),
163-
("Breath_Ctrl_LSB"),
164-
("Ctrl_3_LSB"),
165-
("Foot_Ctrl_LSB"),
166-
("Portamento_Time_LSB"),
167-
("Data_Entry_LSB"),
168-
("Chan_Vol_LSB"),
169-
("Balance_LSB"),
170-
("Ctrl_9_LSB"),
171-
("Pan_Ctrl_LSB"),
172-
("Exp_Pedal_LSB"),
173-
("FX_Ctrl_1_LSB"),
174-
("FX_Ctrl_2_LSB"),
175-
("Ctrl_14_LSB"),
176-
("Ctrl_15_LSB"),
177-
("Gen_Pur_1_LSB"),
178-
("Gen_Pur_2_LSB"),
179-
("Gen_Pur_3_LSB"),
180-
("Gen_Pur_4_LSB"),
181-
("Ctrl_20_LSB"),
182-
("Ctrl_21_LSB"),
183-
("Ctrl_22_LSB"),
184-
("Ctrl_23_LSB"),
185-
("Ctrl_24_LSB"),
186-
("Ctrl_25_LSB"),
187-
("Ctrl_26_LSB"),
188-
("Ctrl_27_LSB"),
189-
("Ctrl_28_LSB"),
190-
("Ctrl_29_LSB"),
191-
("Ctrl_30_LSB"),
192-
("Ctrl_31_LSB"),
193-
("Sus_Damp_Pedal_sw"),
194-
("Portamento_sw"),
195-
("Sostenuto_sw"),
196-
("Soft_Pedal_sw"),
197-
("Legato_Foot_sw"),
198-
("Hold_2_sw"),
199-
("Sound_Ctrl_1_Variation"),
200-
("Sound_Ctrl_2_Tibre"),
201-
("Sound_Ctrl_3_Release"),
202-
("Sound_Ctrl_4_Attack"),
203-
("Sound_Ctrl_5_Bright"),
204-
("Sound_Ctrl_6_Decay"),
205-
("Sound_Ctrl_7_Vib_Rate"),
206-
("Sound_Ctrl_8_Vib_Depth"),
207-
("Sound_Ctrl_9_Vib_Delay"),
208-
("Sound_Ctrl_10"),
209-
("Gen_Pur_5"),
210-
("Gen_Pur_6"),
211-
("Gen_Pur_7"),
212-
("Gen_Pur_8"),
213-
("Portamento_Ctrl"),
214-
("Ctrl_85"),
215-
("Ctrl_86"),
216-
("Ctrl_87"),
217-
("HR_Vel_Prefix"),
218-
("Ctrl_89"),
219-
("Ctrl_90"),
220-
("FX_1_Depth_Reverb"),
221-
("FX_2_Depth"),
222-
("FX_3_Depth"),
223-
("FX_4_Depth"),
224-
("FX_5_Depth"),
225-
("Data_Inc + Value"),
226-
("Data_Dec + Value"),
227-
("NRPN_LSB + Value"),
228-
("NRPN_MSB + Value"),
229-
("RPN_LSB + Value"),
230-
("RPN_MSB + Value"),
231-
("Ctrl_102"),
232-
("Ctrl_103"),
233-
("Ctrl_104"),
234-
("Ctrl_105"),
235-
("Ctrl_106"),
236-
("Ctrl_107"),
237-
("Ctrl_108"),
238-
("Ctrl_109"),
239-
("Ctrl_110"),
240-
("Ctrl_111"),
241-
("Ctrl_112"),
242-
("Ctrl_113"),
243-
("Ctrl_114"),
244-
("Ctrl_115"),
245-
("Ctrl_116"),
246-
("Ctrl_117"),
247-
("Ctrl_118"),
248-
("Ctrl_119"),
249-
("All_Sound_Off"),
250-
("Reset_All_Ctrls"),
251-
("Local_Ctrl_Sw"),
252-
("All_Notes_Off"),
253-
("Omni_Mode_Off"),
254-
("Omni_Mode_On"),
255-
("Mono_Mode_On"),
256-
("Poly_Mode_On"),
146+
"Bank_Select",
147+
"Modulation",
148+
"Breath_Ctrl",
149+
"Ctrl_3",
150+
"Foot_Ctrl",
151+
"Portamento_Time",
152+
"Data_Entry_MSB",
153+
"Chan_Vol",
154+
"Balance",
155+
"Ctrl_9",
156+
"Pan_Ctrl",
157+
"Exp_Pedal",
158+
"FX_Ctrl_1",
159+
"FX_Ctrl_2",
160+
"Ctrl_14",
161+
"Ctrl_15",
162+
"Gen_Pur_1",
163+
"Gen_Pur_2",
164+
"Gen_Pur_3",
165+
"Gen_Pur_4",
166+
"Ctrl_20",
167+
"Ctrl_21",
168+
"Ctrl_22",
169+
"Ctrl_23",
170+
"Ctrl_24",
171+
"Ctrl_25",
172+
"Ctrl_26",
173+
"Ctrl_27",
174+
"Ctrl_28",
175+
"Ctrl_29",
176+
"Ctrl_30",
177+
"Ctrl_31",
178+
"Bank_Sel_LSB",
179+
"Modulation_LSB",
180+
"Breath_Ctrl_LSB",
181+
"Ctrl_3_LSB",
182+
"Foot_Ctrl_LSB",
183+
"Portamento_Time_LSB",
184+
"Data_Entry_LSB",
185+
"Chan_Vol_LSB",
186+
"Balance_LSB",
187+
"Ctrl_9_LSB",
188+
"Pan_Ctrl_LSB",
189+
"Exp_Pedal_LSB",
190+
"FX_Ctrl_1_LSB",
191+
"FX_Ctrl_2_LSB",
192+
"Ctrl_14_LSB",
193+
"Ctrl_15_LSB",
194+
"Gen_Pur_1_LSB",
195+
"Gen_Pur_2_LSB",
196+
"Gen_Pur_3_LSB",
197+
"Gen_Pur_4_LSB",
198+
"Ctrl_20_LSB",
199+
"Ctrl_21_LSB",
200+
"Ctrl_22_LSB",
201+
"Ctrl_23_LSB",
202+
"Ctrl_24_LSB",
203+
"Ctrl_25_LSB",
204+
"Ctrl_26_LSB",
205+
"Ctrl_27_LSB",
206+
"Ctrl_28_LSB",
207+
"Ctrl_29_LSB",
208+
"Ctrl_30_LSB",
209+
"Ctrl_31_LSB",
210+
"Sus_Damp_Pedal_sw",
211+
"Portamento_sw",
212+
"Sostenuto_sw",
213+
"Soft_Pedal_sw",
214+
"Legato_Foot_sw",
215+
"Hold_2_sw",
216+
"Sound_Ctrl_1_Variation",
217+
"Sound_Ctrl_2_Timbre",
218+
"Sound_Ctrl_3_Release",
219+
"Sound_Ctrl_4_Attack",
220+
"Sound_Ctrl_5_Bright",
221+
"Sound_Ctrl_6_Decay",
222+
"Sound_Ctrl_7_Vib_Rate",
223+
"Sound_Ctrl_8_Vib_Depth",
224+
"Sound_Ctrl_9_Vib_Delay",
225+
"Sound_Ctrl_10",
226+
"Gen_Pur_5",
227+
"Gen_Pur_6",
228+
"Gen_Pur_7",
229+
"Gen_Pur_8",
230+
"Portamento_Ctrl",
231+
"Ctrl_85",
232+
"Ctrl_86",
233+
"Ctrl_87",
234+
"HR_Vel_Prefix",
235+
"Ctrl_89",
236+
"Ctrl_90",
237+
"FX_1_Depth_Reverb",
238+
"FX_2_Depth",
239+
"FX_3_Depth",
240+
"FX_4_Depth",
241+
"FX_5_Depth",
242+
"Data_Inc + Value",
243+
"Data_Dec + Value",
244+
"NRPN_LSB + Value",
245+
"NRPN_MSB + Value",
246+
"RPN_LSB + Value",
247+
"RPN_MSB + Value",
248+
"Ctrl_102",
249+
"Ctrl_103",
250+
"Ctrl_104",
251+
"Ctrl_105",
252+
"Ctrl_106",
253+
"Ctrl_107",
254+
"Ctrl_108",
255+
"Ctrl_109",
256+
"Ctrl_110",
257+
"Ctrl_111",
258+
"Ctrl_112",
259+
"Ctrl_113",
260+
"Ctrl_114",
261+
"Ctrl_115",
262+
"Ctrl_116",
263+
"Ctrl_117",
264+
"Ctrl_118",
265+
"Ctrl_119",
266+
"All_Sound_Off",
267+
"Reset_All_Ctrls",
268+
"Local_Ctrl_Sw",
269+
"All_Notes_Off",
270+
"Omni_Mode_Off",
271+
"Omni_Mode_On",
272+
"Mono_Mode_On",
273+
"Poly_Mode_On",
257274
]
258275

259276

0 commit comments

Comments
 (0)