```-- | Windowing functions.
module Sound.SC3.Lang.Math.Window where

import qualified Numeric.GSL.Special.Bessel as M {- hmatrix-special -}
import qualified Numeric.GSL.Special.Trig as M

-- * Type and conversion

-- | A function from a \(0,1)\ normalised input to an output.
type Window x = x -> x

-- | A discrete /n/ element rendering of a 'Window'.
type Table x = [x]

-- | Generate an /n/ element table from a \(0,1)\ normalised window
-- function.
window_table :: (Integral n,Fractional a,Enum a) => n -> Window a -> Table a
window_table n f =
let k = 1 / (fromIntegral n - 1)
in map f [0,k..1]

-- * Math

-- | Regular modified Bessel function of fractional order zero.
bessel0 :: Double -> Double
bessel0 = M.bessel_Inu 0

-- | /n/ ^ 2.
square :: Num a => a -> a
square x = x * x

-- * Window functions

-- | Gaussian window, θ <= 0.5.
gaussian :: Floating a => a -> Window a
gaussian theta i = exp (- (0.5 * square ((i - 0.5) / (theta * 0.5))))

-- | Hann raised cosine window.
hann :: Floating a => Window a
hann i = 0.5 * (1 - cos (2 * pi * i))

-- | Hamming raised cosine window.
hamming :: Floating a => Window a
hamming i = 0.54 - 0.46 * cos (2 * pi * i)

-- | Kaiser windowing function, β is shape (1,2,8).
kaiser :: Double -> Window Double
kaiser beta i =
let beta' = bessel0 beta
in bessel0 (beta * sqrt (1 - ((2 * i - 1) ** 2))) / beta'

-- | 'M.sinc' window.
lanczos :: Window Double
lanczos i = M.sinc (2 * i - 1)

-- | Unit ('id') window, also known as a Dirichlet window.
rectangular :: Window a
rectangular = id

-- | 'sin' window.
sine :: Floating a => Window a
sine i = sin (i * pi)

-- | Triangular window, ie. Bartlett window with zero end-points.
triangular :: Fractional a => Window a
triangular i = 2 * (0.5 - abs (i - 0.5))

-- * Tables

-- | 'window_table' . 'gaussian'.
--
-- > plot [gaussian_table 1024 0.25,gaussian_table 1024 0.5]
gaussian_table :: (Integral n, Floating b, Enum b) => n -> b -> [b]
gaussian_table n = window_table n . gaussian

-- | 'window_table' . 'hamming'.
--
-- plot [hann 128,hamming 128]
hamming_table :: Int -> [Double]
hamming_table n = window_table n hamming

-- | 'window_table' . 'hann'.
--
-- plot [hann_table 128]
hann_table :: Int -> [Double]
hann_table n = window_table n hann

-- | 'window_table' . 'kaiser'.
--
-- plot [kaiser_table 128 1,kaiser_table 128 2,kaiser_table 128 8]
kaiser_table :: Int -> Double -> [Double]
kaiser_table n = window_table n . kaiser

-- | 'window_table' . 'lanczos'.
--
-- plot [lanczos (2^9)]
lanczos_table :: Integral n => n -> [Double]
lanczos_table n = window_table n lanczos

-- | 'window_table' . 'sine'.
--
-- plot [sine 128]
sine_table :: (Integral n, Floating b, Enum b) => n -> [b]
sine_table n = window_table n sine

-- | 'window_table' . 'triangular'.
--
-- plot [triangular (2^9)]
triangular_table :: (Integral n, Fractional b, Enum b) => n -> [b]
triangular_table n = window_table n triangular
```