diff --git a/website/sandbox/chord-drill-sergeant/src/Main.elm b/website/sandbox/chord-drill-sergeant/src/Main.elm index 2c9f33aa6..2e6de1a1c 100644 --- a/website/sandbox/chord-drill-sergeant/src/Main.elm +++ b/website/sandbox/chord-drill-sergeant/src/Main.elm @@ -17,7 +17,7 @@ type alias Model = { whitelistedChords : List Theory.Chord , whitelistedChordTypes : List Theory.ChordType , whitelistedInversions : List Theory.ChordInversion - , whitelistedNoteClasses : List Theory.NoteClass + , whitelistedPitchClasses : List Theory.PitchClass , selectedChord : Maybe Theory.Chord , isPaused : Bool , tempo : Int @@ -41,7 +41,7 @@ type Msg | ToggleInspectChord | ToggleInversion Theory.ChordInversion | ToggleChordType Theory.ChordType - | ToggleNoteClass Theory.NoteClass + | TogglePitchClass Theory.PitchClass | DoNothing @@ -78,8 +78,8 @@ init = chordTypes = Theory.allChordTypes - noteClasses = - Theory.allNoteClasses + pitchClasses = + Theory.allPitchClasses in { whitelistedChords = Theory.allChords @@ -87,11 +87,11 @@ init = , end = lastNote , inversions = inversions , chordTypes = chordTypes - , noteClasses = noteClasses + , pitchClasses = pitchClasses } , whitelistedChordTypes = chordTypes , whitelistedInversions = inversions - , whitelistedNoteClasses = noteClasses + , whitelistedPitchClasses = pitchClasses , selectedChord = Nothing , isPaused = True , tempo = 60 @@ -187,7 +187,7 @@ update msg model = , end = model.lastNote , inversions = model.whitelistedInversions , chordTypes = chordTypes - , noteClasses = model.whitelistedNoteClasses + , pitchClasses = model.whitelistedPitchClasses } } , Cmd.none @@ -210,30 +210,30 @@ update msg model = , end = model.lastNote , inversions = inversions , chordTypes = model.whitelistedChordTypes - , noteClasses = model.whitelistedNoteClasses + , pitchClasses = model.whitelistedPitchClasses } } , Cmd.none ) - ToggleNoteClass noteClass -> + TogglePitchClass pitchClass -> let - noteClasses = - if List.member noteClass model.whitelistedNoteClasses then - List.filter ((/=) noteClass) model.whitelistedNoteClasses + pitchClasses = + if List.member pitchClass model.whitelistedPitchClasses then + List.filter ((/=) pitchClass) model.whitelistedPitchClasses else - noteClass :: model.whitelistedNoteClasses + pitchClass :: model.whitelistedPitchClasses in ( { model - | whitelistedNoteClasses = noteClasses + | whitelistedPitchClasses = pitchClasses , whitelistedChords = Theory.allChords { start = model.firstNote , end = model.lastNote , inversions = model.whitelistedInversions , chordTypes = model.whitelistedChordTypes - , noteClasses = noteClasses + , pitchClasses = pitchClasses } } , Cmd.none @@ -270,18 +270,18 @@ debugger = ] -noteClassCheckboxes : List Theory.NoteClass -> Html Msg -noteClassCheckboxes noteClasses = +pitchClassCheckboxes : List Theory.PitchClass -> Html Msg +pitchClassCheckboxes pitchClasses = ul [] - (Theory.allNoteClasses + (Theory.allPitchClasses |> List.map - (\noteClass -> + (\pitchClass -> li [] - [ label [] [ text (Theory.viewNoteClass noteClass) ] + [ label [] [ text (Theory.viewPitchClass pitchClass) ] , input [ type_ "checkbox" - , onClick (ToggleNoteClass noteClass) - , checked (List.member noteClass noteClasses) + , onClick (TogglePitchClass pitchClass) + , checked (List.member pitchClass pitchClasses) ] [] ] @@ -364,7 +364,7 @@ view model = , handleDecrease = DecreaseTempo , handleInput = SetTempo } - , noteClassCheckboxes model.whitelistedNoteClasses + , pitchClassCheckboxes model.whitelistedPitchClasses , inversionCheckboxes model.whitelistedInversions , chordTypeCheckboxes model.whitelistedChordTypes , playPause model diff --git a/website/sandbox/chord-drill-sergeant/src/Theory.elm b/website/sandbox/chord-drill-sergeant/src/Theory.elm index ba95215a8..63cba0e31 100644 --- a/website/sandbox/chord-drill-sergeant/src/Theory.elm +++ b/website/sandbox/chord-drill-sergeant/src/Theory.elm @@ -110,7 +110,7 @@ type Note {-| I alluded to this concept in the Note type's documentation. These are the letters of notes. For instance C2, C3, C4 are all instances of C. -} -type NoteClass +type PitchClass = C | C_sharp | D @@ -205,7 +205,7 @@ type KeyClass chords that harmonize with one another. -} type alias Key = - { noteClass : NoteClass + { pitchClass : PitchClass , mode : Mode } @@ -225,24 +225,24 @@ type Mode type alias NoteMetadata = { note : Note , label : String - , noteClass : NoteClass + , pitchClass : PitchClass , natural : Bool } -scaleDegree : Int -> Key -> NoteClass -scaleDegree which { noteClass } = - case noteClass of +scaleDegree : Int -> Key -> PitchClass +scaleDegree which { pitchClass } = + case pitchClass of _ -> C {-| Returns the Note in the cental octave of the piano for a given -NoteClass. For example, C4 -- or "middle C" -- for C. +PitchClass. For example, C4 -- or "middle C" -- for C. -} -noteInCentralOctave : NoteClass -> Note -noteInCentralOctave noteClass = - case noteClass of +noteInCentralOctave : PitchClass -> Note +noteInCentralOctave pitchClass = + case pitchClass of C -> C4 @@ -543,7 +543,7 @@ step { direction, interval } note = { direction = direction , interval = Half } - |> (\x -> applySteps x note) + |> (\x -> walkNotes x note) |> Maybe.andThen (List.reverse >> List.head) Whole -> @@ -598,13 +598,15 @@ In the case where applying any of the steps would result in running off of either edge of the piano, this function returns a Nothing. -} -applySteps : List IntervalVector -> Note -> Maybe (List Note) -applySteps steps note = - doApplySteps steps note [] |> Maybe.map List.reverse +walkNotes : List IntervalVector -> Note -> Maybe (List Note) +walkNotes steps note = + doWalkNotes steps note [] |> Maybe.map List.reverse -doApplySteps : List IntervalVector -> Note -> List Note -> Maybe (List Note) -doApplySteps steps note result = +{-| Recursive helper for `walkNotes`. +-} +doWalkNotes : List IntervalVector -> Note -> List Note -> Maybe (List Note) +doWalkNotes steps note result = case steps of [] -> Just (note :: result) @@ -612,7 +614,7 @@ doApplySteps steps note result = s :: rest -> case step s note of Just x -> - doApplySteps rest x (note :: result) + doWalkNotes rest x (note :: result) Nothing -> Nothing @@ -629,11 +631,11 @@ keyClass note = Accidental -{-| Return the NoteClass for a given note. +{-| Return the PitchClass for a given note. -} -classifyNote : Note -> NoteClass +classifyNote : Note -> PitchClass classifyNote note = - note |> getNoteMetadata |> .noteClass + note |> getNoteMetadata |> .pitchClass {-| Return a list of the notes that comprise a `chord` @@ -649,12 +651,12 @@ notesForChord { note, chordType, chordInversion } = {-| Return the scale for a given `key` -} notesForKey : Key -> List Note -notesForKey { noteClass, mode } = +notesForKey { pitchClass, mode } = let origin = - noteInCentralOctave noteClass + noteInCentralOctave pitchClass in - case applySteps (intervalsForMode mode) origin of + case walkNotes (intervalsForMode mode) origin of -- We should never hit the Nothing case here. Nothing -> [] @@ -716,94 +718,98 @@ allChordTypes = ] +{-| Return an array of every note on a piano. +Note: Currently this piano has 85 keys, but modern pianos have 88 keys. I would +prefer to have 88 keys, but it's not urgent. +-} noteMetadata : Array NoteMetadata noteMetadata = Array.fromList - [ { note = A1, label = "A1", noteClass = A, natural = True } - , { note = A_sharp1, label = "A♯/B♭1", noteClass = A_sharp, natural = False } - , { note = B1, label = "B1", noteClass = B, natural = True } - , { note = C1, label = "C1", noteClass = C, natural = True } - , { note = C_sharp1, label = "C♯/D♭1", noteClass = C_sharp, natural = False } - , { note = D1, label = "D1", noteClass = D, natural = True } - , { note = D_sharp1, label = "D♯/E♭1", noteClass = D_sharp, natural = False } - , { note = E1, label = "E1", noteClass = E, natural = True } - , { note = F1, label = "F1", noteClass = F, natural = True } - , { note = F_sharp1, label = "F♯/G♭1", noteClass = F_sharp, natural = False } - , { note = G1, label = "G1", noteClass = G, natural = True } - , { note = G_sharp1, label = "G♯/A♭1", noteClass = G, natural = False } - , { note = A2, label = "A2", noteClass = A, natural = True } - , { note = A_sharp2, label = "A♯/B♭2", noteClass = A_sharp, natural = False } - , { note = B2, label = "B2", noteClass = B, natural = True } - , { note = C2, label = "C2", noteClass = C, natural = True } - , { note = C_sharp2, label = "C♯/D♭2", noteClass = C_sharp, natural = False } - , { note = D2, label = "D2", noteClass = D, natural = True } - , { note = D_sharp2, label = "D♯/E♭2", noteClass = D_sharp, natural = False } - , { note = E2, label = "E2", noteClass = E, natural = True } - , { note = F2, label = "F2", noteClass = F, natural = True } - , { note = F_sharp2, label = "F♯/G♭2", noteClass = F_sharp, natural = False } - , { note = G2, label = "G2", noteClass = G, natural = True } - , { note = G_sharp2, label = "G♯/A♭2", noteClass = G, natural = False } - , { note = A3, label = "A3", noteClass = A, natural = True } - , { note = A_sharp3, label = "A♯/B♭3", noteClass = A_sharp, natural = False } - , { note = B3, label = "B3", noteClass = B, natural = True } - , { note = C3, label = "C3", noteClass = C, natural = True } - , { note = C_sharp3, label = "C♯/D♭3", noteClass = C_sharp, natural = False } - , { note = D3, label = "D3", noteClass = D, natural = True } - , { note = D_sharp3, label = "D♯/E♭3", noteClass = D_sharp, natural = False } - , { note = E3, label = "E3", noteClass = E, natural = True } - , { note = F3, label = "F3", noteClass = F, natural = True } - , { note = F_sharp3, label = "F♯/G♭3", noteClass = F_sharp, natural = False } - , { note = G3, label = "G3", noteClass = G, natural = True } - , { note = G_sharp3, label = "G♯/A♭3", noteClass = G, natural = False } - , { note = A4, label = "A4", noteClass = A, natural = True } - , { note = A_sharp4, label = "A♯/B♭4", noteClass = A_sharp, natural = False } - , { note = B4, label = "B4", noteClass = B, natural = True } - , { note = C4, label = "C4", noteClass = C, natural = True } - , { note = C_sharp4, label = "C♯/D♭4", noteClass = C_sharp, natural = False } - , { note = D4, label = "D4", noteClass = D, natural = True } - , { note = D_sharp4, label = "D♯/E♭4", noteClass = D_sharp, natural = False } - , { note = E4, label = "E4", noteClass = E, natural = True } - , { note = F4, label = "F4", noteClass = F, natural = True } - , { note = F_sharp4, label = "F♯/G♭4", noteClass = F_sharp, natural = False } - , { note = G4, label = "G4", noteClass = G, natural = True } - , { note = G_sharp4, label = "G♯/A♭4", noteClass = G, natural = False } - , { note = A5, label = "A5", noteClass = A, natural = True } - , { note = A_sharp5, label = "A♯/B♭5", noteClass = A_sharp, natural = False } - , { note = B5, label = "B5", noteClass = B, natural = True } - , { note = C5, label = "C5", noteClass = C, natural = True } - , { note = C_sharp5, label = "C♯/D♭5", noteClass = C_sharp, natural = False } - , { note = D5, label = "D5", noteClass = D, natural = True } - , { note = D_sharp5, label = "D♯/E♭5", noteClass = D_sharp, natural = False } - , { note = E5, label = "E5", noteClass = E, natural = True } - , { note = F5, label = "F5", noteClass = F, natural = True } - , { note = F_sharp5, label = "F♯/G♭5", noteClass = F_sharp, natural = False } - , { note = G5, label = "G5", noteClass = G, natural = True } - , { note = G_sharp5, label = "G♯/A♭5", noteClass = G, natural = False } - , { note = A6, label = "A6", noteClass = A, natural = True } - , { note = A_sharp6, label = "A♯/B♭6", noteClass = A_sharp, natural = False } - , { note = B6, label = "B6", noteClass = B, natural = True } - , { note = C6, label = "C6", noteClass = C, natural = True } - , { note = C_sharp6, label = "C♯/D♭6", noteClass = C_sharp, natural = False } - , { note = D6, label = "D6", noteClass = D, natural = True } - , { note = D_sharp6, label = "D♯/E♭6", noteClass = D_sharp, natural = False } - , { note = E6, label = "E6", noteClass = E, natural = True } - , { note = F6, label = "F6", noteClass = F, natural = True } - , { note = F_sharp6, label = "F♯/G♭6", noteClass = F_sharp, natural = False } - , { note = G6, label = "G6", noteClass = G, natural = True } - , { note = G_sharp6, label = "G♯/A♭6", noteClass = G, natural = False } - , { note = A7, label = "A7", noteClass = A, natural = True } - , { note = A_sharp7, label = "A♯/B♭7", noteClass = A_sharp, natural = False } - , { note = B7, label = "B7", noteClass = B, natural = True } - , { note = C7, label = "C7", noteClass = C, natural = True } - , { note = C_sharp7, label = "C♯/D♭7", noteClass = C_sharp, natural = False } - , { note = D7, label = "D7", noteClass = D, natural = True } - , { note = D_sharp7, label = "D♯/E♭7", noteClass = D_sharp, natural = False } - , { note = E7, label = "E7", noteClass = E, natural = True } - , { note = F7, label = "F7", noteClass = F, natural = True } - , { note = F_sharp7, label = "F♯/G♭7", noteClass = F_sharp, natural = False } - , { note = G7, label = "G7", noteClass = G, natural = True } - , { note = G_sharp7, label = "G♯/A♭7", noteClass = G, natural = False } - , { note = C8, label = "C8", noteClass = C, natural = True } + [ { note = A1, label = "A1", pitchClass = A, natural = True } + , { note = A_sharp1, label = "A♯/B♭1", pitchClass = A_sharp, natural = False } + , { note = B1, label = "B1", pitchClass = B, natural = True } + , { note = C1, label = "C1", pitchClass = C, natural = True } + , { note = C_sharp1, label = "C♯/D♭1", pitchClass = C_sharp, natural = False } + , { note = D1, label = "D1", pitchClass = D, natural = True } + , { note = D_sharp1, label = "D♯/E♭1", pitchClass = D_sharp, natural = False } + , { note = E1, label = "E1", pitchClass = E, natural = True } + , { note = F1, label = "F1", pitchClass = F, natural = True } + , { note = F_sharp1, label = "F♯/G♭1", pitchClass = F_sharp, natural = False } + , { note = G1, label = "G1", pitchClass = G, natural = True } + , { note = G_sharp1, label = "G♯/A♭1", pitchClass = G, natural = False } + , { note = A2, label = "A2", pitchClass = A, natural = True } + , { note = A_sharp2, label = "A♯/B♭2", pitchClass = A_sharp, natural = False } + , { note = B2, label = "B2", pitchClass = B, natural = True } + , { note = C2, label = "C2", pitchClass = C, natural = True } + , { note = C_sharp2, label = "C♯/D♭2", pitchClass = C_sharp, natural = False } + , { note = D2, label = "D2", pitchClass = D, natural = True } + , { note = D_sharp2, label = "D♯/E♭2", pitchClass = D_sharp, natural = False } + , { note = E2, label = "E2", pitchClass = E, natural = True } + , { note = F2, label = "F2", pitchClass = F, natural = True } + , { note = F_sharp2, label = "F♯/G♭2", pitchClass = F_sharp, natural = False } + , { note = G2, label = "G2", pitchClass = G, natural = True } + , { note = G_sharp2, label = "G♯/A♭2", pitchClass = G, natural = False } + , { note = A3, label = "A3", pitchClass = A, natural = True } + , { note = A_sharp3, label = "A♯/B♭3", pitchClass = A_sharp, natural = False } + , { note = B3, label = "B3", pitchClass = B, natural = True } + , { note = C3, label = "C3", pitchClass = C, natural = True } + , { note = C_sharp3, label = "C♯/D♭3", pitchClass = C_sharp, natural = False } + , { note = D3, label = "D3", pitchClass = D, natural = True } + , { note = D_sharp3, label = "D♯/E♭3", pitchClass = D_sharp, natural = False } + , { note = E3, label = "E3", pitchClass = E, natural = True } + , { note = F3, label = "F3", pitchClass = F, natural = True } + , { note = F_sharp3, label = "F♯/G♭3", pitchClass = F_sharp, natural = False } + , { note = G3, label = "G3", pitchClass = G, natural = True } + , { note = G_sharp3, label = "G♯/A♭3", pitchClass = G, natural = False } + , { note = A4, label = "A4", pitchClass = A, natural = True } + , { note = A_sharp4, label = "A♯/B♭4", pitchClass = A_sharp, natural = False } + , { note = B4, label = "B4", pitchClass = B, natural = True } + , { note = C4, label = "C4", pitchClass = C, natural = True } + , { note = C_sharp4, label = "C♯/D♭4", pitchClass = C_sharp, natural = False } + , { note = D4, label = "D4", pitchClass = D, natural = True } + , { note = D_sharp4, label = "D♯/E♭4", pitchClass = D_sharp, natural = False } + , { note = E4, label = "E4", pitchClass = E, natural = True } + , { note = F4, label = "F4", pitchClass = F, natural = True } + , { note = F_sharp4, label = "F♯/G♭4", pitchClass = F_sharp, natural = False } + , { note = G4, label = "G4", pitchClass = G, natural = True } + , { note = G_sharp4, label = "G♯/A♭4", pitchClass = G, natural = False } + , { note = A5, label = "A5", pitchClass = A, natural = True } + , { note = A_sharp5, label = "A♯/B♭5", pitchClass = A_sharp, natural = False } + , { note = B5, label = "B5", pitchClass = B, natural = True } + , { note = C5, label = "C5", pitchClass = C, natural = True } + , { note = C_sharp5, label = "C♯/D♭5", pitchClass = C_sharp, natural = False } + , { note = D5, label = "D5", pitchClass = D, natural = True } + , { note = D_sharp5, label = "D♯/E♭5", pitchClass = D_sharp, natural = False } + , { note = E5, label = "E5", pitchClass = E, natural = True } + , { note = F5, label = "F5", pitchClass = F, natural = True } + , { note = F_sharp5, label = "F♯/G♭5", pitchClass = F_sharp, natural = False } + , { note = G5, label = "G5", pitchClass = G, natural = True } + , { note = G_sharp5, label = "G♯/A♭5", pitchClass = G, natural = False } + , { note = A6, label = "A6", pitchClass = A, natural = True } + , { note = A_sharp6, label = "A♯/B♭6", pitchClass = A_sharp, natural = False } + , { note = B6, label = "B6", pitchClass = B, natural = True } + , { note = C6, label = "C6", pitchClass = C, natural = True } + , { note = C_sharp6, label = "C♯/D♭6", pitchClass = C_sharp, natural = False } + , { note = D6, label = "D6", pitchClass = D, natural = True } + , { note = D_sharp6, label = "D♯/E♭6", pitchClass = D_sharp, natural = False } + , { note = E6, label = "E6", pitchClass = E, natural = True } + , { note = F6, label = "F6", pitchClass = F, natural = True } + , { note = F_sharp6, label = "F♯/G♭6", pitchClass = F_sharp, natural = False } + , { note = G6, label = "G6", pitchClass = G, natural = True } + , { note = G_sharp6, label = "G♯/A♭6", pitchClass = G, natural = False } + , { note = A7, label = "A7", pitchClass = A, natural = True } + , { note = A_sharp7, label = "A♯/B♭7", pitchClass = A_sharp, natural = False } + , { note = B7, label = "B7", pitchClass = B, natural = True } + , { note = C7, label = "C7", pitchClass = C, natural = True } + , { note = C_sharp7, label = "C♯/D♭7", pitchClass = C_sharp, natural = False } + , { note = D7, label = "D7", pitchClass = D, natural = True } + , { note = D_sharp7, label = "D♯/E♭7", pitchClass = D_sharp, natural = False } + , { note = E7, label = "E7", pitchClass = E, natural = True } + , { note = F7, label = "F7", pitchClass = F, natural = True } + , { note = F_sharp7, label = "F♯/G♭7", pitchClass = F_sharp, natural = False } + , { note = G7, label = "G7", pitchClass = G, natural = True } + , { note = G_sharp7, label = "G♯/A♭7", pitchClass = G, natural = False } + , { note = C8, label = "C8", pitchClass = C, natural = True } ] @@ -1106,10 +1112,10 @@ chordWithinRange start end chord = False -{-| Return a list of all of the chords that we know about. +{-| Return a list of all of the pitch classes that we know about. -} -allNoteClasses : List NoteClass -allNoteClasses = +allPitchClasses : List PitchClass +allPitchClasses = [ C , C_sharp , D @@ -1134,14 +1140,14 @@ allChords : , end : Note , inversions : List ChordInversion , chordTypes : List ChordType - , noteClasses : List NoteClass + , pitchClasses : List PitchClass } -> List Chord -allChords { start, end, inversions, chordTypes, noteClasses } = +allChords { start, end, inversions, chordTypes, pitchClasses } = let notes = notesFromRange start end - |> List.filter (\note -> List.member (classifyNote note) noteClasses) + |> List.filter (\note -> List.member (classifyNote note) pitchClasses) in notes |> List.Extra.andThen @@ -1163,28 +1169,25 @@ allChords { start, end, inversions, chordTypes, noteClasses } = |> List.filter (chordWithinRange start end) -{-| Serialize a human-readable format of `note`. +{-| Return a human-readable format of `note`. -} viewNote : Note -> String viewNote note = note |> getNoteMetadata |> .label -inspectChord : Chord -> String -inspectChord { note, chordType, chordInversion } = - viewNote note ++ " " ++ chordTypeName chordType ++ " " ++ inversionName chordInversion ++ " position" - - +{-| Return a human-readable format of `chord`. +-} viewChord : Chord -> String viewChord { note, chordType, chordInversion } = - viewNoteClass (classifyNote note) ++ " " ++ chordTypeName chordType ++ " " ++ inversionName chordInversion ++ " position" + viewPitchClass (classifyNote note) ++ " " ++ chordTypeName chordType ++ " " ++ inversionName chordInversion ++ " position" -{-| Serialize a human-readable format of `noteClass`. +{-| Return a human-readable format of `pitchClass`. -} -viewNoteClass : NoteClass -> String -viewNoteClass noteClass = - case noteClass of +viewPitchClass : PitchClass -> String +viewPitchClass pitchClass = + case pitchClass of C -> "C"