\subsection{Conversion functions with default settings}
\seclabel{default-performance}

\subsubsection{Examples of Player Construction}

A ``default player'' called \function{Default.player} (not to be confused with
``deaf player''!) is defined for use when none other is specified in
the score; it also functions as a base from which other players can be
derived.  \function{Default.player} responds only to the \constructor{Velocity} note
attribute and to the \constructor{Accent}, \constructor{Staccato}, and \constructor{Legato}
phrase attributes.  It is defined in \figref{default-Player}.
Before reading this code, recall how players are invoked by the
\function{Performance.fromMusic} function defined in the last section; in particular, note the
calls to \function{playNote} and \function{interpretPhase} defined above.  Then
note:
\begin{enumerate}
\item \function{defltPlayNote} is the only function (even in the definition
of \function{Performance.fromMusic}) that actually generates an event.  It also modifies
that event based on an interpretation of each note attribute by the
function \function{defltNasHandler}.

\item  \function{defltNasHandler} only recognizes the \constructor{Velocity} attribute,
which it uses to set the event velocity accordingly.

\item \function{defltInterpPhrase} calls (mutually recursively)
\function{Performance.fromMusic} to interpret a phrase,
and then modifies the result based on
an interpretation of each phrase attribute by the function
\function{defltInterpPhrase}.

\item \function{defltInterpPhrase} only recognizes the \constructor{Accent},
\constructor{Staccato}, and \constructor{Legato} phrase attributes.
For each of these it uses the numeric argument as a ``scaling'' factor
of the volume (for
\constructor{Accent}) and duration (for \constructor{Staccato} and \constructor{Legato}).
Thus \expression{(Phrase (Legato 1.1) m)} effectively increases the duration
of each note in \expression{m} by 10\% (without changing the tempo).
\end{enumerate}

It should be clear that much of the code in Figure
\ref{default-Player} can be re-used in defining a new player.
For example, to define a player \function{weird} that interprets note
attributes just like \function{Default.player} but behaves differently with
respect to phrase attributes, we could write:
\begin{haskelllisting}
  weird :: T
  weird  = Performance.PlayerCons {
              pname           = "Weirdo",
              playNote        = defltPlayNote defltNasHandler,
              interpretPhrase = liftM . myPhraseInterpreter
              notatePlayer    = defltNotatePlayer ()
           }
\end{haskelllisting}
and then supply a suitable definition of \function{myPhraseInterpreter}.  That
definition could also re-use code, in the following sense: suppose we
wish to add an interpretation for \constructor{Crescendo}, but otherwise
have \function{myPhraseInterpreter} behave just like \function{defltInterpPhrase}.
\begin{haskelllisting}
  myPhraseInterpreter :: PhraseAttribute -> Performance.T time dyn note -> Performance.T time dyn note
  myPhraseInterpreter (Dyn (Crescendo x)) pf = ...
  myPhraseInterpreter  pa                 pf = defltInterpPhrase pa pf
\end{haskelllisting}

\begin{exercise}
Fill in the \expression{...} in the definition of \function{myPhraseInterpreter} according
to the following strategy:  Assume $0<\expression{x}<1$.  Gradually scale
the volume of each event by a factor of $1.0$ through $1.0+\expression{x}$,
using linear interpolation.
\end{exercise}

\begin{exercise}
Choose some of the other phrase attributes and provide interpretations
of them, such as \constructor{Diminuendo}, \constructor{Slurred}, \constructor{Trill}, etc.
(The \function{trill} functions from \secref{basic-examples} may be
useful here.)
\end{exercise}

{\small
\begin{haskelllisting}

> module Haskore.Performance.Default where

> import qualified Haskore.Music       as Music
> import qualified Haskore.Performance as Performance
> import qualified Haskore.Performance.Context as Context
> import qualified Haskore.Performance.Player  as Player

> import qualified Haskore.Basic.TimeOrderedList    as TimeList

> import qualified Haskore.Basic.Tempo    as Tempo
> import qualified Haskore.Basic.Duration as Dur

> import qualified Numeric.NonNegative.Class   as NonNeg
> import qualified Numeric.NonNegative.Wrapper as NonNegW

> import Prelude hiding (map)

\end{haskelllisting}
}

\begin{figure}
{\small
\begin{haskelllisting}

> -- default is a reserved keyword
> player ::
>    (NonNeg.C time, Fractional time, Real time, Fractional dyn) =>
>    Player.T time dyn note
> player = map "Default"
>
> -- a default PMap that makes everything into a Default.player
> map ::
>    (NonNeg.C time, Fractional time, Real time, Fractional dyn) =>
>    Player.Name -> Player.T time dyn note
> map pname =
>    Performance.PlayerCons {
>       Performance.name            = pname,
>       Performance.playNote        = playNote,
>       Performance.interpretPhrase = interpretPhrase,
>       Performance.notatePlayer    = notatePlayer ()
>    }
>
> playNote :: (Fractional time, Real time) =>
>    Performance.NoteFun time dyn note
> playNote
>    (Performance.Context curDur _ curKey curVelocity) d note =
>        TimeList.singleton 0
>             (Performance.Event {
>                Performance.eventDur       = Dur.toNumber d * curDur,
>                Performance.eventTranspose = curKey,
>                Performance.eventDynamics  = curVelocity,
>                Performance.eventNote      = note } )
>
> interpretPhrase ::
>    (NonNeg.C time, Fractional time, Fractional dyn) =>
>    Performance.PhraseFun time dyn note
> interpretPhrase (Music.Dyn (Music.Accent   x)) = Player.accent x
> interpretPhrase (Music.Art (Music.Staccato x)) = Player.staccatoAbs x
> interpretPhrase (Music.Art (Music.Legato   x)) = Player.legatoAbs x
> interpretPhrase _                              = id
>
> notatePlayer :: () -> Performance.NotateFun
> notatePlayer _ = ()

> context ::
>    (NonNeg.C time, Fractional time, Real time, Fractional dyn) =>
>    Context.T time dyn note
> context =
>    Performance.Context {
>       Performance.contextPlayer     = player,
>       Performance.contextDur        = Tempo.metro 60 Dur.qn,
>       Performance.contextTranspose  = 0,
>       Performance.contextDynamics   = 1
>    }

\end{haskelllisting}
}
\caption{Definition of default Player \function{Default.player}.}
\figlabel{default-Player}
\end{figure}

{\small
\begin{haskelllisting}

> fromMusic ::
>    (Ord note, NonNeg.C time, RealFrac time, Fractional dyn, Ord dyn) =>
>    Music.T note -> Performance.T time dyn note
> fromMusic =
>    Performance.fromMusic map context
>
> fromMusicModifyContext ::
>    (Ord note, NonNeg.C time, RealFrac time, Fractional dyn, Ord dyn) =>
>    (Context.T time dyn note -> Context.T time dyn note) ->
>    Music.T note ->
>    Performance.T time dyn note
> fromMusicModifyContext update =
>    Performance.fromMusic
>       map
>       (update context)
>
> floatFromMusic :: (Ord note) =>
>    Music.T note -> Performance.T NonNegW.Float Float note
> floatFromMusic = fromMusic
>
> paddedFromMusic  ::
>    (Ord note, NonNeg.C time, RealFrac time, Fractional dyn, Ord dyn) =>
>    Music.T note -> Performance.Padded time dyn note
> paddedFromMusic =
>    Performance.paddedFromMusic map context
>
> paddedFromMusicModifyContext ::
>    (Ord note, NonNeg.C time, RealFrac time, Fractional dyn, Ord dyn) =>
>    (Context.T time dyn note -> Context.T time dyn note) ->
>    Music.T note ->
>    Performance.T time dyn note
> paddedFromMusicModifyContext update =
>    Performance.fromMusic
>       map
>       (update context)

\end{haskelllisting}
}
