Strudel, a JavaScript version of Tidal Cycles.
https://tinyurl.com/298b4p66
// --- samples ---
await samples({ gtr: 'gtr/0001_cleanC.wav' }, 'github:tidalcycles/Dirt-Samples/master/')
samples('github:eddyflux/crate')
// --- tempo & feel ---
setcpm(25/4) // slow, funky
let swingMask = "<0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1>/16"
let microSwing = 0.02 // subtle shove on offbeats
// --- simple sound wrappers (only Strudel-safe ops) ---
const lead8 = p => p.s("square").gain(0.65).crush(6).lpf(1600).delay(0.25).delayfb(0.25)
const bass8 = p => p.s("square").gain(0.95).lpf(750)
const pad8 = p => p.s("square").gain(0.35).lpf(1200)
const gtrStab = p => p.s("gtr").gain(0.45).room(0.6)
const rand = Math.random
// === KICK: seeded arrays (no .split) ===
const seedKickGrids = [
["bd","~","~","~","bd","~","~","~","bd","~","~","~","bd","~","~","~"],
["bd","~","bd","~","~","bd","~","~","bd","~","~","bd","~","~","~","~"],
["bd","~","~","bd","bd","~","~","~","~","bd","~","~","bd","~","~","~"],
["bd","~","~","~","bd","~","bd","~","~","~","bd","~","bd","~","~","~"]
]
const genKick = (i) => {
let grid = seedKickGrids[i % seedKickGrids.length].slice() // copy
for (let s = 0; s < grid.length; s++){
if (grid[s] === "bd" && rand() < 0.15) grid[s] = "~"
if (grid[s] === "~" && rand() < 0.08) grid[s] = "bd"
}
return grid.join(' ')
}
// === SNARE: backbeat + ghosts ===
const genSnare = (i) => {
let g = Array(16).fill('~')
g[4] = "sd"; g[12] = "sd"
let ghostProb = 0.05 + (i % 4) * 0.03
for (let s = 0; s < 16; s++){
if (g[s] === "~" && rand() < ghostProb) g[s] = (rand() < 0.7 ? "sd" : "~")
}
if (i % 3 === 0 && rand() < 0.5) { // flam-ish extra
let pos = 1 + Math.floor(rand()*14)
g[pos] = "sd"
}
return g.join(' ')
}
// === HATS: evolving density, open/closed mix ===
const genHats = (i) => {
let density = 0.35 + (i % 8) * 0.03
let g = Array(16).fill('~')
for (let s = 0; s < 16; s++){
if (rand() < density) g[s] = (rand() < 0.8 ? "hh" : "oh")
}
return g.join(' ')
}
// === BASS: modal 8-bit line, per-bar variation ===
const bassScale = ['e2','g2','a2','b1','d2','e2','g2','a2']
const genBass = (i) => {
let g = Array(16).fill('~')
let idx = (i * 2) % bassScale.length
;[0,4,7,10,14].forEach((p,k)=> g[p] = bassScale[(idx+k)%bassScale.length])
if (i % 4 === 2) g[2] = bassScale[(idx+5)%bassScale.length]
if (i % 5 === 3) g[8] = bassScale[(idx+3)%bassScale.length]
return g.join(' ')
}
// =====================================================
// INTRO (4 bars): sparse drums + 8-bit lead + guitar
// =====================================================
let introDrums = stack(
s("bd ~ bd ~ bd ~ bd ~ bd ~ bd ~ bd ~ bd ~").bank('crate').gain(1),
s("~ ~ ~ ~ sd ~ ~ ~ ~ ~ ~ ~ sd ~ ~ ~").bank('crate').gain(0.8).late(0.01),
s("~ hh ~ hh ~ hh ~ hh ~ hh ~ hh ~ hh ~ hh").bank('crate')
.gain(0.32).mask(swingMask).late(microSwing).hpf(900)
)
let introLead = lead8(note("e4 ~ g4 ~ b4 ~ ~ ~ d5 ~ b4 ~ g4 ~ ~ ~"))
let introGtr = gtrStab(s("gtr ~ ~ ~ ~ ~ gtr ~ ~ ~ ~ gtr ~ ~ gtr ~"))
let intro = stack(introDrums, introLead, introGtr).segment(4)
// =====================================================
// VERSE (16 bars): evolving drums + bass + pad
// =====================================================
let vKickBars = Array.from({length:16}, (_,i)=> s(genKick(i)).bank('crate').gain(1.05))
let vSnareBars = Array.from({length:16}, (_,i)=> s(genSnare(i)).bank('crate').gain(0.95).late(0.012))
let vHatBars = Array.from({length:16}, (_,i)=> s(genHats(i)).bank('crate')
.gain(0.34).mask(swingMask).late(microSwing).hpf(800))
let vDrumBars = vKickBars.map((_,i)=> stack(vKickBars[i], vSnareBars[i], vHatBars[i]))
let verseDrums = cat(vDrumBars)
let vBassBars = Array.from({length:16}, (_,i)=> bass8(note(genBass(i))))
let verseBass = cat(vBassBars)
let versePad = pad8(
note("[e3 g3 b3] ~ [d3 g3 b3] ~ [a2 e3 a3] ~ [g2 b2 e3] ~").slow(2)
).gain(0.3)
let verse = stack(verseDrums, verseBass, versePad).size(8) // 16 bars
// =====================================================
// CHORUS (8 bars): tighter backbeat + hook lead + pads
// =====================================================
let cK = "bd ~ bd ~ bd ~ bd ~ bd ~ bd ~ bd ~ bd ~"
let cS = "~ ~ ~ ~ sd ~ ~ ~ ~ ~ ~ ~ sd ~ ~ ~"
let cHH = "hh ~ hh ~ oh ~ hh ~ hh ~ hh ~ oh ~ hh ~"
let chorusDrums = stack(
s(cK).bank('crate').gain(1.1),
s(cS).bank('crate').gain(1.0).late(0.015),
s(cHH).bank('crate').gain(0.42).mask(swingMask).late(microSwing+0.004).hpf(650)
).segment(8)
let chorusBass = bass8(
note("e2 e2 g2 ~ b1 e2 a2 ~ e2 g2 b1 ~ d2 e2 g2 ~")
).gain(1.0)
let chorusHook = lead8(
note("e4 g4 b4 e5 d5 b4 g4 e4 g4 a4 b4 d5 b4 a4 g4 e4")
).gain(0.9).crush(5)
let chorusPad = pad8(
note("[e3 b3] ~ [a3 e4] ~ [g3 d4] ~ [b3 e4] ~").slow(2)
)
let chorus = stack(chorusDrums, chorusBass, chorusHook, chorusPad).size(4) // 8 bars
// =====================================================
// BREAKDOWN (4 bars)
// =====================================================
let breakdown = stack(
s("bd ~ ~ ~ ~ ~ ~ ~ bd ~ ~ ~ ~ ~ ~ ~").bank('crate').gain(0.75).lpf(500),
lead8(note("e4 ~ ~ ~ g4 ~ ~ ~ b4 ~ ~ ~ e4 ~ ~ ~")).gain(0.45),
pad8(note("[e3 g3 b3] ~ ~ ~ [a3 e4] ~ ~ ~")).gain(0.25)
).segment(4)
// =====================================================
// CHORUS RETURN (8 bars) & OUTRO (4 bars)
// =====================================================
let chorus2 = chorus
let outro = stack(
gtrStab(s("gtr ~ ~ ~ ~ ~ ~ ~ gtr ~ ~ ~ ~ ~ ~ ~")).gain(0.55),
bass8(note("e2 ~ ~ ~ d2 ~ ~ ~ b1 ~ ~ ~ e2 ~ ~ ~")).gain(0.85),
s("bd ~ ~ ~ ~ ~ ~ ~ bd ~ ~ ~ ~ ~ ~ ~").bank('crate').gain(0.7)
).segment(4)
// --- full arrangement ---
seq([intro, verse, chorus, breakdown, chorus2, outro])
https://tinyurl.com/ycyu8hca
await samples({'gtr': 'gtr/0001_cleanC.wav'}, 'github:tidalcycles/Dirt-Samples/master/');
samples('github:eddyflux/crate')
setcpm(15/4)
// Melodic instrument definitions
const melodia = x => x.note().s("ocarina").gain(0.6).clip(1).release(0.1).color(2)
const guitar = x => x.note().s("gtr").room(1).gain(0.35).clip(1).release(0.3)
const accordi = x => x.note().s("recorder_bass_sus").gain(0.8).clip(1).release(0.5)
const basso = x => x.note().s("gm_electric_bass_pick").gain(0.7).clip(1).sustain(0.8)
const synth = x => x.note().s("square").gain(0.4).lpf(1500).resonance(8)
// Enhanced swing with micro-timing variations
let swingMask = "<0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1>/16"
let microSwing = "<0 0.8 0 1.2 0 0.9 0 1.1>/8"
// Evolving harmonic progression
const scalaIntro = "<c#4:major>"
const scalaVerse = "<c#4:major [f#4:major b3:major] [g#4:minor e4:major] [a4:major f#4:minor]>"
const scalaChorus = "<[e4:major a4:major] [f#4:minor b4:major] [g#4:minor c#5:major] [a4:major d#4:dim]>"
const scalaBreakdown = "<c#4:minor [f#4:minor bb3:major] [g#4:dim e4:minor]>"
// ---------- INTRO (4 bars): Complex beat + melodic entry ----------
let introDrums = cat(
"bd ~ bd bd ~ bd ~ ~ bd ~ ~ bd bd ~ bd ~",
"bd bd ~ ~ bd ~ bd bd ~ ~ bd ~ bd ~ ~ bd",
"~ bd ~ bd bd ~ ~ ~ bd bd ~ bd ~ bd ~ ~",
"bd ~ ~ bd ~ bd bd ~ bd ~ bd ~ ~ ~ bd bd"
)
let introHats = cat(
"hh ~ hh hh ~ oh ~ hh hh ~ hh ~ oh hh ~ ~",
"~ hh ~ oh hh hh ~ ~ oh ~ hh hh ~ ~ oh hh",
"hh oh ~ ~ ~ hh hh oh ~ hh ~ ~ hh ~ oh ~",
"oh ~ hh ~ hh ~ ~ hh oh hh ~ hh ~ oh ~ hh"
)
let introMelody = "<[0,2,4] ~ [4,6] ~ [2,5] ~ [0,4] ~>".scale(scalaIntro).apply(melodia)
let introGuitar = "<4 2 0 ~ 4 ~ 2 0>".scale(scalaIntro).transpose(-12).apply(guitar)
let intro = stack(
s(introDrums).bank('crate').gain(0.9),
s(introHats).bank('crate').gain(0.3).late(microSwing).hpf(1000),
introMelody,
introGuitar
).segment(4)
// ---------- VERSE (16 bars): Melodic foundation with complex rhythms ----------
let vK = cat(
"bd ~ ~ ~ bd ~ ~ ~ bd ~ ~ ~ bd ~ ~ ~",
"bd ~ ~ ~ bd ~ bd ~ bd ~ ~ ~ ~ bd ~ ~",
"bd ~ bd ~ bd ~ ~ ~ bd ~ ~ bd ~ ~ ~ ~",
"bd ~ ~ ~ ~ bd ~ bd ~ ~ bd ~ bd ~ ~ ~"
)
let vS = cat(
"~ ~ ~ ~ sd ~ ~ ~ ~ ~ ~ ~ sd ~ ~ ~",
"~ ~ ~ ~ sd ~ ~ ~ ~ ~ sd ~ ~ sd ~ ~",
"~ ~ sd ~ ~ ~ ~ ~ sd ~ ~ ~ ~ ~ ~ sd",
"~ sd ~ ~ sd ~ ~ ~ ~ ~ ~ ~ sd ~ sd ~"
)
let vHH = cat(
"~ hh ~ hh ~ hh ~ hh ~ hh ~ hh ~ hh ~ hh",
"hh ~ hh ~ oh ~ hh ~ hh ~ oh ~ hh ~ hh ~",
"~ oh hh ~ hh ~ ~ hh oh ~ hh ~ ~ hh oh ~",
"hh hh ~ ~ ~ oh hh hh ~ ~ hh oh hh ~ ~ hh"
)
let verseDrums = stack(
s(vK).bank('crate').gain(1.0),
s(vS).bank('crate').gain(0.9),
s(vHH).bank('crate').gain(0.35).late(microSwing).mask(swingMask).hpf(800)
).segment(16)
// Melodic verse elements
let verseAccordi = "<[0,2,4]*2 [2,4,6] [4,6,1] [0,2,5]>".struct("[x ~]*4").scale(scalaVerse).apply(accordi)
let verseGuitar = "<[4 2 0 4]*2 [6 4 2 6] [1 4 6 1] [2 0 4 2]>".scale(scalaVerse).transpose(-12).apply(guitar)
let verseBasso = "<-3 ~ -1 ~ 0 ~ -3 ~ 2 ~ 0 ~ -1 ~ 4 ~>".scale(scalaVerse).transpose(-12).apply(basso)
// Lead melody line
let verseMelody = cat(
"0 ~ 2 4 ~ 6 ~ 4 2 ~ 0 ~ 4 2 ~ ~",
"2 4 ~ 6 4 ~ 2 ~ 0 2 ~ 4 ~ 6 4 2",
"~ 4 6 ~ 1 4 ~ 6 ~ 2 4 ~ 0 ~ 2 ~",
"4 ~ 2 ~ 0 4 ~ 2 6 ~ 4 2 ~ 0 ~ 4"
).scale(scalaVerse).transpose(12).apply(melodia)
let verse = stack(verseDrums, verseAccordi, verseGuitar, verseBasso, verseMelody).size(8)
// ---------- CHORUS (16 bars): Full melodic complexity ----------
let cK = cat(
"bd ~ bd ~ bd ~ bd ~ bd ~ bd ~ bd ~ bd ~",
"bd bd ~ ~ bd ~ ~ bd ~ bd bd ~ bd ~ ~ ~",
"bd ~ ~ bd bd bd ~ ~ ~ bd ~ bd bd ~ bd ~",
"bd ~ bd bd ~ ~ bd ~ bd ~ ~ ~ bd bd ~ bd"
)
let cS = cat(
"~ ~ ~ ~ sd ~ ~ ~ ~ ~ ~ ~ sd ~ ~ ~",
"~ ~ ~ sd ~ ~ ~ ~ sd ~ sd ~ ~ ~ ~ ~",
"~ ~ ~ ~ sd sd ~ ~ ~ ~ ~ sd sd ~ ~ ~",
"~ sd ~ ~ ~ ~ sd ~ ~ sd ~ ~ sd ~ sd ~"
)
let cHH = cat(
"hh ~ hh ~ oh ~ hh ~ hh ~ hh ~ oh ~ hh ~",
"~ hh oh hh ~ hh ~ oh hh ~ ~ hh oh hh ~ ~",
"hh oh ~ ~ hh ~ hh oh ~ hh hh ~ ~ oh hh hh",
"oh ~ hh hh ~ oh ~ ~ hh hh oh ~ hh ~ ~ oh"
)
let chorusDrums = stack(
s(cK).bank('crate').gain(1.1),
s(cS).bank('crate').gain(1.0),
s(cHH).bank('crate').gain(0.4).late(microSwing).mask(swingMask).hpf(600)
).segment(16)
// Rich harmonic chorus
let chorusAccordi = "<[0,2,4,6]*4 [2,4,6,1] [4,6,1,3] [0,2,5,7]>".struct("[x ~ x ~]*2").scale(scalaChorus).apply(accordi)
let chorusGuitar1 = "<[0 4 2 6]*2 [4 1 6 3] [2 6 4 1] [0 5 2 7]>".scale(scalaChorus).transpose(-12).apply(guitar)
let chorusGuitar2 = "<[4 0 6 2] [1 4 3 6] [6 2 1 4] [5 0 7 2]>".scale(scalaChorus).transpose(-24).apply(guitar)
let chorusBasso = "<0 ~ 2 ~ 4 ~ 0 ~ 1 ~ 4 ~ 2 ~ 6 ~>".scale(scalaChorus).transpose(-24).apply(basso)
// Soaring lead melodies
let chorusMelody1 = cat(
"0 2 4 6 ~ 4 2 ~ 6 4 ~ 2 0 ~ 4 ~",
"2 ~ 4 6 1 ~ 4 ~ 6 1 4 ~ 2 6 ~ 4",
"4 6 ~ 1 3 6 ~ 4 1 ~ 3 ~ 6 4 1 ~",
"0 ~ 2 5 ~ 7 2 ~ 5 0 ~ 7 ~ 2 5 0"
).scale(scalaChorus).transpose(12).apply(melodia)
let chorusMelody2 = cat(
"~ 4 ~ 6 4 ~ 2 4 ~ 6 4 2 ~ 0 ~ 2",
"4 2 ~ 6 ~ 1 4 6 ~ 3 1 ~ 4 ~ 2 ~",
"6 ~ 1 ~ 4 3 ~ 6 4 1 ~ 3 ~ 6 ~ 4",
"2 5 ~ 0 7 ~ 5 2 0 ~ 7 ~ 5 ~ 2 7"
).scale(scalaChorus).transpose(24).apply(melodia).gain(0.4)
let chorusSynth = "<[0,4,6] ~ [2,6,1] ~ [4,1,3] ~ [0,5,7] ~>".scale(scalaChorus).apply(synth)
let chorus = stack(
chorusDrums,
chorusAccordi,
chorusGuitar1,
chorusGuitar2,
chorusBasso,
chorusMelody1,
chorusMelody2,
chorusSynth
).size(8)
// ---------- BREAKDOWN (8 bars): Filtered melodic focus ----------
let breakdownDrums = s("bd ~ ~ ~ ~ ~ ~ ~ bd ~ ~ ~ ~ ~ ~ ~")
.bank('crate')
.gain(0.6)
.lpf(sine.slow(2).range(200, 800))
.segment(8)
let breakdownMelody = "<0 ~ ~ ~ 2 ~ ~ ~ 4 ~ ~ ~ 0 ~ ~ ~>".scale(scalaBreakdown).transpose(12).apply(melodia)
let breakdownGuitar = "<-3 ~ ~ ~ 0 ~ ~ ~ 2 ~ ~ ~ -1 ~ ~ ~>".scale(scalaBreakdown).apply(guitar)
let breakdownBasso = "<-7 ~ ~ ~ -5 ~ ~ ~ -3 ~ ~ ~ -7 ~ ~ ~>".scale(scalaBreakdown).apply(basso)
let breakdown = stack(
breakdownDrums,
breakdownMelody,
breakdownGuitar,
breakdownBasso
).room(0.8).segment(8)
// ---------- OUTRO (4 bars): Melodic resolution ----------
let outroMelody = "<0 2 4 6 4 2 0 ~ ~ ~ ~ ~ ~ ~ ~ ~>".scale(scalaIntro).transpose(12).apply(melodia)
let outroGuitar = "<-3 -1 0 2 0 -1 -3 ~ ~ ~ ~ ~ ~ ~ ~ ~>".scale(scalaIntro).apply(guitar)
let outroDrums = s("bd ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~").bank('crate').gain(0.7).segment(4)
let outro = stack(outroMelody, outroGuitar, outroDrums)
// ---------- Final arrangement ----------
seq([intro, verse, chorus, breakdown, chorus.fast(1.5), outro])
https://tinyurl.com/2xaxupbj
// --- samples ---
await samples({ gtr: 'gtr/0001_cleanC.wav' }, 'github:tidalcycles/Dirt-Samples/master/')
samples('github:eddyflux/crate')
// --- tempo ---
setcpm(25/4) // slow, funky
let swingMask = "<0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1>/16"
let microSwing = 0.02 // subtle shove on offbeats
// --- simple sound wrappers (only Strudel-safe ops) ---
const lead8 = p => p.s("square").gain(0.65).crush(6).lpf(1600).delay(0.25).delayfb(0.25)
const bass8 = p => p.s("square").gain(0.95).lpf(750)
const pad8 = p => p.s("sawtooth").gain(0.35).lpf(1200).room(0.8).size(2)
const gtrStab = p => p.s("gtr").gain(0.45).room(0.6)
const triumphPad = p => p.s("sawtooth").gain(0.5).lpf(800).room(0.9).size(4)
const rand = Math.random
// === KICK: seeded arrays (no .split) ===
const seedKickGrids = [
["bd","~","~","~","bd","~","~","~","bd","~","~","~","bd","~","~","~"],
["bd","~","bd","~","~","bd","~","~","bd","~","~","bd","~","~","~","~"],
["bd","~","~","bd","bd","~","~","~","~","bd","~","~","bd","~","~","~"],
["bd","~","~","~","bd","~","bd","~","~","~","bd","~","bd","~","~","~"]
]
const genKick = (i) => {
let grid = seedKickGrids[i % seedKickGrids.length].slice() // copy
for (let s = 0; s < grid.length; s++){
if (grid[s] === "bd" && rand() < 0.15) grid[s] = "~"
if (grid[s] === "~" && rand() < 0.08) grid[s] = "bd"
}
return grid.join(' ')
}
// === SNARE: backbeat + ghosts ===
const genSnare = (i) => {
let g = Array(16).fill('~')
g[4] = "sd"; g[12] = "sd"
let ghostProb = 0.05 + (i % 4) * 0.03
for (let s = 0; s < 16; s++){
if (g[s] === "~" && rand() < ghostProb) g[s] = (rand() < 0.7 ? "sd" : "~")
}
if (i % 3 === 0 && rand() < 0.5) { // flam-ish extra
let pos = 1 + Math.floor(rand()*14)
g[pos] = "sd"
}
return g.join(' ')
}
// === HATS: evolving density, open/closed mix ===
const genHats = (i) => {
let density = 0.35 + (i % 8) * 0.03
let g = Array(16).fill('~')
for (let s = 0; s < 16; s++){
if (rand() < density) g[s] = (rand() < 0.8 ? "hh" : "oh")
}
return g.join(' ')
}
// === BASS: modal 8-bit line, per-bar variation ===
const bassScale = ['e2','g2','a2','b1','d2','e2','g2','a2']
const genBass = (i) => {
let g = Array(16).fill('~')
let idx = (i * 2) % bassScale.length
;[0,4,7,10,14].forEach((p,k)=> g[p] = bassScale[(idx+k)%bassScale.length])
if (i % 4 === 2) g[2] = bassScale[(idx+5)%bassScale.length]
if (i % 5 === 3) g[8] = bassScale[(idx+3)%bassScale.length]
return g.join(' ')
}
// =====================================================
// INTRO (4 bars): sparse drums + 8-bit lead + guitar
// =====================================================
let introDrums = stack(
s("bd ~ bd ~ bd ~ bd ~ bd ~ bd ~ bd ~ bd ~").bank('crate').gain(1),
s("~ ~ ~ ~ sd ~ ~ ~ ~ ~ ~ ~ sd ~ ~ ~").bank('crate').gain(0.8).late(0.01),
s("~ hh ~ hh ~ hh ~ hh ~ hh ~ hh ~ hh ~ hh").bank('crate')
.gain(0.32).mask(swingMask).late(microSwing).hpf(900)
)
let introLead = lead8(note("e4 ~ g4 ~ b4 ~ ~ ~ d5 ~ b4 ~ g4 ~ ~ ~"))
let introGtr = gtrStab(s("gtr ~ ~ ~ ~ ~ gtr ~ ~ ~ ~ gtr ~ ~ gtr ~"))
let intro = stack(introDrums, introLead, introGtr).segment(4)
// =====================================================
// VERSE (16 bars): evolving drums + bass + pad
// =====================================================
let vKickBars = Array.from({length:16}, (_,i)=> s(genKick(i)).bank('crate').gain(1.05))
let vSnareBars = Array.from({length:16}, (_,i)=> s(genSnare(i)).bank('crate').gain(0.95).late(0.012))
let vHatBars = Array.from({length:16}, (_,i)=> s(genHats(i)).bank('crate')
.gain(0.34).mask(swingMask).late(microSwing).hpf(800))
let vDrumBars = vKickBars.map((_,i)=> stack(vKickBars[i], vSnareBars[i], vHatBars[i]))
let verseDrums = cat(vDrumBars)
let vBassBars = Array.from({length:16}, (_,i)=> bass8(note(genBass(i))))
let verseBass = cat(vBassBars)
let versePad = pad8(
note("[e3 g3 b3] ~ [d3 g3 b3] ~ [a2 e3 a3] ~ [g2 b2 e3] ~").slow(2)
).gain(0.3)
// Add a subtle build-up pad to the verse
let buildUpPad = pad8(note("[e3 g3 b3] [d3 g3 b3] [a2 e3 a3] [g2 b2 e3]"))
.slow(4).gain(0.1).lpf(400).room(0.7)
let verse = stack(verseDrums, verseBass, versePad, buildUpPad).size(8) // 16 bars
// =====================================================
// CHORUS (8 bars): tighter backbeat + hook lead + pads
// =====================================================
let cK = "bd ~ bd ~ bd ~ bd ~ bd ~ bd ~ bd ~ bd ~"
let cS = "~ ~ ~ ~ sd ~ ~ ~ ~ ~ ~ ~ sd ~ ~ ~"
let cHH = "hh ~ hh ~ oh ~ hh ~ hh ~ hh ~ oh ~ hh ~"
let chorusDrums = stack(
s(cK).bank('crate').gain(1.1),
s(cS).bank('crate').gain(1.0).late(0.015),
s(cHH).bank('crate').gain(0.42).mask(swingMask).late(microSwing+0.004).hpf(650)
).segment(8)
let chorusBass = bass8(
note("e2 e2 g2 ~ b1 e2 a2 ~ e2 g2 b1 ~ d2 e2 g2 ~")
).gain(1.0)
let chorusHook = lead8(
note("e4 g4 b4 e5 d5 b4 g4 e4 g4 a4 b4 d5 b4 a4 g4 e4")
).gain(0.9).crush(5)
let chorusPad = pad8(
note("[e3 b3] ~ [a3 e4] ~ [g3 d4] ~ [b3 e4] ~").slow(2)
)
// Add a higher pad for the chorus
let chorusHighPad = triumphPad(note("[e3 b3 e4] [a3 e4 a4] [g3 d4 g4] [b3 e4 b4]")).slow(2)
let chorus = stack(chorusDrums, chorusBass, chorusHook, chorusPad, chorusHighPad).size(4) // 8 bars
// =====================================================
// TRANSITION (4 bars): builds to chorus
// =====================================================
let transition = stack(
s("bd ~ ~ ~ ~ ~ ~ ~ bd ~ ~ ~ ~ ~ ~ ~").bank('crate').gain(0.8),
bass8(note("e2 ~ ~ ~ d2 ~ ~ ~ b1 ~ ~ ~ e2 ~ ~ ~")),
buildUpPad.gain(0.35).lpf(800).room(0.8) // rising pad
).segment(4)
// =====================================================
// BREAKDOWN (4 bars)
// =====================================================
let breakdown = stack(
s("bd ~ ~ ~ ~ ~ ~ ~ bd ~ ~ ~ ~ ~ ~ ~").bank('crate').gain(0.75).lpf(500),
lead8(note("e4 ~ ~ ~ g4 ~ ~ ~ b4 ~ ~ ~ e4 ~ ~ ~")).gain(0.45),
pad8(note("[e3 g3 b3] ~ ~ ~ [a3 e4] ~ ~ ~")).gain(0.25)
).segment(4)
// =====================================================
// CHORUS RETURN (8 bars) & OUTRO (4 bars)
// =====================================================
let chorus2 = chorus
let outro = stack(
gtrStab(s("gtr ~ ~ ~ ~ ~ ~ ~ gtr ~ ~ ~ ~ ~ ~ ~")).gain(0.55),
bass8(note("e2 ~ ~ ~ d2 ~ ~ ~ b1 ~ ~ ~ e2 ~ ~ ~")).gain(0.85),
s("bd ~ ~ ~ ~ ~ ~ ~ bd ~ ~ ~ ~ ~ ~ ~").bank('crate').gain(0.7),
triumphPad(note("[e3 g3 b3 e4]")).slow(4) // sustained triumphant chord
).segment(8) // extended outro
// --- full arrangement ---
seq([intro, verse, transition, chorus, breakdown, chorus2, outro])