Pure Data, one patch at a time Repository
Between late 2014 and mid-2016 I taught myself Pure Data, one patch at a time, and committed almost everything to git.
The repository contains 54 commits on a single linear branch, from 66a4e2d ("First oscillator test", November 2014) to 442165e ("Archive cleanup + README", June 2016). A git log of the thing reads like a syllabus, which is more or less what it was.
The progression is visible in the repository itself. It starts with oscillators and phasors, then moves through additive synthesis, FM, envelopes and polyphony. From there it branches into sequencing, MIDI, pitch tracking, GEM graphics, effects and networking, before eventually reaching a guitar sampler and several increasingly elaborate live loopers. There are also side trips into medieval talea rhythms, golden-ratio tuning and random sequencing.
Some of the folder names are in French: clavier, nombre d'or, boîte à rythmes. The whole thing has the character of a long sequence of small questions, each answered with another patch.
From synthesis to analysis
The most substantial piece of software in the repository came near the end: music-analysis/analyse.py batch-processes a music library and attempts to identify the musical key of each track, up to 5,814 files. The pipeline starts Pure Data headlessly with an analysis patch, captures its output, and uses VLC to feed each track into Pd's audio input. sigmund~ estimates pitch; the patch reduces those estimates modulo 12 and accumulates twelve pitch-class counters. A second headless Pd process sends a MIDI note that triggers the counters to flush their contents to stdout. Python then parses the resulting histogram and applies a very simple heuristic. It takes the two highest pitch classes and checks whether they are a perfect fifth apart. If they are, the lower one is taken as the tonic; otherwise the higher one wins.
liste = sorted(liste, key=lambda liste: liste[1])
maxi = []
maxi.append(liste[11])
maxi.append(liste[10])
maxi = sorted(maxi, key=lambda maxi: maxi[0])
if (maxi[1][0] - maxi[0][0] == 7):
tonique = maxi[0]
else:
tonique = maxi[1]
It is a rough approximation of the kind of pitch-class reasoning used by Krumhansl's key-finding work. I don't know how accurate the resulting classifications were: The script produced data files, but the repository contains no evaluation against a known corpus. What survives is the experiment itself: a first attempt at taking something learned through synthesis and turning it into a piece of batch data processing.
Making the network audible
Another part of the repository took a different kind of input: the WiFi traffic around me. The idea came from the simple observation that a computer network is full of activity that is normally completely invisible. Beacons, probe requests, associations and other 802.11 frames are constantly passing through the space around us. I wanted to turn that traffic into sound.
The experiment was recorded one evening at the Cité Universitaire de Cuques in Aix-en-Provence. There was plenty of network activity that night, so the resulting recording captures a fairly dense stream of packets.
WiFi sonification, Cité Universitaire de Cuques, Aix-en-Provence, May 2016
The setup was split between the shell and Pure Data. On the command line, tshark captured frames from a WiFi interface in monitor mode:
sudo tshark -l -i wlan1mon -x \
| cut -c7-53 \
| sed -u -b 's/ /\r\n/g' \
> /dev/udp/localhost/34567
The command takes a slice of each packet's hexadecimal dump, splits it into individual bytes and sends those bytes as UDP messages to Pure Data. networking/udp-receive.pd receives them with netreceive, converts the hexadecimal values into MIDI note numbers, and sends the resulting values through the global freq and trigger signals. The sound comes from adsr/dual-adsr.pd, a patch that had originally grown out of several earlier experiments. Among its various controls and signal-routing components is a table mapping note values onto frequencies based on the golden ratio, along with a keyboard for playing the same scale. That lookup eventually became the reusable lib/note-to-freq.pd abstraction.
The result is a small chain running across several layers of the repository:
802.11 frames
↓
tshark
↓
hexadecimal bytes
↓
UDP
↓
Pure Data
↓
byte → note
↓
phi-based frequency mapping
↓
synth
The mapping is arbitrary, but the input is not. Packet arrival is a continuous stream of events produced by the environment, and the sonification makes that otherwise invisible activity audible. The golden-ratio tuning adds another layer of abstraction between the network and the resulting sound.
A first oscillator leads to additive synthesis, which leads to pitch analysis, which leads to visualization and eventually to processing an entire music library. A networking experiment reuses a synthesizer developed months earlier. The guitar looper brings together MIDI, effects and reusable abstractions.
The repository is a record of learning by building: one question at a time, most of them abandoned once answered, a few carried far enough to become something real.