Home

This is my place on the web. Eventually, you'll find below all manner of publications, blog posts, microblog posts, and essays. Some of this content was previously hosted on my academic website at Columbia and on a Jekyll blog that was hosted on GitHub Pages.

Two more minimalists

Short post tonight. I often feel quite defensive when I start off thinking or writing about what I like in minimalist music, because, let's face it – even thanks to interesting work by Music Theorists™ – there's a fair bit of residual snobbishness in academe when it comes to this repertoire. I think the problem is that there are some composers in this style who have written some pretty bad music, and its hard to get away from the idea that choosing to study someone's musical works has this side-effect of inaugurating the person in some sort of music-analytical Hall of Fame: “this person's work is worth analyzing”.

A guide to free reference and academic paper management with Zotero

Update: I recently learned that box.com plans to deprecate WebDAV support in October 2019, a decision which renderse part of the workflow described here unsustainable beyond October. As I come up with an alternative solition, I will change this post to reflect the new reality. First things first, we need a reference manager. A reference manager stores bibliographic information for each reference, and most of them support associating the reference with a source file corresponding to the reference.

Generate keyword arguments programmatically in Python

This is a little helper that can be used in Python 3 to generate a set of dictionaries from a schema that specifies iterators that provide the values of the generated dictionaries. It will generate one dictionary for every configuration (i.e. Cartesian product) of values specified by iterators in the schema. Non-iterable values are kept fixed. Generators may also be used in the schema (see code snippet). This is useful for programmatically constructing keyword arguments when experimenting with the parameters of functions, because a dictionary can be unpacked into keyword arguments by using the double star operator (**some_dict) in the last argument position.

Introduction to DFT and Fourier phase space for music analysis

Follows exposition in Jason Yust, “Schubert's Harmonic Language and Fourier Phase Space.” Journal of Music Theory. 59/1 (2015) Import some modules and functions that will be useful later. import itertools import music21 import numpy as np from matplotlib import pyplot as plt from numpy.fft import fft %matplotlib inline The Fourier transform decomposes a time-varying signal into a mixture of sinusoidal components. To take advantage of the Fourier transform, we represent a pitch class (multi)set as a pitch-class vector, where the n-th entry in the vector correpsonds to the cardinality of the pc n in the multiset.

Serial matrix in J

J is an APL-like array programming language. It was developed in collaboration with Ken Iverson. The documentation online, especially the tutorials and educational material, is exemplary. This weekend I worked through the J primer. If you can ignore the rhapsodic evangelism for the language, then it's a robust and thought-provoking introduction to a very different way of programming. One of my motivations for learning something about J is to understand this article about a combinatorics problem with an application in music theory.

Embedding models and music

A post on the Google Research blog today announced the open-sourcing of Embedding Projector, a web application for interactive visualization and analysis of high-dimensional data Over the summer, I presented work (co-authored with Jaan Altosaar) on the application of word embedding models to a large–and admittedly noisy–corpus of classical music. It appears that word embedding models capture something about sequences of chords. Our work, and related recent work with a different dataset, shows that that major triads are somewhat evenly distributed through the embedding space, in their circle-of-fifths order.

Accessing column names in Processing.org Tables

For a project I am currently working on using the Processing programming language, I use the provided Table class to read in data from a flat CSV file. The column names in this file have to match parameters specified elsewhere in the code. As a consquence, when validating the data from the file, I need access to the column names. There is an undocumented private field in all instances of the Table object which contains the column names (when the flag to treat the first line of the file as column headers is flipped in the Table constructor).

Hot Twitter topics for GE16 candidates one week in

This post is timely given RTE's recent publication of their analysis of social media usage during the 2016 general election in Ireland, available here. It looks like they've partnered with the ADAPT Centre for Digital Content Technology to produce the Twitter data and Facebook for that content. It's a pity that they: don't indicate the source of their data don't indicate on what basis were Tweets deemed to be about the election (was it simply the presence of the #ge16 hashtag?

Breaking Beethoven

Last night, at the suggestion of a friend, I took a midi performance of the first movement of Beethoven's Op. 2, No. 1 (a piano sonata in F minor) and squashed it all into the one octave. It's a sort of pitch-class version of the movement, where each pitch-class is represented by a real pitch, bounded to a given octave of the piano. But there are twelve different ways to do this, since the “destination” octave could be bounded by twelve different pitch-classes.

The right way to use requests in parallel in Python

Today I was working on getting as many YouTube comments out of the internets as was possible. I'm sure that my code has a long way to go, but here's one speed-up that a naive first day out with multiprocessing and requests generated. import requests import multiprocessing BASE_URI = 'http://placewherestuff.is/?q=' def internet_resource_getter(stuff_to_get): session = session.Session() stuff_got = [] for thing in stuff_to_get: response = session.get(BASE_URI + thing) stuff_got.append(response.json()) return stuff_got stuff_that_needs_getting = ['a', 'b', 'c'] pool = multiprocessing.