% from AutoTrack by Stefan Ratschan \section{Styles} \begin{haskelllisting}

    > module Haskore.Interface.AutoTrack.Style
    >           (T, playToStream, jazz, bossa, takeFive, rock,
    >            thomasCarib, harmonic) where

    > import Data.Bool.HT (select, )
    > import Data.List.HT (viewR, )
    > import Haskore.Basic.Duration (en, qn, (%+), )
    > import Haskore.Music ((+:+), (=:=), )

    > import qualified Haskore.Composition.Rhythm as Rhythm
    > import qualified Haskore.Composition.Drum   as Drum
    > import qualified Haskore.Basic.Duration as Dur
    > import qualified Haskore.Basic.Pitch    as Pitch
    > import qualified Haskore.Music          as Music
    > import qualified Haskore.Music.GeneralMIDI as MidiMusic
    > import qualified Haskore.Melody         as Melody
    > import qualified Haskore.Interface.MIDI.Render as MidiRender
    > import qualified Sound.MIDI.File.Save   as MidiSave

    > import qualified Haskore.Interface.AutoTrack.Transposeable as Transposeable
    > import qualified Haskore.Interface.AutoTrack.ChordSymbol as ChordSymbol
    > import qualified Haskore.Interface.AutoTrack.ChartBar    as ChartBar
    > import qualified Haskore.Interface.AutoTrack.ChordChart  as ChordChart
    > import qualified Haskore.Interface.AutoTrack.EventChart  as EventChart
    > import qualified Haskore.Interface.AutoTrack.Instrument  as Instrument

    > import qualified Data.ByteString.Lazy as B

\end{haskelllisting} A style takes a chord chart and creates some music out of it. \begin{haskelllisting}

    > type T       = ChordChart.T -> MidiMusic.T
    > type TMelody = ChordChart.T -> Melody.T ()

\end{haskelllisting} \subsection{Filtering music} Filtering certain parts from music, in order to introduce rests \emph{after} the creation of some music. The needed information can be encoded in several ways: \begin{enumerate} \item [ (Music.Dur, Music.Dur) ]: Place of rest, length of rest, sorted \item [ Music.Dur ]: Place to switch from rest to music, or other way round \item Music.Dur [ Bool ]: Some basic duration and then True implies music, False implies Rest \end{enumerate} We use the third possibility here, but use a helper function with a more general interface, which additionally specifies the length of the first list member (different from the basic duration). \begin{haskelllisting}

    > filterMusic :: Music.Dur -> [ Bool ] -> Music.T note -> Music.T note
    > filterMusic = fm 0

    > fm :: Music.Dur -> Music.Dur -> [ Bool ] -> Music.T note -> Music.T note
    > fm fDur bDur plc =
    >    Music.switchBinary
    >       (\dur at -> case at of
    >           (Just  _) -> Music.atom (min dur (musicDur fDur bDur plc)) at
    >           (Nothing) -> Music.rest dur)
    >       (\ctrl m -> case ctrl of
    >           (Music.Tempo t) -> Music.changeTempo t (fm (fDur*t) (bDur*t) plc m)
    >           _               -> Music.control ctrl m)
    >       (\m0 m1 -> let m0' = fm fDur  bDur plc  m0
    >                      (rFDur, rPlc) = remLen bDur plc (Music.dur m0 - fDur)
    >                      m1' = fm rFDur bDur rPlc m1
    >                  in m0' +:+ m1')
    >       (\m0 m1 -> fm fDur bDur plc m0 =:= fm fDur bDur plc m1)
    >       (Music.rest 0)

    > remLen :: Music.Dur -> [ Bool ] -> Music.Dur -> (Music.Dur, [ Bool ])
    > remLen bDur plc len =
    >    if bDur>len
    >    then (bDur-len, plc)
    >    else (len-bDur, tail plc)

    > musicDur :: (Num a) => a -> a -> [Bool] -> a
    > musicDur fDur bDir plc =
    >    sum (zipWith const (fDur : repeat bDir) (takeWhile id plc))
    > --   sum (map fst (takeWhile snd (zip (fDur : repeat bDir) plc)))

\end{haskelllisting} \subsection{Playing Styles} Playing a chord chart and style into a stream of binary MIDI data. We abuse a String to store it. \begin{haskelllisting}

    > playToStream :: Int -> T -> Integer -> Int -> ChordChart.T -> B.ByteString
    > playToStream trans style tempo chornum chart =
    >     let countin = Rhythm.countIn (ChartBar.dur (head (ChordChart.bars chart)))
    >         choruses = Music.replicate chornum (style (Transposeable.transpose trans chart))
    >         music = Music.changeTempo (tempo%+60) (countin +:+ choruses)
    >     in MidiSave.toByteString (MidiRender.generalMidiDeflt music)

\end{haskelllisting} \subsection{Drum Fill} \begin{haskelllisting}

    > jazzFill :: Music.Dur -> MidiMusic.T
    > jazzFill d =
    >    if d >= 2%+4
    >      then
    >        let shuffle dr =
    >               Rhythm.toShuffledMusicWithDrumUnit en dr . Rhythm.fromString
    >        in  Music.rest (d-2%+4) +:+
    >               (shuffle Drum.SplashCymbal     "...x" =:=
    >                shuffle Drum.AcousticBassDrum "...x" =:=
    >                shuffle Drum.AcousticSnare    ".xx.")
    >      else error "jazzFill: d must be at least 2%+4"

    > endFill :: [ ChartBar.T ] -> MidiMusic.T
    > endFill l =
    >    let Just (initLd,lastLd) = viewR $ map ChartBar.dur l
    >    in  Music.line (map Music.rest initLd) +:+
    >        jazzFill lastLd

\end{haskelllisting} \subsection{Bass Lines} First some auxiliary function to play the bass note of a chord. \begin{haskelllisting}

    > bassFromMelody :: Melody.T () -> MidiMusic.T
    > bassFromMelody =
    >    MidiMusic.fromMelodyNullAttr MidiMusic.AcousticBass

    > bassChoose :: (Music.Dur, ChordSymbol.T) -> Melody.T ()
    > bassChoose (l, (ChordSymbol.Cons _ b _)) = bassNote l b

    > bassNote :: Music.Dur -> Pitch.Class -> Melody.T ()
    > bassNote l b =
    >    Melody.note (Instrument.bottomRange Instrument.bass b) l ()

\end{haskelllisting} \subsubsection{Chart Bass} This bass line style plays the root of a chord on every chord of a chord chart. \begin{haskelllisting}

    > evFromCC :: ChordChart.T -> [(Music.Dur, ChordSymbol.T)]
    > evFromCC = EventChart.events . EventChart.fromChordChart

    > chartBass :: TMelody
    > chartBass =
    >    Music.line . map bassChoose . evFromCC

\end{haskelllisting} \subsubsection{Quarter Bass} This bass line style plays the root of the current chord on every quarter note. It first creates chords on every beat, then maps bassChoose to it. Problem: Right now only works if all chords are on quarter notes! \begin{haskelllisting}

    > splitToDur :: Music.Dur -> [ ( Music.Dur, e ) ] -> [ ( Music.Dur, e ) ]
    > splitToDur sd =
    >    concatMap (\(d,e) -> replicate (fromInteger (Dur.divide d sd)) (sd, e))

    > quarterBass :: TMelody
    > quarterBass =
    >    Music.line . map bassChoose . splitToDur (1%+4) . evFromCC

    > eighthBass :: TMelody
    > eighthBass =
    >    Music.line . map bassChoose . splitToDur (1%+8) . evFromCC

\end{haskelllisting} \subsubsection{Bossa Bass} A simple bass for Bossas using the bass note and its fifth. \begin{haskelllisting}

    > bossaBass :: TMelody
    > bossaBass = Music.line . map bossaBassC . evFromCC

    > bossaBassC :: (Music.Dur, ChordSymbol.T) -> Melody.T ()
    > bossaBassC (l, ch@(ChordSymbol.Cons r _ _)) =
    >   let r7 = Transposeable.transpose 7 r
    >       bossa' = bassNote (3%+8) r +:+ bassNote (1%+8) r7 +:+
    >                bassNote (1%+2) r7 +:+
    >                bossaBassC (l - 1%+1, ch)
    >   in select (bassChoose (l, ch))
    >         [(l >= 1%+1, bossa'),
    >          (l >= 1%+2, bassNote (3%+8) r +:+ bassNote (1%+8) r)]

\end{haskelllisting} \subsubsection{Walking Bass Line} Creating a good walking bass is a science in itself. There are numerous books which give various rules for creating good bass lines. The following code is still VERY experimental and just follows these basic rules: \begin{itemize} \item Create the root on the first quarter note of a chord, and \item create random quarter notes of the appropriate scale for the rest. \end{itemize} We do this by creating a walking bass line for every chord of a chart separately and then concatenating the created bass lines. \begin{haskelllisting} walking :: T walking = Music.line . map walkChord . evFromCC c \end{haskelllisting} Walking bass line for a single chord of a certain length. Take the root for the first note and random notes for the rest. \begin{haskelllisting} walkChord :: (Music.Dur, ChordSymbol.T) -> Melody.T () walkChord (d, ch) | (divisible d (1%+4)) = bassChoose ((1%+4), ch) +:+ walkRandom ((divide d (1%+4))-1) ch \end{haskelllisting} Create a random walking bass line of n quarter notes using chord ch. \begin{haskelllisting} walkRandom :: Int -> ChordSymbol.T -> Melody.T () walkRandom n ch = let scale = (chordToScale ch) choice = \n -> bassChooseR n (1%+4, scale) in line (map choice (take n (randList (length scale)))) bassChooseR :: Int -> (Music.Dur, Scale) -> Melody.T () bassChooseR n (d, s) = Melody.note d (pitch (s!!n)) () \end{haskelllisting} \subsection{Full Styles} The jazz style works for 3/4 and 4/4 measure. It currently does not yet use walking bass, but uses the quarter bass style above. \begin{haskelllisting}

    > jazzDrum :: Music.Dur -> MidiMusic.T
    > jazzDrum d =
    >    select (error "jazzDrum supports only 3%+4 and 4%+4")
    >       [(d==3%+4, Rhythm.jazzWaltzRideP Drum.RideCymbal2 =:=
    >                  Rhythm.jazzWaltzHiHatP Drum.PedalHiHat),
    >        (d==4%+4, Music.replicate 2
    >                    (Rhythm.jazzRideP Drum.RideCymbal2 =:=
    >                     Rhythm.backBeatP Drum.PedalHiHat))]

    > jazz :: T
    > jazz s = let drums = Music.line (map (jazzDrum . ChartBar.dur) (ChordChart.bars s)) =:=
    >                      endFill (ChordChart.bars s)
    >              (bd, hc) = ChordChart.hasChord s
    >          in  filterMusic bd hc drums =:=
    >                 bassFromMelody (quarterBass s)
    >

\end{haskelllisting} The bossa style just plays the usual bossa clave with the hi-hat on the backbeat and some simple bass. \begin{haskelllisting}

    > bossa :: T
    > bossa c = let drums = Music.repeat Rhythm.claveBossa =:=
    >                       Music.repeat Rhythm.ride =:=
    >                       Music.repeat (Rhythm.backBeatP Drum.PedalHiHat)
    >               bass = bassFromMelody (bossaBass c)
    >           in Music.take ((4 * ChordChart.length c) %+ 4) drums =:= bass

\end{haskelllisting} The Take-Five style works for charts with 5/4 measures only. \begin{haskelllisting}

    > takeFiveBass :: ChartBar.T -> Melody.T ()
    > takeFiveBass b =
    >    if ChartBar.dur b == 5%+4  &&  length (ChartBar.chords b) <= 2
    >      then
    >        let c=ChartBar.chords b
    >            bass d Nothing  = Music.rest d
    >            bass d (Just x) = bassChoose (d, x)
    >        in if length c == 2
    >             then bass (3%+4) (c!!0) +:+ bass (2%+4) (c!!1)
    >             else bass (3%+4) (c!!0) +:+ bass (2%+4) (c!!0)
    >      else error "takeFiveBass: only allowed for 5%+4 and maximally 2 chords per bar"

    > takeFive :: T
    > takeFive (ChordChart.Cons l) =
    >     let rep pat = concat (replicate (length l) (Rhythm.fromString pat))
    >         hiHatR  = rep "..x .x"
    >         cymbalR = rep "x. xx x. x. xx"
    >     in Rhythm.toMusicWithDrumUnit         qn Drum.PedalHiHat  hiHatR  =:=
    >        Rhythm.toShuffledMusicWithDrumUnit en Drum.RideCymbal2 cymbalR =:=
    >        endFill l =:=
    >        bassFromMelody (Music.line (map takeFiveBass l))

\end{haskelllisting} The rock style just plays the usual hi-hat eights, bass drum on downbeat, snare on backbeat. \begin{haskelllisting}

    > rock :: T
    > rock c = let drums = Music.repeat Rhythm.basicBassDrum =:=
    >                      Music.repeat Rhythm.basicSnare =:=
    >                      Music.repeat Rhythm.basicHiHat
    >              bass  = bassFromMelody (eighthBass c)
    >          in Music.take ((4 * ChordChart.length c) %+ 4) drums =:= bass

\end{haskelllisting} This style is not yet finished. \begin{haskelllisting}

    > thomasCarib :: T
    > thomasCarib c =
    >    Rhythm.backBeatP Drum.PedalHiHat =:=
    >    Rhythm.basicBassDrum =:=
    >    Rhythm.toShuffledMusicWithDrumUnit en Drum.Claves
    >       (Rhythm.fromString ".. .x .x x.") =:=
    >    bassFromMelody (chartBass c)

\end{haskelllisting} This is a rather simple style where the tones of a chord a played simultaneously. \begin{haskelllisting}

    > harmonic :: T
    > harmonic =
    >    let chordSymbolToMusic (dur, cs) = Music.chord $
    >           map (\p -> Melody.note p dur ()) $
    >              ChordSymbol.toChord cs
    >    in  bassFromMelody . Music.line .
    >           map chordSymbolToMusic . evFromCC

\end{haskelllisting}