@onjmin/dtm 0.1.47 → 0.1.49
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/index.d.mts +55 -2
- package/dist/index.d.ts +55 -2
- package/dist/index.js +408 -51
- package/dist/index.mjs +405 -51
- package/dist/voice-worker.js +90 -25
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -90,12 +90,14 @@ __export(index_exports, {
|
|
|
90
90
|
init: () => init,
|
|
91
91
|
injectStyles: () => injectStyles,
|
|
92
92
|
isChordHeavyTrack: () => isChordHeavyTrack,
|
|
93
|
+
isValidHttpUrl: () => isValidHttpUrl,
|
|
93
94
|
koeUrl: () => koeUrl,
|
|
94
95
|
mountDAW: () => mountDAW,
|
|
95
96
|
mountMmlPlayer: () => mountMmlPlayer,
|
|
96
97
|
normalizeLyrics: () => normalizeLyrics,
|
|
97
98
|
onClick: () => onClick,
|
|
98
99
|
panToStereo: () => panToStereo,
|
|
100
|
+
parseCustomVocals: () => parseCustomVocals,
|
|
99
101
|
parseLyrics: () => parseLyrics,
|
|
100
102
|
parseMML: () => parseMML,
|
|
101
103
|
parseMmlMeta: () => parseMmlMeta,
|
|
@@ -104,6 +106,7 @@ __export(index_exports, {
|
|
|
104
106
|
setDrawOffset: () => setDrawOffset,
|
|
105
107
|
shiftNotes: () => shiftNotes,
|
|
106
108
|
showLoadingOverlay: () => showLoadingOverlay,
|
|
109
|
+
stripCustomVocals: () => stripCustomVocals,
|
|
107
110
|
stripLyrics: () => stripLyrics,
|
|
108
111
|
stripMmlMeta: () => stripMmlMeta,
|
|
109
112
|
vocalVolumeToGain: () => vocalVolumeToGain
|
|
@@ -1831,7 +1834,7 @@ var INSTRUMENT_PRESETS = {
|
|
|
1831
1834
|
}
|
|
1832
1835
|
};
|
|
1833
1836
|
|
|
1834
|
-
// node_modules/.pnpm/@onjmin+koe@1.0.
|
|
1837
|
+
// node_modules/.pnpm/@onjmin+koe@1.0.4/node_modules/@onjmin/koe/dist/index.js
|
|
1835
1838
|
var MAGIC = 1263486208;
|
|
1836
1839
|
function parseKoeHeader(headerBytes) {
|
|
1837
1840
|
const view = new DataView(headerBytes);
|
|
@@ -1841,6 +1844,8 @@ function parseKoeHeader(headerBytes) {
|
|
|
1841
1844
|
return { jsonLength: view.getUint32(4, true) };
|
|
1842
1845
|
}
|
|
1843
1846
|
var pcmBase = (jsonLength) => 8 + jsonLength;
|
|
1847
|
+
var MAX_PHONEME_SAMPLES = 5242880;
|
|
1848
|
+
var MAX_JSON_LENGTH = 50 * 1024 * 1024;
|
|
1844
1849
|
var BlobVoiceSource = class {
|
|
1845
1850
|
constructor(blob2, base) {
|
|
1846
1851
|
this.blob = blob2;
|
|
@@ -1862,22 +1867,60 @@ var RangeVoiceSource = class {
|
|
|
1862
1867
|
base;
|
|
1863
1868
|
async readBytes(offset, length) {
|
|
1864
1869
|
const start = this.base + offset;
|
|
1865
|
-
|
|
1866
|
-
headers: { Range: `bytes=${start}-${start + length - 1}` }
|
|
1867
|
-
});
|
|
1868
|
-
if (!res.ok && res.status !== 206) {
|
|
1869
|
-
throw new Error(`.koe range request failed: ${res.status}`);
|
|
1870
|
-
}
|
|
1871
|
-
return res.arrayBuffer();
|
|
1870
|
+
return rangeFetch(this.url, start, length);
|
|
1872
1871
|
}
|
|
1873
1872
|
};
|
|
1874
1873
|
async function rangeFetch(url2, start, length) {
|
|
1875
1874
|
const res = await fetch(url2, {
|
|
1876
|
-
headers: { Range: `bytes=${start}-${start + length - 1}` }
|
|
1875
|
+
headers: { Range: `bytes=${start}-${start + length - 1}` },
|
|
1876
|
+
credentials: "omit"
|
|
1877
|
+
// never leak cookies / auth to a MML-supplied URL
|
|
1877
1878
|
});
|
|
1878
|
-
if (
|
|
1879
|
-
throw new Error(
|
|
1880
|
-
|
|
1879
|
+
if (res.status !== 206) {
|
|
1880
|
+
throw new Error(
|
|
1881
|
+
`.koe fetch failed: expected 206 Partial Content, got ${res.status}`
|
|
1882
|
+
);
|
|
1883
|
+
}
|
|
1884
|
+
return readCapped(res, length);
|
|
1885
|
+
}
|
|
1886
|
+
async function readCapped(res, length) {
|
|
1887
|
+
const reader = res.body?.getReader();
|
|
1888
|
+
if (!reader) {
|
|
1889
|
+
const buf = await res.arrayBuffer();
|
|
1890
|
+
if (buf.byteLength > length) {
|
|
1891
|
+
throw new Error(
|
|
1892
|
+
`.koe fetch failed: response exceeds requested ${length} bytes`
|
|
1893
|
+
);
|
|
1894
|
+
}
|
|
1895
|
+
return buf;
|
|
1896
|
+
}
|
|
1897
|
+
const out = new Uint8Array(length);
|
|
1898
|
+
let received = 0;
|
|
1899
|
+
for (; ; ) {
|
|
1900
|
+
const { done, value } = await reader.read();
|
|
1901
|
+
if (done) break;
|
|
1902
|
+
if (received + value.byteLength > length) {
|
|
1903
|
+
await reader.cancel();
|
|
1904
|
+
throw new Error(
|
|
1905
|
+
`.koe fetch failed: response exceeds requested ${length} bytes`
|
|
1906
|
+
);
|
|
1907
|
+
}
|
|
1908
|
+
out.set(value, received);
|
|
1909
|
+
received += value.byteLength;
|
|
1910
|
+
}
|
|
1911
|
+
return received === length ? out.buffer : out.buffer.slice(0, received);
|
|
1912
|
+
}
|
|
1913
|
+
function validateJsonLength(jsonLength) {
|
|
1914
|
+
if (!Number.isInteger(jsonLength) || jsonLength < 0 || jsonLength > MAX_JSON_LENGTH) {
|
|
1915
|
+
throw new Error(`manifest JSON length out of bounds: ${jsonLength}`);
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
function parseManifest(json) {
|
|
1919
|
+
const manifest = JSON.parse(new TextDecoder().decode(json));
|
|
1920
|
+
if (!manifest || typeof manifest !== "object" || typeof manifest.phonemes !== "object" || manifest.phonemes === null) {
|
|
1921
|
+
throw new Error("invalid manifest: missing phonemes table");
|
|
1922
|
+
}
|
|
1923
|
+
return manifest;
|
|
1881
1924
|
}
|
|
1882
1925
|
var VoiceBank = class _VoiceBank {
|
|
1883
1926
|
constructor(manifest, source) {
|
|
@@ -1891,20 +1934,41 @@ var VoiceBank = class _VoiceBank {
|
|
|
1891
1934
|
* @param koe a Blob/File of the .koe archive, or a URL (served with Range support)
|
|
1892
1935
|
*/
|
|
1893
1936
|
static async load(koe) {
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1937
|
+
try {
|
|
1938
|
+
if (typeof koe === "string") {
|
|
1939
|
+
if (/^blob:/i.test(koe)) {
|
|
1940
|
+
const res = await fetch(koe);
|
|
1941
|
+
if (!res.ok) {
|
|
1942
|
+
throw new Error(`blob: URL fetch failed: ${res.status}`);
|
|
1943
|
+
}
|
|
1944
|
+
return await _VoiceBank.fromBlob(await res.blob());
|
|
1945
|
+
}
|
|
1946
|
+
if (!/^https?:/i.test(koe)) {
|
|
1947
|
+
throw new Error(`unsupported URL protocol: ${koe}`);
|
|
1948
|
+
}
|
|
1949
|
+
const header = await rangeFetch(koe, 0, 8);
|
|
1950
|
+
const { jsonLength } = parseKoeHeader(header);
|
|
1951
|
+
validateJsonLength(jsonLength);
|
|
1952
|
+
const json = await rangeFetch(koe, 8, jsonLength);
|
|
1953
|
+
const manifest = parseManifest(json);
|
|
1954
|
+
return new _VoiceBank(
|
|
1955
|
+
manifest,
|
|
1956
|
+
new RangeVoiceSource(koe, pcmBase(jsonLength))
|
|
1957
|
+
);
|
|
1958
|
+
}
|
|
1959
|
+
return await _VoiceBank.fromBlob(koe);
|
|
1960
|
+
} catch (error) {
|
|
1961
|
+
throw new Error(
|
|
1962
|
+
`Failed to load .koe voice bank: ${error instanceof Error ? error.message : String(error)}`
|
|
1902
1963
|
);
|
|
1903
1964
|
}
|
|
1965
|
+
}
|
|
1966
|
+
static async fromBlob(koe) {
|
|
1904
1967
|
const header = await koe.slice(0, 8).arrayBuffer();
|
|
1905
1968
|
const { jsonLength } = parseKoeHeader(header);
|
|
1969
|
+
validateJsonLength(jsonLength);
|
|
1906
1970
|
const json = await koe.slice(8, 8 + jsonLength).arrayBuffer();
|
|
1907
|
-
const manifest =
|
|
1971
|
+
const manifest = parseManifest(json);
|
|
1908
1972
|
return new _VoiceBank(
|
|
1909
1973
|
manifest,
|
|
1910
1974
|
new BlobVoiceSource(koe, pcmBase(jsonLength))
|
|
@@ -1912,7 +1976,7 @@ var VoiceBank = class _VoiceBank {
|
|
|
1912
1976
|
}
|
|
1913
1977
|
/** True if the bank contains a phoneme under this alias. */
|
|
1914
1978
|
has(phoneme) {
|
|
1915
|
-
return this.manifest.phonemes
|
|
1979
|
+
return Object.hasOwn(this.manifest.phonemes, phoneme);
|
|
1916
1980
|
}
|
|
1917
1981
|
/**
|
|
1918
1982
|
* Raw Int16 PCM bytes (48 kHz / mono) for a phoneme, or null if unknown.
|
|
@@ -1920,8 +1984,11 @@ var VoiceBank = class _VoiceBank {
|
|
|
1920
1984
|
* worker / AudioWorklet.
|
|
1921
1985
|
*/
|
|
1922
1986
|
async readPcmBytes(phoneme) {
|
|
1987
|
+
if (!Object.hasOwn(this.manifest.phonemes, phoneme)) return null;
|
|
1923
1988
|
const entry = this.manifest.phonemes[phoneme];
|
|
1924
|
-
if (!entry)
|
|
1989
|
+
if (!Number.isInteger(entry.offset) || !Number.isInteger(entry.length) || entry.offset < 0 || entry.length < 0 || entry.length > MAX_PHONEME_SAMPLES) {
|
|
1990
|
+
throw new Error(`manifest entry out of bounds for phoneme: ${phoneme}`);
|
|
1991
|
+
}
|
|
1925
1992
|
return this.source.readBytes(entry.offset, entry.length * 2);
|
|
1926
1993
|
}
|
|
1927
1994
|
/**
|
|
@@ -1931,7 +1998,7 @@ var VoiceBank = class _VoiceBank {
|
|
|
1931
1998
|
async getPcm(phoneme) {
|
|
1932
1999
|
const buf = await this.readPcmBytes(phoneme);
|
|
1933
2000
|
if (!buf) return null;
|
|
1934
|
-
const int16 = new Int16Array(buf);
|
|
2001
|
+
const int16 = new Int16Array(buf, 0, Math.floor(buf.byteLength / 2));
|
|
1935
2002
|
const f64 = new Float64Array(int16.length);
|
|
1936
2003
|
for (let i = 0; i < int16.length; i++) f64[i] = int16[i] / 32768;
|
|
1937
2004
|
return f64;
|
|
@@ -2122,7 +2189,8 @@ var Worldline = class _Worldline {
|
|
|
2122
2189
|
}
|
|
2123
2190
|
const outLen = WL._PhraseSynthSynth(ps, yPtrPtr, 0);
|
|
2124
2191
|
const yPtr = WL.getValue(yPtrPtr, "*");
|
|
2125
|
-
const audio = outLen > 0 ? new Float32Array(WL.HEAPF32.buffer, yPtr, outLen).slice() : null;
|
|
2192
|
+
const audio = outLen > 0 && yPtr ? new Float32Array(WL.HEAPF32.buffer, yPtr, outLen).slice() : null;
|
|
2193
|
+
if (yPtr) WL._free(yPtr);
|
|
2126
2194
|
WL._free(yPtrPtr);
|
|
2127
2195
|
WL._PhraseSynthDelete(ps);
|
|
2128
2196
|
return audio;
|
|
@@ -2313,7 +2381,7 @@ var parseLyrics = (mml) => {
|
|
|
2313
2381
|
let pan = 64;
|
|
2314
2382
|
let octave = 0;
|
|
2315
2383
|
const modelMatch = rest.match(
|
|
2316
|
-
/^([a-z_]
|
|
2384
|
+
/^([a-z_][a-z0-9_]*?)(?=(?:[vqpo]-?\d)|[^a-z0-9_]|$)(?::(\d+))?/i
|
|
2317
2385
|
);
|
|
2318
2386
|
let model = "";
|
|
2319
2387
|
const metaTokens = [];
|
|
@@ -2388,6 +2456,40 @@ var stripLyrics = (mml) => {
|
|
|
2388
2456
|
}
|
|
2389
2457
|
return kept.join("\n");
|
|
2390
2458
|
};
|
|
2459
|
+
var CUSTOM_VOCAL_LINE = /^@@([a-zA-Z_][a-zA-Z0-9_]*)\s+(\S+)\s+(\S+)\s*$/;
|
|
2460
|
+
var CUSTOM_VOCAL_URL_MAX_LEN = 2048;
|
|
2461
|
+
var isValidHttpUrl = (s) => {
|
|
2462
|
+
if (s.length > CUSTOM_VOCAL_URL_MAX_LEN) return false;
|
|
2463
|
+
try {
|
|
2464
|
+
const u = new URL(s);
|
|
2465
|
+
return u.protocol === "http:" || u.protocol === "https:";
|
|
2466
|
+
} catch {
|
|
2467
|
+
return false;
|
|
2468
|
+
}
|
|
2469
|
+
};
|
|
2470
|
+
var parseCustomVocals = (mml) => {
|
|
2471
|
+
const map = /* @__PURE__ */ new Map();
|
|
2472
|
+
for (const seg of splitSegments(mml)) {
|
|
2473
|
+
const m = seg.match(CUSTOM_VOCAL_LINE);
|
|
2474
|
+
if (!m) continue;
|
|
2475
|
+
const key = m[1].toLowerCase();
|
|
2476
|
+
const iconUrl = m[2];
|
|
2477
|
+
const koeUrl2 = m[3];
|
|
2478
|
+
if (!isValidHttpUrl(koeUrl2)) {
|
|
2479
|
+
console.warn(
|
|
2480
|
+
`[dtm] \u30AB\u30B9\u30BF\u30E0\u30DC\u30FC\u30AB\u30EB "${key}": koe URL \u304C\u4E0D\u6B63\u307E\u305F\u306F\u9577\u3059\u304E\u308B\u305F\u3081\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3059`,
|
|
2481
|
+
koeUrl2.slice(0, 80)
|
|
2482
|
+
);
|
|
2483
|
+
continue;
|
|
2484
|
+
}
|
|
2485
|
+
const resolvedIconUrl = isValidHttpUrl(iconUrl) ? iconUrl : "";
|
|
2486
|
+
map.set(key, { key, iconUrl: resolvedIconUrl, url: koeUrl2 });
|
|
2487
|
+
}
|
|
2488
|
+
return [...map.values()];
|
|
2489
|
+
};
|
|
2490
|
+
var stripCustomVocals = (mml) => mml.split(/[\n\r]+/).map(
|
|
2491
|
+
(line) => line.split(";").filter((seg) => !CUSTOM_VOCAL_LINE.test(seg.trim())).join(";")
|
|
2492
|
+
).join("\n");
|
|
2391
2493
|
var panToStereo = (pan) => Math.max(-1, Math.min(1, (pan - 64) / 64));
|
|
2392
2494
|
var createLyricsConductor = (lyrics) => {
|
|
2393
2495
|
const pointers = /* @__PURE__ */ new Map();
|
|
@@ -2514,7 +2616,10 @@ var KOE_VOICEBANKS = {
|
|
|
2514
2616
|
ruko_male: "\u6B32\u97F3\u30EB\u30B3\u2642\u9023\u7D9A\u97F3Ver.1.03.koe",
|
|
2515
2617
|
ruko_female: "\u6B32\u97F3\u30EB\u30B3\u2640\u6B4C\u9023\u7D9A\u97F3\u666E1.00.koe",
|
|
2516
2618
|
teto: "\u91CD\u97F3\u30C6\u30C8\u5358\u72EC\u97F3.koe",
|
|
2517
|
-
shiyo: "\u9769\u547D\u30B7\u30E8.koe"
|
|
2619
|
+
shiyo: "\u9769\u547D\u30B7\u30E8.koe",
|
|
2620
|
+
rei: "\u8DB3\u7ACB\u30EC\u30A4ver3.5.0.koe",
|
|
2621
|
+
MGRoid: "MGRoid_\u539F\u97F3\u8A2D\u5B9A\u6E08\u307F.koe",
|
|
2622
|
+
MOTRoid: "MOTRoid\u5B8C\u5168\u7248V2.koe"
|
|
2518
2623
|
};
|
|
2519
2624
|
var KOE_VOICEBANK_LABELS = {
|
|
2520
2625
|
tsukuyomi: "\u3064\u304F\u3088\u307F\u3061\u3083\u3093",
|
|
@@ -2523,7 +2628,10 @@ var KOE_VOICEBANK_LABELS = {
|
|
|
2523
2628
|
ruko_male: "\u6B32\u97F3\u30EB\u30B3\u2642",
|
|
2524
2629
|
ruko_female: "\u6B32\u97F3\u30EB\u30B3\u2640",
|
|
2525
2630
|
teto: "\u91CD\u97F3\u30C6\u30C8",
|
|
2526
|
-
shiyo: "\u9769\u547D\u30B7\u30E8"
|
|
2631
|
+
shiyo: "\u9769\u547D\u30B7\u30E8",
|
|
2632
|
+
rei: "\u8DB3\u7ACB\u30EC\u30A4",
|
|
2633
|
+
MGRoid: "MGRoid",
|
|
2634
|
+
MOTRoid: "MOTRoid"
|
|
2527
2635
|
};
|
|
2528
2636
|
var VOICE_IMAGE_KEY = {
|
|
2529
2637
|
klatt: "puyuyu",
|
|
@@ -2533,7 +2641,10 @@ var VOICE_IMAGE_KEY = {
|
|
|
2533
2641
|
ruko_male: "ruko",
|
|
2534
2642
|
ruko_female: "ruko",
|
|
2535
2643
|
teto: "teto",
|
|
2536
|
-
shiyo: "shiyo"
|
|
2644
|
+
shiyo: "shiyo",
|
|
2645
|
+
rei: "rei",
|
|
2646
|
+
MGRoid: "MGRoid",
|
|
2647
|
+
MOTRoid: "MOTRoid"
|
|
2537
2648
|
};
|
|
2538
2649
|
var KOE_VOICEBANK_TERMS = {
|
|
2539
2650
|
tsukuyomi: "https://tyc.rei-yumesaki.net/material/utau/terms/",
|
|
@@ -2542,7 +2653,10 @@ var KOE_VOICEBANK_TERMS = {
|
|
|
2542
2653
|
ruko_male: "https://long-sleeper.net/index.php?id=22",
|
|
2543
2654
|
ruko_female: "https://long-sleeper.net/index.php?id=22",
|
|
2544
2655
|
teto: "https://kasaneteto.jp/guidelines/voice.html",
|
|
2545
|
-
shiyo: "https://kakumeisiyo.my.canva.site/dagkuyjwycs"
|
|
2656
|
+
shiyo: "https://kakumeisiyo.my.canva.site/dagkuyjwycs",
|
|
2657
|
+
rei: "https://mechanicalgirl.jp/guidelines/",
|
|
2658
|
+
MGRoid: "https://x.com/nisusansu/status/1048825378188353536",
|
|
2659
|
+
MOTRoid: "https://www.nicovideo.jp/watch/sm40031282"
|
|
2546
2660
|
};
|
|
2547
2661
|
var koeUrl = (name, base = KOE_BASE_URL) => `${base}/${encodeURIComponent(name)}`;
|
|
2548
2662
|
var DEFAULT_WORLDLINE_SCRIPT = "https://onjmin.github.io/koe/demo/world/worldline.js";
|
|
@@ -2648,7 +2762,7 @@ var createLocalBackend = async (options) => {
|
|
|
2648
2762
|
}
|
|
2649
2763
|
const rate = entry.pitch > 0 ? targetHz / entry.pitch : 1;
|
|
2650
2764
|
return {
|
|
2651
|
-
pcm: Float32Array
|
|
2765
|
+
pcm: new Float32Array(pcm),
|
|
2652
2766
|
preSec: entry.pre / KOE_SAMPLE_RATE / rate,
|
|
2653
2767
|
rate
|
|
2654
2768
|
};
|
|
@@ -2909,6 +3023,16 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2909
3023
|
for (const m of models) if (m) set.add(m.toLowerCase());
|
|
2910
3024
|
await Promise.all([...set].map((m) => load2(m)));
|
|
2911
3025
|
};
|
|
3026
|
+
const registerVoicebanks = (banks) => {
|
|
3027
|
+
for (const [k, v] of Object.entries(banks)) {
|
|
3028
|
+
const key = k.toLowerCase();
|
|
3029
|
+
if (key === FALLBACK_MODEL) continue;
|
|
3030
|
+
if (catalog[key] === v) continue;
|
|
3031
|
+
catalog[key] = v;
|
|
3032
|
+
loaded.delete(key);
|
|
3033
|
+
loading.delete(key);
|
|
3034
|
+
}
|
|
3035
|
+
};
|
|
2912
3036
|
const forEachSungNote = (track, fn) => {
|
|
2913
3037
|
let prevVowel = "";
|
|
2914
3038
|
for (const note of track.notes) {
|
|
@@ -3015,7 +3139,14 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
3015
3139
|
stopStream();
|
|
3016
3140
|
for (const v of loaded.values()) v.reset?.();
|
|
3017
3141
|
};
|
|
3018
|
-
return {
|
|
3142
|
+
return {
|
|
3143
|
+
loadModels,
|
|
3144
|
+
registerVoicebanks,
|
|
3145
|
+
warm,
|
|
3146
|
+
startStream,
|
|
3147
|
+
stopStream,
|
|
3148
|
+
reset
|
|
3149
|
+
};
|
|
3019
3150
|
};
|
|
3020
3151
|
var createVoiceRegistry = (models = {}, fallback = "klatt") => {
|
|
3021
3152
|
const sing = (model, syllable, e) => {
|
|
@@ -4469,7 +4600,8 @@ var parseMML = (mml, options = {}) => {
|
|
|
4469
4600
|
meta: {}
|
|
4470
4601
|
};
|
|
4471
4602
|
}
|
|
4472
|
-
const
|
|
4603
|
+
const noCustomVocals = stripCustomVocals(mml);
|
|
4604
|
+
const noComments = noCustomVocals.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
4473
4605
|
const meta = parseMmlMeta(noComments);
|
|
4474
4606
|
const noMeta = stripMmlMeta(noComments);
|
|
4475
4607
|
const lyrics = collectLyrics ? parseLyrics(noMeta) : void 0;
|
|
@@ -5814,6 +5946,7 @@ var DAW_CSS = `
|
|
|
5814
5946
|
height: 20px;
|
|
5815
5947
|
border-radius: 50%;
|
|
5816
5948
|
object-fit: cover;
|
|
5949
|
+
image-rendering: pixelated;
|
|
5817
5950
|
}
|
|
5818
5951
|
|
|
5819
5952
|
/* \u2500\u2500\u2500 \u5E83\u5E45\u62E1\u5F35 \u2500\u2500\u2500 */
|
|
@@ -6299,26 +6432,38 @@ var createSynth = (ctx, destination = ctx.destination) => {
|
|
|
6299
6432
|
return { playNote, playDrum };
|
|
6300
6433
|
};
|
|
6301
6434
|
|
|
6435
|
+
// assets/404Chip.png
|
|
6436
|
+
var Chip_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAcElEQVR42u2WOw7AIAxD7Yr7X9kdqi5IIXQKBWckKHrOTyEAodAuFJsBDGAAA7TIIT0LkuTQ/1r0L4u3XgZ6ZbNKsvf9mlBSqu5fU9DXMFP3teujeOtPQbYPZnplFK88A4xuwmM2IX0VG8AABjge4AZHeT8uyZjZYAAAAABJRU5ErkJggg==";
|
|
6437
|
+
|
|
6438
|
+
// assets/MGRoid.png
|
|
6439
|
+
var MGRoid_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABy0lEQVR42tWXv0tCURTHPy9dwog0AssiVLChNmnQaHaJIoj+gQgkoj+jsSEiGmpodosWA9ck6g1BDg0qQYNLDpG1GK/h3RvvxfU+nbyd6f4473C/33ve95xr0b853kk2m2UQs21bDi3v+ghDtnCQQzEWcwDO2u2+kC83mwDcTEwEMWkZx4Cjc7xMJAA4DkCeGx11GRDrjUZDefdG5YA+uwUyaQetlstEPK5ELi0ajfZ1gKEzYEkG/iK/23l0B7MDRnwV1O51fYx6dABj/wI9coHsdz1g3j0NCyZsLRPmK+HL4jMAixdlAD4KB0pmxsquQtSOCgDMs6Bkwkgd0FoqlQIgs7oFQGhjRemX+ZwW/lMAfNfo9RdZxumAshZ0r8K+Ow6lT9zBUk4d6anqIq/v+5CH17tm1wIrqAOSTHiQuJvlMzdAoYiKuSDkRjPgiE4IgPtkUlv3q19fWj/ZSRndDyhNIsyJ+n+dzyvna7e3ALwJvZisVFD1F7ZtO/9DB+SJHw53lVneqytW1PteVdDwd4HU/u3zivKDzbkZbc2QViqVtMiNZMDy5oJE8Pcu3zsdAMYjEWVAzzvg/yrhQK/ker3u20yn0wPFHjoDP1pgkXMfnLDSAAAAAElFTkSuQmCC";
|
|
6440
|
+
|
|
6441
|
+
// assets/MOTRoid.png
|
|
6442
|
+
var MOTRoid_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAByElEQVR42s2WTyiEURTFfyMbS1ZSlIUxScpCNrNAkpLdhClFlJRJdpQ/5V+xE7PQFJHFyJKUJKLZaBZqkhjKQslCLG3UWIw7ec/7xidq3lnNve++23fOO2/u86ChPbyd+hp3tDbzH9g5OFLivVCXByCPHMPjlrkw+KsiuhI5VyBfT/z3mev9JJZ1ezywdfeccnNmbhVyuy/3Coj7nVwv2KwpAaAn8ZiVkezT652UsO8WCK5jJ0pcH9OYOrha9un1GVivwMzEOADJ6CoApQtx48bdQNnnr3cAugMNAMRWpoz1/usbALzBQQB8/kZLFZAv0/EwVpdVESfGMV+lsb94xz4FMu4f6lTybpkLdObf+lurwNTcvOLWh6XpXzX0n54Z89JP+ts/CwRtj1cAFHq9Sj4+uWisr5sdVeLXZBKA/ZIqy6fhT3O7YmNJPdOWFmNd8vBQiW97R7JOTXtfxYKjyAwAzQPp//jxp8v0tAuFjA3Pw2EA5ourjfvt84DTQkFNVQrgrb9Dyb/UNhlvhe76ootjtd9a+gXxlrjy2P0eEOZOyDDTGLpFRtlPJezzgNPZC6LBPgDKlyPG9fvhAQCC0XWzAms7dt2CDzsGp242tsuqAAAAAElFTkSuQmCC";
|
|
6443
|
+
|
|
6302
6444
|
// assets/puyuyu.png
|
|
6303
|
-
var puyuyu_default = "data:image/png;base64,
|
|
6445
|
+
var puyuyu_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB60lEQVR42tWXPUxTURiGn9vWMCgtEQoDcWhAFgdtB0dMGjfcIAwMjcYoKIObq3F1EwKixNR0cCC46YQ4ODqIi4kRjUPj0Jaa1roYi9fh9Kuck3tvb7v08C73J+/5Tt7nnPvlHoeQend3yKULXXxQc8L4IvRZsU6JM9NJAKLZOQCazox6jiU0/2Gzrgq6r5RvetsFeP+2EkjEPgJ+yd3olDL81RObEp+My7Ct6oLrRcIeAmbyyKULngOikf2uJpA6GT54kug7gfZ6HO6cdwF+pYYBGBxT12vzrwF49mKpq8JXZzcAyG9dBqBRqgJw8lNRob+ybwkBc+2vrx1oBknQq4Sg6OnyCEf7g319YGU1rSM6taWujtou9S/ZwILxid1gf2sP2NsJZZdGZz57DkhMvlG9/uVZvT906bePwO9GDYCBwSFtDUWLN1UfePxkw/tzCumXeawh0O4D59InNAL54gIAN27d1wZsPrqnvu8zz/V+EdIvBD7u/bGUgEhI/BjLae9PlwqBBf385trbQ0Buvj2ccAFGR396kuhVZvJyOQ5A6s5Xx64+UPlebd2p/wAhYSYQ3S40tef1XCxwIkn+fx4s2wPmv2FyXCdhJjcT+703k1v3V+x0OhkJiV7ll9x+Ap1Px25giWNzOv4HHKK9IIEhxAYAAAAASUVORK5CYII=";
|
|
6446
|
+
|
|
6447
|
+
// assets/rei.png
|
|
6448
|
+
var rei_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACXElEQVR42s2XQWhTQRCGv1c8CFa9SSPEKkQPtfIOBQUlBgThEVIjEgRvEuuhCDkVL7Ug2N4ilqB4aCveFOnBanm+gxRUKlgJUmgraEA0YEpPRT3opeth30p2eXk0XrJzecxkZnbm39mZicM26dXAGUEblKkuOFHyvn09AmBtY90B6KLD5LSKUNH9ZB8Aw/W1/zpA2StSfuxDQGWeyWX1u5/3Nf7t8RORjk4uvYs9aOVqt8a/CQ5gBQI7WlZ9mLkZOaxGZ+jqesGpCgCe50nB2JFIO3sQ+FftRuaNbFkzSPgjGv9j+SgAe9zV2INMvbT3zRIEtkZT4buXEa3QrVUpQUWLuBX9GXwgv+O35d1Tkj94nwBYbvyUflxba0Bl7CZ2A3B6fhKA17krsQ72Tk3qSLQZQOc7oTnlMtWFVtMwRGZGGiYOxTreGk1F94XFkmU10DS3BYAQEhBx47CMcKIWadhKT2Vu8iOXixIBo7Pa8wo2c/lYRXX32yXR+CK/d8/GdkR79oHNXF4AbBzrBSCZL0Qa7OxNtodEiED/1C9t5tgzC0zB+ZknADwNeYXE0rWbkbWgOqUpf/HhIwC7wg5bfhhO0bGyZZ2wqXOJ5rsyqfpMIuPPPdLkF0rXAfhcuaPJU12+NmPS71/KjhgEWke0rwbUJqQif+weBKA+NwtANn9J0//9ta7xtbTcAVOLvmafNqfgRM2xCwEzY8LNZbBQUAoADJy7qNWE+XrKIQLckpsQQ0Oa3vNZieRwsSjsegUqIkX3pqf1qg33+/6e/dH/C9a/R+or3iSFRMcR+AtdbNaYOcb0dwAAAABJRU5ErkJggg==";
|
|
6304
6449
|
|
|
6305
6450
|
// assets/rino.png
|
|
6306
|
-
var rino_default = "data:image/png;base64,
|
|
6451
|
+
var rino_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABvklEQVR42mNkIACC8yv/MzAwMKSF+jOQAmat3ojCXzuxnRGbOiaGAQaM1PY5oRBBD4kBDwEWdIGdR078p6YFesryeOUHTwjAfI7u4kt3HzLgEyfWp4M/BHD5zE1BhoGBgYFh+vZdDAwMDAzKauoo4jAAk8cFkHLTf+TcMPhC4O6tm6gCaD6Fy6OJZ7o5Q0Ji194hmgbQfZ6VFA+h0TRMm7cQtSiVkcFrwc4jJ4ZYLoD5/P9/SIEobGCNNa5hPsel7t3FY1hz06xBHwLoccxj5IhV4/8nT/CqWz61D4V/bNu2wZkGGNHrAlhu2HvxBgMDAwPDmtJssgze9eAJStyHdE8d5O0BdxsLRuSWEHrcWXl5EWUgzKdwQKBFNfjbhEXailjlTf79Q+GfYYL4pe/qfQYGBgaGU9dQW8WPd18bnK1ieBqQddVCiXtOyU8MDAwMDBGrJzAwMDAw2Duj5vNMIX2UtDF9STtUH1TBNVSL0M0fvCUhIYDu81ioz3EBWMhJv0KtFZdd/j5IQwDm4oN792PVAEsTDDAaTR86iNO6xMDAwMCwiMECa0gMnTSAK0RwySNC5BJKSCTv/T64QgAAipubBW9f1GUAAAAASUVORK5CYII=";
|
|
6307
6452
|
|
|
6308
6453
|
// assets/roze.png
|
|
6309
|
-
var roze_default = "data:image/png;base64,
|
|
6454
|
+
var roze_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB0klEQVR42s2XPUsDQRCGnxVbC4OVFkELlRR+lBY2dkmlpSLYWVmIpA7BOkL+gQghjYVWiaRVsBFNgiZGQbGIlR+FP2AtzEh23TsTEW6nudu529l53/nYXUVHZqbmNEC9VVWEiPwXJEHzg+wPELEMime12yvRaQCllHjunPjYfjDG42MTxnxAuZDbDEbOwHc8Rss5DfCcTBvIQ5Aa3229MDp2skfHrjM3os8BeQlCLsgWZhadBkRfLB84megSbVWFZ1VQb1UN5GvJDePH8/ppX4Znp+cB+LBySJDLev7kgC2/Ia4dFb+Qrqz9aWF/cuC/DIVkv7Nq/OkD4pFk5Y+OZsVaxiqRCI1tr7kVPQNB2S6MCFLdaJhtTWuj13/LdsEYPmUzAMTSafzeC+wO1bVLumc2mwC04ymzA1LoywF/+4Ad4/dSCYDhVKqvBeLZ3dDq8JeB970v5Ne2vsOESK+MvOTXARixqsQ/BiTrY0mzbt9yuVDk0i/sE9XQYcZ5b5BziD+nYvFIYmWfFYNkdWnLqb9pnxl9RZi1T8f+3Qts5BL7/XwegIvJZQAu7917yKZ+BWCnUjGqpmsvUH5XwW/IbaS2nrtjZ+fUnadKJIy7Y+QMfAL8JMMLhDWQAQAAAABJRU5ErkJggg==";
|
|
6310
6455
|
|
|
6311
6456
|
// assets/ruko.png
|
|
6312
|
-
var ruko_default = "data:image/png;base64,
|
|
6457
|
+
var ruko_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACC0lEQVR42s2XsUsbURzHP08kinNvkWAXiy0F6dBJM0S7Bf+AUK2CkKCzS6GDZJBObkJBcNFS7NRFApaCEbRdHERQTJwKGYS4dJE2FM/h7id9P1/SKx3ufZfk3r17d9/P+/1+9ztDQgVBEPIParVaJsm8HlKWyedyTme1gwPzp/OnIyOJFjyt17sS0fdLn4D8kSfTDpI6T0pE1hPCqRPo7RQD/6tm38PYsZuExFb6BDqdkL16VSwC8DiTAeC83bbmbW1vW/NEbz99s0hA3c860CtPLk60ZHwv/n2jnK7Mzkbjm5vWeFbFgkiTSr8ObKytWVnwulKRyuW8IGw2AZiInQgZk8065w+/mAbgx8lnZ2z5kwWy1+I8DCMwS4NDzgv3VMyIU9HFl/cRGWPs87++e5YFeiCfy1nHxavLRAs9eDLeNQY6ZZe//YBod2YGgMzUVKIF2zs7ABz1RN7mPu5HdUHtvb8xIO9pIdO3sOCsA39znlT+vg1119RoNEKAr9UqAM9vbizHweQkAGf70Z6XSiUTZ0HoIutvTyhPKjpcXw8BgnwegEcDA86FLq6v7S64VgNgvFw2qs6EXvWE975etGOtwmLFOq6+W3Z/B8QEtDQRfwiI87uuNSZQnp+3Oh/R0slvAFZH7UTSnZG8NSV7NAn/6sBYoeCcKM5+PnvpJNF//KHrjfS6Qjx1ArcCiMI3kOeT7AAAAABJRU5ErkJggg==";
|
|
6313
6458
|
|
|
6314
6459
|
// assets/shiyo.png
|
|
6315
|
-
var shiyo_default = "data:image/png;base64,
|
|
6460
|
+
var shiyo_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACJklEQVR42s2Xv09TURTHP5eAJJrI3ISBhIFJiaBp08GFAYKTA6FxejVBGgeTtzjxF7gwaWoNtCPEoSwSli4aa+uPSHFiaGLiQFwkDDWBBK7De6fpvd4+YOKe5eW8e+557/u959dV9BcdP1Xvy0ajoXv1dDoNQLPZBCCTyaik/bYMcMWiEpBjITcQiwhyBxOG3cbqJAC5sKW8YmDwPAOttYHMRn7n+nMATn7Iygtjn1LKZkL3MuFvDBzv3Qfg+98I0c9PywA8nBm51AeGb793xoK/MSB/eG18NUJeenwh5NXakdNOd75FVN+YNtbF3h8GJDoXn6wnbhBmRDZjhhYX3kX62we4/AizEhMSY/7WgU3r7LtnTGjogtyWk3Zo6MJILpz2PAtEcmHL+d7O425BGR1N/NDxXuhnNxw87+w+z84a+r2FNaej/+x2dpy9wK6Q/sbAbtztfm9tJZ71bq0GwOHU1KVixt+JSCriyM1nAKTGxoz1yYkJQ2/t7zsdd9ptAH51XiZml38xIJNKEHzQAEunp6aBxYDNSH17+0J1RbqkfzFgz/3FYhGApWzWsLt7dmboXwciLG/qdQAqlYpy+ZNp2V8GgiDQAIVCARcTIq+tuX85vjeI2Pu7N6lbQ55ngZx1Oq54+ZUVAMrlcqTn81H+V6sAvEqljP1iZ98jxB+Hcc/588gzBj6WShogOz/vZMRG+GVuDoCnBwdG9+ubPX3mhStn4B+i9swYdEa2xAAAAABJRU5ErkJggg==";
|
|
6316
6461
|
|
|
6317
6462
|
// assets/teto.png
|
|
6318
|
-
var teto_default = "data:image/png;base64,
|
|
6463
|
+
var teto_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB00lEQVR42tVXPUsDQRB9q8GvQiyjWKS0CApBCEENafwoYiMWIoJX+gMiKFoqFskPsFQQsbLxisQqRCQIEgiksEzhRyspREU9i705suNecqmyviozszfsezs7OxEIDqfZyMTSAIBcxebrRAc50YMuQ/gx5CDGhFR/HwCg+PGp+DWKtFTICAUcHUMOYhzp1e+5/v2jVYSjSSFhhgKZWNrRMTx5ew/EvJ0S1tCA1p+r2GYoEKIffMeEcHxSKlK6BwCsJaeV+AXzhyng+nl+4/pAiFc5BzHMHslbsr1rK0r5+f1uEVfC/BoghmJxS7bLp6pkvLwn49GEW9UyDp9+8v9qgDpWFnpG2atDvZ8pZs2uml0D3ltgJ1YAAOnypfa9dwrH8gv3zP+gVlaY8+95fnPeAs08IJptv8nHKRy4jPfRZlISPvnNm4gUJebXdwAA15sRAMDCaR0A8PL8CABYarwCAPLDIwCA0bFxZT3VQrsZ0Zw+wJl723eZkJ+YWl9yXqi6Nl8fTW3Iy1E8c1opYZQCCryzPIdy9qQATUwEincKc28BgdcEx9RDTbGrE1HFr+kH5teA0rk4Q46bwYZizwVkbnQNBPp3TIjPJBX77rbUUe6uK/ALBWuzghq8Lc4AAAAASUVORK5CYII=";
|
|
6319
6464
|
|
|
6320
6465
|
// assets/tsukuyomi.png
|
|
6321
|
-
var tsukuyomi_default = "data:image/png;base64,
|
|
6466
|
+
var tsukuyomi_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB3UlEQVR42tWXPUsDQRCGnwuijYIoFqKmEDSCxIgIgqnsogbsrC3ERiwN4g8Ikk6sFH+BnYofvcTKxoigBCzEYGGjWIiCOYvNBHe5TdQUt051czc3e++zO7tzHnUst7vn04BlFue9Ws8jhGxN9ZTPzU43NkIlj41E6AQ8m/JYfByAoWgXAPtHJzRCRN43SbizBkzlv1X2VzLuVoHYzf0TAMnys+aLCTGThMTJGnKfQOpyWF1cvgHQsh4FYPDzRd3vmQHgoPShJbi9uqhJyPk1UK3Jwsq1/115rLst8AX/4UFP0NsbGHf7+Kr579l7zR/ZGvbcrAJR7vvqEOwcTdZMYIuTPCYJUS7Ewydgzn2Bay2gdWzqR4nMuMPlhcC5l/HcWQOnCaU4lVU3xI9tnwFQnOgDoDmdDs5QKmlxYhdGmBA2ibhTBfKFHCkCm00dAKymJn+USAidHx8DkI+0q7PBUC7j5BJ7jlSB7RyXziVT8fM7Oz7AeLmsz3VEaWi7UvtAcmvJC+qmq4T/XT8gdTsw2692to07AF7jeU35wFq/7COqzhdVnVOnu3aHgNm1VpVXlImJX9zQffO5kDg1dlb3CNj6dZsVK2vAVP7Xf8bwCfxWuc23Eanmt/xlh07gC6oBviFE8rZHAAAAAElFTkSuQmCC";
|
|
6322
6467
|
|
|
6323
6468
|
// src/voice-images.ts
|
|
6324
6469
|
var VOICE_IMAGES = {
|
|
@@ -6328,8 +6473,12 @@ var VOICE_IMAGES = {
|
|
|
6328
6473
|
ruko: ruko_default,
|
|
6329
6474
|
shiyo: shiyo_default,
|
|
6330
6475
|
teto: teto_default,
|
|
6331
|
-
tsukuyomi: tsukuyomi_default
|
|
6476
|
+
tsukuyomi: tsukuyomi_default,
|
|
6477
|
+
rei: rei_default,
|
|
6478
|
+
MGRoid: MGRoid_default,
|
|
6479
|
+
MOTRoid: MOTRoid_default
|
|
6332
6480
|
};
|
|
6481
|
+
var FALLBACK_VOCAL_ICON = Chip_default;
|
|
6333
6482
|
|
|
6334
6483
|
// src/mml-player.ts
|
|
6335
6484
|
var STEPS_PER_BEAT3 = 48;
|
|
@@ -6528,6 +6677,9 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6528
6677
|
collectLyrics: true
|
|
6529
6678
|
});
|
|
6530
6679
|
const lyricTracks = lyrics ?? /* @__PURE__ */ new Map();
|
|
6680
|
+
const customVocalByKey = new Map(
|
|
6681
|
+
parseCustomVocals(mml).map((d) => [d.key, d])
|
|
6682
|
+
);
|
|
6531
6683
|
const bpm = parsedBpm ?? options.defaultBpm ?? DEFAULT_BPM;
|
|
6532
6684
|
const drumPatternDict = options.drumPatterns ?? DRUM_PATTERNS;
|
|
6533
6685
|
const drumPattern = meta.drum ? drumPatternDict[meta.drum] ?? null : null;
|
|
@@ -6929,15 +7081,23 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6929
7081
|
for (const [index, lt] of lyricTracks) {
|
|
6930
7082
|
const em = emojiByTrack.get(index);
|
|
6931
7083
|
if (!em) continue;
|
|
7084
|
+
const custom = customVocalByKey.get(lt.model.toLowerCase());
|
|
6932
7085
|
const imgKey = VOICE_IMAGE_KEY[lt.model.toLowerCase()];
|
|
6933
|
-
const src = imgKey ? VOICE_IMAGES[imgKey] : void 0;
|
|
7086
|
+
const src = custom ? custom.iconUrl || FALLBACK_VOCAL_ICON : imgKey ? VOICE_IMAGES[imgKey] : void 0;
|
|
6934
7087
|
if (!src) continue;
|
|
6935
7088
|
const img = doc.createElement("img");
|
|
6936
7089
|
img.src = src;
|
|
7090
|
+
if (custom) {
|
|
7091
|
+
img.onerror = () => {
|
|
7092
|
+
img.onerror = null;
|
|
7093
|
+
img.src = FALLBACK_VOCAL_ICON;
|
|
7094
|
+
};
|
|
7095
|
+
}
|
|
6937
7096
|
img.width = 20;
|
|
6938
7097
|
img.height = 20;
|
|
6939
7098
|
img.style.borderRadius = "50%";
|
|
6940
7099
|
img.style.objectFit = "cover";
|
|
7100
|
+
img.style.imageRendering = "pixelated";
|
|
6941
7101
|
img.draggable = false;
|
|
6942
7102
|
promotedToImage.add(em);
|
|
6943
7103
|
em.textContent = "";
|
|
@@ -7372,6 +7532,13 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
7372
7532
|
}
|
|
7373
7533
|
});
|
|
7374
7534
|
try {
|
|
7535
|
+
if (customVocalByKey.size > 0) {
|
|
7536
|
+
v.registerVoicebanks?.(
|
|
7537
|
+
Object.fromEntries(
|
|
7538
|
+
[...customVocalByKey].map(([k, d]) => [k, d.url])
|
|
7539
|
+
)
|
|
7540
|
+
);
|
|
7541
|
+
}
|
|
7375
7542
|
await v.loadModels(tracks.map((t) => t.model));
|
|
7376
7543
|
if (skipSinging) return;
|
|
7377
7544
|
const startTime = performance.now();
|
|
@@ -7527,6 +7694,29 @@ var MIDI_INFO_HTML = `
|
|
|
7527
7694
|
<p style="margin-top:4px;"><small>\u6B4C\u8A5E\u306E\u62BD\u51FA: <a href="https://rpgen3.github.io/ust2txt/" target="_blank" rel="noopener">ust2txt</a></small></p>
|
|
7528
7695
|
</div>
|
|
7529
7696
|
`;
|
|
7697
|
+
var KOE_INFO_HTML = `
|
|
7698
|
+
<div class="dtm-modal-body-content">
|
|
7699
|
+
<h4>1. UTAU\u97F3\u6E90\u3092 .koe \u306B\u5909\u63DB\u3059\u308B</h4>
|
|
7700
|
+
<p>UTAU\u7528\u306E\u97F3\u6E90\uFF08zip\uFF09\u3092\u305D\u306E\u307E\u307E\u4F7F\u3046\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093\u3002\u4E0B\u8A18\u306E\u5909\u63DB\u30B5\u30A4\u30C8\u3067 <code>.koe</code> \u5F62\u5F0F\u306B\u5909\u63DB\u3057\u3066\u304F\u3060\u3055\u3044\u3002</p>
|
|
7701
|
+
<p style="margin-top:4px;"><small>\u5909\u63DB\u30B5\u30A4\u30C8: <a href="https://onjmin.github.io/koe/demo/" target="_blank" rel="noopener">koe\u5909\u63DB\u30C7\u30E2\uFF08onjmin.github.io/koe/demo\uFF09</a></small></p>
|
|
7702
|
+
|
|
7703
|
+
<h4>2. \u5909\u63DB\u3057\u305F .koe \u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3059\u308B</h4>
|
|
7704
|
+
<p>\u5909\u63DB\u5F8C\u306E <code>.koe</code> \u30D5\u30A1\u30A4\u30EB\u306F\u3001\u8AB0\u3067\u3082\u76F4\u63A5\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3067\u304D\u308B\u5F62\u3067\u30CD\u30C3\u30C8\u4E0A\u306B\u7F6E\u304F\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08\u30ED\u30FC\u30AB\u30EB\u306E\u30D5\u30A1\u30A4\u30EB\u30D1\u30B9\u306F\u4F7F\u3048\u307E\u305B\u3093\uFF09\u3002</p>
|
|
7705
|
+
<ul>
|
|
7706
|
+
<li><strong>Google\u30C9\u30E9\u30A4\u30D6</strong>: \u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u5F8C\u3001\u5171\u6709\u8A2D\u5B9A\u3092\u300C\u30EA\u30F3\u30AF\u3092\u77E5\u3063\u3066\u3044\u308B\u5168\u54E1\u300D\u306B\u5909\u66F4 \u2192 \u5171\u6709\u30EA\u30F3\u30AF\u306E<code>/d/</code>\u3068<code>/view</code>\u306E\u9593\u306EID\uFF08\u30D5\u30A1\u30A4\u30EBID\uFF09\u3092 controlled URL \u306B\u7D44\u307F\u8FBC\u3093\u3067\u76F4\u63A5\u30EA\u30F3\u30AF\u5316\u3057\u307E\u3059\uFF08\u4F8B: <code>https://drive.google.com/uc?export=download&id=\u30D5\u30A1\u30A4\u30EBID</code>\uFF09\u3002</li>
|
|
7707
|
+
<li>\u305D\u306E\u4ED6\u3001\u76F4\u63A5\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9URL\u3092\u767A\u884C\u3067\u304D\u308B\u30DB\u30B9\u30C6\u30A3\u30F3\u30B0\uFF08GitHub Pages\u3001Cloudflare R2 \u306A\u3069\uFF09\u3067\u3082\u69CB\u3044\u307E\u305B\u3093\u3002</li>
|
|
7708
|
+
</ul>
|
|
7709
|
+
|
|
7710
|
+
<h4>3. DTM\u3067\u4F7F\u3046</h4>
|
|
7711
|
+
<ul>
|
|
7712
|
+
<li>\u6B4C\u5531\u30E2\u30C7\u30EB\u306E\u30D7\u30EB\u30C0\u30A6\u30F3\u304B\u3089\u300C\u30AB\u30B9\u30BF\u30E0\u97F3\u6E90\u3092\u8FFD\u52A0\u2026\u300D\u3092\u9078\u3073\u307E\u3059\u3002</li>
|
|
7713
|
+
<li>\u300C\u97F3\u6E90URL\u300D\u306B\u624B\u98062\u306E\u76F4\u63A5\u30EA\u30F3\u30AF\u3092\u8CBC\u308A\u4ED8\u3051\u307E\u3059\u3002</li>
|
|
7714
|
+
<li>\u30A2\u30A4\u30B3\u30F3\u753B\u50CFUR\u30EB\u30FB\u8868\u793A\u540D\u30FB\u8B58\u5225\u5B50\u306F\u4EFB\u610F\u3067\u3059\uFF08\u7701\u7565\u53EF\uFF09\u3002</li>
|
|
7715
|
+
<li>\u300C\u8FFD\u52A0\u300D\u3092\u62BC\u3059\u3068\u30D7\u30EB\u30C0\u30A6\u30F3\u306B\u767B\u9332\u3055\u308C\u3001\u4EE5\u964D\u305D\u306E\u30C8\u30E9\u30C3\u30AF\u3067\u4F7F\u3048\u307E\u3059\u3002</li>
|
|
7716
|
+
</ul>
|
|
7717
|
+
<p style="margin-top:4px;"><small>\u203B\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3057\u305F\u97F3\u6E90\u306F\u81EA\u5DF1\u8CAC\u4EFB\u3067\u7BA1\u7406\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u6A29\u5229\u95A2\u4FC2\uFF08\u914D\u5E03\u5143\u306E\u5229\u7528\u898F\u7D04\uFF09\u306B\u3082\u5F93\u3063\u3066\u304F\u3060\u3055\u3044\u3002</small></p>
|
|
7718
|
+
</div>
|
|
7719
|
+
`;
|
|
7530
7720
|
var BASE_STEP_WIDTH = 0.5;
|
|
7531
7721
|
var BASE_KEY_HEIGHT = 15;
|
|
7532
7722
|
var TRACKS_SIMPLE = [
|
|
@@ -7667,12 +7857,14 @@ var TRACKS_ADVANCED = [
|
|
|
7667
7857
|
}
|
|
7668
7858
|
];
|
|
7669
7859
|
var DEFAULT_TRACKS = TRACKS_SIMPLE;
|
|
7670
|
-
var
|
|
7671
|
-
var
|
|
7860
|
+
var BASE_LYRIC_MODELS = ["klatt", ...Object.keys(KOE_VOICEBANKS)];
|
|
7861
|
+
var BASE_LYRIC_MODEL_LABELS = {
|
|
7672
7862
|
klatt: "\u8EFD\u91CF\u30ED\u30DC\u58F0",
|
|
7673
7863
|
...KOE_VOICEBANK_LABELS
|
|
7674
7864
|
};
|
|
7675
|
-
var lyricModelLabel = (model) =>
|
|
7865
|
+
var lyricModelLabel = (model, customMap) => BASE_LYRIC_MODEL_LABELS[model] ?? customMap.get(model)?.label ?? model;
|
|
7866
|
+
var CUSTOM_VOCAL_ADD_VALUE = "+custom";
|
|
7867
|
+
var CUSTOM_VOCAL_KEY_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
7676
7868
|
var clamp3 = (v, min, max) => Math.min(Math.max(v, min), max);
|
|
7677
7869
|
var normalizeInstrumentName = (name) => {
|
|
7678
7870
|
if (!name) return "";
|
|
@@ -7729,6 +7921,22 @@ var mountDAW = (target, options = {}) => {
|
|
|
7729
7921
|
let currentPlayStep = 0;
|
|
7730
7922
|
let ready = false;
|
|
7731
7923
|
let isLoading = false;
|
|
7924
|
+
const customVocalsMap = /* @__PURE__ */ new Map();
|
|
7925
|
+
const registerCustomVocal = (def) => {
|
|
7926
|
+
const key = def.key.toLowerCase();
|
|
7927
|
+
if (BASE_LYRIC_MODELS.includes(key)) return;
|
|
7928
|
+
customVocalsMap.set(key, { ...def, key });
|
|
7929
|
+
};
|
|
7930
|
+
const resetCustomVocals = () => {
|
|
7931
|
+
customVocalsMap.clear();
|
|
7932
|
+
for (const d of options.customVocals ?? []) registerCustomVocal(d);
|
|
7933
|
+
};
|
|
7934
|
+
resetCustomVocals();
|
|
7935
|
+
const genCustomVocalKey = () => {
|
|
7936
|
+
let n = 1;
|
|
7937
|
+
while (customVocalsMap.has(`custom${n}`)) n++;
|
|
7938
|
+
return `custom${n}`;
|
|
7939
|
+
};
|
|
7732
7940
|
let selectedNotes = [];
|
|
7733
7941
|
let selectionRect = null;
|
|
7734
7942
|
let copiedNotes = [];
|
|
@@ -8482,6 +8690,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
8482
8690
|
const overlay = showLoadingOverlay(refs.rollContainer);
|
|
8483
8691
|
setLoading(true);
|
|
8484
8692
|
try {
|
|
8693
|
+
if (customVocalsMap.size > 0) {
|
|
8694
|
+
voices.registerVoicebanks?.(
|
|
8695
|
+
Object.fromEntries(
|
|
8696
|
+
[...customVocalsMap].map(([k, d]) => [k, d.url])
|
|
8697
|
+
)
|
|
8698
|
+
);
|
|
8699
|
+
}
|
|
8485
8700
|
await voices.loadModels(streamTracks.map((t) => t.model));
|
|
8486
8701
|
await voices.warm(streamTracks);
|
|
8487
8702
|
} catch (err2) {
|
|
@@ -8646,6 +8861,20 @@ var mountDAW = (target, options = {}) => {
|
|
|
8646
8861
|
<a data-dtm="lyric-terms-link" target="_blank" rel="noopener" style="color:var(--dtm-primary);text-decoration:underline"></a>
|
|
8647
8862
|
<span>\u306E\u5229\u7528\u898F\u7D04\u306B\u5F93\u3063\u3066\u304F\u3060\u3055\u3044</span>
|
|
8648
8863
|
</div>
|
|
8864
|
+
<div class="dtm-row dtm-hidden" data-dtm="lyric-custom" style="flex-direction:column;align-items:stretch;gap:4px">
|
|
8865
|
+
<div class="dtm-row" style="justify-content: space-between; align-items: center;">
|
|
8866
|
+
<a data-dtm="lyric-custom-conv-link" href="https://onjmin.github.io/koe/demo/" target="_blank" rel="noopener" style="font-size:11px;color:var(--dtm-primary);text-decoration:underline">UTAU\u97F3\u6E90(zip)\u3092.koe\u306B\u5909\u63DB</a>
|
|
8867
|
+
<button class="dtm-btn dtm-btn--ghost dtm-btn--xs" data-dtm="lyric-custom-guide">\u4F7F\u3044\u65B9\u30AC\u30A4\u30C9</button>
|
|
8868
|
+
</div>
|
|
8869
|
+
<input type="url" class="dtm-input" data-dtm="lyric-custom-src" placeholder="\u97F3\u6E90URL\uFF08https://\u301C.koe\uFF09" aria-label="\u30AB\u30B9\u30BF\u30E0\u97F3\u6E90\uFF08.koe\uFF09\u306EURL">
|
|
8870
|
+
<input type="url" class="dtm-input" data-dtm="lyric-custom-icon" placeholder="\u30A2\u30A4\u30B3\u30F3\u753B\u50CFURL\uFF08\u4EFB\u610F\uFF09" aria-label="\u30AB\u30B9\u30BF\u30E0\u97F3\u6E90\u306E\u30A2\u30A4\u30B3\u30F3\u753B\u50CFURL">
|
|
8871
|
+
<input type="text" class="dtm-input" data-dtm="lyric-custom-alias" placeholder="\u8868\u793A\u540D\uFF08\u4EFB\u610F\uFF09" aria-label="\u30AB\u30B9\u30BF\u30E0\u97F3\u6E90\u306E\u8868\u793A\u540D\uFF08\u30D7\u30EB\u30C0\u30A6\u30F3\u306E\u5225\u540D\uFF09" maxlength="64">
|
|
8872
|
+
<input type="text" class="dtm-input" data-dtm="lyric-custom-key" placeholder="\u8B58\u5225\u5B50\uFF08\u4EFB\u610F\u30FB\u7701\u7565\u3067\u81EA\u52D5\u63A1\u756A\u3001\u82F1\u5B57\u59CB\u307E\u308A\u82F1\u6570\u5B57\u3068_\uFF09" aria-label="\u30AB\u30B9\u30BF\u30E0\u97F3\u6E90\u306EMML\u8B58\u5225\u5B50\uFF08\u30AD\u30FC\uFF09" maxlength="32">
|
|
8873
|
+
<div class="dtm-row">
|
|
8874
|
+
<span class="dtm-label dtm-grow" data-dtm="lyric-custom-note" style="color:var(--dtm-warn)"></span>
|
|
8875
|
+
<button class="dtm-btn dtm-btn--primary" data-dtm="lyric-custom-apply">\u8FFD\u52A0</button>
|
|
8876
|
+
</div>
|
|
8877
|
+
</div>
|
|
8649
8878
|
<div class="dtm-row" data-dtm="lyric-body" style="flex-direction:column;align-items:stretch">
|
|
8650
8879
|
<div class="dtm-row">
|
|
8651
8880
|
<span class="dtm-label">\u58F0\u91CF</span>
|
|
@@ -8696,6 +8925,30 @@ var mountDAW = (target, options = {}) => {
|
|
|
8696
8925
|
const lyricTermsLink = lyricDiv.querySelector(
|
|
8697
8926
|
'[data-dtm="lyric-terms-link"]'
|
|
8698
8927
|
);
|
|
8928
|
+
const lyricCustom = lyricDiv.querySelector(
|
|
8929
|
+
'[data-dtm="lyric-custom"]'
|
|
8930
|
+
);
|
|
8931
|
+
const lyricCustomSrc = lyricDiv.querySelector(
|
|
8932
|
+
'[data-dtm="lyric-custom-src"]'
|
|
8933
|
+
);
|
|
8934
|
+
const lyricCustomIcon = lyricDiv.querySelector(
|
|
8935
|
+
'[data-dtm="lyric-custom-icon"]'
|
|
8936
|
+
);
|
|
8937
|
+
const lyricCustomAlias = lyricDiv.querySelector(
|
|
8938
|
+
'[data-dtm="lyric-custom-alias"]'
|
|
8939
|
+
);
|
|
8940
|
+
const lyricCustomKey = lyricDiv.querySelector(
|
|
8941
|
+
'[data-dtm="lyric-custom-key"]'
|
|
8942
|
+
);
|
|
8943
|
+
const lyricCustomGuide = lyricDiv.querySelector(
|
|
8944
|
+
'[data-dtm="lyric-custom-guide"]'
|
|
8945
|
+
);
|
|
8946
|
+
const lyricCustomNote = lyricDiv.querySelector(
|
|
8947
|
+
'[data-dtm="lyric-custom-note"]'
|
|
8948
|
+
);
|
|
8949
|
+
const lyricCustomApply = lyricDiv.querySelector(
|
|
8950
|
+
'[data-dtm="lyric-custom-apply"]'
|
|
8951
|
+
);
|
|
8699
8952
|
const fmtPan = (pan) => pan === 64 ? "C" : pan < 64 ? `L${64 - pan}` : `R${pan - 64}`;
|
|
8700
8953
|
const addOpt = (value, label) => {
|
|
8701
8954
|
const o = document.createElement("option");
|
|
@@ -8704,9 +8957,15 @@ var mountDAW = (target, options = {}) => {
|
|
|
8704
8957
|
lyricModelSel.appendChild(o);
|
|
8705
8958
|
};
|
|
8706
8959
|
addOpt("", "\u30DC\u30FC\u30AB\u30EB\u306A\u3057");
|
|
8707
|
-
for (const m of
|
|
8708
|
-
|
|
8709
|
-
|
|
8960
|
+
for (const m of BASE_LYRIC_MODELS)
|
|
8961
|
+
addOpt(m, lyricModelLabel(m, customVocalsMap));
|
|
8962
|
+
for (const [k, def] of customVocalsMap) addOpt(k, def.label ?? k);
|
|
8963
|
+
addOpt(CUSTOM_VOCAL_ADD_VALUE, "\u30AB\u30B9\u30BF\u30E0\u97F3\u6E90\u3092\u8FFD\u52A0\u2026");
|
|
8964
|
+
if (active.lyricModel && !BASE_LYRIC_MODELS.includes(active.lyricModel) && !customVocalsMap.has(active.lyricModel)) {
|
|
8965
|
+
addOpt(
|
|
8966
|
+
active.lyricModel,
|
|
8967
|
+
lyricModelLabel(active.lyricModel, customVocalsMap)
|
|
8968
|
+
);
|
|
8710
8969
|
}
|
|
8711
8970
|
lyricModelSel.value = active.lyricModel;
|
|
8712
8971
|
lyricOctaveSel.value = String(active.vocalOctave);
|
|
@@ -8720,9 +8979,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
8720
8979
|
lyricCount.textContent = active.lyricModel && n > 0 ? `${n}\u97F3\u7BC0` : "";
|
|
8721
8980
|
};
|
|
8722
8981
|
const syncLyricTerms = () => {
|
|
8982
|
+
if (customVocalsMap.has(active.lyricModel)) {
|
|
8983
|
+
lyricTerms.classList.add("dtm-hidden");
|
|
8984
|
+
return;
|
|
8985
|
+
}
|
|
8723
8986
|
const url2 = active.lyricModel ? KOE_VOICEBANK_TERMS[active.lyricModel] : void 0;
|
|
8724
8987
|
if (url2) {
|
|
8725
|
-
const label = lyricModelLabel(active.lyricModel);
|
|
8988
|
+
const label = lyricModelLabel(active.lyricModel, customVocalsMap);
|
|
8726
8989
|
lyricTermsLink.textContent = `${label}UTAU\u97F3\u6E90`;
|
|
8727
8990
|
lyricTermsLink.href = url2;
|
|
8728
8991
|
lyricTerms.classList.remove("dtm-hidden");
|
|
@@ -8731,7 +8994,24 @@ var mountDAW = (target, options = {}) => {
|
|
|
8731
8994
|
}
|
|
8732
8995
|
};
|
|
8733
8996
|
const syncLyricIcon = () => {
|
|
8734
|
-
|
|
8997
|
+
if (!active.lyricModel) {
|
|
8998
|
+
lyricIcon.removeAttribute("src");
|
|
8999
|
+
lyricIcon.classList.add("dtm-hidden");
|
|
9000
|
+
return;
|
|
9001
|
+
}
|
|
9002
|
+
const customDef = customVocalsMap.get(active.lyricModel);
|
|
9003
|
+
if (customDef !== void 0) {
|
|
9004
|
+
const iconSrc = customDef.iconUrl || FALLBACK_VOCAL_ICON;
|
|
9005
|
+
lyricIcon.src = iconSrc;
|
|
9006
|
+
lyricIcon.classList.remove("dtm-hidden");
|
|
9007
|
+
lyricIcon.onerror = () => {
|
|
9008
|
+
lyricIcon.onerror = null;
|
|
9009
|
+
lyricIcon.src = FALLBACK_VOCAL_ICON;
|
|
9010
|
+
};
|
|
9011
|
+
return;
|
|
9012
|
+
}
|
|
9013
|
+
lyricIcon.onerror = null;
|
|
9014
|
+
const imgKey = VOICE_IMAGE_KEY[active.lyricModel.toLowerCase()];
|
|
8735
9015
|
const src = imgKey ? VOICE_IMAGES[imgKey] : void 0;
|
|
8736
9016
|
if (src) {
|
|
8737
9017
|
lyricIcon.src = src;
|
|
@@ -8750,11 +9030,64 @@ var mountDAW = (target, options = {}) => {
|
|
|
8750
9030
|
};
|
|
8751
9031
|
syncLyricVisibility();
|
|
8752
9032
|
lyricModelSel.addEventListener("change", () => {
|
|
9033
|
+
if (lyricModelSel.value === CUSTOM_VOCAL_ADD_VALUE) {
|
|
9034
|
+
lyricCustomNote.textContent = "";
|
|
9035
|
+
lyricCustomAlias.value = "";
|
|
9036
|
+
lyricCustomKey.value = "";
|
|
9037
|
+
lyricCustom.classList.remove("dtm-hidden");
|
|
9038
|
+
return;
|
|
9039
|
+
}
|
|
9040
|
+
lyricCustom.classList.add("dtm-hidden");
|
|
8753
9041
|
active.lyricModel = lyricModelSel.value;
|
|
8754
9042
|
syncLyricVisibility();
|
|
8755
9043
|
syncInstDisabled();
|
|
8756
9044
|
fireLyricsChange(active);
|
|
8757
9045
|
});
|
|
9046
|
+
lyricCustomGuide.addEventListener("click", () => {
|
|
9047
|
+
showModal("\u30AB\u30B9\u30BF\u30E0\u97F3\u6E90(.koe)\u306E\u4F7F\u3044\u65B9", KOE_INFO_HTML);
|
|
9048
|
+
});
|
|
9049
|
+
lyricCustomApply.addEventListener("click", () => {
|
|
9050
|
+
const src = lyricCustomSrc.value.trim();
|
|
9051
|
+
if (!isValidHttpUrl(src)) {
|
|
9052
|
+
lyricCustomNote.textContent = "\u97F3\u6E90URL\u304C\u4E0D\u6B63\u3067\u3059\uFF08http/https\u306E\u307F\u30FB2048\u6587\u5B57\u307E\u3067\uFF09";
|
|
9053
|
+
return;
|
|
9054
|
+
}
|
|
9055
|
+
const iconRaw = lyricCustomIcon.value.trim();
|
|
9056
|
+
const iconUrl = isValidHttpUrl(iconRaw) ? iconRaw : "";
|
|
9057
|
+
const alias = lyricCustomAlias.value.trim();
|
|
9058
|
+
const existing = [...customVocalsMap.values()].find(
|
|
9059
|
+
(d) => d.url === src
|
|
9060
|
+
);
|
|
9061
|
+
const keyRaw = lyricCustomKey.value.trim().toLowerCase();
|
|
9062
|
+
let key;
|
|
9063
|
+
if (keyRaw) {
|
|
9064
|
+
if (!CUSTOM_VOCAL_KEY_RE.test(keyRaw)) {
|
|
9065
|
+
lyricCustomNote.textContent = "\u8B58\u5225\u5B50\u304C\u4E0D\u6B63\u3067\u3059\uFF08\u82F1\u5B57\u307E\u305F\u306F\u30A2\u30F3\u30C0\u30FC\u30B9\u30B3\u30A2\u3067\u59CB\u307E\u308B\u82F1\u6570\u5B57\u30FB_\u306E\u307F\uFF09";
|
|
9066
|
+
return;
|
|
9067
|
+
}
|
|
9068
|
+
if (BASE_LYRIC_MODELS.includes(keyRaw)) {
|
|
9069
|
+
lyricCustomNote.textContent = "\u305D\u306E\u8B58\u5225\u5B50\u306F\u5185\u8535\u30E2\u30C7\u30EB\u540D\u3068\u885D\u7A81\u3057\u3066\u3044\u307E\u3059";
|
|
9070
|
+
return;
|
|
9071
|
+
}
|
|
9072
|
+
const conflict = customVocalsMap.get(keyRaw);
|
|
9073
|
+
if (conflict && conflict.url !== src) {
|
|
9074
|
+
lyricCustomNote.textContent = "\u305D\u306E\u8B58\u5225\u5B50\u306F\u5225\u306E\u97F3\u6E90\u306B\u4F7F\u7528\u6E08\u307F\u3067\u3059";
|
|
9075
|
+
return;
|
|
9076
|
+
}
|
|
9077
|
+
key = keyRaw;
|
|
9078
|
+
} else {
|
|
9079
|
+
key = existing?.key ?? genCustomVocalKey();
|
|
9080
|
+
}
|
|
9081
|
+
registerCustomVocal({
|
|
9082
|
+
key,
|
|
9083
|
+
iconUrl: iconUrl || (existing?.iconUrl ?? ""),
|
|
9084
|
+
url: src,
|
|
9085
|
+
label: alias || existing?.label
|
|
9086
|
+
});
|
|
9087
|
+
active.lyricModel = key;
|
|
9088
|
+
fireLyricsChange(active);
|
|
9089
|
+
updateTrackPanel();
|
|
9090
|
+
});
|
|
8758
9091
|
lyricOctaveSel.addEventListener("change", () => {
|
|
8759
9092
|
active.vocalOctave = Number.parseInt(lyricOctaveSel.value, 10);
|
|
8760
9093
|
fireLyricsChange(active);
|
|
@@ -8938,9 +9271,25 @@ var mountDAW = (target, options = {}) => {
|
|
|
8938
9271
|
const head = params ? `${x.model} ${params}` : x.model;
|
|
8939
9272
|
return `@@${x.i} ${head} ${x.text}`;
|
|
8940
9273
|
});
|
|
8941
|
-
const
|
|
9274
|
+
const customVocalDecls = [];
|
|
9275
|
+
for (const [key, def] of customVocalsMap) {
|
|
9276
|
+
const isUsed = trackStates.some(
|
|
9277
|
+
(t) => t.lyricModel.trim().toLowerCase() === key && t.lyrics.trim().length > 0 && clipNotes(t.core.getNotes()).length > 0
|
|
9278
|
+
);
|
|
9279
|
+
if (!isUsed) continue;
|
|
9280
|
+
const iconPart = def.iconUrl || "-";
|
|
9281
|
+
customVocalDecls.push(`@@${key} ${iconPart} ${def.url}`);
|
|
9282
|
+
}
|
|
9283
|
+
const full = [
|
|
9284
|
+
metaLineFull,
|
|
9285
|
+
...customVocalDecls,
|
|
9286
|
+
...trackLines,
|
|
9287
|
+
...lyricLines,
|
|
9288
|
+
MML_END_MARKER
|
|
9289
|
+
].filter((s) => s.length > 0).join(";\n");
|
|
8942
9290
|
const minified = [
|
|
8943
9291
|
metaLineMini,
|
|
9292
|
+
...customVocalDecls,
|
|
8944
9293
|
...trackLinesMini,
|
|
8945
9294
|
...lyricLines,
|
|
8946
9295
|
MML_END_MARKER
|
|
@@ -9005,6 +9354,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
9005
9354
|
stop();
|
|
9006
9355
|
clearAll();
|
|
9007
9356
|
for (const t of trackStates) t.core.setLoadMode(true);
|
|
9357
|
+
resetCustomVocals();
|
|
9358
|
+
for (const def of parseCustomVocals(mml)) registerCustomVocal(def);
|
|
9008
9359
|
const {
|
|
9009
9360
|
placements,
|
|
9010
9361
|
bpm: parsedBpm,
|
|
@@ -10364,6 +10715,9 @@ var SoundFont = class _SoundFont {
|
|
|
10364
10715
|
this.ch = ch;
|
|
10365
10716
|
this.isDrum = isDrum;
|
|
10366
10717
|
}
|
|
10718
|
+
zones;
|
|
10719
|
+
ch;
|
|
10720
|
+
isDrum;
|
|
10367
10721
|
static afterTime = 0.5;
|
|
10368
10722
|
static fonts = /* @__PURE__ */ new Map();
|
|
10369
10723
|
static ch = -1;
|
|
@@ -11330,12 +11684,14 @@ var createDtmStudio = async (options = {}) => {
|
|
|
11330
11684
|
init,
|
|
11331
11685
|
injectStyles,
|
|
11332
11686
|
isChordHeavyTrack,
|
|
11687
|
+
isValidHttpUrl,
|
|
11333
11688
|
koeUrl,
|
|
11334
11689
|
mountDAW,
|
|
11335
11690
|
mountMmlPlayer,
|
|
11336
11691
|
normalizeLyrics,
|
|
11337
11692
|
onClick,
|
|
11338
11693
|
panToStereo,
|
|
11694
|
+
parseCustomVocals,
|
|
11339
11695
|
parseLyrics,
|
|
11340
11696
|
parseMML,
|
|
11341
11697
|
parseMmlMeta,
|
|
@@ -11344,6 +11700,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
11344
11700
|
setDrawOffset,
|
|
11345
11701
|
shiftNotes,
|
|
11346
11702
|
showLoadingOverlay,
|
|
11703
|
+
stripCustomVocals,
|
|
11347
11704
|
stripLyrics,
|
|
11348
11705
|
stripMmlMeta,
|
|
11349
11706
|
vocalVolumeToGain
|