@onjmin/dtm 0.1.46 → 0.1.48
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 +57 -2
- package/dist/index.d.ts +57 -2
- package/dist/index.js +419 -55
- package/dist/index.mjs +416 -55
- package/dist/voice-worker.js +90 -25
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1719,7 +1719,7 @@ var INSTRUMENT_PRESETS = {
|
|
|
1719
1719
|
}
|
|
1720
1720
|
};
|
|
1721
1721
|
|
|
1722
|
-
// node_modules/.pnpm/@onjmin+koe@1.0.
|
|
1722
|
+
// node_modules/.pnpm/@onjmin+koe@1.0.4/node_modules/@onjmin/koe/dist/index.js
|
|
1723
1723
|
var MAGIC = 1263486208;
|
|
1724
1724
|
function parseKoeHeader(headerBytes) {
|
|
1725
1725
|
const view = new DataView(headerBytes);
|
|
@@ -1729,6 +1729,8 @@ function parseKoeHeader(headerBytes) {
|
|
|
1729
1729
|
return { jsonLength: view.getUint32(4, true) };
|
|
1730
1730
|
}
|
|
1731
1731
|
var pcmBase = (jsonLength) => 8 + jsonLength;
|
|
1732
|
+
var MAX_PHONEME_SAMPLES = 5242880;
|
|
1733
|
+
var MAX_JSON_LENGTH = 50 * 1024 * 1024;
|
|
1732
1734
|
var BlobVoiceSource = class {
|
|
1733
1735
|
constructor(blob2, base) {
|
|
1734
1736
|
this.blob = blob2;
|
|
@@ -1750,22 +1752,60 @@ var RangeVoiceSource = class {
|
|
|
1750
1752
|
base;
|
|
1751
1753
|
async readBytes(offset, length) {
|
|
1752
1754
|
const start = this.base + offset;
|
|
1753
|
-
|
|
1754
|
-
headers: { Range: `bytes=${start}-${start + length - 1}` }
|
|
1755
|
-
});
|
|
1756
|
-
if (!res.ok && res.status !== 206) {
|
|
1757
|
-
throw new Error(`.koe range request failed: ${res.status}`);
|
|
1758
|
-
}
|
|
1759
|
-
return res.arrayBuffer();
|
|
1755
|
+
return rangeFetch(this.url, start, length);
|
|
1760
1756
|
}
|
|
1761
1757
|
};
|
|
1762
1758
|
async function rangeFetch(url2, start, length) {
|
|
1763
1759
|
const res = await fetch(url2, {
|
|
1764
|
-
headers: { Range: `bytes=${start}-${start + length - 1}` }
|
|
1760
|
+
headers: { Range: `bytes=${start}-${start + length - 1}` },
|
|
1761
|
+
credentials: "omit"
|
|
1762
|
+
// never leak cookies / auth to a MML-supplied URL
|
|
1765
1763
|
});
|
|
1766
|
-
if (
|
|
1767
|
-
throw new Error(
|
|
1768
|
-
|
|
1764
|
+
if (res.status !== 206) {
|
|
1765
|
+
throw new Error(
|
|
1766
|
+
`.koe fetch failed: expected 206 Partial Content, got ${res.status}`
|
|
1767
|
+
);
|
|
1768
|
+
}
|
|
1769
|
+
return readCapped(res, length);
|
|
1770
|
+
}
|
|
1771
|
+
async function readCapped(res, length) {
|
|
1772
|
+
const reader = res.body?.getReader();
|
|
1773
|
+
if (!reader) {
|
|
1774
|
+
const buf = await res.arrayBuffer();
|
|
1775
|
+
if (buf.byteLength > length) {
|
|
1776
|
+
throw new Error(
|
|
1777
|
+
`.koe fetch failed: response exceeds requested ${length} bytes`
|
|
1778
|
+
);
|
|
1779
|
+
}
|
|
1780
|
+
return buf;
|
|
1781
|
+
}
|
|
1782
|
+
const out = new Uint8Array(length);
|
|
1783
|
+
let received = 0;
|
|
1784
|
+
for (; ; ) {
|
|
1785
|
+
const { done, value } = await reader.read();
|
|
1786
|
+
if (done) break;
|
|
1787
|
+
if (received + value.byteLength > length) {
|
|
1788
|
+
await reader.cancel();
|
|
1789
|
+
throw new Error(
|
|
1790
|
+
`.koe fetch failed: response exceeds requested ${length} bytes`
|
|
1791
|
+
);
|
|
1792
|
+
}
|
|
1793
|
+
out.set(value, received);
|
|
1794
|
+
received += value.byteLength;
|
|
1795
|
+
}
|
|
1796
|
+
return received === length ? out.buffer : out.buffer.slice(0, received);
|
|
1797
|
+
}
|
|
1798
|
+
function validateJsonLength(jsonLength) {
|
|
1799
|
+
if (!Number.isInteger(jsonLength) || jsonLength < 0 || jsonLength > MAX_JSON_LENGTH) {
|
|
1800
|
+
throw new Error(`manifest JSON length out of bounds: ${jsonLength}`);
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
function parseManifest(json) {
|
|
1804
|
+
const manifest = JSON.parse(new TextDecoder().decode(json));
|
|
1805
|
+
if (!manifest || typeof manifest !== "object" || typeof manifest.phonemes !== "object" || manifest.phonemes === null) {
|
|
1806
|
+
throw new Error("invalid manifest: missing phonemes table");
|
|
1807
|
+
}
|
|
1808
|
+
return manifest;
|
|
1769
1809
|
}
|
|
1770
1810
|
var VoiceBank = class _VoiceBank {
|
|
1771
1811
|
constructor(manifest, source) {
|
|
@@ -1779,20 +1819,41 @@ var VoiceBank = class _VoiceBank {
|
|
|
1779
1819
|
* @param koe a Blob/File of the .koe archive, or a URL (served with Range support)
|
|
1780
1820
|
*/
|
|
1781
1821
|
static async load(koe) {
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1822
|
+
try {
|
|
1823
|
+
if (typeof koe === "string") {
|
|
1824
|
+
if (/^blob:/i.test(koe)) {
|
|
1825
|
+
const res = await fetch(koe);
|
|
1826
|
+
if (!res.ok) {
|
|
1827
|
+
throw new Error(`blob: URL fetch failed: ${res.status}`);
|
|
1828
|
+
}
|
|
1829
|
+
return await _VoiceBank.fromBlob(await res.blob());
|
|
1830
|
+
}
|
|
1831
|
+
if (!/^https?:/i.test(koe)) {
|
|
1832
|
+
throw new Error(`unsupported URL protocol: ${koe}`);
|
|
1833
|
+
}
|
|
1834
|
+
const header = await rangeFetch(koe, 0, 8);
|
|
1835
|
+
const { jsonLength } = parseKoeHeader(header);
|
|
1836
|
+
validateJsonLength(jsonLength);
|
|
1837
|
+
const json = await rangeFetch(koe, 8, jsonLength);
|
|
1838
|
+
const manifest = parseManifest(json);
|
|
1839
|
+
return new _VoiceBank(
|
|
1840
|
+
manifest,
|
|
1841
|
+
new RangeVoiceSource(koe, pcmBase(jsonLength))
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
return await _VoiceBank.fromBlob(koe);
|
|
1845
|
+
} catch (error) {
|
|
1846
|
+
throw new Error(
|
|
1847
|
+
`Failed to load .koe voice bank: ${error instanceof Error ? error.message : String(error)}`
|
|
1790
1848
|
);
|
|
1791
1849
|
}
|
|
1850
|
+
}
|
|
1851
|
+
static async fromBlob(koe) {
|
|
1792
1852
|
const header = await koe.slice(0, 8).arrayBuffer();
|
|
1793
1853
|
const { jsonLength } = parseKoeHeader(header);
|
|
1854
|
+
validateJsonLength(jsonLength);
|
|
1794
1855
|
const json = await koe.slice(8, 8 + jsonLength).arrayBuffer();
|
|
1795
|
-
const manifest =
|
|
1856
|
+
const manifest = parseManifest(json);
|
|
1796
1857
|
return new _VoiceBank(
|
|
1797
1858
|
manifest,
|
|
1798
1859
|
new BlobVoiceSource(koe, pcmBase(jsonLength))
|
|
@@ -1800,7 +1861,7 @@ var VoiceBank = class _VoiceBank {
|
|
|
1800
1861
|
}
|
|
1801
1862
|
/** True if the bank contains a phoneme under this alias. */
|
|
1802
1863
|
has(phoneme) {
|
|
1803
|
-
return this.manifest.phonemes
|
|
1864
|
+
return Object.hasOwn(this.manifest.phonemes, phoneme);
|
|
1804
1865
|
}
|
|
1805
1866
|
/**
|
|
1806
1867
|
* Raw Int16 PCM bytes (48 kHz / mono) for a phoneme, or null if unknown.
|
|
@@ -1808,8 +1869,11 @@ var VoiceBank = class _VoiceBank {
|
|
|
1808
1869
|
* worker / AudioWorklet.
|
|
1809
1870
|
*/
|
|
1810
1871
|
async readPcmBytes(phoneme) {
|
|
1872
|
+
if (!Object.hasOwn(this.manifest.phonemes, phoneme)) return null;
|
|
1811
1873
|
const entry = this.manifest.phonemes[phoneme];
|
|
1812
|
-
if (!entry)
|
|
1874
|
+
if (!Number.isInteger(entry.offset) || !Number.isInteger(entry.length) || entry.offset < 0 || entry.length < 0 || entry.length > MAX_PHONEME_SAMPLES) {
|
|
1875
|
+
throw new Error(`manifest entry out of bounds for phoneme: ${phoneme}`);
|
|
1876
|
+
}
|
|
1813
1877
|
return this.source.readBytes(entry.offset, entry.length * 2);
|
|
1814
1878
|
}
|
|
1815
1879
|
/**
|
|
@@ -1819,7 +1883,7 @@ var VoiceBank = class _VoiceBank {
|
|
|
1819
1883
|
async getPcm(phoneme) {
|
|
1820
1884
|
const buf = await this.readPcmBytes(phoneme);
|
|
1821
1885
|
if (!buf) return null;
|
|
1822
|
-
const int16 = new Int16Array(buf);
|
|
1886
|
+
const int16 = new Int16Array(buf, 0, Math.floor(buf.byteLength / 2));
|
|
1823
1887
|
const f64 = new Float64Array(int16.length);
|
|
1824
1888
|
for (let i = 0; i < int16.length; i++) f64[i] = int16[i] / 32768;
|
|
1825
1889
|
return f64;
|
|
@@ -2010,7 +2074,8 @@ var Worldline = class _Worldline {
|
|
|
2010
2074
|
}
|
|
2011
2075
|
const outLen = WL._PhraseSynthSynth(ps, yPtrPtr, 0);
|
|
2012
2076
|
const yPtr = WL.getValue(yPtrPtr, "*");
|
|
2013
|
-
const audio = outLen > 0 ? new Float32Array(WL.HEAPF32.buffer, yPtr, outLen).slice() : null;
|
|
2077
|
+
const audio = outLen > 0 && yPtr ? new Float32Array(WL.HEAPF32.buffer, yPtr, outLen).slice() : null;
|
|
2078
|
+
if (yPtr) WL._free(yPtr);
|
|
2014
2079
|
WL._free(yPtrPtr);
|
|
2015
2080
|
WL._PhraseSynthDelete(ps);
|
|
2016
2081
|
return audio;
|
|
@@ -2201,7 +2266,7 @@ var parseLyrics = (mml) => {
|
|
|
2201
2266
|
let pan = 64;
|
|
2202
2267
|
let octave = 0;
|
|
2203
2268
|
const modelMatch = rest.match(
|
|
2204
|
-
/^([a-z_]
|
|
2269
|
+
/^([a-z_][a-z0-9_]*?)(?=(?:[vqpo]-?\d)|[^a-z0-9_]|$)(?::(\d+))?/i
|
|
2205
2270
|
);
|
|
2206
2271
|
let model = "";
|
|
2207
2272
|
const metaTokens = [];
|
|
@@ -2276,6 +2341,40 @@ var stripLyrics = (mml) => {
|
|
|
2276
2341
|
}
|
|
2277
2342
|
return kept.join("\n");
|
|
2278
2343
|
};
|
|
2344
|
+
var CUSTOM_VOCAL_LINE = /^@@([a-zA-Z_][a-zA-Z0-9_]*)\s+(\S+)\s+(\S+)\s*$/;
|
|
2345
|
+
var CUSTOM_VOCAL_URL_MAX_LEN = 2048;
|
|
2346
|
+
var isValidHttpUrl = (s) => {
|
|
2347
|
+
if (s.length > CUSTOM_VOCAL_URL_MAX_LEN) return false;
|
|
2348
|
+
try {
|
|
2349
|
+
const u = new URL(s);
|
|
2350
|
+
return u.protocol === "http:" || u.protocol === "https:";
|
|
2351
|
+
} catch {
|
|
2352
|
+
return false;
|
|
2353
|
+
}
|
|
2354
|
+
};
|
|
2355
|
+
var parseCustomVocals = (mml) => {
|
|
2356
|
+
const map = /* @__PURE__ */ new Map();
|
|
2357
|
+
for (const seg of splitSegments(mml)) {
|
|
2358
|
+
const m = seg.match(CUSTOM_VOCAL_LINE);
|
|
2359
|
+
if (!m) continue;
|
|
2360
|
+
const key = m[1].toLowerCase();
|
|
2361
|
+
const iconUrl = m[2];
|
|
2362
|
+
const koeUrl2 = m[3];
|
|
2363
|
+
if (!isValidHttpUrl(koeUrl2)) {
|
|
2364
|
+
console.warn(
|
|
2365
|
+
`[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`,
|
|
2366
|
+
koeUrl2.slice(0, 80)
|
|
2367
|
+
);
|
|
2368
|
+
continue;
|
|
2369
|
+
}
|
|
2370
|
+
const resolvedIconUrl = isValidHttpUrl(iconUrl) ? iconUrl : "";
|
|
2371
|
+
map.set(key, { key, iconUrl: resolvedIconUrl, url: koeUrl2 });
|
|
2372
|
+
}
|
|
2373
|
+
return [...map.values()];
|
|
2374
|
+
};
|
|
2375
|
+
var stripCustomVocals = (mml) => mml.split(/[\n\r]+/).map(
|
|
2376
|
+
(line) => line.split(";").filter((seg) => !CUSTOM_VOCAL_LINE.test(seg.trim())).join(";")
|
|
2377
|
+
).join("\n");
|
|
2279
2378
|
var panToStereo = (pan) => Math.max(-1, Math.min(1, (pan - 64) / 64));
|
|
2280
2379
|
var createLyricsConductor = (lyrics) => {
|
|
2281
2380
|
const pointers = /* @__PURE__ */ new Map();
|
|
@@ -2402,7 +2501,10 @@ var KOE_VOICEBANKS = {
|
|
|
2402
2501
|
ruko_male: "\u6B32\u97F3\u30EB\u30B3\u2642\u9023\u7D9A\u97F3Ver.1.03.koe",
|
|
2403
2502
|
ruko_female: "\u6B32\u97F3\u30EB\u30B3\u2640\u6B4C\u9023\u7D9A\u97F3\u666E1.00.koe",
|
|
2404
2503
|
teto: "\u91CD\u97F3\u30C6\u30C8\u5358\u72EC\u97F3.koe",
|
|
2405
|
-
shiyo: "\u9769\u547D\u30B7\u30E8.koe"
|
|
2504
|
+
shiyo: "\u9769\u547D\u30B7\u30E8.koe",
|
|
2505
|
+
rei: "\u8DB3\u7ACB\u30EC\u30A4ver3.5.0.koe",
|
|
2506
|
+
MGRoid: "MGRoid_\u539F\u97F3\u8A2D\u5B9A\u6E08\u307F.koe",
|
|
2507
|
+
MOTRoid: "MOTRoid\u5B8C\u5168\u7248V2.koe"
|
|
2406
2508
|
};
|
|
2407
2509
|
var KOE_VOICEBANK_LABELS = {
|
|
2408
2510
|
tsukuyomi: "\u3064\u304F\u3088\u307F\u3061\u3083\u3093",
|
|
@@ -2411,7 +2513,10 @@ var KOE_VOICEBANK_LABELS = {
|
|
|
2411
2513
|
ruko_male: "\u6B32\u97F3\u30EB\u30B3\u2642",
|
|
2412
2514
|
ruko_female: "\u6B32\u97F3\u30EB\u30B3\u2640",
|
|
2413
2515
|
teto: "\u91CD\u97F3\u30C6\u30C8",
|
|
2414
|
-
shiyo: "\u9769\u547D\u30B7\u30E8"
|
|
2516
|
+
shiyo: "\u9769\u547D\u30B7\u30E8",
|
|
2517
|
+
rei: "\u8DB3\u7ACB\u30EC\u30A4",
|
|
2518
|
+
MGRoid: "MGRoid",
|
|
2519
|
+
MOTRoid: "MOTRoid"
|
|
2415
2520
|
};
|
|
2416
2521
|
var VOICE_IMAGE_KEY = {
|
|
2417
2522
|
klatt: "puyuyu",
|
|
@@ -2421,7 +2526,10 @@ var VOICE_IMAGE_KEY = {
|
|
|
2421
2526
|
ruko_male: "ruko",
|
|
2422
2527
|
ruko_female: "ruko",
|
|
2423
2528
|
teto: "teto",
|
|
2424
|
-
shiyo: "shiyo"
|
|
2529
|
+
shiyo: "shiyo",
|
|
2530
|
+
rei: "rei",
|
|
2531
|
+
MGRoid: "MGRoid",
|
|
2532
|
+
MOTRoid: "MOTRoid"
|
|
2425
2533
|
};
|
|
2426
2534
|
var KOE_VOICEBANK_TERMS = {
|
|
2427
2535
|
tsukuyomi: "https://tyc.rei-yumesaki.net/material/utau/terms/",
|
|
@@ -2430,7 +2538,10 @@ var KOE_VOICEBANK_TERMS = {
|
|
|
2430
2538
|
ruko_male: "https://long-sleeper.net/index.php?id=22",
|
|
2431
2539
|
ruko_female: "https://long-sleeper.net/index.php?id=22",
|
|
2432
2540
|
teto: "https://kasaneteto.jp/guidelines/voice.html",
|
|
2433
|
-
shiyo: "https://kakumeisiyo.my.canva.site/dagkuyjwycs"
|
|
2541
|
+
shiyo: "https://kakumeisiyo.my.canva.site/dagkuyjwycs",
|
|
2542
|
+
rei: "https://mechanicalgirl.jp/guidelines/",
|
|
2543
|
+
MGRoid: "https://x.com/nisusansu/status/1048825378188353536",
|
|
2544
|
+
MOTRoid: "https://www.nicovideo.jp/watch/sm40031282"
|
|
2434
2545
|
};
|
|
2435
2546
|
var koeUrl = (name, base = KOE_BASE_URL) => `${base}/${encodeURIComponent(name)}`;
|
|
2436
2547
|
var DEFAULT_WORLDLINE_SCRIPT = "https://onjmin.github.io/koe/demo/world/worldline.js";
|
|
@@ -2797,6 +2908,16 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2797
2908
|
for (const m of models) if (m) set.add(m.toLowerCase());
|
|
2798
2909
|
await Promise.all([...set].map((m) => load2(m)));
|
|
2799
2910
|
};
|
|
2911
|
+
const registerVoicebanks = (banks) => {
|
|
2912
|
+
for (const [k, v] of Object.entries(banks)) {
|
|
2913
|
+
const key = k.toLowerCase();
|
|
2914
|
+
if (key === FALLBACK_MODEL) continue;
|
|
2915
|
+
if (catalog[key] === v) continue;
|
|
2916
|
+
catalog[key] = v;
|
|
2917
|
+
loaded.delete(key);
|
|
2918
|
+
loading.delete(key);
|
|
2919
|
+
}
|
|
2920
|
+
};
|
|
2800
2921
|
const forEachSungNote = (track, fn) => {
|
|
2801
2922
|
let prevVowel = "";
|
|
2802
2923
|
for (const note of track.notes) {
|
|
@@ -2903,7 +3024,14 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2903
3024
|
stopStream();
|
|
2904
3025
|
for (const v of loaded.values()) v.reset?.();
|
|
2905
3026
|
};
|
|
2906
|
-
return {
|
|
3027
|
+
return {
|
|
3028
|
+
loadModels,
|
|
3029
|
+
registerVoicebanks,
|
|
3030
|
+
warm,
|
|
3031
|
+
startStream,
|
|
3032
|
+
stopStream,
|
|
3033
|
+
reset
|
|
3034
|
+
};
|
|
2907
3035
|
};
|
|
2908
3036
|
var createVoiceRegistry = (models = {}, fallback = "klatt") => {
|
|
2909
3037
|
const sing = (model, syllable, e) => {
|
|
@@ -4357,7 +4485,8 @@ var parseMML = (mml, options = {}) => {
|
|
|
4357
4485
|
meta: {}
|
|
4358
4486
|
};
|
|
4359
4487
|
}
|
|
4360
|
-
const
|
|
4488
|
+
const noCustomVocals = stripCustomVocals(mml);
|
|
4489
|
+
const noComments = noCustomVocals.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
4361
4490
|
const meta = parseMmlMeta(noComments);
|
|
4362
4491
|
const noMeta = stripMmlMeta(noComments);
|
|
4363
4492
|
const lyrics = collectLyrics ? parseLyrics(noMeta) : void 0;
|
|
@@ -4370,6 +4499,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4370
4499
|
let octave = 4;
|
|
4371
4500
|
let currentStep = 0;
|
|
4372
4501
|
let baseLength = 16;
|
|
4502
|
+
let velocity = 100;
|
|
4373
4503
|
const contributors = /* @__PURE__ */ new Map();
|
|
4374
4504
|
const recordContributor = () => {
|
|
4375
4505
|
let set = contributors.get(trackIndex);
|
|
@@ -4390,6 +4520,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4390
4520
|
octave = 4;
|
|
4391
4521
|
currentStep = 0;
|
|
4392
4522
|
baseLength = 16;
|
|
4523
|
+
velocity = 100;
|
|
4393
4524
|
continue;
|
|
4394
4525
|
}
|
|
4395
4526
|
const body = part.replace(/\s+/g, "").toLowerCase();
|
|
@@ -4468,6 +4599,8 @@ var parseMML = (mml, options = {}) => {
|
|
|
4468
4599
|
if (bpm === null) {
|
|
4469
4600
|
bpm = clamp2(Number.parseInt(numStr, 10), 1, 255);
|
|
4470
4601
|
}
|
|
4602
|
+
} else if (ch === "v" && numStr) {
|
|
4603
|
+
velocity = clamp2(Number.parseInt(numStr, 10), 0, 127);
|
|
4471
4604
|
}
|
|
4472
4605
|
pushTok("ctrl", currentStep, 0, tokStart);
|
|
4473
4606
|
} else if (ch === "[") {
|
|
@@ -4513,7 +4646,8 @@ var parseMML = (mml, options = {}) => {
|
|
|
4513
4646
|
trackIndex,
|
|
4514
4647
|
startStep: currentStep,
|
|
4515
4648
|
pitch: p,
|
|
4516
|
-
durationSteps: Math.max(1, steps)
|
|
4649
|
+
durationSteps: Math.max(1, steps),
|
|
4650
|
+
velocity
|
|
4517
4651
|
});
|
|
4518
4652
|
}
|
|
4519
4653
|
pushTok("chord", currentStep, Math.max(1, steps), tokStart);
|
|
@@ -4536,7 +4670,8 @@ var parseMML = (mml, options = {}) => {
|
|
|
4536
4670
|
trackIndex,
|
|
4537
4671
|
startStep: currentStep,
|
|
4538
4672
|
pitch: midiPitch,
|
|
4539
|
-
durationSteps: Math.max(1, steps)
|
|
4673
|
+
durationSteps: Math.max(1, steps),
|
|
4674
|
+
velocity
|
|
4540
4675
|
});
|
|
4541
4676
|
pushTok("note", currentStep, Math.max(1, steps), tokStart);
|
|
4542
4677
|
currentStep += steps;
|
|
@@ -5696,6 +5831,7 @@ var DAW_CSS = `
|
|
|
5696
5831
|
height: 20px;
|
|
5697
5832
|
border-radius: 50%;
|
|
5698
5833
|
object-fit: cover;
|
|
5834
|
+
image-rendering: pixelated;
|
|
5699
5835
|
}
|
|
5700
5836
|
|
|
5701
5837
|
/* \u2500\u2500\u2500 \u5E83\u5E45\u62E1\u5F35 \u2500\u2500\u2500 */
|
|
@@ -6181,26 +6317,38 @@ var createSynth = (ctx, destination = ctx.destination) => {
|
|
|
6181
6317
|
return { playNote, playDrum };
|
|
6182
6318
|
};
|
|
6183
6319
|
|
|
6320
|
+
// assets/404Chip.png
|
|
6321
|
+
var Chip_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAcElEQVR42u2WOw7AIAxD7Yr7X9kdqi5IIXQKBWckKHrOTyEAodAuFJsBDGAAA7TIIT0LkuTQ/1r0L4u3XgZ6ZbNKsvf9mlBSqu5fU9DXMFP3teujeOtPQbYPZnplFK88A4xuwmM2IX0VG8AABjge4AZHeT8uyZjZYAAAAABJRU5ErkJggg==";
|
|
6322
|
+
|
|
6184
6323
|
// assets/puyuyu.png
|
|
6185
|
-
var puyuyu_default = "data:image/png;base64,
|
|
6324
|
+
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=";
|
|
6325
|
+
|
|
6326
|
+
// assets/rei.png
|
|
6327
|
+
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==";
|
|
6186
6328
|
|
|
6187
6329
|
// assets/rino.png
|
|
6188
|
-
var rino_default = "data:image/png;base64,
|
|
6330
|
+
var rino_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABvklEQVR42mNkIACC8yv/MzAwMKSF+jOQAmat3ojCXzuxnRGbOiaGAQaM1PY5oRBBD4kBDwEWdIGdR078p6YFesryeOUHTwjAfI7u4kt3HzLgEyfWp4M/BHD5zE1BhoGBgYFh+vZdDAwMDAzKauoo4jAAk8cFkHLTf+TcMPhC4O6tm6gCaD6Fy6OJZ7o5Q0Ji194hmgbQfZ6VFA+h0TRMm7cQtSiVkcFrwc4jJ4ZYLoD5/P9/SIEobGCNNa5hPsel7t3FY1hz06xBHwLoccxj5IhV4/8nT/CqWz61D4V/bNu2wZkGGNHrAlhu2HvxBgMDAwPDmtJssgze9eAJStyHdE8d5O0BdxsLRuSWEHrcWXl5EWUgzKdwQKBFNfjbhEXailjlTf79Q+GfYYL4pe/qfQYGBgaGU9dQW8WPd18bnK1ieBqQddVCiXtOyU8MDAwMDBGrJzAwMDAw2Duj5vNMIX2UtDF9STtUH1TBNVSL0M0fvCUhIYDu81ioz3EBWMhJv0KtFZdd/j5IQwDm4oN792PVAEsTDDAaTR86iNO6xMDAwMCwiMECa0gMnTSAK0RwySNC5BJKSCTv/T64QgAAipubBW9f1GUAAAAASUVORK5CYII=";
|
|
6189
6331
|
|
|
6190
6332
|
// assets/roze.png
|
|
6191
|
-
var roze_default = "data:image/png;base64,
|
|
6333
|
+
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==";
|
|
6192
6334
|
|
|
6193
6335
|
// assets/ruko.png
|
|
6194
|
-
var ruko_default = "data:image/png;base64,
|
|
6336
|
+
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==";
|
|
6195
6337
|
|
|
6196
6338
|
// assets/shiyo.png
|
|
6197
|
-
var shiyo_default = "data:image/png;base64,
|
|
6339
|
+
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==";
|
|
6198
6340
|
|
|
6199
6341
|
// assets/teto.png
|
|
6200
|
-
var teto_default = "data:image/png;base64,
|
|
6342
|
+
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=";
|
|
6201
6343
|
|
|
6202
6344
|
// assets/tsukuyomi.png
|
|
6203
|
-
var tsukuyomi_default = "data:image/png;base64,
|
|
6345
|
+
var tsukuyomi_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB3UlEQVR42tWXPUsDQRCGnwuijYIoFqKmEDSCxIgIgqnsogbsrC3ERiwN4g8Ikk6sFH+BnYofvcTKxoigBCzEYGGjWIiCOYvNBHe5TdQUt051czc3e++zO7tzHnUst7vn04BlFue9Ws8jhGxN9ZTPzU43NkIlj41E6AQ8m/JYfByAoWgXAPtHJzRCRN43SbizBkzlv1X2VzLuVoHYzf0TAMnys+aLCTGThMTJGnKfQOpyWF1cvgHQsh4FYPDzRd3vmQHgoPShJbi9uqhJyPk1UK3Jwsq1/115rLst8AX/4UFP0NsbGHf7+Kr579l7zR/ZGvbcrAJR7vvqEOwcTdZMYIuTPCYJUS7Ewydgzn2Bay2gdWzqR4nMuMPlhcC5l/HcWQOnCaU4lVU3xI9tnwFQnOgDoDmdDs5QKmlxYhdGmBA2ibhTBfKFHCkCm00dAKymJn+USAidHx8DkI+0q7PBUC7j5BJ7jlSB7RyXziVT8fM7Oz7AeLmsz3VEaWi7UvtAcmvJC+qmq4T/XT8gdTsw2692to07AF7jeU35wFq/7COqzhdVnVOnu3aHgNm1VpVXlImJX9zQffO5kDg1dlb3CNj6dZsVK2vAVP7Xf8bwCfxWuc23Eanmt/xlh07gC6oBviFE8rZHAAAAAElFTkSuQmCC";
|
|
6346
|
+
|
|
6347
|
+
// assets/MGRoid.png
|
|
6348
|
+
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";
|
|
6349
|
+
|
|
6350
|
+
// assets/MOTRoid.png
|
|
6351
|
+
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";
|
|
6204
6352
|
|
|
6205
6353
|
// src/voice-images.ts
|
|
6206
6354
|
var VOICE_IMAGES = {
|
|
@@ -6210,8 +6358,12 @@ var VOICE_IMAGES = {
|
|
|
6210
6358
|
ruko: ruko_default,
|
|
6211
6359
|
shiyo: shiyo_default,
|
|
6212
6360
|
teto: teto_default,
|
|
6213
|
-
tsukuyomi: tsukuyomi_default
|
|
6361
|
+
tsukuyomi: tsukuyomi_default,
|
|
6362
|
+
rei: rei_default,
|
|
6363
|
+
MGRoid: MGRoid_default,
|
|
6364
|
+
MOTRoid: MOTRoid_default
|
|
6214
6365
|
};
|
|
6366
|
+
var FALLBACK_VOCAL_ICON = Chip_default;
|
|
6215
6367
|
|
|
6216
6368
|
// src/mml-player.ts
|
|
6217
6369
|
var STEPS_PER_BEAT3 = 48;
|
|
@@ -6410,6 +6562,9 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6410
6562
|
collectLyrics: true
|
|
6411
6563
|
});
|
|
6412
6564
|
const lyricTracks = lyrics ?? /* @__PURE__ */ new Map();
|
|
6565
|
+
const customVocalByKey = new Map(
|
|
6566
|
+
parseCustomVocals(mml).map((d) => [d.key, d])
|
|
6567
|
+
);
|
|
6413
6568
|
const bpm = parsedBpm ?? options.defaultBpm ?? DEFAULT_BPM;
|
|
6414
6569
|
const drumPatternDict = options.drumPatterns ?? DRUM_PATTERNS;
|
|
6415
6570
|
const drumPattern = meta.drum ? drumPatternDict[meta.drum] ?? null : null;
|
|
@@ -6458,7 +6613,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6458
6613
|
startStep: p.startStep,
|
|
6459
6614
|
durationSteps: p.durationSteps,
|
|
6460
6615
|
pitch: p.pitch,
|
|
6461
|
-
velocity:
|
|
6616
|
+
velocity: p.velocity
|
|
6462
6617
|
}));
|
|
6463
6618
|
return { id: String(index), volume: trackVolume, notes };
|
|
6464
6619
|
});
|
|
@@ -6811,15 +6966,23 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6811
6966
|
for (const [index, lt] of lyricTracks) {
|
|
6812
6967
|
const em = emojiByTrack.get(index);
|
|
6813
6968
|
if (!em) continue;
|
|
6969
|
+
const custom = customVocalByKey.get(lt.model.toLowerCase());
|
|
6814
6970
|
const imgKey = VOICE_IMAGE_KEY[lt.model.toLowerCase()];
|
|
6815
|
-
const src = imgKey ? VOICE_IMAGES[imgKey] : void 0;
|
|
6971
|
+
const src = custom ? custom.iconUrl || FALLBACK_VOCAL_ICON : imgKey ? VOICE_IMAGES[imgKey] : void 0;
|
|
6816
6972
|
if (!src) continue;
|
|
6817
6973
|
const img = doc.createElement("img");
|
|
6818
6974
|
img.src = src;
|
|
6975
|
+
if (custom) {
|
|
6976
|
+
img.onerror = () => {
|
|
6977
|
+
img.onerror = null;
|
|
6978
|
+
img.src = FALLBACK_VOCAL_ICON;
|
|
6979
|
+
};
|
|
6980
|
+
}
|
|
6819
6981
|
img.width = 20;
|
|
6820
6982
|
img.height = 20;
|
|
6821
6983
|
img.style.borderRadius = "50%";
|
|
6822
6984
|
img.style.objectFit = "cover";
|
|
6985
|
+
img.style.imageRendering = "pixelated";
|
|
6823
6986
|
img.draggable = false;
|
|
6824
6987
|
promotedToImage.add(em);
|
|
6825
6988
|
em.textContent = "";
|
|
@@ -7254,6 +7417,13 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
7254
7417
|
}
|
|
7255
7418
|
});
|
|
7256
7419
|
try {
|
|
7420
|
+
if (customVocalByKey.size > 0) {
|
|
7421
|
+
v.registerVoicebanks?.(
|
|
7422
|
+
Object.fromEntries(
|
|
7423
|
+
[...customVocalByKey].map(([k, d]) => [k, d.url])
|
|
7424
|
+
)
|
|
7425
|
+
);
|
|
7426
|
+
}
|
|
7257
7427
|
await v.loadModels(tracks.map((t) => t.model));
|
|
7258
7428
|
if (skipSinging) return;
|
|
7259
7429
|
const startTime = performance.now();
|
|
@@ -7409,6 +7579,29 @@ var MIDI_INFO_HTML = `
|
|
|
7409
7579
|
<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>
|
|
7410
7580
|
</div>
|
|
7411
7581
|
`;
|
|
7582
|
+
var KOE_INFO_HTML = `
|
|
7583
|
+
<div class="dtm-modal-body-content">
|
|
7584
|
+
<h4>1. UTAU\u97F3\u6E90\u3092 .koe \u306B\u5909\u63DB\u3059\u308B</h4>
|
|
7585
|
+
<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>
|
|
7586
|
+
<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>
|
|
7587
|
+
|
|
7588
|
+
<h4>2. \u5909\u63DB\u3057\u305F .koe \u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3059\u308B</h4>
|
|
7589
|
+
<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>
|
|
7590
|
+
<ul>
|
|
7591
|
+
<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>
|
|
7592
|
+
<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>
|
|
7593
|
+
</ul>
|
|
7594
|
+
|
|
7595
|
+
<h4>3. DTM\u3067\u4F7F\u3046</h4>
|
|
7596
|
+
<ul>
|
|
7597
|
+
<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>
|
|
7598
|
+
<li>\u300C\u97F3\u6E90URL\u300D\u306B\u624B\u98062\u306E\u76F4\u63A5\u30EA\u30F3\u30AF\u3092\u8CBC\u308A\u4ED8\u3051\u307E\u3059\u3002</li>
|
|
7599
|
+
<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>
|
|
7600
|
+
<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>
|
|
7601
|
+
</ul>
|
|
7602
|
+
<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>
|
|
7603
|
+
</div>
|
|
7604
|
+
`;
|
|
7412
7605
|
var BASE_STEP_WIDTH = 0.5;
|
|
7413
7606
|
var BASE_KEY_HEIGHT = 15;
|
|
7414
7607
|
var TRACKS_SIMPLE = [
|
|
@@ -7549,12 +7742,14 @@ var TRACKS_ADVANCED = [
|
|
|
7549
7742
|
}
|
|
7550
7743
|
];
|
|
7551
7744
|
var DEFAULT_TRACKS = TRACKS_SIMPLE;
|
|
7552
|
-
var
|
|
7553
|
-
var
|
|
7745
|
+
var BASE_LYRIC_MODELS = ["klatt", ...Object.keys(KOE_VOICEBANKS)];
|
|
7746
|
+
var BASE_LYRIC_MODEL_LABELS = {
|
|
7554
7747
|
klatt: "\u8EFD\u91CF\u30ED\u30DC\u58F0",
|
|
7555
7748
|
...KOE_VOICEBANK_LABELS
|
|
7556
7749
|
};
|
|
7557
|
-
var lyricModelLabel = (model) =>
|
|
7750
|
+
var lyricModelLabel = (model, customMap) => BASE_LYRIC_MODEL_LABELS[model] ?? customMap.get(model)?.label ?? model;
|
|
7751
|
+
var CUSTOM_VOCAL_ADD_VALUE = "+custom";
|
|
7752
|
+
var CUSTOM_VOCAL_KEY_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
7558
7753
|
var clamp3 = (v, min, max) => Math.min(Math.max(v, min), max);
|
|
7559
7754
|
var normalizeInstrumentName = (name) => {
|
|
7560
7755
|
if (!name) return "";
|
|
@@ -7611,6 +7806,22 @@ var mountDAW = (target, options = {}) => {
|
|
|
7611
7806
|
let currentPlayStep = 0;
|
|
7612
7807
|
let ready = false;
|
|
7613
7808
|
let isLoading = false;
|
|
7809
|
+
const customVocalsMap = /* @__PURE__ */ new Map();
|
|
7810
|
+
const registerCustomVocal = (def) => {
|
|
7811
|
+
const key = def.key.toLowerCase();
|
|
7812
|
+
if (BASE_LYRIC_MODELS.includes(key)) return;
|
|
7813
|
+
customVocalsMap.set(key, { ...def, key });
|
|
7814
|
+
};
|
|
7815
|
+
const resetCustomVocals = () => {
|
|
7816
|
+
customVocalsMap.clear();
|
|
7817
|
+
for (const d of options.customVocals ?? []) registerCustomVocal(d);
|
|
7818
|
+
};
|
|
7819
|
+
resetCustomVocals();
|
|
7820
|
+
const genCustomVocalKey = () => {
|
|
7821
|
+
let n = 1;
|
|
7822
|
+
while (customVocalsMap.has(`custom${n}`)) n++;
|
|
7823
|
+
return `custom${n}`;
|
|
7824
|
+
};
|
|
7614
7825
|
let selectedNotes = [];
|
|
7615
7826
|
let selectionRect = null;
|
|
7616
7827
|
let copiedNotes = [];
|
|
@@ -8364,6 +8575,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
8364
8575
|
const overlay = showLoadingOverlay(refs.rollContainer);
|
|
8365
8576
|
setLoading(true);
|
|
8366
8577
|
try {
|
|
8578
|
+
if (customVocalsMap.size > 0) {
|
|
8579
|
+
voices.registerVoicebanks?.(
|
|
8580
|
+
Object.fromEntries(
|
|
8581
|
+
[...customVocalsMap].map(([k, d]) => [k, d.url])
|
|
8582
|
+
)
|
|
8583
|
+
);
|
|
8584
|
+
}
|
|
8367
8585
|
await voices.loadModels(streamTracks.map((t) => t.model));
|
|
8368
8586
|
await voices.warm(streamTracks);
|
|
8369
8587
|
} catch (err2) {
|
|
@@ -8528,6 +8746,20 @@ var mountDAW = (target, options = {}) => {
|
|
|
8528
8746
|
<a data-dtm="lyric-terms-link" target="_blank" rel="noopener" style="color:var(--dtm-primary);text-decoration:underline"></a>
|
|
8529
8747
|
<span>\u306E\u5229\u7528\u898F\u7D04\u306B\u5F93\u3063\u3066\u304F\u3060\u3055\u3044</span>
|
|
8530
8748
|
</div>
|
|
8749
|
+
<div class="dtm-row dtm-hidden" data-dtm="lyric-custom" style="flex-direction:column;align-items:stretch;gap:4px">
|
|
8750
|
+
<div class="dtm-row" style="justify-content: space-between; align-items: center;">
|
|
8751
|
+
<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>
|
|
8752
|
+
<button class="dtm-btn dtm-btn--ghost dtm-btn--xs" data-dtm="lyric-custom-guide">\u4F7F\u3044\u65B9\u30AC\u30A4\u30C9</button>
|
|
8753
|
+
</div>
|
|
8754
|
+
<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">
|
|
8755
|
+
<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">
|
|
8756
|
+
<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">
|
|
8757
|
+
<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">
|
|
8758
|
+
<div class="dtm-row">
|
|
8759
|
+
<span class="dtm-label dtm-grow" data-dtm="lyric-custom-note" style="color:var(--dtm-warn)"></span>
|
|
8760
|
+
<button class="dtm-btn dtm-btn--primary" data-dtm="lyric-custom-apply">\u8FFD\u52A0</button>
|
|
8761
|
+
</div>
|
|
8762
|
+
</div>
|
|
8531
8763
|
<div class="dtm-row" data-dtm="lyric-body" style="flex-direction:column;align-items:stretch">
|
|
8532
8764
|
<div class="dtm-row">
|
|
8533
8765
|
<span class="dtm-label">\u58F0\u91CF</span>
|
|
@@ -8578,6 +8810,30 @@ var mountDAW = (target, options = {}) => {
|
|
|
8578
8810
|
const lyricTermsLink = lyricDiv.querySelector(
|
|
8579
8811
|
'[data-dtm="lyric-terms-link"]'
|
|
8580
8812
|
);
|
|
8813
|
+
const lyricCustom = lyricDiv.querySelector(
|
|
8814
|
+
'[data-dtm="lyric-custom"]'
|
|
8815
|
+
);
|
|
8816
|
+
const lyricCustomSrc = lyricDiv.querySelector(
|
|
8817
|
+
'[data-dtm="lyric-custom-src"]'
|
|
8818
|
+
);
|
|
8819
|
+
const lyricCustomIcon = lyricDiv.querySelector(
|
|
8820
|
+
'[data-dtm="lyric-custom-icon"]'
|
|
8821
|
+
);
|
|
8822
|
+
const lyricCustomAlias = lyricDiv.querySelector(
|
|
8823
|
+
'[data-dtm="lyric-custom-alias"]'
|
|
8824
|
+
);
|
|
8825
|
+
const lyricCustomKey = lyricDiv.querySelector(
|
|
8826
|
+
'[data-dtm="lyric-custom-key"]'
|
|
8827
|
+
);
|
|
8828
|
+
const lyricCustomGuide = lyricDiv.querySelector(
|
|
8829
|
+
'[data-dtm="lyric-custom-guide"]'
|
|
8830
|
+
);
|
|
8831
|
+
const lyricCustomNote = lyricDiv.querySelector(
|
|
8832
|
+
'[data-dtm="lyric-custom-note"]'
|
|
8833
|
+
);
|
|
8834
|
+
const lyricCustomApply = lyricDiv.querySelector(
|
|
8835
|
+
'[data-dtm="lyric-custom-apply"]'
|
|
8836
|
+
);
|
|
8581
8837
|
const fmtPan = (pan) => pan === 64 ? "C" : pan < 64 ? `L${64 - pan}` : `R${pan - 64}`;
|
|
8582
8838
|
const addOpt = (value, label) => {
|
|
8583
8839
|
const o = document.createElement("option");
|
|
@@ -8586,9 +8842,15 @@ var mountDAW = (target, options = {}) => {
|
|
|
8586
8842
|
lyricModelSel.appendChild(o);
|
|
8587
8843
|
};
|
|
8588
8844
|
addOpt("", "\u30DC\u30FC\u30AB\u30EB\u306A\u3057");
|
|
8589
|
-
for (const m of
|
|
8590
|
-
|
|
8591
|
-
|
|
8845
|
+
for (const m of BASE_LYRIC_MODELS)
|
|
8846
|
+
addOpt(m, lyricModelLabel(m, customVocalsMap));
|
|
8847
|
+
for (const [k, def] of customVocalsMap) addOpt(k, def.label ?? k);
|
|
8848
|
+
addOpt(CUSTOM_VOCAL_ADD_VALUE, "\u30AB\u30B9\u30BF\u30E0\u97F3\u6E90\u3092\u8FFD\u52A0\u2026");
|
|
8849
|
+
if (active.lyricModel && !BASE_LYRIC_MODELS.includes(active.lyricModel) && !customVocalsMap.has(active.lyricModel)) {
|
|
8850
|
+
addOpt(
|
|
8851
|
+
active.lyricModel,
|
|
8852
|
+
lyricModelLabel(active.lyricModel, customVocalsMap)
|
|
8853
|
+
);
|
|
8592
8854
|
}
|
|
8593
8855
|
lyricModelSel.value = active.lyricModel;
|
|
8594
8856
|
lyricOctaveSel.value = String(active.vocalOctave);
|
|
@@ -8602,9 +8864,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
8602
8864
|
lyricCount.textContent = active.lyricModel && n > 0 ? `${n}\u97F3\u7BC0` : "";
|
|
8603
8865
|
};
|
|
8604
8866
|
const syncLyricTerms = () => {
|
|
8867
|
+
if (customVocalsMap.has(active.lyricModel)) {
|
|
8868
|
+
lyricTerms.classList.add("dtm-hidden");
|
|
8869
|
+
return;
|
|
8870
|
+
}
|
|
8605
8871
|
const url2 = active.lyricModel ? KOE_VOICEBANK_TERMS[active.lyricModel] : void 0;
|
|
8606
8872
|
if (url2) {
|
|
8607
|
-
const label = lyricModelLabel(active.lyricModel);
|
|
8873
|
+
const label = lyricModelLabel(active.lyricModel, customVocalsMap);
|
|
8608
8874
|
lyricTermsLink.textContent = `${label}UTAU\u97F3\u6E90`;
|
|
8609
8875
|
lyricTermsLink.href = url2;
|
|
8610
8876
|
lyricTerms.classList.remove("dtm-hidden");
|
|
@@ -8613,7 +8879,24 @@ var mountDAW = (target, options = {}) => {
|
|
|
8613
8879
|
}
|
|
8614
8880
|
};
|
|
8615
8881
|
const syncLyricIcon = () => {
|
|
8616
|
-
|
|
8882
|
+
if (!active.lyricModel) {
|
|
8883
|
+
lyricIcon.removeAttribute("src");
|
|
8884
|
+
lyricIcon.classList.add("dtm-hidden");
|
|
8885
|
+
return;
|
|
8886
|
+
}
|
|
8887
|
+
const customDef = customVocalsMap.get(active.lyricModel);
|
|
8888
|
+
if (customDef !== void 0) {
|
|
8889
|
+
const iconSrc = customDef.iconUrl || FALLBACK_VOCAL_ICON;
|
|
8890
|
+
lyricIcon.src = iconSrc;
|
|
8891
|
+
lyricIcon.classList.remove("dtm-hidden");
|
|
8892
|
+
lyricIcon.onerror = () => {
|
|
8893
|
+
lyricIcon.onerror = null;
|
|
8894
|
+
lyricIcon.src = FALLBACK_VOCAL_ICON;
|
|
8895
|
+
};
|
|
8896
|
+
return;
|
|
8897
|
+
}
|
|
8898
|
+
lyricIcon.onerror = null;
|
|
8899
|
+
const imgKey = VOICE_IMAGE_KEY[active.lyricModel.toLowerCase()];
|
|
8617
8900
|
const src = imgKey ? VOICE_IMAGES[imgKey] : void 0;
|
|
8618
8901
|
if (src) {
|
|
8619
8902
|
lyricIcon.src = src;
|
|
@@ -8632,11 +8915,64 @@ var mountDAW = (target, options = {}) => {
|
|
|
8632
8915
|
};
|
|
8633
8916
|
syncLyricVisibility();
|
|
8634
8917
|
lyricModelSel.addEventListener("change", () => {
|
|
8918
|
+
if (lyricModelSel.value === CUSTOM_VOCAL_ADD_VALUE) {
|
|
8919
|
+
lyricCustomNote.textContent = "";
|
|
8920
|
+
lyricCustomAlias.value = "";
|
|
8921
|
+
lyricCustomKey.value = "";
|
|
8922
|
+
lyricCustom.classList.remove("dtm-hidden");
|
|
8923
|
+
return;
|
|
8924
|
+
}
|
|
8925
|
+
lyricCustom.classList.add("dtm-hidden");
|
|
8635
8926
|
active.lyricModel = lyricModelSel.value;
|
|
8636
8927
|
syncLyricVisibility();
|
|
8637
8928
|
syncInstDisabled();
|
|
8638
8929
|
fireLyricsChange(active);
|
|
8639
8930
|
});
|
|
8931
|
+
lyricCustomGuide.addEventListener("click", () => {
|
|
8932
|
+
showModal("\u30AB\u30B9\u30BF\u30E0\u97F3\u6E90(.koe)\u306E\u4F7F\u3044\u65B9", KOE_INFO_HTML);
|
|
8933
|
+
});
|
|
8934
|
+
lyricCustomApply.addEventListener("click", () => {
|
|
8935
|
+
const src = lyricCustomSrc.value.trim();
|
|
8936
|
+
if (!isValidHttpUrl(src)) {
|
|
8937
|
+
lyricCustomNote.textContent = "\u97F3\u6E90URL\u304C\u4E0D\u6B63\u3067\u3059\uFF08http/https\u306E\u307F\u30FB2048\u6587\u5B57\u307E\u3067\uFF09";
|
|
8938
|
+
return;
|
|
8939
|
+
}
|
|
8940
|
+
const iconRaw = lyricCustomIcon.value.trim();
|
|
8941
|
+
const iconUrl = isValidHttpUrl(iconRaw) ? iconRaw : "";
|
|
8942
|
+
const alias = lyricCustomAlias.value.trim();
|
|
8943
|
+
const existing = [...customVocalsMap.values()].find(
|
|
8944
|
+
(d) => d.url === src
|
|
8945
|
+
);
|
|
8946
|
+
const keyRaw = lyricCustomKey.value.trim().toLowerCase();
|
|
8947
|
+
let key;
|
|
8948
|
+
if (keyRaw) {
|
|
8949
|
+
if (!CUSTOM_VOCAL_KEY_RE.test(keyRaw)) {
|
|
8950
|
+
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";
|
|
8951
|
+
return;
|
|
8952
|
+
}
|
|
8953
|
+
if (BASE_LYRIC_MODELS.includes(keyRaw)) {
|
|
8954
|
+
lyricCustomNote.textContent = "\u305D\u306E\u8B58\u5225\u5B50\u306F\u5185\u8535\u30E2\u30C7\u30EB\u540D\u3068\u885D\u7A81\u3057\u3066\u3044\u307E\u3059";
|
|
8955
|
+
return;
|
|
8956
|
+
}
|
|
8957
|
+
const conflict = customVocalsMap.get(keyRaw);
|
|
8958
|
+
if (conflict && conflict.url !== src) {
|
|
8959
|
+
lyricCustomNote.textContent = "\u305D\u306E\u8B58\u5225\u5B50\u306F\u5225\u306E\u97F3\u6E90\u306B\u4F7F\u7528\u6E08\u307F\u3067\u3059";
|
|
8960
|
+
return;
|
|
8961
|
+
}
|
|
8962
|
+
key = keyRaw;
|
|
8963
|
+
} else {
|
|
8964
|
+
key = existing?.key ?? genCustomVocalKey();
|
|
8965
|
+
}
|
|
8966
|
+
registerCustomVocal({
|
|
8967
|
+
key,
|
|
8968
|
+
iconUrl: iconUrl || (existing?.iconUrl ?? ""),
|
|
8969
|
+
url: src,
|
|
8970
|
+
label: alias || existing?.label
|
|
8971
|
+
});
|
|
8972
|
+
active.lyricModel = key;
|
|
8973
|
+
fireLyricsChange(active);
|
|
8974
|
+
updateTrackPanel();
|
|
8975
|
+
});
|
|
8640
8976
|
lyricOctaveSel.addEventListener("change", () => {
|
|
8641
8977
|
active.vocalOctave = Number.parseInt(lyricOctaveSel.value, 10);
|
|
8642
8978
|
fireLyricsChange(active);
|
|
@@ -8820,9 +9156,25 @@ var mountDAW = (target, options = {}) => {
|
|
|
8820
9156
|
const head = params ? `${x.model} ${params}` : x.model;
|
|
8821
9157
|
return `@@${x.i} ${head} ${x.text}`;
|
|
8822
9158
|
});
|
|
8823
|
-
const
|
|
9159
|
+
const customVocalDecls = [];
|
|
9160
|
+
for (const [key, def] of customVocalsMap) {
|
|
9161
|
+
const isUsed = trackStates.some(
|
|
9162
|
+
(t) => t.lyricModel.trim().toLowerCase() === key && t.lyrics.trim().length > 0 && clipNotes(t.core.getNotes()).length > 0
|
|
9163
|
+
);
|
|
9164
|
+
if (!isUsed) continue;
|
|
9165
|
+
const iconPart = def.iconUrl || "-";
|
|
9166
|
+
customVocalDecls.push(`@@${key} ${iconPart} ${def.url}`);
|
|
9167
|
+
}
|
|
9168
|
+
const full = [
|
|
9169
|
+
metaLineFull,
|
|
9170
|
+
...customVocalDecls,
|
|
9171
|
+
...trackLines,
|
|
9172
|
+
...lyricLines,
|
|
9173
|
+
MML_END_MARKER
|
|
9174
|
+
].filter((s) => s.length > 0).join(";\n");
|
|
8824
9175
|
const minified = [
|
|
8825
9176
|
metaLineMini,
|
|
9177
|
+
...customVocalDecls,
|
|
8826
9178
|
...trackLinesMini,
|
|
8827
9179
|
...lyricLines,
|
|
8828
9180
|
MML_END_MARKER
|
|
@@ -8887,6 +9239,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
8887
9239
|
stop();
|
|
8888
9240
|
clearAll();
|
|
8889
9241
|
for (const t of trackStates) t.core.setLoadMode(true);
|
|
9242
|
+
resetCustomVocals();
|
|
9243
|
+
for (const def of parseCustomVocals(mml)) registerCustomVocal(def);
|
|
8890
9244
|
const {
|
|
8891
9245
|
placements,
|
|
8892
9246
|
bpm: parsedBpm,
|
|
@@ -8947,7 +9301,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
8947
9301
|
const t = trackStates[p.trackIndex];
|
|
8948
9302
|
if (!t) continue;
|
|
8949
9303
|
t.core.addNote(p.startStep, p.pitch, {
|
|
8950
|
-
noteLengthSteps: p.durationSteps
|
|
9304
|
+
noteLengthSteps: p.durationSteps,
|
|
9305
|
+
velocity: p.velocity
|
|
8951
9306
|
});
|
|
8952
9307
|
}
|
|
8953
9308
|
if (parsedBpm) setBpm(parsedBpm);
|
|
@@ -9683,7 +10038,7 @@ var playMML = (mml, options = {}) => {
|
|
|
9683
10038
|
startStep: p.startStep,
|
|
9684
10039
|
durationSteps: p.durationSteps,
|
|
9685
10040
|
pitch: p.pitch,
|
|
9686
|
-
velocity:
|
|
10041
|
+
velocity: p.velocity
|
|
9687
10042
|
}));
|
|
9688
10043
|
return { id: String(index), volume: masterVolume, notes };
|
|
9689
10044
|
});
|
|
@@ -10245,6 +10600,9 @@ var SoundFont = class _SoundFont {
|
|
|
10245
10600
|
this.ch = ch;
|
|
10246
10601
|
this.isDrum = isDrum;
|
|
10247
10602
|
}
|
|
10603
|
+
zones;
|
|
10604
|
+
ch;
|
|
10605
|
+
isDrum;
|
|
10248
10606
|
static afterTime = 0.5;
|
|
10249
10607
|
static fonts = /* @__PURE__ */ new Map();
|
|
10250
10608
|
static ch = -1;
|
|
@@ -11209,12 +11567,14 @@ export {
|
|
|
11209
11567
|
init,
|
|
11210
11568
|
injectStyles,
|
|
11211
11569
|
isChordHeavyTrack,
|
|
11570
|
+
isValidHttpUrl,
|
|
11212
11571
|
koeUrl,
|
|
11213
11572
|
mountDAW,
|
|
11214
11573
|
mountMmlPlayer,
|
|
11215
11574
|
normalizeLyrics,
|
|
11216
11575
|
onClick,
|
|
11217
11576
|
panToStereo,
|
|
11577
|
+
parseCustomVocals,
|
|
11218
11578
|
parseLyrics,
|
|
11219
11579
|
parseMML,
|
|
11220
11580
|
parseMmlMeta,
|
|
@@ -11223,6 +11583,7 @@ export {
|
|
|
11223
11583
|
setDrawOffset,
|
|
11224
11584
|
shiftNotes,
|
|
11225
11585
|
showLoadingOverlay,
|
|
11586
|
+
stripCustomVocals,
|
|
11226
11587
|
stripLyrics,
|
|
11227
11588
|
stripMmlMeta,
|
|
11228
11589
|
vocalVolumeToGain
|