UPLIFTING TRANCE CLASSIC

UPLIFTING TRANCE CLASSIC

Log in to post a comment.

// ============================================================================
// UPLIFTING TRANCE CLASSIC (138 BPM) - Dittytoy Code
// ============================================================================

ditty.bpm = 138;

// ----------------------------------------------------------------------------
// 1. SYNTH DEFINITIONS
// ----------------------------------------------------------------------------

// High-Energy Supersaw Lead
const supersaw = synth.def(class {
    constructor(options) {
        this.detune = [0.985, 0.993, 1.000, 1.007, 1.015];
        this.phases = this.detune.map(() => Math.random());
    }
    process(note, env, tick, options) {
        let freq = midi_to_hz(note);
        let sig = 0;
        
        // Accumulate 5 detuned saw waves
        for (let i = 0; i < this.detune.length; i++) {
            this.phases[i] += freq * this.detune[i] * ditty.dt;
            this.phases[i] %= 1.0;
            sig += (this.phases[i] * 2 - 1);
        }
        
        // Dynamic Filter Cutoff Sweep via option
        let cutoff = options.cutoff || 0.5;
        sig = Math.sin(sig * Math.PI * cutoff); 
        
        return sig * 0.2 * env.value;
    }
}, { attack: 0.01, release: 0.3 });

// Resonant 303-style Acid Saw Bass
const acidBass = synth.def(class {
    constructor(options) {
        this.phase = Math.random();
    }
    process(note, env, tick, options) {
        let freq = midi_to_hz(note);
        this.phase += freq * ditty.dt;
        this.phase %= 1.0;
        
        let saw = this.phase * 2 - 1;
        // Simple resonant waveshaping filter simulation
        let envCut = env.value ** 1.5;
        let out = Math.tanh(saw * (1 + envCut * 4));
        return out * 0.4 * env.value;
    }
}, { attack: 0.005, release: 0.15 });

// Pluck / Arpeggiator Synth
const pluck = synth.def((phase, env, tick, options) => {
    let sig = (phase % 1) * 2 - 1; // Saw wave
    return Math.sin(sig * Math.PI * 0.8) * env.value;
}, { attack: 0.002, release: 0.18 });

// Drums: Kick, Clap, Hi-Hat
const kick = synth.def(class {
    constructor(options) {
        this.phase = 0;
    }
    process(note, env, tick, options) {
        // Fast pitch drop from ~180 Hz down to ~50 Hz for the initial 'thump'
        let pitchEnv = env.value ** 4; 
        let freq = 50 + pitchEnv * 130;
        
        this.phase += freq * ditty.dt;
        let sineWave = Math.sin(this.phase * Math.PI * 2);
        
        // Add transient click at the start
        let click = (env.value > 0.95) ? (Math.random() * 2 - 1) * 0.15 : 0;
        
        // Apply drive/saturation using Math.tanh for body and punch
        let drive = 1.8;
        let saturated = Math.tanh((sineWave + click) * drive);
        
        return saturated * 0.9 * (env.value ** 0.8);
    }
}, { attack: 0.0005, release: 0.38 });

const hat = synth.def((phase, env, tick, options) => {
    return (Math.random() * 2 - 1) * env.value;
}, { attack: 0.001, release: 0.05 });

// ----------------------------------------------------------------------------
// 2. MUSICAL DATA (Scale: C Minor / Eb Major Trance Progression)
// ----------------------------------------------------------------------------

const bassLine = [
    c2, c2, c2, c2,  c2, c2, c2, c2,
    ab1, ab1, ab1, ab1, eb2, eb2, bb1, bb1
];

const arpNotes = [
    c4, g4, c5, eb5, g5, eb5, c5, g4,
    ab3, eb4, ab4, c5, eb5, c5, ab4, eb4,
    eb4, bb4, eb5, g5, bb5, g5, eb5, bb4,
    bb3, f4, bb4, d5, f5, d5, bb4, f4
];

const leadMelody = [
    c5, g5, eb5, d5, c5, g5, eb5, f5,
    ab5, g5, eb5, d5, c5, d5, eb5, g5
];

// ----------------------------------------------------------------------------
// 3. LOOPS (SEPARATE THREADS)
// ----------------------------------------------------------------------------

// Kick Loop (Classic 4-on-the-floor)
loop((loopCount) => {
    kick.play(c2, { amp: 1.2 });
    sleep(1.0);
}, { name: 'Kick' });

// Offbeat Open Hi-Hat
loop((loopCount) => {
    sleep(0.5);
    hat.play(c6, { amp: 0.6, release: 0.08 });
    sleep(0.5);
}, { name: 'Offbeat Hat' });

// 16th Note Driving Bassline
loop((loopCount) => {
    let idx = loopCount % bassLine.length;
    acidBass.play(bassLine[idx], { 
        amp: idx % 2 === 0 ? 0.8 : 0.6,
        pan: (loopCount % 4 === 0) ? -0.1 : 0.1 
    });
    sleep(0.25);
}, { name: 'Driving Bass' });

// Fast 16th-note Arpeggio Layer
loop((loopCount) => {
    let note = arpNotes[loopCount % arpNotes.length];
    pluck.play(note, { 
        amp: 0.45, 
        pan: Math.sin(loopCount * 0.25) * 0.6 // Panning sweep
    });
    sleep(0.25);
}, { name: 'Trance Arp' });

// Main Euphoric Lead (Starts filtering up dynamically)
loop((loopCount) => {
    let step = loopCount % leadMelody.length;
    let cutoffValue = 0.3 + 0.6 * Math.abs(Math.sin(loopCount * 0.05)); // Filter modulation
    
    supersaw.play(leadMelody[step], { 
        duration: 0.5,
        attack: 0.01,
        release: 0.4,
        amp: 0.7,
        cutoff: cutoffValue,
        pan: (step % 2 === 0) ? 0.3 : -0.3
    });
    sleep(0.5);
}, { name: 'Main Anthem Lead' });