Master of Puppets (intro)

The (start of the) intro to Master of Puppets with some kind of electric guitar synth.

Inspired by Fork: Smoke on the water (loud!).

Log in to post a comment.

const sin = Math.sin;
const exp = Math.exp;
const PI = Math.PI;

const melody = [
    220 / 4, // bpm
    
    // notes, duration, pause, stop_at_end
    [[e3, b3],   0.25, 1,       true],
    [[d4, a4],   0.15, 0.25,    true],
    [[db4, ab4], 0.15, 0.25,    true],
    [[c4, g4],   4.0,  3.5,     false],
    
    0.9 * 220 / 2,
    
    [[e3, b3],       0.20, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[e4],           0.25, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[eb4],          0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[d4, a4],       0.15, 0.5,  true],
    [[db4, ab4],     0.15, 0.5,  true],
    [[c4, g4],       0.6,  1,    false],
    
    [[e3],           0.20, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[b3],           0.25, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[bb3],          0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[a3],           0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[ab3],          0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[g3],           0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[f3, eb4, bb4], 0.25, 0.25, true],
    [[e3],           0.25, 0.25, false],
    
    [[e3, b3],       0.20, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[e4],           0.25, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[eb4],          0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[d4, a4],       0.15, 0.5,  true],
    [[db4, ab4],     0.15, 0.5,  true],
    [[c4, g4],       0.6,  1,    false],
    
    [[e3],           0.20, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[b3],           0.25, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[e3],           0.20, 0.25, true],
    [[bb3],          0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[a3],           0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[ab3],          0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[g3],           0.25, 0.25, true],
    [[e3],           0.25, 0.25, true],
    [[f3, eb4, bb4], 0.25, 0.25, true],
    [[e3],           1.25, 0.25, false],
    
    [[], 0, 4, false] // pause for a bit
];

const tri = x => ((x / 2 / PI) % 1) * 2 - 1;

const guitar = synth.def(class {
    constructor(options) {
        this.phase = Math.random();
        this.prev = 0;
        this.vibe = Math.random();
    }
    process(note, env, tick, options) {
        this.phase += ditty.dt;
        
        const hit = exp(tick * -50);
        const freq = midi_to_hz(note) + hit * 3;
        const mod = sin(2 * PI * this.phase * freq * 0.251 + 0.01 * sin(2 * PI * 100 * this.phase)); // why does 0.251 just work?
        const val = sin(2 * PI * this.phase * freq + (10 + 6 * this.vibe) * mod) * env.value * 20 +
          sin(2 * (2 * PI * this.phase * freq)) * env.value * 20 * 0.5 +
          sin(3 * (2 * PI * this.phase * freq + 1 * (10 + 6 * this.vibe) * mod)) * env.value * 50 * 0.25 +
          sin(4 * (2 * PI * this.phase * freq)) * env.value * 50 * 0.125;
        
        this.prev += (val - this.prev) * (0.3 + hit * 1);
        const out = clamp(this.prev, -1, 1) * 0.5 * 0.2;
        
        return [out, out];
    }
});

const bass = synth.def(class {
    constructor(options) {
        this.phase = Math.random();
    }
    process(note, env, tick, options) {
        this.phase += ditty.dt;
        
        const freq = midi_to_hz(note);
        const val = sin(2 * PI * this.phase * freq) * env.value;
        
        const out = clamp(val, -1, 1) * 0.7 + clamp(3 * val, -1, 1) * 0.3;
        
        return [out, out];
    }
});

loop(loopcount => {
    const pos = loopcount % melody.length;
    if (typeof melody[pos] == "number") {
        ditty.bpm = melody[pos];
    } else {
        const [notes, dur, pause, stop] = melody[pos];
        const atk = () => 0.005 + Math.random() * 0.005;
        for (const note of notes) {
            guitar.play(note, {attack: atk(), decay: 0.05, duration: stop? dur : 0, release: stop? 0.05 : second_to_tick(dur), curve: [4, 0, -4], pan: -1});
            guitar.play(note, {attack: atk(), decay: 0.05, duration: stop? dur : 0, release: stop? 0.05 : second_to_tick(dur), curve: [4, 0, -4], pan: 1});
            bass.play(note - 24, {attack: 0.005, duration: stop? dur : 0, release: second_to_tick(dur), curve: [4, 0, -4], pan: -1});
            bass.play(note - 24, {attack: 0.005, duration: stop? dur : 0, release: second_to_tick(dur), curve: [4, 0, -4], pan: 1});
        }
        sleep(pause);
    }
}, {name: "eguitar"});