packages feed

hemokit-0.4.0: apps/FFT.hs

module Main where

import           Control.Monad
import           Control.Monad.Trans
import           Data.Complex
import           Data.Conduit
import qualified Data.Conduit.List as CL
import qualified Data.Vector as V
import           Numeric.FFT.Vector.Unnormalized
import           System.Environment
import           Text.Printf

import           Hemokit


packets :: EmotivDevice -> Source IO EmotivState
packets d = forever (liftIO (readEmotiv d) >>= yield . fst)

buffer :: Monad m => Int -> Conduit a m [ a ]
buffer n = forever (CL.take n >>= yield)

printAll :: Sink [V.Vector Double] IO ()
printAll = awaitForever $ \tds -> liftIO $ putStrLn (unlines (map showFFT tds))


-- Convert a length M list of length N vectors into a length N list of length M vectors.
transposeV :: Int -> [ V.Vector a ] -> [ V.Vector a ]
transposeV n vs = [ V.fromList (map (V.! i) vs) | i <- [ 0 .. n - 1 ] ]

showFFT :: V.Vector Double -> String
-- showFFT ms = map (toChar . (/(V.maximum ms))) $ V.toList ms
showFFT ms = unwords . map (formatNumber . (/ V.maximum ms)) $ V.toList ms
    where
      formatNumber n = printf "%2.0f" (n*100)
      toChar m
        | m < 0.25 = ' '
        | m < 0.5  = '.'
        | m < 0.75 = 'o'
        | otherwise = '#'

norm :: V.Vector Double -> V.Vector Double
norm v = V.map (subtract avg) v
  where
    avg = V.sum v / fromIntegral (V.length v)


main :: IO ()
main = do
  args <- getArgs
  let model = if "--developer" `elem` args then Developer else Consumer

  devices <- getEmotivDevices
  device <- case devices of
    [] -> error "No devices found."
    _  -> openEmotivDevice model (last devices)

  let size = 256
  let fft = plan dftR2C size

  let sensorData = mapOutput (V.map fromIntegral . sensors) (packets device)
  let fftConduit = mapOutput (map (V.map magnitude . execute fft . norm) . transposeV 14) (buffer size)

  sensorData $= fftConduit $$ printAll