The Thing about Accidentals...
...is that they can be a real pain.
Last weekend, I mentioned that I threw away most of the layout and formatting code, which I started rewriting from scratch. Well, this weekend I threw away everything else, and started abstracting away many of the general properties that are shared between different types of notation.

Testing Note-Head Displacement
One of the big design flaws in the previous version was the coupling of notes and tabs. I essentially had a single Note class that encapsulated everything about a specific note, including the string/fret information, attached lyrics, attached accidentals, and other modifiers. This class had a big render() method that drew everything (the tabs, the accidentals, etc.) in one go.
This made the code hard to follow, hard to test, and very hard to add features to.
In the new version, I have different classes for different types of staves, notes, accidentals, and other modifiers, which are managed by a hierarchy of contexts. This means that adding support for a new type of instrument, say a Didgeridoo, is a matter of creating a new DidgeridooStave class to render its stave, and maybe a DidgeridooNote class to render any Didgeridoo notational symbols.
Yes, even the tests were rewritten. I wrote about 150 tests. All new, all fresh. It wasn't much fun, but I do have a significant level of confidence in the code.
So what did I gain from all of this? Just the following...
Accidentals are tricky. In the image below, notice how the flat is nicely shifted to make room for the flat.
And this is how it deals with a chord on steroids.
I tried hard to break it.
It gets a bit confused when you bring in a second voice, but still quite respectable.

Accidentals with Multiple Voices
The formatter doesn't just work with accidentals. It works with all kinds of modifiers, such as bends. Last week, I showed you how the modifier handled multiple bent notes on the same chord. Below, notice how full and half bends share the text annotation area. (This excited me a wee bit.)
The new layout code allows for justification. Below, the top stave is rendered without justification, while the bottom two are justified to different widths.
The justification works across staves too, so you can have multiple staves playing different parts, all lined up in the notation.
That's all I have to show for this week, folks! Since this is all new code, there are a few things that I lost support for, in particular: beams and ties. Hopefully it'll all be back next week.







16 comments (imported from blogger)
In particular I've been interested to read your notes on the data structures you are using. I have a (much simpler) personal project that keeps getting aborted because I keep getting the data structures wrong.
Looking forward to seeing more...
Regards
How many different voices can your engine currently support / how do you deal with different voices that have the same note? I know especially in vocal work, parts will sometimes be singing the same note but the stem direction dictates the voice they follow, might be something to take a stab at with the next iteration.
@Will, the engine can support any number of voices, but only 2 on a single stave (I've never seen a stave with more than 2 voices... if you have, let me know.) Re: same note, it simply shifts the lower voice to the right a bit. If you look at the "Layout Justification" image, notice how for the chords on the first beat, the lower chord is shifted right (due to the notes being adjacent)?... that's exactly what happens when the notes are the same too.
I'm loving the explanations as well - keep up the commentary.
Any thoughts on using this to play back the music from javascript that you have notated?
(See the Music Notation Project: http://musicnotation.org for examples of these. My favorite is TwinNote http://twinnote.org)
Seems like someone interested in one of these alternative notation systems could adapt your code for use with it, hopefully without too much effort? (The positioning of accidentals wouldn't be a problem then!)
The Music Notation Project has worked on doing this with Lilypond and Finale. (See: http://musicnotation.org/software/ )
At any rate, keep up the good work!