@onjmin/dtm 0.1.90 → 0.1.92
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 +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +169 -13
- package/dist/index.mjs +169 -13
- package/dist/voice-worker.js +77 -4
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2154,6 +2154,15 @@ var vibratoPitchCurve = (baseHz, preMs) => (tMs) => {
|
|
|
2154
2154
|
return baseHz * 2 ** (cents / 1200);
|
|
2155
2155
|
};
|
|
2156
2156
|
|
|
2157
|
+
// src/voice-worker-types.ts
|
|
2158
|
+
var COMPOSITE_ALIAS_SEP = "\0";
|
|
2159
|
+
var packCompositeAlias = (consonantAlias, vowelAlias) => `${COMPOSITE_ALIAS_SEP}${consonantAlias}${COMPOSITE_ALIAS_SEP}${vowelAlias}`;
|
|
2160
|
+
var unpackCompositeAlias = (alias) => {
|
|
2161
|
+
if (!alias.startsWith(COMPOSITE_ALIAS_SEP)) return null;
|
|
2162
|
+
const parts = alias.slice(COMPOSITE_ALIAS_SEP.length).split(COMPOSITE_ALIAS_SEP);
|
|
2163
|
+
return parts.length === 2 ? [parts[0], parts[1]] : null;
|
|
2164
|
+
};
|
|
2165
|
+
|
|
2157
2166
|
// src/lyrics.ts
|
|
2158
2167
|
var kanaTable = {
|
|
2159
2168
|
\u3042: ["", "a"],
|
|
@@ -2332,9 +2341,10 @@ var parseLyrics = (mml) => {
|
|
|
2332
2341
|
let delay = 0;
|
|
2333
2342
|
let gender = 50;
|
|
2334
2343
|
let breathiness = 50;
|
|
2344
|
+
let tension = 50;
|
|
2335
2345
|
let octaveUnison = "none";
|
|
2336
2346
|
const modelMatch = rest.match(
|
|
2337
|
-
/^([a-z_][a-z0-9_]*?)(?=(?:[
|
|
2347
|
+
/^([a-z_][a-z0-9_]*?)(?=(?:[vqpobrghewt]-?\d)|[^a-z0-9_]|$)(?::(\d+))?/i
|
|
2338
2348
|
);
|
|
2339
2349
|
let model = "";
|
|
2340
2350
|
const metaTokens = [];
|
|
@@ -2403,6 +2413,13 @@ var parseLyrics = (mml) => {
|
|
|
2403
2413
|
rest = rest.substring(hMatch[0].length).trim();
|
|
2404
2414
|
continue;
|
|
2405
2415
|
}
|
|
2416
|
+
const tMatch = rest.match(/^t(\d+)/i);
|
|
2417
|
+
if (tMatch) {
|
|
2418
|
+
tension = clamp2(Number.parseInt(tMatch[1], 10), 0, 100);
|
|
2419
|
+
metaTokens.push(tMatch[0]);
|
|
2420
|
+
rest = rest.substring(tMatch[0].length).trim();
|
|
2421
|
+
continue;
|
|
2422
|
+
}
|
|
2406
2423
|
const eMatch = rest.match(/^e(\d+)/i);
|
|
2407
2424
|
if (eMatch) {
|
|
2408
2425
|
delay = clamp2(Number.parseInt(eMatch[1], 10), 0, 100);
|
|
@@ -2436,6 +2453,7 @@ var parseLyrics = (mml) => {
|
|
|
2436
2453
|
delay,
|
|
2437
2454
|
gender,
|
|
2438
2455
|
breathiness,
|
|
2456
|
+
tension,
|
|
2439
2457
|
octaveUnison,
|
|
2440
2458
|
syllables,
|
|
2441
2459
|
metaText: metaTokens.join(" "),
|
|
@@ -2757,8 +2775,33 @@ var resolveKoeAlias = (hasAlias, pitchTokens, syl, prevVowel, noteNum) => {
|
|
|
2757
2775
|
const hit = tryAlias(base);
|
|
2758
2776
|
if (hit) return hit;
|
|
2759
2777
|
}
|
|
2778
|
+
if (cons && vow) {
|
|
2779
|
+
const vowelAlias = tryAlias(vow) ?? tryAlias(`${pv} ${vow}`);
|
|
2780
|
+
const consAlias = vowelAlias ? tryAlias(cons) : null;
|
|
2781
|
+
if (vowelAlias && consAlias)
|
|
2782
|
+
return packCompositeAlias(consAlias, vowelAlias);
|
|
2783
|
+
}
|
|
2760
2784
|
return null;
|
|
2761
2785
|
};
|
|
2786
|
+
var COMPOSITE_SPLICE_XFADE_SEC = 5e-3;
|
|
2787
|
+
var spliceCompositePcm = (consonantPcm, vowelPcm, sampleRate) => {
|
|
2788
|
+
if (consonantPcm.length === 0 || vowelPcm.length === 0) return null;
|
|
2789
|
+
const xfade = Math.min(
|
|
2790
|
+
Math.floor(sampleRate * COMPOSITE_SPLICE_XFADE_SEC),
|
|
2791
|
+
consonantPcm.length,
|
|
2792
|
+
vowelPcm.length
|
|
2793
|
+
);
|
|
2794
|
+
const pcm = new Float64Array(consonantPcm.length + vowelPcm.length - xfade);
|
|
2795
|
+
pcm.set(consonantPcm, 0);
|
|
2796
|
+
for (let i2 = 0; i2 < xfade; i2++) {
|
|
2797
|
+
const t = (i2 + 1) / (xfade + 1);
|
|
2798
|
+
const idx = consonantPcm.length - xfade + i2;
|
|
2799
|
+
pcm[idx] = consonantPcm[idx] * (1 - t) + vowelPcm[i2] * t;
|
|
2800
|
+
}
|
|
2801
|
+
pcm.set(vowelPcm.subarray(xfade), consonantPcm.length);
|
|
2802
|
+
const consonantMs = (consonantPcm.length - xfade / 2) / sampleRate * 1e3;
|
|
2803
|
+
return { pcm, preMs: consonantMs, consonantMs };
|
|
2804
|
+
};
|
|
2762
2805
|
var createLocalBackend = async (options) => {
|
|
2763
2806
|
const bank = await VoiceBank.load(options.koe);
|
|
2764
2807
|
const worldline = options.lightweight ? null : await Worldline.load({
|
|
@@ -2773,7 +2816,40 @@ var createLocalBackend = async (options) => {
|
|
|
2773
2816
|
}
|
|
2774
2817
|
return p;
|
|
2775
2818
|
};
|
|
2819
|
+
const renderComposite = async (consonantAlias, vowelAlias, pitch, durationMs, vibrato, expr) => {
|
|
2820
|
+
if (!worldline) return null;
|
|
2821
|
+
const [consonantPcm, vowelPcm] = await Promise.all([
|
|
2822
|
+
getPcm(consonantAlias),
|
|
2823
|
+
getPcm(vowelAlias)
|
|
2824
|
+
]);
|
|
2825
|
+
if (!consonantPcm || !vowelPcm) return null;
|
|
2826
|
+
const spliced = spliceCompositePcm(consonantPcm, vowelPcm, KOE_SAMPLE_RATE);
|
|
2827
|
+
if (!spliced) return null;
|
|
2828
|
+
const targetHz = midiToFreq(pitch);
|
|
2829
|
+
const audio = worldline.renderNote({
|
|
2830
|
+
pcm: spliced.pcm,
|
|
2831
|
+
pitch: vibrato ? vibratoPitchCurve(targetHz, spliced.preMs) : targetHz,
|
|
2832
|
+
durationMs,
|
|
2833
|
+
preMs: spliced.preMs,
|
|
2834
|
+
consonantMs: spliced.consonantMs,
|
|
2835
|
+
gender: expr?.gender,
|
|
2836
|
+
breathiness: expr?.breathiness,
|
|
2837
|
+
tension: expr?.tension
|
|
2838
|
+
});
|
|
2839
|
+
return audio ? { pcm: audio, preSec: spliced.preMs / 1e3, rate: 1 } : null;
|
|
2840
|
+
};
|
|
2776
2841
|
const renderAlias = async (alias, pitch, durationMs, vibrato, expr) => {
|
|
2842
|
+
const composite = unpackCompositeAlias(alias);
|
|
2843
|
+
if (composite) {
|
|
2844
|
+
return renderComposite(
|
|
2845
|
+
composite[0],
|
|
2846
|
+
composite[1],
|
|
2847
|
+
pitch,
|
|
2848
|
+
durationMs,
|
|
2849
|
+
vibrato,
|
|
2850
|
+
expr
|
|
2851
|
+
);
|
|
2852
|
+
}
|
|
2777
2853
|
const pcm = await getPcm(alias);
|
|
2778
2854
|
if (!pcm || pcm.length === 0) return null;
|
|
2779
2855
|
const entry = bank.manifest.phonemes[alias];
|
|
@@ -2786,7 +2862,8 @@ var createLocalBackend = async (options) => {
|
|
|
2786
2862
|
durationMs,
|
|
2787
2863
|
...lead,
|
|
2788
2864
|
gender: expr?.gender,
|
|
2789
|
-
breathiness: expr?.breathiness
|
|
2865
|
+
breathiness: expr?.breathiness,
|
|
2866
|
+
tension: expr?.tension
|
|
2790
2867
|
});
|
|
2791
2868
|
if (audio) return { pcm: audio, preSec: lead.preMs / 1e3, rate: 1 };
|
|
2792
2869
|
}
|
|
@@ -2867,7 +2944,8 @@ var createWorkerBackend = async (workerUrl, options) => {
|
|
|
2867
2944
|
durationMs,
|
|
2868
2945
|
vibrato,
|
|
2869
2946
|
gender: expr?.gender,
|
|
2870
|
-
breathiness: expr?.breathiness
|
|
2947
|
+
breathiness: expr?.breathiness,
|
|
2948
|
+
tension: expr?.tension
|
|
2871
2949
|
});
|
|
2872
2950
|
});
|
|
2873
2951
|
return {
|
|
@@ -2896,7 +2974,7 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2896
2974
|
const inflight = /* @__PURE__ */ new Map();
|
|
2897
2975
|
const active = /* @__PURE__ */ new Set();
|
|
2898
2976
|
let prevVowel = "";
|
|
2899
|
-
const keyOf = (alias, pitch, durationMs, vibrato, expr) => `${alias}|${pitch}|${Math.round(durationMs / 10) * 10}${vibrato ? "|vib" : ""}${expr?.gender !== void 0 ? `|g${Math.round(expr.gender * 100)}` : ""}${expr?.breathiness !== void 0 ? `|h${Math.round(expr.breathiness * 100)}` : ""}`;
|
|
2977
|
+
const keyOf = (alias, pitch, durationMs, vibrato, expr) => `${alias}|${pitch}|${Math.round(durationMs / 10) * 10}${vibrato ? "|vib" : ""}${expr?.gender !== void 0 ? `|g${Math.round(expr.gender * 100)}` : ""}${expr?.breathiness !== void 0 ? `|h${Math.round(expr.breathiness * 100)}` : ""}${expr?.tension !== void 0 ? `|t${Math.round(expr.tension * 100)}` : ""}`;
|
|
2900
2978
|
const renderInto = (alias, pitch, durationMs, vibrato, expr) => {
|
|
2901
2979
|
const key = keyOf(alias, pitch, durationMs, vibrato, expr);
|
|
2902
2980
|
const existing = renderCache.get(key);
|
|
@@ -3127,7 +3205,8 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
3127
3205
|
let n = 0;
|
|
3128
3206
|
const expr = {
|
|
3129
3207
|
gender: track.gender,
|
|
3130
|
-
breathiness: track.breathiness
|
|
3208
|
+
breathiness: track.breathiness,
|
|
3209
|
+
tension: track.tension
|
|
3131
3210
|
};
|
|
3132
3211
|
forEachSungNote(track, (note, prevVowel) => {
|
|
3133
3212
|
if (n >= count && note.startSec >= STREAM_LOOKAHEAD_SEC) return;
|
|
@@ -3214,7 +3293,11 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
3214
3293
|
pitch,
|
|
3215
3294
|
note.durationSec * 1e3,
|
|
3216
3295
|
track.vibrato,
|
|
3217
|
-
{
|
|
3296
|
+
{
|
|
3297
|
+
gender: track.gender,
|
|
3298
|
+
breathiness: track.breathiness,
|
|
3299
|
+
tension: track.tension
|
|
3300
|
+
}
|
|
3218
3301
|
);
|
|
3219
3302
|
if (session !== streamSession) return;
|
|
3220
3303
|
if (key) {
|
|
@@ -7905,14 +7988,33 @@ var DAW_CSS = `
|
|
|
7905
7988
|
border-right: 2px solid var(--c-black);
|
|
7906
7989
|
border-bottom: 2px solid var(--c-black);
|
|
7907
7990
|
}
|
|
7991
|
+
/* \u30A2\u30A4\u30B3\u30F3\u304C\u753B\u9762\u4E0A\u7AEF\u306B\u8FD1\u304F\u4E0A\u306B\u51FA\u3059\u4F59\u767D\u304C\u7121\u3044\u5834\u5408\u306F\u4E0B\u306B\u53CD\u8EE2\u8868\u793A\u3059\u308B\uFF08positionBalloon \u304C\u4ED8\u4E0E\uFF09 */
|
|
7992
|
+
.dtm-player-balloon--below {
|
|
7993
|
+
transform: translate(-50%, 0);
|
|
7994
|
+
}
|
|
7995
|
+
.dtm-player-balloon--below::after {
|
|
7996
|
+
bottom: auto;
|
|
7997
|
+
top: -6px;
|
|
7998
|
+
border-right: none;
|
|
7999
|
+
border-bottom: none;
|
|
8000
|
+
border-left: 2px solid var(--c-black);
|
|
8001
|
+
border-top: 2px solid var(--c-black);
|
|
8002
|
+
}
|
|
7908
8003
|
.dtm-player-balloon--visible {
|
|
7909
8004
|
display: block;
|
|
7910
8005
|
animation: dtm-balloon-fade-in 0.1s steps(2);
|
|
7911
8006
|
}
|
|
8007
|
+
.dtm-player-balloon--below.dtm-player-balloon--visible {
|
|
8008
|
+
animation-name: dtm-balloon-fade-in-below;
|
|
8009
|
+
}
|
|
7912
8010
|
@keyframes dtm-balloon-fade-in {
|
|
7913
8011
|
from { opacity: 0; transform: translate(-50%, -100%) translateY(4px); }
|
|
7914
8012
|
to { opacity: 1; transform: translate(-50%, -100%) translateY(0); }
|
|
7915
8013
|
}
|
|
8014
|
+
@keyframes dtm-balloon-fade-in-below {
|
|
8015
|
+
from { opacity: 0; transform: translate(-50%, 0) translateY(-4px); }
|
|
8016
|
+
to { opacity: 1; transform: translate(-50%, 0) translateY(0); }
|
|
8017
|
+
}
|
|
7916
8018
|
@keyframes dtm-emoji-jump {
|
|
7917
8019
|
0% { transform: translateY(0); }
|
|
7918
8020
|
35% { transform: translateY(-5px); }
|
|
@@ -8338,9 +8440,17 @@ var balloonAnchors = /* @__PURE__ */ new WeakMap();
|
|
|
8338
8440
|
var positionBalloon = (balloonEl) => {
|
|
8339
8441
|
const anchor = balloonAnchors.get(balloonEl);
|
|
8340
8442
|
if (!anchor) return;
|
|
8443
|
+
const win = balloonEl.ownerDocument?.defaultView ?? window;
|
|
8341
8444
|
const rect = anchor.getBoundingClientRect();
|
|
8342
|
-
|
|
8343
|
-
|
|
8445
|
+
const centerX = rect.left + rect.width / 2;
|
|
8446
|
+
const balloonRect = balloonEl.getBoundingClientRect();
|
|
8447
|
+
const showBelow = rect.top - balloonRect.height - 6 < 0;
|
|
8448
|
+
balloonEl.classList.toggle("dtm-player-balloon--below", showBelow);
|
|
8449
|
+
balloonEl.style.top = showBelow ? `${rect.bottom + 6}px` : `${rect.top - 6}px`;
|
|
8450
|
+
const halfWidth = balloonRect.width / 2 || 40;
|
|
8451
|
+
const minX = halfWidth + 4;
|
|
8452
|
+
const maxX = win.innerWidth - halfWidth - 4;
|
|
8453
|
+
balloonEl.style.left = `${Math.min(Math.max(centerX, minX), maxX)}px`;
|
|
8344
8454
|
};
|
|
8345
8455
|
var balloonListenersBound = false;
|
|
8346
8456
|
var ensureBalloonListeners = () => {
|
|
@@ -8366,6 +8476,7 @@ var hideActiveBalloon = () => {
|
|
|
8366
8476
|
}
|
|
8367
8477
|
};
|
|
8368
8478
|
var showBalloon = (balloonEl) => {
|
|
8479
|
+
balloonEl.classList.add("dtm-player-balloon--visible");
|
|
8369
8480
|
positionBalloon(balloonEl);
|
|
8370
8481
|
if (activeBalloonEl === balloonEl) {
|
|
8371
8482
|
if (activeBalloonTimer) {
|
|
@@ -8374,7 +8485,6 @@ var showBalloon = (balloonEl) => {
|
|
|
8374
8485
|
} else {
|
|
8375
8486
|
hideActiveBalloon();
|
|
8376
8487
|
activeBalloonEl = balloonEl;
|
|
8377
|
-
balloonEl.classList.add("dtm-player-balloon--visible");
|
|
8378
8488
|
}
|
|
8379
8489
|
activeBalloonTimer = setTimeout(() => {
|
|
8380
8490
|
hideActiveBalloon();
|
|
@@ -8676,10 +8786,6 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8676
8786
|
const textSpan = doc.createElement("span");
|
|
8677
8787
|
textSpan.textContent = "\u{1F97A}";
|
|
8678
8788
|
em.appendChild(textSpan);
|
|
8679
|
-
em.addEventListener("click", (e) => {
|
|
8680
|
-
e.stopPropagation();
|
|
8681
|
-
toggleMute(index);
|
|
8682
|
-
});
|
|
8683
8789
|
mmlHeader.appendChild(em);
|
|
8684
8790
|
emojiEls.push(em);
|
|
8685
8791
|
emojiByTrack.set(index, em);
|
|
@@ -9441,6 +9547,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
9441
9547
|
delaySend: (lt.delay ?? 0) / 100,
|
|
9442
9548
|
gender: (lt.gender ?? 50) / 100,
|
|
9443
9549
|
breathiness: (lt.breathiness ?? 50) / 100,
|
|
9550
|
+
tension: (lt.tension ?? 50) / 100,
|
|
9444
9551
|
octaveUnison: lt.octaveUnison,
|
|
9445
9552
|
notes
|
|
9446
9553
|
};
|
|
@@ -13291,6 +13398,16 @@ var BREATHINESS_INFO_HTML = `
|
|
|
13291
13398
|
<p>\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8\u3068\u7D44\u307F\u5408\u308F\u305B\u308B\u3068\u3001\u63FA\u308C\u306A\u304C\u3089\u606F\u3063\u307D\u3044\u3001\u3088\u308A\u30A8\u30E2\u30FC\u30B7\u30E7\u30CA\u30EB\u306A\u8868\u73FE\u306B\u306A\u308A\u3084\u3059\u3044\u3067\u3059\u3002koe\u97F3\u6E90\uFF08UTAU\u7531\u6765\u306E.koe\u97F3\u6E90\uFF09\u9650\u5B9A\u306E\u52B9\u679C\u3067\u3001klatt\uFF08\u5185\u8535\u306E\u7C21\u6613\u5408\u6210\uFF09\u3067\u306F\u5909\u5316\u3057\u307E\u305B\u3093\u3002</p>
|
|
13292
13399
|
</div>
|
|
13293
13400
|
`;
|
|
13401
|
+
var TENSION_INFO_HTML = `
|
|
13402
|
+
<div class="dtm-modal-body-content">
|
|
13403
|
+
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
13404
|
+
<p>\u58F0\u306E\u5F35\u308A\uFF0F\u62BC\u3057\u51FA\u3057\u306E\u5F37\u3055\u3067\u3059\u300250\u304C\u7121\u5909\u5316\u3001\u5927\u304D\u3044\u307B\u3069\u5F35\u3063\u305F\u30FB\u62BC\u3057\u305F\u58F0\uFF08\u300C\u3053\u3076\u3057\u300D\u5BC4\u308A\u3001\u529B\u5F37\u304F\u6B4C\u308F\u305B\u308B\uFF09\u306B\u306A\u308A\u3001\u5C0F\u3055\u3044\u307B\u3069\u8131\u529B\u3057\u305F\u30EA\u30E9\u30C3\u30AF\u30B9\u3057\u305F\u58F0\u306B\u306A\u308A\u307E\u3059\u3002</p>
|
|
13405
|
+
<h4>\u30D6\u30EC\u30B7\u30CD\u30B9\u3068\u306E\u9055\u3044</h4>
|
|
13406
|
+
<p>\u30D6\u30EC\u30B7\u30CD\u30B9\u306F\u606F\u6210\u5206\u306E\u91CF\uFF08\u82AF\u306E\u3042\u308B\u58F0\u21D4\u606F\u3063\u307D\u3044\u58F0\uFF09\u3092\u52D5\u304B\u3057\u307E\u3059\u304C\u3001\u30C6\u30F3\u30B7\u30E7\u30F3\u306F\u58F0\u5E2F\u306E\u7DE0\u307E\u308A\u30FB\u62BC\u3057\u306E\u5F37\u3055\uFF08\u8131\u529B\u21D4\u5F35\u3063\u305F\u58F0\uFF09\u3092\u52D5\u304B\u3057\u307E\u3059\u3002\u30C6\u30F3\u30B7\u30E7\u30F3\u3092\u4E0A\u3052\u308B\u3068\u30B5\u30D3\u306E\u529B\u5F37\u3055\u3001\u4E0B\u3052\u308B\u3068\u7A4F\u3084\u304B\u306A\u56C1\u304D\u306B\u5BC4\u305B\u305F\u6B4C\u308F\u305B\u65B9\u306B\u306A\u308A\u307E\u3059\u3002</p>
|
|
13407
|
+
<h4>\u4ED6\u306E\u8A2D\u5B9A\u3068\u306E\u517C\u306D\u5408\u3044</h4>
|
|
13408
|
+
<p>\u30D6\u30EC\u30B7\u30CD\u30B9\u3092\u4E0B\u3052\u3064\u3064\u30C6\u30F3\u30B7\u30E7\u30F3\u3092\u4E0A\u3052\u308B\u3068\u3001\u3088\u308A\u82AF\u304C\u3042\u308A\u529B\u5F37\u3044\u6B4C\u58F0\u306B\u306A\u308A\u307E\u3059\u3002\u9006\u306B\u30D6\u30EC\u30B7\u30CD\u30B9\u3092\u4E0A\u3052\u3064\u3064\u30C6\u30F3\u30B7\u30E7\u30F3\u3092\u4E0B\u3052\u308B\u3068\u3001\u3088\u308A\u8131\u529B\u3057\u305F\u606F\u3063\u307D\u3044\u6B4C\u58F0\u306B\u306A\u308A\u307E\u3059\u3002koe\u97F3\u6E90\uFF08UTAU\u7531\u6765\u306E.koe\u97F3\u6E90\uFF09\u9650\u5B9A\u306E\u52B9\u679C\u3067\u3001klatt\uFF08\u5185\u8535\u306E\u7C21\u6613\u5408\u6210\uFF09\u3067\u306F\u5909\u5316\u3057\u307E\u305B\u3093\u3002</p>
|
|
13409
|
+
</div>
|
|
13410
|
+
`;
|
|
13294
13411
|
var LYRIC_REVERB_INFO_HTML = `
|
|
13295
13412
|
<div class="dtm-modal-body-content">
|
|
13296
13413
|
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
@@ -13815,6 +13932,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13815
13932
|
vocalDelay: t.vocalDelay,
|
|
13816
13933
|
vocalGender: t.vocalGender,
|
|
13817
13934
|
vocalBreathiness: t.vocalBreathiness,
|
|
13935
|
+
vocalTension: t.vocalTension,
|
|
13818
13936
|
vocalOctaveUnison: t.vocalOctaveUnison
|
|
13819
13937
|
};
|
|
13820
13938
|
if (lyricsDebounceTimer) clearTimeout(lyricsDebounceTimer);
|
|
@@ -13880,6 +13998,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13880
13998
|
vocalDelay: 0,
|
|
13881
13999
|
vocalGender: 50,
|
|
13882
14000
|
vocalBreathiness: 50,
|
|
14001
|
+
vocalTension: 50,
|
|
13883
14002
|
vocalOctaveUnison: "none",
|
|
13884
14003
|
trackInstrument: "",
|
|
13885
14004
|
trackCompression: 0,
|
|
@@ -13911,6 +14030,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13911
14030
|
delay: t.vocalDelay,
|
|
13912
14031
|
gender: t.vocalGender,
|
|
13913
14032
|
breathiness: t.vocalBreathiness,
|
|
14033
|
+
tension: t.vocalTension,
|
|
13914
14034
|
octaveUnison: t.vocalOctaveUnison,
|
|
13915
14035
|
syllables
|
|
13916
14036
|
});
|
|
@@ -14721,6 +14841,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
14721
14841
|
delaySend: (lt.delay ?? 0) / 100,
|
|
14722
14842
|
gender: (lt.gender ?? 50) / 100,
|
|
14723
14843
|
breathiness: (lt.breathiness ?? 50) / 100,
|
|
14844
|
+
tension: (lt.tension ?? 50) / 100,
|
|
14724
14845
|
octaveUnison: lt.octaveUnison,
|
|
14725
14846
|
notes
|
|
14726
14847
|
};
|
|
@@ -15149,6 +15270,12 @@ var mountDAW = (target, options = {}) => {
|
|
|
15149
15270
|
<span class="dtm-label" data-dtm="lyric-breathiness-label"></span>
|
|
15150
15271
|
<button class="dtm-infobtn" data-dtm="lyric-breathiness-info" title="\u30D6\u30EC\u30B7\u30CD\u30B9\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
15151
15272
|
</div>
|
|
15273
|
+
<div class="dtm-row">
|
|
15274
|
+
<span class="dtm-label">\u30C6\u30F3\u30B7\u30E7\u30F3</span>
|
|
15275
|
+
<input type="range" class="dtm-range dtm-grow" data-dtm="lyric-tension" min="0" max="100" aria-label="\u30C6\u30F3\u30B7\u30E7\u30F3\uFF08\u5F35\u308A/\u529B\u5F37\u3055\u3001koe\u97F3\u6E90\u9650\u5B9A\uFF09">
|
|
15276
|
+
<span class="dtm-label" data-dtm="lyric-tension-label"></span>
|
|
15277
|
+
<button class="dtm-infobtn" data-dtm="lyric-tension-info" title="\u30C6\u30F3\u30B7\u30E7\u30F3\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
15278
|
+
</div>
|
|
15152
15279
|
<div class="dtm-row">
|
|
15153
15280
|
<span class="dtm-label" style="display:inline-flex;align-items:center;gap:2px">
|
|
15154
15281
|
<input type="checkbox" data-dtm="lyric-vibrato" aria-label="\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8">\u30D3\u30D6\u30E9\u30FC\u30C8
|
|
@@ -15252,6 +15379,18 @@ var mountDAW = (target, options = {}) => {
|
|
|
15252
15379
|
lyricBreathinessInfo.addEventListener("click", () => {
|
|
15253
15380
|
showModal("\u30D6\u30EC\u30B7\u30CD\u30B9\u306E\u89E3\u8AAC", BREATHINESS_INFO_HTML);
|
|
15254
15381
|
});
|
|
15382
|
+
const lyricTension = lyricDiv.querySelector(
|
|
15383
|
+
'[data-dtm="lyric-tension"]'
|
|
15384
|
+
);
|
|
15385
|
+
const lyricTensionLabel = lyricDiv.querySelector(
|
|
15386
|
+
'[data-dtm="lyric-tension-label"]'
|
|
15387
|
+
);
|
|
15388
|
+
const lyricTensionInfo = lyricDiv.querySelector(
|
|
15389
|
+
'[data-dtm="lyric-tension-info"]'
|
|
15390
|
+
);
|
|
15391
|
+
lyricTensionInfo.addEventListener("click", () => {
|
|
15392
|
+
showModal("\u30C6\u30F3\u30B7\u30E7\u30F3\u306E\u89E3\u8AAC", TENSION_INFO_HTML);
|
|
15393
|
+
});
|
|
15255
15394
|
const lyricVibrato = lyricDiv.querySelector(
|
|
15256
15395
|
'[data-dtm="lyric-vibrato"]'
|
|
15257
15396
|
);
|
|
@@ -15339,6 +15478,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
15339
15478
|
lyricGenderLabel.textContent = `${active.vocalGender}`;
|
|
15340
15479
|
lyricBreathiness.value = String(active.vocalBreathiness);
|
|
15341
15480
|
lyricBreathinessLabel.textContent = `${active.vocalBreathiness}`;
|
|
15481
|
+
lyricTension.value = String(active.vocalTension);
|
|
15482
|
+
lyricTensionLabel.textContent = `${active.vocalTension}`;
|
|
15342
15483
|
lyricVibrato.checked = active.vocalVibrato;
|
|
15343
15484
|
lyricOctaveUnison.value = active.vocalOctaveUnison;
|
|
15344
15485
|
const updateLyricCount = () => {
|
|
@@ -15509,6 +15650,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
15509
15650
|
lyricBreathinessLabel.textContent = `${active.vocalBreathiness}`;
|
|
15510
15651
|
fireLyricsChange(active);
|
|
15511
15652
|
});
|
|
15653
|
+
lyricTension.addEventListener("input", () => {
|
|
15654
|
+
active.vocalTension = Number.parseInt(lyricTension.value, 10);
|
|
15655
|
+
lyricTensionLabel.textContent = `${active.vocalTension}`;
|
|
15656
|
+
fireLyricsChange(active);
|
|
15657
|
+
});
|
|
15512
15658
|
}
|
|
15513
15659
|
if (active.config.id === "chord" && showChord) {
|
|
15514
15660
|
const div = document.createElement("div");
|
|
@@ -15713,6 +15859,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
15713
15859
|
del: t.vocalDelay,
|
|
15714
15860
|
gen: t.vocalGender,
|
|
15715
15861
|
bre: t.vocalBreathiness,
|
|
15862
|
+
ten: t.vocalTension,
|
|
15716
15863
|
uni: t.vocalOctaveUnison
|
|
15717
15864
|
})).filter(
|
|
15718
15865
|
(x2) => x2.model.length > 0 && x2.text.length > 0 && x2.notes.length > 0
|
|
@@ -15727,6 +15874,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
15727
15874
|
x2.del === 0 ? "" : `e${x2.del}`,
|
|
15728
15875
|
x2.gen === 50 ? "" : `g${x2.gen}`,
|
|
15729
15876
|
x2.bre === 50 ? "" : `h${x2.bre}`,
|
|
15877
|
+
x2.ten === 50 ? "" : `t${x2.ten}`,
|
|
15730
15878
|
OCTAVE_UNISON_TOKEN[x2.uni]
|
|
15731
15879
|
].filter((s) => s.length > 0).join(" ");
|
|
15732
15880
|
const head = params ? `${x2.model} ${params}` : x2.model;
|
|
@@ -15969,6 +16117,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
15969
16117
|
active.vocalDelay = 0;
|
|
15970
16118
|
active.vocalGender = 50;
|
|
15971
16119
|
active.vocalBreathiness = 50;
|
|
16120
|
+
active.vocalTension = 50;
|
|
15972
16121
|
active.vocalOctaveUnison = "none";
|
|
15973
16122
|
} else {
|
|
15974
16123
|
for (const t of trackStates) {
|
|
@@ -15983,6 +16132,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
15983
16132
|
t.vocalDelay = 0;
|
|
15984
16133
|
t.vocalGender = 50;
|
|
15985
16134
|
t.vocalBreathiness = 50;
|
|
16135
|
+
t.vocalTension = 50;
|
|
15986
16136
|
t.vocalOctaveUnison = "none";
|
|
15987
16137
|
}
|
|
15988
16138
|
}
|
|
@@ -16001,6 +16151,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
16001
16151
|
t.vocalDelay = lt.delay ?? 0;
|
|
16002
16152
|
t.vocalGender = lt.gender ?? 50;
|
|
16003
16153
|
t.vocalBreathiness = lt.breathiness ?? 50;
|
|
16154
|
+
t.vocalTension = lt.tension ?? 50;
|
|
16155
|
+
t.vocalTension = lt.tension ?? 50;
|
|
16004
16156
|
t.vocalOctaveUnison = lt.octaveUnison ?? "none";
|
|
16005
16157
|
});
|
|
16006
16158
|
for (const p of placements) {
|
|
@@ -16085,6 +16237,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
16085
16237
|
active.vocalDelay = 0;
|
|
16086
16238
|
active.vocalGender = 50;
|
|
16087
16239
|
active.vocalBreathiness = 50;
|
|
16240
|
+
active.vocalTension = 50;
|
|
16088
16241
|
active.vocalOctaveUnison = "none";
|
|
16089
16242
|
} else {
|
|
16090
16243
|
clearAll();
|
|
@@ -16101,6 +16254,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
16101
16254
|
t.vocalDelay = 0;
|
|
16102
16255
|
t.vocalGender = 50;
|
|
16103
16256
|
t.vocalBreathiness = 50;
|
|
16257
|
+
t.vocalTension = 50;
|
|
16104
16258
|
t.vocalOctaveUnison = "none";
|
|
16105
16259
|
}
|
|
16106
16260
|
}
|
|
@@ -17465,6 +17619,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
17465
17619
|
t.vocalDelay = data.vocalDelay ?? 0;
|
|
17466
17620
|
t.vocalGender = data.vocalGender ?? 50;
|
|
17467
17621
|
t.vocalBreathiness = data.vocalBreathiness ?? 50;
|
|
17622
|
+
t.vocalTension = data.vocalTension ?? 50;
|
|
17468
17623
|
t.vocalOctaveUnison = data.vocalOctaveUnison ?? "none";
|
|
17469
17624
|
},
|
|
17470
17625
|
applyTrackInstrument: (trackIndex, instrumentName) => {
|
|
@@ -17587,6 +17742,7 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
17587
17742
|
delaySend: (lt.delay ?? 0) / 100,
|
|
17588
17743
|
gender: (lt.gender ?? 50) / 100,
|
|
17589
17744
|
breathiness: (lt.breathiness ?? 50) / 100,
|
|
17745
|
+
tension: (lt.tension ?? 50) / 100,
|
|
17590
17746
|
octaveUnison: lt.octaveUnison,
|
|
17591
17747
|
notes
|
|
17592
17748
|
};
|
package/dist/voice-worker.js
CHANGED
|
@@ -525,6 +525,14 @@
|
|
|
525
525
|
return baseHz * 2 ** (cents / 1200);
|
|
526
526
|
};
|
|
527
527
|
|
|
528
|
+
// src/voice-worker-types.ts
|
|
529
|
+
var COMPOSITE_ALIAS_SEP = "\0";
|
|
530
|
+
var unpackCompositeAlias = (alias) => {
|
|
531
|
+
if (!alias.startsWith(COMPOSITE_ALIAS_SEP)) return null;
|
|
532
|
+
const parts = alias.slice(COMPOSITE_ALIAS_SEP.length).split(COMPOSITE_ALIAS_SEP);
|
|
533
|
+
return parts.length === 2 ? [parts[0], parts[1]] : null;
|
|
534
|
+
};
|
|
535
|
+
|
|
528
536
|
// src/voice-worker.ts
|
|
529
537
|
var KOE_SAMPLE_RATE = 48e3;
|
|
530
538
|
var midiToFreq = (m) => 440 * 2 ** ((m - 69) / 12);
|
|
@@ -540,8 +548,62 @@
|
|
|
540
548
|
}
|
|
541
549
|
return p;
|
|
542
550
|
};
|
|
543
|
-
var
|
|
551
|
+
var COMPOSITE_SPLICE_XFADE_SEC = 5e-3;
|
|
552
|
+
var spliceCompositePcm = (consonantPcm, vowelPcm, sampleRate) => {
|
|
553
|
+
if (consonantPcm.length === 0 || vowelPcm.length === 0) return null;
|
|
554
|
+
const xfade = Math.min(
|
|
555
|
+
Math.floor(sampleRate * COMPOSITE_SPLICE_XFADE_SEC),
|
|
556
|
+
consonantPcm.length,
|
|
557
|
+
vowelPcm.length
|
|
558
|
+
);
|
|
559
|
+
const pcm = new Float64Array(consonantPcm.length + vowelPcm.length - xfade);
|
|
560
|
+
pcm.set(consonantPcm, 0);
|
|
561
|
+
for (let i2 = 0; i2 < xfade; i2++) {
|
|
562
|
+
const t = (i2 + 1) / (xfade + 1);
|
|
563
|
+
const idx = consonantPcm.length - xfade + i2;
|
|
564
|
+
pcm[idx] = consonantPcm[idx] * (1 - t) + vowelPcm[i2] * t;
|
|
565
|
+
}
|
|
566
|
+
pcm.set(vowelPcm.subarray(xfade), consonantPcm.length);
|
|
567
|
+
const consonantMs = (consonantPcm.length - xfade / 2) / sampleRate * 1e3;
|
|
568
|
+
return { pcm, preMs: consonantMs, consonantMs };
|
|
569
|
+
};
|
|
570
|
+
var renderComposite = async (consonantAlias, vowelAlias, pitch, durationMs, vibrato, gender, breathiness, tension) => {
|
|
571
|
+
if (!worldline) return null;
|
|
572
|
+
const [consonantPcm, vowelPcm] = await Promise.all([
|
|
573
|
+
getPcm(consonantAlias),
|
|
574
|
+
getPcm(vowelAlias)
|
|
575
|
+
]);
|
|
576
|
+
if (!consonantPcm || !vowelPcm) return null;
|
|
577
|
+
const spliced = spliceCompositePcm(consonantPcm, vowelPcm, KOE_SAMPLE_RATE);
|
|
578
|
+
if (!spliced) return null;
|
|
579
|
+
const targetHz = midiToFreq(pitch);
|
|
580
|
+
const audio = worldline.renderNote({
|
|
581
|
+
pcm: spliced.pcm,
|
|
582
|
+
pitch: vibrato ? vibratoPitchCurve(targetHz, spliced.preMs) : targetHz,
|
|
583
|
+
durationMs,
|
|
584
|
+
preMs: spliced.preMs,
|
|
585
|
+
consonantMs: spliced.consonantMs,
|
|
586
|
+
gender,
|
|
587
|
+
breathiness,
|
|
588
|
+
tension
|
|
589
|
+
});
|
|
590
|
+
return audio ? { pcm: audio, preSec: spliced.preMs / 1e3, rate: 1 } : null;
|
|
591
|
+
};
|
|
592
|
+
var renderAlias = async (alias, pitch, durationMs, vibrato, gender, breathiness, tension) => {
|
|
544
593
|
if (!bank) return null;
|
|
594
|
+
const composite = unpackCompositeAlias(alias);
|
|
595
|
+
if (composite) {
|
|
596
|
+
return renderComposite(
|
|
597
|
+
composite[0],
|
|
598
|
+
composite[1],
|
|
599
|
+
pitch,
|
|
600
|
+
durationMs,
|
|
601
|
+
vibrato,
|
|
602
|
+
gender,
|
|
603
|
+
breathiness,
|
|
604
|
+
tension
|
|
605
|
+
);
|
|
606
|
+
}
|
|
545
607
|
const pcm = await getPcm(alias);
|
|
546
608
|
if (!pcm || pcm.length === 0) return null;
|
|
547
609
|
const entry = bank.manifest.phonemes[alias];
|
|
@@ -554,7 +616,8 @@
|
|
|
554
616
|
durationMs,
|
|
555
617
|
...lead,
|
|
556
618
|
gender,
|
|
557
|
-
breathiness
|
|
619
|
+
breathiness,
|
|
620
|
+
tension
|
|
558
621
|
});
|
|
559
622
|
if (audio) return { pcm: audio, preSec: lead.preMs / 1e3, rate: 1 };
|
|
560
623
|
}
|
|
@@ -586,7 +649,16 @@
|
|
|
586
649
|
return;
|
|
587
650
|
}
|
|
588
651
|
if (msg.type === "render") {
|
|
589
|
-
const {
|
|
652
|
+
const {
|
|
653
|
+
id,
|
|
654
|
+
alias,
|
|
655
|
+
pitch,
|
|
656
|
+
durationMs,
|
|
657
|
+
vibrato,
|
|
658
|
+
gender,
|
|
659
|
+
breathiness,
|
|
660
|
+
tension
|
|
661
|
+
} = msg;
|
|
590
662
|
try {
|
|
591
663
|
const out = await renderAlias(
|
|
592
664
|
alias,
|
|
@@ -594,7 +666,8 @@
|
|
|
594
666
|
durationMs,
|
|
595
667
|
vibrato,
|
|
596
668
|
gender,
|
|
597
|
-
breathiness
|
|
669
|
+
breathiness,
|
|
670
|
+
tension
|
|
598
671
|
);
|
|
599
672
|
if (out) {
|
|
600
673
|
wself.postMessage(
|
package/package.json
CHANGED