pixi-effects 0.27.0 → 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 +15 -0
- package/README.md +9 -5
- package/ai/chat-template.html +3 -3
- package/dist/{Base-CVezIEdo.d.ts → Base-CKGl6jCo.d.ts} +1 -1
- package/dist/{Base-DzC3i919.d.cts → Base-DjhdL8B1.d.cts} +1 -1
- package/dist/Composition-DRCTWIYH.cjs +16 -0
- package/dist/{Composition-QCOWQSDB.cjs.map → Composition-DRCTWIYH.cjs.map} +1 -1
- package/dist/Composition-TZHVYIGH.js +7 -0
- package/dist/{Composition-4TYDRRRY.js.map → Composition-TZHVYIGH.js.map} +1 -1
- package/dist/Controller.d.cts +2 -2
- package/dist/Controller.d.ts +2 -2
- package/dist/{Movie-CQ0Nz62a.d.cts → Movie-CbYwTs6U.d.cts} +1 -1
- package/dist/{Movie-M9dKm9dI.d.ts → Movie-ILKq2fw_.d.ts} +1 -1
- package/dist/Presenter.d.cts +2 -2
- package/dist/Presenter.d.ts +2 -2
- package/dist/{chunk-TGJACVLD.js → chunk-BQNNZEAX.js} +5 -5
- package/dist/chunk-BQNNZEAX.js.map +1 -0
- package/dist/{chunk-NDR2VQFV.cjs → chunk-C7HJJ7MZ.cjs} +61 -61
- package/dist/{chunk-NDR2VQFV.cjs.map → chunk-C7HJJ7MZ.cjs.map} +1 -1
- package/dist/{chunk-CKTS6G6I.js → chunk-K3F2YKL4.js} +3 -3
- package/dist/{chunk-CKTS6G6I.js.map → chunk-K3F2YKL4.js.map} +1 -1
- package/dist/{chunk-RQMI7EJT.cjs → chunk-YOV6MEXH.cjs} +5 -5
- package/dist/chunk-YOV6MEXH.cjs.map +1 -0
- package/dist/index.cjs +58 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +31 -13
- package/dist/index.js.map +1 -1
- package/dist/loader.css +1 -1
- package/dist/{music-4O367SPR.cjs → music-6MTHQEXS.cjs} +297 -99
- package/dist/music-6MTHQEXS.cjs.map +1 -0
- package/dist/{music-3O5MDQXY.js → music-72YJAMXH.js} +297 -100
- package/dist/music-72YJAMXH.js.map +1 -0
- package/dist/three.cjs +5 -5
- package/dist/three.d.cts +2 -2
- package/dist/three.d.ts +2 -2
- package/dist/three.js +1 -1
- package/dist/{types-DUVefWiB.d.cts → types-BNVsBBZf.d.cts} +2 -0
- package/dist/{types-DUVefWiB.d.ts → types-BNVsBBZf.d.ts} +2 -0
- package/llms-full.txt +1 -1
- package/package.json +2 -2
- package/skills/pixi-effects/SKILL.md +1 -1
- package/skills/pixi-effects/template.html +6 -6
- package/dist/Composition-4TYDRRRY.js +0 -7
- package/dist/Composition-QCOWQSDB.cjs +0 -16
- package/dist/chunk-RQMI7EJT.cjs.map +0 -1
- package/dist/chunk-TGJACVLD.js.map +0 -1
- package/dist/music-3O5MDQXY.js.map +0 -1
- package/dist/music-4O367SPR.cjs.map +0 -1
package/dist/loader.css
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* pixi-effects loader: one line of HTML on the page, a few lines of CSS, no JavaScript of your own.
|
|
3
3
|
*
|
|
4
|
-
* <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.27.
|
|
4
|
+
* <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.27.2/dist/loader.css">
|
|
5
5
|
* <div class="stage" style="position: relative"> <!-- any box the canvas sits in, with position: relative -->
|
|
6
6
|
* <canvas id="stage" width="1280" height="720"></canvas>
|
|
7
7
|
* <div class="pe-loader" data-label="LOADING"></div> <!-- or class="pe-loader pe-loader--bar" -->
|
|
@@ -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,11 +367,11 @@ 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
|
-
function
|
|
374
|
+
function* reverbSteps(send, out, wet, size = 0.8) {
|
|
275
375
|
const L = out.L, R = out.R, sL = send.L, sR = send.R;
|
|
276
376
|
const scale = SR / 44100;
|
|
277
377
|
const comb = (len) => ({ b: new Float32Array(Math.max(8, Math.round(len * scale))), i: 0, fb: size, d: 0, damp: 0.35 });
|
|
@@ -279,29 +379,40 @@ function reverb(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
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
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;
|
|
304
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;
|
|
414
|
+
}
|
|
415
|
+
return y;
|
|
305
416
|
}
|
|
306
417
|
|
|
307
418
|
// src/audio/music/notation.ts
|
|
@@ -723,6 +834,18 @@ function rng(seed) {
|
|
|
723
834
|
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
724
835
|
};
|
|
725
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
|
+
}
|
|
726
849
|
function musicLength(m) {
|
|
727
850
|
return m.seconds + m.tail;
|
|
728
851
|
}
|
|
@@ -745,8 +868,41 @@ function musicBeatTimes(m, until = m.seconds) {
|
|
|
745
868
|
}
|
|
746
869
|
return times.filter((t) => t < until);
|
|
747
870
|
}
|
|
748
|
-
function
|
|
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
|
+
}
|
|
902
|
+
function* renderMusicSteps(m, sampleRate, length, loop) {
|
|
749
903
|
setSampleRate(sampleRate);
|
|
904
|
+
const units = m.tracks.length + (m.drums.length ? 1 : 0) + 2;
|
|
905
|
+
let unit = 0;
|
|
750
906
|
const total = Math.max(2, Math.round(length * sampleRate));
|
|
751
907
|
const rnd = rng(m.seed);
|
|
752
908
|
const map = new TempoMap(m.tempo);
|
|
@@ -761,6 +917,15 @@ function renderMusic(m, sampleRate, length, loop = false) {
|
|
|
761
917
|
const levelAt = (vol) => {
|
|
762
918
|
if (typeof vol === "number") return () => vol;
|
|
763
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
|
+
}
|
|
764
929
|
return (sec) => {
|
|
765
930
|
const t = loop && loopSec > 0 ? sec % loopSec : sec;
|
|
766
931
|
if (t <= pts[0][0]) return pts[0][1];
|
|
@@ -772,11 +937,11 @@ function renderMusic(m, sampleRate, length, loop = false) {
|
|
|
772
937
|
};
|
|
773
938
|
for (const tr of m.tracks) {
|
|
774
939
|
const inst = VOICES[tr.inst];
|
|
775
|
-
scratch.L.fill(0);
|
|
776
|
-
scratch.R.fill(0);
|
|
777
940
|
for (let r = 0; r < repeats; r++) {
|
|
778
941
|
const offset = r * loopSec;
|
|
779
|
-
for (
|
|
942
|
+
for (let ei = 0; ei < tr.events.length; ei++) {
|
|
943
|
+
const e = tr.events[ei];
|
|
944
|
+
yield (unit + ei / tr.events.length) / units;
|
|
780
945
|
const strum = e.midi.length > 1 ? tr.strum : 0;
|
|
781
946
|
const startBeat = swingShift(e.t);
|
|
782
947
|
const lenSec = Math.max(0.05, (map.seconds(e.t + e.dur) - map.seconds(e.t)) * tr.legato);
|
|
@@ -788,26 +953,37 @@ function renderMusic(m, sampleRate, length, loop = false) {
|
|
|
788
953
|
});
|
|
789
954
|
}
|
|
790
955
|
}
|
|
956
|
+
const [lo, hi] = extent(scratch);
|
|
957
|
+
let end = hi + 1;
|
|
791
958
|
if (tr.tone < 1) {
|
|
792
959
|
const fc = 400 * 50 ** tr.tone;
|
|
793
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)];
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
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;
|
|
797
971
|
}
|
|
972
|
+
end = Math.max(end, i);
|
|
798
973
|
}
|
|
799
974
|
const level = levelAt(tr.vol), pan = Math.max(-1, Math.min(1, tr.pan));
|
|
800
975
|
const gl = Math.cos((pan + 1) * Math.PI / 4) * 1.3, gr = Math.sin((pan + 1) * Math.PI / 4) * 1.3;
|
|
801
976
|
const constant = typeof tr.vol === "number";
|
|
802
977
|
let g = constant ? level(0) : 0;
|
|
803
|
-
for (let i =
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
send.L[i] += l * tr.reverb;
|
|
809
|
-
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;
|
|
810
983
|
}
|
|
984
|
+
scratch.L.fill(0, lo, end);
|
|
985
|
+
scratch.R.fill(0, lo, end);
|
|
986
|
+
unit++;
|
|
811
987
|
}
|
|
812
988
|
if (m.drums.length) {
|
|
813
989
|
scratch.L.fill(0);
|
|
@@ -815,6 +991,7 @@ function renderMusic(m, sampleRate, length, loop = false) {
|
|
|
815
991
|
for (let r = 0; r < repeats; r++) {
|
|
816
992
|
const offset = r * loopSec;
|
|
817
993
|
for (const s of m.drums) {
|
|
994
|
+
yield unit / units;
|
|
818
995
|
const end = Math.min(s.to, m.beats);
|
|
819
996
|
for (let rep = 0; s.from + rep * s.repeat < end - 1e-6; rep++) for (const d of s.drums) for (const h of d.hits) {
|
|
820
997
|
const beat = s.from + rep * s.repeat + h.i / m.grid;
|
|
@@ -833,14 +1010,18 @@ function renderMusic(m, sampleRate, length, loop = false) {
|
|
|
833
1010
|
send.L[i] += l;
|
|
834
1011
|
send.R[i] += r;
|
|
835
1012
|
}
|
|
1013
|
+
unit++;
|
|
836
1014
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
1015
|
+
for (const f of reverbSteps(send, out, m.reverb, 0.8)) yield (unit + f) / units;
|
|
1016
|
+
unit++;
|
|
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;
|
|
843
1023
|
}
|
|
1024
|
+
const peak = acc[0], sum = acc[1];
|
|
844
1025
|
const rms = Math.sqrt(sum / (2 * total));
|
|
845
1026
|
const gain = peak > 0 ? Math.min(MUSIC_PEAK / peak, RMS_CAP / Math.max(rms, 1e-9)) : 0;
|
|
846
1027
|
const fade = Math.min(Math.floor(0.4 * sampleRate), total >> 2);
|
|
@@ -849,8 +1030,24 @@ function renderMusic(m, sampleRate, length, loop = false) {
|
|
|
849
1030
|
out.L[i] *= gain * f;
|
|
850
1031
|
out.R[i] *= gain * f;
|
|
851
1032
|
}
|
|
1033
|
+
clearVoiceTables();
|
|
852
1034
|
return [out.L, out.R];
|
|
853
1035
|
}
|
|
1036
|
+
function renderMusic(m, sampleRate, length, loop = false) {
|
|
1037
|
+
const it = renderMusicSteps(m, sampleRate, length, loop);
|
|
1038
|
+
for (; ; ) {
|
|
1039
|
+
const r = it.next();
|
|
1040
|
+
if (r.done) return r.value;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
async function renderMusicAsync(m, sampleRate, length, loop = false, pace) {
|
|
1044
|
+
const it = renderMusicSteps(m, sampleRate, length, loop);
|
|
1045
|
+
for (; ; ) {
|
|
1046
|
+
const r = it.next();
|
|
1047
|
+
if (r.done) return r.value;
|
|
1048
|
+
if (pace) await pace(r.value);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
854
1051
|
|
|
855
1052
|
exports.CHORD_KINDS = CHORD_KINDS;
|
|
856
1053
|
exports.DEFAULT_TAIL = DEFAULT_TAIL;
|
|
@@ -867,6 +1064,7 @@ exports.noteToMidi = noteToMidi;
|
|
|
867
1064
|
exports.parseDrumGrid = parseDrumGrid;
|
|
868
1065
|
exports.parseNotes = parseNotes;
|
|
869
1066
|
exports.renderMusic = renderMusic;
|
|
1067
|
+
exports.renderMusicAsync = renderMusicAsync;
|
|
870
1068
|
exports.resolveMusic = resolveMusic;
|
|
871
|
-
//# sourceMappingURL=music-
|
|
872
|
-
//# sourceMappingURL=music-
|
|
1069
|
+
//# sourceMappingURL=music-6MTHQEXS.cjs.map
|
|
1070
|
+
//# sourceMappingURL=music-6MTHQEXS.cjs.map
|