{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wall #-}
module Streaming.FFT
( streamFFT
) where
import Prelude
( RealFloat
)
import Control.Monad (Monad(return))
import Control.Monad.Primitive
import Data.Complex (Complex(..))
import Data.Either (Either(..))
import Data.Eq (Eq((==)))
import Data.Function (($))
import Data.Ord (Ord(..))
import Data.Primitive.PrimArray
import Data.Primitive.Types
import GHC.Classes (modInt#)
import GHC.Num (Num(..))
import GHC.Real (fromIntegral, RealFrac(..))
import GHC.Types (Int(..))
import Streaming.FFT.Internal (initialDFT, subDFT, updateWindow', rToComplex)
import Streaming.FFT.Types (Window(..), Transform(..), Signal(..), Bin(..))
import Streaming
import Streaming.Prelude (next, yield)
data Depleted
= NotDepleted
| Past !Int
binDepleted :: forall e. (Num e, Ord e, RealFrac e)
=> Bin e
-> e
-> e
-> Depleted
binDepleted (Bin binSize) old new =
let !k = new - (old + fromIntegral binSize)
in if k > 0
then Past (floor k)
else NotDepleted
loadInitial :: forall m e b. (Prim e, PrimMonad m, RealFloat e)
=> MutablePrimArray (PrimState m) (Complex e)
-> Bin e
-> Signal e
-> Int
-> Int
-> e
-> Int
-> Stream (Of e) m b
-> m (Stream (Of e) m b)
loadInitial !mpa !b s@(Signal !sigSize) !ix !binAccum !binFirst !untilSig st = if (untilSig >= sigSize) then return st else do
e <- next st
case e of
Left _ -> return st
Right (x, rest) -> if ix == 0
then loadInitial mpa b s (ix + 1) binAccum x untilSig st
else do
let isDepleted = binDepleted b binFirst x
case isDepleted of
NotDepleted -> loadInitial mpa b s ix (binAccum + 1) binFirst untilSig rest
Past i -> do
let !k = rToComplex (fromIntegral binAccum) :: Complex e
!_ <- writePrimArray mpa (unsafeMod (ix - 1 + untilSig) sigSize) k :: m ()
loadInitial mpa b s (ix + i) 0 x (untilSig + 1) rest
thereafter :: forall m e b c. (Prim e, PrimMonad m, RealFloat e)
=> (Transform m e -> m c)
-> Bin e
-> Signal e
-> Int
-> Int
-> e
-> Window m e
-> Transform m e
-> Stream (Of e) m b
-> Stream (Of c) m b
thereafter extract !b !s !ix !binAccum !binFirst win trans st = do
e <- lift $ next st
case e of
Left r -> return r
Right (x, rest) -> if ix == 0
then thereafter extract b s (ix + 1) binAccum x win trans st
else do
let isDepleted = binDepleted b binFirst x
case isDepleted of
NotDepleted -> thereafter extract b s ix (binAccum + 1) binFirst win trans rest
Past i -> do
let k :: Complex e
!k = rToComplex (fromIntegral binAccum)
!trans' <- lift $ subDFT s win k trans
!info <- lift $ extract trans'
yield info
!_ <- lift $ updateWindow' win k i
thereafter extract b s (ix + i) 0 x win trans' rest
{-# INLINABLE streamFFT #-}
streamFFT :: forall m e b c. (Prim e, PrimMonad m, RealFloat e)
=> (Transform m e -> m c)
-> Bin e
-> Signal e
-> Stream (Of e) m b
-> Stream (Of c) m b
streamFFT extract b s@(Signal sigSize) strm = do
mpaW :: MutablePrimArray (PrimState m) (Complex e) <- lift $ newPrimArray sigSize
let win = Window mpaW
subStrm :: Stream (Of e) m b <- lift $ loadInitial mpaW b s 0 0 0 0 strm
!initialT <- lift $ initialDFT win
!initialInfo <- lift $ extract initialT
!_ <- yield initialInfo
thereafter extract b s 0 0 0 win initialT subStrm
unsafeMod :: Int -> Int -> Int
unsafeMod (I# x#) (I# y#) = I# (modInt# x# y#)
{-# INLINE unsafeMod #-}