Generative Music

with JavaScript & Web Audio

@teropa
FullStackCon 2017

Generative

  1. If something is generative, it is capable of producing something or causing it to develop.
  2. In linguistics, generative is used to describe linguistic theories or models which are based on the idea that a single set of rules can explain how all the possible sentences of a language are formed.

COBUILD Advanced English Dictionary

It's about creating music.

Here's a chord

Playing A Chord with Tone.js

        
const players = {
  'F3':  new Player('F3.mp3' ).toMaster(),
  'G#3': new Player('G#3.mp3').toMaster(),
  'C4':  new Player('C4.mp3' ).toMaster(),
  'D#4': new Player('D#4.mp3').toMaster(),
  'F4':  new Player('F4.mp3' ).toMaster(),
  'G#4': new Player('G#4.mp3').toMaster()
};

['F3', 'G#3', 'C4', 'D#4', 'F4', 'G#4'].forEach((note, i) => {
  const startAtTime = i;
  players[note].start(startAtTime);
});
        
      

Making Loops

        
['F3', 'G#3', 'C4', 'D#4', 'F4', 'G#4'].forEach((note, i) => {
  const startAtTime = i / 2;
  Transport.schedule(function play(time) {
    players[note].start(time);
    Transport.schedule(play, '+3'); // Next after 3s
  }, startAtTime);
});
        
      

Loops

Adding Phasing

        
[{note: 'F3',  dur: 2.91},
 {note: 'G#3', dur: 3.03},
 {note: 'C4',  dur: 3.06},
 {note: 'C#4', dur: 2.97},
 {note: 'F4',  dur: 3.30},
 {note: 'G#4', dur: 3.09}].forEach(({note, dur}, i) => {
  const startAtTime = i / 2;
  Transport.schedule(function play(time) {
    players[note].start(time);
    Transport.schedule(play, `+${dur}`);
  }, startAtTime);
});
        
      

Phasing

Brian Eno: Music for Airports

1978

Photo: AVRO

Airports Approx.

John Cage & Chance Procedures

Math.random()

12 + (Math.random() - 0.5)

Random Durations

Random Octave Shifts

Random Instrumentation

“Essentially the idea is that one is making a kind of music in the way that one might make a garden. One is carefully constructing seeds, or finding seeds, carefully planting them and then letting them have their life.

And that life isn't necessarily exactly what you'd envisaged for them.”

Cellular Automata

Previous
Next

Wolfram's Rule 30

1D Cellular Automaton

        
const rules = {'111': 0, '110': 0, '101': 0, '100': 1,
               '011': 1, '010': 1, '001': 1, '000': 0};
const generations = [[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]];
        
      
        
const rules = {'111': 0, '110': 0, '101': 0, '100': 1,
               '011': 1, '010': 1, '001': 1, '000': 0};
const generations = [[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]];

function nextGeneration(last) {
  const result = new Array(last.length);
  for (let idx = 0; idx < last.length; idx++) {
    const leftIdx  = idx - 1;
    const rightIdx = idx + 1;
    const key = `${last[leftIdx]}${last[idx]}${last[rightIdx]}`;
    result[idx] = rules[key];
  }
  return result;
}
        
      
        
const rules = {'111': 0, '110': 0, '101': 0, '100': 1,
               '011': 1, '010': 1, '001': 1, '000': 0};
const generations = [[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]];

function nextGeneration(last) {
  const result = new Array(last.length);
  for (let idx = 0; idx < last.length; idx++) {
    const leftIdx  = idx > 0 ? idx - 1 : last.length - 1;
    const rightIdx = idx < last.length - 1 ? idx + 1 : 0;
    const key = `${last[leftIdx]}${last[idx]}${last[rightIdx]}`;
    result[idx] = rules[key];
  }
  return result;
}
        
      
        
const rules = {'111': 0, '110': 0, '101': 0, '100': 1,
               '011': 1, '010': 1, '001': 1, '000': 0};
const generations = [[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]];

function nextGeneration(last) {
  const result = new Array(last.length);
  for (let idx = 0; idx < last.length; idx++) {
    const leftIdx  = idx > 0 ? idx - 1 : last.length - 1;
    const rightIdx = idx < last.length - 1 ? idx + 1 : 0;
    const key = `${last[leftIdx]}${last[idx]}${last[rightIdx]}`;
    result[idx] = rules[key];
  }
  return result;
}

generations.push(nextGeneration(last(generations)));
        
      

Iannis Xenakis: Horos

1986

CAs in Electronic Music

Putting a CA to Work

        
Transport.scheduleRepeat(time => {
  generations.push(nextGeneration(last(generations)));
  const generation = last(generations);
  for (let i = 0; i < generation.length; i++) {
    if (generation[i]) play(i, time);
  }
}, 0.2);
        
      

Cellular Drum Machine

Adding randomized delays

        
Transport.scheduleRepeat(time => {
  generations.push(nextGeneration(last(generations)));
  const generation = last(generations);
  for (let i = 0; i < generation.length; i++) {
    if (generation[i]) play(i, Math.random() < 0.3 ? time + 0.1 :
                                                     time);
  }
}, 0.2);
        
      

Cellular Drum Machine

With a Splash of Randomness

Cellular Piano Roll

Laurie Spiegel: Music Mouse

1986

Augmented Generative Music

Press 'z' or 'x' to transpose

Models

Markov Chains

Hiller & Isaacson: Iliac Suite

1957

Training a Markov Chain

        
const data = ['D5', 'D#5', 'D5', 'A#4', 'G4', 'A#4', 'D5'];

function trainMarkovChain(data) {
  const result = {};
  for (let i=0 ; i<data.length - 1 ; i++) {
    const from = data[i];
    const to   = data[i + 1];
    result[from] = result[from] || [];
    result[from].append(to);
  }
  return result;
}
        
      

Generating with a Markov Chain

        
function predictWithMarkovChain(chain, from) {
  const options = (from && chain.hasOwnProperty(from)) ?
    chain[from] :
    Object.keys(chain); // Restart from random token.
  return options[Math.floor(Math.random() * options.length)];
}
        
      

Training Markov Chains

Generating on Bassline

Generating on Melody

Deep Learning

https://magenta.tensorflow.org/2016/07/15/lookback-rnn-attention-rnn

Summary

Approaches

  • Loops, phasing
  • Randomness, chance procedures
  • Algorithmic, cellular automata
  • Interactive, augmentative
  • Learning based, Markov chains

Influences

  • Brian Eno
  • John Cage
  • Iannis Xenakis
  • Laurie Spiegel
  • Hiller & Isaacson

These Slides

teropa.info/generative-music-slides

Workshop on Saturday

FullStack2gether here at CodeNode

skillsmatter.com/conferences/9577-fullstack2gether-2017