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.
This commit is contained in:
parent
e864074600
commit
c24c9b7fb9
2 changed files with 50 additions and 10 deletions
|
@ -10,6 +10,7 @@ import Time exposing (..)
|
||||||
|
|
||||||
import Piano
|
import Piano
|
||||||
import Theory
|
import Theory
|
||||||
|
import Tempo
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ whitelistedChords : List Theory.Chord
|
{ whitelistedChords : List Theory.Chord
|
||||||
|
@ -24,9 +25,18 @@ type Msg = NextChord
|
||||||
| Pause
|
| Pause
|
||||||
| IncreaseTempo
|
| IncreaseTempo
|
||||||
| DecreaseTempo
|
| DecreaseTempo
|
||||||
|
| SetTempo String
|
||||||
|
|
||||||
tempoStep : Int
|
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 : Theory.Chord -> String
|
||||||
viewChord {note, chordType, chordPosition} =
|
viewChord {note, chordType, chordPosition} =
|
||||||
|
@ -78,7 +88,7 @@ init =
|
||||||
{ whitelistedChords = Theory.allChords
|
{ whitelistedChords = Theory.allChords
|
||||||
, selectedChord = cmajor
|
, selectedChord = cmajor
|
||||||
, isPaused = True
|
, isPaused = True
|
||||||
, tempo = 1000
|
, tempo = 60
|
||||||
}
|
}
|
||||||
|
|
||||||
subscriptions : Model -> Sub Msg
|
subscriptions : Model -> Sub Msg
|
||||||
|
@ -86,7 +96,7 @@ subscriptions {isPaused, tempo} =
|
||||||
if isPaused then
|
if isPaused then
|
||||||
Sub.none
|
Sub.none
|
||||||
else
|
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. -}
|
{-| Now that we have state, we need a function to change the state. -}
|
||||||
update : Msg -> Model -> (Model, Cmd Msg)
|
update : Msg -> Model -> (Model, Cmd Msg)
|
||||||
|
@ -108,10 +118,17 @@ update msg model =
|
||||||
Pause -> ( { model | isPaused = True }
|
Pause -> ( { model | isPaused = True }
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
IncreaseTempo -> ( { model | tempo = model.tempo - tempoStep }
|
IncreaseTempo -> ( { model | tempo = model.tempo + tempoStep }
|
||||||
, Cmd.none
|
, 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
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -124,12 +141,13 @@ playPause {isPaused} =
|
||||||
|
|
||||||
view : Model -> Html Msg
|
view : Model -> Html Msg
|
||||||
view model =
|
view model =
|
||||||
div [] [ p [] [ text (viewChord model.selectedChord) ]
|
div [] [ Tempo.render { tempo = model.tempo
|
||||||
, p [] [ text (String.fromInt model.tempo) ]
|
, handleIncrease = IncreaseTempo
|
||||||
, button [ onClick NextChord ] [ text "Next Chord" ]
|
, handleDecrease = DecreaseTempo
|
||||||
, button [ onClick IncreaseTempo ] [ text "Faster" ]
|
, handleInput = SetTempo
|
||||||
, button [ onClick DecreaseTempo ] [ text "Slower" ]
|
}
|
||||||
, playPause model
|
, playPause model
|
||||||
|
, p [] [ text (viewChord model.selectedChord) ]
|
||||||
, Piano.render { highlight = Theory.notesForChord model.selectedChord }
|
, Piano.render { highlight = Theory.notesForChord model.selectedChord }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
22
website/sandbox/chord-drill-sergeant/src/Tempo.elm
Normal file
22
website/sandbox/chord-drill-sergeant/src/Tempo.elm
Normal file
|
@ -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" ]
|
||||||
|
]
|
Loading…
Reference in a new issue