\paragraph{Naming Instruments and Tables}

In CSound, each table and instrument has a unique identifying integer
associated with it.  Haskore, on the other hand, uses strings to name
instruments.  What we need is a way to convert Haskore instrument
names to identifier integers that CSound can use.  Similar to
Haskore's player maps, we define a notion of a \keyword{CSound name map}
for this purpose.
\begin{haskelllisting}

> module Haskore.Interface.CSound.InstrumentMap where
>
> import Haskore.Interface.CSound (PField, Instrument, instruments)
>
> import qualified Data.List as List

> type SoundTable instr = [(instr, Instrument)]

\end{haskelllisting}
A name map can be provided directly in the form
\code{[("name1", int1), ("name2", int2), ...]}, or the programmer can
define auxiliary functions to make map construction easier.
For example:
\begin{haskelllisting}

> tableFromInstruments :: [instr] -> SoundTable instr
> tableFromInstruments nms = zip nms $ instruments

\end{haskelllisting}
The following function will add a name to an existing name map.
If the name is already in the map, an error results.
\begin{haskelllisting}

> addToTable :: (Eq instr) =>
>    instr -> Instrument -> SoundTable instr -> SoundTable instr
> addToTable nm i instrMap =
>    if elem nm (map fst instrMap)
>      then ((nm,i) : instrMap)
>      else (error ("CSound.addToTable: instrument already in the map"))

\end{haskelllisting}

Note the use of the function \function{lookup} imported from \module{List}.
\begin{haskelllisting}

> type ToSound instr = instr -> ([PField], Instrument)

> lookup :: (Eq instr) => SoundTable instr -> ToSound instr
> lookup table instr =
>    maybe (error "CSound.InstrMap.lookup: instrument not found")
>          ((,) [])
>          (List.lookup instr table)

\end{haskelllisting}