music_dsl

 1from dataclasses import dataclass
 2
 3from music_dsl.domain.static.notes import Notes
 4from music_dsl.encode import Scales
 5
 6
 7@dataclass
 8class Key:
 9    root: Notes
10    scale: Scales
11
12
13__version__ = "0.1.0"
14
15# The thin top-level surface (Key/Notes/Scales) is intentional: deeper theory is
16# submodule-scoped (see API-SURFACE.md). __all__ keeps `import *` to exactly this.
17__all__ = ["Key", "Notes", "Scales", "__version__"]
@dataclass
class Key:
 8@dataclass
 9class Key:
10    root: Notes
11    scale: Scales
Key( root: Notes, scale: Scales)
root: Notes
scale: Scales
class Notes(music_dsl.utils.JsonSerializableEnum):
11class Notes(JsonSerializableEnum):
12    C = "C"
13    Cs = "C#"
14    Db = "Db"
15    D = "D"
16    Ds = "D#"
17    Eb = "Eb"
18    E = "E"
19    F = "F"
20    Fs = "F#"
21    Gb = "Gb"
22    G = "G"
23    Gs = "G#"
24    Ab = "Ab"
25    A = "A"
26    As = "A#"
27    Bb = "Bb"
28    B = "B"
29
30    def to_flat(self):
31        if self.value not in _SHARPS_TO_FLATS:
32            return self
33        return Notes(_SHARPS_TO_FLATS[self.value])
34
35    def normalized(self):
36        return self.to_flat()
37
38    def __eq__(self, other):
39        if not isinstance(other, Notes):
40            return NotImplemented  # note == None / str / ScaleDegree → False, not a crash
41        enharmonic = _SHARPS_TO_FLATS.get(other.value) or _FLATS_TO_SHARPS.get(
42            other.value
43        )
44        return self.value == other.value or self.value == enharmonic
45
46    def __hash__(self):
47        # Consistent with the enharmonic __eq__: sharps/flats of the same pitch
48        # (Cs/Db, ...) normalize to one flat spelling, so equal notes hash equal.
49        return hash(self.to_flat().value)
50
51    @classmethod
52    def names_by_value(cls):
53        """Map each note's string value to its member name (e.g. ``'C#' -> 'Cs'``)."""
54        return {note.value: note.name for note in cls}
C = <Notes.C: 'C'>
Cs = <Notes.Cs: 'C#'>
Db = <Notes.Db: 'Db'>
D = <Notes.D: 'D'>
Ds = <Notes.Ds: 'D#'>
Eb = <Notes.Eb: 'Eb'>
E = <Notes.E: 'E'>
F = <Notes.F: 'F'>
Fs = <Notes.Fs: 'F#'>
Gb = <Notes.Gb: 'Gb'>
G = <Notes.G: 'G'>
Gs = <Notes.Gs: 'G#'>
Ab = <Notes.Ab: 'Ab'>
A = <Notes.A: 'A'>
As = <Notes.As: 'A#'>
Bb = <Notes.Bb: 'Bb'>
B = <Notes.B: 'B'>
def to_flat(self):
30    def to_flat(self):
31        if self.value not in _SHARPS_TO_FLATS:
32            return self
33        return Notes(_SHARPS_TO_FLATS[self.value])
def normalized(self):
35    def normalized(self):
36        return self.to_flat()
@classmethod
def names_by_value(cls):
51    @classmethod
52    def names_by_value(cls):
53        """Map each note's string value to its member name (e.g. ``'C#' -> 'Cs'``)."""
54        return {note.value: note.name for note in cls}

Map each note's string value to its member name (e.g. 'C#' -> 'Cs').

class Scales(enum.Enum):
146class Scales(Enum):
147    # --- Modes of the major scale (functional) --------------------------------
148    Major = _fn(_scale_mask(0, 2, 4, 5, 7, 9, 11), "Major (Ionian)", "major-mode")
149    Dorian = _fn(_scale_mask(0, 2, 3, 5, 7, 9, 10), "Dorian", "major-mode")
150    Phrygian = _fn(_scale_mask(0, 1, 3, 5, 7, 8, 10), "Phrygian", "major-mode")
151    Lydian = _fn(_scale_mask(0, 2, 4, 6, 7, 9, 11), "Lydian", "major-mode")
152    Mixolydian = _fn(_scale_mask(0, 2, 4, 5, 7, 9, 10), "Mixolydian", "major-mode")
153    Minor = _fn(_scale_mask(0, 2, 3, 5, 7, 8, 10), "Natural minor (Aeolian)", "major-mode")
154    Locrian = _fn(_scale_mask(0, 1, 3, 5, 6, 8, 10), "Locrian", "major-mode")
155
156    # --- Melodic minor and its modes (functional) -----------------------------
157    MelodicMinor = _fn(_scale_mask(0, 2, 3, 5, 7, 9, 11), "Melodic minor", "melodic-minor")
158    DorianFlat2 = _fn(_scale_mask(0, 1, 3, 5, 7, 9, 10), "Dorian b2", "melodic-minor")
159    LydianAugmented = _fn(_scale_mask(0, 2, 4, 6, 8, 9, 11), "Lydian augmented", "melodic-minor")
160    LydianDominant = _fn(_scale_mask(0, 2, 4, 6, 7, 9, 10), "Lydian dominant", "melodic-minor")
161    MixolydianFlat6 = _fn(_scale_mask(0, 2, 4, 5, 7, 8, 10), "Mixolydian b6", "melodic-minor")
162    LocrianNatural2 = _fn(_scale_mask(0, 2, 3, 5, 6, 8, 10), "Locrian natural 2", "melodic-minor")
163    Altered = _fn(_scale_mask(0, 1, 3, 4, 6, 8, 10), "Altered (Super Locrian)", "melodic-minor")
164
165    # --- Harmonic minor and its modes (functional) ----------------------------
166    HarmonicMinor = _fn(_scale_mask(0, 2, 3, 5, 7, 8, 11), "Harmonic minor", "harmonic-minor")
167    LocrianNatural6 = _fn(_scale_mask(0, 1, 3, 5, 6, 9, 10), "Locrian natural 6", "harmonic-minor")
168    IonianSharp5 = _fn(_scale_mask(0, 2, 4, 5, 8, 9, 11), "Ionian #5", "harmonic-minor")
169    DorianSharp4 = _fn(_scale_mask(0, 2, 3, 6, 7, 9, 10), "Dorian #4 (Ukrainian)", "harmonic-minor")
170    PhrygianDominant = _fn(_scale_mask(0, 1, 4, 5, 7, 8, 10), "Phrygian dominant", "harmonic-minor")
171    LydianSharp2 = _fn(_scale_mask(0, 3, 4, 6, 7, 9, 11), "Lydian #2", "harmonic-minor")
172    Ultralocrian = _fn(_scale_mask(0, 1, 3, 4, 6, 8, 9), "Ultralocrian", "harmonic-minor")
173
174    # --- Harmonic major and other named heptatonics (functional) --------------
175    HarmonicMajor = _fn(_scale_mask(0, 2, 4, 5, 7, 8, 11), "Harmonic major", "harmonic-major")
176    DoubleHarmonic = _fn(_scale_mask(0, 1, 4, 5, 7, 8, 11), "Double harmonic (Byzantine)", "exotic")
177    HungarianMinor = _fn(_scale_mask(0, 2, 3, 6, 7, 8, 11), "Hungarian minor", "exotic")
178    HungarianMajor = _fn(_scale_mask(0, 3, 4, 6, 7, 9, 10), "Hungarian major", "exotic")
179    NeapolitanMajor = _fn(_scale_mask(0, 1, 3, 5, 7, 9, 11), "Neapolitan major", "exotic")
180    NeapolitanMinor = _fn(_scale_mask(0, 1, 3, 5, 7, 8, 11), "Neapolitan minor", "exotic")
181
182    # --- Pentatonic and blues (functional) ------------------------------------
183    MajorPentatonic = _fn(_scale_mask(0, 2, 4, 7, 9), "Major pentatonic", "pentatonic")
184    MinorPentatonic = _fn(_scale_mask(0, 3, 5, 7, 10), "Minor pentatonic", "pentatonic")
185    Blues = _fn(_scale_mask(0, 3, 5, 6, 7, 10), "Blues (minor)", "blues")
186
187    # --- Bebop (functional, 8-note; passing tone documented in SPEC) -----------
188    BebopDominant = _fn(_scale_mask(0, 2, 4, 5, 7, 9, 10, 11), "Bebop dominant", "bebop")
189    BebopMajor = _fn(_scale_mask(0, 2, 4, 5, 7, 8, 9, 11), "Bebop major", "bebop")
190    BebopDorian = _fn(_scale_mask(0, 2, 3, 4, 5, 7, 9, 10), "Bebop Dorian", "bebop")
191    BebopMinor = _fn(_scale_mask(0, 2, 3, 5, 7, 9, 10, 11), "Bebop minor", "bebop")
192
193    # --- Symmetric / atonal (NON-functional: membership only) -----------------
194    WholeTone = _sym(_scale_mask(0, 2, 4, 6, 8, 10), "Whole tone", "symmetric")
195    DiminishedHalfWhole = _sym(
196        _scale_mask(0, 1, 3, 4, 6, 7, 9, 10), "Diminished (half-whole)", "symmetric"
197    )
198    DiminishedWholeHalf = _sym(
199        _scale_mask(0, 2, 3, 5, 6, 8, 9, 11), "Diminished (whole-half)", "symmetric"
200    )
201    Augmented = _sym(_scale_mask(0, 3, 4, 7, 8, 11), "Augmented", "symmetric")
202    Chromatic = _sym(_scale_mask(*range(12)), "Chromatic", "atonal")
Major = <Scales.Major: ScaleDescriptor(mask=46534580949, name='Major (Ionian)', category='major-mode', supports_diatonic_function=True)>
Dorian = <Scales.Dorian: ScaleDescriptor(mask=48699370326, name='Dorian', category='major-mode', supports_diatonic_function=True)>
Phrygian = <Scales.Phrygian: ScaleDescriptor(mask=57358527834, name='Phrygian', category='major-mode', supports_diatonic_function=True)>
Lydian = <Scales.Lydian: ScaleDescriptor(mask=45997578933, name='Lydian', category='major-mode', supports_diatonic_function=True)>
Mixolydian = <Scales.Mixolydian: ScaleDescriptor(mask=46551362262, name='Mixolydian', category='major-mode', supports_diatonic_function=True)>
Minor = <Scales.Minor: ScaleDescriptor(mask=48766495578, name='Natural minor (Aeolian)', category='major-mode', supports_diatonic_function=True)>
Locrian = <Scales.Locrian: ScaleDescriptor(mask=57627028842, name='Locrian', category='major-mode', supports_diatonic_function=True)>
MelodicMinor = <Scales.MelodicMinor: ScaleDescriptor(mask=48682589013, name='Melodic minor', category='melodic-minor', supports_diatonic_function=True)>
DorianFlat2 = <Scales.DorianFlat2: ScaleDescriptor(mask=57291402582, name='Dorian b2', category='melodic-minor', supports_diatonic_function=True)>
LydianAugmented = <Scales.LydianAugmented: ScaleDescriptor(mask=45863328429, name='Lydian augmented', category='melodic-minor', supports_diatonic_function=True)>
LydianDominant = <Scales.LydianDominant: ScaleDescriptor(mask=46014360246, name='Lydian dominant', category='melodic-minor', supports_diatonic_function=True)>
MixolydianFlat6 = <Scales.MixolydianFlat6: ScaleDescriptor(mask=46618487514, name='Mixolydian b6', category='melodic-minor', supports_diatonic_function=True)>
LocrianNatural2 = <Scales.LocrianNatural2: ScaleDescriptor(mask=49034996586, name='Locrian natural 2', category='melodic-minor', supports_diatonic_function=True)>
Altered = <Scales.Altered: ScaleDescriptor(mask=58701032874, name='Altered (Super Locrian)', category='melodic-minor', supports_diatonic_function=True)>
HarmonicMinor = <Scales.HarmonicMinor: ScaleDescriptor(mask=48749714265, name='Harmonic minor', category='harmonic-minor', supports_diatonic_function=True)>
LocrianNatural6 = <Scales.LocrianNatural6: ScaleDescriptor(mask=57559903590, name='Locrian natural 6', category='harmonic-minor', supports_diatonic_function=True)>
IonianSharp5 = <Scales.IonianSharp5: ScaleDescriptor(mask=46400330445, name='Ionian #5', category='harmonic-minor', supports_diatonic_function=True)>
DorianSharp4 = <Scales.DorianSharp4: ScaleDescriptor(mask=48162368310, name='Dorian #4 (Ukrainian)', category='harmonic-minor', supports_diatonic_function=True)>
PhrygianDominant = <Scales.PhrygianDominant: ScaleDescriptor(mask=55210519770, name='Phrygian dominant', category='harmonic-minor', supports_diatonic_function=True)>
LydianSharp2 = <Scales.LydianSharp2: ScaleDescriptor(mask=41701562805, name='Lydian #2', category='harmonic-minor', supports_diatonic_function=True)>
Ultralocrian = <Scales.Ultralocrian: ScaleDescriptor(mask=58734595500, name='Ultralocrian', category='harmonic-minor', supports_diatonic_function=True)>
HarmonicMajor = <Scales.HarmonicMajor: ScaleDescriptor(mask=46601706201, name='Harmonic major', category='harmonic-major', supports_diatonic_function=True)>
DoubleHarmonic = <Scales.DoubleHarmonic: ScaleDescriptor(mask=55193738457, name='Double harmonic (Byzantine)', category='exotic', supports_diatonic_function=True)>
HungarianMinor = <Scales.HungarianMinor: ScaleDescriptor(mask=48212712249, name='Hungarian minor', category='exotic', supports_diatonic_function=True)>
HungarianMajor = <Scales.HungarianMajor: ScaleDescriptor(mask=41718344118, name='Hungarian major', category='exotic', supports_diatonic_function=True)>
NeapolitanMajor = <Scales.NeapolitanMajor: ScaleDescriptor(mask=57274621269, name='Neapolitan major', category='exotic', supports_diatonic_function=True)>
NeapolitanMinor = <Scales.NeapolitanMinor: ScaleDescriptor(mask=57341746521, name='Neapolitan minor', category='exotic', supports_diatonic_function=True)>
MajorPentatonic = <Scales.MajorPentatonic: ScaleDescriptor(mask=45443795604, name='Major pentatonic', category='pentatonic', supports_diatonic_function=True)>
MinorPentatonic = <Scales.MinorPentatonic: ScaleDescriptor(mask=40040212818, name='Minor pentatonic', category='pentatonic', supports_diatonic_function=True)>
Blues = <Scales.Blues: ScaleDescriptor(mask=40577214834, name='Blues (minor)', category='blues', supports_diatonic_function=True)>
BebopDominant = <Scales.BebopDominant: ScaleDescriptor(mask=46568143575, name='Bebop dominant', category='bebop', supports_diatonic_function=True)>
BebopMajor = <Scales.BebopMajor: ScaleDescriptor(mask=46668831453, name='Bebop major', category='bebop', supports_diatonic_function=True)>
BebopDorian = <Scales.BebopDorian: ScaleDescriptor(mask=50847378390, name='Bebop Dorian', category='bebop', supports_diatonic_function=True)>
BebopMinor = <Scales.BebopMinor: ScaleDescriptor(mask=48716151639, name='Bebop minor', category='bebop', supports_diatonic_function=True)>
WholeTone = <Scales.WholeTone: ScaleDescriptor(mask=45812984490, name='Whole tone', category='symmetric', supports_diatonic_function=False)>
DiminishedHalfWhole = <Scales.DiminishedHalfWhole: ScaleDescriptor(mask=58902408630, name='Diminished (half-whole)', category='symmetric', supports_diatonic_function=False)>
DiminishedWholeHalf = <Scales.DiminishedWholeHalf: ScaleDescriptor(mask=49085340525, name='Diminished (whole-half)', category='symmetric', supports_diatonic_function=False)>
Augmented = <Scales.Augmented: ScaleDescriptor(mask=41231686041, name='Augmented', category='symmetric', supports_diatonic_function=False)>
Chromatic = <Scales.Chromatic: ScaleDescriptor(mask=68719476735, name='Chromatic', category='atonal', supports_diatonic_function=False)>
__version__ = '0.1.0'