@onjmin/dtm 0.1.24 → 0.1.26
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/README.md +1 -2
- package/dist/index.d.mts +8 -16
- package/dist/index.d.ts +8 -16
- package/dist/index.js +550 -252
- package/dist/index.mjs +550 -251
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -99,7 +99,6 @@ __export(index_exports, {
|
|
|
99
99
|
playMML: () => playMML,
|
|
100
100
|
playSingingMML: () => playSingingMML,
|
|
101
101
|
setDrawOffset: () => setDrawOffset,
|
|
102
|
-
setupRecorder: () => setupRecorder,
|
|
103
102
|
shiftNotes: () => shiftNotes,
|
|
104
103
|
stripLyrics: () => stripLyrics,
|
|
105
104
|
stripMmlMeta: () => stripMmlMeta,
|
|
@@ -116,34 +115,6 @@ function createAudioContext() {
|
|
|
116
115
|
drumGainNode.connect(audioCtx.destination);
|
|
117
116
|
return { audioCtx, gainNode, drumGainNode };
|
|
118
117
|
}
|
|
119
|
-
function setupRecorder(audioCtx, gainNode, drumGainNode) {
|
|
120
|
-
let isRecording = false;
|
|
121
|
-
let recordedData = [[], []];
|
|
122
|
-
const recorderProcessor = audioCtx.createScriptProcessor(4096, 2, 2);
|
|
123
|
-
recorderProcessor.onaudioprocess = (e) => {
|
|
124
|
-
if (!isRecording) return;
|
|
125
|
-
const left = e.inputBuffer.getChannelData(0);
|
|
126
|
-
const right = e.inputBuffer.getChannelData(1);
|
|
127
|
-
recordedData[0].push(left.slice());
|
|
128
|
-
recordedData[1].push(right.slice());
|
|
129
|
-
};
|
|
130
|
-
gainNode.connect(recorderProcessor);
|
|
131
|
-
drumGainNode.connect(recorderProcessor);
|
|
132
|
-
recorderProcessor.connect(audioCtx.destination);
|
|
133
|
-
return {
|
|
134
|
-
startRecording: () => {
|
|
135
|
-
isRecording = true;
|
|
136
|
-
},
|
|
137
|
-
stopRecording: () => {
|
|
138
|
-
isRecording = false;
|
|
139
|
-
},
|
|
140
|
-
getRecordedData: () => recordedData,
|
|
141
|
-
isRecording: () => isRecording,
|
|
142
|
-
clearRecordedData: () => {
|
|
143
|
-
recordedData = [[], []];
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
118
|
async function fetchSoundFontList(ttl) {
|
|
148
119
|
const res = await fetch(`https://rpgen3.github.io/soundfont/list/${ttl}.txt`);
|
|
149
120
|
const str = await res.text();
|
|
@@ -1240,8 +1211,9 @@ var buildUI = (target, options) => {
|
|
|
1240
1211
|
target.innerHTML = `
|
|
1241
1212
|
<div class="dtm-daw" data-dtm="root">
|
|
1242
1213
|
<div class="dtm-topbar" data-dtm="transport">
|
|
1214
|
+
<button class="dtm-iconbtn" data-dtm="prev-bar" title="1\u5C0F\u7BC0\u524D">${icon("chevronLeft")}</button>
|
|
1243
1215
|
<button class="dtm-play" data-dtm="play" disabled>${icon("play")}<span>\u8A66\u8074</span></button>
|
|
1244
|
-
<button class="dtm-iconbtn
|
|
1216
|
+
<button class="dtm-iconbtn" data-dtm="next-bar" title="1\u5C0F\u7BC0\u5F8C">${icon("chevronRight")}</button>
|
|
1245
1217
|
<label class="dtm-toggle"><input type="checkbox" data-dtm="solo"><span>\u30BD\u30ED</span></label>
|
|
1246
1218
|
<span class="dtm-topbar-loading dtm-blink" data-dtm="topbar-loading">... LOADING ...</span>
|
|
1247
1219
|
<span class="dtm-grow"></span>
|
|
@@ -1406,10 +1378,12 @@ var buildUI = (target, options) => {
|
|
|
1406
1378
|
</div>
|
|
1407
1379
|
<div class="dtm-output dtm-hidden" data-dtm="output-container">
|
|
1408
1380
|
<p class="dtm-label" data-dtm="output-status"></p>
|
|
1381
|
+
<div class="dtm-output-label">\u6539\u884C\u3042\u308A\u7248</div>
|
|
1409
1382
|
<div class="dtm-output-row">
|
|
1410
1383
|
<pre><code data-dtm="output-full"></code></pre>
|
|
1411
1384
|
<button class="dtm-btn dtm-btn--primary dtm-btn--icon" data-dtm="copy-full" title="\u30B3\u30D4\u30FC">${icon("copy")}</button>
|
|
1412
1385
|
</div>
|
|
1386
|
+
<div class="dtm-output-label">\uFF11\u884C\u7248</div>
|
|
1413
1387
|
<div class="dtm-output-row">
|
|
1414
1388
|
<pre><code data-dtm="output-mini"></code></pre>
|
|
1415
1389
|
<button class="dtm-btn dtm-btn--primary dtm-btn--icon" data-dtm="copy-mini" title="\u30B3\u30D4\u30FC">${icon("copy")}</button>
|
|
@@ -1428,6 +1402,7 @@ var buildUI = (target, options) => {
|
|
|
1428
1402
|
<div class="dtm-modal-body" data-dtm="modal-body"></div>
|
|
1429
1403
|
</div>
|
|
1430
1404
|
</div>
|
|
1405
|
+
|
|
1431
1406
|
</div>`;
|
|
1432
1407
|
const root = q(target, '[data-dtm="root"]');
|
|
1433
1408
|
const sel = (name) => q(root, `[data-dtm="${name}"]`);
|
|
@@ -1436,7 +1411,8 @@ var buildUI = (target, options) => {
|
|
|
1436
1411
|
topbar: sel("transport"),
|
|
1437
1412
|
topbarLoading: sel("topbar-loading"),
|
|
1438
1413
|
playBtn: sel("play"),
|
|
1439
|
-
|
|
1414
|
+
prevBarBtn: sel("prev-bar"),
|
|
1415
|
+
nextBarBtn: sel("next-bar"),
|
|
1440
1416
|
soloCheckbox: sel("solo"),
|
|
1441
1417
|
toolPen: sel("tool-pen"),
|
|
1442
1418
|
toolSelect: sel("tool-select"),
|
|
@@ -2611,7 +2587,20 @@ var createWorkerBackend = async (workerUrl, options) => {
|
|
|
2611
2587
|
};
|
|
2612
2588
|
};
|
|
2613
2589
|
var createKoeVoice = async (ctx, destination, options) => {
|
|
2614
|
-
|
|
2590
|
+
let backend;
|
|
2591
|
+
if (options.voiceWorkerUrl) {
|
|
2592
|
+
try {
|
|
2593
|
+
backend = await createWorkerBackend(options.voiceWorkerUrl, options);
|
|
2594
|
+
} catch (err2) {
|
|
2595
|
+
console.warn(
|
|
2596
|
+
"[dtm] Failed to spawn voice worker. Falling back to local backend.",
|
|
2597
|
+
err2
|
|
2598
|
+
);
|
|
2599
|
+
backend = await createLocalBackend(options);
|
|
2600
|
+
}
|
|
2601
|
+
} else {
|
|
2602
|
+
backend = await createLocalBackend(options);
|
|
2603
|
+
}
|
|
2615
2604
|
const renderCache = /* @__PURE__ */ new Map();
|
|
2616
2605
|
const inflight = /* @__PURE__ */ new Map();
|
|
2617
2606
|
const active = /* @__PURE__ */ new Set();
|
|
@@ -2792,7 +2781,7 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2792
2781
|
if (!m?.renderToCache) continue;
|
|
2793
2782
|
let n = 0;
|
|
2794
2783
|
forEachSungNote(track, (note, prevVowel) => {
|
|
2795
|
-
if (n >= count) return;
|
|
2784
|
+
if (n >= count && note.startSec >= 3) return;
|
|
2796
2785
|
n++;
|
|
2797
2786
|
promises.push(
|
|
2798
2787
|
m.renderToCache?.(
|
|
@@ -2825,14 +2814,18 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2825
2814
|
if (opts?.isAudible && !opts.isAudible(track)) continue;
|
|
2826
2815
|
const t0 = anchorTime + note.startSec;
|
|
2827
2816
|
if (model.renderToCache && model.scheduleCached) {
|
|
2828
|
-
const
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2817
|
+
const renderToCache = model.renderToCache;
|
|
2818
|
+
const scheduleCached = model.scheduleCached;
|
|
2819
|
+
void (async () => {
|
|
2820
|
+
const key = await renderToCache(
|
|
2821
|
+
note.syllable,
|
|
2822
|
+
prevVowel,
|
|
2823
|
+
note.pitch,
|
|
2824
|
+
note.durationSec * 1e3
|
|
2825
|
+
);
|
|
2826
|
+
if (session !== streamSession) return;
|
|
2827
|
+
if (key) scheduleCached(key, t0, peak, track.pan);
|
|
2828
|
+
})();
|
|
2836
2829
|
} else {
|
|
2837
2830
|
const when = t0 - ctx.currentTime;
|
|
2838
2831
|
model(note.syllable, {
|
|
@@ -4126,6 +4119,110 @@ var isChordHeavyTrack = (notes, threshold = 0.6) => {
|
|
|
4126
4119
|
return chordNotes / notes.length >= threshold;
|
|
4127
4120
|
};
|
|
4128
4121
|
|
|
4122
|
+
// src/mml-info.ts
|
|
4123
|
+
var MML_INFO_HTML = `
|
|
4124
|
+
<div class="dtm-modal-body-content">
|
|
4125
|
+
<h4>1. \u97F3\u7B26\u3068\u4F11\u7B26</h4>
|
|
4126
|
+
<p><code>c</code>(\u30C9) <code>d</code>(\u30EC) <code>e</code>(\u30DF) <code>f</code>(\u30D5\u30A1) <code>g</code>(\u30BD) <code>a</code>(\u30E9) <code>b</code>(\u30B7) \u306E\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8\u3067\u8868\u3057\u307E\u3059\u3002</p>
|
|
4127
|
+
<ul>
|
|
4128
|
+
<li>\u534A\u97F3\u4E0A\u3052\u308B: <code>c#</code> \u307E\u305F\u306F <code>c+</code></li>
|
|
4129
|
+
<li>\u534A\u97F3\u4E0B\u3052\u308B: <code>d-</code></li>
|
|
4130
|
+
<li>\u4F11\u7B26: <code>r</code></li>
|
|
4131
|
+
</ul>
|
|
4132
|
+
|
|
4133
|
+
<h4>2. \u97F3\u306E\u9577\u3055</h4>
|
|
4134
|
+
<p>\u97F3\u540D\u3084\u4F11\u7B26\u306E\u5F8C\u306B\u6570\u5024\u3067\u6307\u5B9A\u3057\u307E\u3059\uFF08\u4F8B: <code>4</code> = 4\u5206\u97F3\u7B26, <code>8</code> = 8\u5206\u97F3\u7B26, <code>16</code> = 16\u5206\u97F3\u7B26\uFF09\u3002</p>
|
|
4135
|
+
<ul>
|
|
4136
|
+
<li><code>c4</code> : 4\u5206\u97F3\u7B26\u306E\u30C9</li>
|
|
4137
|
+
<li><code>r8</code> : 8\u5206\u4F11\u7B26</li>
|
|
4138
|
+
<li><code>c4.</code> : \u4ED8\u70B94\u5206\u97F3\u7B26\u306E\u30C9\uFF08\u9577\u3055\u30921.5\u500D\u306B\uFF09</li>
|
|
4139
|
+
<li>\u6570\u5024\u3092\u7701\u7565\u3059\u308B\u3068\u3001<code>l</code> \u30B3\u30DE\u30F3\u30C9\u3067\u8A2D\u5B9A\u3055\u308C\u305F\u30C7\u30D5\u30A9\u30EB\u30C8\u9577\uFF08\u901A\u5E3816\u5206\uFF09\u306B\u306A\u308A\u307E\u3059\u3002</li>
|
|
4140
|
+
</ul>
|
|
4141
|
+
|
|
4142
|
+
<h4>3. \u30AA\u30AF\u30BF\u30FC\u30D6\uFF08\u97F3\u306E\u9AD8\u3055\uFF09</h4>
|
|
4143
|
+
<ul>
|
|
4144
|
+
<li><code>o4</code>, <code>o5</code> : \u9AD8\u3055\u3092\u76F4\u63A5\u6307\u5B9A\uFF08\u3075\u3064\u3046\u306F o4 \u304B o5\uFF09</li>
|
|
4145
|
+
<li><code>></code> : 1\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0A\u3052\u308B</li>
|
|
4146
|
+
<li><code><</code> : 1\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0B\u3052\u308B</li>
|
|
4147
|
+
</ul>
|
|
4148
|
+
|
|
4149
|
+
<h4>4. \u30C6\u30F3\u30DD</h4>
|
|
4150
|
+
<ul>
|
|
4151
|
+
<li><code>t120</code> : \u66F2\u306E\u901F\u3055\u3092BPM120\u306B\u6307\u5B9A\u3002\u203B\u30E1\u30ED\u30C7\u30A3\uFF08@0\uFF09\u306E\u30C6\u30F3\u30DD\u6307\u5B9A\u304C\u66F2\u5168\u4F53\u306B\u53CD\u6620\u3055\u308C\u307E\u3059\u3002</li>
|
|
4152
|
+
</ul>
|
|
4153
|
+
|
|
4154
|
+
<h4>5. \u548C\u97F3</h4>
|
|
4155
|
+
<p>\u97F3\u7B26\u3092 <code>[</code> \u3068 <code>]</code> \u3067\u56F2\u3080\u3068\u540C\u6642\u306B\u767A\u97F3\u3057\u307E\u3059\u3002</p>
|
|
4156
|
+
<pre>\u4F8B: [ceg]4 \uFF08\u30C9\u30FB\u30DF\u30FB\u30BD\u30924\u5206\u97F3\u7B26\u3067\u540C\u6642\u306B\u767A\u97F3\uFF09</pre>
|
|
4157
|
+
|
|
4158
|
+
<h4>6. \u30C8\u30E9\u30C3\u30AF\u306E\u533A\u5207\u308A</h4>
|
|
4159
|
+
<p><code>;</code> \u307E\u305F\u306F <code>@0</code>\u301C<code>@3</code> \u3067\u30C8\u30E9\u30C3\u30AF\u3092\u5207\u308A\u66FF\u3048\u307E\u3059\u3002</p>
|
|
4160
|
+
<ul>
|
|
4161
|
+
<li><code>@0</code>: \u30E1\u30ED\u30C7\u30A3</li>
|
|
4162
|
+
<li><code>@1</code>: \u30B5\u30D6\u30E1\u30ED</li>
|
|
4163
|
+
<li><code>@2</code>: \u30D9\u30FC\u30B9</li>
|
|
4164
|
+
<li><code>@3</code>: \u4F34\u594F</li>
|
|
4165
|
+
</ul>
|
|
4166
|
+
|
|
4167
|
+
<h4>7. \u6B4C\u58F0\u30FB\u6B4C\u8A5E\u5165\u529B</h4>
|
|
4168
|
+
<p><code>@@<\u30C8\u30E9\u30C3\u30AF\u756A\u53F7> <\u97F3\u6E90\u540D> <\u6B4C\u8A5E></code> \u306E\u5F62\u5F0F\u3067\u3001\u97F3\u7B26\u3068\u540C\u671F\u3059\u308B\u6B4C\u8A5E\u3092\u5165\u529B\u3067\u304D\u307E\u3059\u3002</p>
|
|
4169
|
+
<pre>\u4F8B: @@0 tsukuyomi \u3069\u3093\u3050\u308A\u3053\u308D\u3053\u308D\u3069\u3093\u3050\u308A\u3053</pre>
|
|
4170
|
+
<p style="margin-top:4px; margin-bottom:16px;"><small>\uFF08\u97F3\u6E90\u540D\u306F <code>tsukuyomi</code> \u3084 <code>klatt</code>, <code>roze</code> \u306A\u3069\u306E\u97F3\u58F0\u30E2\u30C7\u30EB\u3092\u6307\u5B9A\u3067\u304D\u307E\u3059\uFF09</small></p>
|
|
4171
|
+
|
|
4172
|
+
<h4 style="margin-top: 18px; border-top: 1px solid var(--dtm-border2); padding-top: 8px;">\u30B5\u30F3\u30D7\u30EB\u66F2\uFF08\u8A66\u8074\u30FB\u30B3\u30D4\u30FC\uFF09</h4>
|
|
4173
|
+
|
|
4174
|
+
<!-- \u30B5\u30F3\u30D7\u30EB1 -->
|
|
4175
|
+
<div class="dtm-modal-sample-box">
|
|
4176
|
+
<div class="dtm-modal-sample-header">
|
|
4177
|
+
<span class="dtm-modal-sample-tag">1. \u57FA\u672C\u306E\u30E1\u30ED\u30C7\u30A3</span>
|
|
4178
|
+
<button class="dtm-btn dtm-btn--ghost dtm-btn--xs dtm-modal-sample-copy-btn" data-mml="@0 t120 l8 o5 c d e f g a b > c">\u{1F4CB} \u30B3\u30D4\u30FC</button>
|
|
4179
|
+
</div>
|
|
4180
|
+
<pre style="margin: 0; padding: 6px;">@0 t120 l8 o5 c d e f g a b > c</pre>
|
|
4181
|
+
<div class="dtm-modal-sample-desc">
|
|
4182
|
+
\u57FA\u672C\u7684\u306A\u30E1\u30ED\u30C7\u30A3\u306E\u66F8\u304D\u65B9\uFF08\u97F3\u540D\u30FB\u9577\u3055\u30FB\u30AA\u30AF\u30BF\u30FC\u30D6\u3068\u30C6\u30F3\u30DD\uFF09\u3002
|
|
4183
|
+
</div>
|
|
4184
|
+
<div style="margin-top: 8px;">
|
|
4185
|
+
<button class="dtm-btn dtm-btn--primary dtm-btn--xs dtm-modal-sample-play-btn" data-mml="@0 t120 l8 o5 c d e f g a b > c">\u25B6 \u8A66\u8074</button>
|
|
4186
|
+
</div>
|
|
4187
|
+
<div class="dtm-modal-sample-player-container"></div>
|
|
4188
|
+
</div>
|
|
4189
|
+
|
|
4190
|
+
<!-- \u30B5\u30F3\u30D7\u30EB2 -->
|
|
4191
|
+
<div class="dtm-modal-sample-box">
|
|
4192
|
+
<div class="dtm-modal-sample-header">
|
|
4193
|
+
<span class="dtm-modal-sample-tag">2. \u8907\u6570\u30C8\u30E9\u30C3\u30AF\u3068\u548C\u97F3</span>
|
|
4194
|
+
<button class="dtm-btn dtm-btn--ghost dtm-btn--xs dtm-modal-sample-copy-btn" data-mml="@0 t120 o5 c e g2 ; @3 o4 [ceg]2 [ceg]2">\u{1F4CB} \u30B3\u30D4\u30FC</button>
|
|
4195
|
+
</div>
|
|
4196
|
+
<pre style="margin: 0; padding: 6px;">@0 t120 o5 c e g2 ;
|
|
4197
|
+
@3 o4 [ceg]2 [ceg]2</pre>
|
|
4198
|
+
<div class="dtm-modal-sample-desc">
|
|
4199
|
+
; \u3067\u30C8\u30E9\u30C3\u30AF\uFF08\u4E0A\uFF1D\u30E1\u30ED\u30C7\u30A3\uFF0F\u4E0B\uFF1D\u4F34\u594F\uFF09\u3092\u5206\u3051\u3001[ceg] \u3067\u548C\u97F3\u3092\u9CF4\u3089\u3057\u307E\u3059\u3002
|
|
4200
|
+
</div>
|
|
4201
|
+
<div style="margin-top: 8px;">
|
|
4202
|
+
<button class="dtm-btn dtm-btn--primary dtm-btn--xs dtm-modal-sample-play-btn" data-mml="@0 t120 o5 c e g2 ; @3 o4 [ceg]2 [ceg]2">\u25B6 \u8A66\u8074</button>
|
|
4203
|
+
</div>
|
|
4204
|
+
<div class="dtm-modal-sample-player-container"></div>
|
|
4205
|
+
</div>
|
|
4206
|
+
|
|
4207
|
+
<!-- \u30B5\u30F3\u30D7\u30EB3 -->
|
|
4208
|
+
<div class="dtm-modal-sample-box">
|
|
4209
|
+
<div class="dtm-modal-sample-header">
|
|
4210
|
+
<span class="dtm-modal-sample-tag">3. \u6B4C\u5531\u4ED8\u304D (\u3069\u3093\u3050\u308A\u3053\u308D\u3053\u308D)</span>
|
|
4211
|
+
<button class="dtm-btn dtm-btn--ghost dtm-btn--xs dtm-modal-sample-copy-btn" data-mml="@0 t120 v100 o4g8 g8 e8 e8 f8 e8 d8 c8 g8 g8 e8 e8 d4.; @@0 tsukuyomi \u3069\u3093\u3050\u308A\u3053\u308D\u3053\u308D\u3069\u3093\u3050\u308A\u3053;">\u{1F4CB} \u30B3\u30D4\u30FC</button>
|
|
4212
|
+
</div>
|
|
4213
|
+
<pre style="margin: 0; padding: 6px;">@0 t120 v100 o4g8 g8 e8 e8 f8 e8 d8 c8 g8 g8 e8 e8 d4.;
|
|
4214
|
+
@@0 tsukuyomi \u3069\u3093\u3050\u308A\u3053\u308D\u3053\u308D\u3069\u3093\u3050\u308A\u3053;</pre>
|
|
4215
|
+
<div class="dtm-modal-sample-desc">
|
|
4216
|
+
@@0 tsukuyomi \u6B4C\u8A5E... \u3067\u30E1\u30ED\u30C7\u30A3\u30C8\u30E9\u30C3\u30AF\u306B\u6B4C\u8A5E\u3092\u540C\u671F\u3055\u305B\u3066\u6B4C\u308F\u305B\u307E\u3059\u3002\u203B\u72EC\u81EA\u62E1\u5F35
|
|
4217
|
+
</div>
|
|
4218
|
+
<div style="margin-top: 8px;">
|
|
4219
|
+
<button class="dtm-btn dtm-btn--primary dtm-btn--xs dtm-modal-sample-play-btn" data-mml="@0 t120 v100 o4g8 g8 e8 e8 f8 e8 d8 c8 g8 g8 e8 e8 d4.; @@0 tsukuyomi \u3069\u3093\u3050\u308A\u3053\u308D\u3053\u308D\u3069\u3093\u3050\u308A\u3053;">\u25B6 \u8A66\u8074</button>
|
|
4220
|
+
</div>
|
|
4221
|
+
<div class="dtm-modal-sample-player-container"></div>
|
|
4222
|
+
</div>
|
|
4223
|
+
</div>
|
|
4224
|
+
`;
|
|
4225
|
+
|
|
4129
4226
|
// src/mml-parser.ts
|
|
4130
4227
|
var PITCH_MAP2 = {
|
|
4131
4228
|
c: 0,
|
|
@@ -4137,7 +4234,7 @@ var PITCH_MAP2 = {
|
|
|
4137
4234
|
b: 11
|
|
4138
4235
|
};
|
|
4139
4236
|
var clamp2 = (value, lo, hi) => Math.min(hi, Math.max(lo, value));
|
|
4140
|
-
var META_DIRECTIVE = /#(inst|drum|volume|mode)=([\w-]+)/gi;
|
|
4237
|
+
var META_DIRECTIVE = /#(inst|drum|volume|drumvolume|mode)=([\w-]+)/gi;
|
|
4141
4238
|
var parseMmlMeta = (mml) => {
|
|
4142
4239
|
const meta = {};
|
|
4143
4240
|
for (const m of mml.matchAll(META_DIRECTIVE)) {
|
|
@@ -4147,6 +4244,9 @@ var parseMmlMeta = (mml) => {
|
|
|
4147
4244
|
else if (key === "volume") {
|
|
4148
4245
|
const v = Number.parseInt(m[2], 10);
|
|
4149
4246
|
if (!Number.isNaN(v)) meta.volume = v;
|
|
4247
|
+
} else if (key === "drumvolume") {
|
|
4248
|
+
const dv = Number.parseInt(m[2], 10);
|
|
4249
|
+
if (!Number.isNaN(dv)) meta.drumVolume = dv;
|
|
4150
4250
|
} else if (key === "mode") {
|
|
4151
4251
|
if (m[2] === "simple" || m[2] === "advanced") {
|
|
4152
4252
|
meta.mode = m[2];
|
|
@@ -4161,6 +4261,8 @@ var formatMmlMeta = (meta) => {
|
|
|
4161
4261
|
if (meta.instrument) parts.push(`#inst=${meta.instrument}`);
|
|
4162
4262
|
if (meta.drum) parts.push(`#drum=${meta.drum}`);
|
|
4163
4263
|
if (meta.volume !== void 0) parts.push(`#volume=${meta.volume}`);
|
|
4264
|
+
if (meta.drumVolume !== void 0)
|
|
4265
|
+
parts.push(`#drumvolume=${meta.drumVolume}`);
|
|
4164
4266
|
if (meta.mode) parts.push(`#mode=${meta.mode}`);
|
|
4165
4267
|
return parts.join(" ");
|
|
4166
4268
|
};
|
|
@@ -4748,9 +4850,13 @@ var DAW_CSS = `
|
|
|
4748
4850
|
/* \u30C7\u30B6\u30A4\u30F3\u30C8\u30FC\u30AF\u30F3\u306F\u7DE8\u96C6UI\u672C\u4F53\uFF08.dtm-daw\uFF09\u306B\u52A0\u3048\u3001\u305D\u306E\u5916\u5074\u306B\u5DEE\u3057\u8FBC\u307E\u308C\u308B
|
|
4749
4851
|
\u30B3\u30F3\u30C8\u30ED\u30FC\u30EB\u30D0\u30FC\uFF08.dtm-controlbar\uFF09\u306B\u3082\u4F9B\u7D66\u3059\u308B\u3002mountPresetSelect /
|
|
4750
4852
|
mountModeSwitch \u306EUI\u306F .dtm-daw \u306E\u5144\u5F1F\u3068\u3057\u3066\u7F6E\u304B\u308C\u308B\u305F\u3081\u3001\u3053\u3053\u3067\u914D\u3089\u306A\u3044\u3068
|
|
4751
|
-
var(--dtm-*) \u304C\u89E3\u6C7A\u3067\u304D\u305A\u7121\u88C5\u98FE\uFF08\u767D\u5730\u30FB\u65E2\u5B9A\u30D5\u30A9\u30F3\u30C8\uFF09\u306B\u306A\u3063\u3066\u3057\u307E\u3046\u3002
|
|
4853
|
+
var(--dtm-*) \u304C\u89E3\u6C7A\u3067\u304D\u305A\u7121\u88C5\u98FE\uFF08\u767D\u5730\u30FB\u65E2\u5B9A\u30D5\u30A9\u30F3\u30C8\uFF09\u306B\u306A\u3063\u3066\u3057\u307E\u3046\u3002
|
|
4854
|
+
\u518D\u751F\u5C02\u7528\u30D3\u30E5\u30FC\u306E\u30E2\u30FC\u30C0\u30EB\uFF0F\u5229\u7528\u898F\u7D04\u30AB\u30D0\u30FC\u306F document.body \u76F4\u4E0B\u3078\u91CD\u306D\u308B\u305F\u3081\u3001
|
|
4855
|
+
.dtm-daw \u306E\u5916\u306B\u51FA\u308B\u3002\u3053\u308C\u3089\u3082\u540C\u69D8\u306B\u30C8\u30FC\u30AF\u30F3\u3092\u4F9B\u7D66\u3057\u306A\u3044\u3068\u9ED2\u5730\u30FB\u767D\u6587\u5B57\u306B\u306A\u308B\u3002 */
|
|
4752
4856
|
.dtm-daw,
|
|
4753
|
-
.dtm-controlbar
|
|
4857
|
+
.dtm-controlbar,
|
|
4858
|
+
.dtm-modal-overlay,
|
|
4859
|
+
.dtm-consent-overlay {
|
|
4754
4860
|
/* PICO-8 16\u8272\u30D1\u30EC\u30C3\u30C8\u3088\u308A */
|
|
4755
4861
|
--c-black: #000000;
|
|
4756
4862
|
--c-navy: #1d2b53;
|
|
@@ -4878,7 +4984,7 @@ var DAW_CSS = `
|
|
|
4878
4984
|
top: 0;
|
|
4879
4985
|
z-index: 20;
|
|
4880
4986
|
display: flex;
|
|
4881
|
-
flex-wrap:
|
|
4987
|
+
flex-wrap: nowrap;
|
|
4882
4988
|
align-items: center;
|
|
4883
4989
|
gap: var(--dtm-gap);
|
|
4884
4990
|
padding: 6px;
|
|
@@ -4888,6 +4994,17 @@ var DAW_CSS = `
|
|
|
4888
4994
|
inset 0 0 0 2px var(--c-black),
|
|
4889
4995
|
0 0 0 2px var(--dtm-success),
|
|
4890
4996
|
4px 4px 0 var(--c-black);
|
|
4997
|
+
overflow-x: auto;
|
|
4998
|
+
scrollbar-width: none;
|
|
4999
|
+
}
|
|
5000
|
+
.dtm-topbar::-webkit-scrollbar {
|
|
5001
|
+
display: none;
|
|
5002
|
+
}
|
|
5003
|
+
.dtm-topbar > * {
|
|
5004
|
+
flex-shrink: 0;
|
|
5005
|
+
}
|
|
5006
|
+
.dtm-topbar > .dtm-grow {
|
|
5007
|
+
flex-shrink: 1;
|
|
4891
5008
|
}
|
|
4892
5009
|
|
|
4893
5010
|
/* PLAY\u30DC\u30BF\u30F3 \u2014 \u30B2\u30FC\u30E0\u306E\u300C\u6C7A\u5B9A\u30DC\u30BF\u30F3\u300D\u7684\u5B58\u5728\u611F */
|
|
@@ -5238,6 +5355,15 @@ var DAW_CSS = `
|
|
|
5238
5355
|
line-height: 1.8;
|
|
5239
5356
|
color: var(--dtm-success);
|
|
5240
5357
|
}
|
|
5358
|
+
.dtm-output-label {
|
|
5359
|
+
font-size: 11px;
|
|
5360
|
+
color: var(--dtm-muted);
|
|
5361
|
+
font-family: var(--dtm-font);
|
|
5362
|
+
margin-top: 10px;
|
|
5363
|
+
}
|
|
5364
|
+
.dtm-output-label:first-of-type {
|
|
5365
|
+
margin-top: 0;
|
|
5366
|
+
}
|
|
5241
5367
|
.dtm-output-row { display: flex; gap: 8px; align-items: flex-start; margin-top: 6px; }
|
|
5242
5368
|
.dtm-output-row pre { flex: 1; }
|
|
5243
5369
|
|
|
@@ -5348,10 +5474,76 @@ var DAW_CSS = `
|
|
|
5348
5474
|
justify-content: center;
|
|
5349
5475
|
padding: 16px;
|
|
5350
5476
|
backdrop-filter: blur(2px);
|
|
5477
|
+
/* body\u76F4\u4E0B\u306B\u91CD\u306D\u305F\u5834\u5408\uFF08\u518D\u751F\u5C02\u7528\u30D3\u30E5\u30FC\uFF09\u3067\u3082\u6587\u5B57\u8272\u30FB\u30D5\u30A9\u30F3\u30C8\u304C
|
|
5478
|
+
.dtm-daw \u304B\u3089\u7D99\u627F\u3067\u304D\u306A\u3044\u305F\u3081\u3001\u3053\u3053\u3067\u660E\u793A\u3059\u308B\u3002 */
|
|
5479
|
+
color: var(--dtm-text);
|
|
5480
|
+
font-family: var(--dtm-font);
|
|
5351
5481
|
}
|
|
5352
5482
|
.dtm-modal-overlay[hidden] {
|
|
5353
5483
|
display: none !important;
|
|
5354
5484
|
}
|
|
5485
|
+
|
|
5486
|
+
/* \u2500\u2500\u2500 \u5229\u7528\u898F\u7D04\u540C\u610F\u30AB\u30D0\u30FC \u2500\u2500\u2500 */
|
|
5487
|
+
.dtm-consent-overlay {
|
|
5488
|
+
position: fixed;
|
|
5489
|
+
inset: 0;
|
|
5490
|
+
z-index: 10100;
|
|
5491
|
+
background: rgba(0, 0, 0, 0.6);
|
|
5492
|
+
display: flex;
|
|
5493
|
+
align-items: center;
|
|
5494
|
+
justify-content: center;
|
|
5495
|
+
padding: 16px;
|
|
5496
|
+
backdrop-filter: blur(2px);
|
|
5497
|
+
/* body\u76F4\u4E0B\u306B\u91CD\u306D\u308B\u305F\u3081 .dtm-daw \u304B\u3089\u7D99\u627F\u3067\u304D\u306A\u3044\u6587\u5B57\u8272\u30FB\u30D5\u30A9\u30F3\u30C8\u3092\u660E\u793A\u3002 */
|
|
5498
|
+
color: var(--dtm-text);
|
|
5499
|
+
font-family: var(--dtm-font);
|
|
5500
|
+
}
|
|
5501
|
+
.dtm-consent-overlay[hidden] {
|
|
5502
|
+
display: none !important;
|
|
5503
|
+
}
|
|
5504
|
+
.dtm-consent-modal {
|
|
5505
|
+
max-width: 450px;
|
|
5506
|
+
width: 100%;
|
|
5507
|
+
max-height: 85vh;
|
|
5508
|
+
display: flex;
|
|
5509
|
+
flex-direction: column;
|
|
5510
|
+
background: var(--dtm-surface);
|
|
5511
|
+
border: 2px solid var(--c-black);
|
|
5512
|
+
box-shadow:
|
|
5513
|
+
inset 0 0 0 2px var(--c-black),
|
|
5514
|
+
0 0 0 2px var(--dtm-primary),
|
|
5515
|
+
4px 4px 0 var(--c-black);
|
|
5516
|
+
overflow-y: auto;
|
|
5517
|
+
}
|
|
5518
|
+
.dtm-consent-header {
|
|
5519
|
+
background: var(--dtm-deep);
|
|
5520
|
+
color: var(--dtm-text);
|
|
5521
|
+
padding: 8px 12px;
|
|
5522
|
+
border-bottom: 2px solid var(--c-black);
|
|
5523
|
+
font-weight: bold;
|
|
5524
|
+
text-align: center;
|
|
5525
|
+
font-size: 14px;
|
|
5526
|
+
}
|
|
5527
|
+
.dtm-consent-body {
|
|
5528
|
+
padding: 12px 16px;
|
|
5529
|
+
font-size: 13px;
|
|
5530
|
+
line-height: 1.6;
|
|
5531
|
+
}
|
|
5532
|
+
.dtm-consent-body a {
|
|
5533
|
+
color: var(--dtm-primary);
|
|
5534
|
+
text-decoration: underline;
|
|
5535
|
+
}
|
|
5536
|
+
.dtm-consent-body a:hover {
|
|
5537
|
+
color: var(--dtm-accent);
|
|
5538
|
+
}
|
|
5539
|
+
.dtm-consent-footer {
|
|
5540
|
+
padding: 8px;
|
|
5541
|
+
border-top: 2px solid var(--c-black);
|
|
5542
|
+
background: var(--dtm-deep);
|
|
5543
|
+
display: flex;
|
|
5544
|
+
justify-content: center;
|
|
5545
|
+
}
|
|
5546
|
+
|
|
5355
5547
|
.dtm-modal {
|
|
5356
5548
|
max-width: 500px;
|
|
5357
5549
|
width: 100%;
|
|
@@ -5485,18 +5677,19 @@ var DAW_CSS = `
|
|
|
5485
5677
|
}
|
|
5486
5678
|
|
|
5487
5679
|
.dtm-hidden { display: none !important; }
|
|
5488
|
-
/* \u8AAD\u8FBC\u6642\u306E\
|
|
5680
|
+
/* \u8AAD\u8FBC\u6642\u306E\u8B66\u544A\u304A\u77E5\u3089\u305B\uFF08\u4F8B: \u30B7\u30F3\u30D7\u30EB\u30E2\u30FC\u30C9\u3067\u306E\u30C8\u30E9\u30C3\u30AF\u5408\u7B97\uFF09\u3002 */
|
|
5489
5681
|
.dtm-load-note {
|
|
5490
5682
|
margin: 6px 0 0;
|
|
5491
5683
|
padding: 0 2px;
|
|
5492
5684
|
font-family: var(--dtm-font);
|
|
5493
|
-
font-size:
|
|
5685
|
+
font-size: 11px;
|
|
5494
5686
|
line-height: 1.5;
|
|
5495
5687
|
letter-spacing: .04em;
|
|
5496
|
-
color: var(--dtm-
|
|
5497
|
-
|
|
5688
|
+
color: var(--dtm-warn); /* \u8B66\u544A\u8272\uFF08\u30AA\u30EC\u30F3\u30B8\uFF09 */
|
|
5689
|
+
font-weight: bold;
|
|
5690
|
+
opacity: 1.0;
|
|
5498
5691
|
}
|
|
5499
|
-
.dtm-load-note::before { content: "\
|
|
5692
|
+
.dtm-load-note::before { content: "\u26A0 "; }
|
|
5500
5693
|
.dtm-grow { flex: 1 1 auto; }
|
|
5501
5694
|
.dtm-lyric-icon {
|
|
5502
5695
|
flex: 0 0 auto;
|
|
@@ -5897,6 +6090,7 @@ var STEPS_PER_BEAT3 = 48;
|
|
|
5897
6090
|
var STEPS_PER_BAR = 192;
|
|
5898
6091
|
var DEFAULT_TRACK_COLORS = ["#00e436", "#29adff", "#ff77a8", "#ffec27"];
|
|
5899
6092
|
var activePlayer = null;
|
|
6093
|
+
var agreedModelsInSession = /* @__PURE__ */ new Set();
|
|
5900
6094
|
var LYRIC_MODEL_LABELS = {
|
|
5901
6095
|
klatt: "\u8EFD\u91CF\u30ED\u30DC\u58F0",
|
|
5902
6096
|
...KOE_VOICEBANK_LABELS
|
|
@@ -6013,6 +6207,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6013
6207
|
const drumPatternDict = options.drumPatterns ?? DRUM_PATTERNS;
|
|
6014
6208
|
const drumPattern = meta.drum ? drumPatternDict[meta.drum] ?? null : null;
|
|
6015
6209
|
const trackVolume = meta.volume ?? options.volume ?? 100;
|
|
6210
|
+
const drumVolume = meta.drumVolume ?? 80;
|
|
6016
6211
|
const colors = options.trackColors ?? DEFAULT_TRACK_COLORS;
|
|
6017
6212
|
const useSynth = options.synth ?? !options.onPlayNote;
|
|
6018
6213
|
const secondsPerStep = 60 / bpm / STEPS_PER_BEAT3;
|
|
@@ -6152,16 +6347,21 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6152
6347
|
const menuDropdown = doc.createElement("div");
|
|
6153
6348
|
menuDropdown.className = "dtm-player-menu";
|
|
6154
6349
|
menuDropdown.style.display = "none";
|
|
6155
|
-
const
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6350
|
+
const makeMenuItem = (label) => {
|
|
6351
|
+
const item = doc.createElement("button");
|
|
6352
|
+
item.type = "button";
|
|
6353
|
+
item.className = "dtm-player-menu-item";
|
|
6354
|
+
item.textContent = label;
|
|
6355
|
+
return item;
|
|
6356
|
+
};
|
|
6357
|
+
const showMmlItem = makeMenuItem("MML\u3092\u8868\u793A");
|
|
6358
|
+
const mmlInfoItem = makeMenuItem("MML\u66F8\u5F0F\u3068\u306F");
|
|
6359
|
+
const embedItem = makeMenuItem("\u57CB\u3081\u8FBC\u3080");
|
|
6360
|
+
const copyMmlItem = makeMenuItem("MML\u30B3\u30D4\u30FC");
|
|
6361
|
+
menuDropdown.appendChild(showMmlItem);
|
|
6362
|
+
menuDropdown.appendChild(mmlInfoItem);
|
|
6164
6363
|
menuDropdown.appendChild(embedItem);
|
|
6364
|
+
menuDropdown.appendChild(copyMmlItem);
|
|
6165
6365
|
menuContainer.appendChild(menuDropdown);
|
|
6166
6366
|
mmlHeader.appendChild(menuContainer);
|
|
6167
6367
|
const toggleMenu = (show) => {
|
|
@@ -6184,38 +6384,200 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6184
6384
|
e.stopPropagation();
|
|
6185
6385
|
toggleMenu();
|
|
6186
6386
|
});
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
if (
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6387
|
+
let infoModalEl = null;
|
|
6388
|
+
let modalSamplePlayer = null;
|
|
6389
|
+
const closeInfoModal = () => {
|
|
6390
|
+
if (modalSamplePlayer) {
|
|
6391
|
+
modalSamplePlayer.stop();
|
|
6392
|
+
modalSamplePlayer.destroy();
|
|
6393
|
+
modalSamplePlayer = null;
|
|
6394
|
+
}
|
|
6395
|
+
infoModalEl?.remove();
|
|
6396
|
+
infoModalEl = null;
|
|
6397
|
+
};
|
|
6398
|
+
const openInfoModal = (title) => {
|
|
6399
|
+
closeInfoModal();
|
|
6400
|
+
const overlay = doc.createElement("div");
|
|
6401
|
+
overlay.className = "dtm-modal-overlay";
|
|
6402
|
+
const modal = doc.createElement("div");
|
|
6403
|
+
modal.className = "dtm-win dtm-modal";
|
|
6404
|
+
const header = doc.createElement("div");
|
|
6405
|
+
header.className = "dtm-modal-header";
|
|
6406
|
+
const titleEl = doc.createElement("span");
|
|
6407
|
+
titleEl.className = "dtm-modal-title";
|
|
6408
|
+
titleEl.textContent = title;
|
|
6409
|
+
const closeBtn = doc.createElement("button");
|
|
6410
|
+
closeBtn.type = "button";
|
|
6411
|
+
closeBtn.className = "dtm-modal-close";
|
|
6412
|
+
closeBtn.innerHTML = "×";
|
|
6413
|
+
closeBtn.title = "\u9589\u3058\u308B";
|
|
6414
|
+
header.append(titleEl, closeBtn);
|
|
6415
|
+
const modalBody = doc.createElement("div");
|
|
6416
|
+
modalBody.className = "dtm-modal-body";
|
|
6417
|
+
modal.append(header, modalBody);
|
|
6418
|
+
overlay.appendChild(modal);
|
|
6419
|
+
closeBtn.addEventListener("click", (e) => {
|
|
6420
|
+
e.stopPropagation();
|
|
6421
|
+
closeInfoModal();
|
|
6422
|
+
});
|
|
6423
|
+
overlay.addEventListener("click", (e) => {
|
|
6424
|
+
if (e.target === overlay) closeInfoModal();
|
|
6425
|
+
});
|
|
6426
|
+
doc.body.appendChild(overlay);
|
|
6427
|
+
infoModalEl = overlay;
|
|
6428
|
+
return modalBody;
|
|
6429
|
+
};
|
|
6430
|
+
const appendCopyButton = (parent, text) => {
|
|
6431
|
+
const actions = doc.createElement("div");
|
|
6432
|
+
actions.style.marginTop = "8px";
|
|
6433
|
+
const copyBtn = doc.createElement("button");
|
|
6434
|
+
copyBtn.type = "button";
|
|
6435
|
+
copyBtn.className = "dtm-btn dtm-btn--primary dtm-btn--xs";
|
|
6436
|
+
copyBtn.textContent = "\u{1F4CB} \u30B3\u30D4\u30FC";
|
|
6437
|
+
copyBtn.addEventListener("click", async (e) => {
|
|
6438
|
+
e.stopPropagation();
|
|
6439
|
+
const ok = await copyToClipboard(doc, text);
|
|
6440
|
+
copyBtn.textContent = ok ? "\u2713 \u30B3\u30D4\u30FC\u5B8C\u4E86" : "\u30B3\u30D4\u30FC\u5931\u6557";
|
|
6441
|
+
if (ok) copyBtn.classList.add("dtm-btn--success");
|
|
6442
|
+
setTimeout(() => {
|
|
6443
|
+
copyBtn.textContent = "\u{1F4CB} \u30B3\u30D4\u30FC";
|
|
6444
|
+
copyBtn.classList.remove("dtm-btn--success");
|
|
6445
|
+
}, 1200);
|
|
6446
|
+
});
|
|
6447
|
+
actions.appendChild(copyBtn);
|
|
6448
|
+
parent.appendChild(actions);
|
|
6449
|
+
};
|
|
6450
|
+
const wireSampleButtons = (modalBody) => {
|
|
6451
|
+
const copyBtns = modalBody.querySelectorAll(".dtm-modal-sample-copy-btn");
|
|
6452
|
+
for (const btn of copyBtns) {
|
|
6453
|
+
const el = btn;
|
|
6454
|
+
el.addEventListener("click", async (e) => {
|
|
6455
|
+
e.stopPropagation();
|
|
6456
|
+
const sampleMml = el.getAttribute("data-mml") ?? "";
|
|
6457
|
+
const original = el.textContent;
|
|
6458
|
+
const ok = await copyToClipboard(doc, sampleMml);
|
|
6459
|
+
el.textContent = ok ? "\u2713 \u30B3\u30D4\u30FC\u5B8C\u4E86" : "\u30B3\u30D4\u30FC\u5931\u6557";
|
|
6460
|
+
if (ok) el.classList.add("dtm-btn--success");
|
|
6461
|
+
setTimeout(() => {
|
|
6462
|
+
el.textContent = original;
|
|
6463
|
+
el.classList.remove("dtm-btn--success");
|
|
6464
|
+
}, 1200);
|
|
6465
|
+
});
|
|
6194
6466
|
}
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6467
|
+
let activeSampleBtn = null;
|
|
6468
|
+
const resetSampleBtn = (b) => {
|
|
6469
|
+
if (!b) return;
|
|
6470
|
+
b.textContent = "\u25B6 \u8A66\u8074";
|
|
6471
|
+
b.classList.remove("dtm-btn--danger");
|
|
6472
|
+
b.classList.add("dtm-btn--primary");
|
|
6473
|
+
};
|
|
6474
|
+
const markPlaying = (b) => {
|
|
6475
|
+
b.textContent = "\u25A0 \u505C\u6B62";
|
|
6476
|
+
b.classList.remove("dtm-btn--primary");
|
|
6477
|
+
b.classList.add("dtm-btn--danger");
|
|
6478
|
+
};
|
|
6479
|
+
const playBtns = modalBody.querySelectorAll(".dtm-modal-sample-play-btn");
|
|
6480
|
+
for (const btn of playBtns) {
|
|
6481
|
+
const el = btn;
|
|
6482
|
+
el.addEventListener("click", (e) => {
|
|
6483
|
+
e.stopPropagation();
|
|
6484
|
+
const sampleMml = el.getAttribute("data-mml") ?? "";
|
|
6485
|
+
if (activeSampleBtn === el && modalSamplePlayer) {
|
|
6486
|
+
if (modalSamplePlayer.isPlaying()) {
|
|
6487
|
+
modalSamplePlayer.stop();
|
|
6488
|
+
} else {
|
|
6489
|
+
modalSamplePlayer.play();
|
|
6490
|
+
markPlaying(el);
|
|
6491
|
+
}
|
|
6492
|
+
return;
|
|
6493
|
+
}
|
|
6494
|
+
if (modalSamplePlayer) {
|
|
6495
|
+
modalSamplePlayer.stop();
|
|
6496
|
+
modalSamplePlayer.destroy();
|
|
6497
|
+
modalSamplePlayer = null;
|
|
6498
|
+
}
|
|
6499
|
+
resetSampleBtn(activeSampleBtn);
|
|
6500
|
+
activeSampleBtn = el;
|
|
6501
|
+
const sampleBox = el.closest(".dtm-modal-sample-box");
|
|
6502
|
+
const container = sampleBox?.querySelector(
|
|
6503
|
+
".dtm-modal-sample-player-container"
|
|
6504
|
+
);
|
|
6505
|
+
if (!container) return;
|
|
6506
|
+
container.innerHTML = "";
|
|
6507
|
+
modalSamplePlayer = mountMmlPlayer(container, sampleMml, {
|
|
6508
|
+
onPlayNote: options.onPlayNote,
|
|
6509
|
+
onPlayDrum: options.onPlayDrum,
|
|
6510
|
+
onResumeAudio: options.onResumeAudio,
|
|
6511
|
+
getAudioTime: options.getAudioTime,
|
|
6512
|
+
singingVoices: options.singingVoices,
|
|
6513
|
+
drumPatterns: options.drumPatterns,
|
|
6514
|
+
volume: trackVolume,
|
|
6515
|
+
// 解説モーダル内の試聴サンプルは規約同意を要求しない。
|
|
6516
|
+
skipConsent: true,
|
|
6517
|
+
onStop: () => {
|
|
6518
|
+
if (activeSampleBtn === el) resetSampleBtn(el);
|
|
6519
|
+
}
|
|
6520
|
+
});
|
|
6521
|
+
markPlaying(el);
|
|
6522
|
+
modalSamplePlayer.play();
|
|
6523
|
+
});
|
|
6524
|
+
}
|
|
6525
|
+
};
|
|
6526
|
+
showMmlItem.addEventListener("click", (e) => {
|
|
6527
|
+
e.stopPropagation();
|
|
6528
|
+
toggleMenu(false);
|
|
6529
|
+
const modalBody = openInfoModal("MML");
|
|
6530
|
+
const pre = doc.createElement("pre");
|
|
6531
|
+
pre.textContent = mml;
|
|
6532
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
6533
|
+
pre.style.wordBreak = "break-all";
|
|
6534
|
+
modalBody.appendChild(pre);
|
|
6535
|
+
appendCopyButton(modalBody, mml);
|
|
6536
|
+
});
|
|
6537
|
+
mmlInfoItem.addEventListener("click", (e) => {
|
|
6538
|
+
e.stopPropagation();
|
|
6539
|
+
toggleMenu(false);
|
|
6540
|
+
const modalBody = openInfoModal("MML\u306E\u66F8\u304D\u65B9\u89E3\u8AAC");
|
|
6541
|
+
modalBody.innerHTML = MML_INFO_HTML;
|
|
6542
|
+
wireSampleButtons(modalBody);
|
|
6198
6543
|
});
|
|
6199
6544
|
embedItem.addEventListener("click", async (e) => {
|
|
6200
6545
|
e.stopPropagation();
|
|
6201
|
-
|
|
6546
|
+
toggleMenu(false);
|
|
6547
|
+
const modalBody = openInfoModal("\u57CB\u3081\u8FBC\u307F");
|
|
6548
|
+
const loading = doc.createElement("p");
|
|
6549
|
+
loading.textContent = "\u751F\u6210\u4E2D...";
|
|
6550
|
+
modalBody.appendChild(loading);
|
|
6202
6551
|
try {
|
|
6203
6552
|
const embedBase = options.embedUrl ?? "https://onjmin.github.io/dtm/demo/embed.html";
|
|
6204
6553
|
const payload = await encodeMml(mml);
|
|
6205
6554
|
const url2 = `${embedBase}#${payload}`;
|
|
6206
6555
|
const snippet = `<iframe src="${url2}" width="100%" height="260" frameborder="0" loading="lazy" title="@onjmin/dtm player"></iframe>`;
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6556
|
+
if (!modalBody.isConnected) return;
|
|
6557
|
+
loading.remove();
|
|
6558
|
+
const desc = doc.createElement("p");
|
|
6559
|
+
desc.textContent = "\u3053\u306EHTML\u3092\u30D6\u30ED\u30B0\u3084\u30B5\u30A4\u30C8\u306B\u8CBC\u308A\u4ED8\u3051\u308B\u3068\u3001\u30D7\u30EC\u30A4\u30E4\u30FC\u3092\u305D\u306E\u307E\u307E\u57CB\u3081\u8FBC\u3081\u307E\u3059\u3002";
|
|
6560
|
+
const pre = doc.createElement("pre");
|
|
6561
|
+
pre.textContent = snippet;
|
|
6562
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
6563
|
+
pre.style.wordBreak = "break-all";
|
|
6564
|
+
modalBody.append(desc, pre);
|
|
6565
|
+
appendCopyButton(modalBody, snippet);
|
|
6213
6566
|
} catch (err2) {
|
|
6214
6567
|
console.error("[dtm] failed to generate embed snippet", err2);
|
|
6215
|
-
|
|
6568
|
+
if (modalBody.isConnected) loading.textContent = "\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F";
|
|
6569
|
+
}
|
|
6570
|
+
});
|
|
6571
|
+
copyMmlItem.addEventListener("click", async (e) => {
|
|
6572
|
+
e.stopPropagation();
|
|
6573
|
+
const success = await copyToClipboard(doc, mml);
|
|
6574
|
+
if (success) {
|
|
6575
|
+
copyMmlItem.textContent = "\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F\uFF01";
|
|
6576
|
+
} else {
|
|
6577
|
+
copyMmlItem.textContent = "\u30B3\u30D4\u30FC\u5931\u6557";
|
|
6216
6578
|
}
|
|
6217
6579
|
setTimeout(() => {
|
|
6218
|
-
|
|
6580
|
+
copyMmlItem.textContent = "MML\u30B3\u30D4\u30FC";
|
|
6219
6581
|
}, 2e3);
|
|
6220
6582
|
});
|
|
6221
6583
|
const promotedToImage = /* @__PURE__ */ new Set();
|
|
@@ -6461,6 +6823,77 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6461
6823
|
root.appendChild(termsDiv);
|
|
6462
6824
|
}
|
|
6463
6825
|
target.appendChild(root);
|
|
6826
|
+
let consentOverlayEl = null;
|
|
6827
|
+
const checkConsentAndShow = () => {
|
|
6828
|
+
try {
|
|
6829
|
+
if (options.skipConsent) return;
|
|
6830
|
+
const unagreed = termsModels.filter((model) => {
|
|
6831
|
+
if (agreedModelsInSession.has(model)) return false;
|
|
6832
|
+
try {
|
|
6833
|
+
if (typeof localStorage === "undefined" || !localStorage) return true;
|
|
6834
|
+
return localStorage.getItem(`dtm_agreed_terms_${model}`) !== "true";
|
|
6835
|
+
} catch (e) {
|
|
6836
|
+
console.warn(
|
|
6837
|
+
"[dtm-player] localStorage access denied in consent check",
|
|
6838
|
+
e
|
|
6839
|
+
);
|
|
6840
|
+
return true;
|
|
6841
|
+
}
|
|
6842
|
+
});
|
|
6843
|
+
if (unagreed.length === 0) return;
|
|
6844
|
+
const consentOverlay = doc.createElement("div");
|
|
6845
|
+
consentOverlay.className = "dtm-consent-overlay";
|
|
6846
|
+
const modal = doc.createElement("div");
|
|
6847
|
+
modal.className = "dtm-win dtm-consent-modal";
|
|
6848
|
+
const header = doc.createElement("div");
|
|
6849
|
+
header.className = "dtm-consent-header";
|
|
6850
|
+
header.textContent = "\u5229\u7528\u898F\u7D04\u306E\u78BA\u8A8D";
|
|
6851
|
+
const body2 = doc.createElement("div");
|
|
6852
|
+
body2.className = "dtm-consent-body";
|
|
6853
|
+
let contentHTML = `<p style="margin: 0 0 8px 0; line-height: 1.4; font-weight: bold; color: var(--dtm-danger);">\u672C\u30C7\u30FC\u30BF\u306B\u306F UTAU \u6B4C\u58F0\u97F3\u6E90\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\u3002<br>\u3054\u5229\u7528\u306B\u3042\u305F\u3063\u3066\u306F\u3001\u4EE5\u4E0B\u306E\u97F3\u6E90\u5229\u7528\u898F\u7D04\u3078\u306E\u540C\u610F\u304C\u5FC5\u8981\u3067\u3059\u3002</p>`;
|
|
6854
|
+
for (const model of unagreed) {
|
|
6855
|
+
const label = KOE_VOICEBANK_LABELS[model] || model;
|
|
6856
|
+
const url2 = KOE_VOICEBANK_TERMS[model];
|
|
6857
|
+
contentHTML += `
|
|
6858
|
+
<div style="margin-bottom: 8px; padding: 6px 10px; background: var(--dtm-deep); border: 2px solid var(--c-black); box-shadow: 2px 2px 0 var(--c-black);">
|
|
6859
|
+
<div style="display: flex; align-items: center; gap: 4px; flex-wrap: wrap; font-size: 11px; font-weight: bold; color: var(--dtm-gold);">
|
|
6860
|
+
<span>\u4F7F\u7528\u6642\u306B\u306F</span>
|
|
6861
|
+
<a href="${url2}" target="_blank" rel="noopener noreferrer" style="color: var(--dtm-primary); text-decoration: underline;">${label}UTAU\u97F3\u6E90</a>
|
|
6862
|
+
<span>\u306E\u5229\u7528\u898F\u7D04\u306B\u5F93\u3063\u3066\u304F\u3060\u3055\u3044</span>
|
|
6863
|
+
</div>
|
|
6864
|
+
</div>
|
|
6865
|
+
`;
|
|
6866
|
+
}
|
|
6867
|
+
body2.innerHTML = contentHTML;
|
|
6868
|
+
const footer = doc.createElement("div");
|
|
6869
|
+
footer.className = "dtm-consent-footer";
|
|
6870
|
+
const btn = doc.createElement("button");
|
|
6871
|
+
btn.type = "button";
|
|
6872
|
+
btn.className = "dtm-btn dtm-btn--success";
|
|
6873
|
+
btn.textContent = "\u540C\u610F\u3057\u3066\u5229\u7528\u3059\u308B";
|
|
6874
|
+
btn.onclick = () => {
|
|
6875
|
+
for (const model of unagreed) {
|
|
6876
|
+
try {
|
|
6877
|
+
if (typeof localStorage !== "undefined" && localStorage) {
|
|
6878
|
+
localStorage.setItem(`dtm_agreed_terms_${model}`, "true");
|
|
6879
|
+
}
|
|
6880
|
+
} catch (e) {
|
|
6881
|
+
}
|
|
6882
|
+
agreedModelsInSession.add(model);
|
|
6883
|
+
}
|
|
6884
|
+
consentOverlay.remove();
|
|
6885
|
+
consentOverlayEl = null;
|
|
6886
|
+
};
|
|
6887
|
+
footer.appendChild(btn);
|
|
6888
|
+
modal.append(header, body2, footer);
|
|
6889
|
+
consentOverlay.appendChild(modal);
|
|
6890
|
+
doc.body.appendChild(consentOverlay);
|
|
6891
|
+
consentOverlayEl = consentOverlay;
|
|
6892
|
+
} catch (err2) {
|
|
6893
|
+
console.error("[dtm-player] Error in checkConsentAndShow:", err2);
|
|
6894
|
+
}
|
|
6895
|
+
};
|
|
6896
|
+
checkConsentAndShow();
|
|
6464
6897
|
const autoScroll = (lane, el) => {
|
|
6465
6898
|
if (el.offsetWidth === 0 || lane.clientWidth === 0) return;
|
|
6466
6899
|
const elementCenter = el.offsetLeft + el.offsetWidth / 2;
|
|
@@ -6519,7 +6952,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6519
6952
|
if (useSynth) ensureSynth().playNote(e);
|
|
6520
6953
|
},
|
|
6521
6954
|
onPlayDrum: (e) => {
|
|
6522
|
-
const velocity = e.velocity * (trackVolume / 100);
|
|
6955
|
+
const velocity = e.velocity * (drumVolume / 100) * (trackVolume / 100);
|
|
6523
6956
|
options.onPlayDrum?.({ ...e, velocity });
|
|
6524
6957
|
if (useSynth) ensureSynth().playDrum({ ...e, velocity });
|
|
6525
6958
|
},
|
|
@@ -6635,6 +7068,8 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6635
7068
|
hideActiveBalloon();
|
|
6636
7069
|
}
|
|
6637
7070
|
root.remove();
|
|
7071
|
+
consentOverlayEl?.remove();
|
|
7072
|
+
closeInfoModal();
|
|
6638
7073
|
};
|
|
6639
7074
|
const instance = {
|
|
6640
7075
|
play,
|
|
@@ -6676,108 +7111,6 @@ var CHORD_INFO_HTML = `
|
|
|
6676
7111
|
</ul>
|
|
6677
7112
|
</div>
|
|
6678
7113
|
`;
|
|
6679
|
-
var MML_INFO_HTML = `
|
|
6680
|
-
<div class="dtm-modal-body-content">
|
|
6681
|
-
<h4>1. \u97F3\u7B26\u3068\u4F11\u7B26</h4>
|
|
6682
|
-
<p><code>c</code>(\u30C9) <code>d</code>(\u30EC) <code>e</code>(\u30DF) <code>f</code>(\u30D5\u30A1) <code>g</code>(\u30BD) <code>a</code>(\u30E9) <code>b</code>(\u30B7) \u306E\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8\u3067\u8868\u3057\u307E\u3059\u3002</p>
|
|
6683
|
-
<ul>
|
|
6684
|
-
<li>\u534A\u97F3\u4E0A\u3052\u308B: <code>c#</code> \u307E\u305F\u306F <code>c+</code></li>
|
|
6685
|
-
<li>\u534A\u97F3\u4E0B\u3052\u308B: <code>d-</code></li>
|
|
6686
|
-
<li>\u4F11\u7B26: <code>r</code></li>
|
|
6687
|
-
</ul>
|
|
6688
|
-
|
|
6689
|
-
<h4>2. \u97F3\u306E\u9577\u3055</h4>
|
|
6690
|
-
<p>\u97F3\u540D\u3084\u4F11\u7B26\u306E\u5F8C\u306B\u6570\u5024\u3067\u6307\u5B9A\u3057\u307E\u3059\uFF08\u4F8B: <code>4</code> = 4\u5206\u97F3\u7B26, <code>8</code> = 8\u5206\u97F3\u7B26, <code>16</code> = 16\u5206\u97F3\u7B26\uFF09\u3002</p>
|
|
6691
|
-
<ul>
|
|
6692
|
-
<li><code>c4</code> : 4\u5206\u97F3\u7B26\u306E\u30C9</li>
|
|
6693
|
-
<li><code>r8</code> : 8\u5206\u4F11\u7B26</li>
|
|
6694
|
-
<li><code>c4.</code> : \u4ED8\u70B94\u5206\u97F3\u7B26\u306E\u30C9\uFF08\u9577\u3055\u30921.5\u500D\u306B\uFF09</li>
|
|
6695
|
-
<li>\u6570\u5024\u3092\u7701\u7565\u3059\u308B\u3068\u3001<code>l</code> \u30B3\u30DE\u30F3\u30C9\u3067\u8A2D\u5B9A\u3055\u308C\u305F\u30C7\u30D5\u30A9\u30EB\u30C8\u9577\uFF08\u901A\u5E3816\u5206\uFF09\u306B\u306A\u308A\u307E\u3059\u3002</li>
|
|
6696
|
-
</ul>
|
|
6697
|
-
|
|
6698
|
-
<h4>3. \u30AA\u30AF\u30BF\u30FC\u30D6\uFF08\u97F3\u306E\u9AD8\u3055\uFF09</h4>
|
|
6699
|
-
<ul>
|
|
6700
|
-
<li><code>o4</code>, <code>o5</code> : \u9AD8\u3055\u3092\u76F4\u63A5\u6307\u5B9A\uFF08\u3075\u3064\u3046\u306F o4 \u304B o5\uFF09</li>
|
|
6701
|
-
<li><code>></code> : 1\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0A\u3052\u308B</li>
|
|
6702
|
-
<li><code><</code> : 1\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0B\u3052\u308B</li>
|
|
6703
|
-
</ul>
|
|
6704
|
-
|
|
6705
|
-
<h4>4. \u30C6\u30F3\u30DD</h4>
|
|
6706
|
-
<ul>
|
|
6707
|
-
<li><code>t120</code> : \u66F2\u306E\u901F\u3055\u3092BPM120\u306B\u6307\u5B9A\u3002\u203B\u30E1\u30ED\u30C7\u30A3\uFF08@0\uFF09\u306E\u30C6\u30F3\u30DD\u6307\u5B9A\u304C\u66F2\u5168\u4F53\u306B\u53CD\u6620\u3055\u308C\u307E\u3059\u3002</li>
|
|
6708
|
-
</ul>
|
|
6709
|
-
|
|
6710
|
-
<h4>5. \u548C\u97F3</h4>
|
|
6711
|
-
<p>\u97F3\u7B26\u3092 <code>[</code> \u3068 <code>]</code> \u3067\u56F2\u3080\u3068\u540C\u6642\u306B\u767A\u97F3\u3057\u307E\u3059\u3002</p>
|
|
6712
|
-
<pre>\u4F8B: [ceg]4 \uFF08\u30C9\u30FB\u30DF\u30FB\u30BD\u30924\u5206\u97F3\u7B26\u3067\u540C\u6642\u306B\u767A\u97F3\uFF09</pre>
|
|
6713
|
-
|
|
6714
|
-
<h4>6. \u30C8\u30E9\u30C3\u30AF\u306E\u533A\u5207\u308A</h4>
|
|
6715
|
-
<p><code>;</code> \u307E\u305F\u306F <code>@0</code>\u301C<code>@3</code> \u3067\u30C8\u30E9\u30C3\u30AF\u3092\u5207\u308A\u66FF\u3048\u307E\u3059\u3002</p>
|
|
6716
|
-
<ul>
|
|
6717
|
-
<li><code>@0</code>: \u30E1\u30ED\u30C7\u30A3</li>
|
|
6718
|
-
<li><code>@1</code>: \u30B5\u30D6\u30E1\u30ED</li>
|
|
6719
|
-
<li><code>@2</code>: \u30D9\u30FC\u30B9</li>
|
|
6720
|
-
<li><code>@3</code>: \u4F34\u594F</li>
|
|
6721
|
-
</ul>
|
|
6722
|
-
|
|
6723
|
-
<h4>7. \u6B4C\u58F0\u30FB\u6B4C\u8A5E\u5165\u529B</h4>
|
|
6724
|
-
<p><code>@@<\u30C8\u30E9\u30C3\u30AF\u756A\u53F7> <\u97F3\u6E90\u540D> <\u6B4C\u8A5E></code> \u306E\u5F62\u5F0F\u3067\u3001\u97F3\u7B26\u3068\u540C\u671F\u3059\u308B\u6B4C\u8A5E\u3092\u5165\u529B\u3067\u304D\u307E\u3059\u3002</p>
|
|
6725
|
-
<pre>\u4F8B: @@0 tsukuyomi \u3069\u3093\u3050\u308A\u3053\u308D\u3053\u308D\u3069\u3093\u3050\u308A\u3053</pre>
|
|
6726
|
-
<p style="margin-top:4px; margin-bottom:16px;"><small>\uFF08\u97F3\u6E90\u540D\u306F <code>tsukuyomi</code> \u3084 <code>klatt</code>, <code>roze</code> \u306A\u3069\u306E\u97F3\u58F0\u30E2\u30C7\u30EB\u3092\u6307\u5B9A\u3067\u304D\u307E\u3059\uFF09</small></p>
|
|
6727
|
-
|
|
6728
|
-
<h4 style="margin-top: 18px; border-top: 1px solid var(--dtm-border2); padding-top: 8px;">\u30B5\u30F3\u30D7\u30EB\u66F2\uFF08\u8A66\u8074\u30FB\u30B3\u30D4\u30FC\uFF09</h4>
|
|
6729
|
-
|
|
6730
|
-
<!-- \u30B5\u30F3\u30D7\u30EB1 -->
|
|
6731
|
-
<div class="dtm-modal-sample-box">
|
|
6732
|
-
<div class="dtm-modal-sample-header">
|
|
6733
|
-
<span class="dtm-modal-sample-tag">1. \u57FA\u672C\u306E\u30E1\u30ED\u30C7\u30A3</span>
|
|
6734
|
-
<button class="dtm-btn dtm-btn--ghost dtm-btn--xs dtm-modal-sample-copy-btn" data-mml="@0 t120 l8 o5 c d e f g a b > c">\u{1F4CB} \u30B3\u30D4\u30FC</button>
|
|
6735
|
-
</div>
|
|
6736
|
-
<pre style="margin: 0; padding: 6px;">@0 t120 l8 o5 c d e f g a b > c</pre>
|
|
6737
|
-
<div class="dtm-modal-sample-desc">
|
|
6738
|
-
\u57FA\u672C\u7684\u306A\u30E1\u30ED\u30C7\u30A3\u306E\u66F8\u304D\u65B9\uFF08\u97F3\u540D\u30FB\u9577\u3055\u30FB\u30AA\u30AF\u30BF\u30FC\u30D6\u3068\u30C6\u30F3\u30DD\uFF09\u3002
|
|
6739
|
-
</div>
|
|
6740
|
-
<div style="margin-top: 8px;">
|
|
6741
|
-
<button class="dtm-btn dtm-btn--primary dtm-btn--xs dtm-modal-sample-play-btn" data-mml="@0 t120 l8 o5 c d e f g a b > c">\u25B6 \u8A66\u8074</button>
|
|
6742
|
-
</div>
|
|
6743
|
-
<div class="dtm-modal-sample-player-container"></div>
|
|
6744
|
-
</div>
|
|
6745
|
-
|
|
6746
|
-
<!-- \u30B5\u30F3\u30D7\u30EB2 -->
|
|
6747
|
-
<div class="dtm-modal-sample-box">
|
|
6748
|
-
<div class="dtm-modal-sample-header">
|
|
6749
|
-
<span class="dtm-modal-sample-tag">2. \u8907\u6570\u30C8\u30E9\u30C3\u30AF\u3068\u548C\u97F3</span>
|
|
6750
|
-
<button class="dtm-btn dtm-btn--ghost dtm-btn--xs dtm-modal-sample-copy-btn" data-mml="@0 t120 o5 c e g2 ; @3 o4 [ceg]2 [ceg]2">\u{1F4CB} \u30B3\u30D4\u30FC</button>
|
|
6751
|
-
</div>
|
|
6752
|
-
<pre style="margin: 0; padding: 6px;">@0 t120 o5 c e g2 ;
|
|
6753
|
-
@3 o4 [ceg]2 [ceg]2</pre>
|
|
6754
|
-
<div class="dtm-modal-sample-desc">
|
|
6755
|
-
; \u3067\u30C8\u30E9\u30C3\u30AF\uFF08\u4E0A\uFF1D\u30E1\u30ED\u30C7\u30A3\uFF0F\u4E0B\uFF1D\u4F34\u594F\uFF09\u3092\u5206\u3051\u3001[ceg] \u3067\u548C\u97F3\u3092\u9CF4\u3089\u3057\u307E\u3059\u3002
|
|
6756
|
-
</div>
|
|
6757
|
-
<div style="margin-top: 8px;">
|
|
6758
|
-
<button class="dtm-btn dtm-btn--primary dtm-btn--xs dtm-modal-sample-play-btn" data-mml="@0 t120 o5 c e g2 ; @3 o4 [ceg]2 [ceg]2">\u25B6 \u8A66\u8074</button>
|
|
6759
|
-
</div>
|
|
6760
|
-
<div class="dtm-modal-sample-player-container"></div>
|
|
6761
|
-
</div>
|
|
6762
|
-
|
|
6763
|
-
<!-- \u30B5\u30F3\u30D7\u30EB3 -->
|
|
6764
|
-
<div class="dtm-modal-sample-box">
|
|
6765
|
-
<div class="dtm-modal-sample-header">
|
|
6766
|
-
<span class="dtm-modal-sample-tag">3. \u6B4C\u5531\u4ED8\u304D (\u3069\u3093\u3050\u308A\u3053\u308D\u3053\u308D)</span>
|
|
6767
|
-
<button class="dtm-btn dtm-btn--ghost dtm-btn--xs dtm-modal-sample-copy-btn" data-mml="@0 t120 v100 o4g8 g8 e8 e8 f8 e8 d8 c8 g8 g8 e8 e8 d4.; @@0 tsukuyomi \u3069\u3093\u3050\u308A\u3053\u308D\u3053\u308D\u3069\u3093\u3050\u308A\u3053;">\u{1F4CB} \u30B3\u30D4\u30FC</button>
|
|
6768
|
-
</div>
|
|
6769
|
-
<pre style="margin: 0; padding: 6px;">@0 t120 v100 o4g8 g8 e8 e8 f8 e8 d8 c8 g8 g8 e8 e8 d4.;
|
|
6770
|
-
@@0 tsukuyomi \u3069\u3093\u3050\u308A\u3053\u308D\u3053\u308D\u3069\u3093\u3050\u308A\u3053;</pre>
|
|
6771
|
-
<div class="dtm-modal-sample-desc">
|
|
6772
|
-
@@0 tsukuyomi \u6B4C\u8A5E... \u3067\u30E1\u30ED\u30C7\u30A3\u30C8\u30E9\u30C3\u30AF\u306B\u6B4C\u8A5E\u3092\u540C\u671F\u3055\u305B\u3066\u6B4C\u308F\u305B\u307E\u3059\u3002\u203B\u72EC\u81EA\u62E1\u5F35
|
|
6773
|
-
</div>
|
|
6774
|
-
<div style="margin-top: 8px;">
|
|
6775
|
-
<button class="dtm-btn dtm-btn--primary dtm-btn--xs dtm-modal-sample-play-btn" data-mml="@0 t120 v100 o4g8 g8 e8 e8 f8 e8 d8 c8 g8 g8 e8 e8 d4.; @@0 tsukuyomi \u3069\u3093\u3050\u308A\u3053\u308D\u3053\u308D\u3069\u3093\u3050\u308A\u3053;">\u25B6 \u8A66\u8074</button>
|
|
6776
|
-
</div>
|
|
6777
|
-
<div class="dtm-modal-sample-player-container"></div>
|
|
6778
|
-
</div>
|
|
6779
|
-
</div>
|
|
6780
|
-
`;
|
|
6781
7114
|
var MIDI_INFO_HTML = `
|
|
6782
7115
|
<div class="dtm-modal-body-content">
|
|
6783
7116
|
<h4>1. MIDI\u30D5\u30A1\u30A4\u30EB\u3068\u306F</h4>
|
|
@@ -7721,7 +8054,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
7721
8054
|
};
|
|
7722
8055
|
const updateTransport = () => {
|
|
7723
8056
|
const playing = playbackState === "playing";
|
|
7724
|
-
const label = playing ? "\
|
|
8057
|
+
const label = playing ? "\u505C\u6B62" : playbackState === "paused" ? "\u518D\u958B" : "\u8A66\u8074";
|
|
7725
8058
|
refs.playBtn.innerHTML = `${icon(playing ? "pause" : "play")}<span>${label}</span>`;
|
|
7726
8059
|
refs.playBtn.classList.toggle("dtm-play--stop", playing);
|
|
7727
8060
|
};
|
|
@@ -7989,6 +8322,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
7989
8322
|
instrument: currentInstrument || void 0,
|
|
7990
8323
|
drum: currentDrumPattern !== "none" ? currentDrumPattern : void 0,
|
|
7991
8324
|
volume: masterVolume,
|
|
8325
|
+
drumVolume,
|
|
7992
8326
|
mode
|
|
7993
8327
|
});
|
|
7994
8328
|
if (refs.decomposeChordToggle.checked) {
|
|
@@ -8140,6 +8474,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
8140
8474
|
refs.masterVolume.value = String(meta.volume);
|
|
8141
8475
|
refs.masterVolumeLabel.textContent = `${meta.volume}%`;
|
|
8142
8476
|
}
|
|
8477
|
+
if (meta.drumVolume !== void 0) {
|
|
8478
|
+
drumVolume = meta.drumVolume;
|
|
8479
|
+
refs.drumVolume.value = String(meta.drumVolume);
|
|
8480
|
+
refs.drumVolumeLabel.textContent = `${meta.drumVolume}%`;
|
|
8481
|
+
}
|
|
8143
8482
|
for (const t of trackStates) {
|
|
8144
8483
|
t.lyrics = "";
|
|
8145
8484
|
t.lyricModel = "";
|
|
@@ -8148,8 +8487,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
8148
8487
|
t.vocalPan = 64;
|
|
8149
8488
|
t.vocalOctave = 0;
|
|
8150
8489
|
}
|
|
8151
|
-
lyrics?.forEach((lt
|
|
8152
|
-
const t = trackStates[
|
|
8490
|
+
lyrics?.forEach((lt) => {
|
|
8491
|
+
const t = trackStates[lt.trackId];
|
|
8153
8492
|
if (!t) return;
|
|
8154
8493
|
t.lyrics = lt.syllables.map((s) => s.kana).join("");
|
|
8155
8494
|
t.lyricModel = lt.model;
|
|
@@ -8293,8 +8632,17 @@ var mountDAW = (target, options = {}) => {
|
|
|
8293
8632
|
const wireEvents = () => {
|
|
8294
8633
|
refs.playBtn.addEventListener("click", togglePlay);
|
|
8295
8634
|
refs.playBtn.disabled = false;
|
|
8296
|
-
refs.
|
|
8297
|
-
|
|
8635
|
+
refs.prevBarBtn.addEventListener("click", () => {
|
|
8636
|
+
const targetStep = Math.max(
|
|
8637
|
+
0,
|
|
8638
|
+
Math.floor((getCurrentPlayStep() - 1) / renderConfig.stepsPerBar) * renderConfig.stepsPerBar
|
|
8639
|
+
);
|
|
8640
|
+
jumpTo(targetStep);
|
|
8641
|
+
});
|
|
8642
|
+
refs.nextBarBtn.addEventListener("click", () => {
|
|
8643
|
+
const targetStep = Math.floor(getCurrentPlayStep() / renderConfig.stepsPerBar + 1) * renderConfig.stepsPerBar;
|
|
8644
|
+
jumpTo(targetStep);
|
|
8645
|
+
});
|
|
8298
8646
|
refs.soloCheckbox.addEventListener("change", () => {
|
|
8299
8647
|
isSolo = refs.soloCheckbox.checked;
|
|
8300
8648
|
});
|
|
@@ -8657,6 +9005,20 @@ var mountDAW = (target, options = {}) => {
|
|
|
8657
9005
|
if (playbackState === "paused") return pausedPlayStep;
|
|
8658
9006
|
return playStartStep;
|
|
8659
9007
|
};
|
|
9008
|
+
const jumpTo = async (step) => {
|
|
9009
|
+
const wasPlaying = playbackState === "playing";
|
|
9010
|
+
if (wasPlaying) {
|
|
9011
|
+
sequencer.stop();
|
|
9012
|
+
options.singingVoices?.stopStream();
|
|
9013
|
+
playStartStep = step;
|
|
9014
|
+
pausedPlayStep = step;
|
|
9015
|
+
currentPlayStep = step;
|
|
9016
|
+
playbackState = "paused";
|
|
9017
|
+
await play();
|
|
9018
|
+
} else {
|
|
9019
|
+
forcePauseAt(step);
|
|
9020
|
+
}
|
|
9021
|
+
};
|
|
8660
9022
|
const forcePauseAt = (step) => {
|
|
8661
9023
|
playStartStep = step;
|
|
8662
9024
|
pausedPlayStep = step;
|
|
@@ -8731,6 +9093,7 @@ var playMML = (mml, options = {}) => {
|
|
|
8731
9093
|
const drumPatternDict = options.drumPatterns ?? DRUM_PATTERNS;
|
|
8732
9094
|
const drumPattern = meta.drum ? drumPatternDict[meta.drum] ?? null : null;
|
|
8733
9095
|
let masterVolume = meta.volume ?? options.volume ?? 100;
|
|
9096
|
+
let drumVolume = meta.drumVolume ?? 80;
|
|
8734
9097
|
const trackIndices = [...new Set(placements.map((p) => p.trackIndex))].sort(
|
|
8735
9098
|
(a, b) => a - b
|
|
8736
9099
|
);
|
|
@@ -8767,7 +9130,7 @@ var playMML = (mml, options = {}) => {
|
|
|
8767
9130
|
synth?.playNote(e);
|
|
8768
9131
|
},
|
|
8769
9132
|
onPlayDrum: (e) => {
|
|
8770
|
-
const velocity = e.velocity * (masterVolume / 100);
|
|
9133
|
+
const velocity = e.velocity * (drumVolume / 100) * (masterVolume / 100);
|
|
8771
9134
|
options.onPlayDrum?.({ ...e, velocity });
|
|
8772
9135
|
synth?.playDrum({ ...e, velocity });
|
|
8773
9136
|
},
|
|
@@ -9326,7 +9689,6 @@ var importFrom = async (url2, name) => {
|
|
|
9326
9689
|
var createDtmStudio = async (options = {}) => {
|
|
9327
9690
|
const cdn = { ...DEFAULT_CDN, ...options.cdn };
|
|
9328
9691
|
const features = {
|
|
9329
|
-
recorder: true,
|
|
9330
9692
|
midi: true,
|
|
9331
9693
|
chord: true,
|
|
9332
9694
|
presetUI: true,
|
|
@@ -9365,68 +9727,6 @@ var createDtmStudio = async (options = {}) => {
|
|
|
9365
9727
|
const singingVoices = createSingingVoices(audioCtx, masterGain, {
|
|
9366
9728
|
voiceWorkerUrl
|
|
9367
9729
|
});
|
|
9368
|
-
const recorder = features.recorder ? setupRecorder(audioCtx, masterGain, drumGain) : null;
|
|
9369
|
-
const downloadWav = () => {
|
|
9370
|
-
if (!recorder) return;
|
|
9371
|
-
const recordedData = recorder.getRecordedData();
|
|
9372
|
-
const ch = recordedData.length;
|
|
9373
|
-
const len = recordedData[0].length;
|
|
9374
|
-
if (len === 0) return;
|
|
9375
|
-
const bufSize = recordedData[0][0].length;
|
|
9376
|
-
const wave = new Float32Array(ch * len * bufSize);
|
|
9377
|
-
let idx = 0;
|
|
9378
|
-
for (let i = 0; i < len; i++)
|
|
9379
|
-
for (let j = 0; j < bufSize; j++)
|
|
9380
|
-
for (let k = 0; k < ch; k++) wave[idx++] = recordedData[k][i][j];
|
|
9381
|
-
const sampleRate = audioCtx.sampleRate;
|
|
9382
|
-
const channels = 2;
|
|
9383
|
-
const bitRate = 16;
|
|
9384
|
-
const step = bitRate / 8;
|
|
9385
|
-
const blockSize = channels * step;
|
|
9386
|
-
const byteLen = wave.length * step;
|
|
9387
|
-
const view = new DataView(new ArrayBuffer(44 + byteLen));
|
|
9388
|
-
const ws = (off2, s) => {
|
|
9389
|
-
for (let i = 0; i < s.length; i++)
|
|
9390
|
-
view.setUint8(off2 + i, s.charCodeAt(i));
|
|
9391
|
-
};
|
|
9392
|
-
ws(0, "RIFF");
|
|
9393
|
-
view.setUint32(4, 32 + byteLen, true);
|
|
9394
|
-
ws(8, "WAVE");
|
|
9395
|
-
ws(12, "fmt ");
|
|
9396
|
-
view.setUint32(16, 16, true);
|
|
9397
|
-
view.setUint16(20, 1, true);
|
|
9398
|
-
view.setUint16(22, channels, true);
|
|
9399
|
-
view.setUint32(24, sampleRate, true);
|
|
9400
|
-
view.setUint32(28, sampleRate * blockSize, true);
|
|
9401
|
-
view.setUint16(32, blockSize, true);
|
|
9402
|
-
view.setUint16(34, bitRate, true);
|
|
9403
|
-
ws(36, "data");
|
|
9404
|
-
view.setUint32(40, byteLen, true);
|
|
9405
|
-
const clamp4 = (n, a2, b) => Math.max(a2, Math.min(b, n));
|
|
9406
|
-
let off = 44;
|
|
9407
|
-
for (let i = 0; i < wave.length; i++, off += step)
|
|
9408
|
-
view.setInt16(
|
|
9409
|
-
off,
|
|
9410
|
-
clamp4(Math.round(wave[i] * 32768), -32768, 32767),
|
|
9411
|
-
true
|
|
9412
|
-
);
|
|
9413
|
-
const blob2 = new Blob([view], { type: "audio/wav" });
|
|
9414
|
-
const url2 = URL.createObjectURL(blob2);
|
|
9415
|
-
const a = document.createElement("a");
|
|
9416
|
-
a.href = url2;
|
|
9417
|
-
a.download = "record.wav";
|
|
9418
|
-
a.click();
|
|
9419
|
-
URL.revokeObjectURL(url2);
|
|
9420
|
-
};
|
|
9421
|
-
const onToggleRecord = recorder ? () => {
|
|
9422
|
-
if (recorder.isRecording()) {
|
|
9423
|
-
recorder.stopRecording();
|
|
9424
|
-
downloadWav();
|
|
9425
|
-
} else {
|
|
9426
|
-
recorder.clearRecordedData();
|
|
9427
|
-
recorder.startRecording();
|
|
9428
|
-
}
|
|
9429
|
-
} : void 0;
|
|
9430
9730
|
const listReady = new Promise((resolve) => {
|
|
9431
9731
|
SoundFont_list.init();
|
|
9432
9732
|
SoundFont_list.onload(() => resolve());
|
|
@@ -9633,7 +9933,6 @@ var createDtmStudio = async (options = {}) => {
|
|
|
9633
9933
|
onPlayDrum: playDrum,
|
|
9634
9934
|
singingVoices,
|
|
9635
9935
|
parseMidi,
|
|
9636
|
-
onToggleRecord,
|
|
9637
9936
|
onInstrumentChange: handleInstrumentChange,
|
|
9638
9937
|
...dawOverrides
|
|
9639
9938
|
};
|
|
@@ -9925,7 +10224,6 @@ var createDtmStudio = async (options = {}) => {
|
|
|
9925
10224
|
playMML,
|
|
9926
10225
|
playSingingMML,
|
|
9927
10226
|
setDrawOffset,
|
|
9928
|
-
setupRecorder,
|
|
9929
10227
|
shiftNotes,
|
|
9930
10228
|
stripLyrics,
|
|
9931
10229
|
stripMmlMeta,
|