packages feed

synthesizer-llvm-0.3: src/Synthesizer/LLVM/Frame.hs

{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
module Synthesizer.LLVM.Frame where

import qualified Synthesizer.LLVM.Frame.Stereo as Stereo

import qualified LLVM.Extra.ScalarOrVector as SoV
import qualified LLVM.Extra.Vector as Vector
import qualified LLVM.Extra.Class as Class
import qualified LLVM.Extra.Control as C
import qualified LLVM.Extra.Arithmetic as A

import qualified LLVM.Core as LLVM
import LLVM.Core
          (CodeGenFunction, Value, Vector,
           IsPrimitive, IsArithmetic, )

import qualified Data.TypeLevel.Num as TypeNum
import Data.TypeLevel.Num (D2, D4, )

import Foreign.Storable.Tuple ()

import Data.Word (Word32, )

import qualified Data.Traversable as Trav

import NumericPrelude.Numeric hiding (zero, one, div, signum, )
import NumericPrelude.Base


{- |
Copy mono signal to both stereo channels.
-}
stereoFromMono ::
   a -> CodeGenFunction r (Stereo.T a)
stereoFromMono x =
   return $ Stereo.cons x x

mixMonoFromStereo ::
   (A.Additive a) =>
   Stereo.T a -> CodeGenFunction r a
mixMonoFromStereo s =
   mix (Stereo.left s) (Stereo.right s)


stereoFromVector ::
   (IsPrimitive a) =>
   Value (Vector D2 a) ->
   CodeGenFunction r (Stereo.T (Value a))
stereoFromVector x =
   Trav.mapM (LLVM.extractelement x . LLVM.valueOf) $ Stereo.cons 0 1

vectorFromStereo ::
   (IsPrimitive a) =>
   Stereo.T (Value a) ->
   CodeGenFunction r (Value (Vector D2 a))
vectorFromStereo =
   Vector.assemble . listFromStereo


quadroFromVector ::
   (IsPrimitive a) =>
   Value (Vector D4 a) ->
   CodeGenFunction r (Stereo.T (Stereo.T (Value a)))
quadroFromVector x =
   Trav.mapM (Trav.mapM (LLVM.extractelement x . LLVM.valueOf)) $
   Stereo.cons (Stereo.cons 0 1) (Stereo.cons 2 3)

vectorFromQuadro ::
   (IsPrimitive a) =>
   Stereo.T (Stereo.T (Value a)) ->
   CodeGenFunction r (Value (Vector D4 a))
vectorFromQuadro =
   Vector.assemble .
   concatMap listFromStereo . listFromStereo

listFromStereo :: Stereo.T a -> [a]
listFromStereo s =
   [Stereo.left s, Stereo.right s]


mix ::
   (A.Additive a) =>
   a -> a -> CodeGenFunction r a
mix = A.add


{- |
This may mean more shuffling and is not necessarily better than mixStereo.
-}
mixStereoV ::
   (IsArithmetic a, IsPrimitive a) =>
   Stereo.T (Value a) -> Stereo.T (Value a) ->
   CodeGenFunction r (Stereo.T (Value a))
mixStereoV x y =
   do xv <- vectorFromStereo x
      yv <- vectorFromStereo y
      stereoFromVector =<< A.add xv yv

mixVector ::
   (Vector.Arithmetic a, TypeNum.Pos n) =>
   Value (Vector n a) ->
   CodeGenFunction r (Value a)
mixVector = Vector.sum

mixVectorToStereo ::
   (Vector.Arithmetic a, TypeNum.Pos n) =>
   Value (Vector n a) ->
   CodeGenFunction r (Stereo.T (Value a))
mixVectorToStereo =
   fmap (uncurry Stereo.cons) .
   Vector.sumInterleavedToPair

{- |
Mix components with even index to the left channel
and components with odd index to the right channel.
-}
mixInterleavedVectorToStereo ::
   (Vector.Arithmetic a, TypeNum.Pos n) =>
   Value (Vector n a) ->
   CodeGenFunction r (Stereo.T (Value a))
mixInterleavedVectorToStereo =
   fmap (uncurry Stereo.cons) .
   Vector.sumInterleavedToPair


amplifyMono ::
   (A.PseudoRing a) =>
   a -> a -> CodeGenFunction r a
amplifyMono = A.mul

amplifyStereo ::
   (A.PseudoRing a) =>
   a -> Stereo.T a -> CodeGenFunction r (Stereo.T a)
amplifyStereo x =
   Trav.mapM (A.mul x)


subsampleVector ::
   (Vector.Access n a v) =>
   v -> CodeGenFunction r a
subsampleVector =
   Vector.extract (LLVM.value LLVM.zero :: Value Word32)


signum ::
   (SoV.IntegerConstant a,
    LLVM.IsFirstClass a,
    LLVM.CmpRet a Bool) =>
   Value a -> CodeGenFunction r (Value a)
signum x = do
   negative <- A.cmp LLVM.CmpLT x Class.zeroTuple
   positive <- A.cmp LLVM.CmpGT x Class.zeroTuple
   C.select negative (A.fromInteger' (-1))
      =<< C.select positive (A.fromInteger' 1) (A.fromInteger' 0)