@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.js
CHANGED
|
@@ -41,6 +41,7 @@ __export(index_exports, {
|
|
|
41
41
|
MAX_VOCAL_VOLUME: () => MAX_VOCAL_VOLUME,
|
|
42
42
|
MMLCore: () => MMLCore,
|
|
43
43
|
MML_END_MARKER: () => MML_END_MARKER,
|
|
44
|
+
MidiSearchClient: () => MidiSearchClient,
|
|
44
45
|
PITCH_MAP: () => PITCH_MAP,
|
|
45
46
|
PREWARM_NOTES: () => PREWARM_NOTES,
|
|
46
47
|
TRACKS_ADVANCED: () => TRACKS_ADVANCED,
|
|
@@ -90,6 +91,7 @@ __export(index_exports, {
|
|
|
90
91
|
init: () => init,
|
|
91
92
|
injectStyles: () => injectStyles,
|
|
92
93
|
isChordHeavyTrack: () => isChordHeavyTrack,
|
|
94
|
+
isPlausibleMidiTranscription: () => isPlausibleMidiTranscription,
|
|
93
95
|
isValidHttpUrl: () => isValidHttpUrl,
|
|
94
96
|
koeUrl: () => koeUrl,
|
|
95
97
|
mountDAW: () => mountDAW,
|
|
@@ -103,6 +105,7 @@ __export(index_exports, {
|
|
|
103
105
|
parseMmlMeta: () => parseMmlMeta,
|
|
104
106
|
playMML: () => playMML,
|
|
105
107
|
playSingingMML: () => playSingingMML,
|
|
108
|
+
setBackgroundActive: () => setBackgroundActive,
|
|
106
109
|
setDrawOffset: () => setDrawOffset,
|
|
107
110
|
shiftNotes: () => shiftNotes,
|
|
108
111
|
showLoadingOverlay: () => showLoadingOverlay,
|
|
@@ -1330,7 +1333,13 @@ var icon = (name, size = 20) => {
|
|
|
1330
1333
|
// src/daw-ui.ts
|
|
1331
1334
|
var q = (root, sel) => root.querySelector(sel);
|
|
1332
1335
|
var buildUI = (target, options) => {
|
|
1333
|
-
const {
|
|
1336
|
+
const {
|
|
1337
|
+
drumPatternNames,
|
|
1338
|
+
defaultDrumPattern,
|
|
1339
|
+
defaultBpm,
|
|
1340
|
+
showMidi,
|
|
1341
|
+
showMidiSearch
|
|
1342
|
+
} = options;
|
|
1334
1343
|
const drumOptions = [`<option value="none">\u306A\u3057</option>`].concat(
|
|
1335
1344
|
drumPatternNames.map(
|
|
1336
1345
|
(name) => `<option value="${name}" ${name === defaultDrumPattern ? "selected" : ""}>${name}</option>`
|
|
@@ -1408,6 +1417,16 @@ var buildUI = (target, options) => {
|
|
|
1408
1417
|
<span class="dtm-label" data-dtm="zoomy-label">100%</span>
|
|
1409
1418
|
<button class="dtm-iconbtn" data-dtm="zoomy-in" title="\u62E1\u5927">\uFF0B</button>
|
|
1410
1419
|
</div>
|
|
1420
|
+
<div class="dtm-row">
|
|
1421
|
+
<span class="dtm-label">\u80CC\u666F\u753B\u50CF</span>
|
|
1422
|
+
<input type="file" accept="image/*" data-dtm="bg-file-input" class="dtm-hidden">
|
|
1423
|
+
<button class="dtm-btn dtm-btn--primary" data-dtm="bg-upload">\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9</button>
|
|
1424
|
+
<button class="dtm-btn dtm-btn--danger dtm-hidden" data-dtm="bg-remove">\u524A\u9664</button>
|
|
1425
|
+
</div>
|
|
1426
|
+
<div class="dtm-row dtm-hidden" data-dtm="bg-opacity-row">
|
|
1427
|
+
<span class="dtm-label">\u80CC\u666F\u4E0D\u900F\u660E\u5EA6</span>
|
|
1428
|
+
<input type="range" min="0" max="100" value="40" data-dtm="bg-opacity" class="dtm-slider">
|
|
1429
|
+
</div>
|
|
1411
1430
|
</div>
|
|
1412
1431
|
</details>
|
|
1413
1432
|
|
|
@@ -1446,6 +1465,9 @@ var buildUI = (target, options) => {
|
|
|
1446
1465
|
<textarea class="dtm-textarea dtm-grow" data-dtm="mml-input" placeholder="MML\u3092\u5165\u529B"></textarea>
|
|
1447
1466
|
<button class="dtm-btn dtm-btn--primary" data-dtm="mml-load" style="flex-shrink:0">\u8AAD\u8FBC</button>
|
|
1448
1467
|
</div>
|
|
1468
|
+
<div class="dtm-row" data-dtm="midi-search-row" style="justify-content:flex-end;${showMidiSearch ? "" : "display:none"}">
|
|
1469
|
+
<button class="dtm-btn dtm-btn--primary" data-dtm="midi-search-open">MML\u691C\u7D22</button>
|
|
1470
|
+
</div>
|
|
1449
1471
|
<p class="dtm-load-note dtm-hidden" data-dtm="mml-load-note"></p>
|
|
1450
1472
|
</div>
|
|
1451
1473
|
</details>
|
|
@@ -1556,6 +1578,11 @@ var buildUI = (target, options) => {
|
|
|
1556
1578
|
zoomXOut: sel("zoomx-out"),
|
|
1557
1579
|
zoomYIn: sel("zoomy-in"),
|
|
1558
1580
|
zoomYOut: sel("zoomy-out"),
|
|
1581
|
+
bgFileInput: sel("bg-file-input"),
|
|
1582
|
+
bgUploadBtn: sel("bg-upload"),
|
|
1583
|
+
bgRemoveBtn: sel("bg-remove"),
|
|
1584
|
+
bgOpacityInput: sel("bg-opacity"),
|
|
1585
|
+
bgOpacityRow: sel("bg-opacity-row"),
|
|
1559
1586
|
rollContainer: sel("roll"),
|
|
1560
1587
|
wrapper: sel("wrapper"),
|
|
1561
1588
|
vScroll: sel("vscroll"),
|
|
@@ -1574,6 +1601,7 @@ var buildUI = (target, options) => {
|
|
|
1574
1601
|
midiInfoBtn: sel("midi-info"),
|
|
1575
1602
|
midiTrackSelection: sel("midi-track-selection"),
|
|
1576
1603
|
midiPanel: sel("midi-panel"),
|
|
1604
|
+
midiSearchOpenBtn: sel("midi-search-open"),
|
|
1577
1605
|
mmlInput: sel("mml-input"),
|
|
1578
1606
|
mmlLoadBtn: sel("mml-load"),
|
|
1579
1607
|
mmlLoadNote: sel("mml-load-note"),
|
|
@@ -2619,7 +2647,8 @@ var KOE_VOICEBANKS = {
|
|
|
2619
2647
|
shiyo: "\u9769\u547D\u30B7\u30E8.koe",
|
|
2620
2648
|
rei: "\u8DB3\u7ACB\u30EC\u30A4ver3.5.0.koe",
|
|
2621
2649
|
mgroid: "MGRoid_\u539F\u97F3\u8A2D\u5B9A\u6E08\u307F.koe",
|
|
2622
|
-
motroid: "MOTRoid\u5B8C\u5168\u7248V2.koe"
|
|
2650
|
+
motroid: "MOTRoid\u5B8C\u5168\u7248V2.koe",
|
|
2651
|
+
nynroid: "NYNRoidver1.4.koe"
|
|
2623
2652
|
};
|
|
2624
2653
|
var KOE_VOICEBANK_LABELS = {
|
|
2625
2654
|
tsukuyomi: "\u3064\u304F\u3088\u307F\u3061\u3083\u3093",
|
|
@@ -2631,7 +2660,8 @@ var KOE_VOICEBANK_LABELS = {
|
|
|
2631
2660
|
shiyo: "\u9769\u547D\u30B7\u30E8",
|
|
2632
2661
|
rei: "\u8DB3\u7ACB\u30EC\u30A4",
|
|
2633
2662
|
mgroid: "MGRoid",
|
|
2634
|
-
motroid: "MOTRoid"
|
|
2663
|
+
motroid: "MOTRoid",
|
|
2664
|
+
nynroid: "NYNRoid"
|
|
2635
2665
|
};
|
|
2636
2666
|
var VOICE_IMAGE_KEY = {
|
|
2637
2667
|
klatt: "puyuyu",
|
|
@@ -2644,7 +2674,8 @@ var VOICE_IMAGE_KEY = {
|
|
|
2644
2674
|
shiyo: "shiyo",
|
|
2645
2675
|
rei: "rei",
|
|
2646
2676
|
mgroid: "MGRoid",
|
|
2647
|
-
motroid: "MOTRoid"
|
|
2677
|
+
motroid: "MOTRoid",
|
|
2678
|
+
nynroid: "NYNRoid"
|
|
2648
2679
|
};
|
|
2649
2680
|
var KOE_VOICEBANK_TERMS = {
|
|
2650
2681
|
tsukuyomi: "https://tyc.rei-yumesaki.net/material/utau/terms/",
|
|
@@ -2656,7 +2687,8 @@ var KOE_VOICEBANK_TERMS = {
|
|
|
2656
2687
|
shiyo: "https://kakumeisiyo.my.canva.site/dagkuyjwycs",
|
|
2657
2688
|
rei: "https://mechanicalgirl.jp/guidelines/",
|
|
2658
2689
|
mgroid: "https://x.com/nisusansu/status/1048825378188353536",
|
|
2659
|
-
motroid: "https://www.nicovideo.jp/watch/sm40031282"
|
|
2690
|
+
motroid: "https://www.nicovideo.jp/watch/sm40031282",
|
|
2691
|
+
nynroid: "https://www.bilibili.com/video/BV1V24y1a7qs"
|
|
2660
2692
|
};
|
|
2661
2693
|
var koeUrl = (name, base = KOE_BASE_URL) => `${base}/${encodeURIComponent(name)}`;
|
|
2662
2694
|
var DEFAULT_WORLDLINE_SCRIPT = "https://onjmin.github.io/koe/demo/world/worldline.js";
|
|
@@ -3480,6 +3512,19 @@ var extractMidiPlacements = (midi, selectedTrackIndices) => {
|
|
|
3480
3512
|
}
|
|
3481
3513
|
return { placements, bpm };
|
|
3482
3514
|
};
|
|
3515
|
+
var isPlausibleMidiTranscription = (midi, selectedIndices) => {
|
|
3516
|
+
const { placements } = extractMidiPlacements(midi, selectedIndices);
|
|
3517
|
+
if (placements.length < 4) return false;
|
|
3518
|
+
const shortCount = placements.filter((p) => p.durationSteps <= 1).length;
|
|
3519
|
+
const shortRatio = shortCount / placements.length;
|
|
3520
|
+
const countByStep = /* @__PURE__ */ new Map();
|
|
3521
|
+
for (const p of placements) {
|
|
3522
|
+
countByStep.set(p.startStep, (countByStep.get(p.startStep) ?? 0) + 1);
|
|
3523
|
+
}
|
|
3524
|
+
const denseSteps = [...countByStep.values()].filter((n) => n >= 6).length;
|
|
3525
|
+
const denseRatio = denseSteps / countByStep.size;
|
|
3526
|
+
return shortRatio < 0.6 && denseRatio < 0.35;
|
|
3527
|
+
};
|
|
3483
3528
|
var extractMidiPlacementsByTrack = (midi, selectedIndices, trackIds) => {
|
|
3484
3529
|
const { tracks, division } = midi;
|
|
3485
3530
|
const ticksPerBeat = division;
|
|
@@ -3632,6 +3677,45 @@ var exportMIDI = (options) => {
|
|
|
3632
3677
|
return new Blob([new Uint8Array(arr).buffer], { type: "audio/midi" });
|
|
3633
3678
|
};
|
|
3634
3679
|
|
|
3680
|
+
// src/midi-search.ts
|
|
3681
|
+
var MidiSearchClient = class {
|
|
3682
|
+
config;
|
|
3683
|
+
constructor(config = {}) {
|
|
3684
|
+
this.config = config;
|
|
3685
|
+
}
|
|
3686
|
+
get enabled() {
|
|
3687
|
+
return !!this.config.apiKey;
|
|
3688
|
+
}
|
|
3689
|
+
get baseUrl() {
|
|
3690
|
+
return this.config.baseUrl ?? "https://rpgen-search.pages.dev/api";
|
|
3691
|
+
}
|
|
3692
|
+
headers() {
|
|
3693
|
+
const h = {};
|
|
3694
|
+
if (this.config.apiKey) {
|
|
3695
|
+
h.Authorization = `Bearer ${this.config.apiKey}`;
|
|
3696
|
+
}
|
|
3697
|
+
return h;
|
|
3698
|
+
}
|
|
3699
|
+
async searchSongs(params) {
|
|
3700
|
+
if (!this.enabled) return [];
|
|
3701
|
+
const qs = new URLSearchParams();
|
|
3702
|
+
if (params.title) qs.set("title", params.title);
|
|
3703
|
+
if (params.user) qs.set("user", params.user);
|
|
3704
|
+
if (params.twitter_id) qs.set("twitter_id", params.twitter_id);
|
|
3705
|
+
const url2 = `${this.baseUrl}/picotune/songs${qs.toString() ? `?${qs.toString()}` : ""}`;
|
|
3706
|
+
const res = await fetch(url2, { headers: this.headers() });
|
|
3707
|
+
if (!res.ok) throw new Error(`picotune search failed: ${res.status}`);
|
|
3708
|
+
const body = await res.json();
|
|
3709
|
+
return body.data ?? body.songs ?? body;
|
|
3710
|
+
}
|
|
3711
|
+
async fetchMidi(fileName) {
|
|
3712
|
+
const url2 = `${this.baseUrl}/picotune/songs/${encodeURIComponent(fileName)}`;
|
|
3713
|
+
const res = await fetch(url2, { headers: this.headers() });
|
|
3714
|
+
if (!res.ok) throw new Error(`picotune fetch failed: ${res.status}`);
|
|
3715
|
+
return res.arrayBuffer();
|
|
3716
|
+
}
|
|
3717
|
+
};
|
|
3718
|
+
|
|
3635
3719
|
// src/linked-list.ts
|
|
3636
3720
|
var LinkedList = class {
|
|
3637
3721
|
#cursor;
|
|
@@ -3697,6 +3781,10 @@ var HEADER_HEIGHT = 20;
|
|
|
3697
3781
|
var getRenderConfig = () => g_config;
|
|
3698
3782
|
var g_draw_offset_x = 0;
|
|
3699
3783
|
var g_draw_offset_y = 0;
|
|
3784
|
+
var g_bg_active = false;
|
|
3785
|
+
var setBackgroundActive = (active) => {
|
|
3786
|
+
g_bg_active = active;
|
|
3787
|
+
};
|
|
3700
3788
|
var getDrawOffset = () => ({
|
|
3701
3789
|
x: g_draw_offset_x,
|
|
3702
3790
|
y: g_draw_offset_y
|
|
@@ -3846,7 +3934,7 @@ var drawHeader = () => {
|
|
|
3846
3934
|
const { stepWidth, stepsPerBar } = g_config;
|
|
3847
3935
|
g_header_ctx.save();
|
|
3848
3936
|
g_header_ctx.translate(-g_draw_offset_x, 0);
|
|
3849
|
-
g_header_ctx.fillStyle = "#0a0f1f";
|
|
3937
|
+
g_header_ctx.fillStyle = g_bg_active ? "rgba(10,15,31,0.55)" : "#0a0f1f";
|
|
3850
3938
|
g_header_ctx.fillRect(
|
|
3851
3939
|
g_draw_offset_x,
|
|
3852
3940
|
0,
|
|
@@ -3892,7 +3980,7 @@ var drawGrid = (noteLengthSteps = 1) => {
|
|
|
3892
3980
|
const octave = Math.floor(totalPitch / 12) - 1;
|
|
3893
3981
|
const isC4Range = octave === 4;
|
|
3894
3982
|
const screenY = y - g_draw_offset_y;
|
|
3895
|
-
g_grid_ctx.fillStyle = isBlackKey ? "#080b16" : "#111628";
|
|
3983
|
+
g_grid_ctx.fillStyle = g_bg_active ? isBlackKey ? "rgba(8,11,22,0.55)" : "rgba(17,22,40,0.45)" : isBlackKey ? "#080b16" : "#111628";
|
|
3896
3984
|
g_grid_ctx.fillRect(0, screenY, g_grid_canvas.width, keyHeight);
|
|
3897
3985
|
if (isC4Range) {
|
|
3898
3986
|
g_grid_ctx.fillStyle = "rgba(41,173,255,0.05)";
|
|
@@ -4597,6 +4685,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4597
4685
|
tokenTracks: collectTokens ? tokenTracks : void 0,
|
|
4598
4686
|
lyrics: collectLyrics ? /* @__PURE__ */ new Map() : void 0,
|
|
4599
4687
|
mergedTrackCount: 0,
|
|
4688
|
+
trackVelocity: /* @__PURE__ */ new Map(),
|
|
4600
4689
|
meta: {}
|
|
4601
4690
|
};
|
|
4602
4691
|
}
|
|
@@ -4616,6 +4705,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4616
4705
|
let baseLength = 16;
|
|
4617
4706
|
let velocity = 100;
|
|
4618
4707
|
const contributors = /* @__PURE__ */ new Map();
|
|
4708
|
+
const trackVelocity = /* @__PURE__ */ new Map();
|
|
4619
4709
|
const recordContributor = () => {
|
|
4620
4710
|
let set = contributors.get(trackIndex);
|
|
4621
4711
|
if (!set) {
|
|
@@ -4716,6 +4806,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4716
4806
|
}
|
|
4717
4807
|
} else if (ch === "v" && numStr) {
|
|
4718
4808
|
velocity = clamp2(Number.parseInt(numStr, 10), 0, 127);
|
|
4809
|
+
trackVelocity.set(trackIndex, velocity);
|
|
4719
4810
|
}
|
|
4720
4811
|
pushTok("ctrl", currentStep, 0, tokStart);
|
|
4721
4812
|
} else if (ch === "[") {
|
|
@@ -4805,6 +4896,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4805
4896
|
tokenTracks: collectTokens ? tokenTracks : void 0,
|
|
4806
4897
|
lyrics,
|
|
4807
4898
|
mergedTrackCount,
|
|
4899
|
+
trackVelocity,
|
|
4808
4900
|
meta
|
|
4809
4901
|
};
|
|
4810
4902
|
};
|
|
@@ -5464,6 +5556,18 @@ var DAW_CSS = `
|
|
|
5464
5556
|
4px 4px 0 var(--c-black);
|
|
5465
5557
|
overflow: hidden;
|
|
5466
5558
|
}
|
|
5559
|
+
/* \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 */
|
|
5560
|
+
.dtm-roll::before {
|
|
5561
|
+
content: '';
|
|
5562
|
+
position: absolute;
|
|
5563
|
+
inset: 0;
|
|
5564
|
+
background-image: var(--dtm-roll-bg-image, none);
|
|
5565
|
+
background-size: cover;
|
|
5566
|
+
background-position: center;
|
|
5567
|
+
background-repeat: no-repeat;
|
|
5568
|
+
opacity: var(--dtm-roll-bg-opacity, 0.4);
|
|
5569
|
+
pointer-events: none;
|
|
5570
|
+
}
|
|
5467
5571
|
.dtm-vscroll {
|
|
5468
5572
|
position: relative;
|
|
5469
5573
|
width: 20px;
|
|
@@ -5836,9 +5940,14 @@ var DAW_CSS = `
|
|
|
5836
5940
|
.dtm-modal-body {
|
|
5837
5941
|
padding: 12px;
|
|
5838
5942
|
overflow-y: auto;
|
|
5943
|
+
overflow-x: hidden;
|
|
5839
5944
|
font-size: 13px;
|
|
5840
5945
|
line-height: 1.6;
|
|
5841
5946
|
}
|
|
5947
|
+
.dtm-modal-body * {
|
|
5948
|
+
max-width: 100%;
|
|
5949
|
+
box-sizing: border-box;
|
|
5950
|
+
}
|
|
5842
5951
|
.dtm-modal-body a {
|
|
5843
5952
|
color: var(--dtm-primary);
|
|
5844
5953
|
text-decoration: underline;
|
|
@@ -6375,7 +6484,10 @@ var createSynth = (ctx, destination = ctx.destination) => {
|
|
|
6375
6484
|
osc.frequency.value = freqFromPitch(e.pitch);
|
|
6376
6485
|
const t0 = ctx.currentTime + e.when;
|
|
6377
6486
|
const peak = Math.max(1e-4, 0.06 * e.volume * 1.5);
|
|
6487
|
+
const releaseTime = Math.min(0.02, e.duration * 0.1);
|
|
6488
|
+
const sustainDuration = e.duration - releaseTime;
|
|
6378
6489
|
gain.gain.setValueAtTime(peak, t0);
|
|
6490
|
+
gain.gain.setValueAtTime(peak, t0 + sustainDuration);
|
|
6379
6491
|
gain.gain.exponentialRampToValueAtTime(1e-3, t0 + e.duration);
|
|
6380
6492
|
osc.connect(gain);
|
|
6381
6493
|
if (typeof ctx.createStereoPanner === "function" && e.pan) {
|
|
@@ -6441,6 +6553,9 @@ var MGRoid_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYA
|
|
|
6441
6553
|
// assets/MOTRoid.png
|
|
6442
6554
|
var MOTRoid_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAByElEQVR42s2WTyiEURTFfyMbS1ZSlIUxScpCNrNAkpLdhClFlJRJdpQ/5V+xE7PQFJHFyJKUJKLZaBZqkhjKQslCLG3UWIw7ec/7xidq3lnNve++23fOO2/u86ChPbyd+hp3tDbzH9g5OFLivVCXByCPHMPjlrkw+KsiuhI5VyBfT/z3mev9JJZ1ezywdfeccnNmbhVyuy/3Coj7nVwv2KwpAaAn8ZiVkezT652UsO8WCK5jJ0pcH9OYOrha9un1GVivwMzEOADJ6CoApQtx48bdQNnnr3cAugMNAMRWpoz1/usbALzBQQB8/kZLFZAv0/EwVpdVESfGMV+lsb94xz4FMu4f6lTybpkLdObf+lurwNTcvOLWh6XpXzX0n54Z89JP+ts/CwRtj1cAFHq9Sj4+uWisr5sdVeLXZBKA/ZIqy6fhT3O7YmNJPdOWFmNd8vBQiW97R7JOTXtfxYKjyAwAzQPp//jxp8v0tAuFjA3Pw2EA5ourjfvt84DTQkFNVQrgrb9Dyb/UNhlvhe76ootjtd9a+gXxlrjy2P0eEOZOyDDTGLpFRtlPJezzgNPZC6LBPgDKlyPG9fvhAQCC0XWzAms7dt2CDzsGp242tsuqAAAAAElFTkSuQmCC";
|
|
6443
6555
|
|
|
6556
|
+
// assets/NYNRoid.png
|
|
6557
|
+
var NYNRoid_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABo0lEQVR42tWXoU8DMRTGf7csCAQBOcz4A6aOIOZAETKLBsQGCCwhiIWQCUKCRDAyAWgcWQgoPOHU/gBmOAkJggRTRPeSa7m7lSHWPdNc23u97+v3vvYCrCiVSir5HMdxwAjhmqfAmCPI+uIURKnPcRxjIc1d0GZi7AwU7Y63qyMA5reODaR268qEnc9fDdhaaDabAERRZLRhGDollnmtVsvvKihmqb3b7QJQq9WcGOh0OgDU63Xj/SyN+KeBMAxV2h4K8peTbQAWDy9HGpeIoiiYDA3Y6l9Z29NI788NpII8WN0FYLmgU0ZDfMJ/BiSU0tI4m57RHZWqRn5XzZ33ZDmn/wwk1KmSKg4C3a0eLvIzPbYB2P/61H7wW0ue3wdSvFxZ9Wvu+YARUb/tH1l1PzkMiBYkxOMldpZuAWg/r6eeCa5r+s+A3AuknjcrNwDMvZ4C8L5wAMB1b8Ood7kHpGjFfwZU0tkajYaxt6Ly3tSsNsbvj/QqGbwvPpLFtscMWHtnnxGuMezPyv8q+AdylzX8ZsDJIfv9vjFYLpf/lHvsDPwA5Wy6PgZtokAAAAAASUVORK5CYII=";
|
|
6558
|
+
|
|
6444
6559
|
// assets/puyuyu.png
|
|
6445
6560
|
var puyuyu_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB60lEQVR42tWXPUxTURiGn9vWMCgtEQoDcWhAFgdtB0dMGjfcIAwMjcYoKIObq3F1EwKixNR0cCC46YQ4ODqIi4kRjUPj0Jaa1roYi9fh9Kuck3tvb7v08C73J+/5Tt7nnPvlHoeQend3yKULXXxQc8L4IvRZsU6JM9NJAKLZOQCazox6jiU0/2Gzrgq6r5RvetsFeP+2EkjEPgJ+yd3olDL81RObEp+My7Ct6oLrRcIeAmbyyKULngOikf2uJpA6GT54kug7gfZ6HO6cdwF+pYYBGBxT12vzrwF49mKpq8JXZzcAyG9dBqBRqgJw8lNRob+ybwkBc+2vrx1oBknQq4Sg6OnyCEf7g319YGU1rSM6taWujtou9S/ZwILxid1gf2sP2NsJZZdGZz57DkhMvlG9/uVZvT906bePwO9GDYCBwSFtDUWLN1UfePxkw/tzCumXeawh0O4D59InNAL54gIAN27d1wZsPrqnvu8zz/V+EdIvBD7u/bGUgEhI/BjLae9PlwqBBf385trbQ0Buvj2ccAFGR396kuhVZvJyOQ5A6s5Xx64+UPlebd2p/wAhYSYQ3S40tef1XCxwIkn+fx4s2wPmv2FyXCdhJjcT+703k1v3V+x0OhkJiV7ll9x+Ap1Px25giWNzOv4HHKK9IIEhxAYAAAAASUVORK5CYII=";
|
|
6446
6561
|
|
|
@@ -6476,7 +6591,8 @@ var VOICE_IMAGES = {
|
|
|
6476
6591
|
tsukuyomi: tsukuyomi_default,
|
|
6477
6592
|
rei: rei_default,
|
|
6478
6593
|
MGRoid: MGRoid_default,
|
|
6479
|
-
MOTRoid: MOTRoid_default
|
|
6594
|
+
MOTRoid: MOTRoid_default,
|
|
6595
|
+
NYNRoid: NYNRoid_default
|
|
6480
6596
|
};
|
|
6481
6597
|
var FALLBACK_VOCAL_ICON = Chip_default;
|
|
6482
6598
|
|
|
@@ -7709,12 +7825,12 @@ var KOE_INFO_HTML = `
|
|
|
7709
7825
|
|
|
7710
7826
|
<h4>3. DTM\u3067\u4F7F\u3046</h4>
|
|
7711
7827
|
<ul>
|
|
7712
|
-
<li>\u6B4C\u5531\u30E2\u30C7\u30EB\u306E\u30D7\u30EB\u30C0\u30A6\u30F3\u304B\u3089\u300C\u30AB\u30B9\u30BF\u30E0\u97F3\
|
|
7713
|
-
<li>\u300C\u97F3\
|
|
7714
|
-
<li>\u30A2\u30A4\u30B3\u30F3\u753B\
|
|
7828
|
+
<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>
|
|
7829
|
+
<li>\u300C\u97F3\u58F0URL\u300D\u306B\u624B\u98062\u306E\u76F4\u63A5\u30EA\u30F3\u30AF\u3092\u8CBC\u308A\u4ED8\u3051\u307E\u3059\u3002</li>
|
|
7830
|
+
<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>
|
|
7715
7831
|
<li>\u300C\u8FFD\u52A0\u300D\u3092\u62BC\u3059\u3068\u30D7\u30EB\u30C0\u30A6\u30F3\u306B\u767B\u9332\u3055\u308C\u3001\u4EE5\u964D\u305D\u306E\u30C8\u30E9\u30C3\u30AF\u3067\u4F7F\u3048\u307E\u3059\u3002</li>
|
|
7716
7832
|
</ul>
|
|
7717
|
-
<p style="margin-top:4px;"><small>\
|
|
7833
|
+
<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>
|
|
7718
7834
|
</div>
|
|
7719
7835
|
`;
|
|
7720
7836
|
var BASE_STEP_WIDTH = 0.5;
|
|
@@ -7858,6 +7974,24 @@ var TRACKS_ADVANCED = [
|
|
|
7858
7974
|
];
|
|
7859
7975
|
var DEFAULT_TRACKS = TRACKS_SIMPLE;
|
|
7860
7976
|
var BASE_LYRIC_MODELS = ["klatt", ...Object.keys(KOE_VOICEBANKS)];
|
|
7977
|
+
var LYRIC_MODEL_CATEGORIES = [
|
|
7978
|
+
{
|
|
7979
|
+
label: "kusa\u30D7\u30EA\u30BB\u30C3\u30C8",
|
|
7980
|
+
models: ["klatt", "tsukuyomi"]
|
|
7981
|
+
},
|
|
7982
|
+
{
|
|
7983
|
+
label: "\u304A\u3093J",
|
|
7984
|
+
models: ["roze", "shiyo", "rino"]
|
|
7985
|
+
},
|
|
7986
|
+
{
|
|
7987
|
+
label: "\u4E00\u822C",
|
|
7988
|
+
models: ["teto", "rei", "ruko_male", "ruko_female"]
|
|
7989
|
+
},
|
|
7990
|
+
{
|
|
7991
|
+
label: "\u30AF\u30C3\u30AD\u30FC\u2606",
|
|
7992
|
+
models: ["mgroid", "motroid", "nynroid"]
|
|
7993
|
+
}
|
|
7994
|
+
];
|
|
7861
7995
|
var BASE_LYRIC_MODEL_LABELS = {
|
|
7862
7996
|
klatt: "\u8EFD\u91CF\u30ED\u30DC\u58F0",
|
|
7863
7997
|
...KOE_VOICEBANK_LABELS
|
|
@@ -7865,6 +7999,18 @@ var BASE_LYRIC_MODEL_LABELS = {
|
|
|
7865
7999
|
var lyricModelLabel = (model, customMap) => BASE_LYRIC_MODEL_LABELS[model] ?? customMap.get(model)?.label ?? model;
|
|
7866
8000
|
var CUSTOM_VOCAL_ADD_VALUE = "+custom";
|
|
7867
8001
|
var CUSTOM_VOCAL_KEY_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
8002
|
+
var deriveCustomVocalKeyFromUrl = (url2) => {
|
|
8003
|
+
let name;
|
|
8004
|
+
try {
|
|
8005
|
+
const path = new URL(url2).pathname;
|
|
8006
|
+
name = decodeURIComponent(path.slice(path.lastIndexOf("/") + 1));
|
|
8007
|
+
} catch {
|
|
8008
|
+
return "";
|
|
8009
|
+
}
|
|
8010
|
+
name = name.replace(/\.[^.]*$/, "").normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
8011
|
+
if (name && /^[0-9]/.test(name)) name = `_${name}`;
|
|
8012
|
+
return CUSTOM_VOCAL_KEY_RE.test(name) ? name : "";
|
|
8013
|
+
};
|
|
7868
8014
|
var clamp3 = (v, min, max) => Math.min(Math.max(v, min), max);
|
|
7869
8015
|
var normalizeInstrumentName = (name) => {
|
|
7870
8016
|
if (!name) return "";
|
|
@@ -7882,13 +8028,16 @@ var mountDAW = (target, options = {}) => {
|
|
|
7882
8028
|
const drumPatterns = options.drumPatterns ?? DRUM_PATTERNS;
|
|
7883
8029
|
const showMidi = !!options.parseMidi;
|
|
7884
8030
|
const showChord = !isAdvanced;
|
|
8031
|
+
const midiSearchClient = options.midiSearch ? new MidiSearchClient(options.midiSearch) : void 0;
|
|
8032
|
+
const showMidiSearch = !!midiSearchClient?.enabled;
|
|
7885
8033
|
const refs = buildUI(target, {
|
|
7886
8034
|
tracks: trackConfigs,
|
|
7887
8035
|
drumPatternNames: Object.keys(drumPatterns),
|
|
7888
8036
|
defaultDrumPattern: drumPatterns.dance ? "dance" : Object.keys(drumPatterns)[0] ?? "none",
|
|
7889
8037
|
defaultBpm: options.defaultBpm ?? DEFAULT_BPM,
|
|
7890
8038
|
showMidi,
|
|
7891
|
-
showChord
|
|
8039
|
+
showChord,
|
|
8040
|
+
showMidiSearch
|
|
7892
8041
|
});
|
|
7893
8042
|
const renderConfig = {
|
|
7894
8043
|
stepsPerBar: 192,
|
|
@@ -8501,6 +8650,106 @@ var mountDAW = (target, options = {}) => {
|
|
|
8501
8650
|
redrawAll();
|
|
8502
8651
|
}
|
|
8503
8652
|
};
|
|
8653
|
+
const BG_DB_NAME = "dtm-daw-db";
|
|
8654
|
+
const BG_DB_STORE = "settings";
|
|
8655
|
+
const BG_DB_KEY = "piano-roll-bg";
|
|
8656
|
+
const BG_OPACITY_KEY = "dtm-piano-roll-bg-opacity";
|
|
8657
|
+
const COMPRESSIBLE_IMAGE_TYPES = /* @__PURE__ */ new Set([
|
|
8658
|
+
"image/jpeg",
|
|
8659
|
+
"image/png",
|
|
8660
|
+
"image/webp",
|
|
8661
|
+
"image/bmp"
|
|
8662
|
+
]);
|
|
8663
|
+
const openBgDb = () => new Promise((resolve, reject) => {
|
|
8664
|
+
const req = indexedDB.open(BG_DB_NAME, 1);
|
|
8665
|
+
req.onupgradeneeded = () => req.result.createObjectStore(BG_DB_STORE);
|
|
8666
|
+
req.onsuccess = () => resolve(req.result);
|
|
8667
|
+
req.onerror = () => reject(req.error);
|
|
8668
|
+
});
|
|
8669
|
+
const saveBgBlob = async (blob2) => {
|
|
8670
|
+
const db = await openBgDb();
|
|
8671
|
+
try {
|
|
8672
|
+
await new Promise((resolve, reject) => {
|
|
8673
|
+
const tx = db.transaction(BG_DB_STORE, "readwrite");
|
|
8674
|
+
tx.objectStore(BG_DB_STORE).put(blob2, BG_DB_KEY);
|
|
8675
|
+
tx.oncomplete = () => resolve();
|
|
8676
|
+
tx.onerror = () => reject(tx.error);
|
|
8677
|
+
});
|
|
8678
|
+
} finally {
|
|
8679
|
+
db.close();
|
|
8680
|
+
}
|
|
8681
|
+
};
|
|
8682
|
+
const loadBgBlob = async () => {
|
|
8683
|
+
const db = await openBgDb();
|
|
8684
|
+
try {
|
|
8685
|
+
return await new Promise((resolve, reject) => {
|
|
8686
|
+
const tx = db.transaction(BG_DB_STORE, "readonly");
|
|
8687
|
+
const req = tx.objectStore(BG_DB_STORE).get(BG_DB_KEY);
|
|
8688
|
+
req.onsuccess = () => resolve(req.result ?? null);
|
|
8689
|
+
req.onerror = () => reject(req.error);
|
|
8690
|
+
});
|
|
8691
|
+
} finally {
|
|
8692
|
+
db.close();
|
|
8693
|
+
}
|
|
8694
|
+
};
|
|
8695
|
+
const deleteBgBlob = async () => {
|
|
8696
|
+
const db = await openBgDb();
|
|
8697
|
+
try {
|
|
8698
|
+
await new Promise((resolve, reject) => {
|
|
8699
|
+
const tx = db.transaction(BG_DB_STORE, "readwrite");
|
|
8700
|
+
tx.objectStore(BG_DB_STORE).delete(BG_DB_KEY);
|
|
8701
|
+
tx.oncomplete = () => resolve();
|
|
8702
|
+
tx.onerror = () => reject(tx.error);
|
|
8703
|
+
});
|
|
8704
|
+
} finally {
|
|
8705
|
+
db.close();
|
|
8706
|
+
}
|
|
8707
|
+
};
|
|
8708
|
+
const resizeImageToBlob = (img, maxW, maxH) => {
|
|
8709
|
+
const scale = Math.min(1, maxW / img.width, maxH / img.height);
|
|
8710
|
+
const width = Math.max(1, Math.round(img.width * scale));
|
|
8711
|
+
const height = Math.max(1, Math.round(img.height * scale));
|
|
8712
|
+
const canvas = document.createElement("canvas");
|
|
8713
|
+
canvas.width = width;
|
|
8714
|
+
canvas.height = height;
|
|
8715
|
+
const ctx = canvas.getContext("2d");
|
|
8716
|
+
if (ctx) ctx.drawImage(img, 0, 0, width, height);
|
|
8717
|
+
return new Promise((resolve, reject) => {
|
|
8718
|
+
canvas.toBlob(
|
|
8719
|
+
(blob2) => blob2 ? resolve(blob2) : reject(new Error("toBlob failed")),
|
|
8720
|
+
"image/jpeg",
|
|
8721
|
+
0.7
|
|
8722
|
+
);
|
|
8723
|
+
});
|
|
8724
|
+
};
|
|
8725
|
+
let currentBgObjectUrl = null;
|
|
8726
|
+
const applyBgOpacity = (opacityVal) => {
|
|
8727
|
+
refs.rollContainer.style.setProperty(
|
|
8728
|
+
"--dtm-roll-bg-opacity",
|
|
8729
|
+
String(opacityVal / 100)
|
|
8730
|
+
);
|
|
8731
|
+
refs.bgOpacityInput.value = String(opacityVal);
|
|
8732
|
+
};
|
|
8733
|
+
const applyRollBackground = (blob2) => {
|
|
8734
|
+
if (currentBgObjectUrl) {
|
|
8735
|
+
URL.revokeObjectURL(currentBgObjectUrl);
|
|
8736
|
+
currentBgObjectUrl = null;
|
|
8737
|
+
}
|
|
8738
|
+
if (blob2) {
|
|
8739
|
+
currentBgObjectUrl = URL.createObjectURL(blob2);
|
|
8740
|
+
refs.rollContainer.style.setProperty(
|
|
8741
|
+
"--dtm-roll-bg-image",
|
|
8742
|
+
`url(${currentBgObjectUrl})`
|
|
8743
|
+
);
|
|
8744
|
+
refs.bgOpacityRow.classList.remove("dtm-hidden");
|
|
8745
|
+
} else {
|
|
8746
|
+
refs.rollContainer.style.setProperty("--dtm-roll-bg-image", "none");
|
|
8747
|
+
refs.bgOpacityRow.classList.add("dtm-hidden");
|
|
8748
|
+
}
|
|
8749
|
+
refs.bgRemoveBtn.classList.toggle("dtm-hidden", !blob2);
|
|
8750
|
+
setBackgroundActive(!!blob2);
|
|
8751
|
+
redrawAll();
|
|
8752
|
+
};
|
|
8504
8753
|
const setupCanvas = () => {
|
|
8505
8754
|
const w = refs.rollContainer.clientWidth || 800;
|
|
8506
8755
|
const h = refs.rollContainer.clientHeight || 450;
|
|
@@ -8866,10 +9115,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
8866
9115
|
<a data-dtm="lyric-custom-conv-link" href="https://onjmin.github.io/koe/demo/" target="_blank" rel="noopener" style="font-size:11px;color:var(--dtm-primary);text-decoration:underline">UTAU\u97F3\u6E90(zip)\u3092.koe\u306B\u5909\u63DB</a>
|
|
8867
9116
|
<button class="dtm-btn dtm-btn--ghost dtm-btn--xs" data-dtm="lyric-custom-guide">\u4F7F\u3044\u65B9\u30AC\u30A4\u30C9</button>
|
|
8868
9117
|
</div>
|
|
8869
|
-
<input type="url" class="dtm-input" data-dtm="lyric-custom-src" placeholder="\u97F3\
|
|
8870
|
-
<input type="url" class="dtm-input" data-dtm="lyric-custom-icon" placeholder="\u30A2\u30A4\u30B3\u30F3\u753B\u50CFURL\uFF08\u4EFB\u610F\uFF09" aria-label="\u30AB\u30B9\u30BF\u30E0\u97F3\
|
|
8871
|
-
<input type="text" class="dtm-input" data-dtm="lyric-custom-alias" placeholder="\u8868\u793A\u540D\uFF08\u4EFB\u610F\uFF09" aria-label="\u30AB\u30B9\u30BF\u30E0\u97F3\u6E90\u306E\u8868\u793A\u540D\uFF08\u30D7\u30EB\u30C0\u30A6\u30F3\u306E\u5225\u540D\uFF09" maxlength="64">
|
|
8872
|
-
<input type="text" class="dtm-input" data-dtm="lyric-custom-key" placeholder="\u8B58\u5225\u5B50\uFF08\u4EFB\u610F\u30FB\u7701\u7565\u3067\u81EA\u52D5\u63A1\u756A\u3001\u82F1\u5B57\u59CB\u307E\u308A\u82F1\u6570\u5B57\u3068_\uFF09" aria-label="\u30AB\u30B9\u30BF\u30E0\u97F3\u6E90\u306EMML\u8B58\u5225\u5B50\uFF08\u30AD\u30FC\uFF09" maxlength="32">
|
|
9118
|
+
<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">
|
|
9119
|
+
<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">
|
|
8873
9120
|
<div class="dtm-row">
|
|
8874
9121
|
<span class="dtm-label dtm-grow" data-dtm="lyric-custom-note" style="color:var(--dtm-warn)"></span>
|
|
8875
9122
|
<button class="dtm-btn dtm-btn--primary" data-dtm="lyric-custom-apply">\u8FFD\u52A0</button>
|
|
@@ -8934,12 +9181,6 @@ var mountDAW = (target, options = {}) => {
|
|
|
8934
9181
|
const lyricCustomIcon = lyricDiv.querySelector(
|
|
8935
9182
|
'[data-dtm="lyric-custom-icon"]'
|
|
8936
9183
|
);
|
|
8937
|
-
const lyricCustomAlias = lyricDiv.querySelector(
|
|
8938
|
-
'[data-dtm="lyric-custom-alias"]'
|
|
8939
|
-
);
|
|
8940
|
-
const lyricCustomKey = lyricDiv.querySelector(
|
|
8941
|
-
'[data-dtm="lyric-custom-key"]'
|
|
8942
|
-
);
|
|
8943
9184
|
const lyricCustomGuide = lyricDiv.querySelector(
|
|
8944
9185
|
'[data-dtm="lyric-custom-guide"]'
|
|
8945
9186
|
);
|
|
@@ -8950,23 +9191,35 @@ var mountDAW = (target, options = {}) => {
|
|
|
8950
9191
|
'[data-dtm="lyric-custom-apply"]'
|
|
8951
9192
|
);
|
|
8952
9193
|
const fmtPan = (pan) => pan === 64 ? "C" : pan < 64 ? `L${64 - pan}` : `R${pan - 64}`;
|
|
8953
|
-
const addOpt = (value, label) => {
|
|
9194
|
+
const addOpt = (parent, value, label) => {
|
|
8954
9195
|
const o = document.createElement("option");
|
|
8955
9196
|
o.value = value;
|
|
8956
9197
|
o.textContent = label;
|
|
8957
|
-
|
|
9198
|
+
parent.appendChild(o);
|
|
8958
9199
|
};
|
|
8959
|
-
addOpt("", "\u30DC\u30FC\u30AB\u30EB\u306A\u3057");
|
|
8960
|
-
for (const
|
|
8961
|
-
|
|
8962
|
-
|
|
8963
|
-
|
|
9200
|
+
addOpt(lyricModelSel, "", "\u30DC\u30FC\u30AB\u30EB\u306A\u3057");
|
|
9201
|
+
for (const cat of LYRIC_MODEL_CATEGORIES) {
|
|
9202
|
+
const group = document.createElement("optgroup");
|
|
9203
|
+
group.label = cat.label;
|
|
9204
|
+
for (const m of cat.models) {
|
|
9205
|
+
addOpt(group, m, lyricModelLabel(m, customVocalsMap));
|
|
9206
|
+
}
|
|
9207
|
+
lyricModelSel.appendChild(group);
|
|
9208
|
+
}
|
|
9209
|
+
const customGroup = document.createElement("optgroup");
|
|
9210
|
+
customGroup.label = "\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0";
|
|
9211
|
+
for (const [k, def] of customVocalsMap) {
|
|
9212
|
+
addOpt(customGroup, k, def.label ?? k);
|
|
9213
|
+
}
|
|
9214
|
+
addOpt(customGroup, CUSTOM_VOCAL_ADD_VALUE, "\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0\u3092\u8FFD\u52A0\u2026");
|
|
8964
9215
|
if (active.lyricModel && !BASE_LYRIC_MODELS.includes(active.lyricModel) && !customVocalsMap.has(active.lyricModel)) {
|
|
8965
9216
|
addOpt(
|
|
9217
|
+
customGroup,
|
|
8966
9218
|
active.lyricModel,
|
|
8967
9219
|
lyricModelLabel(active.lyricModel, customVocalsMap)
|
|
8968
9220
|
);
|
|
8969
9221
|
}
|
|
9222
|
+
lyricModelSel.appendChild(customGroup);
|
|
8970
9223
|
lyricModelSel.value = active.lyricModel;
|
|
8971
9224
|
lyricOctaveSel.value = String(active.vocalOctave);
|
|
8972
9225
|
lyricInput.value = active.lyrics;
|
|
@@ -9032,9 +9285,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
9032
9285
|
lyricModelSel.addEventListener("change", () => {
|
|
9033
9286
|
if (lyricModelSel.value === CUSTOM_VOCAL_ADD_VALUE) {
|
|
9034
9287
|
lyricCustomNote.textContent = "";
|
|
9035
|
-
lyricCustomAlias.value = "";
|
|
9036
|
-
lyricCustomKey.value = "";
|
|
9037
9288
|
lyricCustom.classList.remove("dtm-hidden");
|
|
9289
|
+
lyricIcon.removeAttribute("src");
|
|
9290
|
+
lyricIcon.classList.add("dtm-hidden");
|
|
9291
|
+
lyricTerms.classList.add("dtm-hidden");
|
|
9038
9292
|
return;
|
|
9039
9293
|
}
|
|
9040
9294
|
lyricCustom.classList.add("dtm-hidden");
|
|
@@ -9044,45 +9298,41 @@ var mountDAW = (target, options = {}) => {
|
|
|
9044
9298
|
fireLyricsChange(active);
|
|
9045
9299
|
});
|
|
9046
9300
|
lyricCustomGuide.addEventListener("click", () => {
|
|
9047
|
-
showModal("\u30AB\u30B9\u30BF\u30E0\u97F3\
|
|
9301
|
+
showModal("\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0(.koe)\u306E\u4F7F\u3044\u65B9", KOE_INFO_HTML);
|
|
9048
9302
|
});
|
|
9049
9303
|
lyricCustomApply.addEventListener("click", () => {
|
|
9050
9304
|
const src = lyricCustomSrc.value.trim();
|
|
9051
9305
|
if (!isValidHttpUrl(src)) {
|
|
9052
|
-
lyricCustomNote.textContent = "\u97F3\
|
|
9306
|
+
lyricCustomNote.textContent = "\u97F3\u58F0URL\u304C\u4E0D\u6B63\u3067\u3059\uFF08http/https\u306E\u307F\u30FB2048\u6587\u5B57\u307E\u3067\uFF09";
|
|
9053
9307
|
return;
|
|
9054
9308
|
}
|
|
9055
9309
|
const iconRaw = lyricCustomIcon.value.trim();
|
|
9056
9310
|
const iconUrl = isValidHttpUrl(iconRaw) ? iconRaw : "";
|
|
9057
|
-
const alias = lyricCustomAlias.value.trim();
|
|
9058
9311
|
const existing = [...customVocalsMap.values()].find(
|
|
9059
9312
|
(d) => d.url === src
|
|
9060
9313
|
);
|
|
9061
|
-
const keyRaw = lyricCustomKey.value.trim().toLowerCase();
|
|
9062
9314
|
let key;
|
|
9063
|
-
if (
|
|
9064
|
-
|
|
9065
|
-
lyricCustomNote.textContent = "\u8B58\u5225\u5B50\u304C\u4E0D\u6B63\u3067\u3059\uFF08\u82F1\u5B57\u307E\u305F\u306F\u30A2\u30F3\u30C0\u30FC\u30B9\u30B3\u30A2\u3067\u59CB\u307E\u308B\u82F1\u6570\u5B57\u30FB_\u306E\u307F\uFF09";
|
|
9066
|
-
return;
|
|
9067
|
-
}
|
|
9068
|
-
if (BASE_LYRIC_MODELS.includes(keyRaw)) {
|
|
9069
|
-
lyricCustomNote.textContent = "\u305D\u306E\u8B58\u5225\u5B50\u306F\u5185\u8535\u30E2\u30C7\u30EB\u540D\u3068\u885D\u7A81\u3057\u3066\u3044\u307E\u3059";
|
|
9070
|
-
return;
|
|
9071
|
-
}
|
|
9072
|
-
const conflict = customVocalsMap.get(keyRaw);
|
|
9073
|
-
if (conflict && conflict.url !== src) {
|
|
9074
|
-
lyricCustomNote.textContent = "\u305D\u306E\u8B58\u5225\u5B50\u306F\u5225\u306E\u97F3\u6E90\u306B\u4F7F\u7528\u6E08\u307F\u3067\u3059";
|
|
9075
|
-
return;
|
|
9076
|
-
}
|
|
9077
|
-
key = keyRaw;
|
|
9315
|
+
if (existing) {
|
|
9316
|
+
key = existing.key;
|
|
9078
9317
|
} else {
|
|
9079
|
-
|
|
9318
|
+
const derived = deriveCustomVocalKeyFromUrl(src);
|
|
9319
|
+
if (derived && !BASE_LYRIC_MODELS.includes(derived)) {
|
|
9320
|
+
if (!customVocalsMap.has(derived)) {
|
|
9321
|
+
key = derived;
|
|
9322
|
+
} else {
|
|
9323
|
+
let n = 2;
|
|
9324
|
+
while (customVocalsMap.has(`${derived}${n}`)) n++;
|
|
9325
|
+
key = `${derived}${n}`;
|
|
9326
|
+
}
|
|
9327
|
+
} else {
|
|
9328
|
+
key = genCustomVocalKey();
|
|
9329
|
+
}
|
|
9080
9330
|
}
|
|
9081
9331
|
registerCustomVocal({
|
|
9082
9332
|
key,
|
|
9083
9333
|
iconUrl: iconUrl || (existing?.iconUrl ?? ""),
|
|
9084
9334
|
url: src,
|
|
9085
|
-
label:
|
|
9335
|
+
label: existing?.label
|
|
9086
9336
|
});
|
|
9087
9337
|
active.lyricModel = key;
|
|
9088
9338
|
fireLyricsChange(active);
|
|
@@ -9361,7 +9611,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
9361
9611
|
bpm: parsedBpm,
|
|
9362
9612
|
lyrics,
|
|
9363
9613
|
meta,
|
|
9364
|
-
mergedTrackCount
|
|
9614
|
+
mergedTrackCount,
|
|
9615
|
+
trackVelocity
|
|
9365
9616
|
} = parseMML(mml, {
|
|
9366
9617
|
stepsPerBar: renderConfig.stepsPerBar,
|
|
9367
9618
|
collectLyrics: true,
|
|
@@ -9394,6 +9645,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
9394
9645
|
options.onTrackInstrumentChange?.(i, name);
|
|
9395
9646
|
}
|
|
9396
9647
|
});
|
|
9648
|
+
trackStates.forEach((t, i) => {
|
|
9649
|
+
const v = trackVelocity.get(i);
|
|
9650
|
+
if (v !== void 0 && v !== t.volume) {
|
|
9651
|
+
t.volume = v;
|
|
9652
|
+
t.core.setVolume(v);
|
|
9653
|
+
}
|
|
9654
|
+
});
|
|
9397
9655
|
for (const t of trackStates) {
|
|
9398
9656
|
t.lyrics = "";
|
|
9399
9657
|
t.lyricModel = "";
|
|
@@ -9585,7 +9843,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
9585
9843
|
refs.prevBarBtn.addEventListener("click", () => {
|
|
9586
9844
|
const targetStep = Math.max(
|
|
9587
9845
|
0,
|
|
9588
|
-
Math.floor((getCurrentPlayStep() - 1) / renderConfig.stepsPerBar) * renderConfig.stepsPerBar
|
|
9846
|
+
(Math.floor((getCurrentPlayStep() - 1) / renderConfig.stepsPerBar) - 1) * renderConfig.stepsPerBar
|
|
9589
9847
|
);
|
|
9590
9848
|
jumpTo(targetStep);
|
|
9591
9849
|
});
|
|
@@ -9630,6 +9888,41 @@ var mountDAW = (target, options = {}) => {
|
|
|
9630
9888
|
applyZoomY();
|
|
9631
9889
|
notifyViewState();
|
|
9632
9890
|
});
|
|
9891
|
+
refs.bgUploadBtn.addEventListener("click", () => refs.bgFileInput.click());
|
|
9892
|
+
refs.bgFileInput.addEventListener("change", () => {
|
|
9893
|
+
const file = refs.bgFileInput.files?.[0];
|
|
9894
|
+
refs.bgFileInput.value = "";
|
|
9895
|
+
if (!file) return;
|
|
9896
|
+
if (!COMPRESSIBLE_IMAGE_TYPES.has(file.type)) {
|
|
9897
|
+
saveBgBlob(file).then(() => applyRollBackground(file)).catch(() => {
|
|
9898
|
+
});
|
|
9899
|
+
return;
|
|
9900
|
+
}
|
|
9901
|
+
const objectUrl = URL.createObjectURL(file);
|
|
9902
|
+
const img = new Image();
|
|
9903
|
+
img.onload = () => {
|
|
9904
|
+
URL.revokeObjectURL(objectUrl);
|
|
9905
|
+
const maxW = refs.rollContainer.clientWidth || 800;
|
|
9906
|
+
const maxH = refs.rollContainer.clientHeight || 450;
|
|
9907
|
+
resizeImageToBlob(img, maxW, maxH).then(
|
|
9908
|
+
(blob2) => saveBgBlob(blob2).then(() => applyRollBackground(blob2))
|
|
9909
|
+
).catch(() => {
|
|
9910
|
+
});
|
|
9911
|
+
};
|
|
9912
|
+
img.src = objectUrl;
|
|
9913
|
+
});
|
|
9914
|
+
refs.bgRemoveBtn.addEventListener("click", () => {
|
|
9915
|
+
deleteBgBlob().catch(() => {
|
|
9916
|
+
}).finally(() => applyRollBackground(null));
|
|
9917
|
+
});
|
|
9918
|
+
refs.bgOpacityInput.addEventListener("input", () => {
|
|
9919
|
+
const opacityVal = Number.parseInt(refs.bgOpacityInput.value, 10);
|
|
9920
|
+
applyBgOpacity(opacityVal);
|
|
9921
|
+
try {
|
|
9922
|
+
localStorage.setItem(BG_OPACITY_KEY, String(opacityVal));
|
|
9923
|
+
} catch (_) {
|
|
9924
|
+
}
|
|
9925
|
+
});
|
|
9633
9926
|
refs.decomposeChordToggle.addEventListener("change", notifyViewState);
|
|
9634
9927
|
refs.ignoreChordHeavyToggle.addEventListener("change", notifyViewState);
|
|
9635
9928
|
refs.masterVolume.addEventListener("input", () => {
|
|
@@ -9702,11 +9995,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
9702
9995
|
refs.mmlLoadBtn.addEventListener("click", async () => {
|
|
9703
9996
|
const mml = refs.mmlInput.value;
|
|
9704
9997
|
if (!isAdvanced && options.onRequestAdvancedMode) {
|
|
9705
|
-
const { mergedTrackCount } = parseMML(mml, {
|
|
9998
|
+
const { mergedTrackCount, meta } = parseMML(mml, {
|
|
9706
9999
|
stepsPerBar: renderConfig.stepsPerBar,
|
|
9707
10000
|
clampTrackCount: trackStates.length
|
|
9708
10001
|
});
|
|
9709
|
-
if (mergedTrackCount > 0) {
|
|
10002
|
+
if (mergedTrackCount > 0 || meta.mode === "advanced") {
|
|
9710
10003
|
const confirmed = await showConfirmModal(
|
|
9711
10004
|
"\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"
|
|
9712
10005
|
);
|
|
@@ -9740,6 +10033,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
9740
10033
|
};
|
|
9741
10034
|
showModal = (title, bodyHTML) => {
|
|
9742
10035
|
collapseActiveSample();
|
|
10036
|
+
collapseSearchPreview();
|
|
9743
10037
|
refs.modalTitle.textContent = title;
|
|
9744
10038
|
refs.modalBody.innerHTML = bodyHTML;
|
|
9745
10039
|
refs.modalOverlay.removeAttribute("hidden");
|
|
@@ -9828,11 +10122,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
9828
10122
|
};
|
|
9829
10123
|
refs.modalClose.addEventListener("click", () => {
|
|
9830
10124
|
collapseActiveSample();
|
|
10125
|
+
collapseSearchPreview();
|
|
9831
10126
|
refs.modalOverlay.setAttribute("hidden", "");
|
|
9832
10127
|
});
|
|
9833
10128
|
refs.modalOverlay.addEventListener("click", (e) => {
|
|
9834
10129
|
if (e.target === refs.modalOverlay) {
|
|
9835
10130
|
collapseActiveSample();
|
|
10131
|
+
collapseSearchPreview();
|
|
9836
10132
|
refs.modalOverlay.setAttribute("hidden", "");
|
|
9837
10133
|
}
|
|
9838
10134
|
});
|
|
@@ -9853,6 +10149,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
9853
10149
|
})
|
|
9854
10150
|
);
|
|
9855
10151
|
if (showMidi) wireMidi();
|
|
10152
|
+
if (showMidiSearch) wireMidiSearch();
|
|
9856
10153
|
document.addEventListener("keydown", onKeyDown);
|
|
9857
10154
|
refs.root.addEventListener("keydown", (e) => {
|
|
9858
10155
|
const t = e.target;
|
|
@@ -9917,6 +10214,236 @@ var mountDAW = (target, options = {}) => {
|
|
|
9917
10214
|
overlayDuring(() => applyMidiSelection(pendingMidi, selected));
|
|
9918
10215
|
});
|
|
9919
10216
|
};
|
|
10217
|
+
const buildPreviewMml = (midi) => {
|
|
10218
|
+
const analysis = analyzeMidiTracks(midi);
|
|
10219
|
+
const selected = analysis.filter((a) => a.selected).map((a) => a.index);
|
|
10220
|
+
const { placements, bpm: parsedBpm } = extractMidiPlacements(
|
|
10221
|
+
midi,
|
|
10222
|
+
selected
|
|
10223
|
+
);
|
|
10224
|
+
const byTrack = /* @__PURE__ */ new Map();
|
|
10225
|
+
for (const p of placements) {
|
|
10226
|
+
if (!byTrack.has(p.trackId)) byTrack.set(p.trackId, []);
|
|
10227
|
+
byTrack.get(p.trackId)?.push(p);
|
|
10228
|
+
}
|
|
10229
|
+
const refCore = trackStates[0].core;
|
|
10230
|
+
const tempo = Math.round(parsedBpm) || bpm;
|
|
10231
|
+
const lines = [];
|
|
10232
|
+
let i = 0;
|
|
10233
|
+
for (const notes of byTrack.values()) {
|
|
10234
|
+
const asNotes = notes.map((p) => ({
|
|
10235
|
+
id: 0,
|
|
10236
|
+
startStep: p.startStep,
|
|
10237
|
+
durationSteps: p.durationSteps,
|
|
10238
|
+
pitch: p.pitch,
|
|
10239
|
+
velocity: p.velocity
|
|
10240
|
+
}));
|
|
10241
|
+
const mml = refCore.getMMLFromNotes(asNotes, tempo, 100).trim();
|
|
10242
|
+
lines.push(`@${i} ${mml}`);
|
|
10243
|
+
i++;
|
|
10244
|
+
}
|
|
10245
|
+
return [...lines, MML_END_MARKER].join(";\n");
|
|
10246
|
+
};
|
|
10247
|
+
const fetchVerifiedMidi = async (fileName) => {
|
|
10248
|
+
if (!options.parseMidi || !midiSearchClient) {
|
|
10249
|
+
throw new Error("parseMidi/midiSearchClient not injected");
|
|
10250
|
+
}
|
|
10251
|
+
const midiBytes = await midiSearchClient.fetchMidi(fileName);
|
|
10252
|
+
const midi = await options.parseMidi(new Uint8Array(midiBytes));
|
|
10253
|
+
const analysis = analyzeMidiTracks(midi);
|
|
10254
|
+
const selected = analysis.filter((a) => a.selected).map((a) => a.index);
|
|
10255
|
+
if (!isPlausibleMidiTranscription(midi, selected)) {
|
|
10256
|
+
throw new Error("implausible MIDI transcription");
|
|
10257
|
+
}
|
|
10258
|
+
return midi;
|
|
10259
|
+
};
|
|
10260
|
+
let searchPreviewPlayer = null;
|
|
10261
|
+
let searchPreviewBtn = null;
|
|
10262
|
+
const collapseSearchPreview = () => {
|
|
10263
|
+
if (searchPreviewPlayer) {
|
|
10264
|
+
searchPreviewPlayer.stop();
|
|
10265
|
+
searchPreviewPlayer.destroy();
|
|
10266
|
+
searchPreviewPlayer = null;
|
|
10267
|
+
}
|
|
10268
|
+
if (searchPreviewBtn) {
|
|
10269
|
+
searchPreviewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
10270
|
+
searchPreviewBtn.classList.remove("dtm-btn--danger");
|
|
10271
|
+
searchPreviewBtn.classList.add("dtm-btn--ghost");
|
|
10272
|
+
const container = searchPreviewBtn.closest(".dtm-modal-sample-box")?.querySelector(".dtm-modal-sample-player-container");
|
|
10273
|
+
if (container) container.innerHTML = "";
|
|
10274
|
+
searchPreviewBtn = null;
|
|
10275
|
+
}
|
|
10276
|
+
};
|
|
10277
|
+
const wireMidiSearch = () => {
|
|
10278
|
+
if (!midiSearchClient) return;
|
|
10279
|
+
refs.midiSearchOpenBtn.addEventListener("click", () => {
|
|
10280
|
+
showModal(
|
|
10281
|
+
"MML\u691C\u7D22",
|
|
10282
|
+
`
|
|
10283
|
+
<div class="dtm-row" style="flex-wrap:nowrap">
|
|
10284
|
+
<input type="text" class="dtm-input dtm-grow" data-dtm="modal-midi-search-input" placeholder="\u66F2\u540D\u3067MML\u691C\u7D22" style="min-width:0">
|
|
10285
|
+
<button class="dtm-btn dtm-btn--primary" data-dtm="modal-midi-search-btn" style="flex-shrink:0">\u691C\u7D22</button>
|
|
10286
|
+
</div>
|
|
10287
|
+
<div class="dtm-row" data-dtm="modal-midi-search-results" style="flex-direction:column;align-items:stretch;gap:4px"></div>
|
|
10288
|
+
`
|
|
10289
|
+
);
|
|
10290
|
+
const input = refs.modalBody.querySelector(
|
|
10291
|
+
'[data-dtm="modal-midi-search-input"]'
|
|
10292
|
+
);
|
|
10293
|
+
const searchBtn = refs.modalBody.querySelector(
|
|
10294
|
+
'[data-dtm="modal-midi-search-btn"]'
|
|
10295
|
+
);
|
|
10296
|
+
const results = refs.modalBody.querySelector(
|
|
10297
|
+
'[data-dtm="modal-midi-search-results"]'
|
|
10298
|
+
);
|
|
10299
|
+
const runSearch = async () => {
|
|
10300
|
+
const q2 = input.value.trim();
|
|
10301
|
+
if (!q2) return;
|
|
10302
|
+
collapseSearchPreview();
|
|
10303
|
+
searchBtn.disabled = true;
|
|
10304
|
+
searchBtn.textContent = "\u691C\u7D22\u4E2D...";
|
|
10305
|
+
results.innerHTML = "";
|
|
10306
|
+
try {
|
|
10307
|
+
const songs = await midiSearchClient.searchSongs({ title: q2 });
|
|
10308
|
+
if (songs.length === 0) {
|
|
10309
|
+
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F</span>';
|
|
10310
|
+
return;
|
|
10311
|
+
}
|
|
10312
|
+
for (const song of songs) {
|
|
10313
|
+
const box = document.createElement("div");
|
|
10314
|
+
box.className = "dtm-modal-sample-box";
|
|
10315
|
+
const row = document.createElement("div");
|
|
10316
|
+
row.className = "dtm-row";
|
|
10317
|
+
row.style.cssText = "flex-wrap:nowrap;gap:4px;padding:2px 0";
|
|
10318
|
+
const label = document.createElement("span");
|
|
10319
|
+
label.className = "dtm-label";
|
|
10320
|
+
label.style.cssText = "flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
|
|
10321
|
+
label.textContent = `${song.title} - ${song.user}`;
|
|
10322
|
+
const previewBtn = document.createElement("button");
|
|
10323
|
+
previewBtn.className = "dtm-btn dtm-btn--ghost";
|
|
10324
|
+
previewBtn.style.cssText = "flex-shrink:0";
|
|
10325
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
10326
|
+
const loadBtn = document.createElement("button");
|
|
10327
|
+
loadBtn.className = "dtm-btn dtm-btn--primary";
|
|
10328
|
+
loadBtn.style.cssText = "flex-shrink:0";
|
|
10329
|
+
loadBtn.textContent = "\u8AAD\u307F\u8FBC\u307F";
|
|
10330
|
+
const playerContainer = document.createElement("div");
|
|
10331
|
+
playerContainer.className = "dtm-modal-sample-player-container";
|
|
10332
|
+
previewBtn.addEventListener("click", async () => {
|
|
10333
|
+
if (searchPreviewBtn === previewBtn) {
|
|
10334
|
+
if (searchPreviewPlayer?.isPlaying()) {
|
|
10335
|
+
searchPreviewPlayer.stop();
|
|
10336
|
+
} else {
|
|
10337
|
+
stop();
|
|
10338
|
+
previewBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
10339
|
+
try {
|
|
10340
|
+
const midi = await fetchVerifiedMidi(song.file);
|
|
10341
|
+
const mml = buildPreviewMml(midi);
|
|
10342
|
+
playerContainer.innerHTML = "";
|
|
10343
|
+
const player = mountMmlPlayer(playerContainer, mml, {
|
|
10344
|
+
onPlayNote: options.onPlayNote,
|
|
10345
|
+
onPlayDrum: options.onPlayDrum,
|
|
10346
|
+
onResumeAudio: options.onResumeAudio,
|
|
10347
|
+
getAudioTime: options.getAudioTime,
|
|
10348
|
+
singingVoices: options.singingVoices,
|
|
10349
|
+
drumPatterns: options.drumPatterns,
|
|
10350
|
+
volume: masterVolume,
|
|
10351
|
+
_skipInfoModals: true,
|
|
10352
|
+
onStop: () => {
|
|
10353
|
+
if (searchPreviewBtn === previewBtn) {
|
|
10354
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
10355
|
+
previewBtn.classList.remove("dtm-btn--danger");
|
|
10356
|
+
previewBtn.classList.add("dtm-btn--ghost");
|
|
10357
|
+
}
|
|
10358
|
+
}
|
|
10359
|
+
});
|
|
10360
|
+
searchPreviewPlayer = player;
|
|
10361
|
+
searchPreviewBtn = previewBtn;
|
|
10362
|
+
player.play();
|
|
10363
|
+
previewBtn.textContent = "\u25A0 \u505C\u6B62";
|
|
10364
|
+
previewBtn.classList.remove("dtm-btn--ghost");
|
|
10365
|
+
previewBtn.classList.add("dtm-btn--danger");
|
|
10366
|
+
} catch (e) {
|
|
10367
|
+
console.error("[dtm] MIDI preview failed", e);
|
|
10368
|
+
previewBtn.textContent = "\u5931\u6557";
|
|
10369
|
+
}
|
|
10370
|
+
}
|
|
10371
|
+
} else {
|
|
10372
|
+
collapseSearchPreview();
|
|
10373
|
+
stop();
|
|
10374
|
+
previewBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
10375
|
+
try {
|
|
10376
|
+
const midi = await fetchVerifiedMidi(song.file);
|
|
10377
|
+
const mml = buildPreviewMml(midi);
|
|
10378
|
+
playerContainer.innerHTML = "";
|
|
10379
|
+
const player = mountMmlPlayer(playerContainer, mml, {
|
|
10380
|
+
onPlayNote: options.onPlayNote,
|
|
10381
|
+
onPlayDrum: options.onPlayDrum,
|
|
10382
|
+
onResumeAudio: options.onResumeAudio,
|
|
10383
|
+
getAudioTime: options.getAudioTime,
|
|
10384
|
+
singingVoices: options.singingVoices,
|
|
10385
|
+
drumPatterns: options.drumPatterns,
|
|
10386
|
+
volume: masterVolume,
|
|
10387
|
+
_skipInfoModals: true,
|
|
10388
|
+
onStop: () => {
|
|
10389
|
+
if (searchPreviewBtn === previewBtn) {
|
|
10390
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
10391
|
+
previewBtn.classList.remove("dtm-btn--danger");
|
|
10392
|
+
previewBtn.classList.add("dtm-btn--ghost");
|
|
10393
|
+
}
|
|
10394
|
+
}
|
|
10395
|
+
});
|
|
10396
|
+
searchPreviewPlayer = player;
|
|
10397
|
+
searchPreviewBtn = previewBtn;
|
|
10398
|
+
player.play();
|
|
10399
|
+
previewBtn.textContent = "\u25A0 \u505C\u6B62";
|
|
10400
|
+
previewBtn.classList.remove("dtm-btn--ghost");
|
|
10401
|
+
previewBtn.classList.add("dtm-btn--danger");
|
|
10402
|
+
} catch (e) {
|
|
10403
|
+
console.error("[dtm] MIDI preview failed", e);
|
|
10404
|
+
previewBtn.textContent = "\u5931\u6557";
|
|
10405
|
+
}
|
|
10406
|
+
}
|
|
10407
|
+
});
|
|
10408
|
+
loadBtn.addEventListener("click", async () => {
|
|
10409
|
+
loadBtn.disabled = true;
|
|
10410
|
+
loadBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
10411
|
+
try {
|
|
10412
|
+
const pending = await fetchVerifiedMidi(song.file);
|
|
10413
|
+
const analysis = analyzeMidiTracks(pending);
|
|
10414
|
+
const sel = analysis.filter((a) => a.selected).map((a) => a.index);
|
|
10415
|
+
collapseSearchPreview();
|
|
10416
|
+
overlayDuring(() => applyMidiSelection(pending, sel));
|
|
10417
|
+
refs.modalOverlay.setAttribute("hidden", "");
|
|
10418
|
+
} catch (e) {
|
|
10419
|
+
console.error("[dtm] MIDI fetch failed", e);
|
|
10420
|
+
loadBtn.textContent = "\u5931\u6557";
|
|
10421
|
+
} finally {
|
|
10422
|
+
loadBtn.disabled = false;
|
|
10423
|
+
}
|
|
10424
|
+
});
|
|
10425
|
+
row.appendChild(label);
|
|
10426
|
+
row.appendChild(previewBtn);
|
|
10427
|
+
row.appendChild(loadBtn);
|
|
10428
|
+
box.appendChild(row);
|
|
10429
|
+
box.appendChild(playerContainer);
|
|
10430
|
+
results.appendChild(box);
|
|
10431
|
+
}
|
|
10432
|
+
} catch (e) {
|
|
10433
|
+
console.error("[dtm] MIDI search failed", e);
|
|
10434
|
+
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u691C\u7D22\u306B\u5931\u6557\u3057\u307E\u3057\u305F</span>';
|
|
10435
|
+
} finally {
|
|
10436
|
+
searchBtn.disabled = false;
|
|
10437
|
+
searchBtn.textContent = "\u691C\u7D22";
|
|
10438
|
+
}
|
|
10439
|
+
};
|
|
10440
|
+
searchBtn.addEventListener("click", () => void runSearch());
|
|
10441
|
+
input.addEventListener("keydown", (e) => {
|
|
10442
|
+
if (e.key === "Enter") void runSearch();
|
|
10443
|
+
});
|
|
10444
|
+
input.focus();
|
|
10445
|
+
});
|
|
10446
|
+
};
|
|
9920
10447
|
const onKeyDown = (e) => {
|
|
9921
10448
|
if (!(e.ctrlKey || e.metaKey)) return;
|
|
9922
10449
|
if (e.code === "KeyZ" && !e.shiftKey) {
|
|
@@ -9972,6 +10499,22 @@ var mountDAW = (target, options = {}) => {
|
|
|
9972
10499
|
updateUndoRedo();
|
|
9973
10500
|
redrawAll();
|
|
9974
10501
|
if (options.initialMML) loadMML(options.initialMML);
|
|
10502
|
+
let initialOpacity = 40;
|
|
10503
|
+
try {
|
|
10504
|
+
const storedOpacity = localStorage.getItem(BG_OPACITY_KEY);
|
|
10505
|
+
if (storedOpacity !== null) {
|
|
10506
|
+
initialOpacity = Number.parseInt(storedOpacity, 10);
|
|
10507
|
+
if (Number.isNaN(initialOpacity) || initialOpacity < 0 || initialOpacity > 100) {
|
|
10508
|
+
initialOpacity = 40;
|
|
10509
|
+
}
|
|
10510
|
+
}
|
|
10511
|
+
} catch (_) {
|
|
10512
|
+
}
|
|
10513
|
+
applyBgOpacity(initialOpacity);
|
|
10514
|
+
loadBgBlob().then((blob2) => {
|
|
10515
|
+
if (blob2) applyRollBackground(blob2);
|
|
10516
|
+
}).catch(() => {
|
|
10517
|
+
});
|
|
9975
10518
|
let resizeTimer = null;
|
|
9976
10519
|
const resizeObserver = new ResizeObserver(() => {
|
|
9977
10520
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
@@ -11293,13 +11836,17 @@ var createDtmStudio = async (options = {}) => {
|
|
|
11293
11836
|
const mountedPlayers = [];
|
|
11294
11837
|
const mountedModeSwitches = [];
|
|
11295
11838
|
const mountEditor = (target, opts = {}) => {
|
|
11839
|
+
const mergedOpts = {
|
|
11840
|
+
midiSearch: options.midiSearch,
|
|
11841
|
+
...opts
|
|
11842
|
+
};
|
|
11296
11843
|
const {
|
|
11297
11844
|
preset,
|
|
11298
11845
|
presetUI,
|
|
11299
11846
|
onInstrumentChange,
|
|
11300
11847
|
onTrackInstrumentChange: externalOnTrackInstrumentChange,
|
|
11301
11848
|
...dawOverrides
|
|
11302
|
-
} =
|
|
11849
|
+
} = mergedOpts;
|
|
11303
11850
|
const tracks = dawOverrides.tracks ?? TRACKS_SIMPLE;
|
|
11304
11851
|
const trackIds = tracks.map((t) => t.id);
|
|
11305
11852
|
const presetKey = preset && INSTRUMENT_PRESETS[preset] ? preset : defaultPreset;
|
|
@@ -11635,6 +12182,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
11635
12182
|
MAX_VOCAL_VOLUME,
|
|
11636
12183
|
MMLCore,
|
|
11637
12184
|
MML_END_MARKER,
|
|
12185
|
+
MidiSearchClient,
|
|
11638
12186
|
PITCH_MAP,
|
|
11639
12187
|
PREWARM_NOTES,
|
|
11640
12188
|
TRACKS_ADVANCED,
|
|
@@ -11684,6 +12232,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
11684
12232
|
init,
|
|
11685
12233
|
injectStyles,
|
|
11686
12234
|
isChordHeavyTrack,
|
|
12235
|
+
isPlausibleMidiTranscription,
|
|
11687
12236
|
isValidHttpUrl,
|
|
11688
12237
|
koeUrl,
|
|
11689
12238
|
mountDAW,
|
|
@@ -11697,6 +12246,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
11697
12246
|
parseMmlMeta,
|
|
11698
12247
|
playMML,
|
|
11699
12248
|
playSingingMML,
|
|
12249
|
+
setBackgroundActive,
|
|
11700
12250
|
setDrawOffset,
|
|
11701
12251
|
shiftNotes,
|
|
11702
12252
|
showLoadingOverlay,
|