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