{-# LANGUAGE GADTs #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ViewPatterns #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Call.Component.Deck
-- Copyright   :  (c) Fumiaki Kinoshita 2014
-- License     :  BSD3
--
-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
-- Stability   :  experimental
-- Portability :  non-portable
--
-- Decks that plays sounds
--
-----------------------------------------------------------------------------
module Call.Component.Deck (emptyDeck, States, source, pos, pitch, playing, sampleRate) where
import Call.Component
import Control.Lens
import Linear
import Call.Types
import Control.Monad.State.Strict
import Call.Data.Wave
import Control.Object

data States = States
  { _src :: Maybe (Source (V2 Float))
  , _pos :: !Time
  , _pitch :: !Double
  , _playing :: !Bool
  , _sampleRate :: !Double }

--
source :: Lens' States (Maybe (Source (V2 Float)))
source f s = f (_src s) <&> \a -> s { _src = a }
pos :: Lens' States Time
pos f s = f (_pos s) <&> \a -> s { _pos = a }
pitch :: Lens' States Time
pitch f s = f (_pitch s) <&> \a -> s { _pitch = a }
playing :: Lens' States Bool
playing f s = f (_playing s) <&> \a -> s { _playing = a }
sampleRate :: Lens' States Double
sampleRate f s = f (_sampleRate s) <&> \a -> s { _sampleRate = a }

emptyDeck :: Monad m => Object (AccessT States PullAudio) m
emptyDeck = stateful handle $ States Nothing 0 1 False 44100 where -- FIXME: sample rate

handle :: MonadState States m => PullAudio (m a) -> m a
handle (PullAudio dt0 n cont) = use source >>= \case
  Just (Source s) -> do
    pl <- use playing
    t0 <- use pos
    k <- use pitch
    let dt = dt0 * k
    if pl
      then do
        r <- use sampleRate
        pos += dt
        cont $ map s [t0,t0 + dt / fromIntegral n..t0 + dt - 1 / r]
      else do
        cont $ replicate n zero
  Nothing -> cont $ replicate n zero