reframe-video 0.6.25 → 0.6.27
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/dist/bin.js +388 -50
- package/dist/cli.js +390 -49
- package/dist/compile-api.js +30 -1
- package/dist/compile.js +30 -1
- package/dist/diff.js +28 -1
- package/dist/frame.js +28 -1
- package/dist/index.js +72 -6
- package/dist/labels.js +28 -1
- package/dist/types/audio.d.ts +2 -2
- package/dist/types/camera.d.ts +27 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/ir.d.ts +21 -4
- package/guides/edsl-guide.md +38 -6
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -10,10 +10,34 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// ../core/src/ir.ts
|
|
13
|
-
var DEFAULT_TO_DURATION, DEFAULT_TWEEN_DURATION, DEFAULT_MOTIONPATH_DURATION, DEFAULT_STILL_DURATION;
|
|
13
|
+
var SFX_NAMES, BGM_SYNTHS, DEFAULT_TO_DURATION, DEFAULT_TWEEN_DURATION, DEFAULT_MOTIONPATH_DURATION, DEFAULT_STILL_DURATION;
|
|
14
14
|
var init_ir = __esm({
|
|
15
15
|
"../core/src/ir.ts"() {
|
|
16
16
|
"use strict";
|
|
17
|
+
SFX_NAMES = [
|
|
18
|
+
"whoosh",
|
|
19
|
+
"swish",
|
|
20
|
+
"rise",
|
|
21
|
+
"riser",
|
|
22
|
+
"warp",
|
|
23
|
+
"tick",
|
|
24
|
+
"click",
|
|
25
|
+
"blip",
|
|
26
|
+
"pop",
|
|
27
|
+
"select",
|
|
28
|
+
"thud",
|
|
29
|
+
"boom",
|
|
30
|
+
"knock",
|
|
31
|
+
"chime",
|
|
32
|
+
"ding",
|
|
33
|
+
"coin",
|
|
34
|
+
"sparkle",
|
|
35
|
+
"shimmer",
|
|
36
|
+
"success",
|
|
37
|
+
"zap",
|
|
38
|
+
"error"
|
|
39
|
+
];
|
|
40
|
+
BGM_SYNTHS = ["ambient-pad", "lofi", "pulse", "tension", "uplift"];
|
|
17
41
|
DEFAULT_TO_DURATION = 0.5;
|
|
18
42
|
DEFAULT_TWEEN_DURATION = 0.5;
|
|
19
43
|
DEFAULT_MOTIONPATH_DURATION = 1;
|
|
@@ -647,7 +671,6 @@ function validateScene(ir) {
|
|
|
647
671
|
}
|
|
648
672
|
}
|
|
649
673
|
}
|
|
650
|
-
const SFX_NAMES = ["whoosh", "pop", "tick", "rise", "shimmer", "thud"];
|
|
651
674
|
for (const [i, cue] of (ir.audio?.cues ?? []).entries()) {
|
|
652
675
|
if (typeof cue.at === "string" && !labels.has(cue.at)) {
|
|
653
676
|
problems.push(
|
|
@@ -683,6 +706,10 @@ function validateScene(ir) {
|
|
|
683
706
|
if (ir.audio?.bgm?.file !== void 0 && ir.audio.bgm.synth !== void 0) {
|
|
684
707
|
problems.push('audio.bgm: use either "file" or "synth", not both');
|
|
685
708
|
}
|
|
709
|
+
const bgmSynth = ir.audio?.bgm?.synth;
|
|
710
|
+
if (bgmSynth !== void 0 && !BGM_SYNTHS.includes(bgmSynth)) {
|
|
711
|
+
problems.push(`audio.bgm.synth: unknown synth "${bgmSynth}" \u2014 valid: ${BGM_SYNTHS.join(", ")}`);
|
|
712
|
+
}
|
|
686
713
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
687
714
|
}
|
|
688
715
|
function validateComposition(comp) {
|
|
@@ -718,6 +745,7 @@ var EASE_SET, FX_PROPS, BLEND_MODES, IMAGE_FITS, COMMON_PROPS, CAMERA_PROPS, PRO
|
|
|
718
745
|
var init_validate = __esm({
|
|
719
746
|
"../core/src/validate.ts"() {
|
|
720
747
|
"use strict";
|
|
748
|
+
init_ir();
|
|
721
749
|
init_interpolate();
|
|
722
750
|
EASE_SET = new Set(EASE_NAMES);
|
|
723
751
|
FX_PROPS = ["blur", "shadowColor", "shadowBlur", "shadowX", "shadowY", "blend"];
|
|
@@ -1395,7 +1423,11 @@ function resolveAudioPlan(compiled) {
|
|
|
1395
1423
|
fadeIn: cue.fadeIn ?? 0,
|
|
1396
1424
|
fadeOut: cue.fadeOut ?? 0,
|
|
1397
1425
|
pan: cue.pan ?? 0,
|
|
1398
|
-
source: cue.sfx ?
|
|
1426
|
+
source: cue.sfx ? (
|
|
1427
|
+
// auto-vary: default the seed to the cue's order so repeated sfx differ
|
|
1428
|
+
// (pitch/texture); an explicit params.seed always wins.
|
|
1429
|
+
{ kind: "sfx", name: cue.sfx, params: { seed: index, ...cue.params } }
|
|
1430
|
+
) : { kind: "file", path: cue.file }
|
|
1399
1431
|
});
|
|
1400
1432
|
}
|
|
1401
1433
|
cues.sort((a, b) => a.t - b.t);
|
|
@@ -1438,12 +1470,32 @@ var init_audio = __esm({
|
|
|
1438
1470
|
"../core/src/audio.ts"() {
|
|
1439
1471
|
"use strict";
|
|
1440
1472
|
SFX_DURATION = {
|
|
1473
|
+
// transition
|
|
1441
1474
|
whoosh: 0.35,
|
|
1442
|
-
|
|
1443
|
-
tick: 0.03,
|
|
1475
|
+
swish: 0.32,
|
|
1444
1476
|
rise: 0.5,
|
|
1477
|
+
riser: 0.85,
|
|
1478
|
+
warp: 0.5,
|
|
1479
|
+
// ui
|
|
1480
|
+
tick: 0.03,
|
|
1481
|
+
click: 0.05,
|
|
1482
|
+
blip: 0.1,
|
|
1483
|
+
pop: 0.12,
|
|
1484
|
+
select: 0.18,
|
|
1485
|
+
// impact
|
|
1486
|
+
thud: 0.25,
|
|
1487
|
+
boom: 0.6,
|
|
1488
|
+
knock: 0.14,
|
|
1489
|
+
// positive
|
|
1490
|
+
chime: 0.7,
|
|
1491
|
+
ding: 0.5,
|
|
1492
|
+
coin: 0.3,
|
|
1493
|
+
sparkle: 0.6,
|
|
1445
1494
|
shimmer: 0.9,
|
|
1446
|
-
|
|
1495
|
+
success: 0.6,
|
|
1496
|
+
// alert
|
|
1497
|
+
zap: 0.22,
|
|
1498
|
+
error: 0.4
|
|
1447
1499
|
};
|
|
1448
1500
|
FILE_CUE_DURATION = 0.4;
|
|
1449
1501
|
}
|
|
@@ -1739,19 +1791,21 @@ function hash01(n, seed) {
|
|
|
1739
1791
|
h = (h ^ h >>> 16) >>> 0;
|
|
1740
1792
|
return h / 4294967295;
|
|
1741
1793
|
}
|
|
1794
|
+
function seedPitch(seed) {
|
|
1795
|
+
const i = (Math.round(seed) % PITCH_STEPS.length + PITCH_STEPS.length) % PITCH_STEPS.length;
|
|
1796
|
+
return Math.pow(2, PITCH_STEPS[i] / 12);
|
|
1797
|
+
}
|
|
1742
1798
|
function buffer(duration) {
|
|
1743
1799
|
const n = Math.round(duration * SAMPLE_RATE);
|
|
1744
1800
|
return { out: new Float32Array(n), n };
|
|
1745
1801
|
}
|
|
1746
|
-
function whoosh(seed) {
|
|
1802
|
+
function whoosh(seed, pitch) {
|
|
1747
1803
|
const dur2 = 0.35;
|
|
1748
1804
|
const { out, n } = buffer(dur2);
|
|
1749
|
-
let lp = 0;
|
|
1750
|
-
let lp2 = 0;
|
|
1805
|
+
let lp = 0, lp2 = 0;
|
|
1751
1806
|
for (let i = 0; i < n; i++) {
|
|
1752
|
-
const t = i / SAMPLE_RATE;
|
|
1753
|
-
const
|
|
1754
|
-
const center = 1200 * Math.pow(300 / 1200, u);
|
|
1807
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
1808
|
+
const center = 1200 * pitch * Math.pow(0.25, u);
|
|
1755
1809
|
const alpha = Math.min(1, TAU * center / SAMPLE_RATE);
|
|
1756
1810
|
lp += alpha * (noise(i, seed) - lp);
|
|
1757
1811
|
lp2 += alpha * 0.5 * (lp - lp2);
|
|
@@ -1760,103 +1814,363 @@ function whoosh(seed) {
|
|
|
1760
1814
|
}
|
|
1761
1815
|
return out;
|
|
1762
1816
|
}
|
|
1763
|
-
function
|
|
1817
|
+
function swish(seed, pitch) {
|
|
1818
|
+
const dur2 = 0.32;
|
|
1819
|
+
const { out, n } = buffer(dur2);
|
|
1820
|
+
let lp = 0, lp2 = 0;
|
|
1821
|
+
for (let i = 0; i < n; i++) {
|
|
1822
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
1823
|
+
const center = 2600 * pitch * Math.pow(0.2, u);
|
|
1824
|
+
const alpha = Math.min(1, TAU * center / SAMPLE_RATE);
|
|
1825
|
+
lp += alpha * (noise(i, seed) - lp);
|
|
1826
|
+
lp2 += alpha * 0.5 * (lp - lp2);
|
|
1827
|
+
const env = u < 0.15 ? u / 0.15 : expDecay(t - 0.15 * dur2, dur2 * 0.85, 5);
|
|
1828
|
+
out[i] = (lp - lp2) * env * 2.4;
|
|
1829
|
+
}
|
|
1830
|
+
return out;
|
|
1831
|
+
}
|
|
1832
|
+
function rise(_seed, pitch) {
|
|
1833
|
+
const dur2 = 0.5;
|
|
1834
|
+
const { out, n } = buffer(dur2);
|
|
1835
|
+
let phase = 0;
|
|
1836
|
+
for (let i = 0; i < n; i++) {
|
|
1837
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
1838
|
+
const freq = 220 * pitch * Math.pow(4, u);
|
|
1839
|
+
phase += TAU * freq / SAMPLE_RATE;
|
|
1840
|
+
const env = Math.sin(Math.PI * Math.min(1, u * 1.05)) ** 1.5;
|
|
1841
|
+
out[i] = (Math.sin(phase) + 0.3 * Math.sin(2 * phase)) * env * 0.45;
|
|
1842
|
+
}
|
|
1843
|
+
return out;
|
|
1844
|
+
}
|
|
1845
|
+
function riser(seed, pitch) {
|
|
1846
|
+
const dur2 = 0.85;
|
|
1847
|
+
const { out, n } = buffer(dur2);
|
|
1848
|
+
let lp = 0, phase = 0;
|
|
1849
|
+
for (let i = 0; i < n; i++) {
|
|
1850
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
1851
|
+
const center = 200 * pitch * Math.pow(12, u);
|
|
1852
|
+
const alpha = Math.min(1, TAU * center / SAMPLE_RATE);
|
|
1853
|
+
lp += alpha * (noise(i, seed) - lp);
|
|
1854
|
+
const freq = 120 * pitch * Math.pow(6, u);
|
|
1855
|
+
phase += TAU * freq / SAMPLE_RATE;
|
|
1856
|
+
const env = Math.pow(u, 1.6);
|
|
1857
|
+
out[i] = (lp * 1.6 + Math.sin(phase) * 0.5) * env * 0.9;
|
|
1858
|
+
}
|
|
1859
|
+
return out;
|
|
1860
|
+
}
|
|
1861
|
+
function warp(_seed, pitch) {
|
|
1862
|
+
const dur2 = 0.5;
|
|
1863
|
+
const { out, n } = buffer(dur2);
|
|
1864
|
+
let phase = 0;
|
|
1865
|
+
for (let i = 0; i < n; i++) {
|
|
1866
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
1867
|
+
const bend = Math.sin(Math.PI * u);
|
|
1868
|
+
const vib = 1 + 0.4 * Math.sin(TAU * 18 * t);
|
|
1869
|
+
const freq = 300 * pitch * (1 + 2.5 * bend) * vib;
|
|
1870
|
+
phase += TAU * freq / SAMPLE_RATE;
|
|
1871
|
+
const env = Math.sin(Math.PI * u) ** 0.8;
|
|
1872
|
+
out[i] = square(phase) * env * 0.5;
|
|
1873
|
+
}
|
|
1874
|
+
return out;
|
|
1875
|
+
}
|
|
1876
|
+
function tick(seed, pitch) {
|
|
1877
|
+
const dur2 = 0.03;
|
|
1878
|
+
const { out, n } = buffer(dur2);
|
|
1879
|
+
for (let i = 0; i < n; i++) {
|
|
1880
|
+
const t = i / SAMPLE_RATE;
|
|
1881
|
+
const sine = t < 4e-3 ? Math.sin(TAU * 4e3 * pitch * t) : 0;
|
|
1882
|
+
out[i] = (sine * 0.6 + noise(i, seed) * 0.35) * expDecay(t, dur2, 8);
|
|
1883
|
+
}
|
|
1884
|
+
return out;
|
|
1885
|
+
}
|
|
1886
|
+
function click(seed, pitch) {
|
|
1887
|
+
const dur2 = 0.05;
|
|
1888
|
+
const { out, n } = buffer(dur2);
|
|
1889
|
+
let lp = 0;
|
|
1890
|
+
for (let i = 0; i < n; i++) {
|
|
1891
|
+
const t = i / SAMPLE_RATE;
|
|
1892
|
+
lp += 0.5 * (noise(i, seed) - lp);
|
|
1893
|
+
const sine = Math.sin(TAU * 1500 * pitch * t);
|
|
1894
|
+
out[i] = (sine * 0.5 + lp * 0.6) * expDecay(t, dur2, 11);
|
|
1895
|
+
}
|
|
1896
|
+
return out;
|
|
1897
|
+
}
|
|
1898
|
+
function blip(_seed, pitch) {
|
|
1899
|
+
const dur2 = 0.1;
|
|
1900
|
+
const { out, n } = buffer(dur2);
|
|
1901
|
+
let phase = 0;
|
|
1902
|
+
for (let i = 0; i < n; i++) {
|
|
1903
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
1904
|
+
phase += TAU * 880 * pitch / SAMPLE_RATE;
|
|
1905
|
+
const env = Math.min(1, u * 12) * Math.min(1, (1 - u) * 6);
|
|
1906
|
+
out[i] = square(phase) * env * 0.5;
|
|
1907
|
+
}
|
|
1908
|
+
return out;
|
|
1909
|
+
}
|
|
1910
|
+
function pop(seed, pitch) {
|
|
1764
1911
|
const dur2 = 0.12;
|
|
1765
1912
|
const { out, n } = buffer(dur2);
|
|
1766
1913
|
let phase = 0;
|
|
1767
1914
|
for (let i = 0; i < n; i++) {
|
|
1768
1915
|
const t = i / SAMPLE_RATE;
|
|
1769
|
-
const freq = 600 * Math.pow(
|
|
1916
|
+
const freq = 600 * pitch * Math.pow(0.25, t / 0.08);
|
|
1770
1917
|
phase += TAU * freq / SAMPLE_RATE;
|
|
1771
1918
|
const transient = t < 2e-3 ? noise(i, seed) * 0.5 : 0;
|
|
1772
1919
|
out[i] = (Math.sin(phase) + transient) * expDecay(t, dur2, 6) * 0.8;
|
|
1773
1920
|
}
|
|
1774
1921
|
return out;
|
|
1775
1922
|
}
|
|
1776
|
-
function
|
|
1777
|
-
const dur2 = 0.
|
|
1923
|
+
function select(_seed, pitch) {
|
|
1924
|
+
const dur2 = 0.18;
|
|
1925
|
+
const { out, n } = buffer(dur2);
|
|
1926
|
+
let phase = 0;
|
|
1927
|
+
for (let i = 0; i < n; i++) {
|
|
1928
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
1929
|
+
const freq = (t < 0.08 ? 620 : 930) * pitch;
|
|
1930
|
+
phase += TAU * freq / SAMPLE_RATE;
|
|
1931
|
+
const env = Math.min(1, u * 16) * Math.min(1, (1 - u) * 5);
|
|
1932
|
+
out[i] = (Math.sin(phase) + 0.25 * Math.sin(2 * phase)) * env * 0.5;
|
|
1933
|
+
}
|
|
1934
|
+
return out;
|
|
1935
|
+
}
|
|
1936
|
+
function thud(seed, pitch) {
|
|
1937
|
+
const dur2 = 0.25;
|
|
1778
1938
|
const { out, n } = buffer(dur2);
|
|
1939
|
+
let phase = 0, lp = 0;
|
|
1779
1940
|
for (let i = 0; i < n; i++) {
|
|
1780
1941
|
const t = i / SAMPLE_RATE;
|
|
1781
|
-
const
|
|
1782
|
-
|
|
1942
|
+
const freq = 90 * pitch * Math.pow(0.5, t / 0.15);
|
|
1943
|
+
phase += TAU * freq / SAMPLE_RATE;
|
|
1944
|
+
lp += 0.02 * (noise(i, seed) - lp);
|
|
1945
|
+
const attack = t < 0.01 ? lp * 3 : 0;
|
|
1946
|
+
out[i] = (Math.sin(phase) * 0.9 + attack) * expDecay(t, dur2, 5);
|
|
1783
1947
|
}
|
|
1784
1948
|
return out;
|
|
1785
1949
|
}
|
|
1786
|
-
function
|
|
1950
|
+
function boom(seed, pitch) {
|
|
1951
|
+
const dur2 = 0.6;
|
|
1952
|
+
const { out, n } = buffer(dur2);
|
|
1953
|
+
let phase = 0, lp = 0;
|
|
1954
|
+
for (let i = 0; i < n; i++) {
|
|
1955
|
+
const t = i / SAMPLE_RATE;
|
|
1956
|
+
const freq = 70 * pitch * Math.pow(0.5, t / 0.3);
|
|
1957
|
+
phase += TAU * freq / SAMPLE_RATE;
|
|
1958
|
+
lp += 0.06 * (noise(i, seed) - lp);
|
|
1959
|
+
const body = t < 0.06 ? lp * 2.5 * (1 - t / 0.06) : 0;
|
|
1960
|
+
out[i] = (Math.sin(phase) * 1 + body) * expDecay(t, dur2, 3.2);
|
|
1961
|
+
}
|
|
1962
|
+
return out;
|
|
1963
|
+
}
|
|
1964
|
+
function knock(seed, pitch) {
|
|
1965
|
+
const dur2 = 0.14;
|
|
1966
|
+
const { out, n } = buffer(dur2);
|
|
1967
|
+
let phase = 0, lp = 0;
|
|
1968
|
+
for (let i = 0; i < n; i++) {
|
|
1969
|
+
const t = i / SAMPLE_RATE;
|
|
1970
|
+
const freq = 220 * pitch * Math.pow(0.7, t / 0.05);
|
|
1971
|
+
phase += TAU * freq / SAMPLE_RATE;
|
|
1972
|
+
lp += 0.3 * (noise(i, seed) - lp);
|
|
1973
|
+
const tap = t < 5e-3 ? lp : 0;
|
|
1974
|
+
out[i] = (Math.sin(phase) * 0.8 + tap * 0.6) * expDecay(t, dur2, 9);
|
|
1975
|
+
}
|
|
1976
|
+
return out;
|
|
1977
|
+
}
|
|
1978
|
+
function chime(seed, pitch) {
|
|
1979
|
+
const dur2 = 0.7;
|
|
1980
|
+
const { out, n } = buffer(dur2);
|
|
1981
|
+
const f0 = 800 * pitch;
|
|
1982
|
+
const partials = [
|
|
1983
|
+
{ f: f0, a: 1, k: 4 },
|
|
1984
|
+
{ f: f0 * 2.76, a: 0.5, k: 5.5 },
|
|
1985
|
+
{ f: f0 * 5.4, a: 0.28, k: 7 },
|
|
1986
|
+
{ f: f0 * 8.9, a: 0.13, k: 9 }
|
|
1987
|
+
];
|
|
1988
|
+
for (let i = 0; i < n; i++) {
|
|
1989
|
+
const t = i / SAMPLE_RATE;
|
|
1990
|
+
let s = 0;
|
|
1991
|
+
for (const p of partials) s += Math.sin(TAU * p.f * t) * p.a * expDecay(t, dur2, p.k);
|
|
1992
|
+
const strike = t < 3e-3 ? noise(i, seed) * 0.3 : 0;
|
|
1993
|
+
out[i] = (s / 1.9 + strike) * 0.6;
|
|
1994
|
+
}
|
|
1995
|
+
return out;
|
|
1996
|
+
}
|
|
1997
|
+
function ding(_seed, pitch) {
|
|
1787
1998
|
const dur2 = 0.5;
|
|
1788
1999
|
const { out, n } = buffer(dur2);
|
|
1789
|
-
|
|
2000
|
+
const f0 = 1200 * pitch;
|
|
1790
2001
|
for (let i = 0; i < n; i++) {
|
|
1791
2002
|
const t = i / SAMPLE_RATE;
|
|
1792
|
-
const
|
|
1793
|
-
|
|
2003
|
+
const s = Math.sin(TAU * f0 * t) + 0.4 * Math.sin(TAU * f0 * 2 * t) + 0.2 * Math.sin(TAU * f0 * 3.01 * t);
|
|
2004
|
+
out[i] = s / 1.6 * expDecay(t, dur2, 4.5) * 0.6;
|
|
2005
|
+
}
|
|
2006
|
+
return out;
|
|
2007
|
+
}
|
|
2008
|
+
function coin(_seed, pitch) {
|
|
2009
|
+
const dur2 = 0.3;
|
|
2010
|
+
const { out, n } = buffer(dur2);
|
|
2011
|
+
let phase = 0;
|
|
2012
|
+
for (let i = 0; i < n; i++) {
|
|
2013
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
2014
|
+
const freq = (t < 0.06 ? 988 : 1319) * pitch;
|
|
1794
2015
|
phase += TAU * freq / SAMPLE_RATE;
|
|
1795
|
-
const env = Math.
|
|
1796
|
-
out[i] = (
|
|
2016
|
+
const env = Math.min(1, u * 30) * expDecay(Math.max(0, t - 0.06), dur2, 3.5);
|
|
2017
|
+
out[i] = square(phase) * env * 0.55;
|
|
2018
|
+
}
|
|
2019
|
+
return out;
|
|
2020
|
+
}
|
|
2021
|
+
function sparkle(seed, pitch) {
|
|
2022
|
+
const dur2 = 0.6;
|
|
2023
|
+
const { out, n } = buffer(dur2);
|
|
2024
|
+
const steps = [1, 1.5, 2, 3, 4, 5, 6];
|
|
2025
|
+
const base = 1200 * pitch;
|
|
2026
|
+
for (let i = 0; i < n; i++) {
|
|
2027
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
2028
|
+
let s = 0;
|
|
2029
|
+
for (let g = 0; g < steps.length; g++) {
|
|
2030
|
+
const on = u * steps.length - g;
|
|
2031
|
+
if (on > 0 && on < 3) {
|
|
2032
|
+
const ge = Math.exp(-on * 1.8);
|
|
2033
|
+
s += Math.sin(TAU * base * steps[g] * t + hash01(g, seed) * TAU) * ge;
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
out[i] = s / 2.4 * Math.sin(Math.PI * u) ** 0.5 * 0.5;
|
|
2037
|
+
}
|
|
2038
|
+
return out;
|
|
2039
|
+
}
|
|
2040
|
+
function success(_seed, pitch) {
|
|
2041
|
+
const dur2 = 0.6;
|
|
2042
|
+
const { out, n } = buffer(dur2);
|
|
2043
|
+
const notes = [523.25, 659.25, 783.99].map((f) => f * pitch);
|
|
2044
|
+
let phase = 0, cur = 0;
|
|
2045
|
+
for (let i = 0; i < n; i++) {
|
|
2046
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
2047
|
+
const idx = Math.min(notes.length - 1, Math.floor(u * 3.2));
|
|
2048
|
+
if (idx !== cur) cur = idx;
|
|
2049
|
+
phase += TAU * notes[cur] / SAMPLE_RATE;
|
|
2050
|
+
const local = u * 3.2 - idx;
|
|
2051
|
+
const env = Math.min(1, local * 12) * Math.min(1, (1 - Math.min(1, local)) * 4 + 0.2);
|
|
2052
|
+
out[i] = (Math.sin(phase) + 0.3 * Math.sin(2 * phase)) * env * 0.42;
|
|
1797
2053
|
}
|
|
1798
2054
|
return out;
|
|
1799
2055
|
}
|
|
1800
|
-
function shimmer(seed) {
|
|
2056
|
+
function shimmer(seed, pitch) {
|
|
1801
2057
|
const dur2 = 0.9;
|
|
1802
2058
|
const { out, n } = buffer(dur2);
|
|
1803
2059
|
const partials = Array.from({ length: 5 }, (_, p) => ({
|
|
1804
|
-
freq: 2e3 + hash01(p, seed + 7) * 2e3,
|
|
2060
|
+
freq: (2e3 + hash01(p, seed + 7) * 2e3) * pitch,
|
|
1805
2061
|
am: 0.5 + hash01(p, seed + 8) * 1.5,
|
|
1806
2062
|
phase: hash01(p, seed + 9) * TAU
|
|
1807
2063
|
}));
|
|
1808
2064
|
for (let i = 0; i < n; i++) {
|
|
1809
|
-
const t = i / SAMPLE_RATE;
|
|
1810
|
-
const u = t / dur2;
|
|
2065
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
1811
2066
|
const env = Math.sin(Math.PI * u) ** 1.2;
|
|
1812
2067
|
let s = 0;
|
|
1813
|
-
for (const part of partials)
|
|
1814
|
-
s += Math.sin(TAU * part.freq * t + part.phase) * (0.6 + 0.4 * Math.sin(TAU * part.am * t));
|
|
1815
|
-
}
|
|
2068
|
+
for (const part of partials) s += Math.sin(TAU * part.freq * t + part.phase) * (0.6 + 0.4 * Math.sin(TAU * part.am * t));
|
|
1816
2069
|
out[i] = s / 5 * env * 0.5;
|
|
1817
2070
|
}
|
|
1818
2071
|
return out;
|
|
1819
2072
|
}
|
|
1820
|
-
function
|
|
1821
|
-
const dur2 = 0.
|
|
2073
|
+
function zap(seed, pitch) {
|
|
2074
|
+
const dur2 = 0.22;
|
|
1822
2075
|
const { out, n } = buffer(dur2);
|
|
1823
2076
|
let phase = 0;
|
|
1824
|
-
let lp = 0;
|
|
1825
2077
|
for (let i = 0; i < n; i++) {
|
|
1826
|
-
const t = i / SAMPLE_RATE;
|
|
1827
|
-
const freq =
|
|
2078
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
2079
|
+
const freq = 1600 * pitch * Math.pow(0.12, u);
|
|
1828
2080
|
phase += TAU * freq / SAMPLE_RATE;
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
2081
|
+
const grit = noise(i, seed) * 0.25;
|
|
2082
|
+
out[i] = (square(phase) + grit) * expDecay(t, dur2, 4.5) * 0.5;
|
|
2083
|
+
}
|
|
2084
|
+
return out;
|
|
2085
|
+
}
|
|
2086
|
+
function error(_seed, pitch) {
|
|
2087
|
+
const dur2 = 0.4;
|
|
2088
|
+
const { out, n } = buffer(dur2);
|
|
2089
|
+
let phase = 0;
|
|
2090
|
+
for (let i = 0; i < n; i++) {
|
|
2091
|
+
const t = i / SAMPLE_RATE, u = t / dur2;
|
|
2092
|
+
const freq = (t < 0.16 ? 311 : 233) * pitch;
|
|
2093
|
+
phase += TAU * freq / SAMPLE_RATE;
|
|
2094
|
+
const seg = t < 0.16 ? u / 0.4 : (u - 0.4) / 0.6;
|
|
2095
|
+
const env = Math.min(1, seg * 18) * Math.min(1, (1 - seg) * 6);
|
|
2096
|
+
out[i] = square(phase) * env * 0.5;
|
|
1832
2097
|
}
|
|
1833
2098
|
return out;
|
|
1834
2099
|
}
|
|
1835
2100
|
function synthSfx(name, params = {}) {
|
|
1836
|
-
const
|
|
2101
|
+
const seed = params.seed ?? 0;
|
|
2102
|
+
const pitch = (params.pitch ?? 1) * seedPitch(seed);
|
|
2103
|
+
const samples = RECIPES[name](seed, pitch);
|
|
1837
2104
|
if (params.gainDb) {
|
|
1838
2105
|
const g = Math.pow(10, params.gainDb / 20);
|
|
1839
2106
|
for (let i = 0; i < samples.length; i++) samples[i] *= g;
|
|
1840
2107
|
}
|
|
2108
|
+
let peak = 0;
|
|
2109
|
+
for (let i = 0; i < samples.length; i++) peak = Math.max(peak, Math.abs(samples[i]));
|
|
2110
|
+
if (peak > 0.95) {
|
|
2111
|
+
const g = 0.95 / peak;
|
|
2112
|
+
for (let i = 0; i < samples.length; i++) samples[i] *= g;
|
|
2113
|
+
}
|
|
1841
2114
|
return samples;
|
|
1842
2115
|
}
|
|
1843
|
-
function
|
|
2116
|
+
function pad(freqs, duration, seed, opts) {
|
|
1844
2117
|
const { out, n } = buffer(duration);
|
|
1845
|
-
const voices =
|
|
1846
|
-
{ freq: f * (1 + (hash01(v, seed + 3) - 0.5) * 4e-3), am:
|
|
1847
|
-
{ freq: f * (1 - (hash01(v, seed + 6) - 0.5) * 4e-3), am:
|
|
2118
|
+
const voices = freqs.flatMap((f, v) => [
|
|
2119
|
+
{ freq: f * (1 + (hash01(v, seed + 3) - 0.5) * 4e-3), am: opts.amBase + hash01(v, seed + 4) * 0.08, phase: hash01(v, seed + 5) * TAU },
|
|
2120
|
+
{ freq: f * (1 - (hash01(v, seed + 6) - 0.5) * 4e-3), am: opts.amBase + hash01(v, seed + 7) * 0.08, phase: hash01(v, seed + 8) * TAU }
|
|
1848
2121
|
]);
|
|
1849
2122
|
for (let i = 0; i < n; i++) {
|
|
1850
2123
|
const t = i / SAMPLE_RATE;
|
|
1851
2124
|
let s = 0;
|
|
1852
2125
|
for (const voice of voices) {
|
|
1853
2126
|
s += Math.sin(TAU * voice.freq * t + voice.phase) * (0.75 + 0.25 * Math.sin(TAU * voice.am * t));
|
|
2127
|
+
if (opts.bright > 0) s += opts.bright * Math.sin(TAU * voice.freq * 2 * t + voice.phase);
|
|
1854
2128
|
}
|
|
1855
|
-
out[i] = s / voices.length *
|
|
2129
|
+
out[i] = s / voices.length * opts.gain;
|
|
1856
2130
|
}
|
|
1857
2131
|
return out;
|
|
1858
2132
|
}
|
|
1859
|
-
|
|
2133
|
+
function synthAmbientPad(duration, seed = 0) {
|
|
2134
|
+
return pad([110, 165, 220], duration, seed, { amBase: 0.05, bright: 0, gain: 0.7 });
|
|
2135
|
+
}
|
|
2136
|
+
function synthLofi(duration, seed = 0) {
|
|
2137
|
+
return pad([130.81, 164.81, 196, 246.94], duration, seed, { amBase: 0.04, bright: 0.04, gain: 0.62 });
|
|
2138
|
+
}
|
|
2139
|
+
function synthPulse(duration, _seed = 0) {
|
|
2140
|
+
const { out, n } = buffer(duration);
|
|
2141
|
+
const beat2 = 2.2;
|
|
2142
|
+
for (let i = 0; i < n; i++) {
|
|
2143
|
+
const t = i / SAMPLE_RATE;
|
|
2144
|
+
const ph = t * beat2 % 1;
|
|
2145
|
+
const gate = Math.exp(-ph * 5) * 0.9 + 0.1;
|
|
2146
|
+
const s = Math.sin(TAU * 82 * t) + 0.6 * Math.sin(TAU * 123 * t) + 0.3 * Math.sin(TAU * 246 * t);
|
|
2147
|
+
out[i] = s / 1.9 * gate * 0.6;
|
|
2148
|
+
}
|
|
2149
|
+
return out;
|
|
2150
|
+
}
|
|
2151
|
+
function synthTension(duration, seed = 0) {
|
|
2152
|
+
const { out, n } = buffer(duration);
|
|
2153
|
+
const base = [98, 104, 110];
|
|
2154
|
+
for (let i = 0; i < n; i++) {
|
|
2155
|
+
const t = i / SAMPLE_RATE;
|
|
2156
|
+
const drift = 1 + 0.03 * (t / Math.max(1e-3, duration));
|
|
2157
|
+
let s = 0;
|
|
2158
|
+
for (let v = 0; v < base.length; v++) {
|
|
2159
|
+
const f = base[v] * drift * (1 + (hash01(v, seed) - 0.5) * 6e-3);
|
|
2160
|
+
s += Math.sin(TAU * f * t + hash01(v, seed + 1) * TAU);
|
|
2161
|
+
}
|
|
2162
|
+
const swell = 0.6 + 0.4 * Math.sin(TAU * 0.08 * t);
|
|
2163
|
+
out[i] = s / base.length * swell * 0.6;
|
|
2164
|
+
}
|
|
2165
|
+
return out;
|
|
2166
|
+
}
|
|
2167
|
+
function synthUplift(duration, seed = 0) {
|
|
2168
|
+
return pad([196, 246.94, 293.66, 392], duration, seed, { amBase: 0.07, bright: 0.1, gain: 0.6 });
|
|
2169
|
+
}
|
|
2170
|
+
function synthBgm(name, duration, seed = 0) {
|
|
2171
|
+
return BGM_RECIPES[name](duration, seed);
|
|
2172
|
+
}
|
|
2173
|
+
var noise, TAU, expDecay, square, PITCH_STEPS, RECIPES, BGM_RECIPES;
|
|
1860
2174
|
var init_synth = __esm({
|
|
1861
2175
|
"../render-cli/src/audio/synth.ts"() {
|
|
1862
2176
|
"use strict";
|
|
@@ -1864,13 +2178,37 @@ var init_synth = __esm({
|
|
|
1864
2178
|
noise = (n, seed) => hash01(n, seed) * 2 - 1;
|
|
1865
2179
|
TAU = Math.PI * 2;
|
|
1866
2180
|
expDecay = (t, dur2, k = 5) => Math.exp(-k * t / dur2);
|
|
2181
|
+
square = (ph) => (Math.sin(ph) + 0.33 * Math.sin(3 * ph) + 0.2 * Math.sin(5 * ph)) / 1.4;
|
|
2182
|
+
PITCH_STEPS = [0, 2, 4, 7, 9, 12, 5, -3, 16, -5];
|
|
1867
2183
|
RECIPES = {
|
|
1868
2184
|
whoosh,
|
|
1869
|
-
|
|
1870
|
-
tick,
|
|
2185
|
+
swish,
|
|
1871
2186
|
rise,
|
|
2187
|
+
riser,
|
|
2188
|
+
warp,
|
|
2189
|
+
tick,
|
|
2190
|
+
click,
|
|
2191
|
+
blip,
|
|
2192
|
+
pop,
|
|
2193
|
+
select,
|
|
2194
|
+
thud,
|
|
2195
|
+
boom,
|
|
2196
|
+
knock,
|
|
2197
|
+
chime,
|
|
2198
|
+
ding,
|
|
2199
|
+
coin,
|
|
2200
|
+
sparkle,
|
|
1872
2201
|
shimmer,
|
|
1873
|
-
|
|
2202
|
+
success,
|
|
2203
|
+
zap,
|
|
2204
|
+
error
|
|
2205
|
+
};
|
|
2206
|
+
BGM_RECIPES = {
|
|
2207
|
+
"ambient-pad": synthAmbientPad,
|
|
2208
|
+
lofi: synthLofi,
|
|
2209
|
+
pulse: synthPulse,
|
|
2210
|
+
tension: synthTension,
|
|
2211
|
+
uplift: synthUplift
|
|
1874
2212
|
};
|
|
1875
2213
|
}
|
|
1876
2214
|
});
|
|
@@ -1925,7 +2263,7 @@ async function resolveBgmFile(source, duration, sceneDir) {
|
|
|
1925
2263
|
}
|
|
1926
2264
|
throw new Error(`bgm file "${p}" not found`);
|
|
1927
2265
|
}
|
|
1928
|
-
return writeCached(
|
|
2266
|
+
return writeCached(`${source.name}-${duration.toFixed(2)}`, () => synthBgm(source.name, duration));
|
|
1929
2267
|
}
|
|
1930
2268
|
var ROOT, VENDORED, CACHE;
|
|
1931
2269
|
var init_sfx = __esm({
|