StaffDrawer Component for .NET
Purpose
For the SeekWell project, I am designing a StaffDrawer component that takes as input a description of a simple, monophonic musical passage and draws the appropriate musical notation on a provided graphics context. Future improvements will allow for multiple staves to be displayed at once. The component will be written in C#, using the .NET framework with GDI+ for drawing. I am using a shareware font for music notation called Fughetta, developed by Blake Hodgetts (of Eugene, Oregon), who also developed Finale's Maestro font.
Features
Input
Besides providing a Graphics object on which to draw, the input consists of a MusicPassage object, which represents the essential features of the notation as well as providing straightforward conversion to and from my own XML format. This format for music passages, SeekWellXML (see the Schema file) , can be used to store music examples and to facilitate processing of simple music. I will eventually write converters between SeekWellXML and MusicXML to provide access to a wide range of musical data and other utilities, such as a music player application.
Output
The output is simply a rendered version of the music on a .NET Graphics object; this is essentially a bitmap representation of the music. It can be used with a separate ASP.NET control I am working on to render music on a web page. It can also be used by a WIndows Forms control I have designed to provide music notation in client-side Windows applicaitons.
Notation features
Motivation
This component is intended to represent a simple subset of musical notation that is relevant to my research in the creative microdomain SeekWell. In particular, this microdomain is restricted to:
- Single-voice melodies. That is, only one note sounds at a time; overlapping pitches or chords can not occur.
- Equal durations for all notes. All note in the melody can thus be represented conveniently with quarter notes.
- No rests allowed. All melodies thus are composed of a sequence of quarter notes that continue until the very end of the melody.
Despite the seemingly severe restrictions imposed by these constraints, melodies in the SeekWell microdomain can be suprisingly interesting and complicated -- consider some of Bach's suites for solo instruments, for example. Even in single melodies conposed entirely of fixed note durations, principles of harmony, voice leading, and compound melody play active roles.
In spite of my short-term goals for rendering SeekWell melodies with this component, I would like to expand it to handle more complex music at a later time.
Requirements and Desired Features
The following features should be provided by the component:
- Multiple clefs: G, F, and C clefs at different positions and octave transpositions. Initially, Treble clef is the most critical, followed by support for bass, alto, and tenor clefs.
- Key signatures: the control should display the appropriate key signature as requested by the MusicPassage, and notes should be displayed in an intelligent manner, so that accidentals are only displayed where necessary.
- There should be a special no-key-signature mode, where it looks like a C-major staff, but all "black notes" such as C#/Db are displayed with both enharmonic forms available on two noteheads attached to the same stem. This provides for user input from a graphical piano keyboard interface, where it would be inappropriate to guess which enharmonic choice to use or which key the music is in.
- Time signature and bar lines should be optional; if there is no time signature, no bar lines should be displayed. There should also be a mechanism to specify pick-up notes in the first measure. Eventually, mid-passage time signature changes would be desirable.
- Notes should be displayed with a choice of noteheads: the default will be to show every note as a quarter note, but certain notes should be able to use an unfilled whole-note or even a half note without affecting the horizontal positioning. This is necessary for using noteheads as analytical symbols to designate structural significance.
- Slur marks would be a nice future feature, with options to place slur marks either above or below the notes. Additionally, the slurs should have optional text labels.
- Ledger lines will be drawn as appropriate.
- The music should be compressed or expanded to fit within the given graphics context (a rectangular region). Configurable minimum and maximum point sizes for the music font should be provided.
- No line-wrapping will occur; for simplicity, all music will be drawn in one system.
Algorithm
Automatic layout of music notation is a notoriously difficult problem, and for good results it is necessary to spend a very large amount of time and to use techniques such as constraint-satisfaction to find a resonable solution to a given rendering problem. In this simple domain, however, it should be possible to generate passable results. The inclusion of chords, multiple voices on a staff, non-uniform durations, rests, and additional notation features such as expression markings and articulations lead to most of the complications. My algorithm will follow the following approach for one staff. Layout of multiple staffs linked in one system would proceed a bit differently.
- Determine the horizontal space required by each component, at some arbitrary font point size (like 24 point). In a simple case, the horizontal components are:
- Initial Clef (including all the space from the left-hand part of the staff to the right-edge of the clef). In general, each component involves the space for drawing its parts plus the white-space to its left, if any.
- Time signature (optional) (includes white space from the clef to the signature, plus the width of the time signature). This involves the maximum width of the numerator and denominator of the signature, for cases like 3/16.
- Key signature (optional)
- Each measure (these will be counted up with a loop. If there is no time signature, everything is implicitly in the 1st measure). A measure includes:
- The right-hand bar line of the measure and the whitepspace to the right of this bar line (this is a double-bar for the final measure)
- Each note in the measure (via a loop). Each note consists of:
- Spacing to the right of the note. This is critical, and will remain a variable amount during the calculation! That is, we will count up how many notes there are, and later adjust the horizontal space after each note to expand or contract the music to fit. Note the complication: accidentals will just use up empty space from the previous note, so that empty space must have a minimum large enough to fit in the accidental.
- Room for an accidental (optional)
- The notehead
- In the special case of the display of enharmonic choices, room is allocated for two side-by-side noteheads (one on a space, the other on a line) and two accidentals.
- Tally the total horizontal space, and compare with the total horizontal space available. Adjust the note-spacing algebraically (it will be like a simple linear programming problem with minimum-distance and max-distance constraints). This will fit notes in if possible.
- Calculate a scale factor for the point size: HorizontalPointSizeFactor = actual space / required space.
- Calculate a vertical space requirement by subtracting the top staff line used by the bottom staff line used and multiplying by the line distance. Staff lines 1,2,3,4, and 5 are always used, but additional ones can be used due to ledger lines. Calculate a vertical scale factor for the point size: VerticalPointSizeFactor = actual vertical / required vertical.
- Pick the minimum of the vertical and horizontal factors.
- Multiply the default point size 24 by the minimum scaler.
- Round the new point size down.
- Calculate the exact scale factor = new point size / 24. Scale the amount of horizontal space between notes by this factor.
- Recalculate spacing constants using the new point size, and rerun the horizontal space determination algorithm, but this time include actual rendering of the graphics.
Architecture
There are several major .NET components I am developing for music research. These include:
- SeelWellXML: an XML Schema.
- File Converters: Applications to convert SeekWellXML to and from MusicXML and from the EsAC format to SeekWellXML. Once these are done, running two in sequence will produce an EsAC to MusicXML converter for general use.
- MusicCore (class library for music representation: includes pitches, measures, chords, etc.) The MusicPassage class used to represent SeekWellXML in-memory is included here.
- StaffDrawer (class library plus an ASP.NET control and a Windows Forms control) This uses MusicCore internally.
- SeekWellCore: a library containing SeekWell-specifc utility classes, used to manipulate pitches as members of alphabets. It also includes an architecture for making predictions with a model and rating the results.
- SingleLevelModel: a core class used in conjunction with SeekWellCore to implement the Single Level model. Also includes an ASP.NET page for interacting with the model, as well as a Windows Forms application for the same purpose.
- MultiLevelModel: as above, for the Multi Level Model.