module Nes.APU.State.Envelope (
Envelope (..),
newEnvelope,
HasEnvelope (..),
withEnvelope,
tickEnvelope,
getEnvelopeOutput,
) where
data Envelope = MkE
{ Envelope -> Bool
startFlag :: {-# UNPACK #-} !Bool
, Envelope -> Bool
useConstantVolume :: {-# UNPACK #-} !Bool
, Envelope -> Int
constantVolume :: {-# UNPACK #-} !Int
, Envelope -> Int
decayLevel :: {-# UNPACK #-} !Int
, Envelope -> Int
divider :: {-# UNPACK #-} !Int
, Envelope -> Bool
loopFlag :: {-# UNPACK #-} !Bool
}
newEnvelope :: Envelope
newEnvelope :: Envelope
newEnvelope = Bool -> Bool -> Int -> Int -> Int -> Bool -> Envelope
MkE Bool
False Bool
False Int
0 Int
0 Int
0 Bool
False
class HasEnvelope a where
getEnvelope :: a -> Envelope
setEnvelope :: Envelope -> a -> a
{-# INLINE withEnvelope #-}
withEnvelope :: (HasEnvelope a) => (Envelope -> Envelope) -> a -> a
withEnvelope :: forall a. HasEnvelope a => (Envelope -> Envelope) -> a -> a
withEnvelope Envelope -> Envelope
f a
a = Envelope -> a -> a
forall a. HasEnvelope a => Envelope -> a -> a
setEnvelope (Envelope -> Envelope
f (Envelope -> Envelope) -> Envelope -> Envelope
forall a b. (a -> b) -> a -> b
$ a -> Envelope
forall a. HasEnvelope a => a -> Envelope
getEnvelope a
a) a
a
tickEnvelope :: Envelope -> Envelope
tickEnvelope :: Envelope -> Envelope
tickEnvelope Envelope
e =
if Envelope -> Bool
startFlag Envelope
e
then Envelope
e{startFlag = False, decayLevel = 15, divider = constantVolume e}
else Envelope -> Envelope
tickDivider Envelope
e
tickDivider :: Envelope -> Envelope
tickDivider :: Envelope -> Envelope
tickDivider Envelope
e =
if Envelope -> Int
divider Envelope
e Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
then Envelope
e{divider = constantVolume e, decayLevel = newDecay}
else Envelope
e{divider = divider e - 1}
where
newDecay :: Int
newDecay =
if Envelope -> Int
decayLevel Envelope
e Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
then if Envelope -> Bool
loopFlag Envelope
e then Int
15 else Int
0
else Envelope -> Int
decayLevel Envelope
e Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
getEnvelopeOutput :: Envelope -> Int
getEnvelopeOutput :: Envelope -> Int
getEnvelopeOutput Envelope
e =
if Envelope -> Bool
useConstantVolume Envelope
e
then Envelope -> Int
constantVolume Envelope
e
else Envelope -> Int
decayLevel Envelope
e