myTestlll-1.0.0: Euterpea/IO/MUI/FFT.hs
-- Filename: fft.hs
-- Created by: Daniel Winograd-Cort
-- Created on: unknown
-- Last Modified by: Daniel Winograd-Cort
-- Last Modified on: 12/12/2013
-- This module requires the array and pure-fft packages.
{-# LANGUAGE Arrows #-}
module Euterpea.IO.MUI.FFT where
import Control.CCA.Types
import Prelude hiding (init)
import FRP.UISF
import Numeric.FFT (fft)
import Data.Complex
import Data.Map (Map)
import qualified Data.Map as Map
-- | Alternative for working with Math.FFT instead of Numeric.FFT
--import qualified Math.FFT as FFT
--import Data.Array.IArray
--import Data.Array.CArray
--myFFT n lst = elems $ (FFT.dft) (listArray (0, n-1) lst)
--------------------------------------
-- Fast Fourier Transform
--------------------------------------
-- | Returns n samples of type b from the input stream at a time,
-- updating after k samples. This function is good for chunking
-- data and is a critical component to fftA
quantize :: ArrowInit a => Int -> Int -> a b (SEvent [b])
quantize n k = proc d -> do
rec (ds,c) <- init ([],0) -< (take n (d:ds), c+1)
returnA -< if c >= n && c `mod` k == 0 then Just ds else Nothing
-- | Converts the vector result of a dft into a map from frequency to magnitude.
-- One common use is:
-- fftA >>> arr (fmap $ presentFFT clockRate)
presentFFT :: Double -> [Double] -> Map Double Double
presentFFT clockRate a = Map.fromList $ zipWith (curry mkAssoc) [0..] a where
mkAssoc (i,c) = (freq, c) where
samplesPerPeriod = fromIntegral (length a)
freq = i * (clockRate / samplesPerPeriod)
-- | Given a quantization frequency (the number of samples between each
-- successive FFT calculation) and a fundamental period, this will decompose
-- the input signal into its constituent frequencies.
-- NOTE: The fundamental period must be a power of two!
fftA :: ArrowInit a => Int -> Int -> a Double (SEvent [Double])
fftA qf fp = proc d -> do
carray <- quantize fp qf -< d :+ 0
returnA -< fmap (map magnitude . take (fp `div` 2) . fft) carray