\subsubsection{Pitch}
\seclabel{pitch}
Perhaps the most basic musical idea is that of a \keyword{pitch},
which consists of an \keyword{octave} and a \keyword{pitch class}
(i.e. one of 12 semi-tones, cf. \secref{discussion:pitch}):
\begin{haskelllisting}
> module Haskore.Basic.Pitch where
> import Data.Ix(Ix)
> type T = (Octave, Class)
> data Class = Cf | C | Cs | Df | D | Ds | Ef | E | Es | Ff | F | Fs
> | Gf | G | Gs | Af | A | As | Bf | B | Bs
> deriving (Eq,Ord,Ix,Enum,Show,Read)
> type Octave = Int
\end{haskelllisting}
So a \type{Pitch.T} is a pair consisting of a pitch class and an octave.
Octaves are just integers, but we define a datatype for pitch classes,
since distinguishing enharmonics (such as $G^\#$ and $A^b$) may be important
(especially for notation).
\figref{note-freqs} shows the meaning of the some \type{Pitch.T} values.
\begin{figure}
\begin{center}
\begin{tabular}{llr}
$A_2$ & \code{(-3,A)} & 27.5 Hz \\
$A_1$ & \code{(-2,A)} & 55.0 Hz \\
$A $ & \code{(-1,A)} & 110.0 Hz \\
$a $ & \code{( 0,A)} & 220.0 Hz \\
$a^1$ & \code{( 1,A)} & 440.0 Hz \\
$a^2$ & \code{( 2,A)} & 880.0 Hz
\end{tabular}
\end{center}
\caption{Note names, Haskore representations and frequencies.}
\figlabel{note-freqs}
\end{figure}
Treating pitches simply as integers is useful in many settings,
so let's also define some functions for converting between \type{Pitch.T}
values and \type{Pitch.Absolute} values (integers):
\begin{haskelllisting}
> type Absolute = Int
> type Relative = Int
>
> toInt :: T -> Absolute
> toInt (oct,pc) = 12*oct + classToInt pc
>
> fromInt :: Absolute -> T
> fromInt ap =
> let (oct, n) = divMod ap 12
> in (oct, [C,Cs,D,Ds,E,F,Fs,G,Gs,A,As,B] !! n)
>
> classToInt :: Class -> Relative
> classToInt pc = case pc of
> Cf -> 1; C -> 0; Cs -> 1
> Df -> 1; D -> 2; Ds -> 3
> Ef -> 3; E -> 4; Es -> 5
> Ff -> 4; F -> 5; Fs -> 6
> Gf -> 6; G -> 7; Gs -> 8
> Af -> 8; A -> 9; As -> 10
> Bf -> 10; B -> 11; Bs -> 12
\end{haskelllisting}
Now two functions for parsing and formatting pitch classes
in a more human way, that is using '\#' and 'b' suffixes
instead of 's' and 'f'.
We do not simply use
\begin{haskelllisting}
> classParse :: ReadS Class
> classParse (p:'#':r) = reads (p:'s':r)
> classParse (p:'b':r) = reads (p:'f':r)
> classParse r = reads r
> classFormat :: Class -> ShowS
> classFormat pc =
> let (p:r) = show pc
> in (p:) .
> case r of
> [] -> id
> 's':[] -> ('#':)
> 'f':[] -> ('b':)
> _ -> error ("classFormat: Pitch.Class.show must not return suffixes" ++
> " other than 's' and 'f'")
\end{haskelllisting}
Using \type{Pitch.Absolute} we can compute the frequency associated
with a pitch:
\begin{haskelllisting}
> intToFreq :: Floating a => Absolute -> a
> intToFreq ap = 440 * 2 ** (fromIntegral (ap toInt (1,A)) / 12)
\end{haskelllisting}
We can also define a function \function{Pitch.transpose},
which transposes pitches
(analogous to \function{Music.transpose},
which transposes values of type \type{Music.T}):
\begin{haskelllisting}
> transpose :: Relative -> T -> T
> transpose i p = fromInt (toInt p + i)
\end{haskelllisting}
\begin{exercise}
Show that\ \ \code{toInt\ .\ fromInt = id}, and,
up to enharmonic equivalences,\newline \code{fromInt\ .\ toInt = id}.
\end{exercise}
\begin{exercise}
Show that\ \ \code{transpose i (transpose j p) = transpose (i+j) p}.
\end{exercise}