One limitation to computer-based musical analysis has been the tight coupling of representations to development tools. Humdrum tools require familiarity with Unix usage, while MuseData tools run in TenX, a non-standard DOS environment. In contrast, XML programming tools are available for all major industry programming languages and platforms. This lets the user rather than the representation language choose the programming environment, making for simpler development of musical applications.
Two main programming models are currently available for handling XML data: the Document Object Model (DOM) and Simple API for XML (SAX) (Martin et al. 2000). The W3C’s DOM interprets an entire XML document as a tree of nodes. SAX (for serial access) provides an alternative event-based model, where an entire XML document need not be read into memory at once, but can instead be parsed on an as-needed basis. Tools for both models are available for many programming languages (e.g. Java, C++, Visual Basic) from many vendors. These examples use a DOM-based model coded using Microsoft Visual Basic. Both of the analysis program examples are adapted from the problem list on the Humdrum web site.
Say we want to investigate whether Bach’s pieces really have 90% of its notes in one of two durations (e.g., quarters and eighths, or eighths and sixteenths). We can do this by plotting a distribution of note durations on a bar chart, displayed together with a simple spreadsheet. Figure 4 shows the duration distribution for the second movement of Bach’s Cantata No. 6 (BWV 6). The top two note durations make up nearly 87% of the notes. This is not quite the 90% posed in the question, but still a more uneven distribution than often seen. For retrieval purposes, an extended program could then look for the works in a given corpus with the most uneven distribution of note durations.
Note durations are represented as fractions in many musical codes, including MuseData and NIFF. MusicXML follows MuseData’s example in encoding the denominator (which changes rarely) in a separate element from the numerator, which is coded individually for each note. Thus to build the distribution chart, we need to search not only for
<note> elements, but also for the
<divisions> elements that change the duration denominator, represented as fractions of a quarter note. An earlier piece of code searches through the document for all the
<divisions> used, and computes a value called
nDivisions that is an even multiple of all these different divisions.
Once this is done, we search the file for both
<divisions> elements using XPath, a W3C recommendation for addressing parts of an XML document (Clark 1999). We then update the counters in an array that contains all possible duration values within the file. Cue and grace notes are excluded (Figure 5). Following this code, we assign the data to our charting tools of choice (in this case, Microsoft’s Office Web Components).
Figure 5. XPath addressing of notes and divisions.
Set oNodes = oRoot.selectNodes("//note | //divisions") ' XPath Do Set oNote = oNodes.NextNode If oNote Is Nothing Then Exit Do If oNote.tagName = "divisions" Then nMultiplier = nDivisions CLng(oNote.Text) Else Set oTmp = oNote.selectSingleNode("duration") If Not oTmp Is Nothing Then ' Exclude grace and cue notes nDuration = CLng(oTmp.Text) * nMultiplier nCounts(nDuration) = nCounts(nDuration) + 1 End If End If Loop
As another example, say we wanted to investigate whether there is a correlation between pitch and duration in a given score. The code logic is nearly the same. Instead of computing the counts in an array, we instead add pitch/duration pairs for each note to the spreadsheet. Rests are excluded, along with cue and grace notes (Figure 6).
Figure 6. XPath or a coordinate search of pitch and duration.
' Code structure is same as for distribution analysis. ' The Else clause for handling notes changes: Else Set oDuration = oNote.SelectSingleNode("duration") Set oPitch = oNote.SelectSingleNode("pitch") If (Not oDuration Is Nothing) And _ (Not oPitch Is Nothing) Then ' No rests either nDuration = CLng(oDuration.Text) * nMultiplier nPitch = MidiNote(oPitch) ' Separate function oWorksheet.Cells(i, 1) = nDuration oWorksheet.Cells(i, 2) = nPitch End If End If
Afterwards, we map the scatterplot axes to the two columns in the spreadsheet to display the graph. Figure 7 shows a scatter-plot of pitch vs. duration for the first movement of Mozart’s String Quartet No. 7 (K. 169). As with most musical scores we have looked at so far, there is no correlation between the two.