Five-partial sine bank with light FM, detuned saw shadow, smoothed amp + cutoff. Functional DSP — the algorithm is the patch.
glass-weather-previewimport type { ElementaryPatch } from '@/lib/engine/types'
const glassWeather: ElementaryPatch = {
id: 'glass-weather',
title: 'Glass Weather',
author: 'stuart',
year: 2026,
tags: ['ambient', 'drone', 'elementary'],
description:
'Five-partial sine bank with light FM, detuned saw shadow, smoothed amp + cutoff. Functional DSP — the algorithm is the patch.',
engine: 'elementary',
audio: ({ el, rng, schedule, render }) => {
const notes = [220, 261.63, 329.63, 369.99, 440, 523.25, 587.33]
const interval = 4 // faster — chord change every 4s
schedule(interval, (tick) => {
const note = rng.pick(notes, tick, 0)
const amp = rng.range(0.18, 0.4, tick, 1)
const cutoff = rng.range(900, 2400, tick, 2)
const detuneCents = rng.range(-8, 8, tick, 3)
const detune = Math.pow(2, detuneCents / 1200)
const fmDepth = rng.range(2, 8, tick, 4)
// FM modulator on the fundamental
const modFreq = note / 7
const mod = el.mul(
el.cycle(el.const({ key: 'modOsc', value: modFreq })),
el.const({ key: 'modAmt', value: fmDepth }),
)
const fundFreq = el.add(el.const({ key: 'fund', value: note }), mod)
// Five partials, each detuned differently
const fund = el.cycle(fundFreq)
const p2 = el.mul(
el.cycle(el.const({ key: 'p2', value: note * 2 * detune })),
0.5,
)
const p3 = el.mul(
el.cycle(el.const({ key: 'p3', value: note * 3 })),
0.28,
)
const p4 = el.mul(
el.cycle(el.const({ key: 'p4', value: note * 4 * detune })),
0.16,
)
const p5 = el.mul(
el.cycle(el.const({ key: 'p5', value: note * 5 })),
0.09,
)
const partials = el.add(fund, p2, p3, p4, p5)
// Saw shadow at fundamental for body
const sawShadow = el.mul(
el.saw(el.const({ key: 'sw', value: note })),
0.12,
)
const voice = el.add(partials, sawShadow)
const envAmp = el.smooth(
el.tau2pole(1.0),
el.const({ key: 'amp', value: amp }),
)
const cutSm = el.smooth(
el.tau2pole(0.7),
el.const({ key: 'cut', value: cutoff }),
)
const filtered = el.lowpass(cutSm, 0.7, el.mul(voice, envAmp))
const out = el.mul(el.tanh(el.mul(filtered, 0.5)), 0.2)
render(out, out)
})
},
}
export default glassWeather