@onjmin/dtm 0.1.51 → 0.1.55
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 +54 -18
- package/dist/index.d.ts +54 -18
- package/dist/index.js +608 -58
- package/dist/index.mjs +605 -58
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1215,7 +1215,13 @@ var icon = (name, size = 20) => {
|
|
|
1215
1215
|
// src/daw-ui.ts
|
|
1216
1216
|
var q = (root, sel) => root.querySelector(sel);
|
|
1217
1217
|
var buildUI = (target, options) => {
|
|
1218
|
-
const {
|
|
1218
|
+
const {
|
|
1219
|
+
drumPatternNames,
|
|
1220
|
+
defaultDrumPattern,
|
|
1221
|
+
defaultBpm,
|
|
1222
|
+
showMidi,
|
|
1223
|
+
showMidiSearch
|
|
1224
|
+
} = options;
|
|
1219
1225
|
const drumOptions = [`<option value="none">\u306A\u3057</option>`].concat(
|
|
1220
1226
|
drumPatternNames.map(
|
|
1221
1227
|
(name) => `<option value="${name}" ${name === defaultDrumPattern ? "selected" : ""}>${name}</option>`
|
|
@@ -1293,6 +1299,16 @@ var buildUI = (target, options) => {
|
|
|
1293
1299
|
<span class="dtm-label" data-dtm="zoomy-label">100%</span>
|
|
1294
1300
|
<button class="dtm-iconbtn" data-dtm="zoomy-in" title="\u62E1\u5927">\uFF0B</button>
|
|
1295
1301
|
</div>
|
|
1302
|
+
<div class="dtm-row">
|
|
1303
|
+
<span class="dtm-label">\u80CC\u666F\u753B\u50CF</span>
|
|
1304
|
+
<input type="file" accept="image/*" data-dtm="bg-file-input" class="dtm-hidden">
|
|
1305
|
+
<button class="dtm-btn dtm-btn--primary" data-dtm="bg-upload">\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9</button>
|
|
1306
|
+
<button class="dtm-btn dtm-btn--danger dtm-hidden" data-dtm="bg-remove">\u524A\u9664</button>
|
|
1307
|
+
</div>
|
|
1308
|
+
<div class="dtm-row dtm-hidden" data-dtm="bg-opacity-row">
|
|
1309
|
+
<span class="dtm-label">\u80CC\u666F\u4E0D\u900F\u660E\u5EA6</span>
|
|
1310
|
+
<input type="range" min="0" max="100" value="40" data-dtm="bg-opacity" class="dtm-slider">
|
|
1311
|
+
</div>
|
|
1296
1312
|
</div>
|
|
1297
1313
|
</details>
|
|
1298
1314
|
|
|
@@ -1331,6 +1347,9 @@ var buildUI = (target, options) => {
|
|
|
1331
1347
|
<textarea class="dtm-textarea dtm-grow" data-dtm="mml-input" placeholder="MML\u3092\u5165\u529B"></textarea>
|
|
1332
1348
|
<button class="dtm-btn dtm-btn--primary" data-dtm="mml-load" style="flex-shrink:0">\u8AAD\u8FBC</button>
|
|
1333
1349
|
</div>
|
|
1350
|
+
<div class="dtm-row" data-dtm="midi-search-row" style="justify-content:flex-end;${showMidiSearch ? "" : "display:none"}">
|
|
1351
|
+
<button class="dtm-btn dtm-btn--primary" data-dtm="midi-search-open">MML\u691C\u7D22</button>
|
|
1352
|
+
</div>
|
|
1334
1353
|
<p class="dtm-load-note dtm-hidden" data-dtm="mml-load-note"></p>
|
|
1335
1354
|
</div>
|
|
1336
1355
|
</details>
|
|
@@ -1441,6 +1460,11 @@ var buildUI = (target, options) => {
|
|
|
1441
1460
|
zoomXOut: sel("zoomx-out"),
|
|
1442
1461
|
zoomYIn: sel("zoomy-in"),
|
|
1443
1462
|
zoomYOut: sel("zoomy-out"),
|
|
1463
|
+
bgFileInput: sel("bg-file-input"),
|
|
1464
|
+
bgUploadBtn: sel("bg-upload"),
|
|
1465
|
+
bgRemoveBtn: sel("bg-remove"),
|
|
1466
|
+
bgOpacityInput: sel("bg-opacity"),
|
|
1467
|
+
bgOpacityRow: sel("bg-opacity-row"),
|
|
1444
1468
|
rollContainer: sel("roll"),
|
|
1445
1469
|
wrapper: sel("wrapper"),
|
|
1446
1470
|
vScroll: sel("vscroll"),
|
|
@@ -1459,6 +1483,7 @@ var buildUI = (target, options) => {
|
|
|
1459
1483
|
midiInfoBtn: sel("midi-info"),
|
|
1460
1484
|
midiTrackSelection: sel("midi-track-selection"),
|
|
1461
1485
|
midiPanel: sel("midi-panel"),
|
|
1486
|
+
midiSearchOpenBtn: sel("midi-search-open"),
|
|
1462
1487
|
mmlInput: sel("mml-input"),
|
|
1463
1488
|
mmlLoadBtn: sel("mml-load"),
|
|
1464
1489
|
mmlLoadNote: sel("mml-load-note"),
|
|
@@ -2504,7 +2529,8 @@ var KOE_VOICEBANKS = {
|
|
|
2504
2529
|
shiyo: "\u9769\u547D\u30B7\u30E8.koe",
|
|
2505
2530
|
rei: "\u8DB3\u7ACB\u30EC\u30A4ver3.5.0.koe",
|
|
2506
2531
|
mgroid: "MGRoid_\u539F\u97F3\u8A2D\u5B9A\u6E08\u307F.koe",
|
|
2507
|
-
motroid: "MOTRoid\u5B8C\u5168\u7248V2.koe"
|
|
2532
|
+
motroid: "MOTRoid\u5B8C\u5168\u7248V2.koe",
|
|
2533
|
+
nynroid: "NYNRoidver1.4.koe"
|
|
2508
2534
|
};
|
|
2509
2535
|
var KOE_VOICEBANK_LABELS = {
|
|
2510
2536
|
tsukuyomi: "\u3064\u304F\u3088\u307F\u3061\u3083\u3093",
|
|
@@ -2516,7 +2542,8 @@ var KOE_VOICEBANK_LABELS = {
|
|
|
2516
2542
|
shiyo: "\u9769\u547D\u30B7\u30E8",
|
|
2517
2543
|
rei: "\u8DB3\u7ACB\u30EC\u30A4",
|
|
2518
2544
|
mgroid: "MGRoid",
|
|
2519
|
-
motroid: "MOTRoid"
|
|
2545
|
+
motroid: "MOTRoid",
|
|
2546
|
+
nynroid: "NYNRoid"
|
|
2520
2547
|
};
|
|
2521
2548
|
var VOICE_IMAGE_KEY = {
|
|
2522
2549
|
klatt: "puyuyu",
|
|
@@ -2529,7 +2556,8 @@ var VOICE_IMAGE_KEY = {
|
|
|
2529
2556
|
shiyo: "shiyo",
|
|
2530
2557
|
rei: "rei",
|
|
2531
2558
|
mgroid: "MGRoid",
|
|
2532
|
-
motroid: "MOTRoid"
|
|
2559
|
+
motroid: "MOTRoid",
|
|
2560
|
+
nynroid: "NYNRoid"
|
|
2533
2561
|
};
|
|
2534
2562
|
var KOE_VOICEBANK_TERMS = {
|
|
2535
2563
|
tsukuyomi: "https://tyc.rei-yumesaki.net/material/utau/terms/",
|
|
@@ -2541,7 +2569,8 @@ var KOE_VOICEBANK_TERMS = {
|
|
|
2541
2569
|
shiyo: "https://kakumeisiyo.my.canva.site/dagkuyjwycs",
|
|
2542
2570
|
rei: "https://mechanicalgirl.jp/guidelines/",
|
|
2543
2571
|
mgroid: "https://x.com/nisusansu/status/1048825378188353536",
|
|
2544
|
-
motroid: "https://www.nicovideo.jp/watch/sm40031282"
|
|
2572
|
+
motroid: "https://www.nicovideo.jp/watch/sm40031282",
|
|
2573
|
+
nynroid: "https://www.bilibili.com/video/BV1V24y1a7qs"
|
|
2545
2574
|
};
|
|
2546
2575
|
var koeUrl = (name, base = KOE_BASE_URL) => `${base}/${encodeURIComponent(name)}`;
|
|
2547
2576
|
var DEFAULT_WORLDLINE_SCRIPT = "https://onjmin.github.io/koe/demo/world/worldline.js";
|
|
@@ -3365,6 +3394,19 @@ var extractMidiPlacements = (midi, selectedTrackIndices) => {
|
|
|
3365
3394
|
}
|
|
3366
3395
|
return { placements, bpm };
|
|
3367
3396
|
};
|
|
3397
|
+
var isPlausibleMidiTranscription = (midi, selectedIndices) => {
|
|
3398
|
+
const { placements } = extractMidiPlacements(midi, selectedIndices);
|
|
3399
|
+
if (placements.length < 4) return false;
|
|
3400
|
+
const shortCount = placements.filter((p) => p.durationSteps <= 1).length;
|
|
3401
|
+
const shortRatio = shortCount / placements.length;
|
|
3402
|
+
const countByStep = /* @__PURE__ */ new Map();
|
|
3403
|
+
for (const p of placements) {
|
|
3404
|
+
countByStep.set(p.startStep, (countByStep.get(p.startStep) ?? 0) + 1);
|
|
3405
|
+
}
|
|
3406
|
+
const denseSteps = [...countByStep.values()].filter((n) => n >= 6).length;
|
|
3407
|
+
const denseRatio = denseSteps / countByStep.size;
|
|
3408
|
+
return shortRatio < 0.6 && denseRatio < 0.35;
|
|
3409
|
+
};
|
|
3368
3410
|
var extractMidiPlacementsByTrack = (midi, selectedIndices, trackIds) => {
|
|
3369
3411
|
const { tracks, division } = midi;
|
|
3370
3412
|
const ticksPerBeat = division;
|
|
@@ -3517,6 +3559,45 @@ var exportMIDI = (options) => {
|
|
|
3517
3559
|
return new Blob([new Uint8Array(arr).buffer], { type: "audio/midi" });
|
|
3518
3560
|
};
|
|
3519
3561
|
|
|
3562
|
+
// src/midi-search.ts
|
|
3563
|
+
var MidiSearchClient = class {
|
|
3564
|
+
config;
|
|
3565
|
+
constructor(config = {}) {
|
|
3566
|
+
this.config = config;
|
|
3567
|
+
}
|
|
3568
|
+
get enabled() {
|
|
3569
|
+
return !!this.config.apiKey;
|
|
3570
|
+
}
|
|
3571
|
+
get baseUrl() {
|
|
3572
|
+
return this.config.baseUrl ?? "https://rpgen-search.pages.dev/api";
|
|
3573
|
+
}
|
|
3574
|
+
headers() {
|
|
3575
|
+
const h = {};
|
|
3576
|
+
if (this.config.apiKey) {
|
|
3577
|
+
h.Authorization = `Bearer ${this.config.apiKey}`;
|
|
3578
|
+
}
|
|
3579
|
+
return h;
|
|
3580
|
+
}
|
|
3581
|
+
async searchSongs(params) {
|
|
3582
|
+
if (!this.enabled) return [];
|
|
3583
|
+
const qs = new URLSearchParams();
|
|
3584
|
+
if (params.title) qs.set("title", params.title);
|
|
3585
|
+
if (params.user) qs.set("user", params.user);
|
|
3586
|
+
if (params.twitter_id) qs.set("twitter_id", params.twitter_id);
|
|
3587
|
+
const url2 = `${this.baseUrl}/picotune/songs${qs.toString() ? `?${qs.toString()}` : ""}`;
|
|
3588
|
+
const res = await fetch(url2, { headers: this.headers() });
|
|
3589
|
+
if (!res.ok) throw new Error(`picotune search failed: ${res.status}`);
|
|
3590
|
+
const body = await res.json();
|
|
3591
|
+
return body.data ?? body.songs ?? body;
|
|
3592
|
+
}
|
|
3593
|
+
async fetchMidi(fileName) {
|
|
3594
|
+
const url2 = `${this.baseUrl}/picotune/songs/${encodeURIComponent(fileName)}`;
|
|
3595
|
+
const res = await fetch(url2, { headers: this.headers() });
|
|
3596
|
+
if (!res.ok) throw new Error(`picotune fetch failed: ${res.status}`);
|
|
3597
|
+
return res.arrayBuffer();
|
|
3598
|
+
}
|
|
3599
|
+
};
|
|
3600
|
+
|
|
3520
3601
|
// src/linked-list.ts
|
|
3521
3602
|
var LinkedList = class {
|
|
3522
3603
|
#cursor;
|
|
@@ -3582,6 +3663,10 @@ var HEADER_HEIGHT = 20;
|
|
|
3582
3663
|
var getRenderConfig = () => g_config;
|
|
3583
3664
|
var g_draw_offset_x = 0;
|
|
3584
3665
|
var g_draw_offset_y = 0;
|
|
3666
|
+
var g_bg_active = false;
|
|
3667
|
+
var setBackgroundActive = (active) => {
|
|
3668
|
+
g_bg_active = active;
|
|
3669
|
+
};
|
|
3585
3670
|
var getDrawOffset = () => ({
|
|
3586
3671
|
x: g_draw_offset_x,
|
|
3587
3672
|
y: g_draw_offset_y
|
|
@@ -3731,7 +3816,7 @@ var drawHeader = () => {
|
|
|
3731
3816
|
const { stepWidth, stepsPerBar } = g_config;
|
|
3732
3817
|
g_header_ctx.save();
|
|
3733
3818
|
g_header_ctx.translate(-g_draw_offset_x, 0);
|
|
3734
|
-
g_header_ctx.fillStyle = "#0a0f1f";
|
|
3819
|
+
g_header_ctx.fillStyle = g_bg_active ? "rgba(10,15,31,0.55)" : "#0a0f1f";
|
|
3735
3820
|
g_header_ctx.fillRect(
|
|
3736
3821
|
g_draw_offset_x,
|
|
3737
3822
|
0,
|
|
@@ -3777,7 +3862,7 @@ var drawGrid = (noteLengthSteps = 1) => {
|
|
|
3777
3862
|
const octave = Math.floor(totalPitch / 12) - 1;
|
|
3778
3863
|
const isC4Range = octave === 4;
|
|
3779
3864
|
const screenY = y - g_draw_offset_y;
|
|
3780
|
-
g_grid_ctx.fillStyle = isBlackKey ? "#080b16" : "#111628";
|
|
3865
|
+
g_grid_ctx.fillStyle = g_bg_active ? isBlackKey ? "rgba(8,11,22,0.55)" : "rgba(17,22,40,0.45)" : isBlackKey ? "#080b16" : "#111628";
|
|
3781
3866
|
g_grid_ctx.fillRect(0, screenY, g_grid_canvas.width, keyHeight);
|
|
3782
3867
|
if (isC4Range) {
|
|
3783
3868
|
g_grid_ctx.fillStyle = "rgba(41,173,255,0.05)";
|
|
@@ -4482,6 +4567,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4482
4567
|
tokenTracks: collectTokens ? tokenTracks : void 0,
|
|
4483
4568
|
lyrics: collectLyrics ? /* @__PURE__ */ new Map() : void 0,
|
|
4484
4569
|
mergedTrackCount: 0,
|
|
4570
|
+
trackVelocity: /* @__PURE__ */ new Map(),
|
|
4485
4571
|
meta: {}
|
|
4486
4572
|
};
|
|
4487
4573
|
}
|
|
@@ -4501,6 +4587,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4501
4587
|
let baseLength = 16;
|
|
4502
4588
|
let velocity = 100;
|
|
4503
4589
|
const contributors = /* @__PURE__ */ new Map();
|
|
4590
|
+
const trackVelocity = /* @__PURE__ */ new Map();
|
|
4504
4591
|
const recordContributor = () => {
|
|
4505
4592
|
let set = contributors.get(trackIndex);
|
|
4506
4593
|
if (!set) {
|
|
@@ -4601,6 +4688,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4601
4688
|
}
|
|
4602
4689
|
} else if (ch === "v" && numStr) {
|
|
4603
4690
|
velocity = clamp2(Number.parseInt(numStr, 10), 0, 127);
|
|
4691
|
+
trackVelocity.set(trackIndex, velocity);
|
|
4604
4692
|
}
|
|
4605
4693
|
pushTok("ctrl", currentStep, 0, tokStart);
|
|
4606
4694
|
} else if (ch === "[") {
|
|
@@ -4690,6 +4778,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4690
4778
|
tokenTracks: collectTokens ? tokenTracks : void 0,
|
|
4691
4779
|
lyrics,
|
|
4692
4780
|
mergedTrackCount,
|
|
4781
|
+
trackVelocity,
|
|
4693
4782
|
meta
|
|
4694
4783
|
};
|
|
4695
4784
|
};
|
|
@@ -5349,6 +5438,18 @@ var DAW_CSS = `
|
|
|
5349
5438
|
4px 4px 0 var(--c-black);
|
|
5350
5439
|
overflow: hidden;
|
|
5351
5440
|
}
|
|
5441
|
+
/* \u30AB\u30B9\u30BF\u30E0\u80CC\u666F\u753B\u50CF\u30EC\u30A4\u30E4\u30FC\uFF08\u753B\u50CF\u81EA\u4F53\u3092\u534A\u900F\u660E\u5316\u3057\u3001\u30AD\u30E3\u30F3\u30D0\u30B9\u5074\u306E\u5857\u308A\u306F\u7DAD\u6301\uFF09 */
|
|
5442
|
+
.dtm-roll::before {
|
|
5443
|
+
content: '';
|
|
5444
|
+
position: absolute;
|
|
5445
|
+
inset: 0;
|
|
5446
|
+
background-image: var(--dtm-roll-bg-image, none);
|
|
5447
|
+
background-size: cover;
|
|
5448
|
+
background-position: center;
|
|
5449
|
+
background-repeat: no-repeat;
|
|
5450
|
+
opacity: var(--dtm-roll-bg-opacity, 0.4);
|
|
5451
|
+
pointer-events: none;
|
|
5452
|
+
}
|
|
5352
5453
|
.dtm-vscroll {
|
|
5353
5454
|
position: relative;
|
|
5354
5455
|
width: 20px;
|
|
@@ -5721,9 +5822,14 @@ var DAW_CSS = `
|
|
|
5721
5822
|
.dtm-modal-body {
|
|
5722
5823
|
padding: 12px;
|
|
5723
5824
|
overflow-y: auto;
|
|
5825
|
+
overflow-x: hidden;
|
|
5724
5826
|
font-size: 13px;
|
|
5725
5827
|
line-height: 1.6;
|
|
5726
5828
|
}
|
|
5829
|
+
.dtm-modal-body * {
|
|
5830
|
+
max-width: 100%;
|
|
5831
|
+
box-sizing: border-box;
|
|
5832
|
+
}
|
|
5727
5833
|
.dtm-modal-body a {
|
|
5728
5834
|
color: var(--dtm-primary);
|
|
5729
5835
|
text-decoration: underline;
|
|
@@ -6260,7 +6366,10 @@ var createSynth = (ctx, destination = ctx.destination) => {
|
|
|
6260
6366
|
osc.frequency.value = freqFromPitch(e.pitch);
|
|
6261
6367
|
const t0 = ctx.currentTime + e.when;
|
|
6262
6368
|
const peak = Math.max(1e-4, 0.06 * e.volume * 1.5);
|
|
6369
|
+
const releaseTime = Math.min(0.02, e.duration * 0.1);
|
|
6370
|
+
const sustainDuration = e.duration - releaseTime;
|
|
6263
6371
|
gain.gain.setValueAtTime(peak, t0);
|
|
6372
|
+
gain.gain.setValueAtTime(peak, t0 + sustainDuration);
|
|
6264
6373
|
gain.gain.exponentialRampToValueAtTime(1e-3, t0 + e.duration);
|
|
6265
6374
|
osc.connect(gain);
|
|
6266
6375
|
if (typeof ctx.createStereoPanner === "function" && e.pan) {
|
|
@@ -6326,6 +6435,9 @@ var MGRoid_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYA
|
|
|
6326
6435
|
// assets/MOTRoid.png
|
|
6327
6436
|
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";
|
|
6328
6437
|
|
|
6438
|
+
// assets/NYNRoid.png
|
|
6439
|
+
var NYNRoid_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABo0lEQVR42tWXoU8DMRTGf7csCAQBOcz4A6aOIOZAETKLBsQGCCwhiIWQCUKCRDAyAWgcWQgoPOHU/gBmOAkJggRTRPeSa7m7lSHWPdNc23u97+v3vvYCrCiVSir5HMdxwAjhmqfAmCPI+uIURKnPcRxjIc1d0GZi7AwU7Y63qyMA5reODaR268qEnc9fDdhaaDabAERRZLRhGDollnmtVsvvKihmqb3b7QJQq9WcGOh0OgDU63Xj/SyN+KeBMAxV2h4K8peTbQAWDy9HGpeIoiiYDA3Y6l9Z29NI788NpII8WN0FYLmgU0ZDfMJ/BiSU0tI4m57RHZWqRn5XzZ33ZDmn/wwk1KmSKg4C3a0eLvIzPbYB2P/61H7wW0ue3wdSvFxZ9Wvu+YARUb/tH1l1PzkMiBYkxOMldpZuAWg/r6eeCa5r+s+A3AuknjcrNwDMvZ4C8L5wAMB1b8Ood7kHpGjFfwZU0tkajYaxt6Ly3tSsNsbvj/QqGbwvPpLFtscMWHtnnxGuMezPyv8q+AdylzX8ZsDJIfv9vjFYLpf/lHvsDPwA5Wy6PgZtokAAAAAASUVORK5CYII=";
|
|
6440
|
+
|
|
6329
6441
|
// assets/puyuyu.png
|
|
6330
6442
|
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=";
|
|
6331
6443
|
|
|
@@ -6361,7 +6473,8 @@ var VOICE_IMAGES = {
|
|
|
6361
6473
|
tsukuyomi: tsukuyomi_default,
|
|
6362
6474
|
rei: rei_default,
|
|
6363
6475
|
MGRoid: MGRoid_default,
|
|
6364
|
-
MOTRoid: MOTRoid_default
|
|
6476
|
+
MOTRoid: MOTRoid_default,
|
|
6477
|
+
NYNRoid: NYNRoid_default
|
|
6365
6478
|
};
|
|
6366
6479
|
var FALLBACK_VOCAL_ICON = Chip_default;
|
|
6367
6480
|
|
|
@@ -7594,12 +7707,12 @@ var KOE_INFO_HTML = `
|
|
|
7594
7707
|
|
|
7595
7708
|
<h4>3. DTM\u3067\u4F7F\u3046</h4>
|
|
7596
7709
|
<ul>
|
|
7597
|
-
<li>\u6B4C\u5531\u30E2\u30C7\u30EB\u306E\u30D7\u30EB\u30C0\u30A6\u30F3\u304B\u3089\u300C\u30AB\u30B9\u30BF\u30E0\u97F3\
|
|
7598
|
-
<li>\u300C\u97F3\
|
|
7599
|
-
<li>\u30A2\u30A4\u30B3\u30F3\u753B\
|
|
7710
|
+
<li>\u6B4C\u5531\u30E2\u30C7\u30EB\u306E\u30D7\u30EB\u30C0\u30A6\u30F3\u304B\u3089\u300C\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0\u3092\u8FFD\u52A0\u2026\u300D\u3092\u9078\u3073\u307E\u3059\u3002</li>
|
|
7711
|
+
<li>\u300C\u97F3\u58F0URL\u300D\u306B\u624B\u98062\u306E\u76F4\u63A5\u30EA\u30F3\u30AF\u3092\u8CBC\u308A\u4ED8\u3051\u307E\u3059\u3002</li>
|
|
7712
|
+
<li>\u30A2\u30A4\u30B3\u30F3\u753B\u50CFURL\u306F\u4EFB\u610F\u3067\u3059\uFF08\u7701\u7565\u53EF\uFF09\u3002\u8B58\u5225\u5B50\u306F\u30D5\u30A1\u30A4\u30EB\u540D\u304B\u3089\u81EA\u52D5\u751F\u6210\u3055\u308C\u307E\u3059\u3002</li>
|
|
7600
7713
|
<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
7714
|
</ul>
|
|
7602
|
-
<p style="margin-top:4px;"><small>\
|
|
7715
|
+
<p style="margin-top:4px;color:var(--dtm-warn);"><small>\u203BUTAU\u97F3\u6E90\u3092 <code>.koe</code> \u306B\u5909\u63DB\u3057\u3066\u30CD\u30C3\u30C8\u4E0A\u306B\u7F6E\u304F\u884C\u70BA\u306F\u3001\u97F3\u6E90\u30C7\u30FC\u30BF\u306E\u518D\u52A0\u5DE5\u30FB\u518D\u914D\u5E03\u306B\u3042\u305F\u308A\u307E\u3059\u3002\u3053\u308C\u304C\u914D\u5E03\u5143\u306E\u5229\u7528\u898F\u7D04\u306B\u53CD\u3057\u3066\u3044\u306A\u3044\u304B\u306F\u5FC5\u305A\u3054\u81EA\u8EAB\u3067\u78BA\u8A8D\u3057\u3001\u305D\u306E\u8CAC\u4EFB\u3092\u8CA0\u3063\u3066\u304F\u3060\u3055\u3044\u3002</small></p>
|
|
7603
7716
|
</div>
|
|
7604
7717
|
`;
|
|
7605
7718
|
var BASE_STEP_WIDTH = 0.5;
|
|
@@ -7743,6 +7856,24 @@ var TRACKS_ADVANCED = [
|
|
|
7743
7856
|
];
|
|
7744
7857
|
var DEFAULT_TRACKS = TRACKS_SIMPLE;
|
|
7745
7858
|
var BASE_LYRIC_MODELS = ["klatt", ...Object.keys(KOE_VOICEBANKS)];
|
|
7859
|
+
var LYRIC_MODEL_CATEGORIES = [
|
|
7860
|
+
{
|
|
7861
|
+
label: "kusa\u30D7\u30EA\u30BB\u30C3\u30C8",
|
|
7862
|
+
models: ["klatt", "tsukuyomi"]
|
|
7863
|
+
},
|
|
7864
|
+
{
|
|
7865
|
+
label: "\u304A\u3093J",
|
|
7866
|
+
models: ["roze", "shiyo", "rino"]
|
|
7867
|
+
},
|
|
7868
|
+
{
|
|
7869
|
+
label: "\u4E00\u822C",
|
|
7870
|
+
models: ["teto", "rei", "ruko_male", "ruko_female"]
|
|
7871
|
+
},
|
|
7872
|
+
{
|
|
7873
|
+
label: "\u30AF\u30C3\u30AD\u30FC\u2606",
|
|
7874
|
+
models: ["mgroid", "motroid", "nynroid"]
|
|
7875
|
+
}
|
|
7876
|
+
];
|
|
7746
7877
|
var BASE_LYRIC_MODEL_LABELS = {
|
|
7747
7878
|
klatt: "\u8EFD\u91CF\u30ED\u30DC\u58F0",
|
|
7748
7879
|
...KOE_VOICEBANK_LABELS
|
|
@@ -7750,6 +7881,18 @@ var BASE_LYRIC_MODEL_LABELS = {
|
|
|
7750
7881
|
var lyricModelLabel = (model, customMap) => BASE_LYRIC_MODEL_LABELS[model] ?? customMap.get(model)?.label ?? model;
|
|
7751
7882
|
var CUSTOM_VOCAL_ADD_VALUE = "+custom";
|
|
7752
7883
|
var CUSTOM_VOCAL_KEY_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
7884
|
+
var deriveCustomVocalKeyFromUrl = (url2) => {
|
|
7885
|
+
let name;
|
|
7886
|
+
try {
|
|
7887
|
+
const path = new URL(url2).pathname;
|
|
7888
|
+
name = decodeURIComponent(path.slice(path.lastIndexOf("/") + 1));
|
|
7889
|
+
} catch {
|
|
7890
|
+
return "";
|
|
7891
|
+
}
|
|
7892
|
+
name = name.replace(/\.[^.]*$/, "").normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
7893
|
+
if (name && /^[0-9]/.test(name)) name = `_${name}`;
|
|
7894
|
+
return CUSTOM_VOCAL_KEY_RE.test(name) ? name : "";
|
|
7895
|
+
};
|
|
7753
7896
|
var clamp3 = (v, min, max) => Math.min(Math.max(v, min), max);
|
|
7754
7897
|
var normalizeInstrumentName = (name) => {
|
|
7755
7898
|
if (!name) return "";
|
|
@@ -7767,13 +7910,16 @@ var mountDAW = (target, options = {}) => {
|
|
|
7767
7910
|
const drumPatterns = options.drumPatterns ?? DRUM_PATTERNS;
|
|
7768
7911
|
const showMidi = !!options.parseMidi;
|
|
7769
7912
|
const showChord = !isAdvanced;
|
|
7913
|
+
const midiSearchClient = options.midiSearch ? new MidiSearchClient(options.midiSearch) : void 0;
|
|
7914
|
+
const showMidiSearch = !!midiSearchClient?.enabled;
|
|
7770
7915
|
const refs = buildUI(target, {
|
|
7771
7916
|
tracks: trackConfigs,
|
|
7772
7917
|
drumPatternNames: Object.keys(drumPatterns),
|
|
7773
7918
|
defaultDrumPattern: drumPatterns.dance ? "dance" : Object.keys(drumPatterns)[0] ?? "none",
|
|
7774
7919
|
defaultBpm: options.defaultBpm ?? DEFAULT_BPM,
|
|
7775
7920
|
showMidi,
|
|
7776
|
-
showChord
|
|
7921
|
+
showChord,
|
|
7922
|
+
showMidiSearch
|
|
7777
7923
|
});
|
|
7778
7924
|
const renderConfig = {
|
|
7779
7925
|
stepsPerBar: 192,
|
|
@@ -8386,6 +8532,106 @@ var mountDAW = (target, options = {}) => {
|
|
|
8386
8532
|
redrawAll();
|
|
8387
8533
|
}
|
|
8388
8534
|
};
|
|
8535
|
+
const BG_DB_NAME = "dtm-daw-db";
|
|
8536
|
+
const BG_DB_STORE = "settings";
|
|
8537
|
+
const BG_DB_KEY = "piano-roll-bg";
|
|
8538
|
+
const BG_OPACITY_KEY = "dtm-piano-roll-bg-opacity";
|
|
8539
|
+
const COMPRESSIBLE_IMAGE_TYPES = /* @__PURE__ */ new Set([
|
|
8540
|
+
"image/jpeg",
|
|
8541
|
+
"image/png",
|
|
8542
|
+
"image/webp",
|
|
8543
|
+
"image/bmp"
|
|
8544
|
+
]);
|
|
8545
|
+
const openBgDb = () => new Promise((resolve, reject) => {
|
|
8546
|
+
const req = indexedDB.open(BG_DB_NAME, 1);
|
|
8547
|
+
req.onupgradeneeded = () => req.result.createObjectStore(BG_DB_STORE);
|
|
8548
|
+
req.onsuccess = () => resolve(req.result);
|
|
8549
|
+
req.onerror = () => reject(req.error);
|
|
8550
|
+
});
|
|
8551
|
+
const saveBgBlob = async (blob2) => {
|
|
8552
|
+
const db = await openBgDb();
|
|
8553
|
+
try {
|
|
8554
|
+
await new Promise((resolve, reject) => {
|
|
8555
|
+
const tx = db.transaction(BG_DB_STORE, "readwrite");
|
|
8556
|
+
tx.objectStore(BG_DB_STORE).put(blob2, BG_DB_KEY);
|
|
8557
|
+
tx.oncomplete = () => resolve();
|
|
8558
|
+
tx.onerror = () => reject(tx.error);
|
|
8559
|
+
});
|
|
8560
|
+
} finally {
|
|
8561
|
+
db.close();
|
|
8562
|
+
}
|
|
8563
|
+
};
|
|
8564
|
+
const loadBgBlob = async () => {
|
|
8565
|
+
const db = await openBgDb();
|
|
8566
|
+
try {
|
|
8567
|
+
return await new Promise((resolve, reject) => {
|
|
8568
|
+
const tx = db.transaction(BG_DB_STORE, "readonly");
|
|
8569
|
+
const req = tx.objectStore(BG_DB_STORE).get(BG_DB_KEY);
|
|
8570
|
+
req.onsuccess = () => resolve(req.result ?? null);
|
|
8571
|
+
req.onerror = () => reject(req.error);
|
|
8572
|
+
});
|
|
8573
|
+
} finally {
|
|
8574
|
+
db.close();
|
|
8575
|
+
}
|
|
8576
|
+
};
|
|
8577
|
+
const deleteBgBlob = async () => {
|
|
8578
|
+
const db = await openBgDb();
|
|
8579
|
+
try {
|
|
8580
|
+
await new Promise((resolve, reject) => {
|
|
8581
|
+
const tx = db.transaction(BG_DB_STORE, "readwrite");
|
|
8582
|
+
tx.objectStore(BG_DB_STORE).delete(BG_DB_KEY);
|
|
8583
|
+
tx.oncomplete = () => resolve();
|
|
8584
|
+
tx.onerror = () => reject(tx.error);
|
|
8585
|
+
});
|
|
8586
|
+
} finally {
|
|
8587
|
+
db.close();
|
|
8588
|
+
}
|
|
8589
|
+
};
|
|
8590
|
+
const resizeImageToBlob = (img, maxW, maxH) => {
|
|
8591
|
+
const scale = Math.min(1, maxW / img.width, maxH / img.height);
|
|
8592
|
+
const width = Math.max(1, Math.round(img.width * scale));
|
|
8593
|
+
const height = Math.max(1, Math.round(img.height * scale));
|
|
8594
|
+
const canvas = document.createElement("canvas");
|
|
8595
|
+
canvas.width = width;
|
|
8596
|
+
canvas.height = height;
|
|
8597
|
+
const ctx = canvas.getContext("2d");
|
|
8598
|
+
if (ctx) ctx.drawImage(img, 0, 0, width, height);
|
|
8599
|
+
return new Promise((resolve, reject) => {
|
|
8600
|
+
canvas.toBlob(
|
|
8601
|
+
(blob2) => blob2 ? resolve(blob2) : reject(new Error("toBlob failed")),
|
|
8602
|
+
"image/jpeg",
|
|
8603
|
+
0.7
|
|
8604
|
+
);
|
|
8605
|
+
});
|
|
8606
|
+
};
|
|
8607
|
+
let currentBgObjectUrl = null;
|
|
8608
|
+
const applyBgOpacity = (opacityVal) => {
|
|
8609
|
+
refs.rollContainer.style.setProperty(
|
|
8610
|
+
"--dtm-roll-bg-opacity",
|
|
8611
|
+
String(opacityVal / 100)
|
|
8612
|
+
);
|
|
8613
|
+
refs.bgOpacityInput.value = String(opacityVal);
|
|
8614
|
+
};
|
|
8615
|
+
const applyRollBackground = (blob2) => {
|
|
8616
|
+
if (currentBgObjectUrl) {
|
|
8617
|
+
URL.revokeObjectURL(currentBgObjectUrl);
|
|
8618
|
+
currentBgObjectUrl = null;
|
|
8619
|
+
}
|
|
8620
|
+
if (blob2) {
|
|
8621
|
+
currentBgObjectUrl = URL.createObjectURL(blob2);
|
|
8622
|
+
refs.rollContainer.style.setProperty(
|
|
8623
|
+
"--dtm-roll-bg-image",
|
|
8624
|
+
`url(${currentBgObjectUrl})`
|
|
8625
|
+
);
|
|
8626
|
+
refs.bgOpacityRow.classList.remove("dtm-hidden");
|
|
8627
|
+
} else {
|
|
8628
|
+
refs.rollContainer.style.setProperty("--dtm-roll-bg-image", "none");
|
|
8629
|
+
refs.bgOpacityRow.classList.add("dtm-hidden");
|
|
8630
|
+
}
|
|
8631
|
+
refs.bgRemoveBtn.classList.toggle("dtm-hidden", !blob2);
|
|
8632
|
+
setBackgroundActive(!!blob2);
|
|
8633
|
+
redrawAll();
|
|
8634
|
+
};
|
|
8389
8635
|
const setupCanvas = () => {
|
|
8390
8636
|
const w = refs.rollContainer.clientWidth || 800;
|
|
8391
8637
|
const h = refs.rollContainer.clientHeight || 450;
|
|
@@ -8751,10 +8997,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
8751
8997
|
<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
8998
|
<button class="dtm-btn dtm-btn--ghost dtm-btn--xs" data-dtm="lyric-custom-guide">\u4F7F\u3044\u65B9\u30AC\u30A4\u30C9</button>
|
|
8753
8999
|
</div>
|
|
8754
|
-
<input type="url" class="dtm-input" data-dtm="lyric-custom-src" placeholder="\u97F3\
|
|
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\
|
|
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">
|
|
9000
|
+
<input type="url" class="dtm-input" data-dtm="lyric-custom-src" placeholder="\u97F3\u58F0URL\uFF08https://\u301C.koe\uFF09" aria-label="\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0\uFF08.koe\uFF09\u306EURL">
|
|
9001
|
+
<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\u58F0\u306E\u30A2\u30A4\u30B3\u30F3\u753B\u50CFURL">
|
|
8758
9002
|
<div class="dtm-row">
|
|
8759
9003
|
<span class="dtm-label dtm-grow" data-dtm="lyric-custom-note" style="color:var(--dtm-warn)"></span>
|
|
8760
9004
|
<button class="dtm-btn dtm-btn--primary" data-dtm="lyric-custom-apply">\u8FFD\u52A0</button>
|
|
@@ -8819,12 +9063,6 @@ var mountDAW = (target, options = {}) => {
|
|
|
8819
9063
|
const lyricCustomIcon = lyricDiv.querySelector(
|
|
8820
9064
|
'[data-dtm="lyric-custom-icon"]'
|
|
8821
9065
|
);
|
|
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
9066
|
const lyricCustomGuide = lyricDiv.querySelector(
|
|
8829
9067
|
'[data-dtm="lyric-custom-guide"]'
|
|
8830
9068
|
);
|
|
@@ -8835,23 +9073,35 @@ var mountDAW = (target, options = {}) => {
|
|
|
8835
9073
|
'[data-dtm="lyric-custom-apply"]'
|
|
8836
9074
|
);
|
|
8837
9075
|
const fmtPan = (pan) => pan === 64 ? "C" : pan < 64 ? `L${64 - pan}` : `R${pan - 64}`;
|
|
8838
|
-
const addOpt = (value, label) => {
|
|
9076
|
+
const addOpt = (parent, value, label) => {
|
|
8839
9077
|
const o = document.createElement("option");
|
|
8840
9078
|
o.value = value;
|
|
8841
9079
|
o.textContent = label;
|
|
8842
|
-
|
|
9080
|
+
parent.appendChild(o);
|
|
8843
9081
|
};
|
|
8844
|
-
addOpt("", "\u30DC\u30FC\u30AB\u30EB\u306A\u3057");
|
|
8845
|
-
for (const
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
9082
|
+
addOpt(lyricModelSel, "", "\u30DC\u30FC\u30AB\u30EB\u306A\u3057");
|
|
9083
|
+
for (const cat of LYRIC_MODEL_CATEGORIES) {
|
|
9084
|
+
const group = document.createElement("optgroup");
|
|
9085
|
+
group.label = cat.label;
|
|
9086
|
+
for (const m of cat.models) {
|
|
9087
|
+
addOpt(group, m, lyricModelLabel(m, customVocalsMap));
|
|
9088
|
+
}
|
|
9089
|
+
lyricModelSel.appendChild(group);
|
|
9090
|
+
}
|
|
9091
|
+
const customGroup = document.createElement("optgroup");
|
|
9092
|
+
customGroup.label = "\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0";
|
|
9093
|
+
for (const [k, def] of customVocalsMap) {
|
|
9094
|
+
addOpt(customGroup, k, def.label ?? k);
|
|
9095
|
+
}
|
|
9096
|
+
addOpt(customGroup, CUSTOM_VOCAL_ADD_VALUE, "\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0\u3092\u8FFD\u52A0\u2026");
|
|
8849
9097
|
if (active.lyricModel && !BASE_LYRIC_MODELS.includes(active.lyricModel) && !customVocalsMap.has(active.lyricModel)) {
|
|
8850
9098
|
addOpt(
|
|
9099
|
+
customGroup,
|
|
8851
9100
|
active.lyricModel,
|
|
8852
9101
|
lyricModelLabel(active.lyricModel, customVocalsMap)
|
|
8853
9102
|
);
|
|
8854
9103
|
}
|
|
9104
|
+
lyricModelSel.appendChild(customGroup);
|
|
8855
9105
|
lyricModelSel.value = active.lyricModel;
|
|
8856
9106
|
lyricOctaveSel.value = String(active.vocalOctave);
|
|
8857
9107
|
lyricInput.value = active.lyrics;
|
|
@@ -8917,9 +9167,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
8917
9167
|
lyricModelSel.addEventListener("change", () => {
|
|
8918
9168
|
if (lyricModelSel.value === CUSTOM_VOCAL_ADD_VALUE) {
|
|
8919
9169
|
lyricCustomNote.textContent = "";
|
|
8920
|
-
lyricCustomAlias.value = "";
|
|
8921
|
-
lyricCustomKey.value = "";
|
|
8922
9170
|
lyricCustom.classList.remove("dtm-hidden");
|
|
9171
|
+
lyricIcon.removeAttribute("src");
|
|
9172
|
+
lyricIcon.classList.add("dtm-hidden");
|
|
9173
|
+
lyricTerms.classList.add("dtm-hidden");
|
|
8923
9174
|
return;
|
|
8924
9175
|
}
|
|
8925
9176
|
lyricCustom.classList.add("dtm-hidden");
|
|
@@ -8929,45 +9180,41 @@ var mountDAW = (target, options = {}) => {
|
|
|
8929
9180
|
fireLyricsChange(active);
|
|
8930
9181
|
});
|
|
8931
9182
|
lyricCustomGuide.addEventListener("click", () => {
|
|
8932
|
-
showModal("\u30AB\u30B9\u30BF\u30E0\u97F3\
|
|
9183
|
+
showModal("\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0(.koe)\u306E\u4F7F\u3044\u65B9", KOE_INFO_HTML);
|
|
8933
9184
|
});
|
|
8934
9185
|
lyricCustomApply.addEventListener("click", () => {
|
|
8935
9186
|
const src = lyricCustomSrc.value.trim();
|
|
8936
9187
|
if (!isValidHttpUrl(src)) {
|
|
8937
|
-
lyricCustomNote.textContent = "\u97F3\
|
|
9188
|
+
lyricCustomNote.textContent = "\u97F3\u58F0URL\u304C\u4E0D\u6B63\u3067\u3059\uFF08http/https\u306E\u307F\u30FB2048\u6587\u5B57\u307E\u3067\uFF09";
|
|
8938
9189
|
return;
|
|
8939
9190
|
}
|
|
8940
9191
|
const iconRaw = lyricCustomIcon.value.trim();
|
|
8941
9192
|
const iconUrl = isValidHttpUrl(iconRaw) ? iconRaw : "";
|
|
8942
|
-
const alias = lyricCustomAlias.value.trim();
|
|
8943
9193
|
const existing = [...customVocalsMap.values()].find(
|
|
8944
9194
|
(d) => d.url === src
|
|
8945
9195
|
);
|
|
8946
|
-
const keyRaw = lyricCustomKey.value.trim().toLowerCase();
|
|
8947
9196
|
let key;
|
|
8948
|
-
if (
|
|
8949
|
-
|
|
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;
|
|
9197
|
+
if (existing) {
|
|
9198
|
+
key = existing.key;
|
|
8963
9199
|
} else {
|
|
8964
|
-
|
|
9200
|
+
const derived = deriveCustomVocalKeyFromUrl(src);
|
|
9201
|
+
if (derived && !BASE_LYRIC_MODELS.includes(derived)) {
|
|
9202
|
+
if (!customVocalsMap.has(derived)) {
|
|
9203
|
+
key = derived;
|
|
9204
|
+
} else {
|
|
9205
|
+
let n = 2;
|
|
9206
|
+
while (customVocalsMap.has(`${derived}${n}`)) n++;
|
|
9207
|
+
key = `${derived}${n}`;
|
|
9208
|
+
}
|
|
9209
|
+
} else {
|
|
9210
|
+
key = genCustomVocalKey();
|
|
9211
|
+
}
|
|
8965
9212
|
}
|
|
8966
9213
|
registerCustomVocal({
|
|
8967
9214
|
key,
|
|
8968
9215
|
iconUrl: iconUrl || (existing?.iconUrl ?? ""),
|
|
8969
9216
|
url: src,
|
|
8970
|
-
label:
|
|
9217
|
+
label: existing?.label
|
|
8971
9218
|
});
|
|
8972
9219
|
active.lyricModel = key;
|
|
8973
9220
|
fireLyricsChange(active);
|
|
@@ -9246,7 +9493,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
9246
9493
|
bpm: parsedBpm,
|
|
9247
9494
|
lyrics,
|
|
9248
9495
|
meta,
|
|
9249
|
-
mergedTrackCount
|
|
9496
|
+
mergedTrackCount,
|
|
9497
|
+
trackVelocity
|
|
9250
9498
|
} = parseMML(mml, {
|
|
9251
9499
|
stepsPerBar: renderConfig.stepsPerBar,
|
|
9252
9500
|
collectLyrics: true,
|
|
@@ -9279,6 +9527,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
9279
9527
|
options.onTrackInstrumentChange?.(i, name);
|
|
9280
9528
|
}
|
|
9281
9529
|
});
|
|
9530
|
+
trackStates.forEach((t, i) => {
|
|
9531
|
+
const v = trackVelocity.get(i);
|
|
9532
|
+
if (v !== void 0 && v !== t.volume) {
|
|
9533
|
+
t.volume = v;
|
|
9534
|
+
t.core.setVolume(v);
|
|
9535
|
+
}
|
|
9536
|
+
});
|
|
9282
9537
|
for (const t of trackStates) {
|
|
9283
9538
|
t.lyrics = "";
|
|
9284
9539
|
t.lyricModel = "";
|
|
@@ -9470,7 +9725,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
9470
9725
|
refs.prevBarBtn.addEventListener("click", () => {
|
|
9471
9726
|
const targetStep = Math.max(
|
|
9472
9727
|
0,
|
|
9473
|
-
Math.floor((getCurrentPlayStep() - 1) / renderConfig.stepsPerBar) * renderConfig.stepsPerBar
|
|
9728
|
+
(Math.floor((getCurrentPlayStep() - 1) / renderConfig.stepsPerBar) - 1) * renderConfig.stepsPerBar
|
|
9474
9729
|
);
|
|
9475
9730
|
jumpTo(targetStep);
|
|
9476
9731
|
});
|
|
@@ -9515,6 +9770,41 @@ var mountDAW = (target, options = {}) => {
|
|
|
9515
9770
|
applyZoomY();
|
|
9516
9771
|
notifyViewState();
|
|
9517
9772
|
});
|
|
9773
|
+
refs.bgUploadBtn.addEventListener("click", () => refs.bgFileInput.click());
|
|
9774
|
+
refs.bgFileInput.addEventListener("change", () => {
|
|
9775
|
+
const file = refs.bgFileInput.files?.[0];
|
|
9776
|
+
refs.bgFileInput.value = "";
|
|
9777
|
+
if (!file) return;
|
|
9778
|
+
if (!COMPRESSIBLE_IMAGE_TYPES.has(file.type)) {
|
|
9779
|
+
saveBgBlob(file).then(() => applyRollBackground(file)).catch(() => {
|
|
9780
|
+
});
|
|
9781
|
+
return;
|
|
9782
|
+
}
|
|
9783
|
+
const objectUrl = URL.createObjectURL(file);
|
|
9784
|
+
const img = new Image();
|
|
9785
|
+
img.onload = () => {
|
|
9786
|
+
URL.revokeObjectURL(objectUrl);
|
|
9787
|
+
const maxW = refs.rollContainer.clientWidth || 800;
|
|
9788
|
+
const maxH = refs.rollContainer.clientHeight || 450;
|
|
9789
|
+
resizeImageToBlob(img, maxW, maxH).then(
|
|
9790
|
+
(blob2) => saveBgBlob(blob2).then(() => applyRollBackground(blob2))
|
|
9791
|
+
).catch(() => {
|
|
9792
|
+
});
|
|
9793
|
+
};
|
|
9794
|
+
img.src = objectUrl;
|
|
9795
|
+
});
|
|
9796
|
+
refs.bgRemoveBtn.addEventListener("click", () => {
|
|
9797
|
+
deleteBgBlob().catch(() => {
|
|
9798
|
+
}).finally(() => applyRollBackground(null));
|
|
9799
|
+
});
|
|
9800
|
+
refs.bgOpacityInput.addEventListener("input", () => {
|
|
9801
|
+
const opacityVal = Number.parseInt(refs.bgOpacityInput.value, 10);
|
|
9802
|
+
applyBgOpacity(opacityVal);
|
|
9803
|
+
try {
|
|
9804
|
+
localStorage.setItem(BG_OPACITY_KEY, String(opacityVal));
|
|
9805
|
+
} catch (_) {
|
|
9806
|
+
}
|
|
9807
|
+
});
|
|
9518
9808
|
refs.decomposeChordToggle.addEventListener("change", notifyViewState);
|
|
9519
9809
|
refs.ignoreChordHeavyToggle.addEventListener("change", notifyViewState);
|
|
9520
9810
|
refs.masterVolume.addEventListener("input", () => {
|
|
@@ -9587,11 +9877,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
9587
9877
|
refs.mmlLoadBtn.addEventListener("click", async () => {
|
|
9588
9878
|
const mml = refs.mmlInput.value;
|
|
9589
9879
|
if (!isAdvanced && options.onRequestAdvancedMode) {
|
|
9590
|
-
const { mergedTrackCount } = parseMML(mml, {
|
|
9880
|
+
const { mergedTrackCount, meta } = parseMML(mml, {
|
|
9591
9881
|
stepsPerBar: renderConfig.stepsPerBar,
|
|
9592
9882
|
clampTrackCount: trackStates.length
|
|
9593
9883
|
});
|
|
9594
|
-
if (mergedTrackCount > 0) {
|
|
9884
|
+
if (mergedTrackCount > 0 || meta.mode === "advanced") {
|
|
9595
9885
|
const confirmed = await showConfirmModal(
|
|
9596
9886
|
"\u521D\u5FC3\u8005\u30E2\u30FC\u30C9\u3067\u8AAD\u307F\u8FBC\u3080\u3068\u3001\u97F3\u304C\u5D29\u308C\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002<br>\u4E0A\u7D1A\u8005\u30E2\u30FC\u30C9\u306B\u5207\u308A\u66FF\u3048\u307E\u3059\u304B\uFF1F"
|
|
9597
9887
|
);
|
|
@@ -9625,6 +9915,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
9625
9915
|
};
|
|
9626
9916
|
showModal = (title, bodyHTML) => {
|
|
9627
9917
|
collapseActiveSample();
|
|
9918
|
+
collapseSearchPreview();
|
|
9628
9919
|
refs.modalTitle.textContent = title;
|
|
9629
9920
|
refs.modalBody.innerHTML = bodyHTML;
|
|
9630
9921
|
refs.modalOverlay.removeAttribute("hidden");
|
|
@@ -9713,11 +10004,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
9713
10004
|
};
|
|
9714
10005
|
refs.modalClose.addEventListener("click", () => {
|
|
9715
10006
|
collapseActiveSample();
|
|
10007
|
+
collapseSearchPreview();
|
|
9716
10008
|
refs.modalOverlay.setAttribute("hidden", "");
|
|
9717
10009
|
});
|
|
9718
10010
|
refs.modalOverlay.addEventListener("click", (e) => {
|
|
9719
10011
|
if (e.target === refs.modalOverlay) {
|
|
9720
10012
|
collapseActiveSample();
|
|
10013
|
+
collapseSearchPreview();
|
|
9721
10014
|
refs.modalOverlay.setAttribute("hidden", "");
|
|
9722
10015
|
}
|
|
9723
10016
|
});
|
|
@@ -9738,6 +10031,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
9738
10031
|
})
|
|
9739
10032
|
);
|
|
9740
10033
|
if (showMidi) wireMidi();
|
|
10034
|
+
if (showMidiSearch) wireMidiSearch();
|
|
9741
10035
|
document.addEventListener("keydown", onKeyDown);
|
|
9742
10036
|
refs.root.addEventListener("keydown", (e) => {
|
|
9743
10037
|
const t = e.target;
|
|
@@ -9802,6 +10096,236 @@ var mountDAW = (target, options = {}) => {
|
|
|
9802
10096
|
overlayDuring(() => applyMidiSelection(pendingMidi, selected));
|
|
9803
10097
|
});
|
|
9804
10098
|
};
|
|
10099
|
+
const buildPreviewMml = (midi) => {
|
|
10100
|
+
const analysis = analyzeMidiTracks(midi);
|
|
10101
|
+
const selected = analysis.filter((a) => a.selected).map((a) => a.index);
|
|
10102
|
+
const { placements, bpm: parsedBpm } = extractMidiPlacements(
|
|
10103
|
+
midi,
|
|
10104
|
+
selected
|
|
10105
|
+
);
|
|
10106
|
+
const byTrack = /* @__PURE__ */ new Map();
|
|
10107
|
+
for (const p of placements) {
|
|
10108
|
+
if (!byTrack.has(p.trackId)) byTrack.set(p.trackId, []);
|
|
10109
|
+
byTrack.get(p.trackId)?.push(p);
|
|
10110
|
+
}
|
|
10111
|
+
const refCore = trackStates[0].core;
|
|
10112
|
+
const tempo = Math.round(parsedBpm) || bpm;
|
|
10113
|
+
const lines = [];
|
|
10114
|
+
let i = 0;
|
|
10115
|
+
for (const notes of byTrack.values()) {
|
|
10116
|
+
const asNotes = notes.map((p) => ({
|
|
10117
|
+
id: 0,
|
|
10118
|
+
startStep: p.startStep,
|
|
10119
|
+
durationSteps: p.durationSteps,
|
|
10120
|
+
pitch: p.pitch,
|
|
10121
|
+
velocity: p.velocity
|
|
10122
|
+
}));
|
|
10123
|
+
const mml = refCore.getMMLFromNotes(asNotes, tempo, 100).trim();
|
|
10124
|
+
lines.push(`@${i} ${mml}`);
|
|
10125
|
+
i++;
|
|
10126
|
+
}
|
|
10127
|
+
return [...lines, MML_END_MARKER].join(";\n");
|
|
10128
|
+
};
|
|
10129
|
+
const fetchVerifiedMidi = async (fileName) => {
|
|
10130
|
+
if (!options.parseMidi || !midiSearchClient) {
|
|
10131
|
+
throw new Error("parseMidi/midiSearchClient not injected");
|
|
10132
|
+
}
|
|
10133
|
+
const midiBytes = await midiSearchClient.fetchMidi(fileName);
|
|
10134
|
+
const midi = await options.parseMidi(new Uint8Array(midiBytes));
|
|
10135
|
+
const analysis = analyzeMidiTracks(midi);
|
|
10136
|
+
const selected = analysis.filter((a) => a.selected).map((a) => a.index);
|
|
10137
|
+
if (!isPlausibleMidiTranscription(midi, selected)) {
|
|
10138
|
+
throw new Error("implausible MIDI transcription");
|
|
10139
|
+
}
|
|
10140
|
+
return midi;
|
|
10141
|
+
};
|
|
10142
|
+
let searchPreviewPlayer = null;
|
|
10143
|
+
let searchPreviewBtn = null;
|
|
10144
|
+
const collapseSearchPreview = () => {
|
|
10145
|
+
if (searchPreviewPlayer) {
|
|
10146
|
+
searchPreviewPlayer.stop();
|
|
10147
|
+
searchPreviewPlayer.destroy();
|
|
10148
|
+
searchPreviewPlayer = null;
|
|
10149
|
+
}
|
|
10150
|
+
if (searchPreviewBtn) {
|
|
10151
|
+
searchPreviewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
10152
|
+
searchPreviewBtn.classList.remove("dtm-btn--danger");
|
|
10153
|
+
searchPreviewBtn.classList.add("dtm-btn--ghost");
|
|
10154
|
+
const container = searchPreviewBtn.closest(".dtm-modal-sample-box")?.querySelector(".dtm-modal-sample-player-container");
|
|
10155
|
+
if (container) container.innerHTML = "";
|
|
10156
|
+
searchPreviewBtn = null;
|
|
10157
|
+
}
|
|
10158
|
+
};
|
|
10159
|
+
const wireMidiSearch = () => {
|
|
10160
|
+
if (!midiSearchClient) return;
|
|
10161
|
+
refs.midiSearchOpenBtn.addEventListener("click", () => {
|
|
10162
|
+
showModal(
|
|
10163
|
+
"MML\u691C\u7D22",
|
|
10164
|
+
`
|
|
10165
|
+
<div class="dtm-row" style="flex-wrap:nowrap">
|
|
10166
|
+
<input type="text" class="dtm-input dtm-grow" data-dtm="modal-midi-search-input" placeholder="\u66F2\u540D\u3067MML\u691C\u7D22" style="min-width:0">
|
|
10167
|
+
<button class="dtm-btn dtm-btn--primary" data-dtm="modal-midi-search-btn" style="flex-shrink:0">\u691C\u7D22</button>
|
|
10168
|
+
</div>
|
|
10169
|
+
<div class="dtm-row" data-dtm="modal-midi-search-results" style="flex-direction:column;align-items:stretch;gap:4px"></div>
|
|
10170
|
+
`
|
|
10171
|
+
);
|
|
10172
|
+
const input = refs.modalBody.querySelector(
|
|
10173
|
+
'[data-dtm="modal-midi-search-input"]'
|
|
10174
|
+
);
|
|
10175
|
+
const searchBtn = refs.modalBody.querySelector(
|
|
10176
|
+
'[data-dtm="modal-midi-search-btn"]'
|
|
10177
|
+
);
|
|
10178
|
+
const results = refs.modalBody.querySelector(
|
|
10179
|
+
'[data-dtm="modal-midi-search-results"]'
|
|
10180
|
+
);
|
|
10181
|
+
const runSearch = async () => {
|
|
10182
|
+
const q2 = input.value.trim();
|
|
10183
|
+
if (!q2) return;
|
|
10184
|
+
collapseSearchPreview();
|
|
10185
|
+
searchBtn.disabled = true;
|
|
10186
|
+
searchBtn.textContent = "\u691C\u7D22\u4E2D...";
|
|
10187
|
+
results.innerHTML = "";
|
|
10188
|
+
try {
|
|
10189
|
+
const songs = await midiSearchClient.searchSongs({ title: q2 });
|
|
10190
|
+
if (songs.length === 0) {
|
|
10191
|
+
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F</span>';
|
|
10192
|
+
return;
|
|
10193
|
+
}
|
|
10194
|
+
for (const song of songs) {
|
|
10195
|
+
const box = document.createElement("div");
|
|
10196
|
+
box.className = "dtm-modal-sample-box";
|
|
10197
|
+
const row = document.createElement("div");
|
|
10198
|
+
row.className = "dtm-row";
|
|
10199
|
+
row.style.cssText = "flex-wrap:nowrap;gap:4px;padding:2px 0";
|
|
10200
|
+
const label = document.createElement("span");
|
|
10201
|
+
label.className = "dtm-label";
|
|
10202
|
+
label.style.cssText = "flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
|
|
10203
|
+
label.textContent = `${song.title} - ${song.user}`;
|
|
10204
|
+
const previewBtn = document.createElement("button");
|
|
10205
|
+
previewBtn.className = "dtm-btn dtm-btn--ghost";
|
|
10206
|
+
previewBtn.style.cssText = "flex-shrink:0";
|
|
10207
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
10208
|
+
const loadBtn = document.createElement("button");
|
|
10209
|
+
loadBtn.className = "dtm-btn dtm-btn--primary";
|
|
10210
|
+
loadBtn.style.cssText = "flex-shrink:0";
|
|
10211
|
+
loadBtn.textContent = "\u8AAD\u307F\u8FBC\u307F";
|
|
10212
|
+
const playerContainer = document.createElement("div");
|
|
10213
|
+
playerContainer.className = "dtm-modal-sample-player-container";
|
|
10214
|
+
previewBtn.addEventListener("click", async () => {
|
|
10215
|
+
if (searchPreviewBtn === previewBtn) {
|
|
10216
|
+
if (searchPreviewPlayer?.isPlaying()) {
|
|
10217
|
+
searchPreviewPlayer.stop();
|
|
10218
|
+
} else {
|
|
10219
|
+
stop();
|
|
10220
|
+
previewBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
10221
|
+
try {
|
|
10222
|
+
const midi = await fetchVerifiedMidi(song.file);
|
|
10223
|
+
const mml = buildPreviewMml(midi);
|
|
10224
|
+
playerContainer.innerHTML = "";
|
|
10225
|
+
const player = mountMmlPlayer(playerContainer, mml, {
|
|
10226
|
+
onPlayNote: options.onPlayNote,
|
|
10227
|
+
onPlayDrum: options.onPlayDrum,
|
|
10228
|
+
onResumeAudio: options.onResumeAudio,
|
|
10229
|
+
getAudioTime: options.getAudioTime,
|
|
10230
|
+
singingVoices: options.singingVoices,
|
|
10231
|
+
drumPatterns: options.drumPatterns,
|
|
10232
|
+
volume: masterVolume,
|
|
10233
|
+
_skipInfoModals: true,
|
|
10234
|
+
onStop: () => {
|
|
10235
|
+
if (searchPreviewBtn === previewBtn) {
|
|
10236
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
10237
|
+
previewBtn.classList.remove("dtm-btn--danger");
|
|
10238
|
+
previewBtn.classList.add("dtm-btn--ghost");
|
|
10239
|
+
}
|
|
10240
|
+
}
|
|
10241
|
+
});
|
|
10242
|
+
searchPreviewPlayer = player;
|
|
10243
|
+
searchPreviewBtn = previewBtn;
|
|
10244
|
+
player.play();
|
|
10245
|
+
previewBtn.textContent = "\u25A0 \u505C\u6B62";
|
|
10246
|
+
previewBtn.classList.remove("dtm-btn--ghost");
|
|
10247
|
+
previewBtn.classList.add("dtm-btn--danger");
|
|
10248
|
+
} catch (e) {
|
|
10249
|
+
console.error("[dtm] MIDI preview failed", e);
|
|
10250
|
+
previewBtn.textContent = "\u5931\u6557";
|
|
10251
|
+
}
|
|
10252
|
+
}
|
|
10253
|
+
} else {
|
|
10254
|
+
collapseSearchPreview();
|
|
10255
|
+
stop();
|
|
10256
|
+
previewBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
10257
|
+
try {
|
|
10258
|
+
const midi = await fetchVerifiedMidi(song.file);
|
|
10259
|
+
const mml = buildPreviewMml(midi);
|
|
10260
|
+
playerContainer.innerHTML = "";
|
|
10261
|
+
const player = mountMmlPlayer(playerContainer, mml, {
|
|
10262
|
+
onPlayNote: options.onPlayNote,
|
|
10263
|
+
onPlayDrum: options.onPlayDrum,
|
|
10264
|
+
onResumeAudio: options.onResumeAudio,
|
|
10265
|
+
getAudioTime: options.getAudioTime,
|
|
10266
|
+
singingVoices: options.singingVoices,
|
|
10267
|
+
drumPatterns: options.drumPatterns,
|
|
10268
|
+
volume: masterVolume,
|
|
10269
|
+
_skipInfoModals: true,
|
|
10270
|
+
onStop: () => {
|
|
10271
|
+
if (searchPreviewBtn === previewBtn) {
|
|
10272
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
10273
|
+
previewBtn.classList.remove("dtm-btn--danger");
|
|
10274
|
+
previewBtn.classList.add("dtm-btn--ghost");
|
|
10275
|
+
}
|
|
10276
|
+
}
|
|
10277
|
+
});
|
|
10278
|
+
searchPreviewPlayer = player;
|
|
10279
|
+
searchPreviewBtn = previewBtn;
|
|
10280
|
+
player.play();
|
|
10281
|
+
previewBtn.textContent = "\u25A0 \u505C\u6B62";
|
|
10282
|
+
previewBtn.classList.remove("dtm-btn--ghost");
|
|
10283
|
+
previewBtn.classList.add("dtm-btn--danger");
|
|
10284
|
+
} catch (e) {
|
|
10285
|
+
console.error("[dtm] MIDI preview failed", e);
|
|
10286
|
+
previewBtn.textContent = "\u5931\u6557";
|
|
10287
|
+
}
|
|
10288
|
+
}
|
|
10289
|
+
});
|
|
10290
|
+
loadBtn.addEventListener("click", async () => {
|
|
10291
|
+
loadBtn.disabled = true;
|
|
10292
|
+
loadBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
10293
|
+
try {
|
|
10294
|
+
const pending = await fetchVerifiedMidi(song.file);
|
|
10295
|
+
const analysis = analyzeMidiTracks(pending);
|
|
10296
|
+
const sel = analysis.filter((a) => a.selected).map((a) => a.index);
|
|
10297
|
+
collapseSearchPreview();
|
|
10298
|
+
overlayDuring(() => applyMidiSelection(pending, sel));
|
|
10299
|
+
refs.modalOverlay.setAttribute("hidden", "");
|
|
10300
|
+
} catch (e) {
|
|
10301
|
+
console.error("[dtm] MIDI fetch failed", e);
|
|
10302
|
+
loadBtn.textContent = "\u5931\u6557";
|
|
10303
|
+
} finally {
|
|
10304
|
+
loadBtn.disabled = false;
|
|
10305
|
+
}
|
|
10306
|
+
});
|
|
10307
|
+
row.appendChild(label);
|
|
10308
|
+
row.appendChild(previewBtn);
|
|
10309
|
+
row.appendChild(loadBtn);
|
|
10310
|
+
box.appendChild(row);
|
|
10311
|
+
box.appendChild(playerContainer);
|
|
10312
|
+
results.appendChild(box);
|
|
10313
|
+
}
|
|
10314
|
+
} catch (e) {
|
|
10315
|
+
console.error("[dtm] MIDI search failed", e);
|
|
10316
|
+
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u691C\u7D22\u306B\u5931\u6557\u3057\u307E\u3057\u305F</span>';
|
|
10317
|
+
} finally {
|
|
10318
|
+
searchBtn.disabled = false;
|
|
10319
|
+
searchBtn.textContent = "\u691C\u7D22";
|
|
10320
|
+
}
|
|
10321
|
+
};
|
|
10322
|
+
searchBtn.addEventListener("click", () => void runSearch());
|
|
10323
|
+
input.addEventListener("keydown", (e) => {
|
|
10324
|
+
if (e.key === "Enter") void runSearch();
|
|
10325
|
+
});
|
|
10326
|
+
input.focus();
|
|
10327
|
+
});
|
|
10328
|
+
};
|
|
9805
10329
|
const onKeyDown = (e) => {
|
|
9806
10330
|
if (!(e.ctrlKey || e.metaKey)) return;
|
|
9807
10331
|
if (e.code === "KeyZ" && !e.shiftKey) {
|
|
@@ -9857,6 +10381,22 @@ var mountDAW = (target, options = {}) => {
|
|
|
9857
10381
|
updateUndoRedo();
|
|
9858
10382
|
redrawAll();
|
|
9859
10383
|
if (options.initialMML) loadMML(options.initialMML);
|
|
10384
|
+
let initialOpacity = 40;
|
|
10385
|
+
try {
|
|
10386
|
+
const storedOpacity = localStorage.getItem(BG_OPACITY_KEY);
|
|
10387
|
+
if (storedOpacity !== null) {
|
|
10388
|
+
initialOpacity = Number.parseInt(storedOpacity, 10);
|
|
10389
|
+
if (Number.isNaN(initialOpacity) || initialOpacity < 0 || initialOpacity > 100) {
|
|
10390
|
+
initialOpacity = 40;
|
|
10391
|
+
}
|
|
10392
|
+
}
|
|
10393
|
+
} catch (_) {
|
|
10394
|
+
}
|
|
10395
|
+
applyBgOpacity(initialOpacity);
|
|
10396
|
+
loadBgBlob().then((blob2) => {
|
|
10397
|
+
if (blob2) applyRollBackground(blob2);
|
|
10398
|
+
}).catch(() => {
|
|
10399
|
+
});
|
|
9860
10400
|
let resizeTimer = null;
|
|
9861
10401
|
const resizeObserver = new ResizeObserver(() => {
|
|
9862
10402
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
@@ -11177,13 +11717,17 @@ var createDtmStudio = async (options = {}) => {
|
|
|
11177
11717
|
const mountedPlayers = [];
|
|
11178
11718
|
const mountedModeSwitches = [];
|
|
11179
11719
|
const mountEditor = (target, opts = {}) => {
|
|
11720
|
+
const mergedOpts = {
|
|
11721
|
+
midiSearch: options.midiSearch,
|
|
11722
|
+
...opts
|
|
11723
|
+
};
|
|
11180
11724
|
const {
|
|
11181
11725
|
preset,
|
|
11182
11726
|
presetUI,
|
|
11183
11727
|
onInstrumentChange,
|
|
11184
11728
|
onTrackInstrumentChange: externalOnTrackInstrumentChange,
|
|
11185
11729
|
...dawOverrides
|
|
11186
|
-
} =
|
|
11730
|
+
} = mergedOpts;
|
|
11187
11731
|
const tracks = dawOverrides.tracks ?? TRACKS_SIMPLE;
|
|
11188
11732
|
const trackIds = tracks.map((t) => t.id);
|
|
11189
11733
|
const presetKey = preset && INSTRUMENT_PRESETS[preset] ? preset : defaultPreset;
|
|
@@ -11518,6 +12062,7 @@ export {
|
|
|
11518
12062
|
MAX_VOCAL_VOLUME,
|
|
11519
12063
|
MMLCore,
|
|
11520
12064
|
MML_END_MARKER,
|
|
12065
|
+
MidiSearchClient,
|
|
11521
12066
|
PITCH_MAP,
|
|
11522
12067
|
PREWARM_NOTES,
|
|
11523
12068
|
TRACKS_ADVANCED,
|
|
@@ -11567,6 +12112,7 @@ export {
|
|
|
11567
12112
|
init,
|
|
11568
12113
|
injectStyles,
|
|
11569
12114
|
isChordHeavyTrack,
|
|
12115
|
+
isPlausibleMidiTranscription,
|
|
11570
12116
|
isValidHttpUrl,
|
|
11571
12117
|
koeUrl,
|
|
11572
12118
|
mountDAW,
|
|
@@ -11580,6 +12126,7 @@ export {
|
|
|
11580
12126
|
parseMmlMeta,
|
|
11581
12127
|
playMML,
|
|
11582
12128
|
playSingingMML,
|
|
12129
|
+
setBackgroundActive,
|
|
11583
12130
|
setDrawOffset,
|
|
11584
12131
|
shiftNotes,
|
|
11585
12132
|
showLoadingOverlay,
|