ditty.bpm = 60;
const musicBox = synth.def((phase, env, tick, options) => {
const freq = options.freq;
const t = tick;
const PI2 = Math.PI * 2.0;
let y = 0.0;
y += 0.55 * Math.sin(1.0 * PI2 * freq * t) * Math.exp(-2.0 * t);
y += 0.08 * Math.sin(5.3 * PI2 * freq * t) * Math.exp(-3.3 * t);
y += 0.03 * Math.sin(12.7 * PI2 * freq * t) * Math.exp(-5.2 * t);
y += 0.01 * Math.sin(22.5 * PI2 * freq * t) * Math.exp(-7.0 * t);
y += 0.003 * Math.sin(33.5 * PI2 * freq * t) * Math.exp(-10.0 * t);
// Multiply by the Ditty envelope to prevent clicks at the very end
return y * env.value;
}, { attack: 0.005, release: 0.5, duration: 4.0, env: adsr });
// Sequence Data
// copied from https://www.shadertoy.com/view/tdXGRj
const sequenceData = [
{ f: 208.0, t: [23850, 27010, 36700] },
{ f: 233.0, t: [29995] },
{ f: 277.0, t: [37995] },
{ f: 311.0, t: [20980, 33000, 35502] },
{ f: 349.0, t: [850, 6880, 37990, 43950] },
{ f: 370.0, t: [21020, 23930, 26995, 35495, 36695, 42595] },
{ f: 391.0, t: [6980, 34200, 41895] },
{ f: 415.0, t: [41195] },
{ f: 440.0, t: [4000, 9995, 23980, 29980, 32990, 40495, 47095] },
{ f: 466.0, t: [990, 6990, 12930, 15950, 35500, 38000, 42600, 44040, 50700] },
{ f: 494.0, t: [26960, 41900] },
{ f: 523.0, t: [24005, 36705, 41200] },
{ f: 554.0, t: [12960, 15980, 21040, 22500, 33030, 35505, 38004, 40500] },
{ f: 587.0, t: [30000] },
{ f: 622.0, t: [1000, 4005, 7000, 10000, 23000, 37050, 44090, 47090, 50800] },
{ f: 659.0, t: [30005, 36702, 42607] },
{ f: 698.0, t: [3995, 13000, 21030, 24000, 28000, 30800, 33015, 41907, 47100] },
{ f: 740.0, t: [15000, 41207] },
{ f: 784.0, t: [16000, 40507, 41903] },
{ f: 831.0, t: [17977, 28650, 42603] },
{ f: 880.0, t: [10010, 40503] },
{ f: 932.0, t: [17350, 19810, 29100, 30800, 32100, 34800, 41203] },
{ f: 988.0, t: [30009] },
{ f: 1046.0, t: [13005, 16450, 16900, 17980, 18820] },
{ f: 1109.0, t: [9990, 11860, 18400, 30400, 33000] },
{ f: 1174.0, t: [0, 3000, 6100, 9000, 43200, 46100, 49250] },
{ f: 1396.0, t: [1005, 7020, 10000, 10800, 44100, 50860] },
{ f: 1661.0, t: [10400] }
];
let events = [];
for (let track of sequenceData) {
for (let time of track.t) {
events.push({ time: time / 1000.0, freq: track.f });
}
}
events.sort((a, b) => a.time - b.time);
loop(() => {
let currentTime = 0;
sleep(2.0);
for (let i = 0; i < events.length; i++) {
let ev = events[i];
let delay = ev.time - currentTime;
if (delay > 0) {
sleep(delay);
currentTime = ev.time;
}
musicBox.play(0, { freq: ev.freq, amp: 0.2, pan: 0 });
}
const cycleDuration = 90.0;
if (currentTime < cycleDuration) {
sleep(cycleDuration - currentTime);
}
}, { name: 'Memory - Yoko Kanno' });