@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/aproc.js CHANGED
@@ -1,33 +1,27 @@
1
1
  import { map } from "@thi.ng/transducers/map";
2
- /**
3
- * Abstract base class for processors in this package. Provides
4
- * [`IDeref`](https://docs.thi.ng/umbrella/api/interfaces/IDeref.html) to obtain
5
- * the processor's current value.
6
- */
7
- export class AProc {
8
- _val;
9
- constructor(_val) {
10
- this._val = _val;
11
- }
12
- deref() {
13
- return this._val;
14
- }
15
- xform() {
16
- return map((x) => this.next(x));
17
- }
2
+ class AProc {
3
+ constructor(_val) {
4
+ this._val = _val;
5
+ }
6
+ deref() {
7
+ return this._val;
8
+ }
9
+ xform() {
10
+ return map((x) => this.next(x));
11
+ }
18
12
  }
19
- /**
20
- * Similar to {@link AProc}, but for processors with 2 inputs.
21
- */
22
- export class AProc2 {
23
- _val;
24
- constructor(_val) {
25
- this._val = _val;
26
- }
27
- deref() {
28
- return this._val;
29
- }
30
- xform() {
31
- return map(([a, b]) => this.next(a, b));
32
- }
13
+ class AProc2 {
14
+ constructor(_val) {
15
+ this._val = _val;
16
+ }
17
+ deref() {
18
+ return this._val;
19
+ }
20
+ xform() {
21
+ return map(([a, b]) => this.next(a, b));
22
+ }
33
23
  }
24
+ export {
25
+ AProc,
26
+ AProc2
27
+ };
package/biquad.js CHANGED
@@ -3,190 +3,194 @@ import { PI, SQRT2, SQRT2_2 } from "@thi.ng/math/api";
3
3
  import { clamp05 } from "@thi.ng/math/interval";
4
4
  import { AProc } from "./aproc.js";
5
5
  import { dbMag } from "./convert.js";
6
- export const biquad = (type, fc, q, gain) => new Biquad(type, fc, q, gain);
7
- export const biquadLP = (fc, q) => new Biquad("lp", fc, q);
8
- export const biquadHP = (fc, q) => new Biquad("hp", fc, q);
9
- export const biquadBP = (fc, q) => new Biquad("bp", fc, q);
10
- export const biquadNotch = (fc, q) => new Biquad("notch", fc, q);
11
- export const biquadPeak = (fc, q, gain = 6) => new Biquad("peak", fc, q, gain);
12
- export const biquadLoShelf = (fc, gain = -6) => new Biquad("loshelf", fc, undefined, gain);
13
- export const biquadHiShelf = (fc, gain = -6) => new Biquad("hishelf", fc, undefined, gain);
14
- export class Biquad extends AProc {
15
- _type;
16
- _freq;
17
- _q;
18
- _gain;
19
- _a0;
20
- _a1;
21
- _a2;
22
- _b1;
23
- _b2;
24
- _z1;
25
- _z2;
26
- constructor(_type, _freq, _q = SQRT2_2, _gain = 0) {
27
- super(0);
28
- this._type = _type;
29
- this._freq = _freq;
30
- this._q = _q;
31
- this._gain = _gain;
32
- this.reset();
33
- this.calcCoeffs();
34
- }
35
- reset() {
36
- this._z1 = this._z2 = this._val = 0;
37
- return this;
38
- }
39
- next(x) {
40
- const out = x * this._a0 + this._z1;
41
- this._z1 = x * this._a1 + this._z2 - this._b1 * out;
42
- this._z2 = x * this._a2 - this._b2 * out;
43
- return (this._val = out);
44
- }
45
- freq() {
46
- return this._freq;
47
- }
48
- q() {
49
- return this._q;
50
- }
51
- gain() {
52
- return this._gain;
53
- }
54
- set(fc, q, gain) {
55
- this._freq = clamp05(fc);
56
- this._q = q;
57
- this._gain = gain;
58
- this.calcCoeffs();
59
- }
60
- setFreq(fc) {
61
- this._freq = clamp05(fc);
62
- this.calcCoeffs();
63
- }
64
- setQ(q) {
65
- this._q = q;
66
- this.calcCoeffs();
67
- }
68
- setGain(g) {
69
- this._gain = g;
70
- this.calcCoeffs();
71
- }
72
- filterCoeffs() {
73
- return {
74
- zeroes: [this._a0, this._a1, this._a2],
75
- poles: [1, this._b1, this._b2],
76
- };
77
- }
78
- calcCoeffs() {
79
- const k = Math.tan(PI * this._freq);
80
- const k2 = k * k;
81
- const k22 = 2 * (k2 - 1);
82
- const kq = k / this._q;
83
- const k2kqp1 = 1 + kq + k2;
84
- const k2kqm1 = 1 - kq + k2;
85
- const ksqrt2 = k * SQRT2;
86
- const v = dbMag(Math.abs(this._gain));
87
- const kvq = k * (v / this._q);
88
- const ksqrt2v = k * Math.sqrt(2 * v);
89
- let norm = 1 / k2kqp1;
90
- switch (this._type) {
91
- case "lp":
92
- this._a0 = k2 * norm;
93
- this._a1 = 2 * this._a0;
94
- this._a2 = this._a0;
95
- this._b1 = k22 * norm;
96
- this._b2 = k2kqm1 * norm;
97
- break;
98
- case "hp":
99
- this._a0 = norm;
100
- this._a1 = -2 * this._a0;
101
- this._a2 = this._a0;
102
- this._b1 = k22 * norm;
103
- this._b2 = k2kqm1 * norm;
104
- break;
105
- case "bp":
106
- this._a0 = kq * norm;
107
- this._a1 = 0;
108
- this._a2 = -this._a0;
109
- this._b1 = k22 * norm;
110
- this._b2 = k2kqm1 * norm;
111
- break;
112
- case "notch":
113
- this._a0 = (1 + k2) * norm;
114
- this._a1 = k22 * norm;
115
- this._a2 = this._a0;
116
- this._b1 = this._a1;
117
- this._b2 = k2kqm1 * norm;
118
- break;
119
- case "peak": {
120
- const z1 = 1 + kvq + k2;
121
- const z2 = 1 - kvq + k2;
122
- if (this._gain >= 0) {
123
- this._a0 = z1 * norm;
124
- this._a1 = k22 * norm;
125
- this._a2 = z2 * norm;
126
- this._b1 = this._a1;
127
- this._b2 = k2kqm1 * norm;
128
- }
129
- else {
130
- norm = 1 / z1;
131
- this._a0 = k2kqp1 * norm;
132
- this._a1 = k22 * norm;
133
- this._a2 = k2kqm1 * norm;
134
- this._b1 = this._a1;
135
- this._b2 = z2 * norm;
136
- }
137
- break;
138
- }
139
- case "loshelf": {
140
- const z1 = 1 + ksqrt2 + k2;
141
- const z2 = 1 - ksqrt2 + k2;
142
- const vk2 = v * k2;
143
- const y1 = 1 + ksqrt2v + vk2;
144
- const y2 = 1 - ksqrt2v + vk2;
145
- const vk22 = 2 * (vk2 - 1);
146
- if (this._gain >= 0) {
147
- norm = 1 / z1;
148
- this._a0 = y1 * norm;
149
- this._a1 = vk22 * norm;
150
- this._a2 = y2 * norm;
151
- this._b1 = k22 * norm;
152
- this._b2 = z2 * norm;
153
- }
154
- else {
155
- norm = 1 / y1;
156
- this._a0 = z1 * norm;
157
- this._a1 = k22 * norm;
158
- this._a2 = z2 * norm;
159
- this._b1 = vk22 * norm;
160
- this._b2 = y2 * norm;
161
- }
162
- break;
163
- }
164
- case "hishelf": {
165
- const z1 = 1 + ksqrt2 + k2;
166
- const z2 = 1 - ksqrt2 + k2;
167
- const y1 = v + ksqrt2v + k2;
168
- const y2 = v - ksqrt2v + k2;
169
- const vk2 = 2 * (k2 - v);
170
- if (this._gain >= 0) {
171
- norm = 1 / z1;
172
- this._a0 = y1 * norm;
173
- this._a1 = vk2 * norm;
174
- this._a2 = y2 * norm;
175
- this._b1 = k22 * norm;
176
- this._b2 = z2 * norm;
177
- }
178
- else {
179
- norm = 1 / y1;
180
- this._a0 = z1 * norm;
181
- this._a1 = k22 * norm;
182
- this._a2 = z2 * norm;
183
- this._b1 = vk2 * norm;
184
- this._b2 = y2 * norm;
185
- }
186
- break;
187
- }
188
- default:
189
- unsupported(`invalid filter type: ${this._type}`);
6
+ const biquad = (type, fc, q, gain) => new Biquad(type, fc, q, gain);
7
+ const biquadLP = (fc, q) => new Biquad("lp", fc, q);
8
+ const biquadHP = (fc, q) => new Biquad("hp", fc, q);
9
+ const biquadBP = (fc, q) => new Biquad("bp", fc, q);
10
+ const biquadNotch = (fc, q) => new Biquad("notch", fc, q);
11
+ const biquadPeak = (fc, q, gain = 6) => new Biquad("peak", fc, q, gain);
12
+ const biquadLoShelf = (fc, gain = -6) => new Biquad("loshelf", fc, void 0, gain);
13
+ const biquadHiShelf = (fc, gain = -6) => new Biquad("hishelf", fc, void 0, gain);
14
+ class Biquad extends AProc {
15
+ constructor(_type, _freq, _q = SQRT2_2, _gain = 0) {
16
+ super(0);
17
+ this._type = _type;
18
+ this._freq = _freq;
19
+ this._q = _q;
20
+ this._gain = _gain;
21
+ this.reset();
22
+ this.calcCoeffs();
23
+ }
24
+ _a0;
25
+ _a1;
26
+ _a2;
27
+ _b1;
28
+ _b2;
29
+ _z1;
30
+ _z2;
31
+ reset() {
32
+ this._z1 = this._z2 = this._val = 0;
33
+ return this;
34
+ }
35
+ next(x) {
36
+ const out = x * this._a0 + this._z1;
37
+ this._z1 = x * this._a1 + this._z2 - this._b1 * out;
38
+ this._z2 = x * this._a2 - this._b2 * out;
39
+ return this._val = out;
40
+ }
41
+ freq() {
42
+ return this._freq;
43
+ }
44
+ q() {
45
+ return this._q;
46
+ }
47
+ gain() {
48
+ return this._gain;
49
+ }
50
+ set(fc, q, gain) {
51
+ this._freq = clamp05(fc);
52
+ this._q = q;
53
+ this._gain = gain;
54
+ this.calcCoeffs();
55
+ }
56
+ setFreq(fc) {
57
+ this._freq = clamp05(fc);
58
+ this.calcCoeffs();
59
+ }
60
+ setQ(q) {
61
+ this._q = q;
62
+ this.calcCoeffs();
63
+ }
64
+ setGain(g) {
65
+ this._gain = g;
66
+ this.calcCoeffs();
67
+ }
68
+ filterCoeffs() {
69
+ return {
70
+ zeroes: [this._a0, this._a1, this._a2],
71
+ poles: [1, this._b1, this._b2]
72
+ };
73
+ }
74
+ calcCoeffs() {
75
+ const k = Math.tan(PI * this._freq);
76
+ const k2 = k * k;
77
+ const k22 = 2 * (k2 - 1);
78
+ const kq = k / this._q;
79
+ const k2kqp1 = 1 + kq + k2;
80
+ const k2kqm1 = 1 - kq + k2;
81
+ const ksqrt2 = k * SQRT2;
82
+ const v = dbMag(Math.abs(this._gain));
83
+ const kvq = k * (v / this._q);
84
+ const ksqrt2v = k * Math.sqrt(2 * v);
85
+ let norm = 1 / k2kqp1;
86
+ switch (this._type) {
87
+ case "lp":
88
+ this._a0 = k2 * norm;
89
+ this._a1 = 2 * this._a0;
90
+ this._a2 = this._a0;
91
+ this._b1 = k22 * norm;
92
+ this._b2 = k2kqm1 * norm;
93
+ break;
94
+ case "hp":
95
+ this._a0 = norm;
96
+ this._a1 = -2 * this._a0;
97
+ this._a2 = this._a0;
98
+ this._b1 = k22 * norm;
99
+ this._b2 = k2kqm1 * norm;
100
+ break;
101
+ case "bp":
102
+ this._a0 = kq * norm;
103
+ this._a1 = 0;
104
+ this._a2 = -this._a0;
105
+ this._b1 = k22 * norm;
106
+ this._b2 = k2kqm1 * norm;
107
+ break;
108
+ case "notch":
109
+ this._a0 = (1 + k2) * norm;
110
+ this._a1 = k22 * norm;
111
+ this._a2 = this._a0;
112
+ this._b1 = this._a1;
113
+ this._b2 = k2kqm1 * norm;
114
+ break;
115
+ case "peak": {
116
+ const z1 = 1 + kvq + k2;
117
+ const z2 = 1 - kvq + k2;
118
+ if (this._gain >= 0) {
119
+ this._a0 = z1 * norm;
120
+ this._a1 = k22 * norm;
121
+ this._a2 = z2 * norm;
122
+ this._b1 = this._a1;
123
+ this._b2 = k2kqm1 * norm;
124
+ } else {
125
+ norm = 1 / z1;
126
+ this._a0 = k2kqp1 * norm;
127
+ this._a1 = k22 * norm;
128
+ this._a2 = k2kqm1 * norm;
129
+ this._b1 = this._a1;
130
+ this._b2 = z2 * norm;
131
+ }
132
+ break;
133
+ }
134
+ case "loshelf": {
135
+ const z1 = 1 + ksqrt2 + k2;
136
+ const z2 = 1 - ksqrt2 + k2;
137
+ const vk2 = v * k2;
138
+ const y1 = 1 + ksqrt2v + vk2;
139
+ const y2 = 1 - ksqrt2v + vk2;
140
+ const vk22 = 2 * (vk2 - 1);
141
+ if (this._gain >= 0) {
142
+ norm = 1 / z1;
143
+ this._a0 = y1 * norm;
144
+ this._a1 = vk22 * norm;
145
+ this._a2 = y2 * norm;
146
+ this._b1 = k22 * norm;
147
+ this._b2 = z2 * norm;
148
+ } else {
149
+ norm = 1 / y1;
150
+ this._a0 = z1 * norm;
151
+ this._a1 = k22 * norm;
152
+ this._a2 = z2 * norm;
153
+ this._b1 = vk22 * norm;
154
+ this._b2 = y2 * norm;
155
+ }
156
+ break;
157
+ }
158
+ case "hishelf": {
159
+ const z1 = 1 + ksqrt2 + k2;
160
+ const z2 = 1 - ksqrt2 + k2;
161
+ const y1 = v + ksqrt2v + k2;
162
+ const y2 = v - ksqrt2v + k2;
163
+ const vk2 = 2 * (k2 - v);
164
+ if (this._gain >= 0) {
165
+ norm = 1 / z1;
166
+ this._a0 = y1 * norm;
167
+ this._a1 = vk2 * norm;
168
+ this._a2 = y2 * norm;
169
+ this._b1 = k22 * norm;
170
+ this._b2 = z2 * norm;
171
+ } else {
172
+ norm = 1 / y1;
173
+ this._a0 = z1 * norm;
174
+ this._a1 = k22 * norm;
175
+ this._a2 = z2 * norm;
176
+ this._b1 = vk2 * norm;
177
+ this._b2 = y2 * norm;
190
178
  }
179
+ break;
180
+ }
181
+ default:
182
+ unsupported(`invalid filter type: ${this._type}`);
191
183
  }
184
+ }
192
185
  }
186
+ export {
187
+ Biquad,
188
+ biquad,
189
+ biquadBP,
190
+ biquadHP,
191
+ biquadHiShelf,
192
+ biquadLP,
193
+ biquadLoShelf,
194
+ biquadNotch,
195
+ biquadPeak
196
+ };
package/bounce.js CHANGED
@@ -1,18 +1,17 @@
1
1
  import { AProc } from "./aproc.js";
2
- /**
3
- * Returns a new {@link Bounce} processor, which receives a multi-track tuple
4
- * input (e.g. as produced by {@link multiplex}) and yields its "bounced down"
5
- * (aka summed), single channel output.
6
- */
7
- export const bounce = () => new Bounce();
8
- export class Bounce extends AProc {
9
- constructor() {
10
- super(0);
11
- }
12
- next(src) {
13
- let res = 0;
14
- for (let i = src.length; i-- > 0;)
15
- res += src[i];
16
- return (this._val = res);
17
- }
2
+ const bounce = () => new Bounce();
3
+ class Bounce extends AProc {
4
+ constructor() {
5
+ super(0);
6
+ }
7
+ next(src) {
8
+ let res = 0;
9
+ for (let i = src.length; i-- > 0; )
10
+ res += src[i];
11
+ return this._val = res;
12
+ }
18
13
  }
14
+ export {
15
+ Bounce,
16
+ bounce
17
+ };
package/complex.js CHANGED
@@ -1,2 +1,5 @@
1
1
  import { isNumber } from "@thi.ng/checks/is-number";
2
- export const isComplex = (buf) => !isNumber(buf[0]);
2
+ const isComplex = (buf) => !isNumber(buf[0]);
3
+ export {
4
+ isComplex
5
+ };
package/const.js CHANGED
@@ -1,15 +1,14 @@
1
1
  import { AGen } from "./agen.js";
2
- /**
3
- * Returns new gen yielding always the same given value `x`.
4
- *
5
- * @param x -
6
- */
7
- export const constant = (x) => new Const(x);
8
- export class Const extends AGen {
9
- copy() {
10
- return new Const(this._val);
11
- }
12
- next() {
13
- return this._val;
14
- }
2
+ const constant = (x) => new Const(x);
3
+ class Const extends AGen {
4
+ copy() {
5
+ return new Const(this._val);
6
+ }
7
+ next() {
8
+ return this._val;
9
+ }
15
10
  }
11
+ export {
12
+ Const,
13
+ constant
14
+ };
package/convert.js CHANGED
@@ -1,65 +1,19 @@
1
1
  import { TAU } from "@thi.ng/math/api";
2
- /**
3
- * Returns frequency `f` normalized to sample rate `fs`:
4
- * `fnorm = f / fs`
5
- *
6
- * @param f -
7
- * @param fs -
8
- */
9
- export const normFreq = (f, fs) => f / fs;
10
- /**
11
- * Returns frequency `f` in radians, based on sample rate `fs`.
12
- * I.e. Nyquist freq = PI
13
- *
14
- * @param f -
15
- * @param fs -
16
- */
17
- export const freqRad = (f, fs) => (f / fs) * TAU;
18
- /**
19
- * Returns period length in milliseconds for given frequency in Hz.
20
- *
21
- * @param f -
22
- */
23
- export const freqMs = (f) => 1000 / f;
24
- /**
25
- * Reverse op of {@link freqRad}.
26
- *
27
- * @param rad -
28
- * @param fs -
29
- */
30
- export const radFreq = (rad, fs) => (rad / TAU) * fs;
31
- /**
32
- * Returns number of samples for given millisecond period and samle
33
- * rate.
34
- *
35
- * @example
36
- * ```ts
37
- * // samples per 20 ms @ 44.1kHz
38
- * msFrames(20, 44100)
39
- * // 882
40
- * ```
41
- *
42
- * @param t -
43
- * @param fs -
44
- */
45
- export const msFrames = (t, fs) => t * 0.001 * fs;
46
- /**
47
- * Reverse op of {@link msFrames}.
48
- *
49
- * @param frames -
50
- * @param fs -
51
- */
52
- export const framesMs = (frames, fs) => (frames / fs) * 1000;
53
- /**
54
- * Converts given linear magnitude to dBFS (i.e. `20 * log10(x)`)
55
- *
56
- * @param x -
57
- */
58
- export const magDb = (x) => (20 * Math.log(x)) / Math.LN10;
59
- /**
60
- * Converts given dBFS value to linear magnitude
61
- * (i.e. `pow(10, x / 20)`)
62
- *
63
- * @param x -
64
- */
65
- export const dbMag = (x) => 10 ** (x / 20);
2
+ const normFreq = (f, fs) => f / fs;
3
+ const freqRad = (f, fs) => f / fs * TAU;
4
+ const freqMs = (f) => 1e3 / f;
5
+ const radFreq = (rad, fs) => rad / TAU * fs;
6
+ const msFrames = (t, fs) => t * 1e-3 * fs;
7
+ const framesMs = (frames, fs) => frames / fs * 1e3;
8
+ const magDb = (x) => 20 * Math.log(x) / Math.LN10;
9
+ const dbMag = (x) => 10 ** (x / 20);
10
+ export {
11
+ dbMag,
12
+ framesMs,
13
+ freqMs,
14
+ freqRad,
15
+ magDb,
16
+ msFrames,
17
+ normFreq,
18
+ radFreq
19
+ };