leach.studio

Glass Weather

ambient · drone · elementary
↓ source · seed

about this piece

Five-partial sine bank with light FM, detuned saw shadow, smoothed amp + cutoff. Functional DSP — the algorithm is the patch.

seed
glass-weather-preview
by
stuart
year
2026
tags
ambient · drone · elementary
permalink
/a/glass-weather/glass-weather-preview

source

import 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
← leach.studio