@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/merge.js CHANGED
@@ -1,23 +1,21 @@
1
1
  import { AGen } from "./agen.js";
2
2
  import {} from "./api.js";
3
- /**
4
- * Returns a new {@link IGen} which merges signals from multiple mono
5
- * {@link IGen}s into a multi-channel (e.g. stereo) tuples/values.
6
- *
7
- * @param channels
8
- */
9
- export const merge = (...channels) => new Merge(channels, 0);
10
- export const mergeT = (channels, init) => new Merge(channels, init);
11
- export class Merge extends AGen {
12
- _channels;
13
- constructor(_channels, init) {
14
- super(new Array(_channels.length).fill(init));
15
- this._channels = _channels;
16
- }
17
- channel(i) {
18
- return this._channels[i];
19
- }
20
- next() {
21
- return this._channels.map((x) => x.next());
22
- }
3
+ const merge = (...channels) => new Merge(channels, 0);
4
+ const mergeT = (channels, init) => new Merge(channels, init);
5
+ class Merge extends AGen {
6
+ constructor(_channels, init) {
7
+ super(new Array(_channels.length).fill(init));
8
+ this._channels = _channels;
9
+ }
10
+ channel(i) {
11
+ return this._channels[i];
12
+ }
13
+ next() {
14
+ return this._channels.map((x) => x.next());
15
+ }
23
16
  }
17
+ export {
18
+ Merge,
19
+ merge,
20
+ mergeT
21
+ };
package/mix.js CHANGED
@@ -1,20 +1,24 @@
1
1
  import { clamp01 } from "@thi.ng/math/interval";
2
2
  import { AProc2 } from "./aproc.js";
3
3
  import { __ensureGenN } from "./internal/ensure.js";
4
- export const mix = (t) => new Mix(t);
5
- export class Mix extends AProc2 {
6
- _t;
7
- constructor(t = 0.5) {
8
- super(0);
9
- this.mix = t;
10
- }
11
- get mix() {
12
- return this._t.deref();
13
- }
14
- set mix(t) {
15
- this._t = __ensureGenN(t, clamp01);
16
- }
17
- next(a, b) {
18
- return (this._val = a + (b - a) * this._t.next());
19
- }
4
+ const mix = (t) => new Mix(t);
5
+ class Mix extends AProc2 {
6
+ _t;
7
+ constructor(t = 0.5) {
8
+ super(0);
9
+ this.mix = t;
10
+ }
11
+ get mix() {
12
+ return this._t.deref();
13
+ }
14
+ set mix(t) {
15
+ this._t = __ensureGenN(t, clamp01);
16
+ }
17
+ next(a, b) {
18
+ return this._val = a + (b - a) * this._t.next();
19
+ }
20
20
  }
21
+ export {
22
+ Mix,
23
+ mix
24
+ };
package/mul.js CHANGED
@@ -1,40 +1,26 @@
1
1
  import { AGen } from "./agen.js";
2
- /**
3
- * Returns new multiply gen, producing `y(t) = factor * y(t-1)`, using
4
- * given `factor` and `start` values.
5
- *
6
- * Also see {@link exp}.
7
- *
8
- * @param factor -
9
- * @param start -
10
- * @param clamp -
11
- */
12
- export const mul = (factor, start, clamp) => new Mul(factor, start, clamp);
13
- export class Mul extends AGen {
14
- _factor;
15
- _start;
16
- _clamp;
17
- constructor(_factor = 1, _start = 1, _clamp) {
18
- super(0);
19
- this._factor = _factor;
20
- this._start = _start;
21
- this._clamp = _clamp;
22
- this.reset();
23
- }
24
- copy() {
25
- return new Mul(this._factor, this._start, this._clamp);
26
- }
27
- reset() {
28
- this._val = this._start / this._factor;
29
- return this;
30
- }
31
- next() {
32
- let v = this._val * this._factor;
33
- return (this._val =
34
- this._clamp !== undefined
35
- ? this._start < this._clamp
36
- ? Math.min(v, this._clamp)
37
- : Math.max(v, this._clamp)
38
- : v);
39
- }
2
+ const mul = (factor, start, clamp) => new Mul(factor, start, clamp);
3
+ class Mul extends AGen {
4
+ constructor(_factor = 1, _start = 1, _clamp) {
5
+ super(0);
6
+ this._factor = _factor;
7
+ this._start = _start;
8
+ this._clamp = _clamp;
9
+ this.reset();
10
+ }
11
+ copy() {
12
+ return new Mul(this._factor, this._start, this._clamp);
13
+ }
14
+ reset() {
15
+ this._val = this._start / this._factor;
16
+ return this;
17
+ }
18
+ next() {
19
+ let v = this._val * this._factor;
20
+ return this._val = this._clamp !== void 0 ? this._start < this._clamp ? Math.min(v, this._clamp) : Math.max(v, this._clamp) : v;
21
+ }
40
22
  }
23
+ export {
24
+ Mul,
25
+ mul
26
+ };
package/multiplex.js CHANGED
@@ -1,14 +1,18 @@
1
1
  import { AProc } from "./aproc.js";
2
- export function multiplex(...procs) {
3
- return new Multiplex(procs);
2
+ function multiplex(...procs) {
3
+ return new Multiplex(procs);
4
4
  }
5
- export class Multiplex extends AProc {
6
- _procs;
7
- constructor(procs) {
8
- super(procs.map((p) => p.deref()));
9
- this._procs = procs;
10
- }
11
- next(x) {
12
- return (this._val = this._procs.map((p) => p.next(x)));
13
- }
5
+ class Multiplex extends AProc {
6
+ _procs;
7
+ constructor(procs) {
8
+ super(procs.map((p) => p.deref()));
9
+ this._procs = procs;
10
+ }
11
+ next(x) {
12
+ return this._val = this._procs.map((p) => p.next(x));
13
+ }
14
14
  }
15
+ export {
16
+ Multiplex,
17
+ multiplex
18
+ };
package/onepole.js CHANGED
@@ -1,47 +1,46 @@
1
1
  import { TAU } from "@thi.ng/math/api";
2
2
  import { clamp05 } from "@thi.ng/math/interval";
3
3
  import { AProc } from "./aproc.js";
4
- export const onepoleLP = (fc) => new OnePole("lp", fc);
5
- export const onepoleHP = (fc) => new OnePole("hp", fc);
6
- /**
7
- * https://www.earlevel.com/main/2012/12/15/a-one-pole-filter/
8
- */
9
- export class OnePole extends AProc {
10
- _type;
11
- _freq;
12
- _a0;
13
- _b1;
14
- constructor(_type, _freq) {
15
- super(0);
16
- this._type = _type;
17
- this._freq = _freq;
18
- this.setFreq(_freq);
19
- }
20
- clear() {
21
- this._val = 0;
22
- }
23
- reset() {
24
- this.clear();
25
- return this;
26
- }
27
- next(x) {
28
- return (this._val = x * this._a0 + this._val * this._b1);
29
- }
30
- setFreq(fc) {
31
- this._freq = fc = clamp05(fc);
32
- if (this._type === "lp") {
33
- this._b1 = Math.exp(-TAU * fc);
34
- this._a0 = 1 - this._b1;
35
- }
36
- else {
37
- this._b1 = -Math.exp(-TAU * (0.5 - fc));
38
- this._a0 = 1 + this._b1;
39
- }
40
- }
41
- filterCoeffs() {
42
- return {
43
- zeroes: [this._a0],
44
- poles: [1, this._type === "lp" ? this._b1 : -this._b1],
45
- };
4
+ const onepoleLP = (fc) => new OnePole("lp", fc);
5
+ const onepoleHP = (fc) => new OnePole("hp", fc);
6
+ class OnePole extends AProc {
7
+ constructor(_type, _freq) {
8
+ super(0);
9
+ this._type = _type;
10
+ this._freq = _freq;
11
+ this.setFreq(_freq);
12
+ }
13
+ _a0;
14
+ _b1;
15
+ clear() {
16
+ this._val = 0;
17
+ }
18
+ reset() {
19
+ this.clear();
20
+ return this;
21
+ }
22
+ next(x) {
23
+ return this._val = x * this._a0 + this._val * this._b1;
24
+ }
25
+ setFreq(fc) {
26
+ this._freq = fc = clamp05(fc);
27
+ if (this._type === "lp") {
28
+ this._b1 = Math.exp(-TAU * fc);
29
+ this._a0 = 1 - this._b1;
30
+ } else {
31
+ this._b1 = -Math.exp(-TAU * (0.5 - fc));
32
+ this._a0 = 1 + this._b1;
46
33
  }
34
+ }
35
+ filterCoeffs() {
36
+ return {
37
+ zeroes: [this._a0],
38
+ poles: [1, this._type === "lp" ? this._b1 : -this._b1]
39
+ };
40
+ }
47
41
  }
42
+ export {
43
+ OnePole,
44
+ onepoleHP,
45
+ onepoleLP
46
+ };
package/osc-additive.js CHANGED
@@ -1,58 +1,30 @@
1
1
  import { identity } from "@thi.ng/api/fn";
2
2
  import { gibbs } from "./anti-alias.js";
3
3
  import { sin } from "./osc-sin.js";
4
- /**
5
- * Higher order function to produce an additive version of given
6
- * {@link StatelessOscillator}. Returns new oscillator function.
7
- *
8
- * @remarks
9
- * The `freqFn` and `ampFn` functions are used to compute respective frequency
10
- * and amplitude factors for each of the `n` requested harmonics (given in [i,n]
11
- * range).
12
- *
13
- * @param osc -
14
- * @param freqFn -
15
- * @param ampFn -
16
- * @param n -
17
- */
18
- export const additive = (osc, freqFn, ampFn, n) => {
19
- const fcache = [];
20
- const acache = [];
21
- for (let i = 1; i <= n; i++) {
22
- fcache.push(freqFn(i));
23
- acache.push(ampFn(i));
4
+ const additive = (osc, freqFn, ampFn, n) => {
5
+ const fcache = [];
6
+ const acache = [];
7
+ for (let i = 1; i <= n; i++) {
8
+ fcache.push(freqFn(i));
9
+ acache.push(ampFn(i));
10
+ }
11
+ return (phase, freq, amp = 1, dc = 0) => {
12
+ let y = 0;
13
+ for (let i = 0; i < n; i++) {
14
+ y += osc(phase, freq * fcache[i], acache[i]);
24
15
  }
25
- return (phase, freq, amp = 1, dc = 0) => {
26
- let y = 0;
27
- for (let i = 0; i < n; i++) {
28
- y += osc(phase, freq * fcache[i], acache[i]);
29
- }
30
- return dc + amp * y;
31
- };
16
+ return dc + amp * y;
17
+ };
18
+ };
19
+ const squareAdditive = (n = 8, useGibbs = true) => additive(
20
+ sin,
21
+ (i) => 2 * (i - 1) + 1,
22
+ (i) => 1 / (2 * (i - 1) + 1) * (useGibbs ? gibbs(n, i) : 1),
23
+ n
24
+ );
25
+ const sawAdditive = (n = 8, useGibbs = true) => additive(sin, identity, (i) => 1 / i * (useGibbs ? gibbs(n, i) : 1), n);
26
+ export {
27
+ additive,
28
+ sawAdditive,
29
+ squareAdditive
32
30
  };
33
- /**
34
- * Returns a {@link StatelessOscillator} which constructs a square waveform from
35
- * `n` partials. If `useGibbs` is true (default), also applies {@link gibbs} to
36
- * each partial.
37
- *
38
- * @remarks
39
- * Interactive graph of this oscillator:
40
- * https://www.desmos.com/calculator/irugw6gnhy
41
- *
42
- * @param n - number of partials
43
- * @param useGibbs -
44
- */
45
- export const squareAdditive = (n = 8, useGibbs = true) => additive(sin, (i) => 2 * (i - 1) + 1, (i) => (1 / (2 * (i - 1) + 1)) * (useGibbs ? gibbs(n, i) : 1), n);
46
- /**
47
- * Returns a {@link StatelessOscillator} which constructs a sawtooth waveform
48
- * from `n` partials. If `useGibbs` is true (default), also applies
49
- * {@link gibbs} to each partial.
50
- *
51
- * @remarks
52
- * Interactive graph of this oscillator:
53
- * https://www.desmos.com/calculator/irugw6gnhy
54
- *
55
- * @param n - number of partials
56
- * @param useGibbs -
57
- */
58
- export const sawAdditive = (n = 8, useGibbs = true) => additive(sin, identity, (i) => (1 / i) * (useGibbs ? gibbs(n, i) : 1), n);
package/osc-cos.js CHANGED
@@ -1,2 +1,5 @@
1
1
  import { TAU } from "@thi.ng/math/api";
2
- export const cos = (phase, freq, amp = 1, dc = 0) => dc + amp * Math.cos(phase * freq * TAU);
2
+ const cos = (phase, freq, amp = 1, dc = 0) => dc + amp * Math.cos(phase * freq * TAU);
3
+ export {
4
+ cos
5
+ };
package/osc-dsf.js CHANGED
@@ -1,56 +1,19 @@
1
1
  import { TAU } from "@thi.ng/math/api";
2
- /**
3
- * Oscillator using Discrete Summation Formula:
4
- *
5
- * `y(t) = (1-a^2) * sin(2πt) / (1 + a^2 - 2a * cos(b * 2πt))`
6
- *
7
- * @remarks
8
- * `alpha` should be in [0..1) interval, `beta` is used as factor for
9
- * the base `freq` and used for the cosine modulation term. The default
10
- * config for both params is 0.5, 1.0 respectively, creating a waveform
11
- * similar to a bandlimited sawtooth. If both params are zero, the
12
- * result is a pure sine.
13
- *
14
- * Note: Higher `alpha` values cause an increasing number (and
15
- * amplitude) of spikes in the waveform. Therefore, the higher the
16
- * `alpha`, the lower `amp` should be to avoid excessive out-of-range
17
- * values.
18
- *
19
- * References:
20
- * - https://www.desmos.com/calculator/klvl9oszfm
21
- * - https://ccrma.stanford.edu/files/papers/stanm5.pdf
22
- *
23
- * @param phase -
24
- * @param freq -
25
- * @param amp -
26
- * @param dc -
27
- * @param alpha -
28
- * @param beta -
29
- */
30
- export const dsf = (phase, freq, amp = 1, dc = 0, alpha = 0.5, beta = 1) => {
31
- const aa = alpha * alpha;
32
- const a2 = 2 * alpha;
2
+ const dsf = (phase, freq, amp = 1, dc = 0, alpha = 0.5, beta = 1) => {
3
+ const aa = alpha * alpha;
4
+ const a2 = 2 * alpha;
5
+ phase *= TAU * freq;
6
+ return amp * ((1 - aa) * Math.sin(phase) / (1 + aa - a2 * Math.cos(beta * phase))) + dc;
7
+ };
8
+ const dsfHOF = (alpha = 0.5, beta = 1) => {
9
+ const aa = alpha * alpha;
10
+ const a2 = 2 * alpha;
11
+ return (phase, freq, amp = 1, dc = 0) => {
33
12
  phase *= TAU * freq;
34
- return (amp *
35
- (((1 - aa) * Math.sin(phase)) /
36
- (1 + aa - a2 * Math.cos(beta * phase))) +
37
- dc);
13
+ return amp * ((1 - aa) * Math.sin(phase) / (1 + aa - a2 * Math.cos(beta * phase))) + dc;
14
+ };
38
15
  };
39
- /**
40
- * Higher order version of {@link dsf} oscillator with pre-configured
41
- * params. Slightly faster, but not dynamically changeable waveform.
42
- *
43
- * @param alpha -
44
- * @param beta -
45
- */
46
- export const dsfHOF = (alpha = 0.5, beta = 1) => {
47
- const aa = alpha * alpha;
48
- const a2 = 2 * alpha;
49
- return (phase, freq, amp = 1, dc = 0) => {
50
- phase *= TAU * freq;
51
- return (amp *
52
- (((1 - aa) * Math.sin(phase)) /
53
- (1 + aa - a2 * Math.cos(beta * phase))) +
54
- dc);
55
- };
16
+ export {
17
+ dsf,
18
+ dsfHOF
56
19
  };
package/osc-mix.js CHANGED
@@ -1,21 +1,7 @@
1
1
  import { mix as _mix } from "@thi.ng/math/mix";
2
- /**
3
- * HOF oscillator. Takes 2 stateless oscillator fns and returns new
4
- * oscillator function which produces an interpolated result of both.
5
- * The returned function takes an additional `mix` arg ([0..1] range)
6
- * control contributions of either oscillator (default: 0.5 aka 50/50
7
- * ratio).
8
- *
9
- * @param osc1 -
10
- * @param osc2 -
11
- */
12
- export const mixOsc = (osc1, osc2) => (phase, freq, amp = 1, dc = 0, t = 0.5) => _mix(osc1(phase, freq, amp, dc), osc2(phase, freq, amp, dc), t);
13
- /**
14
- * Similar to {@link mixOsc}, but with `mix` arg ([0..1] range)
15
- * directly given to HOF and not changeable after.
16
- *
17
- * @param osc1 -
18
- * @param osc2 -
19
- * @param mix -
20
- */
21
- export const mixOscHOF = (osc1, osc2, mix = 0.5) => (phase, freq, amp = 1, dc = 0) => _mix(osc1(phase, freq, amp, dc), osc2(phase, freq, amp, dc), mix);
2
+ const mixOsc = (osc1, osc2) => (phase, freq, amp = 1, dc = 0, t = 0.5) => _mix(osc1(phase, freq, amp, dc), osc2(phase, freq, amp, dc), t);
3
+ const mixOscHOF = (osc1, osc2, mix = 0.5) => (phase, freq, amp = 1, dc = 0) => _mix(osc1(phase, freq, amp, dc), osc2(phase, freq, amp, dc), mix);
4
+ export {
5
+ mixOsc,
6
+ mixOscHOF
7
+ };
package/osc-parabolic.js CHANGED
@@ -1,14 +1,5 @@
1
1
  import { fract } from "@thi.ng/math/prec";
2
- /**
3
- * Parabolic waveform oscillator.
4
- *
5
- * @remarks
6
- * Reference:
7
- * - https://www.desmos.com/calculator/gsobpc8hsy
8
- *
9
- * @param phase -
10
- * @param freq -
11
- * @param amp -
12
- * @param dc -
13
- */
14
- export const parabolic = (phase, freq, amp = 1, dc = 0) => dc + amp * (8 * (fract(phase * freq) - 0.5) ** 2 - 1);
2
+ const parabolic = (phase, freq, amp = 1, dc = 0) => dc + amp * (8 * (fract(phase * freq) - 0.5) ** 2 - 1);
3
+ export {
4
+ parabolic
5
+ };
package/osc-rect.js CHANGED
@@ -1,9 +1,7 @@
1
1
  import { fract } from "@thi.ng/math/prec";
2
- export const rect = (phase, freq, amp = 1, dc = 0, duty = 0.5) => dc + amp * (fract(phase * freq) < duty ? 1 : -1);
3
- /**
4
- * Higher order version of {@link rect} with pre-configured `duty` width
5
- * (in the (0..1) range).
6
- *
7
- * @param duty -
8
- */
9
- export const rectHOF = (duty = 0.5) => (phase, freq, amp, dc) => rect(phase, freq, amp, dc, duty);
2
+ const rect = (phase, freq, amp = 1, dc = 0, duty = 0.5) => dc + amp * (fract(phase * freq) < duty ? 1 : -1);
3
+ const rectHOF = (duty = 0.5) => (phase, freq, amp, dc) => rect(phase, freq, amp, dc, duty);
4
+ export {
5
+ rect,
6
+ rectHOF
7
+ };
package/osc-saw.js CHANGED
@@ -1,2 +1,5 @@
1
1
  import { fract } from "@thi.ng/math/prec";
2
- export const saw = (phase, freq, amp = 1, dc = 0) => dc + amp * (1 - 2 * fract(phase * freq));
2
+ const saw = (phase, freq, amp = 1, dc = 0) => dc + amp * (1 - 2 * fract(phase * freq));
3
+ export {
4
+ saw
5
+ };
package/osc-sin.js CHANGED
@@ -1,2 +1,5 @@
1
1
  import { TAU } from "@thi.ng/math/api";
2
- export const sin = (phase, freq, amp = 1, dc = 0) => dc + amp * Math.sin(phase * freq * TAU);
2
+ const sin = (phase, freq, amp = 1, dc = 0) => dc + amp * Math.sin(phase * freq * TAU);
3
+ export {
4
+ sin
5
+ };
package/osc-tri.js CHANGED
@@ -1,2 +1,5 @@
1
1
  import { fract } from "@thi.ng/math/prec";
2
- export const tri = (phase, freq, amp = 1, dc = 0) => dc + amp * (Math.abs(fract(phase * freq) * 4 - 2) - 1);
2
+ const tri = (phase, freq, amp = 1, dc = 0) => dc + amp * (Math.abs(fract(phase * freq) * 4 - 2) - 1);
3
+ export {
4
+ tri
5
+ };
package/osc-wavetable.js CHANGED
@@ -1,12 +1,15 @@
1
1
  import { mix as _mix } from "@thi.ng/math/mix";
2
2
  import { fract } from "@thi.ng/math/prec";
3
- export const wavetable = (table, interpolate = _mix) => {
4
- const n = table.length;
5
- const n1 = n - 1;
6
- return (phase, freq, amp = 1, dc = 0) => {
7
- phase = fract(phase * freq) * n;
8
- let i = phase | 0;
9
- let j = i < n1 ? i + 1 : 0;
10
- return dc + amp * interpolate(table[i], table[j], phase - i);
11
- };
3
+ const wavetable = (table, interpolate = _mix) => {
4
+ const n = table.length;
5
+ const n1 = n - 1;
6
+ return (phase, freq, amp = 1, dc = 0) => {
7
+ phase = fract(phase * freq) * n;
8
+ let i = phase | 0;
9
+ let j = i < n1 ? i + 1 : 0;
10
+ return dc + amp * interpolate(table[i], table[j], phase - i);
11
+ };
12
+ };
13
+ export {
14
+ wavetable
12
15
  };