ForSyDe-3.0: examples/Equalizer_Shallow/AudioAnalyzer.lhs
\subsection{Overview}
The \process{Audio Analyzer} analyzes the current bass level and raises a flag when the bass level exceeds a limit.
\begin{figure}
\centering
\scalebox{0.8}{\mbox{\input{Figures/AudioAnalyzer.pstex_t}}}
\caption{The \textit{Audio Analyzer} subsystem}
\label{fig:AudioAnalyzerSubsystem}
\end{figure}
As illutsrated in Figure \ref{fig:AudioAnalyzerSubsystem} the \process{Audio Analyzer} is divided into four blocks. The input signal is first grouped into samples of size $N$ in the process \process{Group Samples} and then processed with a \process{DFT} in order to get the frequency spectrum of the signal. Then the power spectrum is calculated in \process{Spectrum}. In \process{CheckBass} the lowest frequencies are compared with a threshold value. If they exceed this value, the output \process{Distortion Flag} will have the value \constant{Fail}.
Since \process{Group Samples} needs $N$ cycles for the grouping, it produces $N-1$ absent values $\perp$ for each grouped sample. Thus the following processes \process{DFT}, \process{Spectrum} and \process{Check Bass} are all $\Psi$-extended in order to be able to process the absent value $\Abst$.
\begin{code}
module AudioAnalyzer (audioAnalyzer) where
import ForSyDe.Shallow
import Complex
import EqualizerTypes
input = 0.1 :- 0.2 :- input
limit :: Double
limit = 1.0
nLow :: Int
nLow = 3
audioAnalyzer :: Int -> Signal Double -> Signal (AbstExt AnalyzerMsg)
audioAnalyzer pts = mapSY (psi checkBass) -- Check Bass
. mapSY (psi spectrum) -- Spectrum
. mapSY (psi (dft pts)) -- DFT
. groupSY pts -- Group Samples
. mapSY toComplex
spectrum :: (RealFloat a) => Vector (Complex a) -> Vector a
spectrum = mapV log10 . selectLow nLow . mapV power . selectHalf . dropV 1
where
log10 x = log x / log 10
selectLow n xs = takeV n xs
selectHalf xs = takeV half xs
where half = floor (fromIntegral (lengthV xs) / 2)
power x = (magnitude x) ^ 2
checkBass :: Vector Double -> AnalyzerMsg
checkBass = checkLimit limit . sumV
where
checkLimit limit x | x > limit = Fail
| otherwise = Pass
sumV vs = foldlV (+) 0.0 vs
toComplex x = x :+ 0
\end{code}