@onjmin/dtm 0.1.57 → 0.1.58
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 +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +307 -85
- package/dist/index.mjs +307 -85
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5142,8 +5142,6 @@ var DAW_CSS = `
|
|
|
5142
5142
|
max-height: 180px;
|
|
5143
5143
|
overflow-y: auto;
|
|
5144
5144
|
padding: 8px 10px 10px;
|
|
5145
|
-
overflow-x: auto;
|
|
5146
|
-
white-space: nowrap;
|
|
5147
5145
|
scrollbar-width: none;
|
|
5148
5146
|
display: flex;
|
|
5149
5147
|
flex-direction: column;
|
|
@@ -5172,6 +5170,7 @@ var DAW_CSS = `
|
|
|
5172
5170
|
.dtm-cp-bar {
|
|
5173
5171
|
display: flex;
|
|
5174
5172
|
align-items: center;
|
|
5173
|
+
flex-wrap: wrap;
|
|
5175
5174
|
gap: 2px;
|
|
5176
5175
|
margin-top: 2px;
|
|
5177
5176
|
}
|
|
@@ -6874,11 +6873,13 @@ var loadDrumFont = (ctx, pitch) => {
|
|
|
6874
6873
|
_drumLoading.set(pitch, p);
|
|
6875
6874
|
return p;
|
|
6876
6875
|
};
|
|
6876
|
+
var BAR_SEP = /[|ll→]/;
|
|
6877
|
+
var NON_EVENT_RE = /^[=_]$|^N\.C\.$|^N$/i;
|
|
6877
6878
|
var buildDisplayLines = (chords, eventsCount) => {
|
|
6878
6879
|
const rawLines = chords.split("\n").map((l) => l.trim()).filter((l) => l);
|
|
6879
6880
|
const displayLines = [];
|
|
6880
6881
|
let eventCounter = 0;
|
|
6881
|
-
let colorIdx =
|
|
6882
|
+
let colorIdx = 0;
|
|
6882
6883
|
for (const line of rawLines) {
|
|
6883
6884
|
if (/^#/.test(line)) {
|
|
6884
6885
|
const label = line.replace(/^#\s*/, "").trim();
|
|
@@ -6886,19 +6887,21 @@ var buildDisplayLines = (chords, eventsCount) => {
|
|
|
6886
6887
|
if (/^tone\s*=/i.test(label)) continue;
|
|
6887
6888
|
if (/^instrument\s*=/i.test(label)) continue;
|
|
6888
6889
|
if (/^metronome/i.test(label)) continue;
|
|
6889
|
-
colorIdx++;
|
|
6890
|
+
if (displayLines.length > 0 || eventCounter > 0) colorIdx++;
|
|
6890
6891
|
displayLines.push({
|
|
6891
6892
|
type: "section",
|
|
6892
6893
|
section: label,
|
|
6893
|
-
colorIdx
|
|
6894
|
+
colorIdx
|
|
6894
6895
|
});
|
|
6895
6896
|
continue;
|
|
6896
6897
|
}
|
|
6897
|
-
const segments = line.split(
|
|
6898
|
-
if (segments.length
|
|
6898
|
+
const segments = line.split(BAR_SEP);
|
|
6899
|
+
if (segments.length === 0) continue;
|
|
6900
|
+
const hasMultiSeg = segments.length > 1;
|
|
6899
6901
|
const parts = [];
|
|
6900
6902
|
for (let i = 0; i < segments.length; i++) {
|
|
6901
|
-
if (i > 0)
|
|
6903
|
+
if (hasMultiSeg && i > 0)
|
|
6904
|
+
parts.push({ text: "|", isChord: false, eventIdx: -1 });
|
|
6902
6905
|
const bar = segments[i].trim();
|
|
6903
6906
|
if (!bar) continue;
|
|
6904
6907
|
const splitAt = [];
|
|
@@ -6921,7 +6924,7 @@ var buildDisplayLines = (chords, eventsCount) => {
|
|
|
6921
6924
|
splitAt.push(j + 1);
|
|
6922
6925
|
continue;
|
|
6923
6926
|
}
|
|
6924
|
-
if (/^[A-G]
|
|
6927
|
+
if (/^[A-G]$/.test(char)) {
|
|
6925
6928
|
const prev = bar[j - 1];
|
|
6926
6929
|
const prev2 = bar.slice(Math.max(0, j - 2), j);
|
|
6927
6930
|
if (prev === "/" || prev2.toLowerCase() === "on") continue;
|
|
@@ -6930,12 +6933,13 @@ var buildDisplayLines = (chords, eventsCount) => {
|
|
|
6930
6933
|
}
|
|
6931
6934
|
const uniqueSplitAt = Array.from(new Set(splitAt)).filter((idx) => idx >= 0 && idx < bar.length).sort((a, b) => a - b);
|
|
6932
6935
|
if (uniqueSplitAt.length === 0) {
|
|
6936
|
+
const isEvent = !NON_EVENT_RE.test(bar);
|
|
6933
6937
|
parts.push({
|
|
6934
6938
|
text: bar,
|
|
6935
6939
|
isChord: true,
|
|
6936
|
-
eventIdx: eventCounter < eventsCount ? eventCounter : -1
|
|
6940
|
+
eventIdx: isEvent && eventCounter < eventsCount ? eventCounter : -1
|
|
6937
6941
|
});
|
|
6938
|
-
eventCounter++;
|
|
6942
|
+
if (isEvent) eventCounter++;
|
|
6939
6943
|
continue;
|
|
6940
6944
|
}
|
|
6941
6945
|
for (let ci = 0; ci < uniqueSplitAt.length; ci++) {
|
|
@@ -6944,19 +6948,20 @@ var buildDisplayLines = (chords, eventsCount) => {
|
|
|
6944
6948
|
const end = ci < uniqueSplitAt.length - 1 ? uniqueSplitAt[ci + 1] : bar.length;
|
|
6945
6949
|
const symbol = bar.slice(start, end).trim();
|
|
6946
6950
|
if (symbol) {
|
|
6951
|
+
const isEvent = !NON_EVENT_RE.test(symbol);
|
|
6947
6952
|
parts.push({
|
|
6948
6953
|
text: symbol,
|
|
6949
6954
|
isChord: true,
|
|
6950
|
-
eventIdx: eventCounter < eventsCount ? eventCounter : -1
|
|
6955
|
+
eventIdx: isEvent && eventCounter < eventsCount ? eventCounter : -1
|
|
6951
6956
|
});
|
|
6952
|
-
eventCounter++;
|
|
6957
|
+
if (isEvent) eventCounter++;
|
|
6953
6958
|
}
|
|
6954
6959
|
}
|
|
6955
6960
|
}
|
|
6956
6961
|
if (parts.length > 0) {
|
|
6957
6962
|
displayLines.push({
|
|
6958
6963
|
type: "bar",
|
|
6959
|
-
colorIdx
|
|
6964
|
+
colorIdx,
|
|
6960
6965
|
parts
|
|
6961
6966
|
});
|
|
6962
6967
|
}
|
|
@@ -8890,6 +8895,18 @@ var MidiSearchClient = class {
|
|
|
8890
8895
|
if (!res.ok) throw new Error(`picotune fetch failed: ${res.status}`);
|
|
8891
8896
|
return res.arrayBuffer();
|
|
8892
8897
|
}
|
|
8898
|
+
async searchRechord(word) {
|
|
8899
|
+
if (!this.enabled) return [];
|
|
8900
|
+
const qs = new URLSearchParams();
|
|
8901
|
+
qs.set("word", word);
|
|
8902
|
+
qs.set("guest", "true");
|
|
8903
|
+
const url2 = `${this.baseUrl}/rechord/scores?${qs.toString()}`;
|
|
8904
|
+
const res = await fetch(url2, { headers: this.headers() });
|
|
8905
|
+
if (!res.ok) throw new Error(`rechord search failed: ${res.status}`);
|
|
8906
|
+
const body = await res.json();
|
|
8907
|
+
const list = body.result ?? body.data ?? body;
|
|
8908
|
+
return Array.isArray(list) ? list : [];
|
|
8909
|
+
}
|
|
8893
8910
|
};
|
|
8894
8911
|
|
|
8895
8912
|
// src/linked-list.ts
|
|
@@ -11314,6 +11331,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
11314
11331
|
<div style="display: inline-flex; align-items: center; gap: 6px;">
|
|
11315
11332
|
<span class="dtm-label">\u548C\u97F3</span>
|
|
11316
11333
|
<button class="dtm-infobtn" data-dtm="chord-info" title="\u30B3\u30FC\u30C9\u9032\u884C\u306E\u66F8\u304D\u65B9\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
11334
|
+
${showMidiSearch ? `<button class="dtm-btn dtm-btn--ghost" data-dtm="chord-search" title="\u30B3\u30FC\u30C9\u9032\u884C\u691C\u7D22" style="min-height: 24px; min-width: auto; height: 24px; padding: 0 6px; font-size: 11px; display: inline-flex; align-items: center;">\u30B3\u30FC\u30C9\u691C\u7D22</button>` : ""}
|
|
11317
11335
|
</div>
|
|
11318
11336
|
<select class="dtm-select" data-dtm="chord-pattern">
|
|
11319
11337
|
<option value="block">\u30D6\u30ED\u30C3\u30AF</option>
|
|
@@ -11349,6 +11367,14 @@ var mountDAW = (target, options = {}) => {
|
|
|
11349
11367
|
save();
|
|
11350
11368
|
applyChord();
|
|
11351
11369
|
});
|
|
11370
|
+
const searchChordBtn = div.querySelector(
|
|
11371
|
+
'[data-dtm="chord-search"]'
|
|
11372
|
+
);
|
|
11373
|
+
if (searchChordBtn) {
|
|
11374
|
+
searchChordBtn.addEventListener("click", () => {
|
|
11375
|
+
openChordSearchModal(input);
|
|
11376
|
+
});
|
|
11377
|
+
}
|
|
11352
11378
|
}
|
|
11353
11379
|
};
|
|
11354
11380
|
const switchTrack = (id) => {
|
|
@@ -12212,6 +12238,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
12212
12238
|
searchPreviewBtn = null;
|
|
12213
12239
|
}
|
|
12214
12240
|
};
|
|
12241
|
+
let mmlSearchCache = null;
|
|
12242
|
+
let chordSearchCache = null;
|
|
12215
12243
|
const wireMidiSearch = () => {
|
|
12216
12244
|
if (!midiSearchClient) return;
|
|
12217
12245
|
refs.midiSearchOpenBtn.addEventListener("click", () => {
|
|
@@ -12222,6 +12250,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
12222
12250
|
<input type="text" class="dtm-input dtm-grow" data-dtm="modal-midi-search-input" placeholder="\u66F2\u540D\u3067MML\u691C\u7D22" style="min-width:0">
|
|
12223
12251
|
<button class="dtm-btn dtm-btn--primary" data-dtm="modal-midi-search-btn" style="flex-shrink:0">\u691C\u7D22</button>
|
|
12224
12252
|
</div>
|
|
12253
|
+
<div data-dtm="modal-midi-search-status" style="font-size:11px;color:rgba(255,255,255,0.5);min-height:1.4em"></div>
|
|
12225
12254
|
<div class="dtm-row" data-dtm="modal-midi-search-results" style="flex-direction:column;align-items:stretch;gap:4px"></div>
|
|
12226
12255
|
`
|
|
12227
12256
|
);
|
|
@@ -12231,9 +12260,17 @@ var mountDAW = (target, options = {}) => {
|
|
|
12231
12260
|
const searchBtn = refs.modalBody.querySelector(
|
|
12232
12261
|
'[data-dtm="modal-midi-search-btn"]'
|
|
12233
12262
|
);
|
|
12263
|
+
const statusEl = refs.modalBody.querySelector(
|
|
12264
|
+
'[data-dtm="modal-midi-search-status"]'
|
|
12265
|
+
);
|
|
12234
12266
|
const results = refs.modalBody.querySelector(
|
|
12235
12267
|
'[data-dtm="modal-midi-search-results"]'
|
|
12236
12268
|
);
|
|
12269
|
+
if (mmlSearchCache) {
|
|
12270
|
+
input.value = mmlSearchCache.query;
|
|
12271
|
+
statusEl.textContent = `\u300C${mmlSearchCache.query}\u300D\u306E\u691C\u7D22\u7D50\u679C\u3000${mmlSearchCache.count}\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12272
|
+
mmlSearchCache.renderResults(results);
|
|
12273
|
+
}
|
|
12237
12274
|
const runSearch = async () => {
|
|
12238
12275
|
const q2 = input.value.trim();
|
|
12239
12276
|
if (!q2) return;
|
|
@@ -12241,37 +12278,85 @@ var mountDAW = (target, options = {}) => {
|
|
|
12241
12278
|
searchBtn.disabled = true;
|
|
12242
12279
|
searchBtn.textContent = "\u691C\u7D22\u4E2D...";
|
|
12243
12280
|
results.innerHTML = "";
|
|
12281
|
+
statusEl.textContent = "";
|
|
12244
12282
|
try {
|
|
12245
12283
|
const songs = await midiSearchClient.searchSongs({ title: q2 });
|
|
12246
12284
|
if (songs.length === 0) {
|
|
12285
|
+
statusEl.textContent = `\u300C${q2}\u300D\u306E\u691C\u7D22\u7D50\u679C\u30000\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12247
12286
|
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F</span>';
|
|
12287
|
+
mmlSearchCache = {
|
|
12288
|
+
query: q2,
|
|
12289
|
+
count: 0,
|
|
12290
|
+
renderResults: (c) => {
|
|
12291
|
+
c.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F</span>';
|
|
12292
|
+
}
|
|
12293
|
+
};
|
|
12248
12294
|
return;
|
|
12249
12295
|
}
|
|
12250
|
-
|
|
12251
|
-
|
|
12252
|
-
|
|
12253
|
-
const
|
|
12254
|
-
|
|
12255
|
-
|
|
12256
|
-
|
|
12257
|
-
|
|
12258
|
-
|
|
12259
|
-
|
|
12260
|
-
|
|
12261
|
-
|
|
12262
|
-
|
|
12263
|
-
|
|
12264
|
-
|
|
12265
|
-
|
|
12266
|
-
|
|
12267
|
-
|
|
12268
|
-
|
|
12269
|
-
|
|
12270
|
-
|
|
12271
|
-
|
|
12272
|
-
|
|
12273
|
-
|
|
12296
|
+
statusEl.textContent = `\u300C${q2}\u300D\u306E\u691C\u7D22\u7D50\u679C\u3000${songs.length}\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12297
|
+
const renderMmlResults = (container) => {
|
|
12298
|
+
container.innerHTML = "";
|
|
12299
|
+
for (const song of songs) {
|
|
12300
|
+
const box = document.createElement("div");
|
|
12301
|
+
box.className = "dtm-modal-sample-box";
|
|
12302
|
+
const row = document.createElement("div");
|
|
12303
|
+
row.className = "dtm-row";
|
|
12304
|
+
row.style.cssText = "flex-wrap:nowrap;gap:4px;padding:2px 0";
|
|
12305
|
+
const label = document.createElement("span");
|
|
12306
|
+
label.className = "dtm-label";
|
|
12307
|
+
label.style.cssText = "flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
|
|
12308
|
+
label.textContent = `${song.title} - ${song.user}`;
|
|
12309
|
+
const previewBtn = document.createElement("button");
|
|
12310
|
+
previewBtn.className = "dtm-btn dtm-btn--ghost";
|
|
12311
|
+
previewBtn.style.cssText = "flex-shrink:0";
|
|
12312
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
12313
|
+
const loadBtn = document.createElement("button");
|
|
12314
|
+
loadBtn.className = "dtm-btn dtm-btn--primary";
|
|
12315
|
+
loadBtn.style.cssText = "flex-shrink:0";
|
|
12316
|
+
loadBtn.textContent = "\u8AAD\u307F\u8FBC\u307F";
|
|
12317
|
+
const playerContainer = document.createElement("div");
|
|
12318
|
+
playerContainer.className = "dtm-modal-sample-player-container";
|
|
12319
|
+
previewBtn.addEventListener("click", async () => {
|
|
12320
|
+
if (searchPreviewBtn === previewBtn) {
|
|
12321
|
+
if (searchPreviewPlayer?.isPlaying()) {
|
|
12322
|
+
searchPreviewPlayer.stop();
|
|
12323
|
+
} else {
|
|
12324
|
+
stop();
|
|
12325
|
+
previewBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
12326
|
+
try {
|
|
12327
|
+
const midi = await fetchVerifiedMidi(song.file);
|
|
12328
|
+
const mml = buildPreviewMml(midi);
|
|
12329
|
+
playerContainer.innerHTML = "";
|
|
12330
|
+
const player = mountMmlPlayer(playerContainer, mml, {
|
|
12331
|
+
onPlayNote: options.onPlayNote,
|
|
12332
|
+
onPlayDrum: options.onPlayDrum,
|
|
12333
|
+
onResumeAudio: options.onResumeAudio,
|
|
12334
|
+
getAudioTime: options.getAudioTime,
|
|
12335
|
+
singingVoices: options.singingVoices,
|
|
12336
|
+
drumPatterns: options.drumPatterns,
|
|
12337
|
+
volume: masterVolume,
|
|
12338
|
+
_skipInfoModals: true,
|
|
12339
|
+
onStop: () => {
|
|
12340
|
+
if (searchPreviewBtn === previewBtn) {
|
|
12341
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
12342
|
+
previewBtn.classList.remove("dtm-btn--danger");
|
|
12343
|
+
previewBtn.classList.add("dtm-btn--ghost");
|
|
12344
|
+
}
|
|
12345
|
+
}
|
|
12346
|
+
});
|
|
12347
|
+
searchPreviewPlayer = player;
|
|
12348
|
+
searchPreviewBtn = previewBtn;
|
|
12349
|
+
player.play();
|
|
12350
|
+
previewBtn.textContent = "\u25A0 \u505C\u6B62";
|
|
12351
|
+
previewBtn.classList.remove("dtm-btn--ghost");
|
|
12352
|
+
previewBtn.classList.add("dtm-btn--danger");
|
|
12353
|
+
} catch (e) {
|
|
12354
|
+
console.error("[dtm] MIDI preview failed", e);
|
|
12355
|
+
previewBtn.textContent = "\u5931\u6557";
|
|
12356
|
+
}
|
|
12357
|
+
}
|
|
12274
12358
|
} else {
|
|
12359
|
+
collapseSearchPreview();
|
|
12275
12360
|
stop();
|
|
12276
12361
|
previewBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
12277
12362
|
try {
|
|
@@ -12306,31 +12391,169 @@ var mountDAW = (target, options = {}) => {
|
|
|
12306
12391
|
previewBtn.textContent = "\u5931\u6557";
|
|
12307
12392
|
}
|
|
12308
12393
|
}
|
|
12394
|
+
});
|
|
12395
|
+
loadBtn.addEventListener("click", async () => {
|
|
12396
|
+
loadBtn.disabled = true;
|
|
12397
|
+
loadBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
12398
|
+
try {
|
|
12399
|
+
const pending = await fetchVerifiedMidi(song.file);
|
|
12400
|
+
const analysis = analyzeMidiTracks(pending);
|
|
12401
|
+
const sel = analysis.filter((a) => a.selected).map((a) => a.index);
|
|
12402
|
+
collapseSearchPreview();
|
|
12403
|
+
overlayDuring(() => applyMidiSelection(pending, sel));
|
|
12404
|
+
refs.modalOverlay.setAttribute("hidden", "");
|
|
12405
|
+
} catch (e) {
|
|
12406
|
+
console.error("[dtm] MIDI fetch failed", e);
|
|
12407
|
+
loadBtn.textContent = "\u5931\u6557";
|
|
12408
|
+
} finally {
|
|
12409
|
+
loadBtn.disabled = false;
|
|
12410
|
+
}
|
|
12411
|
+
});
|
|
12412
|
+
row.appendChild(label);
|
|
12413
|
+
row.appendChild(previewBtn);
|
|
12414
|
+
row.appendChild(loadBtn);
|
|
12415
|
+
box.appendChild(row);
|
|
12416
|
+
box.appendChild(playerContainer);
|
|
12417
|
+
container.appendChild(box);
|
|
12418
|
+
}
|
|
12419
|
+
};
|
|
12420
|
+
renderMmlResults(results);
|
|
12421
|
+
mmlSearchCache = {
|
|
12422
|
+
query: q2,
|
|
12423
|
+
count: songs.length,
|
|
12424
|
+
renderResults: renderMmlResults
|
|
12425
|
+
};
|
|
12426
|
+
} catch (e) {
|
|
12427
|
+
console.error("[dtm] MIDI search failed", e);
|
|
12428
|
+
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u691C\u7D22\u306B\u5931\u6557\u3057\u307E\u3057\u305F</span>';
|
|
12429
|
+
} finally {
|
|
12430
|
+
searchBtn.disabled = false;
|
|
12431
|
+
searchBtn.textContent = "\u691C\u7D22";
|
|
12432
|
+
}
|
|
12433
|
+
};
|
|
12434
|
+
searchBtn.addEventListener("click", () => void runSearch());
|
|
12435
|
+
input.addEventListener("keydown", (e) => {
|
|
12436
|
+
if (e.key === "Enter") void runSearch();
|
|
12437
|
+
});
|
|
12438
|
+
input.focus();
|
|
12439
|
+
});
|
|
12440
|
+
};
|
|
12441
|
+
const openChordSearchModal = (chordTextArea) => {
|
|
12442
|
+
if (!midiSearchClient) return;
|
|
12443
|
+
const active = trackStates.find((t) => t.config.id === activeTrackId);
|
|
12444
|
+
if (!active) return;
|
|
12445
|
+
showModal(
|
|
12446
|
+
"\u30B3\u30FC\u30C9\u9032\u884C\u691C\u7D22",
|
|
12447
|
+
`
|
|
12448
|
+
<div class="dtm-row" style="flex-wrap:nowrap">
|
|
12449
|
+
<input type="text" class="dtm-input dtm-grow" data-dtm="modal-chord-search-input" placeholder="\u66F2\u540D\u3084\u30B3\u30FC\u30C9\u9032\u884C\u3067\u691C\u7D22" style="min-width:0">
|
|
12450
|
+
<button class="dtm-btn dtm-btn--primary" data-dtm="modal-chord-search-btn" style="flex-shrink:0">\u691C\u7D22</button>
|
|
12451
|
+
</div>
|
|
12452
|
+
<div data-dtm="modal-chord-search-status" style="font-size:11px;color:rgba(255,255,255,0.5);min-height:1.4em"></div>
|
|
12453
|
+
<div class="dtm-row" data-dtm="modal-chord-search-results" style="flex-direction:column;align-items:stretch;gap:4px"></div>
|
|
12454
|
+
`
|
|
12455
|
+
);
|
|
12456
|
+
const input = refs.modalBody.querySelector(
|
|
12457
|
+
'[data-dtm="modal-chord-search-input"]'
|
|
12458
|
+
);
|
|
12459
|
+
const searchBtn = refs.modalBody.querySelector(
|
|
12460
|
+
'[data-dtm="modal-chord-search-btn"]'
|
|
12461
|
+
);
|
|
12462
|
+
const statusEl = refs.modalBody.querySelector(
|
|
12463
|
+
'[data-dtm="modal-chord-search-status"]'
|
|
12464
|
+
);
|
|
12465
|
+
const results = refs.modalBody.querySelector(
|
|
12466
|
+
'[data-dtm="modal-chord-search-results"]'
|
|
12467
|
+
);
|
|
12468
|
+
if (chordSearchCache) {
|
|
12469
|
+
input.value = chordSearchCache.query;
|
|
12470
|
+
statusEl.textContent = `\u300C${chordSearchCache.query}\u300D\u306E\u691C\u7D22\u7D50\u679C\u3000${chordSearchCache.count}\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12471
|
+
chordSearchCache.renderResults(results);
|
|
12472
|
+
}
|
|
12473
|
+
const runSearch = async () => {
|
|
12474
|
+
const q2 = input.value.trim();
|
|
12475
|
+
if (!q2) return;
|
|
12476
|
+
collapseSearchPreview();
|
|
12477
|
+
searchBtn.disabled = true;
|
|
12478
|
+
searchBtn.textContent = "\u691C\u7D22\u4E2D...";
|
|
12479
|
+
results.innerHTML = "";
|
|
12480
|
+
statusEl.textContent = "";
|
|
12481
|
+
try {
|
|
12482
|
+
const scores = await midiSearchClient.searchRechord(q2);
|
|
12483
|
+
if (scores.length === 0) {
|
|
12484
|
+
statusEl.textContent = `\u300C${q2}\u300D\u306E\u691C\u7D22\u7D50\u679C\u30000\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12485
|
+
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F</span>';
|
|
12486
|
+
chordSearchCache = {
|
|
12487
|
+
query: q2,
|
|
12488
|
+
count: 0,
|
|
12489
|
+
renderResults: (c) => {
|
|
12490
|
+
c.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F</span>';
|
|
12491
|
+
}
|
|
12492
|
+
};
|
|
12493
|
+
return;
|
|
12494
|
+
}
|
|
12495
|
+
statusEl.textContent = `\u300C${q2}\u300D\u306E\u691C\u7D22\u7D50\u679C\u3000${scores.length}\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12496
|
+
const renderChordResults = (container) => {
|
|
12497
|
+
container.innerHTML = "";
|
|
12498
|
+
for (const score of scores) {
|
|
12499
|
+
const box = document.createElement("div");
|
|
12500
|
+
box.className = "dtm-modal-sample-box";
|
|
12501
|
+
const row = document.createElement("div");
|
|
12502
|
+
row.className = "dtm-row";
|
|
12503
|
+
row.style.cssText = "flex-wrap:nowrap;gap:4px;padding:2px 0";
|
|
12504
|
+
const label = document.createElement("span");
|
|
12505
|
+
label.className = "dtm-label";
|
|
12506
|
+
label.style.cssText = "flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
|
|
12507
|
+
label.textContent = `${score.title}${score.user?.screen_name ? ` - ${score.user.screen_name}` : ""}`;
|
|
12508
|
+
const previewBtn = document.createElement("button");
|
|
12509
|
+
previewBtn.className = "dtm-btn dtm-btn--ghost";
|
|
12510
|
+
previewBtn.style.cssText = "flex-shrink:0";
|
|
12511
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
12512
|
+
const loadBtn = document.createElement("button");
|
|
12513
|
+
loadBtn.className = "dtm-btn dtm-btn--primary";
|
|
12514
|
+
loadBtn.style.cssText = "flex-shrink:0";
|
|
12515
|
+
loadBtn.textContent = "\u8AAD\u307F\u8FBC\u307F";
|
|
12516
|
+
const playerContainer = document.createElement("div");
|
|
12517
|
+
playerContainer.className = "dtm-modal-sample-player-container";
|
|
12518
|
+
previewBtn.addEventListener("click", async () => {
|
|
12519
|
+
if (searchPreviewBtn === previewBtn) {
|
|
12520
|
+
if (searchPreviewPlayer?.isPlaying()) {
|
|
12521
|
+
searchPreviewPlayer.stop();
|
|
12522
|
+
} else {
|
|
12523
|
+
stop();
|
|
12524
|
+
previewBtn.textContent = "\u518D\u751F\u4E2D...";
|
|
12525
|
+
try {
|
|
12526
|
+
searchPreviewPlayer?.play();
|
|
12527
|
+
previewBtn.textContent = "\u25A0 \u505C\u6B62";
|
|
12528
|
+
previewBtn.classList.remove("dtm-btn--ghost");
|
|
12529
|
+
previewBtn.classList.add("dtm-btn--danger");
|
|
12530
|
+
} catch (e) {
|
|
12531
|
+
console.error("[dtm] Chord preview play failed", e);
|
|
12532
|
+
previewBtn.textContent = "\u5931\u6557";
|
|
12533
|
+
}
|
|
12534
|
+
}
|
|
12309
12535
|
} else {
|
|
12310
12536
|
collapseSearchPreview();
|
|
12311
12537
|
stop();
|
|
12312
12538
|
previewBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
12313
12539
|
try {
|
|
12314
|
-
const midi = await fetchVerifiedMidi(song.file);
|
|
12315
|
-
const mml = buildPreviewMml(midi);
|
|
12316
12540
|
playerContainer.innerHTML = "";
|
|
12317
|
-
const player =
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12327
|
-
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
previewBtn.classList.add("dtm-btn--ghost");
|
|
12541
|
+
const player = mountChordPlayer(
|
|
12542
|
+
playerContainer,
|
|
12543
|
+
score.content,
|
|
12544
|
+
{
|
|
12545
|
+
volume: masterVolume,
|
|
12546
|
+
bpm: score.bpm ?? bpm ?? 120,
|
|
12547
|
+
_skipInfoModals: true,
|
|
12548
|
+
onStop: () => {
|
|
12549
|
+
if (searchPreviewBtn === previewBtn) {
|
|
12550
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
12551
|
+
previewBtn.classList.remove("dtm-btn--danger");
|
|
12552
|
+
previewBtn.classList.add("dtm-btn--ghost");
|
|
12553
|
+
}
|
|
12331
12554
|
}
|
|
12332
12555
|
}
|
|
12333
|
-
|
|
12556
|
+
);
|
|
12334
12557
|
searchPreviewPlayer = player;
|
|
12335
12558
|
searchPreviewBtn = previewBtn;
|
|
12336
12559
|
player.play();
|
|
@@ -12338,49 +12561,48 @@ var mountDAW = (target, options = {}) => {
|
|
|
12338
12561
|
previewBtn.classList.remove("dtm-btn--ghost");
|
|
12339
12562
|
previewBtn.classList.add("dtm-btn--danger");
|
|
12340
12563
|
} catch (e) {
|
|
12341
|
-
console.error("[dtm]
|
|
12564
|
+
console.error("[dtm] Chord preview mount failed", e);
|
|
12342
12565
|
previewBtn.textContent = "\u5931\u6557";
|
|
12343
12566
|
}
|
|
12344
12567
|
}
|
|
12345
12568
|
});
|
|
12346
|
-
loadBtn.addEventListener("click",
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
const sel = analysis.filter((a) => a.selected).map((a) => a.index);
|
|
12353
|
-
collapseSearchPreview();
|
|
12354
|
-
overlayDuring(() => applyMidiSelection(pending, sel));
|
|
12355
|
-
refs.modalOverlay.setAttribute("hidden", "");
|
|
12356
|
-
} catch (e) {
|
|
12357
|
-
console.error("[dtm] MIDI fetch failed", e);
|
|
12358
|
-
loadBtn.textContent = "\u5931\u6557";
|
|
12359
|
-
} finally {
|
|
12360
|
-
loadBtn.disabled = false;
|
|
12569
|
+
loadBtn.addEventListener("click", () => {
|
|
12570
|
+
collapseSearchPreview();
|
|
12571
|
+
chordTextArea.value = score.content;
|
|
12572
|
+
active.savedChordInput = score.content;
|
|
12573
|
+
if (score.bpm) {
|
|
12574
|
+
setBpm(score.bpm);
|
|
12361
12575
|
}
|
|
12576
|
+
applyChord();
|
|
12577
|
+
refs.modalOverlay.setAttribute("hidden", "");
|
|
12362
12578
|
});
|
|
12363
12579
|
row.appendChild(label);
|
|
12364
12580
|
row.appendChild(previewBtn);
|
|
12365
12581
|
row.appendChild(loadBtn);
|
|
12366
12582
|
box.appendChild(row);
|
|
12367
12583
|
box.appendChild(playerContainer);
|
|
12368
|
-
|
|
12584
|
+
container.appendChild(box);
|
|
12369
12585
|
}
|
|
12370
|
-
}
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12376
|
-
}
|
|
12377
|
-
}
|
|
12378
|
-
|
|
12379
|
-
|
|
12380
|
-
|
|
12381
|
-
|
|
12382
|
-
|
|
12586
|
+
};
|
|
12587
|
+
renderChordResults(results);
|
|
12588
|
+
chordSearchCache = {
|
|
12589
|
+
query: q2,
|
|
12590
|
+
count: scores.length,
|
|
12591
|
+
renderResults: renderChordResults
|
|
12592
|
+
};
|
|
12593
|
+
} catch (e) {
|
|
12594
|
+
console.error("[dtm] Chord search failed", e);
|
|
12595
|
+
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u691C\u7D22\u306B\u5931\u6557\u3057\u307E\u3057\u305F</span>';
|
|
12596
|
+
} finally {
|
|
12597
|
+
searchBtn.disabled = false;
|
|
12598
|
+
searchBtn.textContent = "\u691C\u7D22";
|
|
12599
|
+
}
|
|
12600
|
+
};
|
|
12601
|
+
searchBtn.addEventListener("click", () => void runSearch());
|
|
12602
|
+
input.addEventListener("keydown", (e) => {
|
|
12603
|
+
if (e.key === "Enter") void runSearch();
|
|
12383
12604
|
});
|
|
12605
|
+
input.focus();
|
|
12384
12606
|
};
|
|
12385
12607
|
const onKeyDown = (e) => {
|
|
12386
12608
|
if (!(e.ctrlKey || e.metaKey)) return;
|