CRIM

Citations: The Renaissance Imitation Mass Project

CRIM Intervals

CRIM Intervals: A Python Library for Analysis

Based on Python, Pandas, and Mike Cuthbert's music21, CRIM Intervals is a pattern finding engine for musical scores, with an emphasis on the kinds of melodic and harmonic patterns found in Renaissance polyphony. It has been developed as a primary data analysis tool for CRIM, but can be applied and adapted to a wide range of styles. Results are reported in Pandas dataframes (and thus exportable in a variey of standard formats for further analysis), and also via several visualizations methods.

The Basics

CRIM Intervals begins by importing one (or more) MEI, MusicXML, and MIDI files, for example: piece = importScore('https://crimproject.org/mei/CRIM_Model_0008.mei') Once imported this piece object can be explored in various ways. piece.notes(), for instance, produces a dataframe in which each staff (voice part) is represented as a column of events--notes, rests, durations, lyrics, etc. Other methods (see the list below) in turn present these basic events in many different ways: as melodic intervals, harmonic intervals, n-grams, contrapuntal "modules", and so on.

There are many ways to configure these basic methods. For instance intervals can be diatonic, or chromatic, or with (and without) 'quality' (such as M3 vs m3). They can also be simple or compound (a tenth in the latter would be a third in the former).Unisons can be combined (something helpful for comparing similar melodies), or events can be taken at actual durations or 'sampled' at some regular durational span.

Complete documentation of each method capacities is available via doc.strings via this command print(model.YourMethod.__doc__), where you will replace 'YourMethod' with the name of the individual method, for example print(piece.melodic.__doc__).

Key Methods in CRIM Intervals

  • piece.notes(), which finds all the notes and rests in a score, with a tabular score-like representation of the pitches, pitch classes, and durations (expressed in music21 "offsets", in which each quarter note corresponds to the value of 1.0). It can also derminte the location of any note as a measure+beat reference with detailIndex
  • piece.melodic(), which finds melodic intervals in any voice part, with various options for diatonic, chromatic and zero-based distances. Intervals can be compound (distinguishing between tenths and thirds, for instance), or simple, and can include quality (distinguishing major and minor thirds, for instance), or not.
  • piece.harmonic(), which finds harmonic intervals between every combination of two voices in a piece, with various options for diatonic and chromatic. These intervals can also be directed (as when a tenor voice sounds above the altus), or not.
  • piece.lyrics() (for every note)
  • piece.durations(), with quarter-note = 1.0, as per music21.
  • piece.ngrams(), which finds n-grams of any length in each voice part. n-grams are frequently used in linguistic analysis (), and can help us find repeating patterns within and among works. The ngram tool can be used for any of the methods above: melodic, harmonic, durations, lyrics. By default it finds contrapuntal modules, which represent in numerical values a combination of the vertical intervals made between any two voices with the melodic intervals heard in the motion of the lower voice. A module of 7_Held 6_-2, 8 for instance, represents vertical intervals of 7, 6, 8 between two voices and in the lower voice a tied note followed by a descending second. Together these five events represent a typical cadence formula. Repeating modules are a key part of Renaissance contrapuntal style.
  • It is also possible to apply various edit distance tools to many of these patterns, thus allowing users to find exact and close matches.

Classification of Contrapuntal Types

CRIM Intervals also include advanced methods that use combinations of the methods detailed above to predict "contrapuntal types" commonly found in Renaissance polyphony.

  • Cadences are one such type: piece.cadences() can find them with a high degree of accuracy.
  • We have also developed a method that predict various imitative textures, including Fugas, Imitative Duos, and Periodic Entries (as Peter Schubert has named them): piece.presentationTypes().
  • It is also possible to accurately identify homorhythmic passages (where sets of voices move in the same durations and declaim the same lyrics): piece.homorhythm().

In each case we there are various options users can select to refine the searches, including various tools that allow for 'similar' no less than 'exact' matches. Melodic and rhythmic 'flexing' is a key part of Renaissance counterpoint. These methods are too complex to summarize in a short space. But they are powerful tools for machine prospecting of musical works.

Heatmaps, Graphs, and Networks

CRIM Intervals also features tools that help us visualize musical events in different ways, including:

  • bar charts and histograms of events (such as notes, or intervals), which are useful for understand ranges, distributions, and other large-scale distribution of categorical data)
  • heatmaps, showing where in a piece patterns (such as repeating n-grams) occur
  • radar plots, used to show cadences in a radial plot that reveals the tonal profile of a composition (or a corpus of works)
  • progress charts, showing a cadences in a series (from start to finish)
  • network diagrams, showing related patterns or pieces

One Piece, or a Corpus

CRIM Intervals methods can also be applied to a corpus of pieces. We first define a corpus: corpus = CorpusBase(['https://crimproject.org/mei/CRIM_Mass_0006_1.mei', 'https://crimproject.org/mei/CRIM_Mass_0006_2.mei', 'https://crimproject.org/mei/CRIM_Mass_0006_3.mei']), then specify a method to run against each piece in the corpus: corpus.batch(func=ImportedPiece.cadences). The results are reported as a combined dataframe.

Render Scores (or Excertps) with Verovio

CRIM Intervals also has the capacity to render results as modern score with Laurent Pugin's Verovio piece.verovioCadences(), as well as reporting them as data frames and visualizations (for more on that see below).

Code, Tutorials, and Jupyter Notebooks

Find CRIM Intervals Code on github

Learn more and try out CRIM Intervals at: Tutorials and Jupyter Notebooks for CRIM Intervals