// DUBLIN MINIMAL TECHNO
// 4-on-the-floor beat with hypnotic bassline and minimal percussion
ditty.bpm = 128;
// ===== SYNTH DEFINITIONS =====
// Simple sine wave kick drum
const kick = synth.def((phase, env, tick, options) =>
Math.sin(phase * 2 * Math.PI) * env.value
, {
attack: 0.001,
release: 0.4,
duration: 1,
amp: 1.0
});
// Simple closed hi-hat (white noise)
const hihat = synth.def((phase, env, tick, options) =>
(Math.random() - 0.5) * env.value
, {
attack: 0.001,
release: 0.08,
duration: 0.5,
amp: 0.4
});
// Open hi-hat with longer decay
const openhat = synth.def((phase, env, tick, options) =>
(Math.random() - 0.5) * env.value
, {
attack: 0.001,
release: 0.2,
duration: 0.5,
amp: 0.3
});
// Simple square bass with stateful oscillator
const bass = synth.def(class {
constructor(options) {
this.phase = 0;
}
process(note, env, tick, options) {
this.phase += midi_to_hz(note) * ditty.dt;
const freq = midi_to_hz(note);
// Simple square wave
const raw = this.phase % 1 < 0.5 ? 1 : -1;
return raw * env.value * 0.8;
}
}, {
attack: 0.05,
release: 0.1,
amp: 0.7
});
// Sub bass (even lower frequency support)
const subbass = synth.def(class {
constructor(options) {
this.phase = 0;
}
process(note, env, tick, options) {
this.phase += midi_to_hz(note) * ditty.dt;
return Math.sin(this.phase * 2 * Math.PI) * env.value * 0.6;
}
}, {
attack: 0.05,
release: 0.15,
amp: 0.5
});
// Perc synth for minimal clicks
const perc = synth.def((phase, env, tick, options) =>
Math.sin(phase * 2 * Math.PI) * env.value
, {
attack: 0.001,
release: 0.05,
amp: 0.3
});
// ===== MAIN LOOPS =====
// LOOP 1: 4-ON-THE-FLOOR KICK (plays every beat)
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 8th notes
loop( (loopCount) => {
for (let i = 0; i < 8; i++) {
hihat.play(c4, { amp: 0.4 });
sleep(0.5);
}
}, {
name: 'hihat_closed',
amp: 0.8,
sync: 4
});
// LOOP 3: OPEN HI-HAT syncopation (on &2 and &4)
loop( (loopCount) => {
sleep(1.5); // Syncopate: start at 1.5
openhat.play(c4, { amp: 0.3 });
sleep(2); // Open hat every 2 beats (on upbeats)
openhat.play(c4, { amp: 0.25 });
sleep(0.5);
}, {
name: 'hihat_open',
amp: 1,
sync: 4
});
// LOOP 4: MAIN BASSLINE - Hypnotic repeating pattern
loop( (loopCount) => {
// Simple 2-bar bassline pattern typical of Dublin minimal techno
const notes = [c1, g0, c1, g0]; // C-G-C-G pattern (hypnotic)
for (let bar = 0; bar < 2; bar++) {
for (let i = 0; i < notes.length; i++) {
bass.play(notes[i], {
duration: 1,
release: 0.08,
attack: 0.03
});
sleep(1);
}
}
}, {
name: 'bass',
amp: 0.75,
sync: 8
});
// LOOP 5: SUB BASS - Deeper support (holds longer)
loop( (loopCount) => {
// Play root note most of the time, simple and minimal
subbass.play(c1, {
duration: 2,
release: 0.12
});
sleep(2);
subbass.play(g0, {
duration: 2,
release: 0.12
});
sleep(2);
subbass.play(c1, {
duration: 4,
release: 0.15
});
sleep(4);
}, {
name: 'subbass',
amp: 0.5,
sync: 8
});
// LOOP 6: MINIMAL PERC HITS (rare hi-pitched percussion)
loop( (loopCount) => {
sleep(2); // Every 2 beats
perc.play(g4, {
duration: 0.5,
amp: 0.25
});
sleep(2);
}, {
name: 'perc',
amp: 1,
sync: 4
});
// LOOP 7: VARIATION PATTERN (adds movement every 8 bars)
loop( (loopCount) => {
if (loopCount % 2 === 0) {
// Even loops: play extra perc hits
for (let i = 0; i < 16; i++) {
if (Math.random() > 0.7) { // Random 30% chance
perc.play(f4 + Math.random() * 3, {
amp: 0.2,
duration: 0.25
});
}
sleep(0.25);
}
} else {
// Odd loops: simple rest
sleep(4);
}
}, {
name: 'variation',
amp: 1.5,
sync: 4
});