@thi.ng/dsp v4.7.66
This project is part of the @thi.ng/umbrella monorepo.
About
Composable signal generators, oscillators, filters, FFT, spectrum, windowing & related DSP utils.
Partially ported from other thi.ng projects (e.g. thi.ng/synstack, thi.ng/vexed-generation, toxiclibs).
Status
STABLE - used in production
Search or submit any issues for this package
Even though this library is now at v2.0.0 and still retains most of the features from earlier versions, all recently added features (IGen's, IProc's, composition ops etc.) should be considered "beta" and are likely to undergo further (hopefully not too drastic) changes in the near future. Also, pending outcomes of ongoing experiments, some aspects might be ported to WASM.
Support packages
- @thi.ng/dsp-io-wav - WAV file format generation
Related packages
- @thi.ng/math - Assorted common math functions & utilities
Installation
yarn add @thi.ng/dsp
ES module import:
<script type="module" src="https://cdn.skypack.dev/@thi.ng/dsp"></script>
For Node.js REPL:
# with flag only for < v16
node --experimental-repl-await
> const dsp = await import("@thi.ng/dsp");
Package sizes (gzipped, pre-treeshake): ESM: 7.17 KB
Dependencies
Usage examples
Several demos in this repo's /examples directory are using this package.
A selection:
Screenshot | Description | Live demo | Source |
---|---|---|---|
Interactive inverse FFT toy synth | Demo | Source | |
Polygon to cubic curve conversion & visualization | Demo | Source | |
WebGL cube maps with async texture loading | Demo | Source | |
WebGL screenspace ambient occlusion | Demo | Source |
API
IGen
The following unit generators are infinite data sources based on the
IGen
interface
with most being resettable too. The interface is similar to ES6
iterators in that the next value can be obtained by calling .next()
,
however since IGen
s are always infinite, there's no need to wrap the
result
value
as is done with ES6 iterables. Furthermore, all gens defined in this
package do implement Symbol.iterator
and so can actually be used as
standard iterables as well.
IGen
also implements the
IDeref
interface to obtain the gen's current (last generated) value.
// create exponential curve from 0 - 10 over 5 steps
const c = curve(0, 10, 5);
// get next value
c.next()
// 0
c.next()
// 6.087111442696312
c.next()
// 8.505616378877338
c.next()
// 9.46652635750935
c.next()
// 9.848310977098592
c.next()
// 9.999999999999998
// get current value
c.deref()
// 9.999999999999998
// reset gen
c.reset()
// produce an array (can also write into existing buffer)
c.take(6)
// [
// 0,
// 6.087111442696312,
// 8.505616378877338,
// 9.46652635750935,
// 9.848310977098592,
// 9.999999999999998
// ]
// use as ES6 iterable, here w/ transducers
import { take } from "@thi.ng/transducers";
[...take(6, c.reset())]
// [
// 0,
// 6.087111442696312,
// 8.505616378877338,
// 9.46652635750935,
// 9.848310977098592,
// 9.999999999999998
// ]
- add - adder
- adsr - timebased ADSR / AD envelope generator
- alt - alternating values
- constant - constant value
- cosine - trig-free cosine osc
- curve - timebased exponential gain/decay (factory for
madd
) - impulse - impulse gen
- impulseTrain - timebased cyclic impulse
- line - timebased line gen (factory for
add
) - madd - multiply-adder
- mul - multiplier (exponential gain/decay)
- pinkNoise - configurable pink noise (1/f power spectrum)
- reciprocal - fractional sequence (1, 1/2, 1/3, 1/4 etc.)
- sincos - trig-free sin/cos LFO
- sweep - freq sweep gen w/ phase accumulation for oscillators
- whiteNoise - white noise
Higher order generators
- mapG -
IGen
composition / transformation (1-4 inputs) - addG - higher-order adder
- product - product of input gens
- sum - sum of input gens
Oscillators
IGen wrappers
const FS = 44100;
// simple 100Hz sine oscillator
const o = osc(sin, 100 / FS, 0.5);
// get next sample
o.next();
...
// frequency & amplitude modulated saw osc
const fmam = modOsc(
// carrier waveform
saw,
// carrier freq
1000 / FS,
// fmod
osc(saw, 5000 / FS, 0.3),
// amod
osc(saw, 500 / FS)
);
// compute 1sec of signal
fmam.take(FS)
Diagram of the FM/AM osc with some low pass filters applied:
Stateless oscillator functions
IProc
The second fundamental interface in this package, similar to IGen
and
used to implement processors & transformers of input values (e.g those
generated by the various IGen
s available). IProc
implementations have a
.next(x)
method, where x
is the next input to be processed.
The package also provides several approaches to compose multi-step
processing pipelines (see section further below). Furthermore, all
implementations in this package implement the @thi.ng/transducers
IXform
interface
and so can be directly used in transducer pipelines too.
import { comp, push, take, transduce } from "@thi.ng/transducers";
const FS = 48000; // sample rate
const F1 = 1 / FS; // start freq
const F2 = 10000 / FS; // end freq
// generate oscillator sweep with some effects applied
const sig = new Float32Array(
transduce(
comp(
// consume 8 secs worth of samples
take(8 * FS),
// lowpass filter (state variable filter)
svfLP(F2),
// soft clip
waveShaper(4),
// 0.5sec delay w/ 60% feedback
feedbackDelay(0.5 * FS, 0.6)
),
// reducer: collect as array
push(),
// oscillator (consumed as ES6 iterable)
osc(
// osc function (use only 3 harmonics)
sawAdditive(3),
// freq sweep F1 -> F2 over 6 sec
sweep(F1, F2, 6 * FS),
// envelope (using attack & decay phase only)
adsr({ a: 0.05 * FS, d: 5.95 * FS, s: 0 })
)
)
);
fs.writeFileSync("sig.raw", Buffer.from(sig.buffer));
The raw audio file can then be converted to WAV via ffmpeg
:
ffmpeg -f f32le -ar 48k -ac 1 -i sig.raw sig.wav -y
Filters
The following diagrams show various combinations of oscillator signals and their filtered responses (with different cutoff/center frequencies).
All diagrams were generated with this script.
The following filter types / functions are available:
1-pole
onepoleLP
- low pass, 6dB/oct falloffdcBlock
- high pass, 6dB/oct falloffallpass
- allpass (-90° phase shift @ center freq)
Low pass:
DC blocker:
Allpass:
Biquad
biquadLP
- low pass, 12dB/oct falloff, resonancebiquadHP
- high pass, 12dB/oct falloff, resonancebiquadBP
- band pass, 12dB/oct falloff, resonancebiquadNotch
- notch / band-stop, resonance/bandwidthbiquadPeak
- peak EQ, customizable +/- gain, bandwidthbiquadLoShelf
- low shelf, customizable +/- gainbiquadHiShelf
- low shelf, customizable +/- gain
(Q = 0.707 for all versions)
Low pass:
High pass:
Band pass:
Notch:
Peak (gain = 6dB):
Low shelf (gain = -6dB):
High shelf (gain = -6dB):
State variable filter
svfLP
- low pass, resonancesvfHP
- high pass, resonancesvfBP
- band pass, resonancesvfNotch
- notch / band-stop, resonance/bandwidthsvfPeak
- peak EQ, customizable +/- gain, bandwidthsvfAllpass
- allpass, bandwidth
(Q = 0.5 for all versions)
Low pass:
High pass:
Band pass:
Notch:
Peak (gain = 6dB):
Allpass:
Filter responses
Using the Filter response
utils,
the following filter types can be evaluated for analyzing their impact
on specific frequencies (or frequency bands). Any type implementing
IFilter
can be used, currently:
- 1-pole
- DC-block
- Biquad
// peak biquad @ 5kHz w/ -60dB gain
const coeffs = biquadPeak(5000 / FS, 10, -60).filterCoeffs();
// {
// zeroes: [ 0.030659922512760035, -0.04493872132576855, 0.028719301737009807 ],
// poles: [ 1, -0.04493872132576855, -0.94062077575023 ]
// }
// compute 256 filter responses between 0 - nyquist
// (magnitude in dBFS by default, phase shift in radians)
const resp = freqRange(0, 0.5, 256).map((f) => filterResponse(coeffs, f));
// [
// { freq: 0, phase: 0, mag: -9.836140158843584e-14 },
// {
// freq: 0.00196078431372549,
// phase: -1.025916720326544,
// mag: -5.731888923801755
// },
// {
// freq: 0.00392156862745098,
// phase: -1.27451127560192,
// mag: -10.788101434823263
// },
// ...
// ]
Basic filter response plot:
Delay
Ringbuffer / delay line for arbitrary values and support for single & multi-taps at any relative positions. Useful fundamental building block for various other effects, filters etc.
Feedback delay
Variation of delay()
which adds a portion of the delayed value to each
new input and stores result in delay line.
Wave shaping
This operator remaps inputs via a user provided function. The following shaping functions are provided:
waveshapeTan
- arctan based (soft-clip/distortion)waveshapeSigmoid
- sigmoid based, similar to abovewaveshapeSin
- depending on coefficient, can produce entirely new waveforms
Use the interactive calculator @ Desmos to experiment.
Acrtan:
Sigmoid:
Sine:
Foldback distortion
Recursively folds input into [-thresh .. +thresh]
interval and amplifies it with amp
(default: 1/thresh).
Use the interactive calculator @ Desmos to experiment.
FFT
fft()
ifft()
normalizeFFT()
denormalizeFFT()
scaleFFT()
complexArray()
conjugate()
powerSumSquared()
powerMeanSquared()
powerTimeIntegral()
spectrumMag()
spectrumPow()
(optionally as dBFS)spectrumPhase()
binFreq()
freqBin()
fftFreq()
integralT()
/integralTSquared()
integralF()
/integralFSquared()
Window functions
window()
applyWindow()
windowRect()
windowBartlett()
windowWelch()
windowSin()
windowSinPow()
windowLanczos()
windowHann()
windowHamming()
windowBlackman()
windowBlackmanHarris()
windowNuttal()
windowBlackmanNuttal()
windowGauss()
Utilities
Authors
Karsten Schmidt
If this project contributes to an academic publication, please cite it as:
@misc{thing-dsp,
title = "@thi.ng/dsp",
author = "Karsten Schmidt",
note = "https://thi.ng/dsp",
year = 2015
}
License
© 2015 - 2021 Karsten Schmidt // Apache Software License 2.0
3 months ago
4 months ago
4 months ago
4 months ago
5 months ago
5 months ago
4 months ago
5 months ago
5 months ago
5 months ago
5 months ago
6 months ago
6 months ago
7 months ago
7 months ago
8 months ago
12 months ago
12 months ago
11 months ago
11 months ago
12 months ago
11 months ago
8 months ago
10 months ago
10 months ago
11 months ago
10 months ago
9 months ago
10 months ago
10 months ago
8 months ago
9 months ago
9 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago