Skip to content

Instantly share code, notes, and snippets.

@marcoonroad
Last active June 10, 2026 01:50
Show Gist options
  • Select an option

  • Save marcoonroad/87605752c9b67c4b09f367774317a3f5 to your computer and use it in GitHub Desktop.

Select an option

Save marcoonroad/87605752c9b67c4b09f367774317a3f5 to your computer and use it in GitHub Desktop.
Angelcore EDM sample of stretched leads made with Strudel REPL
// angelcore sample(s)
const leads = (isUpper) =>
n(
!isUpper ?
`< 61 61 63*2 - 63 65 61*2 - 61*2 - 63 64 - - - 72*2 - >` :
`< - - - 64*2 - - - - - - - - 67 69 71*2 - 73 >`
)
.cpm(135/4)
.fast(6)
const SuperSaw = (beat, option) => {
// NOTE: default built-in supersaw from Strudel has a lot of muddy
// whenever used in pitch bend / legato riffs contexts, so we made
// other custom options for better fine-tuning and control of sound
if (option < 0)
return beat.s("supersaw")
const DEFAULT_OCTAVE = 3
if (option === 0)
return beat.s("saw").layer(
x => x,
x => x.sub(.2),
x => x.add(.2)
).gain(.15).octave(DEFAULT_OCTAVE)
if (option === 1)
return stack(
beat.s("saw").sub(0.0).velocity(0.5),
beat.s("saw").sub(.03).velocity(0.4), beat.s("saw").add(.03).velocity(0.4),
beat.s("saw").sub(.08).velocity(0.3), beat.s("saw").add(.08).velocity(0.3),
beat.s("saw").sub(.14).velocity(0.2), beat.s("saw").add(.14).velocity(0.2),
beat.s("saw").sub(.21).velocity(0.1), beat.s("saw").add(.21).velocity(0.1)
)
.pan(
stack(
sine.range(-0.8, -0.2),
sine.range(0.2, 0.8)
)
)
.gain(.15).octave(DEFAULT_OCTAVE)
const drift = sine.slow(1).range(-2, 2)
if (option === 2)
return beat.s("saw").layer(
x => x.add(0).velocity(0.6),
x => x.sub(drift.add(7).div(100)).velocity(.4),
x => x.add(drift.add(7).div(100)).velocity(.4),
x => x.sub(.12).velocity(.2),
x => x.add(.12).velocity(.2)
)
.gain(0.2).octave(DEFAULT_OCTAVE)
if (option === 3)
return beat.s("saw").layer(
x => x.add(0.0).pan(0.5).velocity(0.5),
x => x.add(.04).pan(0.4).velocity(0.35), x => x.sub(.04).pan(0.6).velocity(0.35),
x => x.add(.16).pan(0.7).velocity(0.25), x => x.sub(.16).pan(0.3).velocity(0.25),
x => x.add(.32).pan(0.2).velocity(0.20), x => x.sub(.32).pan(0.8).velocity(0.20),
x => x.add(.64).pan(0.9).velocity(0.10), x => x.sub(.64).pan(0.1).velocity(0.10)
).gain(0.3).octave(DEFAULT_OCTAVE)
// NOTE: more dense supersaw with sub-square waves
if (option === 4)
return beat.layer(
x => x.s("square").sub(1.00).velocity(.40),
x => x.s("square").sub(3.00).velocity(.30),
x => x.s("square").sub(6.00).velocity(.20),
x => x.s("square").sub(12.0).velocity(.10),
x => x.s("square").sub(18.0).velocity(.05),
x => x.s("saw").add(0.75).velocity(.10),
x => x.s("saw").add(0.50).velocity(.35),
x => x.s("saw").add(0.25).velocity(.60),
x => x.s("saw").add(0.00).velocity(.70),
x => x.s("saw").sub(0.25).velocity(.60),
x => x.s("saw").sub(0.50).velocity(.35),
x => x.s("saw").sub(0.75).velocity(.10),
).gain(.35).octave(DEFAULT_OCTAVE - 1)
const sawCenter = beat.s("saw").add(0.0).velocity(0.50)
const sawPlusLight = beat.s("saw").add(.08).velocity(0.35)
const sawMinusLight = beat.s("saw").sub(.08).velocity(0.35)
const sawPlusWide = beat.s("saw").add(.18).velocity(0.25)
const sawMinusWide = beat.s("saw").sub(.18).velocity(0.25)
if (option === 5)
return stack(
sawCenter,
sawPlusLight, sawMinusLight,
sawPlusWide, sawMinusWide
).gain(0.3).octave(DEFAULT_OCTAVE)
}
const upperLeads = () =>
SuperSaw(leads(1), 4)
.legato(.666)
.penv(1)
.vib(.333)
.room(.333)
.delay(.333)
.chorus(.333)
.lpf(2500)
.hpf(500)
.adsr("0.005:0.15:0.05:0.55")
.color("purple")
const lowerLeads = () =>
leads(0)
.s("square")
.legato(.777)
.add(3) // NOTE: detuning 3 whole semitones to above
.penv(-1)
.chorus(.111)
.room(.111)
.delay(.111)
.vib(.111)
.gain(.666)
.lpf(1200)
.hpf(200)
.adsr("0.005:0.15:0.05:0.65")
.color("green")
// NOTE: different orbits due differents reverbs/delays
$: upperLeads().orbit(1)._punchcard()
$: lowerLeads().orbit(2)._punchcard()
// creating angelcore-like lead from synth brass instrument
// - unison detuning (with stereo knob/spread) and chorus
// - higher pitches/octaves
// - low brightness (low-pass / cutoff)
// - bitcrushing/low-sample-rate and soft distortion
// - small cents/semitones pitch bend down
// - dynamic compression
// - delay/echo and reverberation
$: note("<- d3 - <c3 e3*2> - d3 - c3@2 b2 d3@2>".fast(12))
.sound("gm_synth_brass_2")
.layer(
x => x.add(0.21).velocity(0.25).pan(0.8),
x => x.add(0.09).velocity(0.30).pan(0.2),
x => x.add(0.03).velocity(0.35).pan(0.8),
x => x.add(0.00).velocity(0.40).pan(0.5),
x => x.sub(0.03).velocity(0.35).pan(0.2),
x => x.sub(0.09).velocity(0.30).pan(0.8),
x => x.sub(0.21).velocity(0.25).pan(0.2)
)
.coarse(2)
// .crush(12)
.soft("2:0.5")
.transpose(18)
.legato(0.5)
.penv(-0.25)
.gain(0.1)
.cutoff(1000)
.resonance(5)
.chorus(0.5)
.every(3, rev)
.delay(0.2)
.room(0.1)
.compressor("-25:5:5:0.005:0.25")
.orbit(3)
.postgain(0.75)
.adsr("0.005:0.2:0.15:0.25")
.cps(90/60/4)
._pianoroll()
@marcoonroad

Copy link
Copy Markdown
Author

NOTE: only works on recent engines of Strudel where both .add() and .sub() (and even .transpose()) support microtonal (cents) semitones, e.g 20 cents being 0.2 semitones. Older versions, and some VSCode plugins included, doesn't handle that well and instead round to closest/nearest integer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment