about summary refs log tree commit diff
diff options
context:
space:
mode:
authorWilliam Carroll <wpcarro@gmail.com>2020-04-11T16·46+0100
committerWilliam Carroll <wpcarro@gmail.com>2020-04-11T16·46+0100
commitc24c9b7fb940793ef75fa61d00abb31c3d56f94b (patch)
tree2a55a46e1d3efc3a6db0faf55a91b363e7c6faec
parente864074600bddf14c6f75bdd683d794705b22367 (diff)
Support BPM for tempo
Using BPM as the unit for tempo.

TODO: Consider a higher-fidelity way to calculate BPM, although I'm not sure
this is critical functionality; an interesting problem is just seducing me, and
this app would be better off resisting the temptation.
-rw-r--r--website/sandbox/chord-drill-sergeant/src/Main.elm38
-rw-r--r--website/sandbox/chord-drill-sergeant/src/Tempo.elm22
2 files changed, 50 insertions, 10 deletions
diff --git a/website/sandbox/chord-drill-sergeant/src/Main.elm b/website/sandbox/chord-drill-sergeant/src/Main.elm
index 3f1168b533a0..8a606767bb69 100644
--- a/website/sandbox/chord-drill-sergeant/src/Main.elm
+++ b/website/sandbox/chord-drill-sergeant/src/Main.elm
@@ -10,6 +10,7 @@ import Time exposing (..)
 
 import Piano
 import Theory
+import Tempo
 
 type alias Model =
   { whitelistedChords : List Theory.Chord
@@ -24,9 +25,18 @@ type Msg = NextChord
          | Pause
          | IncreaseTempo
          | DecreaseTempo
+         | SetTempo String
 
 tempoStep : Int
-tempoStep = 100
+tempoStep = 5
+
+{-| Return the number of milliseconds that elapse during an interval in a
+`target` bpm.
+-}
+bpmToMilliseconds : Int -> Int
+bpmToMilliseconds target =
+  let msPerMinute = 1000 * 60
+  in round (toFloat msPerMinute / toFloat target)
 
 viewChord : Theory.Chord -> String
 viewChord {note, chordType, chordPosition} =
@@ -78,7 +88,7 @@ init =
   { whitelistedChords = Theory.allChords
   , selectedChord = cmajor
   , isPaused = True
-  , tempo = 1000
+  , tempo = 60
   }
 
 subscriptions : Model -> Sub Msg
@@ -86,7 +96,7 @@ subscriptions {isPaused, tempo} =
   if isPaused then
     Sub.none
   else
-    Time.every (toFloat tempo) (\_ -> NextChord)
+    Time.every (tempo |> bpmToMilliseconds |> toFloat) (\_ -> NextChord)
 
 {-| Now that we have state, we need a function to change the state. -}
 update : Msg -> Model -> (Model, Cmd Msg)
@@ -108,12 +118,19 @@ update msg model =
     Pause -> ( { model | isPaused = True }
              , Cmd.none
              )
-    IncreaseTempo -> ( { model | tempo = model.tempo - tempoStep }
+    IncreaseTempo -> ( { model | tempo = model.tempo + tempoStep }
                      , Cmd.none
                      )
-    DecreaseTempo -> ( { model | tempo = model.tempo + tempoStep }
+    DecreaseTempo -> ( { model | tempo = model.tempo - tempoStep }
                      , Cmd.none
                      )
+    SetTempo tempo -> ( { model |
+                          tempo = case String.toInt tempo of
+                                    Just x  -> x
+                                    Nothing -> model.tempo
+                         }
+                      , Cmd.none
+                      )
 
 playPause : Model -> Html Msg
 playPause {isPaused} =
@@ -124,12 +141,13 @@ playPause {isPaused} =
 
 view : Model -> Html Msg
 view model =
-  div [] [ p [] [ text (viewChord model.selectedChord) ]
-         , p [] [ text (String.fromInt model.tempo) ]
-         , button [ onClick NextChord ] [ text "Next Chord" ]
-         , button [ onClick IncreaseTempo ] [ text "Faster" ]
-         , button [ onClick DecreaseTempo ] [ text "Slower" ]
+  div [] [ Tempo.render { tempo = model.tempo
+                        , handleIncrease = IncreaseTempo
+                        , handleDecrease = DecreaseTempo
+                        , handleInput    = SetTempo
+                        }
          , playPause model
+         , p [] [ text (viewChord model.selectedChord) ]
          , Piano.render { highlight = Theory.notesForChord model.selectedChord }
          ]
 
diff --git a/website/sandbox/chord-drill-sergeant/src/Tempo.elm b/website/sandbox/chord-drill-sergeant/src/Tempo.elm
new file mode 100644
index 000000000000..de4fa32795f9
--- /dev/null
+++ b/website/sandbox/chord-drill-sergeant/src/Tempo.elm
@@ -0,0 +1,22 @@
+module Tempo exposing (render)
+
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (..)
+
+type alias Props msg =
+  { tempo : Int
+  , handleIncrease : msg
+  , handleDecrease : msg
+  , handleInput : String -> msg
+  }
+
+render : Props msg -> Html msg
+render {tempo, handleIncrease, handleDecrease, handleInput} =
+  div [] [ p [] [ text ((String.fromInt tempo) ++ " BPM") ]
+         , button [ onClick handleDecrease ] [ text "Slower" ]
+         , input [ onInput handleInput
+                 , placeholder "Set tempo..."
+                 ] []
+         , button [ onClick handleIncrease ] [ text "Faster" ]
+         ]