module Synthesizer.LLVM.Server.CommonPacked (
   module Synthesizer.LLVM.Server.CommonPacked,
   Param,
   ) where

import Synthesizer.LLVM.Server.Common

import qualified Synthesizer.LLVM.Frame.SerialVector as Serial

import qualified Synthesizer.LLVM.CausalParameterized.Process as CausalP
import qualified Synthesizer.LLVM.CausalParameterized.Functional as F
import qualified Synthesizer.LLVM.Parameterized.Signal as SigP

import qualified Data.NonEmpty as NonEmpty

import qualified Algebra.Additive as Additive

import qualified Type.Data.Num.Decimal as TypeNum

import Control.Arrow (arr, )

import NumericPrelude.Numeric ((+), (-), (*), )
import Prelude hiding (Real, (+), (-), (*), )


sumNested :: (Additive.C a) => [a] -> a
sumNested =
   maybe Additive.zero (NonEmpty.foldBalanced (+)) . NonEmpty.fetch


-- maybe this can be merged into a PCS.controllerDiscrete
stair :: Real -> Real
stair i =
   let n = fromIntegral (round i :: Int)
       r = i - n
   in  n + 0.01*r


type SigP p = SigP.T (SampleRate Real, p)
type CausalP p = CausalP.T (SampleRate Real, p)
type FuncP p = F.T (SampleRate Real, p)


type Vector = Serial.Plain VectorSize Real
type VectorValue = Serial.Value VectorSize Real
type VectorSize = TypeNum.D4


vectorSize :: Int
vectorSize =
   TypeNum.integralFromSingleton
      (TypeNum.singleton :: TypeNum.Singleton VectorSize)

vectorRate :: Fractional a => SampleRate a -> a
vectorRate (SampleRate sampleRate) =
   sampleRate / fromIntegral vectorSize


vectorTime :: (p -> Real) -> Param p Real
vectorTime param =
   arr (\(SampleRate sampleRate, p) ->
          param p * sampleRate / fromIntegral vectorSize)