Representation Formats

Scholars have been encoding music into a searchable format since the 1950s (Bronson, 1951), and we might consider "the first wave" of computational music encoding to be in the 1960s, with Arthur Mendel's Josquin project at Princeton, and the DARMS project in New York (led by Stefan Bauer-Mengelberg).

Although the basic idea of encoding seems like a fairly straightforward problem–how might we refer to a musical score as a text object?–it was dealt with in wildly different ways. Here are just a couple of the most notable formats, but know that there are many more.

DARMS

The DARMS project made the decision to not actually encode pitch, but simply location on the staff. See the "space code" from the DARMS Manual below:

Here is an example of hw pitches might be encoded:

DARMS was used quite extensively for typesetting, and was actually used until surprisingly recently in some of the major publishing houses.

Plaine and Easie

The Plaine and Easie format has been most notably used by RISM, which catalogues millions of incipits from libraries around the world.

Kern

Kern (Huron, 1995) is the native format of the Humdrum toolkit.

This webpage does a great job of showing how the format works.

More info

This page from CCARH is quite good, and worth a read.

The Humdrum toolkit is a set of command-line tools (originally written in AWK; the Humdrum extras are written in C++) that can be combined together to ask questions of a score.

Let's Begin

Let's start learning some Python! There are some important things to remember:

Why Python?

Historically, this class has been used as a way of teaching Humdrum. We would begin with symbolic analyses in Humdrum, and the data analysis in R.

Python is a good all-purpose language, and it's used extensively inside academia and out. Our hope is that we can use a single language to cover text-processing of musical scores, data analysis, audio analysis, and machine learning elements this semester.

Variables

Variables are defined in a pretty straightforward way. Here we have variables defining a string ("apples") and a float (3.1415). Another type

Lists and Loops

You can combine things into lists (also called arrays in other languages). See how the list below is defined (with square brackets).

We can also loop over the list! See how a for loop is written in Python below:

In the above, note that the loop needs a colon at the end of the first line, and a tab in the second line. Anything inside of that loop has to have a least one tab. (It doesn't actually matter if it's tabs or spaces, but certain people prefer one over another, and certain companies like to keep consistency; Google uses four spaces, and says to never, ever use tabs).

Basic Conditionals

Conditional statements can include if/else and elif (meaning "else if"). Code becomes very powerful with conditionals...

Exercise 1

Exercise 2:

Below is a Polish folksong. How would you print it off without the global metadata (the lines that begin with "!")?

Homework:

  • Counts the unique key signatures
  • Sums the durations (how many quarter notes, eighth notes, etc.)
  • Sums the pitches?

Copy this Colab document and create your own. You can then share the link on Carmen.

Read in a file

Wednesday Class

Today we will cover:

Counting Things

Many of the first corpus studies were simply counting the occurrences of musical events. There's a lot to be said for simply counting things. You can better understand the language used, and the the likelihood of events.

For example, much of the work from the 80s through the early-2000s focused on the role of statistical learning. We learn grammars and styles through exposure to events. For example, children learn languages by being exposed to words and grammars, and they are implicitly aware of likely transitions. Therefore, understanding the frequency of those events, and how likely they are to occur, might be able to tell us a great deal.

More on Lists

In order to count things, it's helpful to tally them in lists. There are two ways of adding things to lists as you find them.

The first option is to create an empty list, that you then add things to. To create an empty list, you just have to do something like this:

my_list = []

After this, you can add things to the list with append.

for i in range(1,15):
  my_list.append(i)

You can try this below:

Question: Why is there no output?

Exercise: Odd numbers only.

Write a list that scans a list from 1 to 100, and only prints odd numbers.

Hint: Python has a modulo operator (%) that allows you to return the remainder of a number. So

15 % 4

returns "3".

The following will search for all even numbers:

num % 2 == 0

So something like the code below will find all numbers that don't have a remainder of 0 when divided by 2:

num %2 != 0

List comprehension

A more "pythonic" way to solve this problem might be with a list comprehension. The basic formula for a list comprehension is just something like:

[variable for variable in loop if condition]

So to find even numbers, you could just run the below code:

If we want to count how long the list is, we can use the len function, which is built in to Python (it means length).

Functions

If you rerun a line of code, it should probably be in a function. If variables are the nouns of your code, a function is the verb. It makes your code do things.

So if I don't want to always run the same statement over and over again, I can just put it into a function:

Functions become more powerful with arguments (in the parentheses).

Exercise

Write a function that finds evens or odds, depending on the parameter.

Rhythms in a Polish Folksong

How would we look at all rhythms in a Polish folksong?

What about only rhythms?

Substitutions and Regular Expressions

It's useful to be able to substitute things, getting rid of information you don't need and cleaning things up in the process. My favorite way to do this is with "re.sub". "re" stands for "regular expression", which is a fairly old computational tool of searching for things that are not necessarily exact searches.

It's helpful to learn regular expressions as much as possible, especially when dealing with kern files, which are flat text files.

So the expression below is subbing cats for dogs. The logic goes:

re.sub("what you want to change", "what you want to change it with", where you want to change it)

Notice how I need to include the variable at the end.