myTestlll-1.0.0: HSoM/MoreMusic.lhs
%-*- mode: Latex; abbrev-mode: true; auto-fill-function: do-auto-fill -*-
%include lhs2TeX.fmt
%include myFormat.fmt
\out{
\begin{code}
-- This code was automatically generated by lhs2tex --code, from the file
-- HSoM/MoreMusic.lhs. (See HSoM/MakeCode.bat.)
\end{code}
}
\chapter{More Music}
\label{ch:more-music}
\begin{code}
module Euterpea.Music.Note.MoreMusic where
import Euterpea.Music.Note.Music
\end{code}
This chapter explores a number of simple musical ideas, and
contributes to a growing collection of Euterpea functions for
expressing those ideas.
%% \section{Lines and Chords}
%%
%% Two common ideas in music are the construction of notes in a
%% horizontal fashion (a \emph{line} or \emph{melody}), and in a vertical
%% fashion (a \emph{chord}):
%% \begin{code}
%% line, chord :: [Music a] -> Music a
%% line = foldr1 (:+:)
%% chord = foldr1 (:=:)
%% \end{code}
%% From the notes in the C major triad in register 4, I can now construct
%% a C major arpeggio and chord as well:
%% \begin{code}
%% cMaj = [ n 4 qn [] | n <- [c,e,g] ] -- octave 4, quarter notes
%% cMajArp = line cMaj
%% cMajChd = chord cMaj
%% \end{code}
\out{
\begin{code}
line, chord :: [Music a] -> Music a
line = foldr (:+:) (rest 0)
chord = foldr (:=:) (rest 0)
line1, chord1 :: [Music a] -> Music a
line1 = foldr1 (:+:)
chord1 = foldr1 (:=:)
\end{code}
}
\section{Delay and Repeat}
%% Suppose that we wish to describe a melody |m| accompanied by
%% an identical voice a perfect 5th higher. In Euterpea we can simply write
%% |m :=: transpose 7 m|.
We can delay the start of a music value simply by inserting a rest in
front of it, which can be packaged in a function as follows:
\begin{code}
delayM :: Dur -> Music a -> Music a
delayM d m = rest d :+: m
\end{code}
With |delayM| it is easy to write canon-like structures such as |m :=:
delayM d m|, a song written in rounds (see Exercise
\ref{ex:frere-jacques}), and so on.
Recall from Chapter \ref{ch:interlude} the function |timesM| that
repeats a musical phrase a certain number of times:
\begin{code}
timesM :: Int -> Music a -> Music a
timesM 0 m = rest 0
timesM n m = m :+: timesM (n-1) m
\end{code}
More interestingly, Haskell's non-strict semantics allows us to
define \emph{infinite} musical values. For example, a musical value
may be repeated \emph{ad nauseam} using this simple function:
\pagebreak
\begin{code}
repeatM :: Music a -> Music a
repeatM m = m :+: repeatM m
\end{code}
Thus, for example, an infinite ostinato can be expressed in this way,
and then used in different contexts that automatically extract only
the portion that is actually needed. Functions that create such
contexts will be described shortly.
\section{Inversion and Retrograde}
The notions of inversion, retrograde, retrograde inversion, etc.\ as
used in twelve-tone theory are also easily captured in Euterpea.
These terms are usually applied only to a ``line'' of notes, i.e.\ a
melody (in twelve-tone theory it is called a ``row''). The
\emph{retrograde} of a line is simply its reverse---i.e.\ the notes
played in the reverse order. The \emph{inversion} of a line is with
respect to a given pitch (by convention usually the first pitch),
where the intervals between successive pitches are inverted,
i.e.\ negated. If the absolute pitch of the first note is |ap|, then
each pitch |p| is converted into an absolute pitch |ap - (absPitch p -
ap)|, in other words |2*ap - absPitch p|.
To do all this in Haskell, a transformation from a line created by
|line| to a list is defined:
\begin{code}
lineToList :: Music a -> [Music a]
lineToList (Prim (Rest 0)) = []
lineToList (n :+: ns) = n : lineToList ns
lineToList _ =
error "lineToList: argument not created by function line"
\end{code}
Using this function it is then straightforward to define |invert|:
\begin{code}
invert :: Music Pitch -> Music Pitch
invert m =
let l@(Prim (Note _ r) : _) = lineToList m
inv (Prim (Note d p)) =
note d (pitch (2 * absPitch r - absPitch p))
inv (Prim (Rest d)) = rest d
in line (map inv l)
\end{code}
%% invert m = line (map inv l)
%% where l@(Prim (Note _ r) : _) = lineToList m
%% inv (Prim (Note d p)) =
%% note d (pitch (2 * absPitch r - absPitch p))
%% inv (Prim (Rest d)) = rest d
\syn{The pattern |l@(Prim (Note _ r) : _)| is called an \emph{as
pattern}. It behaves just like the pattern |Prim (Note _ r) : _|
but additionally binds |l| to the value of a successful match to
that pattern. |l| can then be used wherever it is in scope, such as
in the last line of the function definition.}
With |lineToList| and |invert| it is then easy to define the remaining
functions via composition:
\begin{code}
retro, retroInvert, invertRetro :: Music Pitch -> Music Pitch
retro = line . reverse . lineToList
retroInvert = retro . invert
invertRetro = invert . retro
\end{code}
As an example of these concepts, Figure~\ref{fig:twelve-tone} shows a
simple melody (not a complete twelve-tone row) and four
transformations of it.
\begin{figure*}
\centerline{
\epsfysize=1in
\epsfbox{pics/TwelveToneTransformationsCropped.eps}
}
\caption{A Simple Melody and Four Transformations}
\label{fig:twelve-tone}
\end{figure*}
\vspace{.1in}\hrule
\begin{exercise}{\em
Show that |retro . retro|, |invert . invert|, and
|retroInvert . invertRetro| are the identity on values created by
|line|. (You may use the lemma that |reverse (reverse l) = l|.)}
\end{exercise}
\begin{exercise}{\em
Define a function |properRow :: Music Pitch -> Bool| that determines
whether or not its argument is a ``proper'' twelve-tone row, meaning
that: (a) it must have exactly twelve notes, and (b) each unique pitch
class is used exactly once (regardless of the octave). Enharmonically
equivalent pitch classes are \emph{not} considered unique. You may
assume that the |Music Pitch| value is generated by the function
|line|, but note that rests are allowed.}
\end{exercise}
\begin{exercise}{\em
Define a function |palin :: Music Pitch -> Bool| that determines
whether or not a given line (as generated by the |line| function) is a
palindrome or not. You should ignore rests, and disregard note
durations---the main question is whether or not the melody is a
palindrome.}
\end{exercise}
\begin{exercise}{\em
Define a function |retroPitches :: Music Pitch -> Music Pitch| that
reverses the pitches in a line, but maintains the durations in the
same order from beginning to end. For example:
\begin{spec}
retroPitches (line [c 4 en, d 4 qn])
===> (line [d 4 en, c 4 qn])
\end{spec}}
\end{exercise}
\vspace{.1in}\hrule
\begin{figure*}
\centerline{
\epsfysize=2.0in
\epsfbox{Pics/pr12.eps}
}
\caption{Nested Polyrhythms (top: |pr1|; bottom: |pr2|)}
\label{polyrhythms}
\end{figure*}
\section{Polyrhythms}
For some rhythmical ideas, first note that if |m| is a line of three
eighth notes, then |tempo (3/2) m| is a \emph{triplet} of eighth notes
(recall that this idea was used in Chapter \ref{ch:interlude}). In
fact |tempo| can be used to create quite complex rhythmical patterns.
For example, consider the ``nested polyrhythms'' shown in Figure
\ref{polyrhythms}. They can be expressed naturally in Euterpea as
follows (note the use of a |let| clause in |pr2| to capture recurring
phrases):
\begin{code}
pr1, pr2 :: Pitch -> Music Pitch
pr1 p = tempo (5/6)
( tempo (4/3) ( mkLn 1 p qn :+:
tempo (3/2) ( mkLn 3 p en :+:
mkLn 2 p sn :+:
mkLn 1 p qn ) :+:
mkLn 1 p qn) :+:
tempo (3/2) ( mkLn 6 p en))
\end{code}
\pagebreak
\begin{code}
pr2 p =
let m1 = tempo (5/4) (tempo (3/2) m2 :+: m2)
m2 = mkLn 3 p en
in tempo (7/6) ( m1 :+:
tempo (5/4) (mkLn 5 p en) :+:
m1 :+:
tempo (3/2) m2)
mkLn :: Int -> p -> Dur -> Music p
mkLn n p d = line $ take n $ repeat $ note d p
\end{code} % $
\syn{|take n lst| is the first |n| elements of the list |lst|. For
example:
\begin{spec}
take 3 [C,Cs,Df,D,Ds] ===> [C,Cs,Df]
\end{spec}
|repeat x| is the infinite list of the same value |x|. For example:
\begin{spec}
take 3 (repeat 42) ===> [42,42,42]
\end{spec}
}
To play polyrhythms |pr1| and |pr2| in parallel using middle C
and middle G, respectively, we can write:
\begin{code}
pr12 :: Music Pitch
pr12 = pr1 (C,4) :=: pr2 (G,4)
\end{code}
\section{Symbolic Meter Changes}
We can implement the notion of ``symbolic meter changes'' of the form
``oldnote = newnote'' (quarter note = dotted eighth, for example) by
defining an infix function:
\begin{code}
(=:=) :: Dur -> Dur -> Music a -> Music a
old =:= new = tempo (new/old)
\end{code}
Of course, using the new function is not much shorter than using
|tempo| directly, but it may have mnemonic value.
\pagebreak
\section{Computing Duration}
\label{sec:duration}
It is often desirable to compute the \emph{duration}, in whole notes,
of a musical value; we can do so as follows:
\begin{code}
dur :: Music a -> Dur
dur (Prim (Note d _)) = d
dur (Prim (Rest d)) = d
dur (m1 :+: m2) = dur m1 + dur m2
dur (m1 :=: m2) = dur m1 `max` dur m2
dur (Modify (Tempo r) m) = dur m / r
dur (Modify _ m) = dur m
\end{code}
The duration of a primitive value is obvious. The duration of
|m1 :+: m2| is the sum of the two, and the duration of |m1 :=: m2| is
the maximum of the two. The only tricky case is the duration of a
music value that is modified by the |Tempo| atttribute---in this case
the duration must be scaled appropriately.
Note that the duration of a music value that is conceptually infinite
in duration will be |bottom|, since |dur| will not terminate.
(Similary, taking the length of an infinite list is |bottom|.) For
example:
\begin{spec}
dur (repeatM (a 4 qn))
==> dur (a 4 qn :+: repeatM (a 4 qn))
==> dur (a 4 qn) + dur (repeatM (a 4 qn))
==> qn + dur (repeatM (a 4 qn))
==> qn + qn + dur (repeatM (a 4 qn))
==> ...
==> bottom
\end{spec}
\section{Super-retrograde}
\label{sec:reverse-music}
Using |dur| we can define a function |revM| that reverses any |Music|
value whose duration is finite (and is thus considerably more useful
than |retro| defined earlier):
\pagebreak
\begin{code}
revM :: Music a -> Music a
revM n@(Prim _) = n
revM (Modify c m) = Modify c (revM m)
revM (m1 :+: m2) = revM m2 :+: revM m1
revM (m1 :=: m2) =
let d1 = dur m1
d2 = dur m2
in if d1>d2 then revM m1 :=: (rest (d1-d2) :+: revM m2)
else (rest (d2-d1) :+: revM m1) :=: revM m2
\end{code}
The first three cases are easy, but the last case is a bit tricky.
The parallel constructor |(:=:)| implicitly begins each of its music
values at the same time. But if one is shorter than the other, then,
when reversed, a \emph{rest} must be inserted before the shorter one,
to account for the difference.
Note that |revM| of a |Music| value whose duration is infinite is
|bottom|. (Analogously, reversing an infinite list is |bottom|.)
\section{|takeM| and |dropM|}
\label{sec:take-and-drop}
Two other useful operations on |Music| values is the ability to
``take'' the first so many beats (in whole notes), discarding the
rest, and conversely, the ability to ``drop'' the first so many beats,
returning what is left. We will first define a function |takeM :: Dur
-> Music a -> Music a| such that |takeM d m| is a \emph{prefix} of |m|
having duration |d|. In other words, it ``takes'' only the first |d|
beats (in whole notes) of |m|. We can define this function as
follows:
\begin{code}
takeM :: Dur -> Music a -> Music a
takeM d m | d <= 0 = rest 0
takeM d (Prim (Note oldD p)) = note (min oldD d) p
takeM d (Prim (Rest oldD)) = rest (min oldD d)
takeM d (m1 :=: m2) = takeM d m1 :=: takeM d m2
takeM d (m1 :+: m2) = let m'1 = takeM d m1
m'2 = takeM (d - dur m'1) m2
in m'1 :+: m'2
takeM d (Modify (Tempo r) m) = tempo r (takeM (d*r) m)
takeM d (Modify c m) = Modify c (takeM d m)
\end{code}
This definition is fairly straightforward, except for the case of
sequential composition, where two cases arise: (1) if |d| is greater
than |dur m1|, then we return \emph{all} of |m1| (i.e.\ |m'1 = m1|),
followed by |d - dur m'1| beats of |m2|, and (2) if |d| is less than
|dur m1|, then we return |d| beats of |m1| (i.e. |m'1|), followed by
nothing (since |d - dur m'1| will be zero). Note that this strategy
will work even if |m1| or |m2| is infinite.
\out{
For backward compatibility:
\begin{code}
cut :: Dur -> Music a -> Music a
cut = takeM
\end{code}
}
Similarly, we can define a function |dropM :: Dur -> Music a -> Music
a| such that |dropM d m| is a \emph{suffix} of |m| where the first |d|
beats (in whole notes) of |m| have been ``dropped:''
\begin{code}
dropM :: Dur -> Music a -> Music a
dropM d m | d <= 0 = m
dropM d (Prim (Note oldD p)) = note (max (oldD-d) 0) p
dropM d (Prim (Rest oldD)) = rest (max (oldD-d) 0)
dropM d (m1 :=: m2) = dropM d m1 :=: dropM d m2
dropM d (m1 :+: m2) = let m'1 = dropM d m1
m'2 = dropM (d - dur m1) m2
in m'1 :+: m'2
dropM d (Modify (Tempo r) m) = tempo r (dropM (d*r) m)
dropM d (Modify c m) = Modify c (dropM d m)
\end{code}
This definition is also straightforward, except for the case of
sequential composition. Again, two cases arise: (1) if |d| is greater
than |dur m1|, then we drop |m1| altogether (i.e.\ |m'1| will be |rest
0|), and simply drop |d - dur m1| from |m2|, and (2) if |d| is less
than |dur m1|, then we return |m'1| followed by all of |m2| (since |d
- dur m1| will be negative). This definition too will work for
infinite values of |m1| or |m2|.
\section{Removing Zeros}
\label{sec:zeros}
Note that functions such as |timesM|, |line|, |revM|, |takeM| and
|dropM| occasionally insert rests of zero duration, and in the case of
|takeM| and |dropM|, may insert notes of zero duration. Doing this
makes the code simpler and more elegant, and since we cannot hear the
effect of the zero-duration events, the musical result is the same.
On the other hand, these extraneous notes and rests (which we will
call ``zeros'') can be annoying when viewing the textual (rather than
audible) representation of the result. To alleviate this problem, we
define a function that removes them from a given |Music| value:
\pagebreak
\begin{code}
removeZeros :: Music a -> Music a
removeZeros (Prim p) = Prim p
removeZeros (m1 :+: m2) =
let m'1 = removeZeros m1
m'2 = removeZeros m2
in case (m'1,m'2) of
(Prim (Note 0 p), m) -> m
(Prim (Rest 0 ), m) -> m
(m, Prim (Note 0 p)) -> m
(m, Prim (Rest 0 )) -> m
(m1, m2) -> m1 :+: m2
removeZeros (m1 :=: m2) =
let m'1 = removeZeros m1
m'2 = removeZeros m2
in case (m'1,m'2) of
(Prim (Note 0 p), m) -> m
(Prim (Rest 0 ), m) -> m
(m, Prim (Note 0 p)) -> m
(m, Prim (Rest 0 )) -> m
(m1, m2) -> m1 :=: m2
removeZeros (Modify c m) = Modify c (removeZeros m)
\end{code}
\syn{A |case| expression can only match against one value. To match
against more than one value, we can place them in a tuple of the
appropriate length. In the case above, |removeZeros| matches
against |m'1| and |m'2| by placing them in a pair |(m'1,m'2)|.}
This function depends on the ``musical axioms'' that if |m1| in either
|m1 :+: m2| or |m1 :=: m2| is a zero, then the latter expressions are
equivalent to just |m2|. Similarly, if |m2| is a zero, they are
equivalent to just |m1|. Although intuitive, a formal proof of these
axioms is deferred until Chapter \ref{ch:algebra}.
As an example of using |removeZeros|, consider the |Music| value:
\begin{spec}
m = c 4 en :+: repeatM (d 4 en)
\end{spec}
\pagebreak
Then note that:
\begin{spec}
takeM hn (dropM hn m)
===>
Prim (Note (0 % 1) (C,4)) :+: (Prim (Note (0 % 1) (D,4)) :+:
(Prim (Note (0 % 1) (D,4)) :+: (Prim (Note (0 % 1) (D,4)) :+:
(Prim (Note (1 % 8) (D,4)) :+: (Prim (Note (1 % 8) (D,4)) :+:
(Prim (Note (1 % 8) (D,4)) :+: (Prim (Note (1 % 8) (D,4)) :+:
Prim (Rest (0 % 1)))))))))
\end{spec}
Note the zero-duration notes and rests. But if we apply |removeZeros|
to the result we get:
\begin{spec}
removeZeros (takeM hn (dropM hn m))
===>
Prim (Note (1 % 8) (D,4)) :+: (Prim (Note (1 % 8) (D,4)) :+:
(Prim (Note (1 % 8) (D,4)) :+: Prim (Note (1 % 8) (D,4))))
\end{spec}
Both the zero-duration rests and notes have been removed.
\section{Truncating Parallel Composition}
\label{sec:truncate}
The duration of |m1 :=: m2| is the maximum of the durations of |m1|
and |m2| (and thus if one is infinite, so is the result). However,
sometimes it is useful to have the result be of duration equal to the
\emph{shorter} of the two. Defining a function to achieve this is not
as easy as it sounds, since it may require truncating the longer one
in the middle of a note (or notes), and it may be that one (or both)
of the |Music| values is infinite.
The goal is to define a ``truncating parallel composition'' operator
|(/=:) :: Music a -> Music a -> Music a|. Using |takeM|, we can make
an initial attempt at a suitable definition for |(/=:)| as follows:
\begin{spec}
(/=:) :: Music a -> Music a -> Music a
m1 /=: m2 = takeM (dur m2) m1 :=: takeM (dur m1) m2
\end{spec}
%% (min (dur m1) (dur m2)) (m1 :=: m2)
Unfortunately, whereas |takeM| can handle infinite-duration music
values, |(/=:)| cannot. This is because |(/=:)| computes the duration
of both of its arguments, but if one of them, say |m1|, has infinite
duration, then |dur m1 ==> bottom|. If, in a particular context, we
know that only one of the two arguments is infinite, and we know which
one (say |m1|), it is always possible to write:
\begin{spec}
takeM (dur m2) m1 :=: m2
\end{spec}
But somehow this seems unsatisfactory.
\subsection{Lazy Evaluation to the Rescue}
\label{sec:lazy-rescue}
The root of this problem is that |dur| uses a conventional number
type, namely the type |Rational| (which is a ratio of |Integer|s), to
compute with, which does not have a value for infinity (|bottom| is
not the same as infinity!). But what if we were to somehow compute
the duration \emph{lazily}---meaning that we only compute that much of
the duration that is needed to perform some arithmetic result of
interest. In particular, if we have one number |n| that we know is
``at least'' |x|, and another number |m| that is exactly |y|, then if
|x>y|, we know that |n>m|, even if |n|'s actual value is infinity!
To realize this idea, let's first define a type synonym for ``lazy
durations:''
\begin{code}
type LazyDur = [Dur]
\end{code}
The intent is that a value |d :: LazyDur| is a non-decreasing list of
durations such that the last element in the list is the actual
duration, and an infinite list implies an infinite duration.
Now let's define a new verion of |dur| that computes the |LazyDur| of
its argument:
\begin{code}
durL :: Music a -> LazyDur
durL m@(Prim _) = [dur m]
durL (m1 :+: m2) = let d1 = durL m1
in d1 ++ map (+(last d1)) (durL m2)
durL (m1 :=: m2) = mergeLD (durL m1) (durL m2)
durL (Modify (Tempo r) m) = map (/r) (durL m)
durL (Modify _ m) = durL m
\end{code}
where |mergeLD| merges two |LazyDur| values into one:
\begin{code}
mergeLD :: LazyDur -> LazyDur -> LazyDur
mergeLD [] ld = ld
mergeLD ld [] = ld
mergeLD ld1@(d1:ds1) ld2@(d2:ds2) =
if d1<d2 then d1 : mergeLD ds1 ld2
else d2 : mergeLD ld1 ds2
\end{code}
We can then define a function |minL| to compare a |LazyDur| with
a regular |Dur|, returning the least |Dur| as a result:
\begin{code}
minL :: LazyDur -> Dur -> Dur
minL [] d' = d'
minL [d] d' = min d d'
minL (d:ds) d' = if d < d' then minL ds d' else d'
\end{code}
And with |minL| we can then define a new version of |takeM|:
\begin{code}
takeML :: LazyDur -> Music a -> Music a
takeML [] m = rest 0
takeML (d:ds) m | d <= 0 = takeML ds m
takeML ld (Prim (Note oldD p)) = note (minL ld oldD) p
takeML ld (Prim (Rest oldD)) = rest (minL ld oldD)
takeML ld (m1 :=: m2) = takeML ld m1 :=: takeML ld m2
takeML ld (m1 :+: m2) =
let m'1 = takeML ld m1
m'2 = takeML (map (\d -> d - dur m'1) ld) m2
in m'1 :+: m'2
takeML ld (Modify (Tempo r) m) = tempo r (takeML (map (*r) ld) m)
takeML ld (Modify c m) = Modify c (takeML ld m)
\end{code}
Compare this definition with that of |takeM|---they are very similar.
Finally, we can define a correct (meaning it works properly on
infinite |Music| values) version of |(/=:)| as follows:
\begin{code}
(/=:) :: Music a -> Music a -> Music a
m1 /=: m2 = takeML (durL m2) m1 :=: takeML (durL m1) m2
\end{code}
Whew! This may seem like a lot of effort, but the new code is
actually not much different from the old, and now we can freely use
|(/=:)| without worrying about which if any of its arguments are
infinite.
\out{
A potential generalization of these ideas:
Let's represent numbers as a non-empty list of monotonically
increasing numbers whose last number is the limit:
newtype ANum a = ANum [a]
deriving (Eq, Show)
instance Num a => Num (ANum a) where
ANum xs + ANum ys = ANum (nLift (+) xs ys)
--ANum xs - ANum ys = ANum (nLift (-) xs ys) -- not valid!!!
ANum xs - ANum ys = ANum (nSub xs ys)
ANum xs * ANum ys = ANum (nLift (*) xs ys)
abs (ANum xs) = ANum (map abs xs)
signum (ANum xs) = ANum (map signum xs)
fromInteger x = ANum [fromInteger x]
nLift op [x] ys = map (x `op`) ys
nLift op xs [y] = map (`op` y) xs
nLift op (x:xs) (y:ys) = (x `op` y) : nLift op xs ys
nSub [x] ys = map (x-) ys
nSub xs [y] = map (subtract y) xs
nSub (x:xs) (y:ys) = nSub xs ys
ANum [x] =* ANum [y] = x == y
ANum (x:xs) =* ANum (y:ys) = ANum xs =* ANum ys
ANum [x] >* ANum (y:ys) = if x<=y then False else ANum [x] >* ANum ys
ANum (x:xs) >* ANum [y] = if x>y then True else ANum xs >* ANum [y]
ANum (x:xs) >* ANum (y:ys) = ANum xs >* ANum ys
an1 >=* an2 = an1 >* an2 || an1 =* an2
an1 <* an2 = not (an1 >=* an2)
an1 <=* an2 = not (an1 >* an2)
The reason that subtraction cannot be handled like addition or
multiplication is that, if one number is at least x and another number
is at least y, we cannot conclude ANYTHING about the difference
between them.
Here are the merge functions for the parallel short constructor:
mergeS :: Performance -> Performance -> Performance
mergeS a@(e1:es1)) b@(e2:es2)) =
if e1 < e2 then foo e1 es1 b
else foo e2 a es2
merge [] es2 = []
merge es1 [] = []
foo e es1 es2 =
let pf = mergeS es1 es2
dft = eTime (head pf) - eTime e
d = min (eDur e) (aDur pf + dft)
in e { eDur = d } : pf
aDur es = Anum (foo 0 es)
where foo d [] = d
foo d (e:es) =
}
\vspace{.1in}\hrule
\begin{exercise}{\em
Try using |(/=:)| with some infinite |Music| values (such as created
by |repeatM|) to assure yourself that it works properly. When using
it with \emph{two} infinite values, it should return an infinite
value, which you can test by applying |takeM| to the result.}
\end{exercise}
\vspace{.1in}\hrule
\section{Trills}
\label{sec:trills}
A \emph{trill} is an ornament that alternates rapidly between two
(usually adjacent) pitches. Two versions of a trill function will be
defined, both of which take the starting note and an interval for the
trill note as arguments (the interval is usually one or two, but can
actually be anything). One version will additionally have an argument
that specifies how long each trill note should be, whereas the other
will have an argument that specifies how many trills should occur. In
both cases the total duration will be the same as the duration of the
original note.
Here is the first trill function:
\begin{code}
trill :: Int -> Dur -> Music Pitch -> Music Pitch
trill i sDur (Prim (Note tDur p)) =
if sDur >= tDur then note tDur p
else note sDur p :+:
trill (negate i) sDur
(note (tDur-sDur) (trans i p))
trill i d (Modify (Tempo r) m) = tempo r (trill i (d*r) m)
trill i d (Modify c m) = Modify c (trill i d m)
trill _ _ _ =
error "trill: input must be a single note."
\end{code}
Using this function it is simple to define a version that starts on the
trill note rather than the start note:
\begin{code}
trill' :: Int -> Dur -> Music Pitch -> Music Pitch
trill' i sDur m = trill (negate i) sDur (transpose i m)
\end{code}
The second way to define a trill is in terms of the number of
subdivided notes to be included in the trill. We can use the first
trill function to define this new one:
\begin{code}
trilln :: Int -> Int -> Music Pitch -> Music Pitch
trilln i nTimes m = trill i (dur m / fromIntegral nTimes) m
\end{code}
This, too, can be made to start on the other note.
\begin{code}
trilln' :: Int -> Int -> Music Pitch -> Music Pitch
trilln' i nTimes m = trilln (negate i) nTimes (transpose i m)
\end{code}
Finally, a |roll| can be implemented as a trill whose interval is
zero. This feature is particularly useful for percussion.
\begin{code}
roll :: Dur -> Music Pitch -> Music Pitch
rolln :: Int -> Music Pitch -> Music Pitch
roll dur m = trill 0 dur m
rolln nTimes m = trilln 0 nTimes m
\end{code}
Figure \ref{fig:ssf} shows a nice use of the trill functions in
encoding the opening lines of John Philip Sousa's \emph{Stars and
Stripes Forever}.
\begin{figure}
\cbox{
\begin{code}
ssfMel :: Music Pitch
ssfMel = line (l1 ++ l2 ++ l3 ++ l4)
where l1 = [ trilln 2 5 (bf 6 en), ef 7 en, ef 6 en, ef 7 en ]
l2 = [ bf 6 sn, c 7 sn, bf 6 sn, g 6 sn, ef 6 en, bf 5 en ]
l3 = [ ef 6 sn, f 6 sn, g 6 sn, af 6 sn, bf 6 en, ef 7 en ]
l4 = [ trill 2 tn (bf 6 qn), bf 6 sn, denr ]
starsAndStripes :: Music Pitch
starsAndStripes = instrument Flute ssfMel
\end{code}}
\caption{Trills in \emph{Stars and Stripes Forever}}
\label{fig:ssf}
\end{figure}
\syn{|ssfMel| uses a |where| clause, which is similar to a |let|
expression, except that the equations appear after the result,
rather than before.}
\section{Grace Notes}
\label{sec:grace-notes}
Recall from Chapter \ref{ch:interlude} the function |graceNote| to
generate grace notes. A more general version is defined below, which
takes a |Rational| argument that specifies that fraction of the
principal note's duration to be used for the grace note's duration:
\begin{code}
grace :: Int -> Rational -> Music Pitch -> Music Pitch
grace n r (Prim (Note d p)) =
note (r*d) (trans n p) :+: note ((1-r)*d) p
grace n r _ =
error "grace: can only add a grace note to a note"
\end{code}
Thus |grace n r (note d p)| is a |Music| value consisting of two
notes, the first being the grace note whose duration is |r*d| and
whose pitch is |n| semitones higher (or lower if |n| is negative) than
|p|, and the second being the principal note at pitch |p| but now with
duration |(1-r)*d|.
Note that |grace| places the downbeat of the grace note at the point
written for the principal note. Sometimes the interpretation of a
grace note is such that the downbeat of the principal note is to be
unchanged. In that case, the grace note reduces the duration of the
\emph{previous} note. We can define a function |grace2| that takes
two notes as arguments, and places the grace note appropriately:
\begin{code}
grace2 :: Int -> Rational ->
Music Pitch -> Music Pitch -> Music Pitch
grace2 n r (Prim (Note d1 p1)) (Prim (Note d2 p2)) =
note (d1-r*d2) p1 :+: note (r*d2) (trans n p2) :+: note d2 p2
grace2 _ _ _ _ =
error "grace2: can only add a grace note to a note"
\end{code}
\vspace{.1in}\hrule
\begin{exercise}{\em
Related to trills and grace notes in Western classical music are the
notions of \emph{mordent}, \emph{turn}, and \emph{appoggiatura}.
Define functions to realize these musical ornamentations.}
\end{exercise}
\vspace{.1in}\hrule
\section{Percussion}
\label{sec:percussion}
Percussion is a difficult notion to represent in the abstract. On one
hand, 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, although 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 pitches 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.
\begin{figure}
\cbox{\small
\begin{spec}
data PercussionSound =
AcousticBassDrum -- MIDI Key 35
| BassDrum1 -- MIDI Key 36
| SideStick -- ...
| AcousticSnare | HandClap | ElectricSnare | LowFloorTom
| ClosedHiHat | HighFloorTom | PedalHiHat | LowTom
| OpenHiHat | LowMidTom | HiMidTom | CrashCymbal1
| HighTom | RideCymbal1 | ChineseCymbal | RideBell
| Tambourine | SplashCymbal | Cowbell | CrashCymbal2
| Vibraslap | RideCymbal2 | HiBongo | LowBongo
| MuteHiConga | OpenHiConga | LowConga | HighTimbale
| LowTimbale | HighAgogo | LowAgogo | Cabasa
| Maracas | ShortWhistle | LongWhistle | ShortGuiro
| LongGuiro | Claves | HiWoodBlock | LowWoodBlock
| MuteCuica | OpenCuica | MuteTriangle
| OpenTriangle -- MIDI Key 82
\end{spec}}
\caption{General MIDI Percussion Names}
\label{fig:percussion}
\end{figure}
\out{
\begin{code}
data PercussionSound =
AcousticBassDrum -- MIDI Key 35
| BassDrum1 -- MIDI Key 36
| SideStick -- ...
| AcousticSnare | HandClap | ElectricSnare | LowFloorTom
| ClosedHiHat | HighFloorTom | PedalHiHat | LowTom
| OpenHiHat | LowMidTom | HiMidTom | CrashCymbal1
| HighTom | RideCymbal1 | ChineseCymbal | RideBell
| Tambourine | SplashCymbal | Cowbell | CrashCymbal2
| Vibraslap | RideCymbal2 | HiBongo | LowBongo
| MuteHiConga | OpenHiConga | LowConga | HighTimbale
| LowTimbale | HighAgogo | LowAgogo | Cabasa
| Maracas | ShortWhistle | LongWhistle | ShortGuiro
| LongGuiro | Claves | HiWoodBlock | LowWoodBlock
| MuteCuica | OpenCuica | MuteTriangle
| OpenTriangle -- MIDI Key 82
deriving (Show,Eq,Ord,Enum)
\end{code}
}
Since MIDI is such a popular platform, it is worth defining some handy
functions for using the General MIDI Standard. In Figure
\ref{fig:percussion} a data type is defined that 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
Euterpea terminology. So all that remains to be done is a way to
convert these percussion sound names into a |Music| value; i.e.\ a
|Note|:
\begin{code}
perc :: PercussionSound -> Dur -> Music Pitch
perc ps dur = note dur (pitch (fromEnum ps + 35))
\end{code}
\syn{|fromEnum| is an operator in the |Enum| class, which is all about
enumerations, and will be discussed in more detail in
Chapter~\ref{ch:qualified-types}. A data type that is a member of
this class can be \emph{enumerated}---i.e.\ the elements of the data
type can be listed in order. |fromEnum| maps each value to its
index in this enumeration. Thus |fromEnum AcousticBassDrum| is 0,
|fromEnum BassDrum1| is 1, and so on.}
If a |Music| value returned from |perc| is played using a piano sound,
then you will get a piano sound. But if you specify the instrument
|Percussion|, MIDI knows to play the apppropriate |PercussionSound|.
Recall the |InstrumentName| data type from Chapter~\ref{ch:music}.
If a |Music| value returned from |perc| is played using, say, the
|AcousticGrandPiano| instrument, then you will hear an acounstic grand
piano sound at the appropriate pitch. But if you specify the
|Percussion| instrument, then you will hear the percussion sound that
was specified as an argument to |perc|.
For example, here are eight bars of a simple rock or ``funk groove''
that uses |perc| and |roll|:
\begin{code}
funkGroove :: Music Pitch
funkGroove
= let p1 = perc LowTom qn
p2 = perc AcousticSnare en
in tempo 3 $ instrument Percussion $ takeM 8 $ repeatM
( ( p1 :+: qnr :+: p2 :+: qnr :+: p2 :+:
p1 :+: p1 :+: qnr :+: p2 :+: enr)
:=: roll en (perc ClosedHiHat 2) )
\end{code} % $
\out{ We can go one step further by defining a ``percussion
datatype:''
\begin{spec}
data Percussion = Perc Dur [NoteAttribute] -- percussion
| Pause Dur -- rest
| Roll Dur Dur [NoteAttribute] -- roll w/duration
| Rolln Int Dur [NoteAttribute] -- roll w/number of strokes
\end{spec}
whose interpretation is given by:
\begin{spec}
percLine :: PercussionSound -> [Percussion] -> Music a
percLine dsnd l = Instr "Drums" (foldr (dlAux dsnd) (Rest 0) l) where
dlAux dsnd (N dur na) = perc dsnd dur na :+: xs
dlAux dsnd (R dur) = Rest dur :+: xs
dlAux dsnd (Roll sDur dur na) = roll sDur (perc dsnd dur na) :+: xs
dlAux dsnd (Rolln nTimes dur na) = rolln nTimes (perc dsnd dur na)
:+: dlAux dsnd xs
\end{spec}
}
\vspace{.1in}\hrule
\begin{exercise}{\em
Write a program that generates all of the General MIDI percussion
sounds, playing through each of them one at a time.}
\end{exercise}
\begin{exercise}{\em
Find a drum beat that you like, and express it in Euterpea. Then use
|repeatM|, |takeM|, and |(:=:)| to add a simple melody to it.}
\end{exercise}
\vspace{.1in}\hrule
\section{A Map for Music}
\label{sec:music-map}
Recall from Chapter \ref{ch:poly} the definition of |map|:
\begin{spec}
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs
\end{spec}
This function is defined on the list data type. Is there something
analogous for |Music|? I.e.\ a function:\footnote{The name |mapM|
would perhaps have been a better choice here, to be consistent with
previous names. However, |mapM| is a predefined function in Haskell,
and thus |mMap| is used instead. Similarly, Haskell's |Monad|
library defines a function |foldM|, and thus in the next section
the name |mFold| is used instead.}
\begin{spec}
mMap :: (a -> b) -> Music a -> Music b
\end{spec}
Such a function is indeed straightforward to define, but it helps to
first define a map-like function for the |Primitive| type:
\begin{code}
pMap :: (a -> b) -> Primitive a -> Primitive b
pMap f (Note d x) = Note d (f x)
pMap f (Rest d) = Rest d
\end{code}
With |pMap| in hand we can now define |mMap|:
\begin{code}
mMap :: (a -> b) -> Music a -> Music b
mMap f (Prim p) = Prim (pMap f p)
mMap f (m1 :+: m2) = mMap f m1 :+: mMap f m2
mMap f (m1 :=: m2) = mMap f m1 :=: mMap f m2
mMap f (Modify c m) = Modify c (mMap f m)
\end{code}
Just as |map f xs| for lists replaces each polymorphic element |x| in
|xs| with |f x|, |mMap f m| for |Music| replaces each polymorphic
element |p| in |m| with |f p|.
As an example of how |mMap| can be used, let's introduces a |Volume|
type for a note:
\begin{code}
type Volume = Int
\end{code}
The goal is to convert a value of type |Music Pitch| into a value of
type |Music (Pitch,Volume)|---that is, to pair each pitch with a
volume attribute. We can define a function to do so as follows:
\begin{code}
addVolume :: Volume -> Music Pitch -> Music (Pitch,Volume)
addVolume v = mMap (\p -> (p,v))
\end{code}
For MIDI, the variable |v| can range from 0 (softest) to 127 (loudest).
For example, compare the loudness of these two phrases:
\begin{spec}
m1, m2 :: Music (Pitch,Volume)
m1 = addVolume 100 (c 4 qn :+: d 4 qn :+: e 4 qn :+: c 4 qn)
m2 = addVolume 30 (c 4 qn :+: d 4 qn :+: e 4 qn :+: c 4 qn)
\end{spec}
using the |play| function. (Recall from Section~\ref{auxiliaries}
that the type of the argument to |play| must be made clear, as is done
here with the type signature.)
%% Currently the |play| function in Euterpea does not know how to play a
%% value of type |Music (Pitch,Volume)|, but it does know how to play a
%% value of type |Music (Pitch, [NoteAttribute])|. The |NoteAtttribute|
%% data type is not defined until Chapter~\ref{ch:performance}, but for
%% now it suffices to know that one of its constructors is |Volume|, and
%% thus we can define a function
%% \begin{code}
%% addVol :: Volume -> Music Pitch -> Music (Pitch, [NoteAttribute])
%% addVol v = mMap (\p -> (p, [Volume v]))
%% \end{code}
%% So if you wish to hear the effect of adding volume to a |Music| value,
%% use |addVol|, not |addVolume|.)
\syn{Note that the name |Volume| is used both as a type synonym and as
a constructor---Haskell allows this, since they can always be
distinguished by context.}
\out{
\begin{code}
data NoteAttribute =
Volume Int -- MIDI convention: 0=min, 127=max
| Fingering Integer
| Dynamics String
| Params [Double]
deriving (Eq, Show)
\end{code}
}
\vspace{.1in}\hrule
\begin{exercise}{\em
Using |mMap|, define a function:
\begin{spec}
scaleVolume :: Rational -> Music (Pitch,Volume)
-> Music (Pitch,Volume)
\end{spec}
such that |scaleVolume s m| scales the volume of each note in |m| by
the factor |s|.
(This problem requires multiplying a |Rational| number by an |Int|
(i.e.\ |Volume|). To do this, some coercions between number types are
needed, which in Haskell is done using \emph{qualified types}, which
are discussed in Chapter~\ref{ch:qualified-types}. For now, you can
simply do the following: If |v| is the volume of a note, then
|round (s * fromIntegral v)| is the desired scaled volume.)}
\end{exercise}
\vspace{.1in}\hrule
\pagebreak
\section{A Fold for Music}
\label{sec:music-fold}
We can also define a fold-like operator for |Music|. But whereas the
list data type has only two constructors (the nullary constructor |[]|
and the binary constructor |(:)|), |Music| has \emph{four}
constructors (|Prim|, (:+:), (:=:), and |Modify|). Thus the following
function takes four arguments in addition to the |Music| value it is
transforming, instead of two:
\begin{code}
mFold :: (Primitive a -> b) -> (b->b->b) -> (b->b->b) ->
(Control -> b -> b) -> Music a -> b
mFold f (+:) (=:) g m =
let rec = mFold f (+:) (=:) g
in case m of
Prim p -> f p
m1 :+: m2 -> rec m1 +: rec m2
m1 :=: m2 -> rec m1 =: rec m2
Modify c m -> g c (rec m)
\end{code}
This somewhat unwieldy function basically takes apart a |Music| value
and puts it back together with different constructors. Indeed, note
that:
\begin{spec}
mFold Prim (:+:) (:=:) Modify m == m
\end{spec}
Although intuitive, proving this property requires induction, a proof
technique discussed in Chapter \ref{ch:induction}.
To see how |mFold| might be used, note first of all that it is more
general than |mMap|---indeed, |mMap| can be defined in terms of
|mFold| like this:
\begin{spec}
mMap :: (a -> b) -> Music a -> Music b
mMap f = mFold g (:+:) (:=:) Modify where
g (Note d x) = note d (f x)
g (Rest d) = rest d
\end{spec}
More interestingly, we can use |mFold| to more succinctly define
functions such as |dur| from Section \ref{sec:duration}:
\begin{spec}
dur :: Music a -> Dur
dur = mFold getDur (+) max modDur where
getDur (Note d _) = d
getDur (Rest d) = d
modDur (Tempo r) d = d/r
modDur _ d = d
\end{spec}
\vspace{.1in}\hrule
\begin{exercise}{\em
Redefine |revM| from Section \ref{sec:reverse-music} using |mFold|.}
\end{exercise}
\begin{exercise}{\em
Define a function |insideOut| that inverts the role of serial and
parallel composition in a |Music| value. Using |insideOut|, see if
you can (a) find a non-trivial value |m :: Music Pitch| such that |m|
is ``musically equivalent'' to (i.e. sounds the same as) |insideOut m|
and (b) find a value |m :: Music Pitch| such that |m :+: insideOut m
:+: m| sounds interesting. (You are free to define what ``sounds
interesting'' means.)}
\end{exercise}
\vspace{.1in}\hrule
\section{Crazy Recursion}
With all the functions and data types that have been defined, and the
power of recursion and higher-order functions well understood, we can
start to do some wild and crazy things with music. Here is just one
such idea.
The goal is to define a function to recursively apply transformations
|f| (to elements in a sequence) and |g| (to accumulated phrases) some
specified number of times:
\begin{code}
rep :: (Music a -> Music a) -> (Music a -> Music a) -> Int
-> Music a -> Music a
rep f g 0 m = rest 0
rep f g n m = m :=: g (rep f g (n-1) (f m))
\end{code}
With this simple function we can create some interesting phrases of
music with very little code. For example, |rep| can be used three
times, nested together, to create a ``cascade'' of sounds:
\out{
\begin{code}
run, cascade, cascades, final :: Music Pitch
run', cascade', cascades', final' :: Music Pitch
\end{code}
}
\begin{code}
run = rep (transpose 5) (delayM tn) 8 (c 4 tn)
cascade = rep (transpose 4) (delayM en) 8 run
cascades = rep id (delayM sn) 2 cascade
\end{code}
We can then make the cascade run up, and then down:
\begin{code}
final = cascades :+: revM cascades
\end{code}
What happens if the |f| and |g| arguments are reversed?
\begin{code}
run' = rep (delayM tn) (transpose 5) 8 (c 4 tn)
cascade' = rep (delayM en) (transpose 4) 8 run'
cascades' = rep (delayM sn) id 2 cascade'
final' = cascades' :+: revM cascades'
\end{code}
\vspace{.1in}\hrule
\pagebreak
\begin{exercise}{\em
Consider this sequence of 8 numbers:
\begin{spec}
s1 = [ 1, 5, 3, 6, 5, 0, 1, 1 ]
\end{spec}
We might interpret this as a sequence of pitches, i.e.\ a melody.
Another way to represent this sequence is as a sequence of 7 intervals:
\begin{spec}
s2 = [ 4, -2, 3, -1, -5, 1, 0 ]
\end{spec}
Together with the starting pitch (i.e.\ 1), this sequence of intervals
can be used to reconstruct the original melody. But, with a suitable
transposition to eliminate negative numbers, it can also be viewed as
another melody. Indeed, we can repeat the process: |s2| can be
represented by this sequence of 6 intervals:
\begin{spec}
s3 = [ -6, 5, -4, -4, 6, -1 ]
\end{spec}
Together with the starting number (i.e.\ 4), |s3| can be used to
reconstruct |s2|. Continuing the process:
\begin{spec}
s4 = [ 11, -9, 0, 10, -7 ]
s5 = [ -20, 9, 10, -17 ]
s6 = [ 29, 1, -27 ]
s7 = [ -28, -28 ]
s8 = [ 0 ]
\end{spec}
Now, if we take the first element of each of these sequences to form
this 8-number sequence:
\begin{spec}
ic = [ 0, -28, 29, -20, 11, -6, 4, 1 ]
\end{spec}
then it alone can be used to re-create the original 8-number sequence
in its entirety. Of course, it can also be used as the original
melody was used, and we could derive another 8-note sequence from
it---and so on. The list |ic| will be referred to as the ``interval
closure'' of the original list |s1|.
Your job is to:
\begin{enumerate}[a)]
\item
Define a function |toIntervals| that takes a list of |n| numbers, and
generates a list of |n| lists, such that the $i^{th}$ list is the sequence
$s_i$ as defined above.
\item
Define a function |getHeads| that takes a list of |n| lists and
returns a list of |n| numbers such that the $i^{th}$ element is the
head of the $i^{th}$ list.
\item
Compose the above two functions in a suitable way to define a function
|intervalClosure| that takes an |n|-element list and returns its
interval closure.
\item
Define a function |intervalClosures| that takes an |n|-element list and
returns an infinite sequence of interval closures.
\item
Now for the open-ended part of this exercise: Interpret the outputs of
any of the functions above to create some ``interesting'' music.
\end{enumerate}
}
\end{exercise}
\begin{exercise}{\em
Write a Euterpea program that sounds like an infinitely descending (in
pitch) sequence of musical lines. Each descending line should fade
into the audible range as it begins its descent, and then fade out as
it descends further. So the beginning and end of each line will be
difficult to hear. And there will be many such lines, each starting
at a different time, some perhaps descending a little faster than
others, or perhaps using different instrument sounds, and so on. The
effect will be that as the music is listened to, everything will seem
to be falling, falling, falling with no end, but no beginning either.
(This illusion is called the \emph{Shepard Tone}, or \emph{Shepard
Scale}, first introduced by Roger Shepard in 1964 \cite{shepard}.)
Use high-order functions, recursion, and whatever other abstraction
techniques you have learned to write an elegant solution to this
problem. Try to parameterize things in such a way that, for example,
with a simple change, you could generate an infinite \emph{ascension}
as well. The |Volume| constructor in the |NoteAttribute| type, as
used in the definition of |addVol|, should be used to set the volumes.}
\end{exercise}
\begin{exercise}{\em
Do something wild and crazy with Euterpea.}
\end{exercise}
\vspace{.1in}\hrule