unmed2-0.0: src/MEDTempo.hs
module MEDTempo (
MEDTempo(..),
Mode(..),
song0Tempo,
song2Tempo,
update,
toTime,
) where
import MEDBlock (Cmd, Val)
import qualified MMD0Song
import qualified MMD2Song
import Amiga
import Data.Bits (testBit, (.&.))
data MEDTempo = MEDTempo
{ mode :: Mode,
primary, secondary :: Int
}
data Mode = Speed | BPM {linesPerBeat :: Int}
tempoMode :: UBYTE -> Mode
tempoMode flags =
if testBit flags 5
then BPM $ fromIntegral (flags .&. 0x1F) + 1
else Speed
song0Tempo :: MMD0Song.MMD0Song -> MEDTempo
song0Tempo song =
MEDTempo
{ mode = tempoMode $ MMD0Song.flags2 song
, primary = fromIntegral $ MMD0Song.deftempo song
, secondary = fromIntegral $ MMD0Song.tempo2 song
}
song2Tempo :: MMD2Song.MMD2Song -> MEDTempo
song2Tempo song =
MEDTempo
{ mode = tempoMode $ MMD2Song.flags2 song
, primary = fromIntegral $ MMD2Song.deftempo song
, secondary = fromIntegral $ MMD2Song.tempo2 song
}
{- |
Interpret tempo related commands.
-}
update :: MEDTempo -> (Cmd, Val) -> MEDTempo
update tempo (cmd,val) =
case cmd of
0x09 -> tempo{secondary = max 1 $ fromIntegral val}
0x0F ->
if 0 < val && val < 0xF0
then tempo{primary = fromIntegral val}
else tempo
_ -> tempo
toTime :: Fractional a => MEDTempo -> a
toTime (MEDTempo mode_ tempo1 tempo2) =
timeFromPrimary mode_ tempo1 * fromIntegral tempo2
-- numbers taken from uade/amigasrc/players/med/common/proplayer.a
ciabFreq :: Fractional a => a
ciabFreq = 715909
timerDiv :: Fractional a => a
timerDiv = 474326
sttempo :: Fractional a => a
sttempo = 2416.3
timeFromPrimary :: Fractional a => Mode -> Int -> a
timeFromPrimary mode_ tempo =
case mode_ of
BPM lpb -> 60 / (fromIntegral tempo * 6 * fromIntegral lpb)
Speed ->
if tempo<=10
then fromIntegral tempo * sttempo / ciabFreq
else timerDiv / (ciabFreq * fromIntegral tempo)