Ditty Mario XXL Mashup 🍄

Oh yeah! Mario time!
Mix of all cool sounds on Dittytoy. Might change when I find new stuff :)

Piano sound from Electric Piano 1 by @athibaul

(Insane cool) Reverb from Karplus synth with reverb by @srtuss

Fat kick from Fat kick by @athibaul

Beat from d-layers beat by @reinder

Log in to post a comment.

// Forked from "Ditty Mario 🍄" by markknol
// https://dittytoy.net/ditty/3cc8ab88cd

ditty.bpm = 90;



const choose = (array) => array[Math.floor(Math.random() * array.length)];
/*
 Reverb from https://dittytoy.net/ditty/827b1b3e63 by @srtuss
*/
class Delayline {
    constructor(n) {
        this.n = ~~n;
        this.p = 0;
        this.lastOut = 0;
        this.data = new Float32Array(n);
    }
    clock(input) {
        this.lastOut = this.data[this.p];
        this.data[this.p] = input;
        if(++this.p >= this.n) {
            this.p = 0;
        }
    }
    tap(offset) {
        var x = this.p - offset - 1;
        x %= this.n;
        if(x < 0) {
            x += this.n;
        }
        return this.data[x];
    }
}

function allpass(delayline, x, k) {
    var delayin = x - delayline.lastOut * k;
    var y = delayline.lastOut + k * delayin;
    delayline.clock(delayin);
    return y;
}

// Simple allpass reverberator, based on this article:
// http://www.spinsemi.com/knowledge_base/effects.html
const reverb = filter.def(class {
    constructor(options) {
        this.lastReturn = 0;
        this.krt = .68;
        this.delaylines = [];
        // Create several delay lines with random lengths
        for(var i = 0; i < 12; ++i) {
            this.delaylines.push(new Delayline(10 + Math.floor(i/12 * 5000)));
        }
    }
    process(input, options) {
        var inv = input[0] + input[1];
        var v = this.lastReturn;
        // Let the signal pass through the loop of delay lines. Inject input signal at multiple locations.
        v = allpass(this.delaylines[0], v + inv, .5);
        v = allpass(this.delaylines[1], v, .5);
        this.delaylines[2].clock(v);
        v = this.delaylines[2].lastOut * this.krt;
        v = allpass(this.delaylines[3], v + inv, .5);
        v = allpass(this.delaylines[4], v, .5);
        this.delaylines[5].clock(v);
        v = this.delaylines[5].lastOut * this.krt;
        v = allpass(this.delaylines[6], v + inv, .5);
        v = allpass(this.delaylines[7], v, .5);
        this.delaylines[8].clock(v);
        v = this.delaylines[8].lastOut * this.krt;
        v = allpass(this.delaylines[9], v + inv, .5);
        v = allpass(this.delaylines[10], v, .5);
        this.delaylines[11].clock(v);
        v = this.delaylines[11].lastOut * this.krt;
        this.lastReturn = v;
        // Tap the delay lines at randomized locations and accumulate the output signal.
        var ret = [0, 0];
        ret[0] += this.delaylines[2].tap(111);
        ret[1] += this.delaylines[2].tap(2250);
        ret[0] += this.delaylines[5].tap(311);
        ret[1] += this.delaylines[5].tap(1150);
        ret[0] += this.delaylines[8].tap(511);
        ret[1] += this.delaylines[8].tap(50);
        ret[0] += this.delaylines[11].tap(4411);
        ret[1] += this.delaylines[11].tap(540);
        // Mix wet + dry signal.
        ret[0] = ret[0] * .1 + input[0];
        ret[1] = ret[1] * .1 + input[1];
        // Slight stereo widening:
        var m = (ret[0] + ret[1]) * .5;
        var s = (ret[1] - ret[0]) * .5;
        ret[0] = m + s * 1.5;
        ret[1] = m - s * 1.5;
        return ret;
    }
});


/*
 Piano sound from https://dittytoy.net/ditty/5f66552091 by @athibaul
*/
const TAU = 2*Math.PI;
const msin = (x,m) => Math.sin(TAU*x + m);
// Electric piano using phase modulation
const ep1 = synth.def( (phase, env, tick, options) => { 
    let sig = msin(phase, msin(11*phase,0) * clamp01(1 - 10*tick)*options.amp);
    sig = sig + msin(phase, msin(phase,0) * 2 * options.amp);
    return sig * env.value;
}, {attack:0.01, release: 0.3, decay: 0.2}
);

const interval = 0.3;
loop(() => {
    [
      e7, e7, 0, e7, 0, c7, e7, 0, g7, 0, 0,  0, g6, 0, 0, 0,
      c7, 0, 0, g6, 0, 0, e6, 0, 0, a6, 0, b6, 0, as6, a6, 0,
      g6, e7, g7, a7, 0, f7, g7, 0, e7, 0, c7, d7, b6, 0, 0,
      c7, 0, 0, g6, 0, 0, e6, 0, 0, a6, 0, b6, 0, as6, a6, 0,
      g6, e7, g7, a7, 0, f7, g7, 0, e7, 0, c7, d7, b6, 0, 0
    ].forEach((note,idx) => (note ? (ep1.play(note - choose([24,36,48]), {amp: Math.random() + 0.3, decay:interval}), ep1.play(note - choose([24,36,48]), {amp: Math.random() + 0.3, decay:interval/2})) : {}, sleep(0.25)));
    sleep(2);
}, {amp:0.1}).connect(reverb.create());

const linexp = (x,x0,x1,y0,y1) => y0 * (y1/y0) ** ((x-x0)/(x1-x0));
const linlin = (x,x0,x1,y0,y1) => y0 + (y1 - y0) * clamp01((x-x0)/(x1-x0));

const tri = synth.def((phase, env) => 1.22*(4.0*Math.abs(phase % 1 - 0.5) - 1.0) * env.value);
const dist = synth.def((phase, env, tick, options) => Math.atan(25*(Math.abs(phase % 1 - 0.5) - 0.25) * env.value));


/*
fat kick from https://dittytoy.net/ditty/57d4ff2921
*/
let rhythm = [1.5,1.5,1,1.5,1.5,1, 1.5,1,1.5,1.5,1,1.5]
let i = 0;
loop( () => {
    // click
    sine.play((tick) => linlin(tick, 0, 0.03, 127, 0), {attack:0.0005, release:0.05, amp:0.1});
    // boom
    sine.play(
        (tick) => linlin(tick, 0, 0.3, a1, f1),
        //{env: adsr2, attack:0.01, decay:0.1, decay_level:0.1, sustain:0.15, sustain_level:0.5, release:0.2, amp:2}
        {env: adsr, attack:0.26, release:0.2}
    );
    // low thump
    tri.play(
        (tick) => linlin(tick, 0, 0.1, e3, f1),
        {env: adsr, attack:0.005, release:0.1}
    );
    // high tump
    tri.play(
        (tick) => linlin(tick, 0, 0.03, a5, a3),
        {env: adsr, attack:0.005, release:0.03, amp:0.3}
    );
    sleep(rhythm[i]/2);
    i = (i+1)%rhythm.length;
    
}, {name:"kick"});


/*
 beat from https://dittytoy.net/ditty/e4696ead7e by @reinder
*/
const noise  = synth.def( (phase, env, tick, options) => (Math.random() * 2 - 1) * env.value, { attack: 0.0125, release: 0.15, env: adsr2 });

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[0] + s * this.right[hist];
            this.right[this.index] = input[1] + s * this.left [hist];
            
            return [ this.left[this.index], this.right[this.index] ];
        }
    }
}, { interval: 1/3, strength: 0.25 }); 

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) => {
    '--x---x---x---xx'.ring(loopCount) == 'x' && noise.play(c3, { amp: 2});
    sleep(.5);
}, { name: 'snare' })
.connect( lowpass.create( { cutoff: 0.15 } ))
.connect( delay.create( { interval: 0.25, strength: 0.15 }))

loop( () => {
    noise.play(c, { amp: 0.02 + 0.01 * Math.random(), pan: Math.sin(ditty.time * 8) });
    sleep(0.25);
}, { name: 'hi-hat' })
.connect( lowpass.create( { cutoff: .9} ))
.connect( delay.create( { interval: 0.25, strength: 0.5 }));