{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TypeFamilies #-} module Synthesizer.LLVM.Wave where import qualified Synthesizer.LLVM.Simple.Value as Value import qualified LLVM.Extra.Arithmetic as A import qualified LLVM.Extra.Monad as M import LLVM.Core (CodeGenFunction, ) import Control.Monad.HT ((<=<), ) import NumericPrelude.Numeric import NumericPrelude.Base hiding (replicate, ) saw :: (A.PseudoRing a, A.IntegerConstant a) => a -> CodeGenFunction r a saw = A.sub (A.fromInteger' 1) <=< A.mul (A.fromInteger' 2) square :: (A.PseudoRing a, A.IntegerConstant a, A.Fraction a) => a -> CodeGenFunction r a square = A.sub (A.fromInteger' 1) <=< A.mul (A.fromInteger' 2) <=< A.truncate <=< A.mul (A.fromInteger' 2) triangle :: (A.PseudoRing a, A.RationalConstant a, A.Fraction a) => a -> CodeGenFunction r a triangle = flip A.sub (A.fromInteger' 1) <=< A.abs <=< flip A.sub (A.fromInteger' 2) <=< A.mul (A.fromInteger' 4) <=< A.incPhase (A.fromRational' 0.75) approxSine2 :: (A.PseudoRing a, A.IntegerConstant a, A.Fraction a) => a -> CodeGenFunction r a approxSine2 t = do x <- saw t A.mul (A.fromInteger' 4) =<< A.mul x =<< A.sub (A.fromInteger' 1) =<< A.abs x approxSine3 :: (A.PseudoRing a, A.RationalConstant a, A.Fraction a) => a -> CodeGenFunction r a approxSine3 t = do x <- triangle t A.mul (A.fromRational' 0.5) =<< A.mul x =<< A.sub (A.fromInteger' 3) =<< A.mul x x approxSine4 :: (A.PseudoRing a, A.RationalConstant a, A.Real a) => a -> CodeGenFunction r a approxSine4 t = do x <- saw t ax <- A.abs x sax <- A.sub (A.fromInteger' 1) ax A.mul (A.fromRational' (16/5)) =<< A.mul x =<< A.mul sax =<< A.add (A.fromInteger' 1) =<< A.mul sax ax {- | For the distortion factor @recip pi@ you get the closest approximation to an undistorted cosine or sine. We have chosen this scaling in order to stay with field operations. -} rationalApproxCosine1, rationalApproxSine1 :: (A.Field a, A.RationalConstant a, A.Real a) => a -> a -> CodeGenFunction r a rationalApproxCosine1 k t = do num2 <- A.square =<< A.mul k =<< A.add (A.fromInteger' (-1)) =<< A.mul (A.fromInteger' 2) t den2 <- A.square =<< A.mul t =<< A.sub (A.fromInteger' 1) t M.liftR2 A.fdiv (A.sub num2 den2) (A.add num2 den2) rationalApproxSine1 k t = do num <- A.mul k =<< A.add (A.fromInteger' (-1)) =<< A.mul (A.fromInteger' 2) t den <- A.mul t =<< A.sub (A.fromInteger' 1) t M.liftR2 A.fdiv (A.mul (A.fromInteger' (-2)) =<< A.mul num den) (M.liftR2 A.add (A.square num) (A.square den)) trapezoidSkew :: (A.Field a, A.RationalConstant a, A.Real a) => a -> a -> CodeGenFunction r a trapezoidSkew p = A.max (A.fromInteger' (-1)) <=< A.min (A.fromInteger' 1) <=< flip A.fdiv p <=< A.sub (A.fromInteger' 1) <=< A.mul (A.fromInteger' 2) sine :: (A.Transcendental a, A.RationalConstant a) => a -> CodeGenFunction r a sine t = A.sin =<< A.mul t =<< Value.decons Value.twoPi {- | This can be used for preprocessing the phase in order to generate locally faster oscillating waves. For example > triangle <=< replicate (valueOf 2.5) shrinks a triangle wave such that 2.5 periods fit into one. -} replicate :: (A.PseudoRing a, A.RationalConstant a, A.Fraction a) => a -> a -> CodeGenFunction r a replicate k = A.fraction <=< A.mul k <=< flip A.sub (A.fromRational' 0.5) <=< A.incPhase (A.fromRational' 0.5) {- | Preprocess the phase such that the first half of a wave is expanded to one period and shifted by 90 degree. E.g. > sine <=< halfEnvelope generates a sequence of sine bows that starts and ends with the maximum. Such a signal can be used to envelope an oscillation generated using 'replicate'. -} halfEnvelope :: (A.PseudoRing a, A.RationalConstant a, A.Fraction a) => a -> CodeGenFunction r a halfEnvelope = A.mul (A.fromRational' 0.5) <=< A.incPhase (A.fromRational' 0.5) partial :: (A.Fraction v, A.PseudoRing v, A.IntegerConstant v) => (v -> CodeGenFunction r v) -> Int -> (v -> CodeGenFunction r v) partial w n t = w =<< A.signedFraction =<< A.mul t (A.fromInteger' (fromIntegral n))