\begin{haskelllisting}
> module Haskore.Melody where
> import Haskore.Basic.Pitch hiding (T)
> import qualified Haskore.Basic.Pitch as Pitch
> import qualified Haskore.Basic.Duration as Duration
> import qualified Haskore.Music as Music
> import Data.Tuple.HT (mapSnd, )
> import qualified Medium
> import qualified Data.List as List
> import Data.Maybe(fromMaybe)
> import qualified Data.Accessor.Basic as Accessor
> data Note attr = Note {noteAttrs_ :: attr, notePitch_ :: Pitch.T}
> deriving (Show, Eq, Ord)
> type T attr = Music.T (Note attr)
> noteAttrs :: Accessor.T (Note attr) attr
> noteAttrs =
> Accessor.fromSetGet (\x n -> n{noteAttrs_ = x}) noteAttrs_
>
> notePitch :: Accessor.T (Note attr) Pitch.T
> notePitch =
> Accessor.fromSetGet (\x n -> n{notePitch_ = x}) notePitch_
> toMelodyNullAttr :: T attr -> T ()
> toMelodyNullAttr =
> Music.mapNote (\(Note _ p) -> Note () p)
\end{haskelllisting}
For convenience,
let's create simple names for familiar notes (\figref{note-names}),
durations, and rests (\figref{durations-rests}).
Despite the large number of them, these names are sufficiently
``unusual'' that name clashes are unlikely.
\begin{figure}{\small
\begin{haskelllisting}
> note :: Pitch.T -> Duration.T -> attr -> T attr
> note p d' nas = Medium.prim (Music.Atom d' (Just (Note nas p)))
>
> note' :: Pitch.Class -> Pitch.Octave ->
> Duration.T -> attr -> T attr
> note' = flip (curry note)
>
> cf,c,cs,df,d,ds,ef,e,es,ff,f,fs,gf,g,gs,af,a,as,bf,b,bs ::
> Pitch.Octave -> Duration.T -> attr -> T attr
>
> cf = note' Cf; c = note' C; cs = note' Cs
> df = note' Df; d = note' D; ds = note' Ds
> ef = note' Ef; e = note' E; es = note' Es
> ff = note' Ff; f = note' F; fs = note' Fs
> gf = note' Gf; g = note' G; gs = note' Gs
> af = note' Af; a = note' A; as = note' As
> bf = note' Bf; b = note' B; bs = note' Bs
\end{haskelllisting}
}
\caption{Convenient note construction functions.}
\figlabel{note-names}
\end{figure}
\begin{comment}
>
\end{comment}
From the notes in the C major triad in register 4, I can now construct
a C major arpeggio and chord as well:
\begin{haskelllisting}
> cMaj :: [T ()]
> cMaj = map (\n -> n 4 Duration.qn ()) [c,e,g]
>
> cMajArp, cMajChd :: T ()
> cMajArp = Music.line cMaj
> cMajChd = Music.chord cMaj
\end{haskelllisting}
It is also possible to retrieve the pitch from a melody note.
But this should be avoided, since it must be dynamically checked,
whether the Melody value actually contains one note.
\begin{haskelllisting}
> noteToPitch :: T attr -> Pitch.T
> noteToPitch =
> let err = error "leastVaryingInversions: melody must consist of a note"
> in Accessor.get notePitch .
> Music.switchList (const (fromMaybe err)) err err err
\end{haskelllisting}
\paragraph*{Inversion and Retrograde.}
The notions of inversion, retrograde, retrograde inversion, etc. used
in 12-tone theory are also easily captured in Haskore. First let's
define a transformation from a line created by \code{line} to a list:
\begin{haskelllisting}
> invertNote :: Pitch.T -> Note attr -> Note attr
> invertNote r =
> Accessor.modify notePitch
> (\ p -> Pitch.fromInt (2 * Pitch.toInt r Pitch.toInt p))
>
> retro, invert, retroInvert, invertRetro ::
> [(d, Music.Atom (Note attr))] -> [(d, Music.Atom (Note attr))]
> retro = List.reverse
> invert l = let r = maybe
> (error "invert: first atom must be a note")
> (Accessor.get notePitch)
> (snd (head l))
> in map (mapSnd (fmap (invertNote r))) l
> retroInvert = retro . invert
> invertRetro = invert . retro
\end{haskelllisting}
\begin{exercise} Show that ``\code{retro\ .\ retro}'',
``\code{invert\ .\ invert}'', and ``\code{retroInvert\ .\ invertRetro}''
are the identity on values created by \code{line}.
\end{exercise}