about summary refs log tree commit diff
path: root/website/sandbox/chord-drill-sergeant/src/Theory.elm
diff options
context:
space:
mode:
authorWilliam Carroll <wpcarro@gmail.com>2020-04-13T14·07+0100
committerWilliam Carroll <wpcarro@gmail.com>2020-04-13T14·46+0100
commita64601cc058950d094a1daa512c94d91d11756cf (patch)
tree1fbe488a6c461668235ef1bf0cece6ac7ad39a2f /website/sandbox/chord-drill-sergeant/src/Theory.elm
parent6a3af6c9c61a8237dfee96c3eb5ce8f9cb2bc0d8 (diff)
Support generating chords for a particular key
Generate chords for a given key.

I believe my Theory.allChords function is taking a long time to generate all of
the chord possibilities. I would like to profile this to verify this
assumption. I think I can create a "staging area" for changes and only
regenerate chords when "committing" the options from the "staging area". This
should stress the application less.

TODO: Profile application to find bottleneck.
Diffstat (limited to 'website/sandbox/chord-drill-sergeant/src/Theory.elm')
-rw-r--r--website/sandbox/chord-drill-sergeant/src/Theory.elm399
1 files changed, 137 insertions, 262 deletions
diff --git a/website/sandbox/chord-drill-sergeant/src/Theory.elm b/website/sandbox/chord-drill-sergeant/src/Theory.elm
index 63cba0e317af..4f89b8c38ffc 100644
--- a/website/sandbox/chord-drill-sergeant/src/Theory.elm
+++ b/website/sandbox/chord-drill-sergeant/src/Theory.elm
@@ -1,6 +1,7 @@
 module Theory exposing (..)
 
 import Array exposing (Array)
+import Dict exposing (Dict)
 import List.Extra
 import Maybe.Extra
 import Misc
@@ -230,11 +231,10 @@ type alias NoteMetadata =
     }
 
 
-scaleDegree : Int -> Key -> PitchClass
-scaleDegree which { pitchClass } =
-    case pitchClass of
-        _ ->
-            C
+{-| An integer representing which note in a given scale to play.
+-}
+type alias ScaleDegree =
+    Int
 
 
 {-| Returns the Note in the cental octave of the piano for a given
@@ -373,16 +373,16 @@ intervalsForMode mode =
     in
     case mode of
         MajorMode ->
-            List.map up [ Whole, Whole, Half, Whole, Whole, Whole, Half ]
+            List.map up [ Whole, Whole, Half, Whole, Whole, Whole ]
 
         MinorMode ->
-            List.map up [ Whole, Half, Whole, Whole, Half, Whole, Whole ]
+            List.map up [ Whole, Half, Whole, Whole, Half, Whole ]
 
         BluesMode ->
             List.map up [ MinorThird, Whole, Half, Half, MinorThird ]
 
 
-{-| Return a list of the intervals the comprise a chord. Each interval measures
+{-| Return a list of the intervals that a chord. Each interval measures
 the distance away from the root-note of the chord.
 -}
 intervalsForChordType : ChordType -> ChordInversion -> List IntervalVector
@@ -648,7 +648,7 @@ notesForChord { note, chordType, chordInversion } =
         |> Maybe.map (\notes -> note :: notes)
 
 
-{-| Return the scale for a given `key`
+{-| Return the scale for a given `key`.
 -}
 notesForKey : Key -> List Note
 notesForKey { pitchClass, mode } =
@@ -718,6 +718,31 @@ allChordTypes =
     ]
 
 
+{-| Return a list of all of the key modes about which we know.
+-}
+allModes : List Mode
+allModes =
+    [ MajorMode, MinorMode, BluesMode ]
+
+
+{-| Return a list of all of the keys about which we know.
+-}
+allKeys : List Key
+allKeys =
+    allPitchClasses
+        |> List.Extra.andThen
+            (\pitchClass ->
+                allModes
+                    |> List.Extra.andThen
+                        (\mode ->
+                            [ { pitchClass = pitchClass
+                              , mode = mode
+                              }
+                            ]
+                        )
+            )
+
+
 {-| 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.
@@ -832,261 +857,19 @@ notes.
 -}
 noteAsNumber : Note -> Int
 noteAsNumber note =
-    case note of
-        C1 ->
+    let
+        result =
+            noteMetadata
+                |> Array.toList
+                |> List.indexedMap Tuple.pair
+                |> Misc.find (\( _, x ) -> x.note == note)
+    in
+    case result of
+        Nothing ->
             0
 
-        C_sharp1 ->
-            1
-
-        D1 ->
-            2
-
-        D_sharp1 ->
-            3
-
-        E1 ->
-            4
-
-        F1 ->
-            5
-
-        F_sharp1 ->
-            6
-
-        G1 ->
-            7
-
-        G_sharp1 ->
-            8
-
-        A1 ->
-            9
-
-        A_sharp1 ->
-            10
-
-        B1 ->
-            11
-
-        C2 ->
-            12
-
-        C_sharp2 ->
-            13
-
-        D2 ->
-            14
-
-        D_sharp2 ->
-            15
-
-        E2 ->
-            16
-
-        F2 ->
-            17
-
-        F_sharp2 ->
-            18
-
-        G2 ->
-            19
-
-        G_sharp2 ->
-            20
-
-        A2 ->
-            21
-
-        A_sharp2 ->
-            22
-
-        B2 ->
-            23
-
-        C3 ->
-            24
-
-        C_sharp3 ->
-            25
-
-        D3 ->
-            26
-
-        D_sharp3 ->
-            27
-
-        E3 ->
-            28
-
-        F3 ->
-            29
-
-        F_sharp3 ->
-            30
-
-        G3 ->
-            31
-
-        G_sharp3 ->
-            32
-
-        A3 ->
-            33
-
-        A_sharp3 ->
-            34
-
-        B3 ->
-            35
-
-        C4 ->
-            36
-
-        C_sharp4 ->
-            37
-
-        D4 ->
-            38
-
-        D_sharp4 ->
-            39
-
-        E4 ->
-            40
-
-        F4 ->
-            41
-
-        F_sharp4 ->
-            42
-
-        G4 ->
-            43
-
-        G_sharp4 ->
-            44
-
-        A4 ->
-            45
-
-        A_sharp4 ->
-            46
-
-        B4 ->
-            47
-
-        C5 ->
-            48
-
-        C_sharp5 ->
-            49
-
-        D5 ->
-            50
-
-        D_sharp5 ->
-            51
-
-        E5 ->
-            52
-
-        F5 ->
-            53
-
-        F_sharp5 ->
-            54
-
-        G5 ->
-            55
-
-        G_sharp5 ->
-            56
-
-        A5 ->
-            57
-
-        A_sharp5 ->
-            58
-
-        B5 ->
-            59
-
-        C6 ->
-            60
-
-        C_sharp6 ->
-            61
-
-        D6 ->
-            62
-
-        D_sharp6 ->
-            63
-
-        E6 ->
-            64
-
-        F6 ->
-            65
-
-        F_sharp6 ->
-            66
-
-        G6 ->
-            67
-
-        G_sharp6 ->
-            68
-
-        A6 ->
-            69
-
-        A_sharp6 ->
-            70
-
-        B6 ->
-            71
-
-        C7 ->
-            72
-
-        C_sharp7 ->
-            73
-
-        D7 ->
-            74
-
-        D_sharp7 ->
-            75
-
-        E7 ->
-            76
-
-        F7 ->
-            77
-
-        F_sharp7 ->
-            78
-
-        G7 ->
-            79
-
-        G_sharp7 ->
-            80
-
-        A7 ->
-            81
-
-        A_sharp7 ->
-            82
-
-        B7 ->
-            83
-
-        C8 ->
-            84
+        Just ( i, _ ) ->
+            i
 
 
 {-| Return true if all of the notes that comprise `chord` can be played on a
@@ -1223,3 +1006,95 @@ viewPitchClass pitchClass =
 
         B ->
             "B"
+
+
+viewMode : Mode -> String
+viewMode mode =
+    case mode of
+        MajorMode ->
+            "major"
+
+        MinorMode ->
+            "minor"
+
+        BluesMode ->
+            "blues"
+
+
+{-| Return the human-readable format of `key`.
+-}
+viewKey : Key -> String
+viewKey { pitchClass, mode } =
+    viewPitchClass pitchClass ++ " " ++ viewMode mode
+
+
+{-| Returns a pairing of a scale-degree to the type of chord at that scale
+degree.
+-}
+practiceChordsForMode : Mode -> Dict ScaleDegree ChordType
+practiceChordsForMode mode =
+    case mode of
+        MajorMode ->
+            Dict.fromList
+                [ ( 1, Major )
+                , ( 2, Minor )
+                , ( 3, Minor )
+                , ( 4, Major )
+                , ( 5, Major )
+                , ( 6, Minor )
+                , ( 7, Diminished )
+                ]
+
+        MinorMode ->
+            Dict.fromList
+                [ ( 1, Minor )
+                , ( 2, Diminished )
+                , ( 3, Major )
+                , ( 4, Minor )
+                , ( 5, Minor )
+                , ( 6, Major )
+                , ( 7, Major )
+                ]
+
+        BluesMode ->
+            Dict.fromList
+                [ ( 1, MajorDominant7 )
+
+                -- While many refer to the blues progression as a I-IV-V, the IV
+                -- chord is really a MajorDominant7 made from the third scale
+                -- degree.
+                , ( 3, MajorDominant7 )
+                , ( 5, MajorDominant7 )
+                ]
+
+
+{-| Returns a list of chords for a particular `key`.
+-}
+chordsForKey : Key -> List Chord
+chordsForKey key =
+    let
+        chords =
+            practiceChordsForMode key.mode
+    in
+    notesForKey key
+        |> List.indexedMap
+            (\i note ->
+                case Dict.get (i + 1) chords of
+                    Nothing ->
+                        Nothing
+
+                    Just chordType ->
+                        Just
+                            (allInversions
+                                |> List.Extra.andThen
+                                    (\inversion ->
+                                        [ { note = note
+                                          , chordType = chordType
+                                          , chordInversion = inversion
+                                          }
+                                        ]
+                                    )
+                            )
+            )
+        |> Maybe.Extra.values
+        |> List.concat