-- | Common math functions.
module Sound.Sc3.Common.Math where

import qualified Data.Fixed {- base -}
import Data.Maybe {- base -}
import Data.Ratio {- base -}
import qualified Numeric {- base -}

import qualified Sound.Sc3.Common.Base as Common.Base {- hsc3 -}

{- | Half pi.

>>> half_pi
1.5707963267948966
-}
half_pi :: Floating a => a
half_pi :: forall a. Floating a => a
half_pi = a
forall a. Floating a => a
pi a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
2

{- | Two pi.

>>> two_pi
6.283185307179586
-}
two_pi :: Floating n => n
two_pi :: forall a. Floating a => a
two_pi = n
2 n -> n -> n
forall a. Num a => a -> a -> a
* n
forall a. Floating a => a
pi

-- | 'abs' of '(-)'.
absdif :: Num a => a -> a -> a
absdif :: forall a. Num a => a -> a -> a
absdif a
i a
j = a -> a
forall a. Num a => a -> a
abs (a
j a -> a -> a
forall a. Num a => a -> a -> a
- a
i)

-- | Sc3 MulAdd type signature, arguments in Sc3 order of input, multiply, add.
type Sc3_MulAdd t = t -> t -> t -> t

{- | Ordinary (un-optimised) multiply-add, see also mulAdd Ugen.

>>> sc3_mul_add 2 3 4 == 2 * 3 + 4
True

>>> map (\x -> sc3_mul_add x 2 3) [1,5]
[5,13]

>>> map (\x -> sc3_mul_add x 3 2) [1,5]
[5,17]
-}
sc3_mul_add :: Num t => Sc3_MulAdd t
sc3_mul_add :: forall t. Num t => Sc3_MulAdd t
sc3_mul_add t
i t
m t
a = t
i t -> t -> t
forall a. Num a => a -> a -> a
* t
m t -> t -> t
forall a. Num a => a -> a -> a
+ t
a

{- | Ordinary Haskell order (un-optimised) multiply-add.

>>> mul_add 3 4 2 == 2 * 3 + 4
True

>>> map (mul_add 2 3) [1,5]
[5,13]

>> map (mul_add 3 4) [1,5]
[7,19]
-}
mul_add :: Num t => t -> t -> t -> t
mul_add :: forall t. Num t => Sc3_MulAdd t
mul_add t
m t
a = (t -> t -> t
forall a. Num a => a -> a -> a
+ t
a) (t -> t) -> (t -> t) -> t -> t
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (t -> t -> t
forall a. Num a => a -> a -> a
* t
m)

{- | 'uncurry' 'mul_add'

>>> mul_add_hs (3,4) 2 == 2 * 3 + 4
True
-}
mul_add_hs :: Num t => (t, t) -> t -> t
mul_add_hs :: forall t. Num t => (t, t) -> t -> t
mul_add_hs = (t -> t -> t -> t) -> (t, t) -> t -> t
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry t -> t -> t -> t
forall t. Num t => Sc3_MulAdd t
mul_add

-- | 'fromInteger' of 'truncate'.
sc3_truncate :: RealFrac a => a -> a
sc3_truncate :: forall a. RealFrac a => a -> a
sc3_truncate = Integer -> a
forall a. Num a => Integer -> a
fromInteger (Integer -> a) -> (a -> Integer) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Integer
forall b. Integral b => a -> b
forall a b. (RealFrac a, Integral b) => a -> b
truncate

-- | 'fromInteger' of 'round'.
sc3_round :: RealFrac a => a -> a
sc3_round :: forall a. RealFrac a => a -> a
sc3_round = Integer -> a
forall a. Num a => Integer -> a
fromInteger (Integer -> a) -> (a -> Integer) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Integer
forall b. Integral b => a -> b
forall a b. (RealFrac a, Integral b) => a -> b
round

-- | 'fromInteger' of 'ceiling'.
sc3_ceiling :: RealFrac a => a -> a
sc3_ceiling :: forall a. RealFrac a => a -> a
sc3_ceiling = Integer -> a
forall a. Num a => Integer -> a
fromInteger (Integer -> a) -> (a -> Integer) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Integer
forall b. Integral b => a -> b
forall a b. (RealFrac a, Integral b) => a -> b
ceiling

-- | 'fromInteger' of 'floor'.
sc3_floor :: RealFrac a => a -> a
sc3_floor :: forall a. RealFrac a => a -> a
sc3_floor = Integer -> a
forall a. Num a => Integer -> a
fromInteger (Integer -> a) -> (a -> Integer) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Integer
forall b. Integral b => a -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor

{- | Variant of @Sc3@ @roundTo@ function.

>>> sc3_round_to (2/3) 0.25
0.75

>>> map (`sc3_round_to` 0.25) [0,0.1 .. 1]
[0.0,0.0,0.25,0.25,0.5,0.5,0.5,0.75,0.75,1.0,1.0]

>>> map (`sc3_round_to` 5.0) [100.0 .. 110.0]
[100.0,100.0,100.0,105.0,105.0,105.0,105.0,105.0,110.0,110.0,110.0]
-}
sc3_round_to :: RealFrac n => n -> n -> n
sc3_round_to :: forall n. RealFrac n => n -> n -> n
sc3_round_to n
a n
b = if n
b n -> n -> Bool
forall a. Eq a => a -> a -> Bool
== n
0 then n
a else n -> n
forall a. RealFrac a => a -> a
sc3_floor ((n
a n -> n -> n
forall a. Fractional a => a -> a -> a
/ n
b) n -> n -> n
forall a. Num a => a -> a -> a
+ n
0.5) n -> n -> n
forall a. Num a => a -> a -> a
* n
b

-- | 'fromInteger' of 'div' of 'floor'.
sc3_idiv :: RealFrac n => n -> n -> n
sc3_idiv :: forall n. RealFrac n => n -> n -> n
sc3_idiv n
a n
b = Integer -> n
forall a. Num a => Integer -> a
fromInteger (n -> Integer
forall b. Integral b => n -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor n
a Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` n -> Integer
forall b. Integral b => n -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor n
b)

{- | 'sc3_lcm'

Least common multiple. This definition extends the usual definition
and returns a negative number if any of the operands is negative. This
makes it consistent with the lattice-theoretical interpretation and
its idempotency, commutative, associative, absorption laws.

>>> lcm 4 6
12

>>> lcm 1 1
1

>>> lcm 1624 26
21112

>>> lcm 1624 (-26) /= (-21112)
True

>>> lcm (-1624) (-26) /= (-21112)
True

>>> lcm 513 (gcd 513 44)
513
-}
sc3_lcm :: t -> t -> t
sc3_lcm :: forall t. t -> t -> t
sc3_lcm = [Char] -> t -> t -> t
forall a. HasCallStack => [Char] -> a
error [Char]
"sc3_lcm: undefined"

{- | 'sc3_gcd'

Greatest common divisor. This definition extends the usual
definition and returns a negative number if both operands are
negative. This makes it consistent with the lattice-theoretical
interpretation and its idempotency, commutative, associative,
absorption laws. <https://www.jsoftware.com/papers/eem/gcd.htm>

>>> gcd 4 6
2

>>> gcd 0 1
1

>>> gcd 1024 256
256

>>> gcd 1024 (-256)
256

>>> gcd (-1024) (-256) /= (-256)
True

>>> gcd (-1024) (lcm (-1024) 256) /= (-1024)
True

>>> gcd 66 54 * lcm 66 54 == 66 * 54
True
-}
sc3_gcd :: t -> t -> t
sc3_gcd :: forall t. t -> t -> t
sc3_gcd = [Char] -> t -> t -> t
forall a. HasCallStack => [Char] -> a
error [Char]
"sc3_gcd: undefined"

{- | The Sc3 @%@ Ugen operator is the 'Data.Fixed.mod'' function.

> 1.5 % 1.2 // ~= 0.3
> -1.5 % 1.2 // ~= 0.9
> 1.5 % -1.2 // ~= -0.9
> -1.5 % -1.2 // ~= -0.3

>>> let (~=) p q = abs (p - q) < 0.000001
>>> let (%) = sc3_mod
>>> (1.5 % 1.2) ~= 0.3
True

>>> ((-1.5) % 1.2) ~= 0.9
True

>>> (1.5 % (-1.2)) ~= (-0.9)
True

>>> ((-1.5) % (-1.2)) ~= (-0.3)
True

> 1.2 % 1.5 // ~= 1.2
> -1.2 % 1.5 // ~= 0.3
> 1.2 % -1.5 // ~= -0.3
> -1.2 % -1.5 // ~= -1.2

>>> (1.2 % 1.5) ~= 1.2
True

>>> ((-1.2) % 1.5) ~= 0.3
True

>>> (1.2 % (-1.5)) ~= (-0.3)
True

>>> ((-1.2) % (-1.5)) ~= (-1.2)
True

>>> map (\n -> sc3_mod n 12.0) [-1.0,12.25,15.0]
[11.0,0.25,3.0]
-}
sc3_mod :: RealFrac n => n -> n -> n
sc3_mod :: forall n. RealFrac n => n -> n -> n
sc3_mod = n -> n -> n
forall a. Real a => a -> a -> a
Data.Fixed.mod'

-- | Type specialised 'sc3_mod'.
fmod_f32 :: Float -> Float -> Float
fmod_f32 :: Float -> Float -> Float
fmod_f32 = Float -> Float -> Float
forall n. RealFrac n => n -> n -> n
sc3_mod

-- | Type specialised 'sc3_mod'.
fmod_f64 :: Double -> Double -> Double
fmod_f64 :: Double -> Double -> Double
fmod_f64 = Double -> Double -> Double
forall n. RealFrac n => n -> n -> n
sc3_mod

{- | @Sc3@ clip function.  Clip /n/ to within range /(i,j)/.  'clip' is a 'Ugen'.

>>> map (\n -> sc3_clip n 5 10) [3..12]
[5,5,5,6,7,8,9,10,10,10]
-}
sc3_clip :: Ord a => a -> a -> a -> a
sc3_clip :: forall a. Ord a => a -> a -> a -> a
sc3_clip a
n a
i a
j = if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
i then a
i else if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
j then a
j else a
n

{- | Variant of 'sc3_clip' with haskell argument structure.

>>> map (clip_hs (5,10)) [3..12]
[5,5,5,6,7,8,9,10,10,10]
-}
clip_hs :: (Ord a) => (a, a) -> a -> a
clip_hs :: forall a. Ord a => (a, a) -> a -> a
clip_hs (a
i, a
j) a
n = a -> a -> a -> a
forall a. Ord a => a -> a -> a -> a
sc3_clip a
n a
i a
j

{- | Fractional modulo, alternate implementation.

>>> map (\n -> sc3_mod_alt n 12.0) [-1.0,12.25,15.0]
[11.0,0.25,3.0]
-}
sc3_mod_alt :: RealFrac a => a -> a -> a
sc3_mod_alt :: forall n. RealFrac n => n -> n -> n
sc3_mod_alt a
n a
hi =
  let lo :: a
lo = a
0.0
  in if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
lo Bool -> Bool -> Bool
&& a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
hi
      then a
n
      else
        if a
hi a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
lo
          then a
lo
          else a
n a -> a -> a
forall a. Num a => a -> a -> a
- a
hi a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. RealFrac a => a -> a
sc3_floor (a
n a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
hi)

{- | Wrap function that is /non-inclusive/ at right edge, ie. the Wrap Ugen rule.

>>> map (round . sc3_wrap_ni 0 5) [4,5,6]
[4,0,1]

>>> map (round . sc3_wrap_ni 5 10) [3..12]
[8,9,5,6,7,8,9,5,6,7]

> Sound.Sc3.Plot.plot_fn_r1_ln (sc3_wrap_ni (-1) 1) (-2,2)
-}
sc3_wrap_ni :: RealFrac a => a -> a -> a -> a
sc3_wrap_ni :: forall a. RealFrac a => a -> a -> a -> a
sc3_wrap_ni a
lo a
hi a
n = a -> a -> a
forall n. RealFrac n => n -> n -> n
sc3_mod (a
n a -> a -> a
forall a. Num a => a -> a -> a
- a
lo) (a
hi a -> a -> a
forall a. Num a => a -> a -> a
- a
lo) a -> a -> a
forall a. Num a => a -> a -> a
+ a
lo

{- | sc_wrap::int

> [5,6].wrap(0,5) == [5,0]

>>> map (wrap_hs_int (0,5)) [5,6]
[5,0]

> [9,10,5,6,7,8,9,10,5,6].wrap(5,10) == [9,10,5,6,7,8,9,10,5,6]

>>> map (wrap_hs_int (5,10)) [3..12]
[9,10,5,6,7,8,9,10,5,6]
-}
wrap_hs_int :: Integral a => (a, a) -> a -> a
wrap_hs_int :: forall a. Integral a => (a, a) -> a -> a
wrap_hs_int (a
i, a
j) a
n = ((a
n a -> a -> a
forall a. Num a => a -> a -> a
- a
i) a -> a -> a
forall a. Integral a => a -> a -> a
`mod` (a
j a -> a -> a
forall a. Num a => a -> a -> a
- a
i a -> a -> a
forall a. Num a => a -> a -> a
+ a
1)) a -> a -> a
forall a. Num a => a -> a -> a
+ a
i

{- | Wrap /n/ to within range /(i,j)/, ie. @AbstractFunction.wrap@,
ie. /inclusive/ at right edge.  'wrap' is a 'Ugen', hence prime.

> [5.0,6.0].wrap(0.0,5.0) == [0.0,1.0]

>>> map (round . wrap_hs (0,4)) [-1,0 .. 5]
[3,0,1,2,3,0,1]

>>> map (round . wrap_hs (0,5)) [5,6]
[0,1]

>>> map (round . wrap_hs (5,10)) [3..12]
[8,9,5,6,7,8,9,5,6,7]

> Sound.Sc3.Plot.plot_fn_r1_ln (wrap_hs (-1,1)) (-2,2)
-}
wrap_hs :: RealFrac n => (n, n) -> n -> n
wrap_hs :: forall n. RealFrac n => (n, n) -> n -> n
wrap_hs (n
i, n
j) n
n =
  let r :: n
r = n
j n -> n -> n
forall a. Num a => a -> a -> a
- n
i -- + 1
      n' :: n
n' = if n
n n -> n -> Bool
forall a. Ord a => a -> a -> Bool
>= n
j then n
n n -> n -> n
forall a. Num a => a -> a -> a
- n
r else if n
n n -> n -> Bool
forall a. Ord a => a -> a -> Bool
< n
i then n
n n -> n -> n
forall a. Num a => a -> a -> a
+ n
r else n
n
  in if n
n' n -> n -> Bool
forall a. Ord a => a -> a -> Bool
>= n
i Bool -> Bool -> Bool
&& n
n' n -> n -> Bool
forall a. Ord a => a -> a -> Bool
< n
j
      then n
n'
      else n
n' n -> n -> n
forall a. Num a => a -> a -> a
- n
r n -> n -> n
forall a. Num a => a -> a -> a
* n -> n
forall a. RealFrac a => a -> a
sc3_floor ((n
n' n -> n -> n
forall a. Num a => a -> a -> a
- n
i) n -> n -> n
forall a. Fractional a => a -> a -> a
/ n
r)

{- | Variant of 'wrap_hs' with @Sc3@ argument ordering.

>>> map (\n -> sc3_wrap n 5 10) [3..12] == map (wrap_hs (5,10)) [3..12]
True

>>> map (\n -> sc3_wrap n 0 4) [-1, 0 .. 5]
[3.0,0.0,1.0,2.0,3.0,0.0,1.0]
-}
sc3_wrap :: RealFrac n => n -> n -> n -> n
sc3_wrap :: forall a. RealFrac a => a -> a -> a -> a
sc3_wrap n
index n
start n
end = (n, n) -> n -> n
forall n. RealFrac n => (n, n) -> n -> n
wrap_hs (n
start, n
end) n
index

{- | Generic variant of 'wrap''.

> [5,6].wrap(0,5) == [5,0]

>>> map (generic_wrap (0,5)) [5,6]
[5,0]

> [9,10,5,6,7,8,9,10,5,6].wrap(5,10) == [9,10,5,6,7,8,9,10,5,6]

>>> map (generic_wrap (5::Integer,10)) [3..12]
[9,10,5,6,7,8,9,10,5,6]
-}
generic_wrap :: (Ord a, Num a) => (a, a) -> a -> a
generic_wrap :: forall a. (Ord a, Num a) => (a, a) -> a -> a
generic_wrap (a
l, a
r) a
n =
  let d :: a
d = a
r a -> a -> a
forall a. Num a => a -> a -> a
- a
l a -> a -> a
forall a. Num a => a -> a -> a
+ a
1
      f :: a -> a
f = (a, a) -> a -> a
forall a. (Ord a, Num a) => (a, a) -> a -> a
generic_wrap (a
l, a
r)
  in if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
l
      then a -> a
f (a
n a -> a -> a
forall a. Num a => a -> a -> a
+ a
d)
      else if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
r then a -> a
f (a
n a -> a -> a
forall a. Num a => a -> a -> a
- a
d) else a
n

{- | Given sample-rate /sr/ and bin-count /n/ calculate frequency of /i/th bin.

>>> bin_to_freq 44100 2048 32
689.0625
-}
bin_to_freq :: (Fractional n, Integral i) => n -> i -> i -> n
bin_to_freq :: forall n i. (Fractional n, Integral i) => n -> i -> i -> n
bin_to_freq n
sr i
n i
i = i -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral i
i n -> n -> n
forall a. Num a => a -> a -> a
* n
sr n -> n -> n
forall a. Fractional a => a -> a -> a
/ i -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral i
n

{- | Fractional midi note number to cycles per second.

>>> map (floor . midi_to_cps) [0,24,69,120,127]
[8,32,440,8372,12543]

>>> map (floor . midi_to_cps) [-36,138]
[1,23679]

>>> map (floor . midi_to_cps) [69.0,69.25 .. 70.0]
[440,446,452,459,466]
-}
midi_to_cps :: Floating a => a -> a
midi_to_cps :: forall a. Floating a => a -> a
midi_to_cps a
i = a
440.0 a -> a -> a
forall a. Num a => a -> a -> a
* (a
2.0 a -> a -> a
forall a. Floating a => a -> a -> a
** ((a
i a -> a -> a
forall a. Num a => a -> a -> a
- a
69.0) a -> a -> a
forall a. Num a => a -> a -> a
* (a
1.0 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
12.0)))

{- | Cycles per second to fractional midi note number.

>>> map (round . cps_to_midi) [8,32,440,8372,12543]
[0,24,69,120,127]

>>> map (round . cps_to_midi) [1,24000]
[-36,138]
-}
cps_to_midi :: Floating a => a -> a
cps_to_midi :: forall a. Floating a => a -> a
cps_to_midi a
a = (a -> a -> a
forall a. Floating a => a -> a -> a
logBase a
2 (a
a a -> a -> a
forall a. Num a => a -> a -> a
* (a
1.0 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
440.0)) a -> a -> a
forall a. Num a => a -> a -> a
* a
12.0) a -> a -> a
forall a. Num a => a -> a -> a
+ a
69.0

{- | Cycles per second to linear octave (4.75 = A4 = 440).

>>> map (cps_to_oct . midi_to_cps) [60,63,69]
[4.0,4.25,4.75]
-}
cps_to_oct :: Floating a => a -> a
cps_to_oct :: forall a. Floating a => a -> a
cps_to_oct a
a = a -> a -> a
forall a. Floating a => a -> a -> a
logBase a
2 (a
a a -> a -> a
forall a. Num a => a -> a -> a
* (a
1.0 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
440.0)) a -> a -> a
forall a. Num a => a -> a -> a
+ a
4.75

{- | Linear octave to cycles per second.

> [4.0,4.25,4.75].octcps.cpsmidi == [60,63,69]

>>> map (cps_to_midi . oct_to_cps) [4.0,4.25,4.75]
[60.0,63.0,69.0]
-}
oct_to_cps :: Floating a => a -> a
oct_to_cps :: forall a. Floating a => a -> a
oct_to_cps a
a = a
440.0 a -> a -> a
forall a. Num a => a -> a -> a
* (a
2.0 a -> a -> a
forall a. Floating a => a -> a -> a
** (a
a a -> a -> a
forall a. Num a => a -> a -> a
- a
4.75))

-- | Degree, scale and steps per octave to key.
degree_to_key :: RealFrac a => [a] -> a -> a -> a
degree_to_key :: forall a. RealFrac a => [a] -> a -> a -> a
degree_to_key [a]
s a
n a
d =
  let l :: Int
l = [a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
s
      d' :: Int
d' = a -> Int
forall b. Integral b => a -> b
forall a b. (RealFrac a, Integral b) => a -> b
round a
d
      a :: a
a = (a
d a -> a -> a
forall a. Num a => a -> a -> a
- Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
d') a -> a -> a
forall a. Num a => a -> a -> a
* a
10.0 a -> a -> a
forall a. Num a => a -> a -> a
* (a
n a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
12.0)
  in (a
n a -> a -> a
forall a. Num a => a -> a -> a
* Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
d' Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
l)) a -> a -> a
forall a. Num a => a -> a -> a
+ [Char] -> [a] -> Int -> a
forall t. [Char] -> [t] -> Int -> t
Common.Base.at_with_error_message [Char]
"degree_to_key" [a]
s (Int
d' Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
l) a -> a -> a
forall a. Num a => a -> a -> a
+ a
a

{- | One-indexed piano key number (for standard 88 key piano) to midi note number.

>>> map pianokey_to_midi [1,49,88]
[21,69,108]
-}
pianokey_to_midi :: Num n => n -> n
pianokey_to_midi :: forall a. Num a => a -> a
pianokey_to_midi = n -> n -> n
forall a. Num a => a -> a -> a
(+) n
20

{- | Piano key to hertz (ba.pianokey2hz in Faust).
     This is useful as a more musical gamut than midi note numbers.
     Ie. if x is in (0,1) then pianokey_to_cps of (x * 88) is in (26,4168)

>>> map (round . pianokey_to_cps) [0,1,40,49,88]
[26,28,262,440,4186]

>>> map (round . midi_to_cps) [0,60,69,127]
[8,262,440,12544]
-}
pianokey_to_cps :: Floating n => n -> n
pianokey_to_cps :: forall a. Floating a => a -> a
pianokey_to_cps = n -> n
forall a. Floating a => a -> a
midi_to_cps (n -> n) -> (n -> n) -> n -> n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. n -> n
forall a. Num a => a -> a
pianokey_to_midi

{- | Linear amplitude to decibels.

>>> map (round . amp_to_db) [0.01,0.05,0.0625,0.125,0.25,0.5]
[-40,-26,-24,-18,-12,-6]
-}
amp_to_db :: Floating a => a -> a
amp_to_db :: forall a. Floating a => a -> a
amp_to_db = (a -> a -> a
forall a. Num a => a -> a -> a
* a
20) (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a -> a
forall a. Floating a => a -> a -> a
logBase a
10

{- | Decibels to linear amplitude.

>>> map (floor . (* 100). db_to_amp) [-40,-26,-24,-18,-12,-6]
[1,5,6,12,25,50]

>>> let amp = map (2 **) [0 .. 15]
>>> let db = [0,-6 .. -90]
>>> map (round . amp_to_db . (/) 1) amp == db
True

>>> db_to_amp (-3)
0.7079457843841379

>>> amp_to_db 0.7079457843841379
-3.0
-}
db_to_amp :: Floating a => a -> a
db_to_amp :: forall a. Floating a => a -> a
db_to_amp = (a
10 a -> a -> a
forall a. Floating a => a -> a -> a
**) (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a -> a
forall a. Num a => a -> a -> a
* a
0.05)

{- | Fractional midi note interval to frequency multiplier.

>>> map midi_to_ratio [-12,0,7,12]
[0.5,1.0,1.4983070768766815,2.0]
-}
midi_to_ratio :: Floating a => a -> a
midi_to_ratio :: forall a. Floating a => a -> a
midi_to_ratio a
a = a
2.0 a -> a -> a
forall a. Floating a => a -> a -> a
** (a
a a -> a -> a
forall a. Num a => a -> a -> a
* (a
1.0 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
12.0))

{- | Inverse of 'midi_to_ratio'.

>>> map ratio_to_midi [3/2,2]
[7.019550008653875,12.0]
-}
ratio_to_midi :: Floating a => a -> a
ratio_to_midi :: forall a. Floating a => a -> a
ratio_to_midi a
a = a
12.0 a -> a -> a
forall a. Num a => a -> a -> a
* a -> a -> a
forall a. Floating a => a -> a -> a
logBase a
2 a
a

{- | /sr/ = sample rate, /r/ = cycle (two-pi), /cps/ = frequency

>>> cps_to_incr 48000 128 375
1.0

>>> cps_to_incr 48000 two_pi 458.3662361046586
6.0e-2
-}
cps_to_incr :: Fractional a => a -> a -> a -> a
cps_to_incr :: forall a. Fractional a => a -> a -> a -> a
cps_to_incr a
sr a
r a
cps = (a
r a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
sr) a -> a -> a
forall a. Num a => a -> a -> a
* a
cps

{- | Inverse of 'cps_to_incr'.

>>> incr_to_cps 48000 128 1
375.0
-}
incr_to_cps :: Fractional a => a -> a -> a -> a
incr_to_cps :: forall a. Fractional a => a -> a -> a -> a
incr_to_cps a
sr a
r a
ic = a
ic a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
r a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
sr)

-- | Pan2 function, identity is linear, sqrt is equal power.
pan2_f :: Fractional t => (t -> t) -> t -> t -> (t, t)
pan2_f :: forall t. Fractional t => (t -> t) -> t -> t -> (t, t)
pan2_f t -> t
f t
p t
q =
  let q' :: t
q' = (t
q t -> t -> t
forall a. Fractional a => a -> a -> a
/ t
2) t -> t -> t
forall a. Num a => a -> a -> a
+ t
0.5
  in (t
p t -> t -> t
forall a. Num a => a -> a -> a
* t -> t
f (t
1 t -> t -> t
forall a. Num a => a -> a -> a
- t
q'), t
p t -> t -> t
forall a. Num a => a -> a -> a
* t -> t
f t
q')

{- | Linear pan.

>>> map (lin_pan2 1) [-1,-0.5,0,0.5,1]
[(1.0,0.0),(0.75,0.25),(0.5,0.5),(0.25,0.75),(0.0,1.0)]
-}
lin_pan2 :: Fractional t => t -> t -> (t, t)
lin_pan2 :: forall t. Fractional t => t -> t -> (t, t)
lin_pan2 = (t -> t) -> t -> t -> (t, t)
forall t. Fractional t => (t -> t) -> t -> t -> (t, t)
pan2_f t -> t
forall a. a -> a
id

{- | Equal power pan.

>>> map (eq_pan2 1) [-1,-0.5,0,0.5,1]
[(1.0,0.0),(0.8660254037844386,0.5),(0.7071067811865476,0.7071067811865476),(0.5,0.8660254037844386),(0.0,1.0)]
-}
eq_pan2 :: Floating t => t -> t -> (t, t)
eq_pan2 :: forall t. Floating t => t -> t -> (t, t)
eq_pan2 = (t -> t) -> t -> t -> (t, t)
forall t. Fractional t => (t -> t) -> t -> t -> (t, t)
pan2_f t -> t
forall a. Floating a => a -> a
sqrt

-- | 'fromInteger' of 'properFraction'.
sc3_properFraction :: RealFrac t => t -> (t, t)
sc3_properFraction :: forall t. RealFrac t => t -> (t, t)
sc3_properFraction t
a =
  let (Integer
p, t
q) = t -> (Integer, t)
forall b. Integral b => t -> (b, t)
forall a b. (RealFrac a, Integral b) => a -> (b, a)
properFraction t
a
  in (Integer -> t
forall a. Num a => Integer -> a
fromInteger Integer
p, t
q)

-- | a^2 - b^2.
sc3_dif_sqr :: Num a => a -> a -> a
sc3_dif_sqr :: forall a. Num a => a -> a -> a
sc3_dif_sqr a
a a
b = (a
a a -> a -> a
forall a. Num a => a -> a -> a
* a
a) a -> a -> a
forall a. Num a => a -> a -> a
- (a
b a -> a -> a
forall a. Num a => a -> a -> a
* a
b)

-- | Euclidean distance function ('sqrt' of sum of squares).
sc3_hypot :: Floating a => a -> a -> a
sc3_hypot :: forall a. Floating a => a -> a -> a
sc3_hypot a
x a
y = a -> a
forall a. Floating a => a -> a
sqrt (a
x a -> a -> a
forall a. Num a => a -> a -> a
* a
x a -> a -> a
forall a. Num a => a -> a -> a
+ a
y a -> a -> a
forall a. Num a => a -> a -> a
* a
y)

-- | Sc3 hypotenuse approximation function.
sc3_hypotx :: (Ord a, Floating a) => a -> a -> a
sc3_hypotx :: forall a. (Ord a, Floating a) => a -> a -> a
sc3_hypotx a
x a
y = a -> a
forall a. Num a => a -> a
abs a
x a -> a -> a
forall a. Num a => a -> a -> a
+ a -> a
forall a. Num a => a -> a
abs a
y a -> a -> a
forall a. Num a => a -> a -> a
- ((a -> a
forall a. Floating a => a -> a
sqrt a
2 a -> a -> a
forall a. Num a => a -> a -> a
- a
1) a -> a -> a
forall a. Num a => a -> a -> a
* a -> a -> a
forall a. Ord a => a -> a -> a
min (a -> a
forall a. Num a => a -> a
abs a
x) (a -> a
forall a. Num a => a -> a
abs a
y))

{- | Fold /k/ to within range /(i,j)/, ie. @AbstractFunction.fold@

>>> map (foldToRange 5 10) [3..12]
[7,6,5,6,7,8,9,10,9,8]
-}
foldToRange :: (Ord a, Num a) => a -> a -> a -> a
foldToRange :: forall a. (Ord a, Num a) => a -> a -> a -> a
foldToRange a
i a
j =
  let f :: a -> a
f a
n =
        if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
j
          then a -> a
f (a
j a -> a -> a
forall a. Num a => a -> a -> a
- (a
n a -> a -> a
forall a. Num a => a -> a -> a
- a
j))
          else
            if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
i
              then a -> a
f (a
i a -> a -> a
forall a. Num a => a -> a -> a
- (a
n a -> a -> a
forall a. Num a => a -> a -> a
- a
i))
              else a
n
  in a -> a
f

-- | Variant of 'foldToRange' with @Sc3@ argument ordering.
sc3_fold :: (Ord a, Num a) => a -> a -> a -> a
sc3_fold :: forall a. (Ord a, Num a) => a -> a -> a -> a
sc3_fold a
n a
i a
j = a -> a -> a -> a
forall a. (Ord a, Num a) => a -> a -> a -> a
foldToRange a
i a
j a
n

-- | Sc3 distort operator.
sc3_distort :: Fractional n => n -> n
sc3_distort :: forall n. Fractional n => n -> n
sc3_distort n
x = n
x n -> n -> n
forall a. Fractional a => a -> a -> a
/ (n
1 n -> n -> n
forall a. Num a => a -> a -> a
+ n -> n
forall a. Num a => a -> a
abs n
x)

-- | Sc3 softclip operator.
sc3_softclip :: (Ord n, Fractional n) => n -> n
sc3_softclip :: forall n. (Ord n, Fractional n) => n -> n
sc3_softclip n
x = let x' :: n
x' = n -> n
forall a. Num a => a -> a
abs n
x in if n
x' n -> n -> Bool
forall a. Ord a => a -> a -> Bool
<= n
0.5 then n
x else (n
x' n -> n -> n
forall a. Num a => a -> a -> a
- n
0.25) n -> n -> n
forall a. Fractional a => a -> a -> a
/ n
x

-- * Bool

-- | True is conventionally 1.  The test to determine true is @> 0@.
sc3_true :: Num n => n
sc3_true :: forall n. Num n => n
sc3_true = n
1

-- | False is conventionally 0.  The test to determine true is @<= 0@.
sc3_false :: Num n => n
sc3_false :: forall n. Num n => n
sc3_false = n
0

{- | Lifted 'not'.

>>> sc3_not sc3_true == sc3_false
True

>>> sc3_not sc3_false == sc3_true
True
-}
sc3_not :: (Ord n, Num n) => n -> n
sc3_not :: forall n. (Ord n, Num n) => n -> n
sc3_not = Bool -> n
forall n. Num n => Bool -> n
sc3_bool (Bool -> n) -> (n -> Bool) -> n -> n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n -> n -> Bool
forall a. Ord a => a -> a -> Bool
<= n
0)

-- | Translate 'Bool' to 'sc3_true' and 'sc3_false'.
sc3_bool :: Num n => Bool -> n
sc3_bool :: forall n. Num n => Bool -> n
sc3_bool Bool
b = if Bool
b then n
forall n. Num n => n
sc3_true else n
forall n. Num n => n
sc3_false

-- | Lift comparison function.
sc3_comparison :: Num n => (n -> n -> Bool) -> n -> n -> n
sc3_comparison :: forall n. Num n => (n -> n -> Bool) -> n -> n -> n
sc3_comparison n -> n -> Bool
f n
p n
q = Bool -> n
forall n. Num n => Bool -> n
sc3_bool (n -> n -> Bool
f n
p n
q)

-- * Eq

-- | Lifted '=='.
sc3_eq :: (Num n, Eq n) => n -> n -> n
sc3_eq :: forall n. (Num n, Eq n) => n -> n -> n
sc3_eq = (n -> n -> Bool) -> n -> n -> n
forall n. Num n => (n -> n -> Bool) -> n -> n -> n
sc3_comparison n -> n -> Bool
forall a. Eq a => a -> a -> Bool
(==)

-- | Lifted '/='.
sc3_neq :: (Num n, Eq n) => n -> n -> n
sc3_neq :: forall n. (Num n, Eq n) => n -> n -> n
sc3_neq = (n -> n -> Bool) -> n -> n -> n
forall n. Num n => (n -> n -> Bool) -> n -> n -> n
sc3_comparison n -> n -> Bool
forall a. Eq a => a -> a -> Bool
(/=)

-- * Ord

-- | Lifted '<'.
sc3_lt :: (Num n, Ord n) => n -> n -> n
sc3_lt :: forall n. (Num n, Ord n) => n -> n -> n
sc3_lt = (n -> n -> Bool) -> n -> n -> n
forall n. Num n => (n -> n -> Bool) -> n -> n -> n
sc3_comparison n -> n -> Bool
forall a. Ord a => a -> a -> Bool
(<)

-- | Lifted '<='.
sc3_lte :: (Num n, Ord n) => n -> n -> n
sc3_lte :: forall n. (Num n, Ord n) => n -> n -> n
sc3_lte = (n -> n -> Bool) -> n -> n -> n
forall n. Num n => (n -> n -> Bool) -> n -> n -> n
sc3_comparison n -> n -> Bool
forall a. Ord a => a -> a -> Bool
(<=)

-- | Lifted '>'.
sc3_gt :: (Num n, Ord n) => n -> n -> n
sc3_gt :: forall n. (Num n, Ord n) => n -> n -> n
sc3_gt = (n -> n -> Bool) -> n -> n -> n
forall n. Num n => (n -> n -> Bool) -> n -> n -> n
sc3_comparison n -> n -> Bool
forall a. Ord a => a -> a -> Bool
(>)

-- | Lifted '>='.
sc3_gte :: (Num n, Ord n) => n -> n -> n
sc3_gte :: forall n. (Num n, Ord n) => n -> n -> n
sc3_gte = (n -> n -> Bool) -> n -> n -> n
forall n. Num n => (n -> n -> Bool) -> n -> n -> n
sc3_comparison n -> n -> Bool
forall a. Ord a => a -> a -> Bool
(>=)

-- * Clip Rule

-- | Enumeration of clipping rules.
data Clip_Rule = Clip_None | Clip_Left | Clip_Right | Clip_Both
  deriving (Int -> Clip_Rule
Clip_Rule -> Int
Clip_Rule -> [Clip_Rule]
Clip_Rule -> Clip_Rule
Clip_Rule -> Clip_Rule -> [Clip_Rule]
Clip_Rule -> Clip_Rule -> Clip_Rule -> [Clip_Rule]
(Clip_Rule -> Clip_Rule)
-> (Clip_Rule -> Clip_Rule)
-> (Int -> Clip_Rule)
-> (Clip_Rule -> Int)
-> (Clip_Rule -> [Clip_Rule])
-> (Clip_Rule -> Clip_Rule -> [Clip_Rule])
-> (Clip_Rule -> Clip_Rule -> [Clip_Rule])
-> (Clip_Rule -> Clip_Rule -> Clip_Rule -> [Clip_Rule])
-> Enum Clip_Rule
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: Clip_Rule -> Clip_Rule
succ :: Clip_Rule -> Clip_Rule
$cpred :: Clip_Rule -> Clip_Rule
pred :: Clip_Rule -> Clip_Rule
$ctoEnum :: Int -> Clip_Rule
toEnum :: Int -> Clip_Rule
$cfromEnum :: Clip_Rule -> Int
fromEnum :: Clip_Rule -> Int
$cenumFrom :: Clip_Rule -> [Clip_Rule]
enumFrom :: Clip_Rule -> [Clip_Rule]
$cenumFromThen :: Clip_Rule -> Clip_Rule -> [Clip_Rule]
enumFromThen :: Clip_Rule -> Clip_Rule -> [Clip_Rule]
$cenumFromTo :: Clip_Rule -> Clip_Rule -> [Clip_Rule]
enumFromTo :: Clip_Rule -> Clip_Rule -> [Clip_Rule]
$cenumFromThenTo :: Clip_Rule -> Clip_Rule -> Clip_Rule -> [Clip_Rule]
enumFromThenTo :: Clip_Rule -> Clip_Rule -> Clip_Rule -> [Clip_Rule]
Enum, Clip_Rule
Clip_Rule -> Clip_Rule -> Bounded Clip_Rule
forall a. a -> a -> Bounded a
$cminBound :: Clip_Rule
minBound :: Clip_Rule
$cmaxBound :: Clip_Rule
maxBound :: Clip_Rule
Bounded)

{- | Clip a value that is expected to be within an input range to an output range, according to a rule.

>>> let f r = map (\x -> apply_clip_rule r 0 1 (-1) 1 x) [-1,0,0.5,1,2]
>>> map f [minBound .. maxBound]
[[Nothing,Nothing,Nothing,Nothing,Nothing],[Just (-1.0),Just (-1.0),Nothing,Nothing,Nothing],[Nothing,Nothing,Nothing,Just 1.0,Just 1.0],[Just (-1.0),Just (-1.0),Nothing,Just 1.0,Just 1.0]]
-}
apply_clip_rule :: Ord n => Clip_Rule -> n -> n -> n -> n -> n -> Maybe n
apply_clip_rule :: forall n. Ord n => Clip_Rule -> n -> n -> n -> n -> n -> Maybe n
apply_clip_rule Clip_Rule
clip_rule n
sl n
sr n
dl n
dr n
x =
  case Clip_Rule
clip_rule of
    Clip_Rule
Clip_None -> Maybe n
forall a. Maybe a
Nothing
    Clip_Rule
Clip_Left -> if n
x n -> n -> Bool
forall a. Ord a => a -> a -> Bool
<= n
sl then n -> Maybe n
forall a. a -> Maybe a
Just n
dl else Maybe n
forall a. Maybe a
Nothing
    Clip_Rule
Clip_Right -> if n
x n -> n -> Bool
forall a. Ord a => a -> a -> Bool
>= n
sr then n -> Maybe n
forall a. a -> Maybe a
Just n
dr else Maybe n
forall a. Maybe a
Nothing
    Clip_Rule
Clip_Both -> if n
x n -> n -> Bool
forall a. Ord a => a -> a -> Bool
<= n
sl then n -> Maybe n
forall a. a -> Maybe a
Just n
dl else if n
x n -> n -> Bool
forall a. Ord a => a -> a -> Bool
>= n
sr then n -> Maybe n
forall a. a -> Maybe a
Just n
dr else Maybe n
forall a. Maybe a
Nothing

-- * LinLin

-- | Scale uni-polar (0,1) input to linear (l,r) range.
urange_ma :: Fractional a => Sc3_MulAdd a -> a -> a -> a -> a
urange_ma :: forall a. Fractional a => Sc3_MulAdd a -> Sc3_MulAdd a
urange_ma Sc3_MulAdd a
mul_add_f a
l a
r a
i = Sc3_MulAdd a
mul_add_f a
i (a
r a -> a -> a
forall a. Num a => a -> a -> a
- a
l) a
l

{- | Scale (0,1) input to linear (l,r) range. u = uni-polar.

>>> map (urange 3 4) [0,0.5,1]
[3.0,3.5,4.0]
-}
urange :: Fractional a => a -> a -> a -> a
urange :: forall a. Fractional a => a -> a -> a -> a
urange = Sc3_MulAdd a -> Sc3_MulAdd a
forall a. Fractional a => Sc3_MulAdd a -> Sc3_MulAdd a
urange_ma Sc3_MulAdd a
forall t. Num t => Sc3_MulAdd t
sc3_mul_add

{- | Calculate multiplier and add values for (-1,1) 'range' transform.

>>> range_muladd 3 4
(0.5,3.5)
-}
range_muladd :: Fractional t => t -> t -> (t, t)
range_muladd :: forall t. Fractional t => t -> t -> (t, t)
range_muladd = t -> t -> t -> t -> (t, t)
forall t. Fractional t => t -> t -> t -> t -> (t, t)
linlin_muladd (-t
1) t
1

{- | Scale bi-polar (-1,1) input to linear (l,r) range.
Note that the argument order is not the same as 'linLin'.
-}
range_ma :: Fractional a => Sc3_MulAdd a -> a -> a -> a -> a
range_ma :: forall a. Fractional a => Sc3_MulAdd a -> Sc3_MulAdd a
range_ma Sc3_MulAdd a
mul_add_f a
l a
r a
i =
  let (a
m, a
a) = a -> a -> (a, a)
forall t. Fractional t => t -> t -> (t, t)
range_muladd a
l a
r
  in Sc3_MulAdd a
mul_add_f a
i a
m a
a

{- | Scale (-1,1) input to linear (l,r) range.
Note that the argument order is not the same as 'linlin'.
Note also that the various range Ugen methods at sclang select mul-add values given the output range of the Ugen, ie LFPulse.range selects a (0,1) input range.

>>> map (range 3 4) [-1,0,1]
[3.0,3.5,4.0]

>>> map (\x -> let (m,a) = linlin_muladd (-1) 1 3 4 in x * m + a) [-1,0,1]
[3.0,3.5,4.0]
-}
range :: Fractional a => a -> a -> a -> a
range :: forall a. Fractional a => a -> a -> a -> a
range = Sc3_MulAdd a -> Sc3_MulAdd a
forall a. Fractional a => Sc3_MulAdd a -> Sc3_MulAdd a
range_ma Sc3_MulAdd a
forall t. Num t => Sc3_MulAdd t
sc3_mul_add

-- | 'uncurry' 'range'
range_hs :: Fractional a => (a, a) -> a -> a
range_hs :: forall a. Fractional a => (a, a) -> a -> a
range_hs = (a -> a -> a -> a) -> (a, a) -> a -> a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry a -> a -> a -> a
forall a. Fractional a => a -> a -> a -> a
range

-- | 'flip' 'range_hs'.  This allows cases such as osc `in_range` (0,1)
in_range :: Fractional a => a -> (a, a) -> a
in_range :: forall a. Fractional a => a -> (a, a) -> a
in_range = ((a, a) -> a -> a) -> a -> (a, a) -> a
forall a b c. (a -> b -> c) -> b -> a -> c
flip (a, a) -> a -> a
forall a. Fractional a => (a, a) -> a -> a
range_hs

{- | Calculate multiplier and add values for 'linlin' transform.
Inputs are: input-min input-max output-min output-max

>>> range_muladd 3 4
(0.5,3.5)

>>> linlin_muladd (-1) 1 3 4
(0.5,3.5)

>>> linlin_muladd 0 1 3 4
(1.0,3.0)

>>> linlin_muladd (-1) 1 0 1
(0.5,0.5)

>>> linlin_muladd (-0.3) 1 (-1) 1
(1.5384615384615383,-0.5384615384615385)
-}
linlin_muladd :: Fractional t => t -> t -> t -> t -> (t, t)
linlin_muladd :: forall t. Fractional t => t -> t -> t -> t -> (t, t)
linlin_muladd t
sl t
sr t
dl t
dr =
  let m :: t
m = (t
dr t -> t -> t
forall a. Num a => a -> a -> a
- t
dl) t -> t -> t
forall a. Fractional a => a -> a -> a
/ (t
sr t -> t -> t
forall a. Num a => a -> a -> a
- t
sl)
      a :: t
a = t
dl t -> t -> t
forall a. Num a => a -> a -> a
- (t
m t -> t -> t
forall a. Num a => a -> a -> a
* t
sl)
  in (t
m, t
a)

{- | Map from one linear range to another linear range.

>>> linlin_ma sc3_mul_add 5 0 10 (-1) 1
0.0
-}
linlin_ma :: Fractional a => Sc3_MulAdd a -> a -> a -> a -> a -> a -> a
linlin_ma :: forall a. Fractional a => Sc3_MulAdd a -> a -> a -> Sc3_MulAdd a
linlin_ma Sc3_MulAdd a
mul_add_f a
i a
sl a
sr a
dl a
dr =
  let (a
m, a
a) = a -> a -> a -> a -> (a, a)
forall t. Fractional t => t -> t -> t -> t -> (t, t)
linlin_muladd a
sl a
sr a
dl a
dr
  in Sc3_MulAdd a
mul_add_f a
i a
m a
a

{- | 'linLin' with a more typical haskell argument structure, ranges as pairs and input last.

>>> map (linlin_hs (0,127) (-0.5,0.5)) [0,63.5,127]
[-0.5,0.0,0.5]
-}
linlin_hs :: Fractional a => (a, a) -> (a, a) -> a -> a
linlin_hs :: forall a. Fractional a => (a, a) -> (a, a) -> a -> a
linlin_hs (a
sl, a
sr) (a
dl, a
dr) = let (a
m, a
a) = a -> a -> a -> a -> (a, a)
forall t. Fractional t => t -> t -> t -> t -> (t, t)
linlin_muladd a
sl a
sr a
dl a
dr in (a -> a -> a
forall a. Num a => a -> a -> a
+ a
a) (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a -> a
forall a. Num a => a -> a -> a
* a
m)

{- | Map from one linear range to another linear range.

>>> map (\i -> sc3_linlin i (-1) 1 0 1) [-1,-0.75 .. 1]
[0.0,0.125,0.25,0.375,0.5,0.625,0.75,0.875,1.0]
-}
sc3_linlin :: Fractional a => a -> a -> a -> a -> a -> a
sc3_linlin :: forall a. Fractional a => a -> a -> a -> a -> a -> a
sc3_linlin a
i a
sl a
sr a
dl a
dr = (a, a) -> (a, a) -> a -> a
forall a. Fractional a => (a, a) -> (a, a) -> a -> a
linlin_hs (a
sl, a
sr) (a
dl, a
dr) a
i

{- | Given enumeration from /dst/ that is in the same relation as /n/ is from /src/.

>>> linlin_enum_plain 'a' 'A' 'e'
'E'

>>> linlin_enum_plain 0 (-50) 16
-34

>>> linlin_enum_plain 0 (-50) (-1)
-51
-}
linlin_enum_plain :: (Enum t, Enum u) => t -> u -> t -> u
linlin_enum_plain :: forall t u. (Enum t, Enum u) => t -> u -> t -> u
linlin_enum_plain t
src u
dst t
n = Int -> u
forall a. Enum a => Int -> a
toEnum (u -> Int
forall a. Enum a => a -> Int
fromEnum u
dst Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (t -> Int
forall a. Enum a => a -> Int
fromEnum t
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- t -> Int
forall a. Enum a => a -> Int
fromEnum t
src))

{- | Variant of 'linlin_enum_plain' that requires /src/ and /dst/ ranges to be of equal size,
-- and for /n/ to lie in /src/.

>>> linlin_enum (0,100) (-50,50) 0x10 -- 16
Just (-34)

>>> linlin_enum (-50,50) (0,100) (-34)
Just 16

>>> linlin_enum (0,100) (-50,50) (-1)
Nothing
-}
linlin_enum :: (Enum t, Enum u) => (t, t) -> (u, u) -> t -> Maybe u
linlin_enum :: forall t u. (Enum t, Enum u) => (t, t) -> (u, u) -> t -> Maybe u
linlin_enum (t
l, t
r) (u
l', u
r') t
n =
  if t -> Int
forall a. Enum a => a -> Int
fromEnum t
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= t -> Int
forall a. Enum a => a -> Int
fromEnum t
l Bool -> Bool -> Bool
&& t -> Int
forall a. Enum a => a -> Int
fromEnum t
r Int -> Int -> Int
forall a. Num a => a -> a -> a
- t -> Int
forall a. Enum a => a -> Int
fromEnum t
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== u -> Int
forall a. Enum a => a -> Int
fromEnum u
r' Int -> Int -> Int
forall a. Num a => a -> a -> a
- u -> Int
forall a. Enum a => a -> Int
fromEnum u
l'
    then u -> Maybe u
forall a. a -> Maybe a
Just (t -> u -> t -> u
forall t u. (Enum t, Enum u) => t -> u -> t -> u
linlin_enum_plain t
l u
l' t
n)
    else Maybe u
forall a. Maybe a
Nothing

-- | Erroring variant.
linlin_enum_err :: (Enum t, Enum u) => (t, t) -> (u, u) -> t -> u
linlin_enum_err :: forall t u. (Enum t, Enum u) => (t, t) -> (u, u) -> t -> u
linlin_enum_err (t, t)
src (u, u)
dst = u -> Maybe u -> u
forall a. a -> Maybe a -> a
fromMaybe ([Char] -> u
forall a. HasCallStack => [Char] -> a
error [Char]
"linlin_enum") (Maybe u -> u) -> (t -> Maybe u) -> t -> u
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (t, t) -> (u, u) -> t -> Maybe u
forall t u. (Enum t, Enum u) => (t, t) -> (u, u) -> t -> Maybe u
linlin_enum (t, t)
src (u, u)
dst

{- | Variant of 'linlin' that requires /src/ and /dst/ ranges to be of
-- equal size, thus with constraint of 'Num' and 'Eq' instead of
-- 'Fractional'.

>>> linlin_eq (0,100) (-50,50) 0x10 -- 16
Just (-34)

>>> linlin_eq (-50,50) (0,100) (-34)
Just 16
-}
linlin_eq :: (Eq a, Num a) => (a, a) -> (a, a) -> a -> Maybe a
linlin_eq :: forall a. (Eq a, Num a) => (a, a) -> (a, a) -> a -> Maybe a
linlin_eq (a
l, a
r) (a
l', a
r') a
n =
  let d :: a
d = a
r a -> a -> a
forall a. Num a => a -> a -> a
- a
l
      d' :: a
d' = a
r' a -> a -> a
forall a. Num a => a -> a -> a
- a
l'
  in if a
d a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
d' then a -> Maybe a
forall a. a -> Maybe a
Just (a
l' a -> a -> a
forall a. Num a => a -> a -> a
+ (a
n a -> a -> a
forall a. Num a => a -> a -> a
- a
l)) else Maybe a
forall a. Maybe a
Nothing

-- | Erroring variant.
linlin_eq_err :: (Eq a, Num a) => (a, a) -> (a, a) -> a -> a
linlin_eq_err :: forall a. (Eq a, Num a) => (a, a) -> (a, a) -> a -> a
linlin_eq_err (a, a)
src (a, a)
dst = a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe ([Char] -> a
forall a. HasCallStack => [Char] -> a
error [Char]
"linlin_eq") (Maybe a -> a) -> (a -> Maybe a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a, a) -> (a, a) -> a -> Maybe a
forall a. (Eq a, Num a) => (a, a) -> (a, a) -> a -> Maybe a
linlin_eq (a, a)
src (a, a)
dst

-- * LinExp

{- | Linear to exponential range conversion.
     Rule is as at linExp Ugen, haskell manner argument ordering.
     Destination values must be nonzero and have the same sign.

>>> map (floor . linexp_hs (1,2) (10,100)) [0,1,1.5,2,3]
[1,10,31,100,1000]

>>> map (floor . linexp_hs (-2,2) (1,100)) [-3,-2,-1,0,1,2,3]
[0,1,3,10,31,100,316]
-}
linexp_hs :: Floating a => (a, a) -> (a, a) -> a -> a
linexp_hs :: forall a. Floating a => (a, a) -> (a, a) -> a -> a
linexp_hs (a
in_l, a
in_r) (a
out_l, a
out_r) a
x =
  let rt :: a
rt = a
out_r a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
out_l
      rn :: a
rn = a
1.0 a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
in_r a -> a -> a
forall a. Num a => a -> a -> a
- a
in_l)
      rr :: a
rr = a
rn a -> a -> a
forall a. Num a => a -> a -> a
* a -> a
forall a. Num a => a -> a
negate a
in_l
  in a
out_l a -> a -> a
forall a. Num a => a -> a -> a
* (a
rt a -> a -> a
forall a. Floating a => a -> a -> a
** (a
x a -> a -> a
forall a. Num a => a -> a -> a
* a
rn a -> a -> a
forall a. Num a => a -> a -> a
+ a
rr))

{- | Variant of 'linexp_hs' with argument ordering as at 'linExp' Ugen.

>>> map (\i -> lin_exp i 1 2 1 3) [1,1.1,1.9,2]
[1.0,1.1161231740339046,2.6878753795222865,3.0]

>>> map (\i -> floor (lin_exp i 1 2 10 100)) [0,1,1.5,2,3]
[1,10,31,100,1000]
-}
lin_exp :: Floating a => a -> a -> a -> a -> a -> a
lin_exp :: forall a. Floating a => a -> a -> a -> a -> a -> a
lin_exp a
x a
in_l a
in_r a
out_l a
out_r = (a, a) -> (a, a) -> a -> a
forall a. Floating a => (a, a) -> (a, a) -> a -> a
linexp_hs (a
in_l, a
in_r) (a
out_l, a
out_r) a
x

{- | @SimpleNumber.linexp@ shifts from linear to exponential ranges.

>>> map (sc3_linexp 1 2 1 3) [1,1.1,1.9,2]
[1.0,1.1161231740339046,2.6878753795222865,3.0]

> [1,1.5,2].collect({|i| i.linexp(1,2,10,100).floor}) == [10,31,100]

>>> map (floor . sc3_linexp 1 2 10 100) [0,1,1.5,2,3]
[10,10,31,100,100]
-}
sc3_linexp :: (Ord a, Floating a) => a -> a -> a -> a -> a -> a
sc3_linexp :: forall a. (Ord a, Floating a) => a -> a -> a -> a -> a -> a
sc3_linexp a
src_l a
src_r a
dst_l a
dst_r a
x =
  case Clip_Rule -> a -> a -> a -> a -> a -> Maybe a
forall n. Ord n => Clip_Rule -> n -> n -> n -> n -> n -> Maybe n
apply_clip_rule Clip_Rule
Clip_Both a
src_l a
src_r a
dst_l a
dst_r a
x of
    Just a
r -> a
r
    Maybe a
Nothing -> ((a
dst_r a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
dst_l) a -> a -> a
forall a. Floating a => a -> a -> a
** ((a
x a -> a -> a
forall a. Num a => a -> a -> a
- a
src_l) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
src_r a -> a -> a
forall a. Num a => a -> a -> a
- a
src_l))) a -> a -> a
forall a. Num a => a -> a -> a
* a
dst_l

{- | @SimpleNumber.explin@ is the inverse of linexp.

>>> map (sc3_explin 10 100 1 2) [10,10,31,100,100]
[1.0,1.0,1.4913616938342726,2.0,2.0]
-}
sc3_explin :: (Ord a, Floating a) => a -> a -> a -> a -> a -> a
sc3_explin :: forall a. (Ord a, Floating a) => a -> a -> a -> a -> a -> a
sc3_explin a
src_l a
src_r a
dst_l a
dst_r a
x =
  a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe
    (a -> a -> a
forall a. Floating a => a -> a -> a
logBase (a
src_r a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
src_l) (a
x a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
src_l) a -> a -> a
forall a. Num a => a -> a -> a
* (a
dst_r a -> a -> a
forall a. Num a => a -> a -> a
- a
dst_l) a -> a -> a
forall a. Num a => a -> a -> a
+ a
dst_l)
    (Clip_Rule -> a -> a -> a -> a -> a -> Maybe a
forall n. Ord n => Clip_Rule -> n -> n -> n -> n -> n -> Maybe n
apply_clip_rule Clip_Rule
Clip_Both a
src_l a
src_r a
dst_l a
dst_r a
x)

-- * ExpExp

{- | Translate from one exponential range to another.

>>> map (round . sc3_expexp 0.1 10 4.3 100) [1 .. 10]
[21,33,44,53,62,71,78,86,93,100]
-}
sc3_expexp :: (Ord a, Floating a) => a -> a -> a -> a -> a -> a
sc3_expexp :: forall a. (Ord a, Floating a) => a -> a -> a -> a -> a -> a
sc3_expexp a
src_l a
src_r a
dst_l a
dst_r a
x =
  a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe
    ((a
dst_r a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
dst_l) a -> a -> a
forall a. Floating a => a -> a -> a
** a -> a -> a
forall a. Floating a => a -> a -> a
logBase (a
src_r a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
src_l) (a
x a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
src_l) a -> a -> a
forall a. Num a => a -> a -> a
* a
dst_l)
    (Clip_Rule -> a -> a -> a -> a -> a -> Maybe a
forall n. Ord n => Clip_Rule -> n -> n -> n -> n -> n -> Maybe n
apply_clip_rule Clip_Rule
Clip_Both a
src_l a
src_r a
dst_l a
dst_r a
x)

-- * LinCurve

{- | Map /x/ from an assumed linear input range (src_l,src_r) to an
exponential curve output range (dst_l,dst_r). 'curve' is like the
parameter in Env.  Unlike with linexp, the output range may include
zero.

> (0..10).lincurve(0,10,-4.3,100,-3).round == [-4,24,45,61,72,81,87,92,96,98,100]

>>> let f = round . sc3_lincurve (-3) 0 10 (-4.3) 100
>>> map f [0 .. 10]
[-4,24,45,61,72,81,87,92,96,98,100]

> import Sound.Sc3.Plot {\- hsc3-plot -\}
> plotTable (map (\c-> map (sc3_lincurve c 0 1 (-1) 1) [0,0.01 .. 1]) [-6,-4 .. 6])
-}
sc3_lincurve :: (Ord a, Floating a) => a -> a -> a -> a -> a -> a -> a
sc3_lincurve :: forall a. (Ord a, Floating a) => a -> a -> a -> a -> a -> a -> a
sc3_lincurve a
curve a
src_l a
src_r a
dst_l a
dst_r a
x =
  case Clip_Rule -> a -> a -> a -> a -> a -> Maybe a
forall n. Ord n => Clip_Rule -> n -> n -> n -> n -> n -> Maybe n
apply_clip_rule Clip_Rule
Clip_Both a
src_l a
src_r a
dst_l a
dst_r a
x of
    Just a
r -> a
r
    Maybe a
Nothing ->
      if a -> a
forall a. Num a => a -> a
abs a
curve a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0.001
        then (a, a) -> (a, a) -> a -> a
forall a. Fractional a => (a, a) -> (a, a) -> a -> a
linlin_hs (a
src_l, a
src_r) (a
dst_l, a
dst_r) a
x
        else
          let grow :: a
grow = a -> a
forall a. Floating a => a -> a
exp a
curve
              a :: a
a = (a
dst_r a -> a -> a
forall a. Num a => a -> a -> a
- a
dst_l) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
1.0 a -> a -> a
forall a. Num a => a -> a -> a
- a
grow)
              b :: a
b = a
dst_l a -> a -> a
forall a. Num a => a -> a -> a
+ a
a
              scaled :: a
scaled = (a
x a -> a -> a
forall a. Num a => a -> a -> a
- a
src_l) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
src_r a -> a -> a
forall a. Num a => a -> a -> a
- a
src_l)
          in a
b a -> a -> a
forall a. Num a => a -> a -> a
- (a
a a -> a -> a
forall a. Num a => a -> a -> a
* (a
grow a -> a -> a
forall a. Floating a => a -> a -> a
** a
scaled))

{- | Inverse of 'sc3_lincurve'.

>>> let f = round . sc3_curvelin (-3) (-4.3) 100 0 10
>>> map f [-4,24,45,61,72,81,87,92,96,98,100] == [0..10]
True
-}
sc3_curvelin :: (Ord a, Floating a) => a -> a -> a -> a -> a -> a -> a
sc3_curvelin :: forall a. (Ord a, Floating a) => a -> a -> a -> a -> a -> a -> a
sc3_curvelin a
curve a
src_l a
src_r a
dst_l a
dst_r a
x =
  case Clip_Rule -> a -> a -> a -> a -> a -> Maybe a
forall n. Ord n => Clip_Rule -> n -> n -> n -> n -> n -> Maybe n
apply_clip_rule Clip_Rule
Clip_Both a
src_l a
src_r a
dst_l a
dst_r a
x of
    Just a
r -> a
r
    Maybe a
Nothing ->
      if a -> a
forall a. Num a => a -> a
abs a
curve a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0.001
        then (a, a) -> (a, a) -> a -> a
forall a. Fractional a => (a, a) -> (a, a) -> a -> a
linlin_hs (a
src_l, a
src_r) (a
dst_l, a
dst_r) a
x
        else
          let grow :: a
grow = a -> a
forall a. Floating a => a -> a
exp a
curve
              a :: a
a = (a
src_r a -> a -> a
forall a. Num a => a -> a -> a
- a
src_l) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
1.0 a -> a -> a
forall a. Num a => a -> a -> a
- a
grow)
              b :: a
b = a
src_l a -> a -> a
forall a. Num a => a -> a -> a
+ a
a
          in a -> a
forall a. Floating a => a -> a
log ((a
b a -> a -> a
forall a. Num a => a -> a -> a
- a
x) a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
a) a -> a -> a
forall a. Num a => a -> a -> a
* (a
dst_r a -> a -> a
forall a. Num a => a -> a -> a
- a
dst_l) a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
curve a -> a -> a
forall a. Num a => a -> a -> a
+ a
dst_l

-- * Pp (pretty print)

-- | Removes all but the last trailing zero from floating point string.
double_pp_rm0 :: String -> String
double_pp_rm0 :: [Char] -> [Char]
double_pp_rm0 =
  let rev_f :: ([a] -> [a]) -> [a] -> [a]
rev_f [a] -> [a]
f = [a] -> [a]
forall a. [a] -> [a]
reverse ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
f ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
forall a. [a] -> [a]
reverse
      remv :: [Char] -> [Char]
remv [Char]
l = case [Char]
l of
        Char
'0' : Char
'.' : [Char]
_ -> [Char]
l
        Char
'0' : [Char]
l' -> [Char] -> [Char]
remv [Char]
l'
        [Char]
_ -> [Char]
l
  in ([Char] -> [Char]) -> [Char] -> [Char]
forall {a} {a}. ([a] -> [a]) -> [a] -> [a]
rev_f [Char] -> [Char]
remv

{- | The default show is odd, 0.05 shows as 5.0e-2.

>>> unwords (map (double_pp 4) [0.0001,0.001,0.01,0.1,1.0])
"0.0001 0.001 0.01 0.1 1.0"
-}
double_pp :: Int -> Double -> String
double_pp :: Int -> Double -> [Char]
double_pp Int
k Double
n = [Char] -> [Char]
double_pp_rm0 (Maybe Int -> Double -> [Char] -> [Char]
forall a. RealFloat a => Maybe Int -> a -> [Char] -> [Char]
Numeric.showFFloat (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
k) Double
n [Char]
"")

{- | Print as integer if integral, else as real.

>>> unwords (map (real_pp 5) [0.0001,0.001,0.01,0.1,1.0])
"0.0001 0.001 0.01 0.1 1"
-}
real_pp :: Int -> Double -> String
real_pp :: Int -> Double -> [Char]
real_pp Int
k Double
n =
  let r :: Rational
r = Double -> Rational
forall a. Real a => a -> Rational
toRational Double
n
  in if Rational -> Integer
forall a. Ratio a -> a
denominator Rational
r Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
1 then Integer -> [Char]
forall a. Show a => a -> [Char]
show (Rational -> Integer
forall a. Ratio a -> a
numerator Rational
r) else Int -> Double -> [Char]
double_pp Int
k Double
n

-- * Parser

-- | Type-specialised 'Text.Read.readMaybe'.
parse_double :: String -> Maybe Double
parse_double :: [Char] -> Maybe Double
parse_double = [Char] -> Maybe Double
forall a. Read a => [Char] -> Maybe a
Common.Base.reads_exact

-- * Optimiser

-- | Non-specialised optimised sum function (3 & 4 element adders).
sum_opt_f :: Num t => (t -> t -> t -> t) -> (t -> t -> t -> t -> t) -> [t] -> t
sum_opt_f :: forall t.
Num t =>
(t -> t -> t -> t) -> (t -> t -> t -> t -> t) -> [t] -> t
sum_opt_f t -> t -> t -> t
f3 t -> t -> t -> t -> t
f4 =
  let recur :: [t] -> t
recur [t]
l =
        case [t]
l of
          t
p : t
q : t
r : t
s : [t]
l' -> [t] -> t
recur (t -> t -> t -> t -> t
f4 t
p t
q t
r t
s t -> [t] -> [t]
forall a. a -> [a] -> [a]
: [t]
l')
          t
p : t
q : t
r : [t]
l' -> [t] -> t
recur (t -> t -> t -> t
f3 t
p t
q t
r t -> [t] -> [t]
forall a. a -> [a] -> [a]
: [t]
l')
          [t]
_ -> [t] -> t
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [t]
l
  in [t] -> t
recur

-- * Sin

{- | Taylor approximation of sin, (-pi, pi).

> import Sound.Sc3.Plot
> let xs = [-pi, -pi + 0.05 .. pi] in plot_p1_ln [map sin_taylor_approximation xs, map sin xs]
> let xs = [-pi, -pi + 0.05 .. pi] in plot_p1_ln [map (\x -> sin_taylor_approximation x - sin x) xs]
-}
sin_taylor_approximation :: Floating a => a -> a
sin_taylor_approximation :: forall a. Floating a => a -> a
sin_taylor_approximation a
x = a
x a -> a -> a
forall a. Num a => a -> a -> a
- (a
x a -> a -> a
forall a. Floating a => a -> a -> a
** a
3) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
3 a -> a -> a
forall a. Num a => a -> a -> a
* a
2) a -> a -> a
forall a. Num a => a -> a -> a
+ (a
x a -> a -> a
forall a. Floating a => a -> a -> a
** a
5) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
5 a -> a -> a
forall a. Num a => a -> a -> a
* a
4 a -> a -> a
forall a. Num a => a -> a -> a
* a
3 a -> a -> a
forall a. Num a => a -> a -> a
* a
2) a -> a -> a
forall a. Num a => a -> a -> a
- (a
x a -> a -> a
forall a. Floating a => a -> a -> a
** a
7) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
7 a -> a -> a
forall a. Num a => a -> a -> a
* a
6 a -> a -> a
forall a. Num a => a -> a -> a
* a
5 a -> a -> a
forall a. Num a => a -> a -> a
* a
4 a -> a -> a
forall a. Num a => a -> a -> a
* a
3 a -> a -> a
forall a. Num a => a -> a -> a
* a
2) a -> a -> a
forall a. Num a => a -> a -> a
+ (a
x a -> a -> a
forall a. Floating a => a -> a -> a
** a
9) a -> a -> a
forall a. Fractional a => a -> a -> a
/ (a
9 a -> a -> a
forall a. Num a => a -> a -> a
* a
8 a -> a -> a
forall a. Num a => a -> a -> a
* a
7 a -> a -> a
forall a. Num a => a -> a -> a
* a
6 a -> a -> a
forall a. Num a => a -> a -> a
* a
5 a -> a -> a
forall a. Num a => a -> a -> a
* a
4 a -> a -> a
forall a. Num a => a -> a -> a
* a
3 a -> a -> a
forall a. Num a => a -> a -> a
* a
2)

{- | Bhaskara approximation of sin, (0, pi).

> import Sound.Sc3.Plot
> let xs = [0, 0.05 .. pi] in plot_p1_ln [map sin_bhaskara_approximation xs, map sin xs]
> let xs = [0, 0.05 .. pi] in plot_p1_ln [map (\x -> sin_bhaskara_approximation x - sin x) xs]
-}
sin_bhaskara_approximation :: Floating a => a -> a
sin_bhaskara_approximation :: forall a. Floating a => a -> a
sin_bhaskara_approximation a
x = (a
16 a -> a -> a
forall a. Num a => a -> a -> a
* a
x a -> a -> a
forall a. Num a => a -> a -> a
* (a
forall a. Floating a => a
pi a -> a -> a
forall a. Num a => a -> a -> a
- a
x)) a -> a -> a
forall a. Fractional a => a -> a -> a
/ ((a
5 a -> a -> a
forall a. Num a => a -> a -> a
* a
forall a. Floating a => a
pi a -> a -> a
forall a. Num a => a -> a -> a
* a
forall a. Floating a => a
pi) a -> a -> a
forall a. Num a => a -> a -> a
- (a
4 a -> a -> a
forall a. Num a => a -> a -> a
* a
x a -> a -> a
forall a. Num a => a -> a -> a
* (a
forall a. Floating a => a
pi a -> a -> a
forall a. Num a => a -> a -> a
- a
x)))

{- | Robin Green, robin_green@playstation.sony.com, (-pi, pi)

> import Sound.Sc3.Plot
> let xs = [-pi, -pi + 0.05 .. pi] in plot_p1_ln [map sin_green_approximation xs, map sin xs]
> let xs = [-pi, -pi + 0.05 .. pi] in plot_p1_ln [map (\x -> sin_green_approximation x - sin x) xs]
-}
sin_green_approximation :: Floating a => a -> a
sin_green_approximation :: forall a. Floating a => a -> a
sin_green_approximation a
x = a
x a -> a -> a
forall a. Num a => a -> a -> a
- (a
0.166666546 a -> a -> a
forall a. Num a => a -> a -> a
* (a
x a -> a -> a
forall a. Floating a => a -> a -> a
** a
3)) a -> a -> a
forall a. Num a => a -> a -> a
+ (a
0.00833216076 a -> a -> a
forall a. Num a => a -> a -> a
* (a
x a -> a -> a
forall a. Floating a => a -> a -> a
** a
5)) a -> a -> a
forall a. Num a => a -> a -> a
- (a
0.000195152832 a -> a -> a
forall a. Num a => a -> a -> a
* (a
x a -> a -> a
forall a. Floating a => a -> a -> a
** a
7))

{- | Paul Adenot, (-pi, pi)

> import Sound.Sc3.Plot
> let xs = [-pi, -pi + 0.05 .. pi] in plot_p1_ln [map sin_adenot_approximation xs, map sin xs]
> let xs = [-pi, -pi + 0.05 .. pi] in plot_p1_ln [map (\x -> sin_adenot_approximation x - sin x) xs]
-}
sin_adenot_approximation :: Floating a => a -> a
sin_adenot_approximation :: forall a. Floating a => a -> a
sin_adenot_approximation a
x = a
0.391969947653056 a -> a -> a
forall a. Num a => a -> a -> a
* a
x a -> a -> a
forall a. Num a => a -> a -> a
* (a
forall a. Floating a => a
pi a -> a -> a
forall a. Num a => a -> a -> a
- a -> a
forall a. Num a => a -> a
abs a
x)

{- Anthony C. Robin, (0, 45).
Simple Trigonometric Approximations, The Mathematical Gazette, Vol. 79, No. 485 (Jul., 1995), pp. 385-387.

> import Sound.Sc3.Plot
> degrees_to_radians = (* pi) . (/ 180)
> let xs = [0, 0.05 .. 45] in plot_p1_ln [map sin_robin_approximation xs, map (sin . degrees_to_radians) xs]
> let xs = [0, 0.05 .. 45] in plot_p1_ln [map (\x -> sin_robin_approximation x - sin (degrees_to_radians x)) xs]
-}
sin_robin_approximation :: Floating a => a -> a
sin_robin_approximation :: forall a. Floating a => a -> a
sin_robin_approximation a
x = let c :: a
c = a
x a -> a -> a
forall a. Num a => a -> a -> a
* a
0.01 in a
c a -> a -> a
forall a. Num a => a -> a -> a
* (a
2 a -> a -> a
forall a. Num a => a -> a -> a
- a
c)