% from AutoTrack by Stefan Ratschan

\subsubsection{Scales}

\begin{haskelllisting}

> module Haskore.Basic.Scale
>          (T, ionian, dorian, phrygian, lydian, mixolydian,
>              aeolian, lokrian, altered, htwt, wtht,
>              ionianRel, dorianRel, phrygianRel, lydianRel, mixolydianRel,
>              aeolianRel, lokrianRel, alteredRel, htwtRel, wthtRel,
>
>              fromOffsets, fromIntervals, continue) where

> import qualified Haskore.Basic.Pitch as Pitch
> import Control.Monad(liftM2)

\end{haskelllisting}

Some of the following code is taken
from the EasyScale implementation of Martin Schwenke.

\begin{haskelllisting}

> type T = [Pitch.Absolute]
> type Intervals = [Pitch.Relative]

\end{haskelllisting}

Make a scale given a list of absolute pitches, usually starting at 0,
and a \type{Pitch.Class} representing the root note of the scale.

\begin{haskelllisting}

> fromOffsets :: [Pitch.Absolute] -> Pitch.Class -> T
> fromOffsets ns pc
>   = map (+ Pitch.classToInt pc) ns

\end{haskelllisting}

Create a scale from a list of intervals between successive notes.

\begin{haskelllisting}

> fromIntervals :: Intervals -> Pitch.Class -> T
> fromIntervals = fromOffsets . scanl (+) 0

\end{haskelllisting}

Continue a scale to all octaves.

\begin{haskelllisting}

> continue :: T -> T
> continue = liftM2 (+) (iterate (12+) 0)

\end{haskelllisting}

Now some general useful scales from music theory.

\begin{haskelllisting}

> ionianRel, dorianRel, phrygianRel, lydianRel, mixolydianRel,
>   aeolianRel, lokrianRel, alteredRel, htwtRel,
>   wthtRel :: Intervals

> ionianRel     = [ 2, 2, 1, 2, 2, 2, 1 ]
> dorianRel     = [ 2, 1, 2, 2, 2, 1, 2 ]
> phrygianRel   = [ 1, 2, 2, 2, 1, 2, 2 ]
> lydianRel     = [ 2, 2, 2, 1, 2, 2, 1 ]
> mixolydianRel = [ 2, 2, 1, 2, 2, 1, 2 ]
> aeolianRel    = [ 2, 1, 2, 2, 1, 2, 2 ]
> lokrianRel    = [ 1, 2, 2, 1, 2, 2, 2 ]
> alteredRel    = [ 1, 2, 1, 2, 2, 2, 2 ]
> htwtRel       = [ 1, 2, 1, 2, 1, 2, 1, 2 ]
> wthtRel       = [ 2, 1, 2, 1, 2, 1, 2, 1 ]

> ionian, dorian, phrygian, lydian, mixolydian,
>   aeolian, lokrian, altered, htwt,
>   wtht :: Pitch.Class -> T

> ionian     = fromIntervals ionianRel
> dorian     = fromIntervals dorianRel
> phrygian   = fromIntervals phrygianRel
> lydian     = fromIntervals lydianRel
> mixolydian = fromIntervals mixolydianRel
> aeolian    = fromIntervals aeolianRel
> lokrian    = fromIntervals lokrianRel
> altered    = fromIntervals alteredRel
> htwt       = fromIntervals htwtRel
> wtht       = fromIntervals wthtRel

\end{haskelllisting}

Example:
Alternatively to applying \function{continue} to a scale
you can create an infinitely increasing scale
using the definition by intervals,
e.g. \code{fromIntervals (cycle ionianRel) Pitch.C}.