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.
This commit is contained in:
		
							parent
							
								
									6a3af6c9c6
								
							
						
					
					
						commit
						a64601cc05
					
				
					 4 changed files with 283 additions and 285 deletions
				
			
		| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
module ChordInspector exposing (render)
 | 
					module ChordInspector exposing (render)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Html exposing (..)
 | 
					import Html exposing (..)
 | 
				
			||||||
 | 
					import NoteInspector
 | 
				
			||||||
import Theory
 | 
					import Theory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,15 +12,4 @@ render chord =
 | 
				
			||||||
            p [] [ text "Cannot retrieve the notes for the chord." ]
 | 
					            p [] [ text "Cannot retrieve the notes for the chord." ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Just notes ->
 | 
					        Just notes ->
 | 
				
			||||||
            ul []
 | 
					            NoteInspector.render notes
 | 
				
			||||||
                (notes
 | 
					 | 
				
			||||||
                    |> List.map
 | 
					 | 
				
			||||||
                        (\note ->
 | 
					 | 
				
			||||||
                            li []
 | 
					 | 
				
			||||||
                                [ text
 | 
					 | 
				
			||||||
                                    (Theory.viewNote
 | 
					 | 
				
			||||||
                                        note
 | 
					 | 
				
			||||||
                                    )
 | 
					 | 
				
			||||||
                                ]
 | 
					 | 
				
			||||||
                        )
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ import ChordInspector
 | 
				
			||||||
import Html exposing (..)
 | 
					import Html exposing (..)
 | 
				
			||||||
import Html.Attributes exposing (..)
 | 
					import Html.Attributes exposing (..)
 | 
				
			||||||
import Html.Events exposing (..)
 | 
					import Html.Events exposing (..)
 | 
				
			||||||
 | 
					import NoteInspector
 | 
				
			||||||
import Piano
 | 
					import Piano
 | 
				
			||||||
import Random
 | 
					import Random
 | 
				
			||||||
import Random.List
 | 
					import Random.List
 | 
				
			||||||
| 
						 | 
					@ -18,11 +19,13 @@ type alias Model =
 | 
				
			||||||
    , whitelistedChordTypes : List Theory.ChordType
 | 
					    , whitelistedChordTypes : List Theory.ChordType
 | 
				
			||||||
    , whitelistedInversions : List Theory.ChordInversion
 | 
					    , whitelistedInversions : List Theory.ChordInversion
 | 
				
			||||||
    , whitelistedPitchClasses : List Theory.PitchClass
 | 
					    , whitelistedPitchClasses : List Theory.PitchClass
 | 
				
			||||||
 | 
					    , whitelistedKeys : List Theory.Key
 | 
				
			||||||
    , selectedChord : Maybe Theory.Chord
 | 
					    , selectedChord : Maybe Theory.Chord
 | 
				
			||||||
    , isPaused : Bool
 | 
					    , isPaused : Bool
 | 
				
			||||||
    , tempo : Int
 | 
					    , tempo : Int
 | 
				
			||||||
    , firstNote : Theory.Note
 | 
					    , firstNote : Theory.Note
 | 
				
			||||||
    , lastNote : Theory.Note
 | 
					    , lastNote : Theory.Note
 | 
				
			||||||
 | 
					    , practiceMode : PracticeMode
 | 
				
			||||||
    , debug :
 | 
					    , debug :
 | 
				
			||||||
        { enable : Bool
 | 
					        { enable : Bool
 | 
				
			||||||
        , inspectChord : Bool
 | 
					        , inspectChord : Bool
 | 
				
			||||||
| 
						 | 
					@ -30,6 +33,13 @@ type alias Model =
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Control the type of practice you'd like.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					type PracticeMode
 | 
				
			||||||
 | 
					    = KeyMode
 | 
				
			||||||
 | 
					    | FineTuneMode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Msg
 | 
					type Msg
 | 
				
			||||||
    = NextChord
 | 
					    = NextChord
 | 
				
			||||||
    | NewChord Theory.Chord
 | 
					    | NewChord Theory.Chord
 | 
				
			||||||
| 
						 | 
					@ -42,7 +52,11 @@ type Msg
 | 
				
			||||||
    | ToggleInversion Theory.ChordInversion
 | 
					    | ToggleInversion Theory.ChordInversion
 | 
				
			||||||
    | ToggleChordType Theory.ChordType
 | 
					    | ToggleChordType Theory.ChordType
 | 
				
			||||||
    | TogglePitchClass Theory.PitchClass
 | 
					    | TogglePitchClass Theory.PitchClass
 | 
				
			||||||
 | 
					    | ToggleKey Theory.Key
 | 
				
			||||||
    | DoNothing
 | 
					    | DoNothing
 | 
				
			||||||
 | 
					    | SetPracticeMode PracticeMode
 | 
				
			||||||
 | 
					    | SelectAllKeys
 | 
				
			||||||
 | 
					    | DeselectAllKeys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{-| The amount by which we increase or decrease tempo.
 | 
					{-| The amount by which we increase or decrease tempo.
 | 
				
			||||||
| 
						 | 
					@ -80,18 +94,31 @@ init =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pitchClasses =
 | 
					        pitchClasses =
 | 
				
			||||||
            Theory.allPitchClasses
 | 
					            Theory.allPitchClasses
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        keys =
 | 
				
			||||||
 | 
					            Theory.allKeys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        practiceMode =
 | 
				
			||||||
 | 
					            KeyMode
 | 
				
			||||||
    in
 | 
					    in
 | 
				
			||||||
    { whitelistedChords =
 | 
					    { practiceMode = practiceMode
 | 
				
			||||||
        Theory.allChords
 | 
					    , whitelistedChords =
 | 
				
			||||||
            { start = firstNote
 | 
					        case practiceMode of
 | 
				
			||||||
            , end = lastNote
 | 
					            KeyMode ->
 | 
				
			||||||
            , inversions = inversions
 | 
					                keys |> List.concatMap Theory.chordsForKey
 | 
				
			||||||
            , chordTypes = chordTypes
 | 
					
 | 
				
			||||||
            , pitchClasses = pitchClasses
 | 
					            FineTuneMode ->
 | 
				
			||||||
            }
 | 
					                Theory.allChords
 | 
				
			||||||
 | 
					                    { start = firstNote
 | 
				
			||||||
 | 
					                    , end = lastNote
 | 
				
			||||||
 | 
					                    , inversions = inversions
 | 
				
			||||||
 | 
					                    , chordTypes = chordTypes
 | 
				
			||||||
 | 
					                    , pitchClasses = pitchClasses
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
    , whitelistedChordTypes = chordTypes
 | 
					    , whitelistedChordTypes = chordTypes
 | 
				
			||||||
    , whitelistedInversions = inversions
 | 
					    , whitelistedInversions = inversions
 | 
				
			||||||
    , whitelistedPitchClasses = pitchClasses
 | 
					    , whitelistedPitchClasses = pitchClasses
 | 
				
			||||||
 | 
					    , whitelistedKeys = keys
 | 
				
			||||||
    , selectedChord = Nothing
 | 
					    , selectedChord = Nothing
 | 
				
			||||||
    , isPaused = True
 | 
					    , isPaused = True
 | 
				
			||||||
    , tempo = 60
 | 
					    , tempo = 60
 | 
				
			||||||
| 
						 | 
					@ -121,6 +148,31 @@ update msg model =
 | 
				
			||||||
        DoNothing ->
 | 
					        DoNothing ->
 | 
				
			||||||
            ( model, Cmd.none )
 | 
					            ( model, Cmd.none )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SetPracticeMode practiceMode ->
 | 
				
			||||||
 | 
					            ( { model
 | 
				
			||||||
 | 
					                | practiceMode = practiceMode
 | 
				
			||||||
 | 
					                , isPaused = True
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            , Cmd.none
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SelectAllKeys ->
 | 
				
			||||||
 | 
					            ( { model
 | 
				
			||||||
 | 
					                | whitelistedKeys = Theory.allKeys
 | 
				
			||||||
 | 
					                , whitelistedChords =
 | 
				
			||||||
 | 
					                    Theory.allKeys |> List.concatMap Theory.chordsForKey
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            , Cmd.none
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        DeselectAllKeys ->
 | 
				
			||||||
 | 
					            ( { model
 | 
				
			||||||
 | 
					                | whitelistedKeys = []
 | 
				
			||||||
 | 
					                , whitelistedChords = []
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            , Cmd.none
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        NewChord chord ->
 | 
					        NewChord chord ->
 | 
				
			||||||
            ( { model | selectedChord = Just chord }
 | 
					            ( { model | selectedChord = Just chord }
 | 
				
			||||||
            , Cmd.none
 | 
					            , Cmd.none
 | 
				
			||||||
| 
						 | 
					@ -239,6 +291,23 @@ update msg model =
 | 
				
			||||||
            , Cmd.none
 | 
					            , Cmd.none
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ToggleKey key ->
 | 
				
			||||||
 | 
					            let
 | 
				
			||||||
 | 
					                keys =
 | 
				
			||||||
 | 
					                    if List.member key model.whitelistedKeys then
 | 
				
			||||||
 | 
					                        List.filter ((/=) key) model.whitelistedKeys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                        key :: model.whitelistedKeys
 | 
				
			||||||
 | 
					            in
 | 
				
			||||||
 | 
					            ( { model
 | 
				
			||||||
 | 
					                | whitelistedKeys = keys
 | 
				
			||||||
 | 
					                , whitelistedChords =
 | 
				
			||||||
 | 
					                    keys |> List.concatMap Theory.chordsForKey
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            , Cmd.none
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SetTempo tempo ->
 | 
					        SetTempo tempo ->
 | 
				
			||||||
            ( { model
 | 
					            ( { model
 | 
				
			||||||
                | tempo =
 | 
					                | tempo =
 | 
				
			||||||
| 
						 | 
					@ -327,6 +396,30 @@ inversionCheckboxes inversions =
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					keyCheckboxes : List Theory.Key -> Html Msg
 | 
				
			||||||
 | 
					keyCheckboxes keys =
 | 
				
			||||||
 | 
					    div []
 | 
				
			||||||
 | 
					        [ h2 [] [ text "Choose Key" ]
 | 
				
			||||||
 | 
					        , button [ onClick SelectAllKeys ] [ text "Select all" ]
 | 
				
			||||||
 | 
					        , button [ onClick DeselectAllKeys ] [ text "Deselect all" ]
 | 
				
			||||||
 | 
					        , ul []
 | 
				
			||||||
 | 
					            (Theory.allKeys
 | 
				
			||||||
 | 
					                |> List.map
 | 
				
			||||||
 | 
					                    (\key ->
 | 
				
			||||||
 | 
					                        li []
 | 
				
			||||||
 | 
					                            [ label [] [ text (Theory.viewKey key) ]
 | 
				
			||||||
 | 
					                            , input
 | 
				
			||||||
 | 
					                                [ type_ "checkbox"
 | 
				
			||||||
 | 
					                                , onClick (ToggleKey key)
 | 
				
			||||||
 | 
					                                , checked (List.member key keys)
 | 
				
			||||||
 | 
					                                ]
 | 
				
			||||||
 | 
					                                []
 | 
				
			||||||
 | 
					                            ]
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
displayChord :
 | 
					displayChord :
 | 
				
			||||||
    { debug : Bool
 | 
					    { debug : Bool
 | 
				
			||||||
    , chord : Theory.Chord
 | 
					    , chord : Theory.Chord
 | 
				
			||||||
| 
						 | 
					@ -364,9 +457,37 @@ view model =
 | 
				
			||||||
            , handleDecrease = DecreaseTempo
 | 
					            , handleDecrease = DecreaseTempo
 | 
				
			||||||
            , handleInput = SetTempo
 | 
					            , handleInput = SetTempo
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        , pitchClassCheckboxes model.whitelistedPitchClasses
 | 
					        , div []
 | 
				
			||||||
        , inversionCheckboxes model.whitelistedInversions
 | 
					            [ h2 [] [ text "Practice Mode" ]
 | 
				
			||||||
        , chordTypeCheckboxes model.whitelistedChordTypes
 | 
					            , input
 | 
				
			||||||
 | 
					                [ type_ "radio"
 | 
				
			||||||
 | 
					                , id "key-mode"
 | 
				
			||||||
 | 
					                , name "key-mode"
 | 
				
			||||||
 | 
					                , checked (model.practiceMode == KeyMode)
 | 
				
			||||||
 | 
					                , onClick (SetPracticeMode KeyMode)
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					                []
 | 
				
			||||||
 | 
					            , label [ for "key-mode" ] [ text "Key Mode" ]
 | 
				
			||||||
 | 
					            , input
 | 
				
			||||||
 | 
					                [ type_ "radio"
 | 
				
			||||||
 | 
					                , id "fine-tune-mode"
 | 
				
			||||||
 | 
					                , name "fine-tune-mode"
 | 
				
			||||||
 | 
					                , checked (model.practiceMode == FineTuneMode)
 | 
				
			||||||
 | 
					                , onClick (SetPracticeMode FineTuneMode)
 | 
				
			||||||
 | 
					                ]
 | 
				
			||||||
 | 
					                []
 | 
				
			||||||
 | 
					            , label [ for "fine-tune-mode" ] [ text "Fine-tuning Mode" ]
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        , case model.practiceMode of
 | 
				
			||||||
 | 
					            KeyMode ->
 | 
				
			||||||
 | 
					                keyCheckboxes model.whitelistedKeys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            FineTuneMode ->
 | 
				
			||||||
 | 
					                div []
 | 
				
			||||||
 | 
					                    [ pitchClassCheckboxes model.whitelistedPitchClasses
 | 
				
			||||||
 | 
					                    , inversionCheckboxes model.whitelistedInversions
 | 
				
			||||||
 | 
					                    , chordTypeCheckboxes model.whitelistedChordTypes
 | 
				
			||||||
 | 
					                    ]
 | 
				
			||||||
        , playPause model
 | 
					        , playPause model
 | 
				
			||||||
        , if model.debug.enable then
 | 
					        , if model.debug.enable then
 | 
				
			||||||
            debugger
 | 
					            debugger
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,7 @@
 | 
				
			||||||
module Misc exposing (..)
 | 
					module Misc exposing (..)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Array exposing (Array)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
comesAfter : a -> List a -> Maybe a
 | 
					comesAfter : a -> List a -> Maybe a
 | 
				
			||||||
comesAfter x xs =
 | 
					comesAfter x xs =
 | 
				
			||||||
| 
						 | 
					@ -33,3 +35,13 @@ comesBefore x xs =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                comesBefore x (z :: rest)
 | 
					                comesBefore x (z :: rest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					find : (a -> Bool) -> List a -> Maybe a
 | 
				
			||||||
 | 
					find pred xs =
 | 
				
			||||||
 | 
					    case xs |> List.filter pred of
 | 
				
			||||||
 | 
					        [] ->
 | 
				
			||||||
 | 
					            Nothing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        x :: _ ->
 | 
				
			||||||
 | 
					            Just x
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
module Theory exposing (..)
 | 
					module Theory exposing (..)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Array exposing (Array)
 | 
					import Array exposing (Array)
 | 
				
			||||||
 | 
					import Dict exposing (Dict)
 | 
				
			||||||
import List.Extra
 | 
					import List.Extra
 | 
				
			||||||
import Maybe.Extra
 | 
					import Maybe.Extra
 | 
				
			||||||
import Misc
 | 
					import Misc
 | 
				
			||||||
| 
						 | 
					@ -230,11 +231,10 @@ type alias NoteMetadata =
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
scaleDegree : Int -> Key -> PitchClass
 | 
					{-| An integer representing which note in a given scale to play.
 | 
				
			||||||
scaleDegree which { pitchClass } =
 | 
					-}
 | 
				
			||||||
    case pitchClass of
 | 
					type alias ScaleDegree =
 | 
				
			||||||
        _ ->
 | 
					    Int
 | 
				
			||||||
            C
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{-| Returns the Note in the cental octave of the piano for a given
 | 
					{-| Returns the Note in the cental octave of the piano for a given
 | 
				
			||||||
| 
						 | 
					@ -373,16 +373,16 @@ intervalsForMode mode =
 | 
				
			||||||
    in
 | 
					    in
 | 
				
			||||||
    case mode of
 | 
					    case mode of
 | 
				
			||||||
        MajorMode ->
 | 
					        MajorMode ->
 | 
				
			||||||
            List.map up [ Whole, Whole, Half, Whole, Whole, Whole, Half ]
 | 
					            List.map up [ Whole, Whole, Half, Whole, Whole, Whole ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        MinorMode ->
 | 
					        MinorMode ->
 | 
				
			||||||
            List.map up [ Whole, Half, Whole, Whole, Half, Whole, Whole ]
 | 
					            List.map up [ Whole, Half, Whole, Whole, Half, Whole ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        BluesMode ->
 | 
					        BluesMode ->
 | 
				
			||||||
            List.map up [ MinorThird, Whole, Half, Half, MinorThird ]
 | 
					            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.
 | 
					the distance away from the root-note of the chord.
 | 
				
			||||||
-}
 | 
					-}
 | 
				
			||||||
intervalsForChordType : ChordType -> ChordInversion -> List IntervalVector
 | 
					intervalsForChordType : ChordType -> ChordInversion -> List IntervalVector
 | 
				
			||||||
| 
						 | 
					@ -648,7 +648,7 @@ notesForChord { note, chordType, chordInversion } =
 | 
				
			||||||
        |> Maybe.map (\notes -> note :: notes)
 | 
					        |> Maybe.map (\notes -> note :: notes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{-| Return the scale for a given `key`
 | 
					{-| Return the scale for a given `key`.
 | 
				
			||||||
-}
 | 
					-}
 | 
				
			||||||
notesForKey : Key -> List Note
 | 
					notesForKey : Key -> List Note
 | 
				
			||||||
notesForKey { pitchClass, mode } =
 | 
					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.
 | 
					{-| Return an array of every note on a piano.
 | 
				
			||||||
Note: Currently this piano has 85 keys, but modern pianos have 88 keys. I would
 | 
					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.
 | 
					prefer to have 88 keys, but it's not urgent.
 | 
				
			||||||
| 
						 | 
					@ -832,261 +857,19 @@ notes.
 | 
				
			||||||
-}
 | 
					-}
 | 
				
			||||||
noteAsNumber : Note -> Int
 | 
					noteAsNumber : Note -> Int
 | 
				
			||||||
noteAsNumber note =
 | 
					noteAsNumber note =
 | 
				
			||||||
    case note of
 | 
					    let
 | 
				
			||||||
        C1 ->
 | 
					        result =
 | 
				
			||||||
 | 
					            noteMetadata
 | 
				
			||||||
 | 
					                |> Array.toList
 | 
				
			||||||
 | 
					                |> List.indexedMap Tuple.pair
 | 
				
			||||||
 | 
					                |> Misc.find (\( _, x ) -> x.note == note)
 | 
				
			||||||
 | 
					    in
 | 
				
			||||||
 | 
					    case result of
 | 
				
			||||||
 | 
					        Nothing ->
 | 
				
			||||||
            0
 | 
					            0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        C_sharp1 ->
 | 
					        Just ( i, _ ) ->
 | 
				
			||||||
            1
 | 
					            i
 | 
				
			||||||
 | 
					 | 
				
			||||||
        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
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{-| Return true if all of the notes that comprise `chord` can be played on a
 | 
					{-| Return true if all of the notes that comprise `chord` can be played on a
 | 
				
			||||||
| 
						 | 
					@ -1223,3 +1006,95 @@ viewPitchClass pitchClass =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        B ->
 | 
					        B ->
 | 
				
			||||||
            "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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue