%-*- 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 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