d-layers lowfi beat

Another fork of a great ditty by @reinder (d-layers beat) which is a fork of my ditty (d-layers)

Log in to post a comment.

// Forked from "d-layers beat" by reinder
// https://dittytoy.net/ditty/e4696ead7e

// Forked from "d-layers" by markknol
// https://dittytoy.net/ditty/461bb6b7cf

const tri    = synth.def( (phase, env, tick, options) => { const v = (phase % 1) * 4; return (v < 2 ? v - 1 : 3 - v) * env.value }, { attack: 0.025, release: 0.5, amp: .8, env: adsr2 });
const square = synth.def( (phase, env, tick, options) => (phase % 1 < 0.5 ? 1 : -1) * env.value, { env: adsr2 });
const noise  = synth.def( (phase, env, tick, options) => (Math.random() * 2 - 1) * env.value, { attack: 0.0125, release: 0.15, env: adsr2 });
const kick   = synth.def( (phase, env, tick, options) => Math.sin(phase * 2 * Math.PI * (1.5 - env.progress)) * env.value, { attack: 0.025, release: 0.2, amp: 0.7, env: adsr2 });
const hihat  = synth.def( (phase, env, tick, options) => (Math.random() * 2 - 1) * Math.pow(1 - env.progress, options.pow) * env.value, { attack: 0.0, release: 0.4, amp: 0.5, pow: 4, env: adsr2 });

ditty.bpm = 128

const delay = filter.def(class {
    constructor(options) {
        this.index = 0;
        this.length = options.interval * ditty.sampleRate * 60 / ditty.bpm | 0;
        this.left  = new Float32Array(this.length);
        this.right = new Float32Array(this.length); 
    }

    process(input, options) {
        if (input) {
            const s = options.strength;
            this.index = (this.index + 1) % this.length;
            const hist = (this.index + 1) % this.length;
            
            this.left [this.index] = input[1] + s * this.right[hist];
            this.right[this.index] = input[0] + s * this.left [hist];
            
            return [ this.left[this.index], this.right[this.index] ];
        }
    }
}, { interval: 1/3, strength: 0.25 }); 

loop((i) => {
    tri.play([c3,c4,c3,c5,c3,c4,f3,g5, c3,c4,c3,c5,c3,c4,g5,d5 ][i%16] + (i/32|0)%2*2, { attack: 0.05 * Math.random(), release: 0.4, pan: 0.5 - Math.random() });
    sine.play([c3,c4,c3,c5,c3,c4,f3,g5, c3,c4,c3,c5,c3,c4,g5,d5 ][i%16] - (i/32|0)%2*3 - 24, { attack: 0., release: .5, pan: 0.5 - Math.random(), amp: .4 });
    sleep(0.5);
}, { name: '📢', amp: .8 })
.connect( delay.create( { interval: 1.25, strength: 0.25 }) )
.connect( delay.create( { interval: 2/3, strength: 0.15 }) )
.connect( delay.create( { interval: 1/2, strength: 0.25 }) )
.connect( delay.create( { interval: 1.5, strength: 0.33 }) )

const lowpass = filter.def(class {
    constructor(options) {
        this.hist0 = [0, 0];
        this.hist1 = [0, 0];
    }

    process(input, options) {
        const alpha = options.cutoff;
        if (input) {
            for (let i = 0; i < 2; i++) {
                this.hist0[i] += alpha * (input[i] - this.hist0[i]);
                this.hist1[i] += alpha * (this.hist0[i] - this.hist1[i]);
            }

            return this.hist1;
        }
    }
}, {cutoff: 1});

loop( (loopCount) => {
    if (beat('x--x-----xx-----x--x------x---x-', loopCount)) kick.play(c);
    sleep(.25);
}, { name: 'kick', amp: 1.6 });

loop( (loopCount) => {
    if (beat('----x-------x-------x----x--x---', loopCount)) noise.play(c, { amp: 1 });
    sleep(.25);
}, { name: 'snare' })
.connect( lowpass.create( { cutoff: 0.15 } ))
.connect( delay.create( { interval: 0.2, strength: 0.1 }));

loop( (loopCount) => {
    if (beat('-----x----x----------x----x--x--', loopCount)) hihat.play(c, { pan: 0.2, release: 0.4 });
    sleep(0.25);
}, { name: 'open hi-hat' })
.connect( lowpass.create( { cutoff: .8} ))

loop( (loopCount) => {
    if (beat('xx-xx-xxxx-xx-xxxx-xx-xxxx-xx-xx', loopCount)) hihat.play(c, { amp: 0.15 + 0.01 * Math.random(), release: 0.2, pan: Math.sin(ditty.time * 2) });
    sleep(0.25);
}, { name: 'hi-hat' })
.connect( lowpass.create( { cutoff: .9} ))
.connect( delay.create( { interval: 0.125, strength: 0.25 }));

function beat(str, loopCount) {
    return str.charAt(loopCount % str.length) == 'x';
}