Skip to content

Instantly share code, notes, and snippets.

@lynn
Created February 29, 2024 14:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lynn/5854634c6465dd0e33bb255c3760d9fd to your computer and use it in GitHub Desktop.
Save lynn/5854634c6465dd0e33bb255c3760d9fd to your computer and use it in GitHub Desktop.
// https://wavepot.com/
const tau = 2*Math.PI;
const bpm = 132;
const bps = bpm / 60;
const spb = 1 / bps;
function pos(t) {
const beat = Math.floor(t / spb);
const frac = (t / spb) % 1.0;
return [beat, frac];
}
function saw(t, n) {
let mix = 0;
for (let i = 1; i <= n; i++) {
mix += 1/i * Math.sin(t*i);
}
return mix;
}
function realsaw(t) {
return 1-t%1*2;
}
function hz(st) {
st -= 1;
return 220 * Math.pow(2, st/12);
}
function bell(t, p) {
return Math.pow(Math.sin(tau * t * p), 3);
}
function unison(f) {
function u(t, p) {
let mix = 0;
for (let k =0; k < 4; k ++) mix += f(t, p * (0.99+k*0.006));
return mix / 4;
}
return u;
}
function melody(t) {
const [beat, frac] = pos(t*2);
const p = hz([0, 12, 11, 2, 4, 7, 2, 0][beat % 8] + 12);
const vol = Math.pow(1-frac, 3);
return unison(bell)(t, p) * vol;
}
function sidechain(t) {
const frac = pos(t)[1];
return Math.pow(frac, 1.2);
}
function chord(t) {
const [beat, frac] = pos(t);
const transpose = 0;
const vol = sidechain(t);
let mix = 0;
const notes = [
[0, 2, 4, 7],
[0, 2, 4, 7],
[0, 2, 4, 7],
[0, 2, 4, 7],
[-5, 1, 5, 10],
[-5, 1, 5, 10.5], // whoa!
[-6, 1, 5, 12],
[5, frac * 6 % 1 < 0.5 ? 24 : 12],
[-7, 0, 4, 7],
[-7, 0, 4, 7],
[-7, 0, 4, 7],
[-7, 0, 4, 7],
[-7, 0, 4, 7],
[-7, 2, 4, 7],
[-3, 2, 4, 5],
[-2, 5],
][beat % 16];
for (let i = 0; i < notes.length; i++) {
const st = notes[i];
const p = hz(st + transpose);
mix += saw(tau * t * p, 3) * vol;
}
return mix;
}
function bass(t) {
const [beat,frac] = pos(t*4);
const i = beat % 16;
const transpose = 0;
const bassline = [-7,-7,-7,null, null, null, 0, 5, null, 0, 5 + Math.floor(frac*3)/3*2, 7, null, null, -12, null];
if (bassline[i] === null) return 0;
const p = hz(bassline[i] - 12 + transpose);
const vol = 1;
return (realsaw(t * p)*0.5 + Math.sin(tau*t*p)) * vol;
}
function delay(f, t) {
let mix = 0;
for (let i = 0; i < 7; i ++) {
mix += Math.pow(0.6, i) * f(t + 64*spb - i * 0.2*spb);
}
return mix;
}
function shape(t) {
return Math.tanh(2*t);
}
function kick(t) {
const [beat,frac] = pos(t);
const vol = beat % 2 === 0 ? 1 : 0.8;
return shape(Math.sin(1 / ((frac+0.21) / 30))) * (1-frac) * vol;
}
function hat(t) {
const [beat,frac] = pos(t*4);
return Math.random(t) * Math.pow(1-frac, 4) * (beat%4/4);
}
function clap(t) {
const [beat,frac] = pos(t);
if (beat % 2 === 0) return 0;
return (frac * 20 % 1 < 0.3 ? Math.pow(Math.sin(0.4 / ((frac+0.2) / 90)), 3) : Math.random() * 0.6) * Math.pow(1-frac, 8);
}
function drums(t) {
return kick(t) + 0.2 * hat(t) + 0.8 * clap(t);
}
function dsp(t) {
return 0.13 * drums(t) + 0.1 * delay(melody, t) + 0.03 * chord(t) + 0.03 * bass(t);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment