{-# LANGUAGE NoImplicitPrelude #-}moduleSynthesizer.LLVM.WavewhereimportqualifiedSynthesizer.LLVM.Simple.ValueasValueimportqualifiedLLVM.Extra.ScalarOrVectorasSoVimportqualifiedLLVM.Extra.ArithmeticasAimportqualifiedLLVM.Extra.MonadasMimportqualifiedLLVM.CoreasLLVMimportLLVM.Core(Value,CodeGenFunction,IsFloating,IsArithmetic,IsConst,)importControl.Monad.HT((<=<),)importqualifiedAlgebra.TranscendentalasTransimportqualifiedAlgebra.FieldasFieldimportqualifiedAlgebra.RingasRingimportNumericPrelude.NumericimportNumericPrelude.Basehiding(replicate,)saw::(Ring.Ca,IsConsta,SoV.Replicateav,IsArithmeticv)=>Valuev->CodeGenFunctionr(Valuev)saw=A.sub(SoV.replicateOf1)<=<A.mul(SoV.replicateOf2)square::(Ring.Ca,IsConsta,SoV.Replicateav,SoV.Fractionv,SoV.Realv)=>Valuev->CodeGenFunctionr(Valuev)square=A.sub(SoV.replicateOf1)<=<A.mul(SoV.replicateOf2)<=<SoV.truncate<=<A.mul(SoV.replicateOf2)triangle::(Field.Ca,IsConsta,SoV.Replicateav,SoV.Fractionv,SoV.Realv)=>Valuev->CodeGenFunctionr(Valuev)triangle=flipA.sub(SoV.replicateOf1)<=<SoV.abs<=<flipA.sub(SoV.replicateOf2)<=<A.mul(SoV.replicateOf4)<=<SoV.incPhase(SoV.replicateOf0.75)approxSine2::(Ring.Ca,IsConsta,SoV.Replicateav,SoV.Realv)=>Valuev->CodeGenFunctionr(Valuev)approxSine2t=dox<-sawtA.mul(SoV.replicateOf4)=<<A.mulx=<<A.sub(SoV.replicateOf1)=<<SoV.absxapproxSine3::(Field.Ca,IsConsta,SoV.Replicateav,SoV.Fractionv,SoV.Realv)=>Valuev->CodeGenFunctionr(Valuev)approxSine3t=dox<-triangletA.mul(SoV.replicateOf0.5)=<<A.mulx=<<A.sub(SoV.replicateOf3)=<<A.mulxxapproxSine4::(Field.Ca,IsConsta,SoV.Replicateav,SoV.Realv)=>Valuev->CodeGenFunctionr(Valuev)approxSine4t=dox<-sawtax<-SoV.absxsax<-A.sub(SoV.replicateOf1)axA.mul(SoV.replicateOf(16/5))=<<A.mulx=<<A.mulsax=<<A.add(SoV.replicateOf1)=<<A.mulsaxax{- |
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::(Field.Ca,IsConsta,SoV.Replicateav,SoV.Realv,IsFloatingv)=>Valuev->Valuev->CodeGenFunctionr(Valuev)rationalApproxCosine1kt=donum2<-A.square=<<A.mulk=<<A.add(SoV.replicateOf(-1))=<<A.mul(SoV.replicateOf2)tden2<-A.square=<<A.mult=<<A.sub(SoV.replicateOf1)tM.liftR2A.fdiv(A.subnum2den2)(A.addnum2den2)rationalApproxSine1kt=donum<-A.mulk=<<A.add(SoV.replicateOf(-1))=<<A.mul(SoV.replicateOf2)tden<-A.mult=<<A.sub(SoV.replicateOf1)tM.liftR2A.fdiv(A.mul(SoV.replicateOf(-2))=<<A.mulnumden)(M.liftR2A.add(A.squarenum)(A.squareden))trapezoidSkew::(Field.Ca,IsConsta,SoV.Replicateav,SoV.Fractionv,SoV.Realv)=>Valuev->Valuev->CodeGenFunctionr(Valuev)trapezoidSkewp=SoV.max(SoV.replicateOf(-1))<=<SoV.min(SoV.replicateOf1)<=<flipA.fdivp<=<A.sub(SoV.replicateOf1)<=<A.mul(SoV.replicateOf2)sine::(Trans.Ca,IsFloatinga,IsConsta)=>-- Value a -> TValue r aValuea->CodeGenFunctionr(Valuea)sinet=A.sin=<<A.mult=<<Value.deconsValue.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::(Field.Ca,IsConsta,SoV.Replicateav,SoV.Fractionv,SoV.Realv)=>Valuev->Valuev->CodeGenFunctionr(Valuev)replicatek=SoV.fraction<=<A.mulk<=<flipA.sub(SoV.replicateOf0.5)<=<SoV.incPhase(SoV.replicateOf0.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::(Field.Ca,IsConsta,SoV.Replicateav,SoV.Fractionv,SoV.Realv)=>Valuev->CodeGenFunctionr(Valuev)halfEnvelope=A.mul(SoV.replicateOf0.5)<=<SoV.incPhase(SoV.replicateOf0.5)partial::(LLVM.IsPrimitivei,LLVM.IsPrimitivea,LLVM.IsIntegeri,IsFloatinga,SoV.Replicateav,SoV.Fractionv)=>(Valuev->CodeGenFunctionr(Valuev))->Valuei->(Valuev->CodeGenFunctionr(Valuev))partialwnt=w=<<SoV.signedFraction=<<A.mult=<<SoV.replicate=<<LLVM.sitofpn