
Midi files or music exported by the typical music editor is "expressionless." A *human* would play that music with slight tempo variations, subtle accents... some notes would be overlapped in time slightly, some separated in time. I want a program that starts with a plain midi file, then via a domain-specific language lets me describe nuances of expression. (Aside: this is mostly an experiment done for curiosity and an excuse to write Haskell code. As a practical matter, since I already play some piano and I am working on improving my music imagination, it makes more sense to put time into music practice and not programming. But hey, I don't always make sense.) Nuances include - stretching or shrinking small units of time, for example single beats within a measure - inserting pauses before or after a beat, or half-beat, or other small unit of time - changing how much sequential notes overlap (in time) or are separated. Be able to do this over a range of time - similar to previous: over a range of time, make notes overlap in time, and vary that overlap from a larger amount to a smaller amount - accenting (making slightly louder) notes at a specific time - put in a crescendo (gradually louder) or decrescendo (gradually softer) over a span of time Examples: stretch time between beats 3 and 4, measure 7: m7 [ 3 --> 4 time:+105% ] Change overlap of beat 3 to following beat by increasing it 100 ms: m7 [ 3 overlap:+100] Over the range of beats 1 to 4, stepping by 1/2 beat, gradually increase the overlap from 100 ms to 200ms: m7 [3 --> 4 (step 1/2) overlap:+100 --> +200] It would be useful to define patterns that are used repetitively. define patternFoo [ 3 --> 4 time:+105% 3 overlap: +100 3 --> 4 (step 1/2) overlap:+100 --> +200 ] Then, m7 [ patternFoo ] Often music has a hierarchy of expressive elements: there is some larger, basic expressive pattern, while individual measures deviate slightly from that. So it is useful to invoke a pattern, then use the language to describe additional changes: m7 [ patternFoo 1 --> 2 overlap:+50 ] In this case, patternFoo already defines an "overlap value" for beat 1, so the additional mention of overlap here is *summed* with the existing value. I want to solicit suggests for the basic data structure to represent the expression descriptors. First, note the job of the software in translating a "flat" midi file into an expressive one can be expressed like this: - For every note in the midi file - find out what overlap applies to that note - find out what dynamic changes apply to that note - find out what time the note occurs at - etc. - finally compute the note's actually begin time, end time, and dynamic So the basic problem to solve is: given a list of expressive element descriptors, and the begin time of a note (specified as a measure and beat), figure out which descriptors are "in effect" at the given time, and sum them. Let's look just at descriptors that stretch or shrink time. Let's say that for measure 7, we have the following two descriptors present: - 1 --> 2 1/2 time:+110% - 2 --> 2 2/3 time:+120% Note: 2 1/2 is "two and a half", 2 2/3 is "two and two-thirds." They overlap in time. I wonder what is the best form to store this information in order to facilitate translating a note? I'm thinking of this: each descriptor becomes a pair of elements: an "on" element and an "off" element. - beat 1: time: +110 ON - beat 2: time: +120 ON - beat 2 1/2: time: +110 OFF - beat 2 2/3: time: +120 OFF For a note at beat X, you run though this list of on/off elements, tracking the total changes to elements like 'time', until you reach beat X.