simetri.extensions.music
Musical notes and scales. MIDI and frequency conversions.
1'''Musical notes and scales. MIDI and frequency conversions.''' 2 3from math import log2 4 5from typing_extensions import Sequence, Any 6 7# from simetri.graphics.extensions.all_enums import MusicScale 8 9def midi_freq(m: int) -> float: 10 '''Return the frequency of a MIDI note number.''' 11 return 2**((m-69)/12) * 440 12 13def midi_m(freq: float) -> int: 14 '''Return the MIDI note number of a frequency.''' 15 return 12 * log2(freq / 440) + 69 16 17 18def note_name(midi_note: int) -> str: 19 """ 20 Returns the name of a MIDI note given its number. 21 22 Args: 23 midi_note: An integer representing the MIDI note number (0-127). 24 25 Returns: 26 A string representing the note name (e.g., "C4", "G#5"), or None if the input is invalid. 27 """ 28 if not isinstance(midi_note, int) or midi_note < 0 or midi_note > 127: 29 return None 30 31 notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] 32 octave = midi_note // 12 - 1 33 note_index = midi_note % 12 34 return notes[note_index] + str(octave) 35 36def scale(m: int, scale_type:str = 'major') -> list: 37 '''Return a list of MIDI notes in a scale.''' 38 steps = {'major': [2, 2, 1, 2, 2, 2, 1], 39 'minor': [2, 1, 2, 2, 1, 2, 2], 40 'chromatic': [1] * 12, 41 'pentatonic': [2, 2, 3, 2, 3],} 42 s = [m] 43 for step in steps[scale_type]: 44 m += step 45 s.append(m) 46 return s 47 48 49 50def jump_scale(scale: Sequence, reference: Any, step:int) -> Any: 51 '''Return the note in a scale that is a certain number of steps away from a reference note. 52 Args: 53 scale: A list of MIDI notes in a scale. 54 reference: The reference note. 55 step: The number of steps away from the reference note. 56 Returns: 57 The note in the scale that is a certain number of steps away from the reference note. 58 59 Example: 60 jump_scale([60, 62, 64, 65, 67, 69, 71], 60, -2) returns 69. 61 ''' 62 i = scale.index(reference) 63 n = len(scale) 64 65 return scale[(i + step) % n]
def
midi_freq(m: int) -> float:
10def midi_freq(m: int) -> float: 11 '''Return the frequency of a MIDI note number.''' 12 return 2**((m-69)/12) * 440
Return the frequency of a MIDI note number.
def
midi_m(freq: float) -> int:
14def midi_m(freq: float) -> int: 15 '''Return the MIDI note number of a frequency.''' 16 return 12 * log2(freq / 440) + 69
Return the MIDI note number of a frequency.
def
note_name(midi_note: int) -> str:
19def note_name(midi_note: int) -> str: 20 """ 21 Returns the name of a MIDI note given its number. 22 23 Args: 24 midi_note: An integer representing the MIDI note number (0-127). 25 26 Returns: 27 A string representing the note name (e.g., "C4", "G#5"), or None if the input is invalid. 28 """ 29 if not isinstance(midi_note, int) or midi_note < 0 or midi_note > 127: 30 return None 31 32 notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] 33 octave = midi_note // 12 - 1 34 note_index = midi_note % 12 35 return notes[note_index] + str(octave)
Returns the name of a MIDI note given its number.
Arguments:
- midi_note: An integer representing the MIDI note number (0-127).
Returns:
A string representing the note name (e.g., "C4", "G#5"), or None if the input is invalid.
def
scale(m: int, scale_type: str = 'major') -> list:
37def scale(m: int, scale_type:str = 'major') -> list: 38 '''Return a list of MIDI notes in a scale.''' 39 steps = {'major': [2, 2, 1, 2, 2, 2, 1], 40 'minor': [2, 1, 2, 2, 1, 2, 2], 41 'chromatic': [1] * 12, 42 'pentatonic': [2, 2, 3, 2, 3],} 43 s = [m] 44 for step in steps[scale_type]: 45 m += step 46 s.append(m) 47 return s
Return a list of MIDI notes in a scale.
def
jump_scale( scale: Sequence, reference: typing_extensions.Any, step: int) -> typing_extensions.Any:
51def jump_scale(scale: Sequence, reference: Any, step:int) -> Any: 52 '''Return the note in a scale that is a certain number of steps away from a reference note. 53 Args: 54 scale: A list of MIDI notes in a scale. 55 reference: The reference note. 56 step: The number of steps away from the reference note. 57 Returns: 58 The note in the scale that is a certain number of steps away from the reference note. 59 60 Example: 61 jump_scale([60, 62, 64, 65, 67, 69, 71], 60, -2) returns 69. 62 ''' 63 i = scale.index(reference) 64 n = len(scale) 65 66 return scale[(i + step) % n]
Return the note in a scale that is a certain number of steps away from a reference note.
Arguments:
- scale: A list of MIDI notes in a scale.
- reference: The reference note.
- step: The number of steps away from the reference note.
Returns:
The note in the scale that is a certain number of steps away from the reference note.
Example:
jump_scale([60, 62, 64, 65, 67, 69, 71], 60, -2) returns 69.