npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@synthlet/digital-delay

v0.1.0

Published

A stereo feedback delay with a filtered, saturated feedback path, as an audio worklet

Readme

@synthlet/digital-delay

A stereo feedback delay whose loop filters, diffuses and saturates

Part of Synthlet

Web Audio has a DelayNode, so the delay line itself is solved. What it cannot do is put that line in a loop. The spec allows a cycle in the graph only if the cycle contains a DelayNode, and that node's effective delay is clamped to at least one render quantum — 128 samples, 2.90 ms at 44.1 kHz. Below that floor nothing is expressible: no flanger, no comb resonance, no tight slapback. Above it, a hand-built DelayNode → GainNode → DelayNode loop still gives you a bare scalar in the feedback path — no filter, no saturation, and no say in what happens when you move the delay time while audio is in the line.

This is one worklet with one algorithm, eight continuous parameters and no modes. Every parameter is an AudioParam, so every one is a CV destination.

"Digital" here means only "the one that isn't analog." It is a clean modern delay, not a model of a PCM42 or an SDE-3000 — none of their converters, filters or quirks are simulated. Its defining behaviour is that changing time preserves pitch: the read head hands over to a second head and crossfades rather than gliding. The other half — tape and bucket-brigade, where moving the knob bends pitch because time and bandwidth are physically coupled — is a different instrument with a different parameter surface, and it is @synthlet/analog-delay. If you came here wanting tape echo, that is the one.

Install

npm install @synthlet/digital-delay

Usage

import {
  DigitalDelay,
  registerDigitalDelayWorklet,
} from "@synthlet/digital-delay";

await registerDigitalDelayWorklet(audioContext);

const delay = DigitalDelay(audioContext, {
  time: 0.25, // seconds
  feedback: 0.5,
  mix: 0.3,
  tone: -0.3, // darken each repeat
  cross: 1, // ping-pong
  diffuse: 0.4,
});

source.connect(delay).connect(audioContext.destination);

delay.time.value = (60 / 120) * 0.75; // a dotted eighth at 120 BPM

There is no tempo-sync parameter. time is a number in seconds and an AudioParam: work the beat division out, or drive it from a node. That is the library's own thesis rather than a shortcut.

Parameters

| Param | Default | Min | Max | Rate | Meaning | | ---------- | ------- | ------ | --- | ------ | ----------------------------------------------------------------------------------------------------- | | time | 0.25 | 0.0002 | 2 | k-rate | Delay time in seconds. The range spans flanger (0.2 ms) through comb resonance to a long echo | | feedback | 0.4 | 0 | 1.2 | k-rate | Loop gain. Above 1 is intentional: self-oscillation is a destination, bounded by the limiter | | mix | 0.3 | 0 | 1 | k-rate | Dry/wet | | tone | 0 | −1 | 1 | k-rate | Tilt on the feedback path, not the output. Negative darkens each repeat, positive thins it | | mod | 0 | 0 | 1 | k-rate | Depth of a 0.7 Hz, 3 ms excursion of the read pointer — vibrato, chorus or flange depending on time | | spread | 0 | 0 | 1 | k-rate | L/R time offset as a ratio. 0 is mono-compatible, 1 makes the right line twice the left | | cross | 0 | 0 | 1 | k-rate | Feedback cross-feed. 0 is two independent lines, 1 is full ping-pong | | diffuse | 0 | 0 | 1 | k-rate | Schroeder allpasses in the loop. 0 is discrete repeats, 1 is a wash |

One construction option, maxTime (default 2 s), sizes the buffers. It is not an AudioParam because it allocates: two lines at the default cost about 1 MB.

Four things the table cannot carry:

  • spread and cross are two parameters, not one. They are independent axes — the L/R time relationship and the feedback matrix. Folded into a single "stereo" morph, the midpoint means nothing: at 0.7 you could not tell whether you had offset, cross-feed, or some of each.
  • mod is not an LFO on time. Moving time sets a new target, which hands over to a second read head and preserves pitch by construction. mod moves the pointer within the current head, which bends it. An Lfo into time gives you continuous handovers, not vibrato — a different, and also useful, effect.
  • The feedback path always has three things in it, whatever tone says: the tilt, a high-pass whose corner rises with feedback so sub-bass cannot pile up, and a soft limiter so the loop cannot run away. The last two are stability rather than tone, and they are what make feedback = 1.2 a musical limit cycle instead of a clip.
  • diffuse puts allpasses in the loop, so above 0 the loop is 142 + 379 samples longer than time. At 0 they are bypassed exactly.

Measured quality

Each of these is an assertion in src/dsp.test.ts, with the measured value in a comment beside its threshold.

| What | Measured | | --------------------------------- | ----------------------------------------------------------- | | Feedback below one render quantum | time = 0.001 with feedback = 0.7 combs at 979 Hz | | feedback = 1.2 over 60 s | peak 0.78, still oscillating, no NaN and no denormal stall | | Pitch through a time sweep | median 440.4 Hz where a glide would read 733 Hz | | Clicks on a time sweep | largest step 0.065, against 0.100 with nothing moving | | tone = −1 | repeat centroid 11169 → 556 Hz over five repeats, monotone | | tone = 0 | 1.2% drift over five repeats, from the stability high-pass | | Mono compatibility | L and R are bit-identical at spread = 0, cross = 0 | | cross decay-neutrality | RT60 2.500 – 2.545 s across cross 0 → 1, a spread of 1.8% | | diffuse echo density | 0.0099 → 0.1903 across five settings, monotone, no step |

Attribution

Original, derived from published descriptions:

| What | Citation | | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | | The rotation feedback matrix | Schlecht & Habets, On Lossless Feedback Delay Networks, IEEE TSP 2017 — the N = 2 case of their characterisation | | Hermite fractional reads | Niemitalo, Polynomial Interpolators for High-Quality Resampling of Oversampled Audio, 2001 | | Allpass diffusion | Dattorro, Effect Design Part 1: Reverberator and Other Filters, JAES 1997 | | Feedback high-pass and limiter | Mutable Instruments Clouds (granular_processor.cc) — fc = 20 + 100·feedback², and the cubic x(27 + x²)/(27 + 9x²) | | Delay-line structure | Mutable Instruments stmlib::DelayLine |

See the repository's THIRD-PARTY-LICENSES.md.

License

MIT © danigb