{-# LANGUAGE NoImplicitPrelude #-}
{- |
Plain interpolation functions.
-}
module Synthesizer.Interpolation.Core (
   linear,
   cubic,
   cubicAlt,
   ) where

import qualified Algebra.Module    as Module
import qualified Algebra.Field     as Field

import Synthesizer.Utility (affineComb, )

import NumericPrelude.Numeric
import NumericPrelude.Base



{-# INLINE linear #-}
linear ::
   (Module.C a v) =>
   v -> v -> a -> v
linear :: forall a v. C a v => v -> v -> a -> v
linear v
x0 v
x1 a
phase = forall t y. C t y => t -> (y, y) -> y
affineComb a
phase (v
x0,v
x1)

{-# INLINE cubic #-}
cubic ::
   (Module.C a v, Field.C a) =>
   v -> v -> v -> v -> a -> v
cubic :: forall a v. (C a v, C a) => v -> v -> v -> v -> a -> v
cubic v
xm1 v
x0 v
x1 v
x2 a
t =
   let lipm12 :: v
lipm12 = forall t y. C t y => t -> (y, y) -> y
affineComb a
t (v
xm1,v
x2)
       lip01 :: v
lip01  = forall t y. C t y => t -> (y, y) -> y
affineComb a
t (v
x0, v
x1)
       three :: a
three  = a
3 forall a. a -> a -> a
`asTypeOf` a
t
   in  v
lip01 forall a. C a => a -> a -> a
+ (a
tforall a. C a => a -> a -> a
*(a
tforall a. C a => a -> a -> a
-a
1)forall a. C a => a -> a -> a
/a
2) forall a v. C a v => a -> v -> v
*>
                  (v
lipm12 forall a. C a => a -> a -> a
+ (v
x0forall a. C a => a -> a -> a
+v
x1) forall a. C a => a -> a -> a
- a
three forall a v. C a v => a -> v -> v
*> v
lip01)

{- |
The interpolators for module operations
do not simply compute a straight linear combination of some vectors.
Instead they add then scale, then add again, and so on.
This is efficient whenever scaling and addition is cheap.
In this case they might save multiplications.
I can't say much about numeric cancellations, however.
-}
{-# INLINE cubicAlt #-}
cubicAlt ::
   (Module.C a v, Field.C a) =>
   v -> v -> v -> v -> a -> v
cubicAlt :: forall a v. (C a v, C a) => v -> v -> v -> v -> a -> v
cubicAlt v
xm1 v
x0 v
x1 v
x2 a
t =
   let half :: a
half = a
1forall a. C a => a -> a -> a
/a
2 forall a. a -> a -> a
`asTypeOf` a
t
   in  forall t y. C t y => t -> y -> y -> y
cubicHalf    a
t  v
x0 (a
half forall a v. C a v => a -> v -> v
*> (v
x1forall a. C a => a -> a -> a
-v
xm1)) forall a. C a => a -> a -> a
+
       forall t y. C t y => t -> y -> y -> y
cubicHalf (a
1forall a. C a => a -> a -> a
-a
t) v
x1 (a
half forall a v. C a v => a -> v -> v
*> (v
x0forall a. C a => a -> a -> a
-v
x2))

{- |
@\t -> cubicHalf t x x'@ has a double zero at 1 and
at 0 it has value x and slope x'.
-}
{-# INLINE cubicHalf #-}
cubicHalf :: (Module.C t y) => t -> y -> y -> y
cubicHalf :: forall t y. C t y => t -> y -> y -> y
cubicHalf t
t y
x y
x' =
   (t
tforall a. C a => a -> a -> a
-t
1)forall a. C a => a -> Integer -> a
^Integer
2 forall a v. C a v => a -> v -> v
*> ((t
1forall a. C a => a -> a -> a
+t
2forall a. C a => a -> a -> a
*t
t)forall a v. C a v => a -> v -> v
*>y
x forall a. C a => a -> a -> a
+ t
tforall a v. C a v => a -> v -> v
*>y
x')