polyphon 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +374 -2
- package/README.zh-TW.md +375 -0
- package/dist/engine/automation.d.ts +24 -0
- package/dist/engine/automation.d.ts.map +1 -0
- package/dist/engine/automation.js +55 -0
- package/dist/engine/automation.js.map +1 -0
- package/dist/engine/compile.d.ts +36 -0
- package/dist/engine/compile.d.ts.map +1 -0
- package/dist/engine/compile.js +103 -0
- package/dist/engine/compile.js.map +1 -0
- package/dist/engine/jukebox.d.ts +113 -0
- package/dist/engine/jukebox.d.ts.map +1 -0
- package/dist/engine/jukebox.js +287 -0
- package/dist/engine/jukebox.js.map +1 -0
- package/dist/engine/mixer.d.ts +29 -0
- package/dist/engine/mixer.d.ts.map +1 -0
- package/dist/engine/mixer.js +141 -0
- package/dist/engine/mixer.js.map +1 -0
- package/dist/engine/output.d.ts +14 -0
- package/dist/engine/output.d.ts.map +1 -0
- package/dist/engine/output.js +51 -0
- package/dist/engine/output.js.map +1 -0
- package/dist/engine/playback.d.ts +97 -0
- package/dist/engine/playback.d.ts.map +1 -0
- package/dist/engine/playback.js +311 -0
- package/dist/engine/playback.js.map +1 -0
- package/dist/engine/prepare.d.ts +6 -0
- package/dist/engine/prepare.d.ts.map +1 -0
- package/dist/engine/prepare.js +12 -0
- package/dist/engine/prepare.js.map +1 -0
- package/dist/engine/render.d.ts +14 -0
- package/dist/engine/render.d.ts.map +1 -0
- package/dist/engine/render.js +60 -0
- package/dist/engine/render.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/instruments/bowed.d.ts +357 -0
- package/dist/instruments/bowed.d.ts.map +1 -0
- package/dist/instruments/bowed.js +502 -0
- package/dist/instruments/bowed.js.map +1 -0
- package/dist/instruments/builtin.d.ts +261 -0
- package/dist/instruments/builtin.d.ts.map +1 -0
- package/dist/instruments/builtin.js +160 -0
- package/dist/instruments/builtin.js.map +1 -0
- package/dist/instruments/definition.d.ts +46 -0
- package/dist/instruments/definition.d.ts.map +1 -0
- package/dist/instruments/definition.js +5 -0
- package/dist/instruments/definition.js.map +1 -0
- package/dist/instruments/dsp/ambience.d.ts +17 -0
- package/dist/instruments/dsp/ambience.d.ts.map +1 -0
- package/dist/instruments/dsp/ambience.js +146 -0
- package/dist/instruments/dsp/ambience.js.map +1 -0
- package/dist/instruments/dsp/core.d.ts +22 -0
- package/dist/instruments/dsp/core.d.ts.map +1 -0
- package/dist/instruments/dsp/core.js +100 -0
- package/dist/instruments/dsp/core.js.map +1 -0
- package/dist/instruments/dsp/drums.d.ts +112 -0
- package/dist/instruments/dsp/drums.d.ts.map +1 -0
- package/dist/instruments/dsp/drums.js +566 -0
- package/dist/instruments/dsp/drums.js.map +1 -0
- package/dist/instruments/dsp/modal.d.ts +30 -0
- package/dist/instruments/dsp/modal.d.ts.map +1 -0
- package/dist/instruments/dsp/modal.js +54 -0
- package/dist/instruments/dsp/modal.js.map +1 -0
- package/dist/instruments/dsp/piano.d.ts +9 -0
- package/dist/instruments/dsp/piano.d.ts.map +1 -0
- package/dist/instruments/dsp/piano.js +230 -0
- package/dist/instruments/dsp/piano.js.map +1 -0
- package/dist/instruments/dsp/pluck.d.ts +53 -0
- package/dist/instruments/dsp/pluck.d.ts.map +1 -0
- package/dist/instruments/dsp/pluck.js +195 -0
- package/dist/instruments/dsp/pluck.js.map +1 -0
- package/dist/instruments/dsp/reverb.d.ts +16 -0
- package/dist/instruments/dsp/reverb.d.ts.map +1 -0
- package/dist/instruments/dsp/reverb.js +47 -0
- package/dist/instruments/dsp/reverb.js.map +1 -0
- package/dist/instruments/dsp/staccato.d.ts +18 -0
- package/dist/instruments/dsp/staccato.d.ts.map +1 -0
- package/dist/instruments/dsp/staccato.js +147 -0
- package/dist/instruments/dsp/staccato.js.map +1 -0
- package/dist/instruments/play.d.ts +21 -0
- package/dist/instruments/play.d.ts.map +1 -0
- package/dist/instruments/play.js +140 -0
- package/dist/instruments/play.js.map +1 -0
- package/dist/instruments/registry.d.ts +63 -0
- package/dist/instruments/registry.d.ts.map +1 -0
- package/dist/instruments/registry.js +50 -0
- package/dist/instruments/registry.js.map +1 -0
- package/dist/instruments/samples.d.ts +30 -0
- package/dist/instruments/samples.d.ts.map +1 -0
- package/dist/instruments/samples.js +109 -0
- package/dist/instruments/samples.js.map +1 -0
- package/dist/instruments/voices.d.ts +76 -0
- package/dist/instruments/voices.d.ts.map +1 -0
- package/dist/instruments/voices.js +1061 -0
- package/dist/instruments/voices.js.map +1 -0
- package/dist/midi.d.ts +15 -0
- package/dist/midi.d.ts.map +1 -0
- package/dist/midi.js +280 -0
- package/dist/midi.js.map +1 -0
- package/dist/notation/format.d.ts +12 -0
- package/dist/notation/format.d.ts.map +1 -0
- package/dist/notation/format.js +102 -0
- package/dist/notation/format.js.map +1 -0
- package/dist/notation/harmony.d.ts +83 -0
- package/dist/notation/harmony.d.ts.map +1 -0
- package/dist/notation/harmony.js +191 -0
- package/dist/notation/harmony.js.map +1 -0
- package/dist/notation/melody.d.ts +25 -0
- package/dist/notation/melody.d.ts.map +1 -0
- package/dist/notation/melody.js +138 -0
- package/dist/notation/melody.js.map +1 -0
- package/dist/notation/part.d.ts +34 -0
- package/dist/notation/part.d.ts.map +1 -0
- package/dist/notation/part.js +15 -0
- package/dist/notation/part.js.map +1 -0
- package/dist/notation/transform.d.ts +28 -0
- package/dist/notation/transform.d.ts.map +1 -0
- package/dist/notation/transform.js +67 -0
- package/dist/notation/transform.js.map +1 -0
- package/dist/song.d.ts +140 -0
- package/dist/song.d.ts.map +1 -0
- package/dist/song.js +45 -0
- package/dist/song.js.map +1 -0
- package/dist/tempo.d.ts +36 -0
- package/dist/tempo.d.ts.map +1 -0
- package/dist/tempo.js +81 -0
- package/dist/tempo.js.map +1 -0
- package/dist/theory.d.ts +70 -0
- package/dist/theory.d.ts.map +1 -0
- package/dist/theory.js +183 -0
- package/dist/theory.js.map +1 -0
- package/dist/transcribe.d.ts +81 -0
- package/dist/transcribe.d.ts.map +1 -0
- package/dist/transcribe.js +433 -0
- package/dist/transcribe.js.map +1 -0
- package/package.json +57 -4
- package/src/engine/automation.ts +65 -0
- package/src/engine/compile.ts +124 -0
- package/src/engine/jukebox.ts +322 -0
- package/src/engine/mixer.ts +166 -0
- package/src/engine/output.ts +59 -0
- package/src/engine/playback.ts +349 -0
- package/src/engine/prepare.ts +15 -0
- package/src/engine/render.ts +71 -0
- package/src/index.ts +28 -0
- package/src/instruments/bowed.ts +660 -0
- package/src/instruments/builtin.ts +180 -0
- package/src/instruments/definition.ts +52 -0
- package/src/instruments/dsp/ambience.ts +142 -0
- package/src/instruments/dsp/core.ts +97 -0
- package/src/instruments/dsp/drums.ts +565 -0
- package/src/instruments/dsp/modal.ts +76 -0
- package/src/instruments/dsp/piano.ts +226 -0
- package/src/instruments/dsp/pluck.ts +240 -0
- package/src/instruments/dsp/reverb.ts +56 -0
- package/src/instruments/dsp/staccato.ts +141 -0
- package/src/instruments/play.ts +151 -0
- package/src/instruments/registry.ts +100 -0
- package/src/instruments/samples.ts +119 -0
- package/src/instruments/voices.ts +1168 -0
- package/src/midi.ts +285 -0
- package/src/notation/format.ts +96 -0
- package/src/notation/harmony.ts +233 -0
- package/src/notation/melody.ts +133 -0
- package/src/notation/part.ts +42 -0
- package/src/notation/transform.ts +78 -0
- package/src/song.ts +170 -0
- package/src/tempo.ts +108 -0
- package/src/theory.ts +208 -0
- package/src/transcribe.ts +487 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Procedural reverb: a stereo impulse response of decaying noise whose highs fade faster than its lows.
|
|
2
|
+
import { rng } from './core.js';
|
|
3
|
+
/** Generate a stereo impulse response: decaying noise, with the highs eaten away over time */
|
|
4
|
+
export function impulse(sr, o) {
|
|
5
|
+
const len = Math.floor(sr * Math.min(8, o.size * 1.15 + (o.preDelay ?? 0) + 0.05));
|
|
6
|
+
const pre = Math.floor((o.preDelay ?? 0.012) * sr);
|
|
7
|
+
const damp = o.damp ?? 0.45;
|
|
8
|
+
const out = [new Float32Array(len), new Float32Array(len)];
|
|
9
|
+
for (let ch = 0; ch < 2; ch++) {
|
|
10
|
+
const r = rng(1234 + ch * 777);
|
|
11
|
+
const d = out[ch];
|
|
12
|
+
const k = Math.pow(10, -3 / (o.size * sr));
|
|
13
|
+
let env = 1;
|
|
14
|
+
let lp = 0;
|
|
15
|
+
for (let i = pre; i < len; i++) {
|
|
16
|
+
const t = (i - pre) / sr;
|
|
17
|
+
// The low-pass coefficient shrinks over time: darker toward the end
|
|
18
|
+
const a = Math.max(0.02, (1 - damp * 0.85) * Math.exp((-t * damp * 3) / Math.max(0.5, o.size)));
|
|
19
|
+
lp += a * (r() - lp);
|
|
20
|
+
let v = lp * env;
|
|
21
|
+
if (o.bloom)
|
|
22
|
+
v *= 1 - Math.exp(-t / o.bloom);
|
|
23
|
+
d[i] = v;
|
|
24
|
+
env *= k;
|
|
25
|
+
}
|
|
26
|
+
// Early reflections
|
|
27
|
+
const er = o.early ?? 0.3;
|
|
28
|
+
if (er > 0) {
|
|
29
|
+
for (let j = 0; j < 8; j++) {
|
|
30
|
+
const at = pre + Math.floor((0.004 + Math.abs(r()) * 0.06) * sr);
|
|
31
|
+
if (at < len)
|
|
32
|
+
d[at] += er * (0.5 + 0.5 * Math.abs(r())) * (r() > 0 ? 1 : -1) * 0.6;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Energy normalization: rooms of different sizes come out equally loud
|
|
37
|
+
let e = 0;
|
|
38
|
+
for (const d of out)
|
|
39
|
+
for (let i = 0; i < d.length; i++)
|
|
40
|
+
e += d[i] * d[i];
|
|
41
|
+
const g = 1 / Math.sqrt(e / 2 + 1e-9);
|
|
42
|
+
for (const d of out)
|
|
43
|
+
for (let i = 0; i < d.length; i++)
|
|
44
|
+
d[i] *= g * 0.5;
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=reverb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reverb.js","sourceRoot":"","sources":["../../../src/instruments/dsp/reverb.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spiccato strings: the bow drops onto the string, draws a few periods of sawtooth (Helmholtz) motion, bounces off, and the string rings on freely.
|
|
3
|
+
* - Bowed for the first 40-65 ms: harmonics falling as 1/k through the body, the bite of the bow lightening as it bounces, and the rustle
|
|
4
|
+
* of the hair catching the string.
|
|
5
|
+
* - Then free: each partial decays at its own rate. The string's internal losses and the bridge take more energy per second from the
|
|
6
|
+
* upper partials (the decay rate grows with frequency), so they are gone within ~0.1 s while the fundamental rings on and the note
|
|
7
|
+
* darkens as it dies, like a pizzicato. (One envelope on every partial kept the attack's bright tone to the end, like a gated synth.)
|
|
8
|
+
* - Five players a few cents and a few milliseconds apart: three copies at ±7 cents beat like a chorus.
|
|
9
|
+
*/
|
|
10
|
+
export declare function spicc(sr: number, m: number): Float32Array;
|
|
11
|
+
/**
|
|
12
|
+
* Brass stab: a short forte blat from two players, a few cents and 12 ms apart. As in the live brass (voices.ts), the lips are a valve whose
|
|
13
|
+
* harmonics fall as e^(-f/F), with F following the loudness: the harmonics come in one after another during the attack, the note is brassiest
|
|
14
|
+
* at its peak and darkens as it dies away. The bell radiates the lows poorly and the cup rolls off the top (first-order corners at 1.1 and 6 kHz).
|
|
15
|
+
* Levelled on its first 250 ms, so every pitch hits equally hard.
|
|
16
|
+
*/
|
|
17
|
+
export declare function brassStab(sr: number, m: number): Float32Array;
|
|
18
|
+
//# sourceMappingURL=staccato.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staccato.d.ts","sourceRoot":"","sources":["../../../src/instruments/dsp/staccato.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,YAAY,CA6CzD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,YAAY,CA0E7D"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// Short sampled notes for fast figures (much cheaper than live synthesis): spiccato strings and brass stabs.
|
|
2
|
+
import { Biquad, rng, tailFade } from './core.js';
|
|
3
|
+
/**
|
|
4
|
+
* Spiccato strings: the bow drops onto the string, draws a few periods of sawtooth (Helmholtz) motion, bounces off, and the string rings on freely.
|
|
5
|
+
* - Bowed for the first 40-65 ms: harmonics falling as 1/k through the body, the bite of the bow lightening as it bounces, and the rustle
|
|
6
|
+
* of the hair catching the string.
|
|
7
|
+
* - Then free: each partial decays at its own rate. The string's internal losses and the bridge take more energy per second from the
|
|
8
|
+
* upper partials (the decay rate grows with frequency), so they are gone within ~0.1 s while the fundamental rings on and the note
|
|
9
|
+
* darkens as it dies, like a pizzicato. (One envelope on every partial kept the attack's bright tone to the end, like a gated synth.)
|
|
10
|
+
* - Five players a few cents and a few milliseconds apart: three copies at ±7 cents beat like a chorus.
|
|
11
|
+
*/
|
|
12
|
+
export function spicc(sr, m) {
|
|
13
|
+
const f = 440 * Math.pow(2, (m - 69) / 12);
|
|
14
|
+
const y = new Float32Array(Math.floor(sr * 0.42));
|
|
15
|
+
const nyq = sr * 0.42;
|
|
16
|
+
const body = (hz) => 0.4 + 1.2 / (1 + ((hz - 450) / 250) ** 2) + 0.7 / (1 + ((hz - 1300) / 500) ** 2) + 0.5 / (1 + ((hz - 3000) / 900) ** 2);
|
|
17
|
+
const r = rng(m * 5 + 1);
|
|
18
|
+
// The bow bites and lightens as it bounces (shared by every partial)
|
|
19
|
+
const acc = new Float32Array(y.length);
|
|
20
|
+
for (let i = 0; i < y.length; i++)
|
|
21
|
+
acc[i] = Math.min(1, i / sr / 0.008) * (0.25 + 0.75 * Math.exp(-i / sr / 0.06));
|
|
22
|
+
for (let p = 0; p < 5; p++) {
|
|
23
|
+
const ff = f * Math.pow(2, (5 * r()) / 1200);
|
|
24
|
+
const i0 = Math.floor(((r() + 1) / 2) * 0.012 * sr);
|
|
25
|
+
// The bow leaves the string
|
|
26
|
+
const i1 = i0 + Math.floor((0.052 + 0.012 * r()) * sr);
|
|
27
|
+
for (let k = 1; k < 40; k++) {
|
|
28
|
+
const hz = ff * k;
|
|
29
|
+
if (hz > nyq)
|
|
30
|
+
break;
|
|
31
|
+
// Decay rate of the free string (nepers per second): T60 ≈ 0.5 s for the fundamental of A3, 0.09 s at 3 kHz
|
|
32
|
+
const dk = Math.exp(-(6 + 0.025 * hz) / sr);
|
|
33
|
+
let e = (0.77 * body(hz)) / k / (1 + (hz / 4500) ** 2);
|
|
34
|
+
// A rotating phasor from a random phase (cheaper than Math.sin per sample)
|
|
35
|
+
const w = (2 * Math.PI * hz) / sr;
|
|
36
|
+
const c = Math.cos(w);
|
|
37
|
+
const s = Math.sin(w);
|
|
38
|
+
const ph = r() * Math.PI;
|
|
39
|
+
let x = Math.cos(ph);
|
|
40
|
+
let z = Math.sin(ph);
|
|
41
|
+
for (let i = i0; i < y.length; i++) {
|
|
42
|
+
y[i] += z * e * acc[i - i0];
|
|
43
|
+
const nx = x * c - z * s;
|
|
44
|
+
z = x * s + z * c;
|
|
45
|
+
x = nx;
|
|
46
|
+
if (i >= i1)
|
|
47
|
+
e *= dk;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const noise = new Biquad(sr, 'bp', Math.min(7000, f * 5), 1.2);
|
|
52
|
+
for (let i = 0; i < y.length; i++)
|
|
53
|
+
y[i] += noise.run(r()) * 0.6 * Math.exp(-i / sr / 0.03);
|
|
54
|
+
// Levelled on the first 150 ms (the old peak normalization left notes ±3 dB apart at random; this is their average)
|
|
55
|
+
let e = 0;
|
|
56
|
+
const w = Math.floor(sr * 0.15);
|
|
57
|
+
for (let i = 0; i < w; i++)
|
|
58
|
+
e += y[i] * y[i];
|
|
59
|
+
const g = 0.24 / (Math.sqrt(e / w) || 1);
|
|
60
|
+
for (let i = 0; i < y.length; i++)
|
|
61
|
+
y[i] *= g;
|
|
62
|
+
return tailFade(y, sr);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Brass stab: a short forte blat from two players, a few cents and 12 ms apart. As in the live brass (voices.ts), the lips are a valve whose
|
|
66
|
+
* harmonics fall as e^(-f/F), with F following the loudness: the harmonics come in one after another during the attack, the note is brassiest
|
|
67
|
+
* at its peak and darkens as it dies away. The bell radiates the lows poorly and the cup rolls off the top (first-order corners at 1.1 and 6 kHz).
|
|
68
|
+
* Levelled on its first 250 ms, so every pitch hits equally hard.
|
|
69
|
+
*/
|
|
70
|
+
export function brassStab(sr, m) {
|
|
71
|
+
const f = 440 * Math.pow(2, (m - 69) / 12);
|
|
72
|
+
const y = new Float32Array(Math.floor(sr * 0.55));
|
|
73
|
+
const nyq = sr * 0.42;
|
|
74
|
+
const r = rng(m * 3 + 9);
|
|
75
|
+
const lo = 1100;
|
|
76
|
+
const hi = 6000;
|
|
77
|
+
const env = (t) => Math.min(1, t / 0.02) * Math.exp(-t / 0.28);
|
|
78
|
+
const BLOCK = 32;
|
|
79
|
+
for (const [det, delay] of [[-6, 0], [6, 0.012]]) {
|
|
80
|
+
const ff = f * Math.pow(2, det / 1200);
|
|
81
|
+
const n = Math.min(80, Math.floor(nyq / ff));
|
|
82
|
+
// Each harmonic is a rotating phasor (cheap sines) from a random phase, with the bell's response and the rotation over one block
|
|
83
|
+
const bell = new Float64Array(n + 1);
|
|
84
|
+
const re = new Float64Array(n + 1);
|
|
85
|
+
const im = new Float64Array(n + 1);
|
|
86
|
+
const cw = new Float64Array(n + 1);
|
|
87
|
+
const sw = new Float64Array(n + 1);
|
|
88
|
+
const cb = new Float64Array(n + 1);
|
|
89
|
+
const sb = new Float64Array(n + 1);
|
|
90
|
+
for (let k = 1; k <= n; k++) {
|
|
91
|
+
const hz = ff * k;
|
|
92
|
+
bell[k] = ((lo + hi) * hz) / Math.sqrt((hz * hz + lo * lo) * (hz * hz + hi * hi));
|
|
93
|
+
const ph = r() * Math.PI;
|
|
94
|
+
const w = (2 * Math.PI * hz) / sr;
|
|
95
|
+
re[k] = Math.cos(ph);
|
|
96
|
+
im[k] = Math.sin(ph);
|
|
97
|
+
cw[k] = Math.cos(w);
|
|
98
|
+
sw[k] = Math.sin(w);
|
|
99
|
+
cb[k] = Math.cos(w * BLOCK);
|
|
100
|
+
sb[k] = Math.sin(w * BLOCK);
|
|
101
|
+
}
|
|
102
|
+
const amp = new Float64Array(n + 1);
|
|
103
|
+
const i0 = Math.floor(delay * sr);
|
|
104
|
+
// (The last part-block falls inside the tail fade and is left silent)
|
|
105
|
+
for (let b = i0; b + BLOCK <= y.length; b += BLOCK) {
|
|
106
|
+
// Per block: the fall-off F from the loudness, then the harmonics' amplitudes, scaled so the loudness follows the envelope
|
|
107
|
+
const e = env((b - i0) / sr);
|
|
108
|
+
const rr = Math.exp(-ff / (2400 * (0.25 + 0.75 * Math.pow(e, 0.7))));
|
|
109
|
+
let rn = 1;
|
|
110
|
+
let s = 0;
|
|
111
|
+
for (let k = 1; k <= n; k++) {
|
|
112
|
+
rn *= rr;
|
|
113
|
+
amp[k] = rn * bell[k];
|
|
114
|
+
s += amp[k] * amp[k];
|
|
115
|
+
}
|
|
116
|
+
const g = e / (Math.sqrt(s) || 1);
|
|
117
|
+
for (let k = 1; k <= n; k++) {
|
|
118
|
+
const a = amp[k] * g;
|
|
119
|
+
let x = re[k];
|
|
120
|
+
let z = im[k];
|
|
121
|
+
if (a < 1e-6) {
|
|
122
|
+
// Too weak to hear: just turn the phasor on by a block
|
|
123
|
+
re[k] = x * cb[k] - z * sb[k];
|
|
124
|
+
im[k] = x * sb[k] + z * cb[k];
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
for (let i = b; i < b + BLOCK; i++) {
|
|
128
|
+
y[i] += z * a;
|
|
129
|
+
const nx = x * cw[k] - z * sw[k];
|
|
130
|
+
z = x * sw[k] + z * cw[k];
|
|
131
|
+
x = nx;
|
|
132
|
+
}
|
|
133
|
+
re[k] = x;
|
|
134
|
+
im[k] = z;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
let e = 0;
|
|
139
|
+
const w = Math.min(y.length, Math.floor(sr * 0.25));
|
|
140
|
+
for (let i = 0; i < w; i++)
|
|
141
|
+
e += y[i] * y[i];
|
|
142
|
+
const k = 0.29 / (Math.sqrt(e / w) || 1);
|
|
143
|
+
for (let i = 0; i < y.length; i++)
|
|
144
|
+
y[i] *= k;
|
|
145
|
+
return tailFade(y, sr);
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=staccato.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staccato.js","sourceRoot":"","sources":["../../../src/instruments/dsp/staccato.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface NoteCall {
|
|
2
|
+
ctx: BaseAudioContext;
|
|
3
|
+
out: AudioNode;
|
|
4
|
+
/** Start time (context seconds) */
|
|
5
|
+
t: number;
|
|
6
|
+
/** Held length (seconds) */
|
|
7
|
+
dur: number;
|
|
8
|
+
/** MIDI pitch (0 for unpitched drums) */
|
|
9
|
+
m: number;
|
|
10
|
+
/** 0-1 */
|
|
11
|
+
vel: number;
|
|
12
|
+
/** Glides: [seconds after the start, target MIDI pitch] */
|
|
13
|
+
bends?: [number, number][];
|
|
14
|
+
/** The track's instrument parameters */
|
|
15
|
+
params?: Readonly<Record<string, number>>;
|
|
16
|
+
/** Bowed strings: the desk (players) of the track, 0 for the first (see deskList in compile.ts) */
|
|
17
|
+
desk?: number;
|
|
18
|
+
}
|
|
19
|
+
/** Play one note */
|
|
20
|
+
export declare function playNote(name: string, c: NoteCall): void;
|
|
21
|
+
//# sourceMappingURL=play.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"play.d.ts","sourceRoot":"","sources":["../../src/instruments/play.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,gBAAgB,CAAC;IACtB,GAAG,EAAE,SAAS,CAAC;IACf,mCAAmC;IACnC,CAAC,EAAE,MAAM,CAAC;IACV,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,CAAC,EAAE,MAAM,CAAC;IACV,UAAU;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IAC3B,wCAAwC;IACxC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C,mGAAmG;IACnG,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,oBAAoB;AACpB,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,CAgExD"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// Play one note on any instrument: a cached sample, a bowed sample with a looping sustain, or a live voice.
|
|
2
|
+
import { DESKS } from './bowed.js';
|
|
3
|
+
import { midiToFrequency } from './definition.js';
|
|
4
|
+
import { getInstrument } from './registry.js';
|
|
5
|
+
import { getSample, hasSample, loopOf, sampleMidi } from './samples.js';
|
|
6
|
+
/** Play one note */
|
|
7
|
+
export function playNote(name, c) {
|
|
8
|
+
const def = getInstrument(name);
|
|
9
|
+
const amp = Math.pow(c.vel, 1.4) * def.level;
|
|
10
|
+
if (def.kind === 'live') {
|
|
11
|
+
def.voice({ ctx: c.ctx, out: c.out, t: c.t, dur: c.dur, f: midiToFrequency(c.m), vel: amp, touch: c.vel, bends: c.bends?.map(([at, m]) => [at, midiToFrequency(m)]), o: c.params ?? {} });
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (def.bow) {
|
|
15
|
+
playBow(def, name, c, amp);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const variant = Math.floor(Math.random() * (def.variants ?? 1));
|
|
19
|
+
const b = getSample(c.ctx, def, name, c.m, variant);
|
|
20
|
+
const src = c.ctx.createBufferSource();
|
|
21
|
+
src.buffer = b;
|
|
22
|
+
// A fixed-pitch drum given a different note is tuned by changing the playback rate (taiko, tom and others are already rendered by pitch and never reach here)
|
|
23
|
+
if (def.fixed !== undefined && c.m && c.m !== def.fixed && (c.params?.tune ?? 0) > 0)
|
|
24
|
+
src.playbackRate.value = Math.pow(2, (c.m - def.fixed) / 12);
|
|
25
|
+
const g = c.ctx.createGain();
|
|
26
|
+
if (def.loop) {
|
|
27
|
+
src.loop = true;
|
|
28
|
+
const a = c.params?.attack ?? 1.5;
|
|
29
|
+
const r = c.params?.release ?? 1.5;
|
|
30
|
+
g.gain.setValueAtTime(0, c.t);
|
|
31
|
+
g.gain.linearRampToValueAtTime(amp, c.t + a);
|
|
32
|
+
g.gain.setValueAtTime(amp, c.t + Math.max(a, c.dur));
|
|
33
|
+
g.gain.linearRampToValueAtTime(0, c.t + Math.max(a, c.dur) + r);
|
|
34
|
+
src.connect(g).connect(c.out);
|
|
35
|
+
src.start(c.t, (c.t * 7.3) % b.duration);
|
|
36
|
+
src.stop(c.t + Math.max(a, c.dur) + r + 0.05);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
g.gain.value = amp;
|
|
40
|
+
if (def.choke)
|
|
41
|
+
choke(c, def.choke, g.gain);
|
|
42
|
+
let out = c.out;
|
|
43
|
+
if (def.spread) {
|
|
44
|
+
const pan = c.ctx.createStereoPanner();
|
|
45
|
+
pan.pan.value = Math.max(-1, Math.min(1, (c.m - 64) / 36)) * def.spread;
|
|
46
|
+
pan.connect(c.out);
|
|
47
|
+
out = pan;
|
|
48
|
+
}
|
|
49
|
+
if (def.tone) {
|
|
50
|
+
const lp = c.ctx.createBiquadFilter();
|
|
51
|
+
lp.type = 'lowpass';
|
|
52
|
+
lp.frequency.value = Math.min(c.ctx.sampleRate * 0.45, def.tone(c.m, c.vel));
|
|
53
|
+
// The Web Audio low-pass Q is the resonance in decibels: -3 dB is roughly Butterworth, with no nasal tone
|
|
54
|
+
lp.Q.value = -3;
|
|
55
|
+
src.connect(lp).connect(g).connect(out);
|
|
56
|
+
}
|
|
57
|
+
else
|
|
58
|
+
src.connect(g).connect(out);
|
|
59
|
+
src.start(c.t);
|
|
60
|
+
const r = c.params?.release ?? def.damper?.(c.m) ?? def.release ?? 0.2;
|
|
61
|
+
if (def.hold === 'damp' && !(c.params?.ring ?? 0) && r !== Infinity) {
|
|
62
|
+
const off = c.t + Math.max(def.minHold ?? 0.03, c.dur);
|
|
63
|
+
g.gain.setValueAtTime(amp, off);
|
|
64
|
+
if (def.afterRing) {
|
|
65
|
+
// The damper stops the string quickly, but a faint ring stays a moment longer
|
|
66
|
+
const [level, fade] = def.afterRing;
|
|
67
|
+
g.gain.setTargetAtTime(amp * level, off, r / 4);
|
|
68
|
+
g.gain.setTargetAtTime(1e-4, off + r, fade / 6.9);
|
|
69
|
+
src.stop(Math.min(off + r + fade, c.t + b.duration));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
g.gain.setTargetAtTime(1e-4, off, r / 4);
|
|
73
|
+
src.stop(Math.min(off + r * 1.5, c.t + b.duration));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else
|
|
77
|
+
src.stop(c.t + b.duration);
|
|
78
|
+
}
|
|
79
|
+
/** The gain of the note last started in each choke group, per audio context */
|
|
80
|
+
const chokeGroups = new WeakMap();
|
|
81
|
+
/** Cut off the note still ringing in a choke group as this one starts (notes are scheduled in time order), and make this one the group's */
|
|
82
|
+
function choke(c, group, gain) {
|
|
83
|
+
let groups = chokeGroups.get(c.ctx);
|
|
84
|
+
if (!groups)
|
|
85
|
+
chokeGroups.set(c.ctx, (groups = new Map()));
|
|
86
|
+
const ringing = groups.get(group);
|
|
87
|
+
if (ringing) {
|
|
88
|
+
// The target of setTargetAtTime cannot be 0 (some implementations diverge): fade toward silence, then close
|
|
89
|
+
ringing.cancelScheduledValues(c.t);
|
|
90
|
+
ringing.setTargetAtTime(1e-4, c.t, 0.004);
|
|
91
|
+
ringing.setValueAtTime(0, c.t + 0.04);
|
|
92
|
+
}
|
|
93
|
+
groups.set(group, gain);
|
|
94
|
+
}
|
|
95
|
+
/** Bowed strings: pick the soft or hard layer, make up pitch with a rate change, loop the sustain section, and lift the bow when the note ends */
|
|
96
|
+
function playBow(def, name, c, amp) {
|
|
97
|
+
const bw = def.bow;
|
|
98
|
+
const o = c.params ?? {};
|
|
99
|
+
let loud = c.vel * (o.bright ?? 1) > bw.loudAt ? 1 : 0;
|
|
100
|
+
const root = sampleMidi(def, c.m);
|
|
101
|
+
// If this layer is not prepared but the other one is: use the other for now, rather than rendering during playback (that would stall);
|
|
102
|
+
// a desk with neither prepared borrows the first desk's players
|
|
103
|
+
const has = (layer, desk) => hasSample(c.ctx.sampleRate, def, name, c.m, layer, desk);
|
|
104
|
+
const seat = DESKS[(c.desk ?? 0) % DESKS.length];
|
|
105
|
+
let desk = DESKS.indexOf(seat);
|
|
106
|
+
if (desk && !has(0, desk) && !has(1, desk) && (has(0, 0) || has(1, 0)))
|
|
107
|
+
desk = 0;
|
|
108
|
+
if (!has(loud, desk) && has(1 - loud, desk))
|
|
109
|
+
loud = 1 - loud;
|
|
110
|
+
const b = getSample(c.ctx, def, name, c.m, loud, desk);
|
|
111
|
+
const src = c.ctx.createBufferSource();
|
|
112
|
+
src.buffer = b;
|
|
113
|
+
const lp = loopOf(b);
|
|
114
|
+
if (lp) {
|
|
115
|
+
src.loop = true;
|
|
116
|
+
src.loopStart = lp[0];
|
|
117
|
+
src.loopEnd = lp[1];
|
|
118
|
+
}
|
|
119
|
+
const rate = src.playbackRate;
|
|
120
|
+
rate.setValueAtTime(Math.pow(2, (c.m - root) / 12), c.t);
|
|
121
|
+
const glide = o.glide ?? bw.glide;
|
|
122
|
+
if (c.bends)
|
|
123
|
+
for (const [at, m] of c.bends)
|
|
124
|
+
rate.setTargetAtTime(Math.pow(2, (m - root) / 12), c.t + at, glide / 3);
|
|
125
|
+
const a = Math.max(0.005, o.attack ?? bw.attack);
|
|
126
|
+
const r = o.release ?? bw.release;
|
|
127
|
+
const off = c.t + Math.max(c.dur, 0.06);
|
|
128
|
+
// A desk after the first lands its bow a little behind the first desk's, by a different amount every note; it lifts it with the others
|
|
129
|
+
const t = c.t + (seat.lag && seat.lag * (0.5 + Math.random()));
|
|
130
|
+
const g = c.ctx.createGain();
|
|
131
|
+
const p = g.gain;
|
|
132
|
+
p.setValueAtTime(0, t);
|
|
133
|
+
p.linearRampToValueAtTime(amp, t + Math.min(a, Math.max(0.005, off - t)));
|
|
134
|
+
p.setValueAtTime(amp, off);
|
|
135
|
+
p.setTargetAtTime(1e-4, off, r / 4);
|
|
136
|
+
src.connect(g).connect(c.out);
|
|
137
|
+
src.start(t);
|
|
138
|
+
src.stop(off + r * 1.6 + 0.02);
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=play.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"play.js","sourceRoot":"","sources":["../../src/instruments/play.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type BuiltInInstrument } from './builtin.ts';
|
|
2
|
+
import type { InstrumentDef } from './definition.ts';
|
|
3
|
+
/** An instrument name. Built-in names autocomplete; any registered name is accepted too. */
|
|
4
|
+
export type InstrumentName = BuiltInInstrument | (string & {});
|
|
5
|
+
/** One note handed to a custom synthesized instrument */
|
|
6
|
+
export interface SynthNote {
|
|
7
|
+
context: BaseAudioContext;
|
|
8
|
+
/** Connect the note's output here */
|
|
9
|
+
destination: AudioNode;
|
|
10
|
+
/** Start time (context seconds) */
|
|
11
|
+
time: number;
|
|
12
|
+
/** How long the note is held (seconds); the release comes after this */
|
|
13
|
+
duration: number;
|
|
14
|
+
/** Frequency (Hz) */
|
|
15
|
+
frequency: number;
|
|
16
|
+
/** Loudness 0-1, already shaped by the instrument's level */
|
|
17
|
+
velocity: number;
|
|
18
|
+
/** Glides: [seconds after the start, target frequency in Hz] */
|
|
19
|
+
glides: [number, number][];
|
|
20
|
+
/** The track's `params`, for instrument-specific settings */
|
|
21
|
+
params: Readonly<Record<string, number>>;
|
|
22
|
+
}
|
|
23
|
+
/** A custom instrument rendered offline, once per pitch, then played back from a buffer */
|
|
24
|
+
export interface CustomSampledInstrument {
|
|
25
|
+
/** Render one note: mono, or [left, right] */
|
|
26
|
+
render(sampleRate: number, midi: number): Float32Array | [Float32Array, Float32Array];
|
|
27
|
+
/** 'ring' (default) plays the whole sample; 'damp' fades it out `release` seconds after the note ends */
|
|
28
|
+
sustain?: 'ring' | 'damp';
|
|
29
|
+
/** Release time in seconds for 'damp' (default 0.2) */
|
|
30
|
+
release?: number;
|
|
31
|
+
/** Output level (default 1) */
|
|
32
|
+
level?: number;
|
|
33
|
+
}
|
|
34
|
+
/** A custom instrument synthesized live, note by note */
|
|
35
|
+
export interface CustomSynthInstrument {
|
|
36
|
+
/** Build the Web Audio graph for one note */
|
|
37
|
+
play(note: SynthNote): void;
|
|
38
|
+
/** Output level (default 1) */
|
|
39
|
+
level?: number;
|
|
40
|
+
/** Supports glides between notes (the `>` marker in a melody) */
|
|
41
|
+
glide?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export type CustomInstrument = CustomSampledInstrument | CustomSynthInstrument;
|
|
44
|
+
/**
|
|
45
|
+
* Add an instrument (or replace one) under a name tracks can use.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* registerInstrument('beep', {
|
|
49
|
+
* play({ context, destination, time, duration, frequency, velocity }) {
|
|
50
|
+
* const osc = new OscillatorNode(context, { type: 'square', frequency });
|
|
51
|
+
* const amp = new GainNode(context, { gain: velocity * 0.2 });
|
|
52
|
+
* osc.connect(amp).connect(destination);
|
|
53
|
+
* osc.start(time);
|
|
54
|
+
* osc.stop(time + duration);
|
|
55
|
+
* },
|
|
56
|
+
* });
|
|
57
|
+
*/
|
|
58
|
+
export declare function registerInstrument(name: string, instrument: CustomInstrument): void;
|
|
59
|
+
/** Every instrument name currently available */
|
|
60
|
+
export declare function instrumentNames(): string[];
|
|
61
|
+
/** Look up an instrument; throws a helpful error for unknown names */
|
|
62
|
+
export declare function getInstrument(name: string): InstrumentDef;
|
|
63
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/instruments/registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD,4FAA4F;AAC5F,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAE/D,yDAAyD;AACzD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,qCAAqC;IACrC,WAAW,EAAE,SAAS,CAAC;IACvB,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IAC3B,6DAA6D;IAC7D,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC1C;AAED,2FAA2F;AAC3F,MAAM,WAAW,uBAAuB;IACtC,8CAA8C;IAC9C,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IACtF,yGAAyG;IACzG,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,yDAAyD;AACzD,MAAM,WAAW,qBAAqB;IACpC,6CAA6C;IAC7C,IAAI,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,gBAAgB,GAAG,uBAAuB,GAAG,qBAAqB,CAAC;AAI/E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAmBnF;AAED,gDAAgD;AAChD,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAIzD"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// The instrument registry: every name a track can use, built-in or registered by the application.
|
|
2
|
+
import { BUILT_IN } from './builtin.js';
|
|
3
|
+
import { forgetSamples } from './samples.js';
|
|
4
|
+
const registry = new Map(Object.entries(BUILT_IN));
|
|
5
|
+
/**
|
|
6
|
+
* Add an instrument (or replace one) under a name tracks can use.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* registerInstrument('beep', {
|
|
10
|
+
* play({ context, destination, time, duration, frequency, velocity }) {
|
|
11
|
+
* const osc = new OscillatorNode(context, { type: 'square', frequency });
|
|
12
|
+
* const amp = new GainNode(context, { gain: velocity * 0.2 });
|
|
13
|
+
* osc.connect(amp).connect(destination);
|
|
14
|
+
* osc.start(time);
|
|
15
|
+
* osc.stop(time + duration);
|
|
16
|
+
* },
|
|
17
|
+
* });
|
|
18
|
+
*/
|
|
19
|
+
export function registerInstrument(name, instrument) {
|
|
20
|
+
forgetSamples(name);
|
|
21
|
+
if ('play' in instrument) {
|
|
22
|
+
registry.set(name, {
|
|
23
|
+
kind: 'live',
|
|
24
|
+
level: instrument.level ?? 1,
|
|
25
|
+
glide: instrument.glide ?? false,
|
|
26
|
+
voice: (c) => instrument.play({ context: c.ctx, destination: c.out, time: c.t, duration: c.dur, frequency: c.f, velocity: c.vel, glides: c.bends ?? [], params: c.o }),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
registry.set(name, {
|
|
31
|
+
kind: 'sample',
|
|
32
|
+
render: (sampleRate, midi) => instrument.render(sampleRate, midi),
|
|
33
|
+
hold: instrument.sustain ?? 'ring',
|
|
34
|
+
release: instrument.release ?? 0.2,
|
|
35
|
+
level: instrument.level ?? 1,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Every instrument name currently available */
|
|
40
|
+
export function instrumentNames() {
|
|
41
|
+
return [...registry.keys()];
|
|
42
|
+
}
|
|
43
|
+
/** Look up an instrument; throws a helpful error for unknown names */
|
|
44
|
+
export function getInstrument(name) {
|
|
45
|
+
const def = registry.get(name);
|
|
46
|
+
if (!def)
|
|
47
|
+
throw new Error(`Unknown instrument "${name}". Available: ${instrumentNames().join(', ')}`);
|
|
48
|
+
return def;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/instruments/registry.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAElG,OAAO,EAAE,QAAQ,EAA0B,MAAM,cAAc,CAAC;AAEhE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAgD7C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAwB,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;AAE1E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,UAA4B;IAC3E,aAAa,CAAC,IAAI,CAAC,CAAC;IACpB,IAAI,MAAM,IAAI,UAAU,EAAE,CAAC;QACzB,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE;YACjB,IAAI,EAAE,MAAM;YACZ,KAAK,EAAE,UAAU,CAAC,KAAK,IAAI,CAAC;YAC5B,KAAK,EAAE,UAAU,CAAC,KAAK,IAAI,KAAK;YAChC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CACX,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3J,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE;YACjB,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC;YACjE,IAAI,EAAE,UAAU,CAAC,OAAO,IAAI,MAAM;YAClC,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,GAAG;YAClC,KAAK,EAAE,UAAU,CAAC,KAAK,IAAI,CAAC;SAC7B,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,iBAAiB,eAAe,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtG,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { SampledInstrument } from './definition.ts';
|
|
2
|
+
/** A sample a song needs rendered before it plays */
|
|
3
|
+
export interface SampleRequest {
|
|
4
|
+
def: SampledInstrument;
|
|
5
|
+
name: string;
|
|
6
|
+
midi: number;
|
|
7
|
+
/** Only this layer (bowed strings pick soft or hard by velocity) */
|
|
8
|
+
layer?: number;
|
|
9
|
+
/** Bowed strings: the desk (players) of the track that plays it, 0 for the first */
|
|
10
|
+
desk?: number;
|
|
11
|
+
}
|
|
12
|
+
/** The pitch actually rendered: bowed strings sample every few semitones, fixed-pitch drums always use one note */
|
|
13
|
+
export declare function sampleMidi(def: SampledInstrument, midi: number): number;
|
|
14
|
+
/** Which layer a bowed string uses at this velocity (times params.bright); near the threshold both layers are prepared (velocity has a little randomness at playback) */
|
|
15
|
+
export declare function bowLayers(def: SampledInstrument, velocity: number, bright?: number): number[];
|
|
16
|
+
/** How many variants of a sampled instrument to precompute (random variants for drums; the soft and hard layers for bowed strings) */
|
|
17
|
+
export declare const variantsOf: (def: SampledInstrument) => number;
|
|
18
|
+
/** Whether a sample is already rendered */
|
|
19
|
+
export declare function hasSample(sampleRate: number, def: SampledInstrument, name: string, midi: number, variant: number, desk?: number): boolean;
|
|
20
|
+
/** The loop section (seconds) of a bowed sample, if it has one */
|
|
21
|
+
export declare const loopOf: (buffer: AudioBuffer) => [number, number] | undefined;
|
|
22
|
+
/** Render (or fetch from the cache) a sample */
|
|
23
|
+
export declare function getSample(ctx: BaseAudioContext, def: SampledInstrument, name: string, midi: number, variant?: number, desk?: number): AudioBuffer;
|
|
24
|
+
/** Drop every cached sample of an instrument (after it is redefined) */
|
|
25
|
+
export declare function forgetSamples(name: string): void;
|
|
26
|
+
/** Render samples ahead of time; after more than 12 ms of continuous work, yield the main thread for a moment (so the screen does not stall) */
|
|
27
|
+
export declare function prepareSamples(ctx: BaseAudioContext, requests: Iterable<SampleRequest>): Promise<void>;
|
|
28
|
+
/** Synchronous version (offline rendering, short play-once jingles) */
|
|
29
|
+
export declare function prepareSamplesSync(ctx: BaseAudioContext, requests: Iterable<SampleRequest>): void;
|
|
30
|
+
//# sourceMappingURL=samples.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"samples.d.ts","sourceRoot":"","sources":["../../src/instruments/samples.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,iBAAiB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAUD,mHAAmH;AACnH,wBAAgB,UAAU,CAAC,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGvE;AAkBD,yKAAyK;AACzK,wBAAgB,SAAS,CAAC,GAAG,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,MAAM,EAAE,CAKxF;AAED,sIAAsI;AACtI,eAAO,MAAM,UAAU,QAAS,iBAAiB,KAAG,MAA6C,CAAC;AAKlG,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,OAAO,CAEpI;AAED,kEAAkE;AAClE,eAAO,MAAM,MAAM,WAAY,WAAW,KAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAA8B,CAAC;AAE/F,gDAAgD;AAChD,wBAAgB,SAAS,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,SAAI,EAAE,IAAI,SAAI,GAAG,WAAW,CAmBvI;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEhD;AAOD,gJAAgJ;AAChJ,wBAAsB,cAAc,CAAC,GAAG,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAY5G;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,IAAI,CAEjG"}
|