// ELECTRO EDM FESTIVE
// High-energy dancefloor with bright synths, dirty bass, and energetic percussion
ditty.bpm = 132;
// ===== INPUT SLIDERS =====
input.bassEnergy = 0.8; // min=0, max=1, step=0.1
input.synthBrightness = 0.7; // min=0, max=1, step=0.1
// ===== SYNTH DEFINITIONS =====
// Punchy kick drum with frequency sweep
const kick = synth.def(class {
constructor(options) {
this.t = 0;
}
process(note, env, tick, options) {
this.t += ditty.dt;
// Pitch drop from 150Hz to 60Hz
const freq = 150 * Math.exp(-this.t * 6);
return Math.sin(this.t * freq * Math.PI * 2) * env.value;
}
}, {
attack: 0.001,
release: 0.5,
duration: 1,
amp: 1.0
});
// Bright closed hi-hats for energy
const hihat = synth.def((phase, env, tick, options) =>
(Math.random() - 0.5) * env.value
, {
attack: 0.0005,
release: 0.06,
duration: 0.5,
amp: 0.5
});
// Crashy open hi-hat for transitions
const crashhat = synth.def((phase, env, tick, options) =>
(Math.random() - 0.5) * env.value
, {
attack: 0.001,
release: 0.25,
duration: 0.5,
amp: 0.6
});
// Dirty sawtooth bass
const bass = synth.def(class {
constructor(options) {
this.phase = 0;
}
process(note, env, tick, options) {
this.phase += midi_to_hz(note) * ditty.dt;
// Sawtooth wave
const raw = (this.phase % 1) * 2 - 1;
// Soft clipping for aggression
const clipped = raw > 0.8 ? 1 : raw < -0.8 ? -1 : raw;
return clipped * env.value * 0.85;
}
}, {
attack: 0.02,
release: 0.12,
amp: 0.8
});
// Bright square wave synth for leads
const brightSynth = synth.def(class {
constructor(options) {
this.phase = 0;
}
process(note, env, tick, options) {
this.phase += midi_to_hz(note) * ditty.dt;
// Square wave
const raw = this.phase % 1 < 0.5 ? 1 : -1;
return raw * env.value * 0.7;
}
}, {
attack: 0.01,
release: 0.15,
amp: 0.6
});
// Arpeggiated synth for festive energy
const arpSynth = synth.def(class {
constructor(options) {
this.phase = 0;
}
process(note, env, tick, options) {
this.phase += midi_to_hz(note) * ditty.dt;
// Triangle wave
const saw = this.phase % 1;
const tri = saw < 0.5 ? saw * 4 - 1 : 3 - saw * 4;
return tri * env.value * 0.6;
}
}, {
attack: 0.005,
release: 0.1,
amp: 0.5
});
// Snare crack
const snare = synth.def((phase, env, tick, options) =>
((Math.random() - 0.5) * 2) * Math.sin(phase * 2 * Math.PI * 200) * env.value
, {
attack: 0.0005,
release: 0.15,
amp: 0.7
});
// Perc for fills
const perc = synth.def((phase, env, tick, options) =>
Math.sin(phase * 2 * Math.PI) * env.value
, {
attack: 0.001,
release: 0.05,
amp: 0.4
});
// ===== MAIN LOOPS =====
// LOOP 1: KICK - 4-on-the-floor base (essential for EDM)
loop( (loopCount) => {
for (let i = 0; i < 4; i++) {
kick.play(c2, { amp: 1.0 });
sleep(1);
}
}, {
name: 'kick',
amp: 1.0,
sync: 4
});
// LOOP 2: CLOSED HI-HATS on 16th notes (high energy)
loop( (loopCount) => {
for (let i = 0; i < 16; i++) {
if (i % 4 !== 0) { // Skip some to create pocket
hihat.play(c5, { amp: 0.4 + Math.random() * 0.1 });
}
sleep(0.25);
}
}, {
name: 'hihat_closed',
amp: 0.9,
sync: 4
});
// LOOP 3: SNARE on 2 and 4 (classic EDM pattern)
loop( (loopCount) => {
sleep(1); // Beat 2
snare.play(c4, { amp: 0.8 });
sleep(1);
sleep(1); // Beat 4
snare.play(c4, { amp: 0.75 });
sleep(1);
}, {
name: 'snare',
amp: 0.85,
sync: 4
});
// LOOP 4: CRASH HATS for variation and transitions
loop( (loopCount) => {
if (loopCount % 2 === 1) { // Every other loop (every 4 bars)
sleep(3.5);
crashhat.play(c5, { amp: 0.6 });
sleep(0.5);
} else {
sleep(4);
}
}, {
name: 'crash',
amp: 0.7,
sync: 4
});
// LOOP 5: MAIN BASS - Dirty and energetic
loop( (loopCount) => {
// Festive bass pattern with more movement
const bassPattern = [c1, g0, c1, eb1, c1, g0, c1, b0];
for (let i = 0; i < bassPattern.length; i++) {
bass.play(bassPattern[i], {
duration: 1,
release: 0.08,
attack: 0.015,
amp: 0.7 + input.bassEnergy * 0.2
});
sleep(1);
}
}, {
name: 'bass',
amp: 0.9,
sync: 8
});
// LOOP 6: BRIGHT SYNTH MELODY - Festival vibe
loop( (loopCount) => {
const melodyNotes = [c5, g4, c5, eb5, c5, g4, a4, g4];
for (let i = 0; i < melodyNotes.length; i++) {
brightSynth.play(melodyNotes[i], {
duration: 0.8,
release: 0.1,
attack: 0.01,
amp: 0.5 + input.synthBrightness * 0.15
});
sleep(1);
}
}, {
name: 'bright_synth',
amp: 0.75,
sync: 8
});
// LOOP 7: ARPEGGIATED FESTIVE SYNTH (adds high-energy texture)
loop( (loopCount) => {
const arpNotes = scale(c5, scales['major'], 1);
for (let i = 0; i < 16; i++) {
arpSynth.play(arpNotes[i % arpNotes.length], {
duration: 0.4,
release: 0.08,
amp: 0.3 + Math.random() * 0.1
});
sleep(0.25);
}
}, {
name: 'arp_synth',
amp: 0.65,
sync: 4
});
// LOOP 8: PERCUSSION FILLS (breaks up monotony with energy bursts)
loop( (loopCount) => {
if (loopCount % 4 === 3) { // Every 16 bars
// Drum fill
for (let i = 0; i < 8; i++) {
perc.play(f4 + i * 2, {
duration: 0.25,
release: 0.04,
amp: 0.3 + Math.random() * 0.15
});
sleep(0.25);
}
} else {
sleep(4);
}
}, {
name: 'fills',
amp: 0.6,
sync: 4
});
// LOOP 9: SECONDARY BRIGHT SYNTH - Counter-melody (festive interaction)
loop( (loopCount) => {
if (loopCount > 0 && loopCount % 2 === 0) {
// Play counter-melody on even loops
const counterNotes = [a5, b5, c6, b5, a5];
for (let i = 0; i < counterNotes.length; i++) {
brightSynth.play(counterNotes[i], {
duration: 1,
release: 0.12,
attack: 0.01,
amp: 0.4
});
sleep(1);
}
} else {
sleep(5);
}
}, {
name: 'counter_synth',
amp: 0.6,
sync: 8
});