@thi.ng/dsp 4.6.16 → 4.6.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +1 -1
  3. package/add.js +24 -38
  4. package/addg.js +4 -19
  5. package/adsr.js +148 -156
  6. package/agen.js +17 -21
  7. package/allpass.js +37 -38
  8. package/alt.js +26 -22
  9. package/anti-alias.js +8 -37
  10. package/api.js +0 -1
  11. package/aproc.js +24 -30
  12. package/biquad.js +188 -184
  13. package/bounce.js +15 -16
  14. package/complex.js +4 -1
  15. package/const.js +12 -13
  16. package/convert.js +18 -64
  17. package/cosine.js +43 -48
  18. package/curve.js +12 -41
  19. package/dcblock.js +9 -10
  20. package/delay.js +100 -111
  21. package/feedback-delay.js +23 -30
  22. package/fft.js +188 -334
  23. package/filter-delay.js +23 -27
  24. package/filter-response.js +22 -33
  25. package/foldback.js +26 -35
  26. package/impulse-train.js +35 -37
  27. package/impulse.js +27 -42
  28. package/integrator.js +27 -32
  29. package/internal/ensure.js +4 -1
  30. package/internal/take.js +8 -5
  31. package/iterable.js +32 -43
  32. package/line.js +10 -25
  33. package/madd.js +25 -40
  34. package/mapg.js +77 -69
  35. package/merge.js +18 -20
  36. package/mix.js +20 -16
  37. package/mul.js +24 -38
  38. package/multiplex.js +15 -11
  39. package/onepole.js +41 -42
  40. package/osc-additive.js +25 -53
  41. package/osc-cos.js +4 -1
  42. package/osc-dsf.js +15 -52
  43. package/osc-mix.js +6 -20
  44. package/osc-parabolic.js +4 -13
  45. package/osc-rect.js +6 -8
  46. package/osc-saw.js +4 -1
  47. package/osc-sin.js +4 -1
  48. package/osc-tri.js +4 -1
  49. package/osc-wavetable.js +12 -9
  50. package/osc.js +40 -74
  51. package/package.json +13 -10
  52. package/pan.js +23 -29
  53. package/pink-noise.js +35 -57
  54. package/pipe.js +6 -4
  55. package/power.js +40 -96
  56. package/product.js +5 -4
  57. package/reciprocal.js +20 -22
  58. package/ref.js +24 -20
  59. package/serial.js +59 -60
  60. package/sincos.js +45 -61
  61. package/sum.js +5 -4
  62. package/svf.js +74 -78
  63. package/sweep.js +4 -27
  64. package/waveshaper.js +41 -60
  65. package/white-noise.js +17 -23
  66. package/window.js +67 -52
package/serial.js CHANGED
@@ -1,66 +1,65 @@
1
1
  import { AProc } from "./aproc.js";
2
- export function serial(...procs) {
3
- const [a, b, c, d] = procs;
4
- switch (procs.length) {
5
- case 2:
6
- return new Serial2(a, b);
7
- case 3:
8
- return new Serial3(a, b, c);
9
- case 4:
10
- return new Serial4(a, b, c, d);
11
- default:
12
- return new Serial(procs);
13
- }
2
+ function serial(...procs) {
3
+ const [a, b, c, d] = procs;
4
+ switch (procs.length) {
5
+ case 2:
6
+ return new Serial2(a, b);
7
+ case 3:
8
+ return new Serial3(a, b, c);
9
+ case 4:
10
+ return new Serial4(a, b, c, d);
11
+ default:
12
+ return new Serial(procs);
13
+ }
14
14
  }
15
- export class Serial2 extends AProc {
16
- _a;
17
- _b;
18
- constructor(_a, _b) {
19
- super(null);
20
- this._a = _a;
21
- this._b = _b;
22
- }
23
- next(x) {
24
- return (this._val = this._b.next(this._a.next(x)));
25
- }
15
+ class Serial2 extends AProc {
16
+ constructor(_a, _b) {
17
+ super(null);
18
+ this._a = _a;
19
+ this._b = _b;
20
+ }
21
+ next(x) {
22
+ return this._val = this._b.next(this._a.next(x));
23
+ }
26
24
  }
27
- export class Serial3 extends AProc {
28
- _a;
29
- _b;
30
- _c;
31
- constructor(_a, _b, _c) {
32
- super(null);
33
- this._a = _a;
34
- this._b = _b;
35
- this._c = _c;
36
- }
37
- next(x) {
38
- return (this._val = this._c.next(this._b.next(this._a.next(x))));
39
- }
25
+ class Serial3 extends AProc {
26
+ constructor(_a, _b, _c) {
27
+ super(null);
28
+ this._a = _a;
29
+ this._b = _b;
30
+ this._c = _c;
31
+ }
32
+ next(x) {
33
+ return this._val = this._c.next(this._b.next(this._a.next(x)));
34
+ }
40
35
  }
41
- export class Serial4 extends AProc {
42
- _a;
43
- _b;
44
- _c;
45
- _d;
46
- constructor(_a, _b, _c, _d) {
47
- super(null);
48
- this._a = _a;
49
- this._b = _b;
50
- this._c = _c;
51
- this._d = _d;
52
- }
53
- next(x) {
54
- return (this._val = this._d.next(this._c.next(this._b.next(this._a.next(x)))));
55
- }
36
+ class Serial4 extends AProc {
37
+ constructor(_a, _b, _c, _d) {
38
+ super(null);
39
+ this._a = _a;
40
+ this._b = _b;
41
+ this._c = _c;
42
+ this._d = _d;
43
+ }
44
+ next(x) {
45
+ return this._val = this._d.next(
46
+ this._c.next(this._b.next(this._a.next(x)))
47
+ );
48
+ }
56
49
  }
57
- export class Serial extends AProc {
58
- _procs;
59
- constructor(_procs) {
60
- super(null);
61
- this._procs = _procs;
62
- }
63
- next(x) {
64
- return (this._val = this._procs.reduce((x, p) => p.next(x), x));
65
- }
50
+ class Serial extends AProc {
51
+ constructor(_procs) {
52
+ super(null);
53
+ this._procs = _procs;
54
+ }
55
+ next(x) {
56
+ return this._val = this._procs.reduce((x2, p) => p.next(x2), x);
57
+ }
66
58
  }
59
+ export {
60
+ Serial,
61
+ Serial2,
62
+ Serial3,
63
+ Serial4,
64
+ serial
65
+ };
package/sincos.js CHANGED
@@ -1,64 +1,48 @@
1
1
  import { TAU } from "@thi.ng/math/api";
2
2
  import { AGen } from "./agen.js";
3
- /**
4
- * Generator of sine & cosine values of given frequency in the form of
5
- * [sin,cos] tuples. Start phase always zero.
6
- *
7
- * @remarks
8
- * Implementation based on a self-oscillating SVF (state-variable
9
- * filter) without using any trig functions. Therefore, ~30% faster, but
10
- * precision only useful for very low (< ~2Hz) frequencies. Due to
11
- * floating point error accumulation, phase & amplitude drift will occur
12
- * for higher frequencies.
13
- *
14
- * References:
15
- * - http://www.earlevel.com/main/2003/03/02/the-digital-state-variable-filter/
16
- *
17
- * @param freq - normalized freq
18
- * @param amp - amplitude (default: 1)
19
- */
20
- export class SinCos extends AGen {
21
- _freq;
22
- _amp;
23
- _f;
24
- _s;
25
- _c;
26
- constructor(_freq, _amp = 1) {
27
- super([0, _amp]);
28
- this._freq = _freq;
29
- this._amp = _amp;
30
- this.calcCoeffs();
31
- }
32
- copy() {
33
- return new SinCos(this._freq, this._amp);
34
- }
35
- reset() {
36
- this.calcCoeffs();
37
- return this;
38
- }
39
- next() {
40
- this._val = [this._s, this._c];
41
- this._s += this._f * this._c;
42
- this._c -= this._f * this._s;
43
- return this._val;
44
- }
45
- freq() {
46
- return this._freq;
47
- }
48
- setFreq(freq) {
49
- this._freq = freq;
50
- this.calcCoeffs();
51
- }
52
- amp() {
53
- return this._amp;
54
- }
55
- setAmp(amp) {
56
- this._amp = amp;
57
- this.calcCoeffs();
58
- }
59
- calcCoeffs() {
60
- this._f = TAU * this._freq;
61
- this._s = 0;
62
- this._c = this._amp;
63
- }
3
+ class SinCos extends AGen {
4
+ constructor(_freq, _amp = 1) {
5
+ super([0, _amp]);
6
+ this._freq = _freq;
7
+ this._amp = _amp;
8
+ this.calcCoeffs();
9
+ }
10
+ _f;
11
+ _s;
12
+ _c;
13
+ copy() {
14
+ return new SinCos(this._freq, this._amp);
15
+ }
16
+ reset() {
17
+ this.calcCoeffs();
18
+ return this;
19
+ }
20
+ next() {
21
+ this._val = [this._s, this._c];
22
+ this._s += this._f * this._c;
23
+ this._c -= this._f * this._s;
24
+ return this._val;
25
+ }
26
+ freq() {
27
+ return this._freq;
28
+ }
29
+ setFreq(freq) {
30
+ this._freq = freq;
31
+ this.calcCoeffs();
32
+ }
33
+ amp() {
34
+ return this._amp;
35
+ }
36
+ setAmp(amp) {
37
+ this._amp = amp;
38
+ this.calcCoeffs();
39
+ }
40
+ calcCoeffs() {
41
+ this._f = TAU * this._freq;
42
+ this._s = 0;
43
+ this._c = this._amp;
44
+ }
64
45
  }
46
+ export {
47
+ SinCos
48
+ };
package/sum.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { MapG2, MapG3 } from "./mapg.js";
2
- export function sum(a, b, c) {
3
- return c
4
- ? new MapG3((a, b, c) => a + b + c, a, b, c, 0)
5
- : new MapG2((a, b) => a + b, a, b, 0);
2
+ function sum(a, b, c) {
3
+ return c ? new MapG3((a2, b2, c2) => a2 + b2 + c2, a, b, c, 0) : new MapG2((a2, b2) => a2 + b2, a, b, 0);
6
4
  }
5
+ export {
6
+ sum
7
+ };
package/svf.js CHANGED
@@ -1,83 +1,79 @@
1
1
  import { PI } from "@thi.ng/math/api";
2
2
  import { clamp05 } from "@thi.ng/math/interval";
3
3
  import { AProc } from "./aproc.js";
4
- export const svfLP = (fc, q) => new SVF("lp", fc, q);
5
- export const svfHP = (fc, q) => new SVF("hp", fc, q);
6
- export const svfBP = (fc, q) => new SVF("bp", fc, q);
7
- export const svfNotch = (fc, q) => new SVF("notch", fc, q);
8
- export const svfPeak = (fc, q) => new SVF("peak", fc, q);
9
- export const svfAllpass = (fc, q) => new SVF("all", fc, q);
10
- /**
11
- * Multi-type state variable filter w/ trapezoidal integration, after
12
- * Andrew Simper.
13
- *
14
- * Reference:
15
- *
16
- * - https://cytomic.com/files/dsp/SvfLinearTrapOptimised2.pdf
17
- * - https://en.wikipedia.org/wiki/Trapezoidal_rule
18
- */
19
- export class SVF extends AProc {
20
- _type;
21
- _freq;
22
- _q;
23
- _a1;
24
- _a2;
25
- _c1;
26
- _c2;
27
- _g;
28
- _k;
29
- constructor(_type, _freq, _q = 0.5) {
30
- super(0);
31
- this._type = _type;
32
- this._freq = _freq;
33
- this._q = _q;
34
- this.reset();
35
- this.computeCoeffs();
36
- }
37
- reset() {
38
- this._c1 = this._c2 = this._val = 0;
39
- return this;
40
- }
41
- next(x) {
42
- const { _c1, _c2 } = this;
43
- const x1 = this._a1 * _c1 + this._a2 * (x - _c2);
44
- const x2 = _c2 + this._g * x1;
45
- this._c1 = 2 * x1 - _c1;
46
- this._c2 = 2 * x2 - _c2;
47
- // TODO support type morphing / interpolation?
48
- switch (this._type) {
49
- case "lp":
50
- return (this._val = x2);
51
- case "hp":
52
- return (this._val = x - this._k * x1 - x2);
53
- case "bp":
54
- return (this._val = x1);
55
- case "notch":
56
- return (this._val = x - this._k * x1);
57
- case "peak":
58
- return (this._val = 2 * x2 - x + this._k * x1);
59
- case "all":
60
- return (this._val = x - 2 * this._k * x1);
61
- }
62
- }
63
- set(fc, q) {
64
- this._freq = fc;
65
- this._q = q;
66
- this.computeCoeffs();
67
- }
68
- setFreq(fc) {
69
- this._freq = fc;
70
- this.computeCoeffs();
71
- }
72
- setQ(q) {
73
- this._q = q;
74
- this.computeCoeffs();
75
- }
76
- computeCoeffs() {
77
- this._freq = clamp05(this._freq);
78
- const g = (this._g = Math.tan(PI * this._freq));
79
- this._k = 2 - 2 * this._q;
80
- this._a1 = 1 / (1 + g * (g + this._k));
81
- this._a2 = g * this._a1;
4
+ const svfLP = (fc, q) => new SVF("lp", fc, q);
5
+ const svfHP = (fc, q) => new SVF("hp", fc, q);
6
+ const svfBP = (fc, q) => new SVF("bp", fc, q);
7
+ const svfNotch = (fc, q) => new SVF("notch", fc, q);
8
+ const svfPeak = (fc, q) => new SVF("peak", fc, q);
9
+ const svfAllpass = (fc, q) => new SVF("all", fc, q);
10
+ class SVF extends AProc {
11
+ constructor(_type, _freq, _q = 0.5) {
12
+ super(0);
13
+ this._type = _type;
14
+ this._freq = _freq;
15
+ this._q = _q;
16
+ this.reset();
17
+ this.computeCoeffs();
18
+ }
19
+ _a1;
20
+ _a2;
21
+ _c1;
22
+ _c2;
23
+ _g;
24
+ _k;
25
+ reset() {
26
+ this._c1 = this._c2 = this._val = 0;
27
+ return this;
28
+ }
29
+ next(x) {
30
+ const { _c1, _c2 } = this;
31
+ const x1 = this._a1 * _c1 + this._a2 * (x - _c2);
32
+ const x2 = _c2 + this._g * x1;
33
+ this._c1 = 2 * x1 - _c1;
34
+ this._c2 = 2 * x2 - _c2;
35
+ switch (this._type) {
36
+ case "lp":
37
+ return this._val = x2;
38
+ case "hp":
39
+ return this._val = x - this._k * x1 - x2;
40
+ case "bp":
41
+ return this._val = x1;
42
+ case "notch":
43
+ return this._val = x - this._k * x1;
44
+ case "peak":
45
+ return this._val = 2 * x2 - x + this._k * x1;
46
+ case "all":
47
+ return this._val = x - 2 * this._k * x1;
82
48
  }
49
+ }
50
+ set(fc, q) {
51
+ this._freq = fc;
52
+ this._q = q;
53
+ this.computeCoeffs();
54
+ }
55
+ setFreq(fc) {
56
+ this._freq = fc;
57
+ this.computeCoeffs();
58
+ }
59
+ setQ(q) {
60
+ this._q = q;
61
+ this.computeCoeffs();
62
+ }
63
+ computeCoeffs() {
64
+ this._freq = clamp05(this._freq);
65
+ const g = this._g = Math.tan(PI * this._freq);
66
+ this._k = 2 - 2 * this._q;
67
+ this._a1 = 1 / (1 + g * (g + this._k));
68
+ this._a2 = g * this._a1;
69
+ }
83
70
  }
71
+ export {
72
+ SVF,
73
+ svfAllpass,
74
+ svfBP,
75
+ svfHP,
76
+ svfLP,
77
+ svfNotch,
78
+ svfPeak
79
+ };
package/sweep.js CHANGED
@@ -1,29 +1,6 @@
1
1
  import { addG } from "./addg.js";
2
2
  import { curve } from "./curve.js";
3
- /**
4
- * Similar to {@link curve}, but with added accumulation (via
5
- * {@link addG}). Systax sugar for `addg(curve(...))` and intended for
6
- * creating oscillator frequency sweeps. By default, the sweep speed is
7
- * clamped at the given `end` value.
8
- *
9
- * @example
10
- * ```ts
11
- * // render 2 sec osc sweep from 100 - 10000Hz
12
- * // FS = 44100
13
- * osc(
14
- * sin,
15
- * // freq & phase gen
16
- * sweep(100 / FS, 10000 / FS, 2 * FS, 0.1),
17
- * // amplitude gen / envelope
18
- * adsr(0.5 * FS, 1.5 * FS, 0)
19
- * ).take(2 * fs)
20
- * // [...]
21
- * ```
22
- *
23
- * @param start -
24
- * @param end -
25
- * @param steps -
26
- * @param rate -
27
- * @param clamp - true, if clamp at `end` value
28
- */
29
- export const sweep = (start, end, steps, rate, clamp = true) => addG(curve(start, end, steps, rate, false, clamp));
3
+ const sweep = (start, end, steps, rate, clamp = true) => addG(curve(start, end, steps, rate, false, clamp));
4
+ export {
5
+ sweep
6
+ };
package/waveshaper.js CHANGED
@@ -1,63 +1,44 @@
1
1
  import { PI } from "@thi.ng/math/api";
2
2
  import { AProc } from "./aproc.js";
3
- /**
4
- * Customizable wave shaper for user defined shaping function supporting
5
- * one (optional, implementation specific) adjustable curve parameter.
6
- * By default uses {@link waveshapeTan} and supports configurable
7
- * curvature. Post-amplification is applied to the transformed result
8
- * value (see remarks).
9
- *
10
- * @remarks
11
- * If `amp` is `true` (default), the curve will be normalized such that
12
- * input values in the [-1 .. 1] range will be mapped to the same output
13
- * interval.
14
- *
15
- * The following wave shaping functions are supplied by default:
16
- *
17
- * - {@link waveshapeTan}
18
- * - {@link waveshapeSigmoid}
19
- * - {@link waveshapeSin}
20
- *
21
- * Interactive graph:
22
- * - https://www.desmos.com/calculator/hg4i7o836i
23
- *
24
- * @param thresh - fold threshold
25
- * @param amp - post amplifier / autogain flag
26
- */
27
- export const waveShaper = (thresh, amp, map) => new WaveShaper(thresh, amp, map);
28
- export class WaveShaper extends AProc {
29
- _coeff;
30
- _map;
31
- _amp;
32
- _autoGain;
33
- constructor(_coeff = 3, amp = true, _map = waveshapeSigmoid) {
34
- super(0);
35
- this._coeff = _coeff;
36
- this._map = _map;
37
- amp === true ? this.setAutoGain() : this.setAmp(amp);
38
- }
39
- next(x) {
40
- return (this._val = this._amp * this._map(x, this._coeff));
41
- }
42
- coeff() {
43
- return this._coeff;
44
- }
45
- setCoeff(t) {
46
- this._coeff = Math.max(t, 0);
47
- this._autoGain && this.setAutoGain();
48
- }
49
- amp() {
50
- return this._amp;
51
- }
52
- setAmp(a) {
53
- this._amp = a;
54
- this._autoGain = false;
55
- }
56
- setAutoGain() {
57
- this._amp = 1 / this._map(1, this._coeff);
58
- this._autoGain = true;
59
- }
3
+ const waveShaper = (thresh, amp, map) => new WaveShaper(thresh, amp, map);
4
+ class WaveShaper extends AProc {
5
+ constructor(_coeff = 3, amp = true, _map = waveshapeSigmoid) {
6
+ super(0);
7
+ this._coeff = _coeff;
8
+ this._map = _map;
9
+ amp === true ? this.setAutoGain() : this.setAmp(amp);
10
+ }
11
+ _amp;
12
+ _autoGain;
13
+ next(x) {
14
+ return this._val = this._amp * this._map(x, this._coeff);
15
+ }
16
+ coeff() {
17
+ return this._coeff;
18
+ }
19
+ setCoeff(t) {
20
+ this._coeff = Math.max(t, 0);
21
+ this._autoGain && this.setAutoGain();
22
+ }
23
+ amp() {
24
+ return this._amp;
25
+ }
26
+ setAmp(a) {
27
+ this._amp = a;
28
+ this._autoGain = false;
29
+ }
30
+ setAutoGain() {
31
+ this._amp = 1 / this._map(1, this._coeff);
32
+ this._autoGain = true;
33
+ }
60
34
  }
61
- export const waveshapeTan = (x, k) => Math.atan(k * x) / k;
62
- export const waveshapeSigmoid = (x, k) => 2 / (1 + Math.exp(-k * x)) - 1;
63
- export const waveshapeSin = (x, k) => Math.sin((PI / k) * x);
35
+ const waveshapeTan = (x, k) => Math.atan(k * x) / k;
36
+ const waveshapeSigmoid = (x, k) => 2 / (1 + Math.exp(-k * x)) - 1;
37
+ const waveshapeSin = (x, k) => Math.sin(PI / k * x);
38
+ export {
39
+ WaveShaper,
40
+ waveShaper,
41
+ waveshapeSigmoid,
42
+ waveshapeSin,
43
+ waveshapeTan
44
+ };
package/white-noise.js CHANGED
@@ -1,26 +1,20 @@
1
1
  import { SYSTEM } from "@thi.ng/random/system";
2
2
  import { AGen } from "./agen.js";
3
- /**
4
- * White noise gen with customizable gain and
5
- * [`IRandom`](https://docs.thi.ng/umbrella/random/interfaces/IRandom.html)
6
- * source.
7
- *
8
- * @param gain -
9
- * @param rnd -
10
- */
11
- export const whiteNoise = (gain, rnd) => new WhiteNoise(gain, rnd);
12
- export class WhiteNoise extends AGen {
13
- _gain;
14
- _rnd;
15
- constructor(_gain = 1, _rnd = SYSTEM) {
16
- super(0);
17
- this._gain = _gain;
18
- this._rnd = _rnd;
19
- }
20
- reset() {
21
- return this;
22
- }
23
- next() {
24
- return (this._val = this._rnd.norm(this._gain));
25
- }
3
+ const whiteNoise = (gain, rnd) => new WhiteNoise(gain, rnd);
4
+ class WhiteNoise extends AGen {
5
+ constructor(_gain = 1, _rnd = SYSTEM) {
6
+ super(0);
7
+ this._gain = _gain;
8
+ this._rnd = _rnd;
9
+ }
10
+ reset() {
11
+ return this;
12
+ }
13
+ next() {
14
+ return this._val = this._rnd.norm(this._gain);
15
+ }
26
16
  }
17
+ export {
18
+ WhiteNoise,
19
+ whiteNoise
20
+ };