Music for Tiny Airports 2/1 đ«
Celebrating the 40 years anniversary of Brian Eno's "Ambient 1: Music for Airports" with an homage written in 256 bytes with the Web Audio API.
Source code
Music for Tiny Airports<svg onload="with(new AudioContext)with(createScriptProcessor(k=8192,t=0,1))connect(destination),onaudioprocess=x=>{for(i=0;i<k;t+=2e-5)x.outputBuffer.getChannelData(0)[i++]='%,IW7:A'.charCodeAt(i%7)*t%.1*(1-t/(Math.tan(i%7)+9)%1)}">
An HTML page, generating hours and hours of music for airports in 256 bytes.
There are three parts to this code.
1. The title and script execution
The title is a text node. The script creating the music is executed using the onload
event handler of an SVG element. This is the smallest way to run JavaScript.
Music for Tiny Airports<svg onload="/* ... */">
2. The Audio setup
with(new AudioContext)with(createScriptProcessor(k=8192,t=0,1))connect(destination),onaudioprocess=x=>{/* ... */}
This instantiate a new AudioContext, creates a Script Processor node with k=8192
samples, t=0
input channels and 1
output channel. Finally we connect it to the audio destination and initialize its onaudioprocess
event handler to generate a new sound buffer when needed. We will reuse the variable t
as an approximation of the time.
3. The music generation
Music for Airport consist of 7 "tape" loops that repeat at different interval.
for(i=0;i<k;t+=2e-5)x.outputBuffer.getChannelData(0)[i++]='%,IW7:A'.charCodeAt(i%7)*t%.1*(1-t/(Math.tan(i%7)+9)%1)
This snippet itself consist of two parts.
3.1. The audio buffer update loop
for(i=0;i<k;t+=2e-5)x.outputBuffer.getChannelData(0)[i++]=/* ... */
This will loop through each of the k=8192
audio samples and assign a new value to channel number 0
of the outputBuffer: Our one and only output channel. That way we will get new sound emitted to the audio destination.
At each iteration t
, our approximation of the time, is increased by 2-e5
. Normally we should increment t
by 1 / sampleRate
but this takes more characters and we couldn't fit a title in 256 bytes.
Browser engines use a sampleRate
of either 44100Hz
or 48000Hz
. That means that our approximation plays at a different pitch in different browsers.
3.2. The music generation
The following snippet is the core of this project where i%7
refers to each of the 7 "tape" loops composing "Ambient 1: Music for Airports"
// 1---------------------2----3------4--------------3---
'%,IW7:A'.charCodeAt(i%7)*t%.1*(1-t/(Math.tan(i%7)+9)%1)
- the frequency of the notes
eb', ab', f', c', ab, f, db'
. - creates a sawtooth oscillator at this frequency.
- sets the envelope of the notes which starts at full volume and decays linearly over the duration of the notes.
- gives the duration of the notes.
Hope you enjoyed this project and write up.