Source code for sound.notes

import re

__all__ = ['note', 'notename', 'scales', 'A0', 'Ab0', 'As0', 'B0', 'Bb0', 'Bs0', 'C0', 'Cb0', 'Cs0', 'D0', 'Db0', 'Ds0', 'E0', 'Eb0', 'Es0', 'F0', 'Fb0', 'Fs0', 'G0', 'Gb0', 'Gs0', 'A1', 'Ab1', 'As1', 'B1', 'Bb1', 'Bs1', 'C1', 'Cb1', 'Cs1', 'D1', 'Db1', 'Ds1', 'E1', 'Eb1', 'Es1', 'F1', 'Fb1', 'Fs1', 'G1', 'Gb1', 'Gs1', 'A2', 'Ab2', 'As2', 'B2', 'Bb2', 'Bs2', 'C2', 'Cb2', 'Cs2', 'D2', 'Db2', 'Ds2', 'E2', 'Eb2', 'Es2', 'F2', 'Fb2', 'Fs2', 'G2', 'Gb2', 'Gs2', 'A3', 'Ab3', 'As3', 'B3', 'Bb3', 'Bs3', 'C3', 'Cb3', 'Cs3', 'D3', 'Db3', 'Ds3', 'E3', 'Eb3', 'Es3', 'F3', 'Fb3', 'Fs3', 'G3', 'Gb3', 'Gs3', 'A4', 'Ab4', 'As4', 'B4', 'Bb4', 'Bs4', 'C4', 'Cb4', 'Cs4', 'D4', 'Db4', 'Ds4', 'E4', 'Eb4', 'Es4', 'F4', 'Fb4', 'Fs4', 'G4', 'Gb4', 'Gs4', 'A5', 'Ab5', 'As5', 'B5', 'Bb5', 'Bs5', 'C5', 'Cb5', 'Cs5', 'D5', 'Db5', 'Ds5', 'E5', 'Eb5', 'Es5', 'F5', 'Fb5', 'Fs5', 'G5', 'Gb5', 'Gs5', 'A6', 'Ab6', 'As6', 'B6', 'Bb6', 'Bs6', 'C6', 'Cb6', 'Cs6', 'D6', 'Db6', 'Ds6', 'E6', 'Eb6', 'Es6', 'F6', 'Fb6', 'Fs6', 'G6', 'Gb6', 'Gs6', 'A7', 'Ab7', 'As7', 'B7', 'Bb7', 'Bs7', 'C7', 'Cb7', 'Cs7', 'D7', 'Db7', 'Ds7', 'E7', 'Eb7', 'Es7', 'F7', 'Fb7', 'Fs7', 'G7', 'Gb7', 'Gs7', 'A8', 'Ab8', 'As8', 'B8', 'Bb8', 'Bs8', 'C8', 'Cb8', 'Cs8', 'D8', 'Db8', 'Ds8', 'E8', 'Eb8', 'Es8', 'F8', 'Fb8', 'Fs8', 'G8', 'Gb8', 'Gs8', 'A9', 'Ab9', 'As9', 'B9', 'Bb9', 'Bs9', 'C9', 'Cb9', 'Cs9', 'D9', 'Db9', 'Ds9', 'E9', 'Eb9', 'Es9', 'F9', 'Fb9', 'Fs9', 'G9', 'Gb9', 'Gs9'] # type: ignore[reportUnsupportedDunderAll]

scales = {
    'major': [0, 2, 4, 5, 7, 9, 11],
    'minor': [0, 2, 3, 5, 7, 9, 10],
    'chromatic': [0,1,2,3,4,5,6,7,8,9,10,11]
}

[docs] def note(degree, octave=3, key='C', scale='major', accidental=''): """ Return the frequency of the note with the given characteristics :param degree: The scale degree of the note, zero-based :param octave: The octave of the note :param key: The key of the scale :param scale: The name of the scale as a string. Options are "major", "minor", and "chromatic". :param accidental: The accidental for this note as a string. Options are "sharp", "#", or "s" for sharp, "flat", "b", or "f" for flat. Note that accidentals do not respect the key - if you are in G major and you ask for the sixth degree (ti) sharpened, you will get back G, not F# like you would play if you were reading sheet music. Consequentially, there is no natural accidental. """ pianokey = (octave*12 + scales[scale][degree % len(scales[scale])]) if accidental.lower() in ('sharp', '#', 's'): pianokey += 1 elif accidental.lower() in ('flat', 'b', 'f'): pianokey -= 1 elif accidental.lower() in ('doublesharp', '##', 'ss'): pianokey += 2 elif accidental.lower() in ('doubleflat', 'bb', 'ff'): pianokey -= 2 return 2**(pianokey/12.) * notename(key + '0')
[docs] def notename(name): """ Translate the name of a note, like "A4", into its frequency in hertz. """ if name == 'C0': return 27.5 * 2**(-9./12) m = re.search('([A-G])(|b|#|s|f)([0-9])', name) if m is None: raise ValueError(f"Invalid note {name}") notestr, accidental, octave = m.group(1), m.group(2), m.group(3) degree = {'C': 0, 'D': 1, 'E': 2, 'F': 3, 'G': 4, 'A': 5, 'B': 6}[notestr] octavenum = int(octave) return note(degree, octavenum, accidental=accidental, key='C', scale='major')
for _octave in range(10): for _letter in 'ABCDEFG': for _accidental in ['', 'b', 's']: _name = _letter + _accidental + str(_octave) vars()[_name] = notename(_name)