module ZMidi.Score.BarBeatPos ( getBeatInBar
, getBarRat
, toRatInBeat
, toBarRat
) where
import ZMidi.Score.Datatypes
import ZMidi.Score.Quantise
import Control.Arrow ( (***) )
import Data.Ratio ( (%) )
getBeatInBar :: TimeSig -> TPB -> Time -> (Bar, Beat, BeatRat)
getBeatInBar NoTimeSig _ _ = error "getBeatInBar applied to noTimeSig"
getBeatInBar (TimeSig num _den _ _) t o =
let (Beat bt, rat) = getRatInBeat t o
(br, bib) = (succ *** succ) $ bt `divMod` num
in (Bar br, Beat bib, rat)
getRatInBeat :: TPB -> Time -> (Beat, BeatRat)
getRatInBeat (TPB t) (Time o) =
((Beat) *** (BeatRat . (% t))) (o `divMod` t)
getBarRat :: TimeSig -> TPB -> Time -> (Bar, BarRat)
getBarRat NoTimeSig _ _ = error "getBeatInBar applied to noTimeSig"
getBarRat (TimeSig num den _ _) (TPB t) (Time o) =
let (bt, rest) = o `divMod` t
(b , bib) = bt `divMod` num
br = ((bib * t) + rest) % (den * t)
in (Bar (succ b), BarRat br)
toRatInBeat :: TimeSig -> BarRat -> (Beat, BeatRat)
toRatInBeat ts br = countBeat (Beat 0, BeatRat . barRat $ br)
where oneBeat = BeatRat (1 % tsNum ts) :: BeatRat
countBeat :: (Beat, BeatRat) -> (Beat, BeatRat)
countBeat (b,x) | rest < 0 = (b,x)
| otherwise = countBeat (succ b, rest)
where rest = x oneBeat
toBarRat :: QBins -> TimeSig -> (Beat, BeatRat) -> BarRat
toBarRat _ NoTimeSig _ = error "toBarRat applied to noTimeSig"
toBarRat q@(QBins x) (TimeSig _n d _ _) (Beat b, BeatRat r) =
BarRat (((pred b * x) + getNumForQBins q r) % (x * d))