module Sound.MED.Generic.Tempo (
MEDTempo(..),
Mode(..),
song0Tempo,
song2Tempo,
update,
toTime,
) where
import Sound.MED.Generic.Block(Cmd,Val)
import qualified Sound.MED.Raw.MMD0Song as MMD0Song
import qualified Sound.MED.Raw.MMD2Song as MMD2Song
import Sound.MED.Basic.Amiga
import Data.Bits (testBit, (.&.))
import Data.Bool.HT (if')
data MEDTempo = MEDTempo
{ MEDTempo -> Mode
mode :: Mode,
MEDTempo -> Int
primary, MEDTempo -> Int
secondary :: Int
}
data Mode = Speed | Octa | BPM {Mode -> Int
linesPerBeat :: Int}
tempoMode :: UBYTE -> UBYTE -> Mode
tempoMode :: UBYTE -> UBYTE -> Mode
tempoMode UBYTE
flags UBYTE
flags2 =
Bool -> Mode -> Mode -> Mode
forall a. Bool -> a -> a -> a
if' (UBYTE -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit UBYTE
flags Int
6) Mode
Octa (Mode -> Mode) -> Mode -> Mode
forall a b. (a -> b) -> a -> b
$
Bool -> Mode -> Mode -> Mode
forall a. Bool -> a -> a -> a
if' (UBYTE -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit UBYTE
flags2 Int
5) (Int -> Mode
BPM (Int -> Mode) -> Int -> Mode
forall a b. (a -> b) -> a -> b
$ UBYTE -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (UBYTE
flags2 UBYTE -> UBYTE -> UBYTE
forall a. Bits a => a -> a -> a
.&. UBYTE
0x1F) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
Mode
Speed
song0Tempo :: MMD0Song.MMD0Song -> MEDTempo
song0Tempo :: MMD0Song -> MEDTempo
song0Tempo MMD0Song
song =
MEDTempo :: Mode -> Int -> Int -> MEDTempo
MEDTempo
{ mode :: Mode
mode = UBYTE -> UBYTE -> Mode
tempoMode (MMD0Song -> UBYTE
MMD0Song.flags MMD0Song
song) (MMD0Song -> UBYTE
MMD0Song.flags2 MMD0Song
song)
, primary :: Int
primary = UWORD -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (UWORD -> Int) -> UWORD -> Int
forall a b. (a -> b) -> a -> b
$ MMD0Song -> UWORD
MMD0Song.deftempo MMD0Song
song
, secondary :: Int
secondary = UBYTE -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (UBYTE -> Int) -> UBYTE -> Int
forall a b. (a -> b) -> a -> b
$ MMD0Song -> UBYTE
MMD0Song.tempo2 MMD0Song
song
}
song2Tempo :: MMD2Song.MMD2Song -> MEDTempo
song2Tempo :: MMD2Song -> MEDTempo
song2Tempo MMD2Song
song =
MEDTempo :: Mode -> Int -> Int -> MEDTempo
MEDTempo
{ mode :: Mode
mode = UBYTE -> UBYTE -> Mode
tempoMode (MMD2Song -> UBYTE
MMD2Song.flags MMD2Song
song) (MMD2Song -> UBYTE
MMD2Song.flags2 MMD2Song
song)
, primary :: Int
primary = UWORD -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (UWORD -> Int) -> UWORD -> Int
forall a b. (a -> b) -> a -> b
$ MMD2Song -> UWORD
MMD2Song.deftempo MMD2Song
song
, secondary :: Int
secondary = UBYTE -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (UBYTE -> Int) -> UBYTE -> Int
forall a b. (a -> b) -> a -> b
$ MMD2Song -> UBYTE
MMD2Song.tempo2 MMD2Song
song
}
update :: MEDTempo -> (Cmd, Val) -> MEDTempo
update :: MEDTempo -> (Int, Int) -> MEDTempo
update MEDTempo
tempo (Int
cmd,Int
val) =
case Int
cmd of
Int
0x09 -> MEDTempo
tempo{secondary :: Int
secondary = Int -> Int -> Int
forall a. Integral a => a -> a -> a
mod (Int
valInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) Int
0x20 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1}
Int
0x0F ->
if Int
0 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
val Bool -> Bool -> Bool
&& Int
val Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0xF0
then MEDTempo
tempo{primary :: Int
primary = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
val}
else MEDTempo
tempo
Int
_ -> MEDTempo
tempo
toTime :: Fractional a => MEDTempo -> a
toTime :: MEDTempo -> a
toTime (MEDTempo Mode
mode_ Int
tempo1 Int
tempo2) =
Mode -> Int -> a
forall a. Fractional a => Mode -> Int -> a
timeFromPrimary Mode
mode_ Int
tempo1 a -> a -> a
forall a. Num a => a -> a -> a
* Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
tempo2
ciabFreq :: Fractional a => a
ciabFreq :: a
ciabFreq = a
715909
timerDiv :: Fractional a => a
timerDiv :: a
timerDiv = a
474326
_sttempo :: Fractional a => a
_sttempo :: a
_sttempo = a
2416.3
sttempoMeasured :: Fractional a => a
sttempoMeasured :: a
sttempoMeasured = a
293.70
octaTempo :: Fractional a => a
octaTempo :: a
octaTempo = a
390.70
timeFromPrimary :: Fractional a => Mode -> Int -> a
timeFromPrimary :: Mode -> Int -> a
timeFromPrimary Mode
mode_ Int
tempo =
case Mode
mode_ of
BPM Int
lpb -> a
60 a -> a -> a
forall a. Fractional a => a -> a -> a
/ (Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
tempo a -> a -> a
forall a. Num a => a -> a -> a
* a
6 a -> a -> a
forall a. Num a => a -> a -> a
* Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lpb)
Mode
Octa -> Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
10 Int
tempo) a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
forall a. Fractional a => a
octaTempo
Mode
Speed ->
if Int
tempoInt -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<=Int
10
then Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
tempo a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
forall a. Fractional a => a
sttempoMeasured
else a
forall a. Fractional a => a
timerDiv a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
forall a. Fractional a => a
ciabFreq a -> a -> a
forall a. Num a => a -> a -> a
* Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
tempo)