🔍

music livecoding with STRUDEL + live midi controls


// Load external samples from bubo:waveforms
samples('bubo:waveforms');

// Define a simple chord progression to support the bassline
let chords = chord("<dm7 em9 cm7 dm9>")

// --- Melodic Layer with MIDI Controls ---
// The note pattern is now set to play along with the chord progression using set(chords).
// It is also controlled by MIDI, which is defined by the cc variable.
 
let cc = await midin('LPD8')
// The notes are no longer hardcoded. The numbers here correspond to the notes within the current chord.
// For example, 0 is the root, 1 is the next note in the chord, and so on.
let d1 = note("<0 1 2 3>")
.set(chords.rootNotes(4))
  
// Corrected MIDI control access from cc(number) 
.sound("sawtooth")
.n("<1 2 3 4 5 6 7 8 9 10>/2").size(1.9)
.velocity(0.55).often(n => n.ply(4))
.attack(cc(1).range(0,0.4))
.sustain(cc(2).range(0.1,0.94))
.release(cc(3).range(0.1,0.94))
  .delay(cc(7).range(0, 9.0))
  .room(cc(8).range(0, 19.0))
.cutoff(cc(5).range(10, 15000))
  .resonance(cc(6).range(0, 55))
  .gain(0.4)
  .fast(4)

._scope()

// --- Bassline Layer ---
// This pattern plays the root notes of the chords progression.
// It uses a sequence of different synth sounds for a varied texture.
// The slow(2/3) function makes the pattern play as triplets.
let d4 = chords.rootNotes(1)
.slow(1/3)
.s("{z_sawtooth}%3").lpf(200).gain(2)  
.sustain(cc(2).range(0.1,1.94))
.decay(.5).scope()

// Stack the two patterns together to play them simultaneously.
stack(d1, d4)