One hundred days of a person's online activity can make a piece of music. Communication becomes a pattern of resonant tones. Entertainment supplies a percussion texture. News, reference browsing, and software activity enter with voices of their own.
I composed this sonification for Wisconsin Public Radio's To the Best of Our Knowledge, using 100 days of the host's web activity. The work accompanied an interview for the show's episode on the quantified self. It turns the traces of ordinary computer use into a portrait that unfolds in time.
Give each habit an instrument.
I built five voices in SuperCollider, one for each category of activity: communication, entertainment, news, reference, and software development. Each has a recognizable sound before the daily values begin to alter its intensity and behavior.
Communication uses resonant metallic tones, with activity shaping the pitch and density of the strikes. Entertainment takes on a brush-and-hat percussion texture. These voices bring two different kinds of movement into the composition: discrete events and a more continuous rhythmic presence.
News uses phase modulation synthesis, changing the depth and character of the tone. Reference browsing works through a resonant filter bank, producing bell-like textures. Software development drives a stepped oscillator pattern, with activity affecting its pace and amplitude.
As the days advance, the instruments are heard together. Their shifting balance gives each part of the record a different musical character. A category can become prominent, retreat, or sit alongside another, carrying the proportions of the source data into the arrangement.
Hear the distribution of attention.
The material is familiar: websites, messages, things read, things worked on. Giving those categories sounds makes the distribution of a person's online time available in another form. You can follow one voice or listen to the overall density of the piece.
The composition also brings duration back into the record. Each day arrives after the previous one. A busy passage has a relationship to the quieter passage around it; a recurring pattern can become recognizable through repetition. The portrait lives in those transitions as much as in any single value.
For me, the interesting design problem is how to give numerical variation a musical identity without losing the thread of the source. Instrument design and data mapping work together: the sound tells you which activity you are following, while the activity changes what the sound does.
A portrait made for radio.
The piece was created for a medium built around listening. The episode also included interviews with Nicholas Felton, Stephen Wolfram, Natasha Dow Schüll, and Sarah Manguso, placing the composition within a wider conversation about measuring and describing a life.
The sonification gives that conversation an audible example. A record of online behavior becomes something that can share the same space as a voice, an interview, and a listener's attention.
The five voices in code.
The excerpt preserves the data mappings and instrument definitions, from the activity columns in the CSV file to the resonators, noise sources, and oscillators that give them sound.
s.boot;
(
~csv=CSVFileReader.readInterpret("/Users/mbk5020/Desktop/trial.csv").post;
~data=~csv.flop;
)
///////////////////////////////////////////////////////////////////////Communication
(
~masteramp=0.2;
~timedelta=1;
~communication=~data.at(1).normalize(200, 800);
~communicationimp=~data.at(1).normalize(0, 8);
~communicationamp=~data.at(1).normalize(0, 0.08);
~entertainment=~data.at(3).normalize(1, 8);
~entertainmentamp=~data.at(3).normalize(0, 0.2);
~news=~data.at(4).normalize(100, 200);
~newsmul=~data.at(4).normalize(0.1, 6);
~newsamp=~data.at(4).normalize(0, 1.8);
~reference=~data.at(5).normalize(200, 1200);
~referenceamp=~data.at(5).normalize(0, 2.2);
~software=~data.at(8).normalize(10, 100);
~softwarespeed=~data.at(8).normalize(0.001, 1);
~softwareamp=~data.at(8).normalize(0, 0.2);
)
(
SynthDef(\communication, {|freq=900, imp=4, mul=0.4, add=0, amp=0.2, out=0, pan=0, rate=3, dur=0.1, gate=1|
var env, env2, src;
env = EnvGen.kr(Env.asr(0.1, 1, 1), gate);
src=DynKlank.ar(`[[freq!4], [0.1, 0.4]], Impulse.ar(imp), decayscale:0.5);
src=GrainIn.ar(1, Impulse.ar(freq), dur, src, pan);
src=LPF.ar(src, 200);
src=Pan2.ar(src*env, pan);
Out.ar(0, src*env*amp);
}).add;
SynthDef(\entertainment, {
|
freq=8, out=0, arousal=100, arousalvol=0.2, buf =2, amp=0.3, pan=0, rate=0.1 t_trig =1
|
var src, brush, hat, thud, env, tempo, value;
tempo = Impulse.ar(freq);
env=EnvGen.ar(Env([1, 1], [2, 2]));
brush = BrownNoise.ar(Decay2.ar(PulseDivider.ar(tempo, 8, 1), 0.005, 0.5));
hat= Mix.ar([WhiteNoise.ar(Decay2.ar(PulseDivider.ar(tempo, 4, 2), 0.005, 0.5))*SinOsc.ar(400)]);
src=Pan2.ar((brush + hat)*amp*env, pan);
Out.ar(out, src);
}).add;
SynthDef(\news, {|freq=400, car=400, amp=30, pan=0, out=0, mul=1, mod=3, rcalmul=0.2, rcalroom=0.8, gate=1|
var src, env;
env = EnvGen.kr(Env.asr(0.1, 1, 1), gate);
src=PMOsc.ar(freq, car, SinOsc.kr(0.01).range(0.1, 30))*SinOsc.kr(mul);
src=BPF.ar(src, freq, rcalmul);
src=FreeVerb.ar(src, 0.3, rcalroom);
src=Pan2.ar(src, pan);
Out.ar(out, src*env*amp*~masteramp);
}).add;
SynthDef(\reference, {
|
freq=900, mul=0.4, add=0, amp=20, out=0, pan=0, rate=3, dur=0.1, gate=1
|
var env, env2, src;
env=EnvGen.kr(Env.asr(0.01, 1), gate, doneAction:2);
src=DynKlank.ar(`[[freq!4], [1, 0.4]], Impulse.ar(4), decayscale:0.5);
src=GrainIn.ar(1, Impulse.ar(6), dur, src, pan);
src=LPF.ar(src, 100);
src=Pan2.ar(src*env, pan);
Out.ar(0, src*env*amp);
}).add;
SynthDef(\software, {
|
freq=100, trig=10, pan=0, out=0, amp=0.8, decay=7, t_gate=1, gate=1, speed=0.1
|
var src, env;
env=EnvGen.kr(Env.asr(0.01, 1), gate, doneAction:2);
src=SinOsc.ar(Stepper.ar(Impulse.ar(freq), 1, 4, 10, 4)*SinOsc.kr(0.1, 0, 50, 100))*LFTri.ar(2);
src=Decay2.ar(src, 0.03, decay);
src=Pan2.ar(src, pan);
Out.ar(out, src*env*amp)
}).add;
)