packages feed

ForSyDe-3.0: examples/Equalizer_Shallow/ButtonControl.lhs

\subsection{Overview}

The subsystem \process{Button Control} works as a user interface in the equalizer system. It receives the four input signals \signal{BassDn}, \signal{BassUp}, \signal{TrebleDn}, \signal{TrebleUp} and the override signal \process{Override} from the \process{Distortion Control} and calculates the new bass and treble values for the output signals \signal{Bass} and \signal{Treble}. The subsytem contains the main processes \process{Button Interface} and \process{Level Control}. The process \process{Level Control} outputs a new value, if either the signal \signal{Button} or the signal \signal{Overr} is present, otherwise the output value is absent. The process \process{Hold Level} is modeled by means of \process{holdSY (0.0, 0.0)} that outputs the last present value, if the input value is absent. The process \process{unzipSY} transforms a signal of tuples (the current bass and treble level) into a tuple of signals (a bass and a treble signal).

\begin{figure}
\centering
\scalebox{0.8}{\mbox{\input{Figures/ButtonControl.pstex_t}}}
\caption{The Subsystem \process{Button Control}}
\end{figure}

\begin{code}
module ButtonControl (buttonControl) where 

import ForSyDe.Shallow
import EqualizerTypes
import Combinators

data State   = Operating 
	     | Locked deriving(Eq, Show)
type Level   = Double
type Bass    = Level
type Treble  = Level

buttonControl :: Signal (AbstExt OverrideMsg) -> Signal (AbstExt Sensor) 
 	      -> Signal (AbstExt Sensor) -> Signal (AbstExt Sensor) 
 	      -> Signal (AbstExt Sensor) -> (Signal Bass,Signal Treble)
buttonControl overrides bassDn bassUp trebleDn trebleUp 
    = (bass, treble) 
      where (bass, treble) = unzipSY levels
 	    levels = ((holdSY (0.0, 0.0)) `funComb2` levelControl) 
                           button overrides
            button = buttonInterface bassDn bassUp trebleDn trebleUp
\end{code}

\subsection{The Process \process{Button Interface}}

The \process{Button Interface} monitors the four input buttons \signal{BassDn}, \signal{BassUp}, \signal{TrebleDn}, \signal{TrebleUp} and indicates if a button is pressed. If two or more buttons are pressed the conflict is resolved by the priority order of the buttons. 

\begin{code}
buttonInterface :: Signal (AbstExt Sensor) -> Signal (AbstExt Sensor) 
		-> Signal (AbstExt Sensor) -> Signal (AbstExt Sensor) 
		-> Signal (AbstExt Button)
buttonInterface bassUp bassDn trebleUp trebleDn 
   = zipWith4SY f bassUp bassDn trebleUp trebleDn
     where f (Prst Active) _ _ _ = Prst BassUp
	   f _ (Prst Active) _ _ = Prst BassDn
	   f _ _ (Prst Active) _ = Prst TrebleUp
	   f _ _ _ (Prst Active) = Prst TrebleDn
	   f _ _ _ _		 = Abst
\end{code}

\subsection{The Process \process{Level Control}}

The process has a local state that consists of a mode and the current values for the bass and treble levels (Figure \ref{fig:FSM_LevelControl}). The \process{Level Control} has two modes, in the mode \constant{Operating} the bass and treble values are stepwise changed in 0.2 steps. However, there exists maximum and minimum values which are -5.0 and +5.0. The process enters the mode \constant{Locked} when the \constant{Override} input has the value \constant{Lock}. In this mode an additional increase of the bass level is prohibitet and even decreased by 1.0 in case the \constant{Override} signal has the value \constant{CutBass}. The subsystem returns to the \constant{Operating} mode on the override value \constant{Release}. The output of the process is an absent extended signal of tuples with the current bass and treble levels.   

\begin{figure}
\resizebox{\columnwidth}{!}{\mbox{\input{Figures/FSM_LevelControl.pstex_t}}}
\caption{The State Diagram of the Process \process{Level Control}}
\label{fig:FSM_LevelControl}
\end{figure}
\begin{code}
levelControl :: Signal (AbstExt Button) -> Signal (AbstExt OverrideMsg) 
 	     -> Signal (AbstExt (Bass,Treble))
levelControl button overrides 
  = mealy2SY nextState output (initState, initLevel) button overrides

nextState :: (State,(Double,Double)) -> AbstExt Button 
	  -> AbstExt OverrideMsg -> (State,(Double,Double))
nextState (state, (bass, treble)) button override
  = (newState, (newBass, newTreble)) where
     newState = if state == Operating then
		   if override == Prst Lock then
		      Locked
		   else
		      Operating
	        else
		   if override == Prst Release then
		      Operating
		   else 
		      Locked

     newBass = if state == Locked then
		  if override == Prst CutBass then
		     decreaseLevel bass cutStep
		  else
	             if button == Prst BassDn then
			decreaseLevel bass step
		     else
			bass
	       else -- state = Operating
		  if button == Prst BassDn then
		     decreaseLevel bass step
		  else 
		     if button == Prst BassUp then
			increaseLevel bass step
		     else
			bass
		    
     newTreble = if button == Prst TrebleDn then
		    decreaseLevel treble step
		 else 
		    if button == Prst TrebleUp then
		       increaseLevel treble step
		    else 
		       treble

output :: (a, (Bass, Treble)) -> AbstExt Button -> AbstExt OverrideMsg 
 	  -> AbstExt (Bass,Treble)
output _           Abst Abst = Abst
output (_, levels) _    _    = Prst levels	          
\end{code}

The process uses the following initial values.

\begin{code}
initState =  Operating
initLevel =  (0.0, 0.0)
maxLevel  =  5.0
minLevel  = -5.0
step      =  0.2
cutStep   =  1.0
\end{code}

The process uses the following auxiliary functions.

\begin{code}
decreaseLevel :: Level -> Level -> Level
decreaseLevel level step = if reducedLevel >= minLevel then
			      reducedLevel
		           else
			      minLevel
			   where reducedLevel = level - step

increaseLevel :: Level -> Level -> Level
increaseLevel level step = if increasedLevel <= maxLevel then
			      increasedLevel
		           else
			      maxLevel
			   where increasedLevel = level + step
\end{code}