
Here's my problem. It's from music. I have a program which reads a MusicXML file and creates a realization (performance) via software synthesis. Currently I'm working on pizzicato and arco markings. Let me explain. A string instrument can play in a number of ways. To name two of them, in "pizzicato" playing, the musician plucks a string, while in "arco" the musician bows the string. Pizzicato and arco markings appear above notes in the sheet music. (Therefore they appear in the MusicXML which is a representation of sheet music.) If a piece has no marking at all, or no marking until later in the piece, "arco" is assumed. When a "pizz." (the usual abbreviation as it appears in sheet music) occurs, then the note under the marking should be played pizzicato, and *so should all following notes until another marking.* When an "arco" occurs, likewise that note and all following notes until the next marking should be played arco. The goal is to determine, for every note in the score, how it should be played. Here's some of the code I have. data Loc = <... representation of a location (measure # and beat) in the score ..> data Note = <.. all data describing a note in the score ... > -- this structure holds all notes. there can be one or many notes at each location notes :: Map Loc [Note] -- pizz. and arco are called, in MusicXML terms, a <direction> of type <words> -- They are only two of many such words. data DirectionWords = DirectionWords String -- this structure holds all direction-words in the score directionWords :: Map Loc [DirectionWords] The following code is not a complete solution, but it illustrates the lovely mapAccum function in Data.Map. Suppose we have data PlayDirection = PlayPizz | PlayArco To determine the direction in effect at each location in 'directionWords' (not in 'notes' which is what we really want) we can use mapAccum in Data.Map. directionInEffect :: Map Loc PlayDirection directionInEffect = snd $ mapAccum step PlayArco directionWords where step :: PlayDirection -> [DirectionWords] -> (PlayDirection,PlayDirection) step dir words | any (== DirectionWords "arco") words = (PlayArco, PlayArco) | any (== DirectionWords "pizz.") words = (PlayPizz, PlayPizz) | otherwise = (dir, dir) But what I really need to do is determine the direction in effect at each location in 'notes'

Maybe something like this:
instance Eq Loc where
a == b = ...
instance Ord Loc where
compare a b = ...
data Instruction = InstrNote (Loc, Note) | InstrPD (Loc, PlayDirection)
write a function that will combine the notes and playdirections into
one list of everything sequentially.
combineNotesDirs :: [(Loc,Note)] -> [(Loc,PlayDirection)] -> [Instruction]
combineNotesDirs [] [] = []
combineNotesDirs [] (d:ds) = undefined --you can figure this out
combineNotesDirs (n:ns) [] = undefined
combineNotesDirs notes@(n:ns) dirs@(d:ds)
| fst d <= fst n = InstrPD d : (zipNotesDirs notes ds)
| otherwise = InstrNote n : (zipNotesDirs ns dirs)
Then loop over that and store them as a map. Traverse the list, keep
track of the playdirection at each entry, and then accumulate the
current direction and note at each note entry into a new map.
instructionlist2map :: [Instruction] -> Map Loc (Note, PlayDirection)
I'm sure this could be cleaned up a bit, but is that sort of what you
were looking for?
On Thu, Aug 18, 2011 at 8:57 PM, Dennis Raddle
Here's my problem. It's from music. I have a program which reads a MusicXML file and creates a realization (performance) via software synthesis. Currently I'm working on pizzicato and arco markings. Let me explain. A string instrument can play in a number of ways. To name two of them, in "pizzicato" playing, the musician plucks a string, while in "arco" the musician bows the string. Pizzicato and arco markings appear above notes in the sheet music. (Therefore they appear in the MusicXML which is a representation of sheet music.) If a piece has no marking at all, or no marking until later in the piece, "arco" is assumed. When a "pizz." (the usual abbreviation as it appears in sheet music) occurs, then the note under the marking should be played pizzicato, and *so should all following notes until another marking.* When an "arco" occurs, likewise that note and all following notes until the next marking should be played arco.
The goal is to determine, for every note in the score, how it should be played.
Here's some of the code I have.
data Loc = <... representation of a location (measure # and beat) in the score ..>
data Note = <.. all data describing a note in the score ... >
-- this structure holds all notes. there can be one or many notes at each location notes :: Map Loc [Note]
-- pizz. and arco are called, in MusicXML terms, a <direction> of type <words> -- They are only two of many such words. data DirectionWords = DirectionWords String
-- this structure holds all direction-words in the score directionWords :: Map Loc [DirectionWords]
The following code is not a complete solution, but it illustrates the lovely mapAccum function in Data.Map.
Suppose we have
data PlayDirection = PlayPizz | PlayArco
To determine the direction in effect at each location in 'directionWords' (not in 'notes' which is what we really want) we can use mapAccum in Data.Map.
directionInEffect :: Map Loc PlayDirection directionInEffect = snd $ mapAccum step PlayArco directionWords where step :: PlayDirection -> [DirectionWords] -> (PlayDirection,PlayDirection) step dir words | any (== DirectionWords "arco") words = (PlayArco, PlayArco) | any (== DirectionWords "pizz.") words = (PlayPizz, PlayPizz) | otherwise = (dir, dir)
But what I really need to do is determine the direction in effect at each location in 'notes'
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Hi David,
This helps, for sure. I wondered if any of the rich selection of
functions in Data.Map could be used, such as union. To perform a union
on two maps, their elements must have the same type. From this one
concludes that a type unifying Note's and PlayDirection's is
necessary, which is what you have done in Instruction.
On Thu, Aug 18, 2011 at 8:46 PM, David McBride
Maybe something like this:
instance Eq Loc where a == b = ... instance Ord Loc where compare a b = ...
data Instruction = InstrNote (Loc, Note) | InstrPD (Loc, PlayDirection)
write a function that will combine the notes and playdirections into one list of everything sequentially.
combineNotesDirs :: [(Loc,Note)] -> [(Loc,PlayDirection)] -> [Instruction] combineNotesDirs [] [] = [] combineNotesDirs [] (d:ds) = undefined --you can figure this out combineNotesDirs (n:ns) [] = undefined combineNotesDirs notes@(n:ns) dirs@(d:ds) | fst d <= fst n = InstrPD d : (zipNotesDirs notes ds) | otherwise = InstrNote n : (zipNotesDirs ns dirs)
Then loop over that and store them as a map. Traverse the list, keep track of the playdirection at each entry, and then accumulate the current direction and note at each note entry into a new map.
instructionlist2map :: [Instruction] -> Map Loc (Note, PlayDirection)
I'm sure this could be cleaned up a bit, but is that sort of what you were looking for?

Well, if you use that instruction type (you can call it whatever you
want), you should be able to use 'map' to
notes2instr :: Map Loc Note -> Map Loc Instr
dirs2instr :: Map Loc PlayDirection -> Map Loc Instr
which might simplify things a little from what I originally posted. I
thought you might be able to use unionWithKey to combine, but that
would still be wrong because you cannot be sure what playdirection you
are in when you hit a specific note.
There is no function in Data.Map that will automatically tuple or
combine two different types of maps for you because there are so many
ways it could be done. Even if it did, your requirements are specific
enough that you'll have to do the work yourself to get the right
answer.
On Fri, Aug 19, 2011 at 2:40 AM, Dennis Raddle
Hi David, This helps, for sure. I wondered if any of the rich selection of functions in Data.Map could be used, such as union. To perform a union on two maps, their elements must have the same type. From this one concludes that a type unifying Note's and PlayDirection's is necessary, which is what you have done in Instruction.
On Thu, Aug 18, 2011 at 8:46 PM, David McBride
wrote: Maybe something like this:
instance Eq Loc where a == b = ... instance Ord Loc where compare a b = ...
data Instruction = InstrNote (Loc, Note) | InstrPD (Loc, PlayDirection)
write a function that will combine the notes and playdirections into one list of everything sequentially.
combineNotesDirs :: [(Loc,Note)] -> [(Loc,PlayDirection)] -> [Instruction] combineNotesDirs [] [] = [] combineNotesDirs [] (d:ds) = undefined --you can figure this out combineNotesDirs (n:ns) [] = undefined combineNotesDirs notes@(n:ns) dirs@(d:ds) | fst d <= fst n = InstrPD d : (zipNotesDirs notes ds) | otherwise = InstrNote n : (zipNotesDirs ns dirs)
Then loop over that and store them as a map. Traverse the list, keep track of the playdirection at each entry, and then accumulate the current direction and note at each note entry into a new map.
instructionlist2map :: [Instruction] -> Map Loc (Note, PlayDirection)
I'm sure this could be cleaned up a bit, but is that sort of what you were looking for?
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
participants (2)
-
David McBride
-
Dennis Raddle