Percussion is a difficult notion to represent in the abstract, since
in a way, a percussion instrument is just another instrument, so why
should it be treated differently?  On the other hand, even common
practice notation treats it specially, even though it has much in
common with non-percussive notation.  The midi standard is equally
ambiguous about the treatment of percussion: on one hand, percussion
sounds are chosen by specifying an octave and pitch, just like any
other instrument, on the other hand these notes have no tonal meaning
whatsoever: they are just a convenient way to select from a large
number of percussion sounds.  Indeed, part of the General Midi
Standard is a set of names for commonly used percussion sounds.


> module Haskore.Composition.Drum
>    (T, GM.Drum(..), Element(..), na,
>     toMusic, toMusicDefaultAttr,
>     lineToMusic, elementToMusic, funkGroove) where

> import Haskore.Composition.Trill
> import qualified Haskore.Basic.Duration as Duration
> import Haskore.Basic.Duration (qn, en, )
> import Haskore.Music (qnr, enr, (=:=), changeTempo, rest, line)
> import Haskore.Melody.Standard (NoteAttributes, na, )

> import qualified Haskore.Music             as Music
> import qualified Haskore.Music.GeneralMIDI as MidiMusic
> import qualified Haskore.Music.Rhythmic    as RhyMusic
> import qualified Sound.MIDI.General as GM

> type T = GM.Drum


Since Midi is such a popular platform, we can at least define some
handy functions for using the General Midi Standard.  We start by
defining the datatype shown in \figref{percussion}, which
borrows its constructor names from the General Midi standard.  The
comments reflecting the ``Midi Key'' numbers will be explained later,
but basically a Midi Key is the equivalent of an absolute pitch in
Haskore terminology.
We will not adapt the MIDI treatment of drums in Haskore
since it makes no sense,
e.g. to transpose drums by increasing the key number.
Thus we defined a special constructor for drums in \type{RhyMusic.T}.
We will now give a function which constructs a \type{RhyMusic.T}
for a given value specifying a drum:

> toMusic :: drum -> Duration.T -> NoteAttributes -> RhyMusic.T drum instr
> toMusic drm dr nas =
>    Music.atom dr (Just (RhyMusic.noteFromAttrs nas (RhyMusic.Drum drm)))

> toMusicDefaultAttr ::
>    drum -> Duration.T -> RhyMusic.T drum instr
> toMusicDefaultAttr drm dr = toMusic drm dr na


For example, here are eight bars of a simple rock or ``funk groove''
that uses \function{Drum.toMusic} and \function{Drum.roll}:

> funkGroove :: MidiMusic.T
> funkGroove =
>     let p1 = toMusic GM.LowTom        qn na
>         p2 = toMusic GM.AcousticSnare en na
>     in changeTempo 3 (Music.take 8 (Music.repeat
>          ( (Music.line [p1, qnr, p2, qnr, p2,
>                         p1, p1, qnr, p2, enr])
>            =:= roll en (toMusic GM.ClosedHiHat 2 na) )
>        ))


We can go one step further by defining
our own little ``percussion datatype'':

> data Element =
>      R                Duration.T                -- rest
>    | N                Duration.T NoteAttributes -- note
>    | Roll  Duration.T Duration.T NoteAttributes -- roll w/duration
>    | Rolln Integer    Duration.T NoteAttributes -- roll w/number of strokes
> lineToMusic :: T -> [Element] -> MidiMusic.T
> lineToMusic dsnd =
>    Music.line . map (elementToMusic dsnd)

> elementToMusic :: T -> Element -> MidiMusic.T
> elementToMusic dsnd el =
>    let drum = toMusic dsnd
>    in  case el of
>           R            dur     -> rest dur
>           N            dur nas -> drum dur nas
>           Roll  sDur   dur nas -> roll sDur (drum dur nas)
>           Rolln nTimes dur nas -> rollN nTimes (drum dur nas)