Concrete Loop

first try

Log in to post a comment.

// 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
});