<div>ties are a presentation-level issue, the underlying (sound) representation is a single note. i suggest</div><div><br></div><div><font class="Apple-style-span" face="'courier new', monospace">Doc = [Note]</font></div>
<div><br></div><div>where Notes have fields for their measure location and duration. then there's no issue with overlapping notes, and start/end times are easy to calculate. ties can be calculated easily later for graphical layout by asking if durations overlap given boundaries (usually measure boundaries, but also measure centers).</div>
<div><br></div><div>i use a natural rhythm EDSL here:</div><a href="http://code.google.com/p/h1ccup/source/browse/trunk/theory/haskell/src/LiveCode.hs">http://code.google.com/p/h1ccup/source/browse/trunk/theory/haskell/src/LiveCode.hs</a><div>
<br></div><div>here's the rhythm-related part (doesn't handle varying tempo). it lets you say things like:</div><div><div><br></div><div><font class="Apple-style-span" face="'courier new', monospace">Note {measure = 3, beat = 2, dur = Dotted $ Triplet Quarter}</font></div>
</div><div><br></div><div>------------------------</div><div><br></div><div><div><font class="Apple-style-span" face="'courier new', monospace">{-# LANGUAGE ExistentialQuantification, ScopedTypeVariables, RecordWildCards, RankNTypes #-}</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">tempo = 200 -- bpm</font></div><div><font class="Apple-style-span" face="'courier new', monospace">timeSig = TimeSig { numBeats = 4</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> , unit = Quarter</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> }</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">data DurBase = Whole | Half | Quarter | Eighth | Sixteenth | ThirtySecond deriving (Enum, Bounded, Show, Eq)</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace">data ModDur = forall x. NoteDur x => Dotted x | Triplet DurBase</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br>
</font></div><div><font class="Apple-style-span" face="'courier new', monospace">data TimeSig = TimeSig {</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> numBeats :: Int</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> , unit :: DurBase</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> }</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br>
</font></div><div><font class="Apple-style-span" face="'courier new', monospace">data Note = forall x . NoteDur x => Note {</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> midiNum :: Int -- 0-255</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> , vel :: Int -- 0-255</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> , chan :: Int -- 0-15</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> , measure :: Integral a => a</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> , beat :: Int</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> , subdiv :: (Real a, Fractional a) => a -- % of beat</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> , dur :: x</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> }</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">class NoteDur a where</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> quarters :: (Real x, Fractional x) => a -> x </font></div><div><font class="Apple-style-span" face="'courier new', monospace"> </font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> calcDurMS :: (Real x, Fractional x) => a -> x</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> calcDurMS d = 1000 * 60 * beats d / realToFrac tempo</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace"> beats :: (Real x, Fractional x) => a -> x </font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> beats d = uncurry (/) $ both quarters (d, unit timeSig)</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> where both (f :: forall a b. (NoteDur a, Real b, Fractional b) => a -> b) (x, y) = (f x, f y)</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">instance NoteDur DurBase where</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> quarters x = z where Just z = lookup x . zip [minBound .. maxBound] $ map (fromRational . (2 ^^)) [2, 1 ..]</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">instance NoteDur ModDur where</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> quarters (Dotted x) = quarters x * 3 / 2</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> quarters (Triplet x) = quarters x * 2 / 3</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace">instance NoteDur Note where</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> quarters Note{..} = quarters dur</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">calcStartMS :: (Real a, Fractional a) => Note -> a</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace">calcStartMS n = realToFrac (subdiv n + (fromIntegral $ (measure n * numBeats timeSig) + beat n)) * (calcDurMS $ unit timeSig)</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br>
</font></div><div><font class="Apple-style-span" face="'courier new', monospace">measureMS :: (Real a, Fractional a) => a</font></div><div><font class="Apple-style-span" face="'courier new', monospace">measureMS = calcStartMS Note { measure = 1</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> , beat = 0</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> , subdiv = 0</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> , midiNum = undefined</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> , vel = undefined</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> , chan = undefined</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> , dur = undefined :: DurBase -- ugh</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> }</font></div></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div>
<font class="Apple-style-span" face="'courier new', monospace">-e</font></div>