pixi-effects 0.27.1 → 0.27.2
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.
- package/CHANGELOG.md +7 -0
- package/README.md +6 -6
- package/ai/chat-template.html +3 -3
- package/dist/Composition-DRCTWIYH.cjs +16 -0
- package/dist/{Composition-YW2G6EXL.cjs.map → Composition-DRCTWIYH.cjs.map} +1 -1
- package/dist/Composition-TZHVYIGH.js +7 -0
- package/dist/{Composition-BJVY5HP7.js.map → Composition-TZHVYIGH.js.map} +1 -1
- package/dist/{chunk-X42BGR6P.js → chunk-BQNNZEAX.js} +4 -4
- package/dist/{chunk-X42BGR6P.js.map → chunk-BQNNZEAX.js.map} +1 -1
- package/dist/{chunk-VH5R473P.cjs → chunk-C7HJJ7MZ.cjs} +61 -61
- package/dist/{chunk-VH5R473P.cjs.map → chunk-C7HJJ7MZ.cjs.map} +1 -1
- package/dist/{chunk-AR3HVHKF.js → chunk-K3F2YKL4.js} +3 -3
- package/dist/{chunk-AR3HVHKF.js.map → chunk-K3F2YKL4.js.map} +1 -1
- package/dist/{chunk-ETKTRQL2.cjs → chunk-YOV6MEXH.cjs} +4 -4
- package/dist/{chunk-ETKTRQL2.cjs.map → chunk-YOV6MEXH.cjs.map} +1 -1
- package/dist/index.cjs +32 -32
- package/dist/index.js +5 -5
- package/dist/loader.css +1 -1
- package/dist/{music-YPUZTWTN.cjs → music-6MTHQEXS.cjs} +269 -99
- package/dist/music-6MTHQEXS.cjs.map +1 -0
- package/dist/{music-JVRNXHQ5.js → music-72YJAMXH.js} +269 -99
- package/dist/music-72YJAMXH.js.map +1 -0
- package/dist/three.cjs +5 -5
- package/dist/three.js +1 -1
- package/llms-full.txt +1 -1
- package/package.json +1 -1
- package/skills/pixi-effects/SKILL.md +1 -1
- package/skills/pixi-effects/template.html +6 -6
- package/dist/Composition-BJVY5HP7.js +0 -7
- package/dist/Composition-YW2G6EXL.cjs +0 -16
- package/dist/music-JVRNXHQ5.js.map +0 -1
- package/dist/music-YPUZTWTN.cjs.map +0 -1
|
@@ -4,8 +4,50 @@ import { warnUnknownOptions, suggestName } from './chunk-BXOCEZ4U.js';
|
|
|
4
4
|
var TAU = Math.PI * 2;
|
|
5
5
|
var SR = 44100;
|
|
6
6
|
function setSampleRate(sr) {
|
|
7
|
+
if (sr !== SR) clearVoiceTables();
|
|
7
8
|
SR = sr;
|
|
8
9
|
}
|
|
10
|
+
function clearVoiceTables() {
|
|
11
|
+
KEYS_TABLES.clear();
|
|
12
|
+
BELL_TABLES.clear();
|
|
13
|
+
}
|
|
14
|
+
var BELL_TABLES = /* @__PURE__ */ new Map();
|
|
15
|
+
function bellTables(f, k, n) {
|
|
16
|
+
const key = f + "/" + k;
|
|
17
|
+
let tb = BELL_TABLES.get(key);
|
|
18
|
+
if (tb && tb.n >= n) return tb;
|
|
19
|
+
const len = Math.max(n, tb ? tb.n * 2 : 0);
|
|
20
|
+
const s35 = new Float64Array(len), e5 = new Float64Array(len), ek = new Float64Array(len), s276 = new Float64Array(len), e4 = new Float64Array(len);
|
|
21
|
+
for (let i = 0; i < len; i++) {
|
|
22
|
+
const t = i / SR;
|
|
23
|
+
s35[i] = Math.sin(TAU * f * 3.5 * t);
|
|
24
|
+
e5[i] = Math.exp(-t * 5);
|
|
25
|
+
ek[i] = Math.exp(-t * k);
|
|
26
|
+
s276[i] = Math.sin(TAU * f * 2.76 * t);
|
|
27
|
+
e4[i] = Math.exp(-t * 4);
|
|
28
|
+
}
|
|
29
|
+
tb = { s35, e5, ek, s276, e4, n: len };
|
|
30
|
+
BELL_TABLES.set(key, tb);
|
|
31
|
+
return tb;
|
|
32
|
+
}
|
|
33
|
+
var KEYS_TABLES = /* @__PURE__ */ new Map();
|
|
34
|
+
function keysTables(f, n) {
|
|
35
|
+
let tb = KEYS_TABLES.get(f);
|
|
36
|
+
if (tb && tb.n >= n) return tb;
|
|
37
|
+
const len = Math.max(n, tb ? tb.n * 2 : 0);
|
|
38
|
+
const decay = new Float64Array(len), s14 = new Float64Array(len), s1 = new Float64Array(len), e18 = new Float64Array(len), e32 = new Float64Array(len);
|
|
39
|
+
for (let i = 0; i < len; i++) {
|
|
40
|
+
const t = i / SR;
|
|
41
|
+
decay[i] = Math.exp(-t * (1.1 + f / 1500));
|
|
42
|
+
s14[i] = Math.sin(TAU * f * 14 * t);
|
|
43
|
+
s1[i] = Math.sin(TAU * f * t);
|
|
44
|
+
e18[i] = Math.exp(-t * 18);
|
|
45
|
+
e32[i] = Math.exp(-t * 3.2);
|
|
46
|
+
}
|
|
47
|
+
tb = { decay, s14, s1, e18, e32, n: len };
|
|
48
|
+
KEYS_TABLES.set(f, tb);
|
|
49
|
+
return tb;
|
|
50
|
+
}
|
|
9
51
|
var mtof = (m) => 440 * 2 ** ((m - 69) / 12);
|
|
10
52
|
var Biquad = class {
|
|
11
53
|
b0 = 1;
|
|
@@ -44,6 +86,10 @@ var Biquad = class {
|
|
|
44
86
|
this.a1 = -2 * c / a0;
|
|
45
87
|
this.a2 = (1 - al) / a0;
|
|
46
88
|
}
|
|
89
|
+
/** All four memories are so small that anything this filter outputs from silence on rounds to 0 in a Float32Array (below half its smallest number). */
|
|
90
|
+
settled() {
|
|
91
|
+
return Math.abs(this.x1) < 1e-47 && Math.abs(this.x2) < 1e-47 && Math.abs(this.y1) < 1e-47 && Math.abs(this.y2) < 1e-47;
|
|
92
|
+
}
|
|
47
93
|
run(x) {
|
|
48
94
|
const y = this.b0 * x + this.b1 * this.x1 + this.b2 * this.x2 - this.a1 * this.y1 - this.a2 * this.y2;
|
|
49
95
|
this.x2 = this.x1;
|
|
@@ -60,28 +106,27 @@ var adsr = (t, dur, a, d, s, r) => {
|
|
|
60
106
|
const base = dur < a ? dur / a : dur < a + d ? 1 - (1 - s) * ((dur - a) / d) : s;
|
|
61
107
|
return Math.max(0, base * (1 - (t - dur) / r));
|
|
62
108
|
};
|
|
63
|
-
function addTo(out, start, i, l, r) {
|
|
64
|
-
const k = start + i;
|
|
65
|
-
if (k >= 0 && k < out.L.length) {
|
|
66
|
-
out.L[k] += l;
|
|
67
|
-
out.R[k] += r;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
109
|
var INSTRUMENTS = ["keys", "pluck", "pad", "bass", "sub", "lead", "bell", "musicbox"];
|
|
71
110
|
var VOICES = {
|
|
72
111
|
// electric piano: two FM operators (tine + bell), a little stereo chorus
|
|
73
112
|
keys(m, dur, vel, out, start, rnd, o) {
|
|
74
113
|
const f = mtof(m), rel = o.release ?? 0.5, total = dur + rel + 1.2;
|
|
75
|
-
const n = Math.floor(Math.min(total, 6) * SR), idx = 1.1 + 2.2 * vel, det = 1 + (rnd() - 0.5) * 2e-3;
|
|
76
|
-
|
|
114
|
+
const n = Math.min(Math.floor(Math.min(total, 6) * SR), Math.ceil((dur + rel) * SR) + 2), idx = 1.1 + 2.2 * vel, det = 1 + (rnd() - 0.5) * 2e-3;
|
|
115
|
+
const lim = Math.min(n, out.L.length - start);
|
|
116
|
+
const tb = keysTables(f, lim), dcy = tb.decay, s14 = tb.s14, s1 = tb.s1, e18 = tb.e18, e32 = tb.e32;
|
|
117
|
+
for (let i = 0; i < lim; i++) {
|
|
77
118
|
const t = i / SR;
|
|
78
|
-
const decay =
|
|
79
|
-
const mod =
|
|
119
|
+
const decay = dcy[i];
|
|
120
|
+
const mod = s14[i] * idx * 0.12 * e18[i] + s1[i] * idx * e32[i];
|
|
80
121
|
const body = Math.sin(TAU * f * t + mod) * decay;
|
|
81
122
|
const body2 = Math.sin(TAU * f * det * t + mod * 0.9) * decay;
|
|
82
123
|
const env = t < dur ? 1 : Math.max(0, 1 - (t - dur) / rel);
|
|
83
124
|
const a = Math.min(1, t / 4e-3) * env * 0.5 * vel;
|
|
84
|
-
|
|
125
|
+
{
|
|
126
|
+
const wl = a * (body * 0.7 + body2 * 0.3), wr = a * (body * 0.3 + body2 * 0.7);
|
|
127
|
+
out.L[start + i] += wl;
|
|
128
|
+
out.R[start + i] += wr;
|
|
129
|
+
}
|
|
85
130
|
}
|
|
86
131
|
},
|
|
87
132
|
// plucked string (Karplus–Strong with a darker loss filter): guitar / harp / koto
|
|
@@ -92,36 +137,65 @@ var VOICES = {
|
|
|
92
137
|
const rel = o.release ?? 0.25, total = Math.min(dur + rel + 0.4, 5), n = Math.floor(total * SR), loss = 0.9965 - 0.5 / (f + 100);
|
|
93
138
|
let p = 0, prev = 0;
|
|
94
139
|
const pan = (rnd() - 0.5) * 0.3;
|
|
95
|
-
for (let i = 0; i <
|
|
140
|
+
for (let i = 0, lim = Math.min(n, out.L.length - start); i < lim; i++) {
|
|
96
141
|
const cur = buf[p], nxt = buf[(p + 1) % len];
|
|
97
142
|
buf[p] = loss * 0.5 * (cur + nxt);
|
|
98
143
|
p = (p + 1) % len;
|
|
99
144
|
const t = i / SR, env = t < dur ? 1 : Math.max(0, 1 - (t - dur) / rel);
|
|
100
145
|
const y = (cur - prev * 0.2) * env * 0.55 * vel;
|
|
101
146
|
prev = cur;
|
|
102
|
-
|
|
147
|
+
{
|
|
148
|
+
const wl = y * (1 - pan), wr = y * (1 + pan);
|
|
149
|
+
out.L[start + i] += wl;
|
|
150
|
+
out.R[start + i] += wr;
|
|
151
|
+
}
|
|
103
152
|
}
|
|
104
153
|
},
|
|
105
154
|
// warm pad: five detuned band-limited saws through a slow low-pass
|
|
106
155
|
pad(m, dur, vel, out, start, rnd, o) {
|
|
107
156
|
const f = mtof(m), A = o.attack ?? 0.7, R = o.release ?? 1.4, n = Math.floor((dur + R) * SR);
|
|
108
|
-
const
|
|
157
|
+
const cs = [-0.14, -0.07, 0, 0.07, 0.14];
|
|
158
|
+
const st = (k) => f * 2 ** (cs[k] / 12 * 0.6) / SR, gL = (k) => 1 - (k - 2) / 2.5, gR = (k) => 1 + (k - 2) / 2.5;
|
|
159
|
+
let p0 = rnd(), p1 = rnd(), p2 = rnd(), p3 = rnd(), p4 = rnd();
|
|
160
|
+
const d0 = st(0), d1 = st(1), d2 = st(2), d3 = st(3), d4 = st(4);
|
|
161
|
+
const gl0 = gL(0), gl1 = gL(1), gl2 = gL(2), gl3 = gL(3), gl4 = gL(4), gr0 = gR(0), gr1 = gR(1), gr2 = gR(2), gr3 = gR(3), gr4 = gR(4);
|
|
109
162
|
const cut = Math.min(1800, 500 + f * 1.5);
|
|
110
163
|
const lp = new Biquad("lp", cut, 0.6), lp2 = new Biquad("lp", cut, 0.6);
|
|
111
|
-
for (let i = 0; i <
|
|
164
|
+
for (let i = 0, lim = Math.min(n, out.L.length - start); i < lim; i++) {
|
|
112
165
|
const t = i / SR;
|
|
113
|
-
let l = 0, r = 0;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
166
|
+
let l = 0, r = 0, sv;
|
|
167
|
+
p0 += d0;
|
|
168
|
+
if (p0 >= 1) p0 -= 1;
|
|
169
|
+
sv = saw(p0, d0);
|
|
170
|
+
l += sv * gl0 * 0.5;
|
|
171
|
+
r += sv * gr0 * 0.5;
|
|
172
|
+
p1 += d1;
|
|
173
|
+
if (p1 >= 1) p1 -= 1;
|
|
174
|
+
sv = saw(p1, d1);
|
|
175
|
+
l += sv * gl1 * 0.5;
|
|
176
|
+
r += sv * gr1 * 0.5;
|
|
177
|
+
p2 += d2;
|
|
178
|
+
if (p2 >= 1) p2 -= 1;
|
|
179
|
+
sv = saw(p2, d2);
|
|
180
|
+
l += sv * gl2 * 0.5;
|
|
181
|
+
r += sv * gr2 * 0.5;
|
|
182
|
+
p3 += d3;
|
|
183
|
+
if (p3 >= 1) p3 -= 1;
|
|
184
|
+
sv = saw(p3, d3);
|
|
185
|
+
l += sv * gl3 * 0.5;
|
|
186
|
+
r += sv * gr3 * 0.5;
|
|
187
|
+
p4 += d4;
|
|
188
|
+
if (p4 >= 1) p4 -= 1;
|
|
189
|
+
sv = saw(p4, d4);
|
|
190
|
+
l += sv * gl4 * 0.5;
|
|
191
|
+
r += sv * gr4 * 0.5;
|
|
122
192
|
const env = t < dur ? Math.min(1, t / A) : Math.max(0, Math.min(1, dur / A) * (1 - (t - dur) / R));
|
|
123
193
|
const g = env * 0.11 * vel;
|
|
124
|
-
|
|
194
|
+
{
|
|
195
|
+
const wl = lp.run(l) * g, wr = lp2.run(r) * g;
|
|
196
|
+
out.L[start + i] += wl;
|
|
197
|
+
out.R[start + i] += wr;
|
|
198
|
+
}
|
|
125
199
|
}
|
|
126
200
|
},
|
|
127
201
|
// synth bass: saw + sine sub, filter envelope
|
|
@@ -129,7 +203,7 @@ var VOICES = {
|
|
|
129
203
|
const f = mtof(m), rel = o.release ?? 0.12, n = Math.floor((dur + rel) * SR);
|
|
130
204
|
let ph = 0, ph2 = 0;
|
|
131
205
|
const lp = new Biquad("lp", 400, 1.1);
|
|
132
|
-
for (let i = 0; i <
|
|
206
|
+
for (let i = 0, lim = Math.min(n, out.L.length - start); i < lim; i++) {
|
|
133
207
|
const t = i / SR, dt = f / SR;
|
|
134
208
|
ph = (ph + dt) % 1;
|
|
135
209
|
ph2 = (ph2 + dt) % 1;
|
|
@@ -137,19 +211,27 @@ var VOICES = {
|
|
|
137
211
|
const s = lp.run(saw(ph, dt)) * 0.55 + Math.sin(TAU * ph2) * 0.55;
|
|
138
212
|
const env = t < dur ? Math.min(1, t / 6e-3) * (0.75 + 0.25 * Math.exp(-t * 4)) : Math.max(0, 1 - (t - dur) / rel) * 0.75;
|
|
139
213
|
const y = s * env * 0.5 * vel;
|
|
140
|
-
|
|
214
|
+
{
|
|
215
|
+
const wl = y, wr = y;
|
|
216
|
+
out.L[start + i] += wl;
|
|
217
|
+
out.R[start + i] += wr;
|
|
218
|
+
}
|
|
141
219
|
}
|
|
142
220
|
},
|
|
143
221
|
// a pure sine bass: a soft heartbeat or sub (no filter sweep, hardly any upper harmonics)
|
|
144
222
|
sub(m, dur, vel, out, start, _rnd, o) {
|
|
145
223
|
const f = mtof(m), rel = o.release ?? 0.2, n = Math.floor((dur + rel) * SR);
|
|
146
224
|
let ph = 0;
|
|
147
|
-
for (let i = 0; i <
|
|
225
|
+
for (let i = 0, lim = Math.min(n, out.L.length - start); i < lim; i++) {
|
|
148
226
|
const t = i / SR;
|
|
149
227
|
ph += TAU * f / SR;
|
|
150
228
|
const env = t < dur ? Math.min(1, t / (o.attack ?? 0.012)) * (0.8 + 0.2 * Math.exp(-t * 5)) : Math.max(0, 1 - (t - dur) / rel) * 0.8;
|
|
151
229
|
const y = (Math.sin(ph) + 0.12 * Math.sin(2 * ph)) * env * 0.6 * vel;
|
|
152
|
-
|
|
230
|
+
{
|
|
231
|
+
const wl = y, wr = y;
|
|
232
|
+
out.L[start + i] += wl;
|
|
233
|
+
out.R[start + i] += wr;
|
|
234
|
+
}
|
|
153
235
|
}
|
|
154
236
|
},
|
|
155
237
|
// lead: soft saw / triangle with a delayed vibrato
|
|
@@ -157,7 +239,7 @@ var VOICES = {
|
|
|
157
239
|
const f = mtof(m), rel = o.release ?? 0.18, A = o.attack ?? 0.02, n = Math.floor((dur + rel) * SR);
|
|
158
240
|
let ph = rnd(), ph2 = rnd();
|
|
159
241
|
const lp = new Biquad("lp", 2600 + 1800 * vel, 0.8);
|
|
160
|
-
for (let i = 0; i <
|
|
242
|
+
for (let i = 0, lim = Math.min(n, out.L.length - start); i < lim; i++) {
|
|
161
243
|
const t = i / SR, vib = 1 + 35e-4 * Math.sin(TAU * 5.3 * t) * Math.min(1, Math.max(0, (t - 0.18) / 0.3));
|
|
162
244
|
const dt = f * vib / SR;
|
|
163
245
|
ph = (ph + dt) % 1;
|
|
@@ -165,38 +247,56 @@ var VOICES = {
|
|
|
165
247
|
const tri = 4 * Math.abs(ph - 0.5) - 1;
|
|
166
248
|
const s = lp.run(saw(ph2, dt) * 0.35 + tri * 0.65);
|
|
167
249
|
const y = s * adsr(t, dur, A, 0.15, 0.7, rel) * 0.28 * vel;
|
|
168
|
-
|
|
250
|
+
{
|
|
251
|
+
const wl = y * 0.9, wr = y * 1.1;
|
|
252
|
+
out.L[start + i] += wl;
|
|
253
|
+
out.R[start + i] += wr;
|
|
254
|
+
}
|
|
169
255
|
}
|
|
170
256
|
},
|
|
171
257
|
// bell / glockenspiel: inharmonic FM; `ring` is how many seconds it keeps sounding
|
|
172
258
|
bell(m, dur, vel, out, start, rnd, o) {
|
|
173
259
|
const f = mtof(m), ring = o.ring ?? 2.5, n = Math.floor(Math.min(dur + ring, 6) * SR), pan = (rnd() - 0.5) * 0.6;
|
|
174
260
|
const k = 1.5 * (2.5 / ring);
|
|
175
|
-
|
|
261
|
+
const lim = Math.min(n, out.L.length - start);
|
|
262
|
+
const tb = bellTables(f, k, lim), s35 = tb.s35, e5 = tb.e5, ek = tb.ek, s276 = tb.s276, e4 = tb.e4;
|
|
263
|
+
for (let i = 0; i < lim; i++) {
|
|
176
264
|
const t = i / SR;
|
|
177
|
-
const mod =
|
|
178
|
-
const s = Math.sin(TAU * f * t + mod) *
|
|
265
|
+
const mod = s35[i] * 1.6 * e5[i];
|
|
266
|
+
const s = Math.sin(TAU * f * t + mod) * ek[i] + s276[i] * 0.25 * e4[i];
|
|
179
267
|
const y = s * Math.min(1, t / 2e-3) * 0.3 * vel;
|
|
180
|
-
|
|
268
|
+
{
|
|
269
|
+
const wl = y * (1 - pan), wr = y * (1 + pan);
|
|
270
|
+
out.L[start + i] += wl;
|
|
271
|
+
out.R[start + i] += wr;
|
|
272
|
+
}
|
|
181
273
|
}
|
|
182
274
|
},
|
|
183
275
|
// music box: a bright tine with a strong upper partial and a short, dry ring
|
|
184
276
|
musicbox(m, dur, vel, out, start, rnd, o) {
|
|
185
277
|
const f = mtof(m), ring = o.ring ?? 1.3, n = Math.floor(Math.min(dur + ring, 4) * SR), pan = (rnd() - 0.5) * 0.4;
|
|
186
|
-
for (let i = 0; i <
|
|
278
|
+
for (let i = 0, lim = Math.min(n, out.L.length - start); i < lim; i++) {
|
|
187
279
|
const t = i / SR;
|
|
188
280
|
const s = Math.sin(TAU * f * t) * Math.exp(-t * (3.2 / ring * 1.3)) + Math.sin(TAU * f * 4 * t) * 0.22 * Math.exp(-t * (9 / ring)) + Math.sin(TAU * f * 6.8 * t) * 0.08 * Math.exp(-t * 18);
|
|
189
281
|
const y = s * Math.min(1, t / 15e-4) * 0.34 * vel;
|
|
190
|
-
|
|
282
|
+
{
|
|
283
|
+
const wl = y * (1 - pan), wr = y * (1 + pan);
|
|
284
|
+
out.L[start + i] += wl;
|
|
285
|
+
out.R[start + i] += wr;
|
|
286
|
+
}
|
|
191
287
|
}
|
|
192
288
|
}
|
|
193
289
|
};
|
|
194
290
|
var DRUMS = ["kick", "snare", "hat", "openhat", "clap", "rim", "tom", "crash", "shaker", "sleigh"];
|
|
195
291
|
function hitDrum(kind, vel, out, start, rnd) {
|
|
196
|
-
const mono = (n, f) => {
|
|
292
|
+
const mono = (n, f, gl = 1, gr = 1) => {
|
|
293
|
+
const lim = Math.min(n, out.L.length - start), L = out.L, R = out.R;
|
|
197
294
|
for (let i = 0; i < n; i++) {
|
|
198
|
-
const
|
|
199
|
-
|
|
295
|
+
const o = f(i / SR);
|
|
296
|
+
if (i < lim) {
|
|
297
|
+
L[start + i] += o * gl;
|
|
298
|
+
R[start + i] += o * gr;
|
|
299
|
+
}
|
|
200
300
|
}
|
|
201
301
|
};
|
|
202
302
|
const len = (s) => Math.floor(s * SR);
|
|
@@ -205,7 +305,7 @@ function hitDrum(kind, vel, out, start, rnd) {
|
|
|
205
305
|
mono(len(0.5), (t) => {
|
|
206
306
|
ph += TAU * (45 + 110 * Math.exp(-t * 28)) / SR;
|
|
207
307
|
const o = (Math.sin(ph) * Math.exp(-t * 7.5) + (t < 4e-3 ? (rnd() - 0.5) * 0.5 : 0)) * 0.95 * vel;
|
|
208
|
-
return
|
|
308
|
+
return o;
|
|
209
309
|
});
|
|
210
310
|
} else if (kind === "snare") {
|
|
211
311
|
const bp = new Biquad("bp", 1900, 0.9), hp = new Biquad("hp", 700, 0.7);
|
|
@@ -214,50 +314,50 @@ function hitDrum(kind, vel, out, start, rnd) {
|
|
|
214
314
|
ph += TAU * (185 - 40 * t) / SR;
|
|
215
315
|
const nz = hp.run(bp.run(rnd() * 2 - 1)) * 2.2;
|
|
216
316
|
const o = (nz * Math.exp(-t * 17) + Math.sin(ph) * Math.exp(-t * 26) * 0.6) * 0.6 * vel;
|
|
217
|
-
return
|
|
218
|
-
});
|
|
317
|
+
return o;
|
|
318
|
+
}, 0.95, 1.05);
|
|
219
319
|
} else if (kind === "clap") {
|
|
220
320
|
const bp = new Biquad("bp", 1500, 1.2);
|
|
221
321
|
mono(len(0.35), (t) => {
|
|
222
322
|
const burst = t < 0.033 ? Math.exp(-(t * 1e3 % 11) * 0.5) : Math.exp(-(t - 0.033) * 22);
|
|
223
323
|
const o = bp.run(rnd() * 2 - 1) * 2.4 * burst * 0.5 * vel;
|
|
224
|
-
return
|
|
225
|
-
});
|
|
324
|
+
return o;
|
|
325
|
+
}, 1, 0.9);
|
|
226
326
|
} else if (kind === "hat" || kind === "openhat") {
|
|
227
327
|
const hp = new Biquad("hp", 7500, 0.8), dec = kind === "hat" ? 55 : 9;
|
|
228
328
|
mono(len(kind === "hat" ? 0.12 : 0.6), (t) => {
|
|
229
329
|
const o = hp.run(rnd() * 2 - 1) * Math.exp(-t * dec) * 0.35 * vel;
|
|
230
|
-
return
|
|
231
|
-
});
|
|
330
|
+
return o;
|
|
331
|
+
}, 0.8, 1.2);
|
|
232
332
|
} else if (kind === "rim") {
|
|
233
333
|
let ph = 0;
|
|
234
334
|
const bp = new Biquad("bp", 3200, 4);
|
|
235
335
|
mono(len(0.1), (t) => {
|
|
236
336
|
ph += TAU * 1750 / SR;
|
|
237
337
|
const o = (Math.sin(ph) * 0.5 + bp.run(rnd() * 2 - 1)) * Math.exp(-t * 70) * 0.5 * vel;
|
|
238
|
-
return
|
|
338
|
+
return o;
|
|
239
339
|
});
|
|
240
340
|
} else if (kind === "tom") {
|
|
241
341
|
let ph = 0;
|
|
242
342
|
mono(len(0.5), (t) => {
|
|
243
343
|
ph += TAU * (95 + 70 * Math.exp(-t * 15)) / SR;
|
|
244
344
|
const o = Math.sin(ph) * Math.exp(-t * 7) * 0.7 * vel;
|
|
245
|
-
return
|
|
345
|
+
return o;
|
|
246
346
|
});
|
|
247
347
|
} else if (kind === "crash") {
|
|
248
348
|
const hp = new Biquad("hp", 5200, 0.7), bp = new Biquad("bp", 9e3, 0.6);
|
|
249
349
|
mono(len(1.8), (t) => {
|
|
250
350
|
const nz = rnd() * 2 - 1;
|
|
251
351
|
const o = (hp.run(nz) * 0.7 + bp.run(nz) * 0.5) * (0.55 * Math.exp(-t * 2.6) + 0.45 * Math.exp(-t * 11)) * 0.5 * vel;
|
|
252
|
-
return
|
|
253
|
-
});
|
|
352
|
+
return o;
|
|
353
|
+
}, 0.9, 1.1);
|
|
254
354
|
} else if (kind === "shaker") {
|
|
255
355
|
const bp = new Biquad("bp", 6500, 1.4);
|
|
256
356
|
mono(len(0.16), (t) => {
|
|
257
357
|
const env = (t < 0.018 ? t / 0.018 : 1) * Math.exp(-t * 28);
|
|
258
358
|
const o = bp.run(rnd() * 2 - 1) * env * 1.4 * 0.3 * vel;
|
|
259
|
-
return
|
|
260
|
-
});
|
|
359
|
+
return o;
|
|
360
|
+
}, 0.85, 1.15);
|
|
261
361
|
} else {
|
|
262
362
|
const bp = new Biquad("bp", 7800, 1);
|
|
263
363
|
const partials = [4200, 5630, 6900, 8350];
|
|
@@ -265,8 +365,8 @@ function hitDrum(kind, vel, out, start, rnd) {
|
|
|
265
365
|
let s = 0;
|
|
266
366
|
for (let k = 0; k < partials.length; k++) s += Math.sin(TAU * partials[k] * t * (1 + k * 7e-4)) * (0.5 + 0.5 * Math.sin(TAU * (19 + k * 3.1) * t + k)) * Math.exp(-t * (7 + k * 2));
|
|
267
367
|
const o = (s * 0.11 + bp.run(rnd() * 2 - 1) * Math.exp(-t * 16) * 0.5) * Math.min(1, t / 3e-3) * vel * 0.8;
|
|
268
|
-
return
|
|
269
|
-
});
|
|
368
|
+
return o;
|
|
369
|
+
}, 0.85, 1.15);
|
|
270
370
|
}
|
|
271
371
|
}
|
|
272
372
|
function* reverbSteps(send, out, wet, size = 0.8) {
|
|
@@ -277,30 +377,40 @@ function* reverbSteps(send, out, wet, size = 0.8) {
|
|
|
277
377
|
c: [1116, 1188, 1277, 1356, 1422, 1491].map((l) => comb(l + off)),
|
|
278
378
|
a: [556, 441, 341].map((l) => ({ b: new Float32Array(Math.max(8, Math.round((l + off) * scale))), i: 0 }))
|
|
279
379
|
});
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
for (
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
c.i = (c.i + 1) % c.b.length;
|
|
287
|
-
y += o;
|
|
288
|
-
}
|
|
289
|
-
for (const a of ch.a) {
|
|
290
|
-
const o = a.b[a.i], inp = y;
|
|
291
|
-
a.b[a.i] = inp + o * 0.5;
|
|
292
|
-
a.i = (a.i + 1) % a.b.length;
|
|
293
|
-
y = o - inp;
|
|
380
|
+
const chL = mk(0), chR = mk(23);
|
|
381
|
+
const block = (i, stop) => {
|
|
382
|
+
for (; i < stop; i++) {
|
|
383
|
+
const m = (sL[i] + sR[i]) * 0.5;
|
|
384
|
+
L[i] += runFlat(m, chL) * wet;
|
|
385
|
+
R[i] += runFlat(m, chR) * wet;
|
|
294
386
|
}
|
|
295
|
-
return y;
|
|
296
387
|
};
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
388
|
+
for (let i = 0; i < L.length; ) {
|
|
389
|
+
yield i / L.length;
|
|
390
|
+
const stop = Math.min(L.length, (i | 16383) + 1);
|
|
391
|
+
block(i, stop);
|
|
392
|
+
i = stop;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
function runFlat(x, ch) {
|
|
396
|
+
let y = 0;
|
|
397
|
+
const cs = ch.c, as = ch.a;
|
|
398
|
+
for (let k = 0; k < 6; k++) {
|
|
399
|
+
const c = cs[k], b = c.b;
|
|
400
|
+
const o = b[c.i];
|
|
401
|
+
c.d = o * (1 - c.damp) + c.d * c.damp;
|
|
402
|
+
b[c.i] = x * 0.03 + c.d * c.fb;
|
|
403
|
+
c.i = c.i + 1 === b.length ? 0 : c.i + 1;
|
|
404
|
+
y += o;
|
|
405
|
+
}
|
|
406
|
+
for (let k = 0; k < 3; k++) {
|
|
407
|
+
const a = as[k], b = a.b;
|
|
408
|
+
const o = b[a.i], inp = y;
|
|
409
|
+
b[a.i] = inp + o * 0.5;
|
|
410
|
+
a.i = a.i + 1 === b.length ? 0 : a.i + 1;
|
|
411
|
+
y = o - inp;
|
|
303
412
|
}
|
|
413
|
+
return y;
|
|
304
414
|
}
|
|
305
415
|
|
|
306
416
|
// src/audio/music/notation.ts
|
|
@@ -722,6 +832,18 @@ function rng(seed) {
|
|
|
722
832
|
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
723
833
|
};
|
|
724
834
|
}
|
|
835
|
+
function extent(b) {
|
|
836
|
+
let lo = b.L.length, hi = -1;
|
|
837
|
+
for (let i = 0; i < b.L.length; i++) if (b.L[i] !== 0 || b.R[i] !== 0) {
|
|
838
|
+
lo = i;
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
for (let i = b.L.length - 1; i >= lo; i--) if (b.L[i] !== 0 || b.R[i] !== 0) {
|
|
842
|
+
hi = i;
|
|
843
|
+
break;
|
|
844
|
+
}
|
|
845
|
+
return [lo, hi];
|
|
846
|
+
}
|
|
725
847
|
function musicLength(m) {
|
|
726
848
|
return m.seconds + m.tail;
|
|
727
849
|
}
|
|
@@ -744,6 +866,37 @@ function musicBeatTimes(m, until = m.seconds) {
|
|
|
744
866
|
}
|
|
745
867
|
return times.filter((t) => t < until);
|
|
746
868
|
}
|
|
869
|
+
function toneRun(scratch, a, b, i, stop, end) {
|
|
870
|
+
const L = scratch.L, R = scratch.R;
|
|
871
|
+
const a0 = a[0], a1 = a[1], b0 = b[0], b1 = b[1];
|
|
872
|
+
for (; i < stop && (i < end || !(a0.settled() && a1.settled() && b0.settled() && b1.settled())); i++) {
|
|
873
|
+
L[i] = a1.run(a0.run(L[i]));
|
|
874
|
+
R[i] = b1.run(b0.run(R[i]));
|
|
875
|
+
}
|
|
876
|
+
return i;
|
|
877
|
+
}
|
|
878
|
+
function mixRun(scratch, out, send, i, stop, level, constant, g, gl, gr, rv, sampleRate) {
|
|
879
|
+
const sL = scratch.L, sR = scratch.R, oL = out.L, oR = out.R, eL = send.L, eR = send.R;
|
|
880
|
+
for (; i < stop; i++) {
|
|
881
|
+
if (!constant) g = level(i / sampleRate);
|
|
882
|
+
const l = sL[i] * g * gl, r = sR[i] * g * gr;
|
|
883
|
+
oL[i] += l;
|
|
884
|
+
oR[i] += r;
|
|
885
|
+
eL[i] += l * rv;
|
|
886
|
+
eR[i] += r * rv;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
function tanhRun(out, i, stop, acc) {
|
|
890
|
+
const L = out.L, R = out.R;
|
|
891
|
+
let peak = acc[0], sum = acc[1];
|
|
892
|
+
for (; i < stop; i++) {
|
|
893
|
+
const l = L[i] = Math.tanh(L[i] * 0.9), r = R[i] = Math.tanh(R[i] * 0.9);
|
|
894
|
+
peak = Math.max(peak, Math.abs(l), Math.abs(r));
|
|
895
|
+
sum += l * l + r * r;
|
|
896
|
+
}
|
|
897
|
+
acc[0] = peak;
|
|
898
|
+
acc[1] = sum;
|
|
899
|
+
}
|
|
747
900
|
function* renderMusicSteps(m, sampleRate, length, loop) {
|
|
748
901
|
setSampleRate(sampleRate);
|
|
749
902
|
const units = m.tracks.length + (m.drums.length ? 1 : 0) + 2;
|
|
@@ -762,6 +915,15 @@ function* renderMusicSteps(m, sampleRate, length, loop) {
|
|
|
762
915
|
const levelAt = (vol) => {
|
|
763
916
|
if (typeof vol === "number") return () => vol;
|
|
764
917
|
const pts = vol.map(([b, v]) => [map.seconds(b), v]);
|
|
918
|
+
if (!loop && pts.every((p, i) => i === 0 || p[0] >= pts[i - 1][0])) {
|
|
919
|
+
let j = 1;
|
|
920
|
+
return (sec) => {
|
|
921
|
+
if (sec <= pts[0][0]) return pts[0][1];
|
|
922
|
+
while (j < pts.length && !(sec < pts[j][0])) j++;
|
|
923
|
+
if (j < pts.length) return pts[j - 1][1] + (pts[j][1] - pts[j - 1][1]) * (sec - pts[j - 1][0]) / (pts[j][0] - pts[j - 1][0]);
|
|
924
|
+
return pts[pts.length - 1][1];
|
|
925
|
+
};
|
|
926
|
+
}
|
|
765
927
|
return (sec) => {
|
|
766
928
|
const t = loop && loopSec > 0 ? sec % loopSec : sec;
|
|
767
929
|
if (t <= pts[0][0]) return pts[0][1];
|
|
@@ -773,8 +935,6 @@ function* renderMusicSteps(m, sampleRate, length, loop) {
|
|
|
773
935
|
};
|
|
774
936
|
for (const tr of m.tracks) {
|
|
775
937
|
const inst = VOICES[tr.inst];
|
|
776
|
-
scratch.L.fill(0);
|
|
777
|
-
scratch.R.fill(0);
|
|
778
938
|
for (let r = 0; r < repeats; r++) {
|
|
779
939
|
const offset = r * loopSec;
|
|
780
940
|
for (let ei = 0; ei < tr.events.length; ei++) {
|
|
@@ -791,28 +951,36 @@ function* renderMusicSteps(m, sampleRate, length, loop) {
|
|
|
791
951
|
});
|
|
792
952
|
}
|
|
793
953
|
}
|
|
954
|
+
const [lo, hi] = extent(scratch);
|
|
955
|
+
let end = hi + 1;
|
|
794
956
|
if (tr.tone < 1) {
|
|
795
957
|
const fc = 400 * 50 ** tr.tone;
|
|
796
958
|
const a = [new Biquad("lp", fc, 0.7), new Biquad("lp", fc, 0.7)], b = [new Biquad("lp", fc, 0.7), new Biquad("lp", fc, 0.7)];
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
959
|
+
let i = lo;
|
|
960
|
+
for (; ; ) {
|
|
961
|
+
const stop = Math.min(total, (i | 65535) + 1);
|
|
962
|
+
const j = toneRun(scratch, a, b, i, stop, end);
|
|
963
|
+
if (j < stop || j >= total) {
|
|
964
|
+
i = j;
|
|
965
|
+
break;
|
|
966
|
+
}
|
|
967
|
+
i = j;
|
|
968
|
+
yield (unit + 0.9) / units;
|
|
801
969
|
}
|
|
970
|
+
end = Math.max(end, i);
|
|
802
971
|
}
|
|
803
972
|
const level = levelAt(tr.vol), pan = Math.max(-1, Math.min(1, tr.pan));
|
|
804
973
|
const gl = Math.cos((pan + 1) * Math.PI / 4) * 1.3, gr = Math.sin((pan + 1) * Math.PI / 4) * 1.3;
|
|
805
974
|
const constant = typeof tr.vol === "number";
|
|
806
975
|
let g = constant ? level(0) : 0;
|
|
807
|
-
for (let i =
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
out.R[i] += r;
|
|
813
|
-
send.L[i] += l * tr.reverb;
|
|
814
|
-
send.R[i] += r * tr.reverb;
|
|
976
|
+
for (let i = lo; i < end; ) {
|
|
977
|
+
const stop = Math.min(end, (i | 65535) + 1);
|
|
978
|
+
mixRun(scratch, out, send, i, stop, level, constant, g, gl, gr, tr.reverb, sampleRate);
|
|
979
|
+
i = stop;
|
|
980
|
+
yield (unit + 0.95) / units;
|
|
815
981
|
}
|
|
982
|
+
scratch.L.fill(0, lo, end);
|
|
983
|
+
scratch.R.fill(0, lo, end);
|
|
816
984
|
unit++;
|
|
817
985
|
}
|
|
818
986
|
if (m.drums.length) {
|
|
@@ -844,13 +1012,14 @@ function* renderMusicSteps(m, sampleRate, length, loop) {
|
|
|
844
1012
|
}
|
|
845
1013
|
for (const f of reverbSteps(send, out, m.reverb, 0.8)) yield (unit + f) / units;
|
|
846
1014
|
unit++;
|
|
847
|
-
|
|
848
|
-
for (let i = 0; i < total;
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
1015
|
+
const acc = new Float64Array(2);
|
|
1016
|
+
for (let i = 0; i < total; ) {
|
|
1017
|
+
const stop = Math.min(total, (i | 65535) + 1);
|
|
1018
|
+
tanhRun(out, i, stop, acc);
|
|
1019
|
+
i = stop;
|
|
1020
|
+
yield (unit + 0.5 * i / total) / units;
|
|
853
1021
|
}
|
|
1022
|
+
const peak = acc[0], sum = acc[1];
|
|
854
1023
|
const rms = Math.sqrt(sum / (2 * total));
|
|
855
1024
|
const gain = peak > 0 ? Math.min(MUSIC_PEAK / peak, RMS_CAP / Math.max(rms, 1e-9)) : 0;
|
|
856
1025
|
const fade = Math.min(Math.floor(0.4 * sampleRate), total >> 2);
|
|
@@ -859,6 +1028,7 @@ function* renderMusicSteps(m, sampleRate, length, loop) {
|
|
|
859
1028
|
out.L[i] *= gain * f;
|
|
860
1029
|
out.R[i] *= gain * f;
|
|
861
1030
|
}
|
|
1031
|
+
clearVoiceTables();
|
|
862
1032
|
return [out.L, out.R];
|
|
863
1033
|
}
|
|
864
1034
|
function renderMusic(m, sampleRate, length, loop = false) {
|
|
@@ -878,5 +1048,5 @@ async function renderMusicAsync(m, sampleRate, length, loop = false, pace) {
|
|
|
878
1048
|
}
|
|
879
1049
|
|
|
880
1050
|
export { CHORD_KINDS, DEFAULT_TAIL, DRUMS, INSTRUMENTS, MAX_SECONDS, MUSIC_PEAK, TempoMap, chordToMidi, musicBeatTimes, musicKey, musicLength, noteToMidi, parseDrumGrid, parseNotes, renderMusic, renderMusicAsync, resolveMusic };
|
|
881
|
-
//# sourceMappingURL=music-
|
|
882
|
-
//# sourceMappingURL=music-
|
|
1051
|
+
//# sourceMappingURL=music-72YJAMXH.js.map
|
|
1052
|
+
//# sourceMappingURL=music-72YJAMXH.js.map
|