Sunday, May 23, 2010

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.
Rendering Accidentals

And this is how it deals with a chord on steroids.

Accidentals Line Up Correctly

I tried hard to break it.

Whoa there, Fella!

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.)

Bends with Text Annotations

The new layout code allows for justification. Below, the top stave is rendered without justification, while the bottom two are justified to different widths.

Layout Justification

The justification works across staves too, so you can have multiple staves playing different parts, all lined up in the notation.
Justification across Staves

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:

  1. I'm continuing to read this with great interest.

    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...

    ReplyDelete
  2. wooa... You have acomplished a lot of things using only js. I'm very amazing. A note about notation. The MusicXML is very difficult to read as you said, so why don't you take a look at GUIDO notation: http://www.informatik.tu-darmstadt.de/AFS/SALIERI/GUIDO/demos.html. I tell you. Is human writable!. Well that's my grain of sand. Again: wow!.

    ReplyDelete
  3. Please take a look about GUIDO in wikipedia: http://en.wikipedia.org/wiki/GUIDO_music_notation

    Regards

    ReplyDelete
  4. Heh, it makes me happy that I wasn't the only one struggling with implementing musical notation. You're already much farther than I ever was though. Regarding GUIDO, it's not exactly easy to read imo. I've written a parser for (a subset of) ascii guitar tabs. I'll try to hook it up once this is up and running. :)

    ReplyDelete
  5. Your rendering of accidental, especially the "steroids" cords are great. I'v never seen any cords like that in practice, but you can handle them!

    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.

    ReplyDelete
  6. Thanks for the comments, everyone. GUIDO looks interesting, it seems it's based on lilypond.

    @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.

    ReplyDelete
  7. This is getting very cool! Either you're working on this full-time, or you have an incredibly lucid vision of how to handle the notation.

    I'm loving the explanations as well - keep up the commentary.

    ReplyDelete
  8. @Kae... Neither... it's all trial-and-error weekend hacking... :-)

    ReplyDelete
  9. On a side note, there is also a lot going on lately with html5 audio (Experiments with audio at http://vocamus.net/dave/?p=1092).

    Any thoughts on using this to play back the music from javascript that you have notated?

    ReplyDelete
  10. amazing. keep up the good work.

    ReplyDelete
  11. This is awesome. I ran across your work while researching an idea I had to make ocarina tabs with canvas. I would have no trouble contributing code to make this happen under your project. I looked on your github account and couldn't find this there though.

    ReplyDelete
  12. Excellent work! Can't wait to see more!

    ReplyDelete
  13. FANTASTIC job!!!

    ReplyDelete
  14. This looks gorgeous. Any thoughts on releasing it?

    ReplyDelete
  15. Excellent work! It's really great to see your progress, and glad to know you're planning on making it open-source. I'd be interested to know how easily your code could be adapted to support alternative, chromatic-staff based notation systems?

    (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!

    ReplyDelete
  16. More than 2 "voices" per staff is definitely required in piano music, I think, or at the very least you may have four "voices" total with three of them on the bass staff, e.g. some very low note, some percussive chords in the left hand, and some middle voice hovering near the top of the clef, maybe crossing between the staves.

    ReplyDelete