const compressor = filter.def(class { constructor(options) { this.gain = 1; } process(input, options) { const sigPower = input[0] ** 2 + input[1] ** 2; if (sigPower === 0) return input; const sigdb = 10 * Math.log10(sigPower); // Signal in decibels const overdb = Math.max(sigdb - options.threshold, 0); debug.probe("overdb", overdb, 10, 2); const target_gaindb = overdb * (1 - options.ratio) / options.ratio; const target_gain = 10 ** (target_gaindb / 20); const time = this.gain > target_gain ? options.attack : options.release; const a0 = Math.min(1, 2.3 * ditty.dt / time); this.gain += (target_gain - this.gain) * a0; debug.probe("gain reduction", 20 * Math.log10(this.gain), 10, 2); return [input[0] * this.gain, input[1] * this.gain]; } }, { threshold: -1, ratio: 8, attack: 0.5, release: 0.2 }); let comp1 = compressor.createShared({ ratio: 4, attack: 0.008, release: 0.7, threshold: -12 }); ditty.bpm = 96; const linexp = (x, x0, x1, y0, y1) => y0 * (y1 / y0) ** ((x - x0) / (x1 - x0)); const linlin = (x, x0, x1, y0, y1) => y0 + (y1 - y0) * Math.min(1, Math.max(0, (x - x0) / (x1 - x0))); const tri = synth.def((phase, env) => 1.22 * (4 * Math.abs(phase % 1 - 0.5) - 1) * env.value); const dist = synth.def((phase, env) => Math.atan(25 * (Math.abs(phase % 1 - 0.5) - 0.25)) * env.value); const rhythm = [ 16, 32, 16, 8, 8, 8, 8, 4, 8, 8, 4, 12, 14, 16, 16, 16, 16, 16 ]; loop((i) => { sine.play((tick) => linlin(tick, 0, 0.2, a1, f1), { env: adsr, attack: 0.01, release: 0.2, amp: 0.8 }); tri.play((tick) => linlin(tick, 0, 0.1, e3, f1), { env: adsr, attack: 0.005, release: 0.1, amp: 0.6 }); tri.play((tick) => linlin(tick, 0, 0.03, a5, a3), { env: adsr, attack: 0.005, release: 0.03, amp: 0.1 }); sleep(rhythm.ring(i)); }, { name: "kick" }).connect(comp1); const sin2p = (x) => Math.sin(2 * Math.PI * x); const fmsynth = synth.def((phase, env) => sin2p(phase + 0.5 * sin2p(phase) * env.value) * env.value); const bass808 = synth.def((phase, env) => { const vibratoRate = 1; const vibratoDepth = 0.001; const baseFreq = 5 * Math.pow(0.5, phase); const vibratoFreq = baseFreq + vibratoDepth * Math.sin(2 * Math.PI * vibratoRate * phase); const wave = Math.sin(2 * Math.PI * vibratoFreq * phase); const glide = Math.exp(-phase * 0.1); return wave * env.value * glide; }); // 808 Kick Sound: Low frequency sine wave with a punchy attack and fast decay (unchanged) const kick808 = synth.def((phase, env) => { const freq = 25 * Math.pow(2, phase); // Low frequency for kick const wave = Math.sin(2 * Math.PI * freq * phase); // Sine wave const envValue = env.value * (1 - Math.pow(phase, 2)); // Exponential decay for punch return wave * envValue; }); const basenotes = [a2, b2, c3, d3, e3]; const kickRhythm = [16, 32, 16, 8, 8, 8, 8, 4]; const bassRhythm = [8, 16, 8, 8, 16, 4, 8, 8]; // Initialize basenote and chord let basenote = basenotes[0]; let currentChord = chords.major7; let offset = 1; loop((i) => { if (i % 4 === 0) { kick808.play({ amp: 1.0, attack: 0.001, release: 0.2 }); } if ( i % 4 === 0) { bass808.play(basenote - 16, { amp: 1, attack: 0.1, sustain: 0.25, release: 4, pan: 0.25}); } if (i % 16 === 0) { let idx; do { idx = Math.floor(basenotes.length * Math.random() / 1); } while (basenote === basenotes[idx]); basenote = basenotes[idx]; currentChord = chords.major7; offset = [1,2,3,4,5,6,7,8].choose(); } // Play a synth bass with current chord progression fmsynth.play(basenote - 16, { amp: 0.1, release: 0.5, pan: 1 }); fmsynth.play(basenote + currentChord.ring(i), { amp: 0.1, attack: 0.001, release: 1, pan: 0.5 }); sleep(0.25); }, { name: "Test" }).connect(comp1);