MUSIC FOR TINY AIRPORTS 2/1 đŸ›«

401 words ~ 2-4 minsMathieu 'p01' Henri on March 17th, 2018

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)
  1. the frequency of the notes eb', ab', f', c', ab, f, db'.
  2. creates a sawtooth oscillator at this frequency.
  3. sets the envelope of the notes which starts at full volume and decays linearly over the duration of the notes.
  4. gives the duration of the notes.

Hope you enjoyed this project and write up.