@onjmin/dtm 0.1.57 → 0.1.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/index.d.mts +33 -1
- package/dist/index.d.ts +33 -1
- package/dist/index.js +346 -93
- package/dist/index.mjs +346 -93
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -5020,8 +5020,6 @@ var DAW_CSS = `
|
|
|
5020
5020
|
max-height: 180px;
|
|
5021
5021
|
overflow-y: auto;
|
|
5022
5022
|
padding: 8px 10px 10px;
|
|
5023
|
-
overflow-x: auto;
|
|
5024
|
-
white-space: nowrap;
|
|
5025
5023
|
scrollbar-width: none;
|
|
5026
5024
|
display: flex;
|
|
5027
5025
|
flex-direction: column;
|
|
@@ -5050,6 +5048,7 @@ var DAW_CSS = `
|
|
|
5050
5048
|
.dtm-cp-bar {
|
|
5051
5049
|
display: flex;
|
|
5052
5050
|
align-items: center;
|
|
5051
|
+
flex-wrap: wrap;
|
|
5053
5052
|
gap: 2px;
|
|
5054
5053
|
margin-top: 2px;
|
|
5055
5054
|
}
|
|
@@ -5418,6 +5417,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
5418
5417
|
const drumPatternDict = options.drumPatterns ?? DRUM_PATTERNS;
|
|
5419
5418
|
const drumPattern = meta.drum ? drumPatternDict[meta.drum] ?? null : null;
|
|
5420
5419
|
const trackVolume = meta.volume ?? options.volume ?? 100;
|
|
5420
|
+
let masterVolume = options.masterVolume ?? 100;
|
|
5421
5421
|
const drumVolume = meta.drumVolume ?? 80;
|
|
5422
5422
|
const colors = options.trackColors ?? DEFAULT_TRACK_COLORS;
|
|
5423
5423
|
const useSynth = options.synth ?? !options.onPlayNote;
|
|
@@ -6197,11 +6197,12 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6197
6197
|
const em = emojiByTrack.get(trackIdx);
|
|
6198
6198
|
if (em) jumpEmojiAt(em, e.when);
|
|
6199
6199
|
if (lyricTracks.has(trackIdx) && !skipSinging) return;
|
|
6200
|
-
|
|
6201
|
-
|
|
6200
|
+
const volume = e.volume * (masterVolume / 100);
|
|
6201
|
+
options.onPlayNote?.({ ...e, volume });
|
|
6202
|
+
if (useSynth) ensureSynth().playNote({ ...e, volume });
|
|
6202
6203
|
},
|
|
6203
6204
|
onPlayDrum: (e) => {
|
|
6204
|
-
const velocity = e.velocity * (drumVolume / 100) * (trackVolume / 100);
|
|
6205
|
+
const velocity = e.velocity * (drumVolume / 100) * (trackVolume / 100) * (masterVolume / 100);
|
|
6205
6206
|
options.onPlayDrum?.({ ...e, velocity });
|
|
6206
6207
|
if (useSynth) ensureSynth().playDrum({ ...e, velocity });
|
|
6207
6208
|
},
|
|
@@ -6225,6 +6226,9 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6225
6226
|
if (activePlayer === instance) activePlayer = null;
|
|
6226
6227
|
options.onStop?.();
|
|
6227
6228
|
};
|
|
6229
|
+
const setVolume = (volume) => {
|
|
6230
|
+
masterVolume = volume;
|
|
6231
|
+
};
|
|
6228
6232
|
const buildStreamTracks = () => [...lyricTracks.entries()].map(([index, lt]) => {
|
|
6229
6233
|
const seqTrack = seqTracks.find((t) => Number(t.id) === index);
|
|
6230
6234
|
const sorted = [...seqTrack?.notes ?? []].sort(
|
|
@@ -6246,7 +6250,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6246
6250
|
return {
|
|
6247
6251
|
id: String(index),
|
|
6248
6252
|
model: lt.model,
|
|
6249
|
-
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * (trackVolume / 100),
|
|
6253
|
+
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * (trackVolume / 100) * (masterVolume / 100),
|
|
6250
6254
|
pan: panToStereo(lt.pan ?? DEFAULT_PAN),
|
|
6251
6255
|
notes
|
|
6252
6256
|
};
|
|
@@ -6360,6 +6364,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6360
6364
|
play,
|
|
6361
6365
|
stop,
|
|
6362
6366
|
isPlaying: () => playing,
|
|
6367
|
+
setVolume,
|
|
6363
6368
|
destroy
|
|
6364
6369
|
};
|
|
6365
6370
|
return instance;
|
|
@@ -6752,11 +6757,13 @@ var loadDrumFont = (ctx, pitch) => {
|
|
|
6752
6757
|
_drumLoading.set(pitch, p);
|
|
6753
6758
|
return p;
|
|
6754
6759
|
};
|
|
6760
|
+
var BAR_SEP = /[|ll→]/;
|
|
6761
|
+
var NON_EVENT_RE = /^[=_]$|^N\.C\.$|^N$/i;
|
|
6755
6762
|
var buildDisplayLines = (chords, eventsCount) => {
|
|
6756
6763
|
const rawLines = chords.split("\n").map((l) => l.trim()).filter((l) => l);
|
|
6757
6764
|
const displayLines = [];
|
|
6758
6765
|
let eventCounter = 0;
|
|
6759
|
-
let colorIdx =
|
|
6766
|
+
let colorIdx = 0;
|
|
6760
6767
|
for (const line of rawLines) {
|
|
6761
6768
|
if (/^#/.test(line)) {
|
|
6762
6769
|
const label = line.replace(/^#\s*/, "").trim();
|
|
@@ -6764,19 +6771,21 @@ var buildDisplayLines = (chords, eventsCount) => {
|
|
|
6764
6771
|
if (/^tone\s*=/i.test(label)) continue;
|
|
6765
6772
|
if (/^instrument\s*=/i.test(label)) continue;
|
|
6766
6773
|
if (/^metronome/i.test(label)) continue;
|
|
6767
|
-
colorIdx++;
|
|
6774
|
+
if (displayLines.length > 0 || eventCounter > 0) colorIdx++;
|
|
6768
6775
|
displayLines.push({
|
|
6769
6776
|
type: "section",
|
|
6770
6777
|
section: label,
|
|
6771
|
-
colorIdx
|
|
6778
|
+
colorIdx
|
|
6772
6779
|
});
|
|
6773
6780
|
continue;
|
|
6774
6781
|
}
|
|
6775
|
-
const segments = line.split(
|
|
6776
|
-
if (segments.length
|
|
6782
|
+
const segments = line.split(BAR_SEP);
|
|
6783
|
+
if (segments.length === 0) continue;
|
|
6784
|
+
const hasMultiSeg = segments.length > 1;
|
|
6777
6785
|
const parts = [];
|
|
6778
6786
|
for (let i = 0; i < segments.length; i++) {
|
|
6779
|
-
if (i > 0)
|
|
6787
|
+
if (hasMultiSeg && i > 0)
|
|
6788
|
+
parts.push({ text: "|", isChord: false, eventIdx: -1 });
|
|
6780
6789
|
const bar = segments[i].trim();
|
|
6781
6790
|
if (!bar) continue;
|
|
6782
6791
|
const splitAt = [];
|
|
@@ -6799,7 +6808,7 @@ var buildDisplayLines = (chords, eventsCount) => {
|
|
|
6799
6808
|
splitAt.push(j + 1);
|
|
6800
6809
|
continue;
|
|
6801
6810
|
}
|
|
6802
|
-
if (/^[A-G]
|
|
6811
|
+
if (/^[A-G]$/.test(char)) {
|
|
6803
6812
|
const prev = bar[j - 1];
|
|
6804
6813
|
const prev2 = bar.slice(Math.max(0, j - 2), j);
|
|
6805
6814
|
if (prev === "/" || prev2.toLowerCase() === "on") continue;
|
|
@@ -6808,12 +6817,13 @@ var buildDisplayLines = (chords, eventsCount) => {
|
|
|
6808
6817
|
}
|
|
6809
6818
|
const uniqueSplitAt = Array.from(new Set(splitAt)).filter((idx) => idx >= 0 && idx < bar.length).sort((a, b) => a - b);
|
|
6810
6819
|
if (uniqueSplitAt.length === 0) {
|
|
6820
|
+
const isEvent = !NON_EVENT_RE.test(bar);
|
|
6811
6821
|
parts.push({
|
|
6812
6822
|
text: bar,
|
|
6813
6823
|
isChord: true,
|
|
6814
|
-
eventIdx: eventCounter < eventsCount ? eventCounter : -1
|
|
6824
|
+
eventIdx: isEvent && eventCounter < eventsCount ? eventCounter : -1
|
|
6815
6825
|
});
|
|
6816
|
-
eventCounter++;
|
|
6826
|
+
if (isEvent) eventCounter++;
|
|
6817
6827
|
continue;
|
|
6818
6828
|
}
|
|
6819
6829
|
for (let ci = 0; ci < uniqueSplitAt.length; ci++) {
|
|
@@ -6822,19 +6832,20 @@ var buildDisplayLines = (chords, eventsCount) => {
|
|
|
6822
6832
|
const end = ci < uniqueSplitAt.length - 1 ? uniqueSplitAt[ci + 1] : bar.length;
|
|
6823
6833
|
const symbol = bar.slice(start, end).trim();
|
|
6824
6834
|
if (symbol) {
|
|
6835
|
+
const isEvent = !NON_EVENT_RE.test(symbol);
|
|
6825
6836
|
parts.push({
|
|
6826
6837
|
text: symbol,
|
|
6827
6838
|
isChord: true,
|
|
6828
|
-
eventIdx: eventCounter < eventsCount ? eventCounter : -1
|
|
6839
|
+
eventIdx: isEvent && eventCounter < eventsCount ? eventCounter : -1
|
|
6829
6840
|
});
|
|
6830
|
-
eventCounter++;
|
|
6841
|
+
if (isEvent) eventCounter++;
|
|
6831
6842
|
}
|
|
6832
6843
|
}
|
|
6833
6844
|
}
|
|
6834
6845
|
if (parts.length > 0) {
|
|
6835
6846
|
displayLines.push({
|
|
6836
6847
|
type: "bar",
|
|
6837
|
-
colorIdx
|
|
6848
|
+
colorIdx,
|
|
6838
6849
|
parts
|
|
6839
6850
|
});
|
|
6840
6851
|
}
|
|
@@ -6848,6 +6859,7 @@ var mountChordPlayer = (target, chords, options = {}) => {
|
|
|
6848
6859
|
let activeIndex = -1;
|
|
6849
6860
|
let activePlayback = null;
|
|
6850
6861
|
let isPlaying = false;
|
|
6862
|
+
let masterVolume = options.volume ?? 80;
|
|
6851
6863
|
let isLoading = false;
|
|
6852
6864
|
let loadAbortId = 0;
|
|
6853
6865
|
let loopEnabled = false;
|
|
@@ -7207,7 +7219,7 @@ var mountChordPlayer = (target, chords, options = {}) => {
|
|
|
7207
7219
|
container2.innerHTML = "";
|
|
7208
7220
|
modalSamplePlayer = mountChordPlayer(container2, sampleChords, {
|
|
7209
7221
|
audioContext: options.audioContext ?? ownCtx ?? void 0,
|
|
7210
|
-
volume:
|
|
7222
|
+
volume: masterVolume,
|
|
7211
7223
|
bpm: options.bpm ?? 120,
|
|
7212
7224
|
studio: options.studio,
|
|
7213
7225
|
// 再帰的なモーダル生成を防ぐ。
|
|
@@ -7548,7 +7560,7 @@ var mountChordPlayer = (target, chords, options = {}) => {
|
|
|
7548
7560
|
};
|
|
7549
7561
|
const playInternal = (startIdx, ctx, cutGain) => {
|
|
7550
7562
|
const C32 = 48;
|
|
7551
|
-
const volume =
|
|
7563
|
+
const volume = masterVolume;
|
|
7552
7564
|
const placements = [];
|
|
7553
7565
|
for (const event of chordEvents) {
|
|
7554
7566
|
if (event.when < playOffsetSec) continue;
|
|
@@ -7705,6 +7717,10 @@ var mountChordPlayer = (target, chords, options = {}) => {
|
|
|
7705
7717
|
}
|
|
7706
7718
|
}
|
|
7707
7719
|
};
|
|
7720
|
+
const setVolume = (volume) => {
|
|
7721
|
+
masterVolume = Math.max(0, Math.min(100, volume));
|
|
7722
|
+
activePlayback?.setVolume(masterVolume);
|
|
7723
|
+
};
|
|
7708
7724
|
const destroy = () => {
|
|
7709
7725
|
stop();
|
|
7710
7726
|
closeInfoModal();
|
|
@@ -7834,6 +7850,7 @@ var mountChordPlayer = (target, chords, options = {}) => {
|
|
|
7834
7850
|
element: container,
|
|
7835
7851
|
play,
|
|
7836
7852
|
stop,
|
|
7853
|
+
setVolume,
|
|
7837
7854
|
destroy,
|
|
7838
7855
|
toggleMetronome,
|
|
7839
7856
|
isPlaying: () => isPlaying
|
|
@@ -8768,6 +8785,18 @@ var MidiSearchClient = class {
|
|
|
8768
8785
|
if (!res.ok) throw new Error(`picotune fetch failed: ${res.status}`);
|
|
8769
8786
|
return res.arrayBuffer();
|
|
8770
8787
|
}
|
|
8788
|
+
async searchRechord(word) {
|
|
8789
|
+
if (!this.enabled) return [];
|
|
8790
|
+
const qs = new URLSearchParams();
|
|
8791
|
+
qs.set("word", word);
|
|
8792
|
+
qs.set("guest", "true");
|
|
8793
|
+
const url2 = `${this.baseUrl}/rechord/scores?${qs.toString()}`;
|
|
8794
|
+
const res = await fetch(url2, { headers: this.headers() });
|
|
8795
|
+
if (!res.ok) throw new Error(`rechord search failed: ${res.status}`);
|
|
8796
|
+
const body = await res.json();
|
|
8797
|
+
const list = body.result ?? body.data ?? body;
|
|
8798
|
+
return Array.isArray(list) ? list : [];
|
|
8799
|
+
}
|
|
8771
8800
|
};
|
|
8772
8801
|
|
|
8773
8802
|
// src/linked-list.ts
|
|
@@ -9855,6 +9884,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
9855
9884
|
showChord,
|
|
9856
9885
|
showMidiSearch
|
|
9857
9886
|
});
|
|
9887
|
+
refs.masterVolume.value = String(options.masterVolume ?? 50);
|
|
9888
|
+
refs.masterVolumeLabel.textContent = `${options.masterVolume ?? 50}%`;
|
|
9889
|
+
refs.drumVolume.value = String(options.drumVolume ?? 80);
|
|
9890
|
+
refs.drumVolumeLabel.textContent = `${options.drumVolume ?? 80}%`;
|
|
9858
9891
|
const renderConfig = {
|
|
9859
9892
|
stepsPerBar: 192,
|
|
9860
9893
|
keyCount: 128,
|
|
@@ -9866,8 +9899,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
9866
9899
|
let zoomX = 100;
|
|
9867
9900
|
let zoomY = 100;
|
|
9868
9901
|
let bpm = options.defaultBpm ?? DEFAULT_BPM;
|
|
9869
|
-
let masterVolume = 50;
|
|
9870
|
-
let drumVolume = 80;
|
|
9902
|
+
let masterVolume = options.masterVolume ?? 50;
|
|
9903
|
+
let drumVolume = options.drumVolume ?? 80;
|
|
9871
9904
|
let currentDrumPattern = refs.drumSelect.value;
|
|
9872
9905
|
let currentInstrument = "";
|
|
9873
9906
|
let activeTrackId = options.initialActiveTrack ?? trackConfigs[0].id;
|
|
@@ -11192,6 +11225,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
11192
11225
|
<div style="display: inline-flex; align-items: center; gap: 6px;">
|
|
11193
11226
|
<span class="dtm-label">\u548C\u97F3</span>
|
|
11194
11227
|
<button class="dtm-infobtn" data-dtm="chord-info" title="\u30B3\u30FC\u30C9\u9032\u884C\u306E\u66F8\u304D\u65B9\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
11228
|
+
${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>` : ""}
|
|
11195
11229
|
</div>
|
|
11196
11230
|
<select class="dtm-select" data-dtm="chord-pattern">
|
|
11197
11231
|
<option value="block">\u30D6\u30ED\u30C3\u30AF</option>
|
|
@@ -11227,6 +11261,14 @@ var mountDAW = (target, options = {}) => {
|
|
|
11227
11261
|
save();
|
|
11228
11262
|
applyChord();
|
|
11229
11263
|
});
|
|
11264
|
+
const searchChordBtn = div.querySelector(
|
|
11265
|
+
'[data-dtm="chord-search"]'
|
|
11266
|
+
);
|
|
11267
|
+
if (searchChordBtn) {
|
|
11268
|
+
searchChordBtn.addEventListener("click", () => {
|
|
11269
|
+
openChordSearchModal(input);
|
|
11270
|
+
});
|
|
11271
|
+
}
|
|
11230
11272
|
}
|
|
11231
11273
|
};
|
|
11232
11274
|
const switchTrack = (id) => {
|
|
@@ -12090,6 +12132,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
12090
12132
|
searchPreviewBtn = null;
|
|
12091
12133
|
}
|
|
12092
12134
|
};
|
|
12135
|
+
let mmlSearchCache = null;
|
|
12136
|
+
let chordSearchCache = null;
|
|
12093
12137
|
const wireMidiSearch = () => {
|
|
12094
12138
|
if (!midiSearchClient) return;
|
|
12095
12139
|
refs.midiSearchOpenBtn.addEventListener("click", () => {
|
|
@@ -12100,6 +12144,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
12100
12144
|
<input type="text" class="dtm-input dtm-grow" data-dtm="modal-midi-search-input" placeholder="\u66F2\u540D\u3067MML\u691C\u7D22" style="min-width:0">
|
|
12101
12145
|
<button class="dtm-btn dtm-btn--primary" data-dtm="modal-midi-search-btn" style="flex-shrink:0">\u691C\u7D22</button>
|
|
12102
12146
|
</div>
|
|
12147
|
+
<div data-dtm="modal-midi-search-status" style="font-size:11px;color:rgba(255,255,255,0.5);min-height:1.4em"></div>
|
|
12103
12148
|
<div class="dtm-row" data-dtm="modal-midi-search-results" style="flex-direction:column;align-items:stretch;gap:4px"></div>
|
|
12104
12149
|
`
|
|
12105
12150
|
);
|
|
@@ -12109,9 +12154,17 @@ var mountDAW = (target, options = {}) => {
|
|
|
12109
12154
|
const searchBtn = refs.modalBody.querySelector(
|
|
12110
12155
|
'[data-dtm="modal-midi-search-btn"]'
|
|
12111
12156
|
);
|
|
12157
|
+
const statusEl = refs.modalBody.querySelector(
|
|
12158
|
+
'[data-dtm="modal-midi-search-status"]'
|
|
12159
|
+
);
|
|
12112
12160
|
const results = refs.modalBody.querySelector(
|
|
12113
12161
|
'[data-dtm="modal-midi-search-results"]'
|
|
12114
12162
|
);
|
|
12163
|
+
if (mmlSearchCache) {
|
|
12164
|
+
input.value = mmlSearchCache.query;
|
|
12165
|
+
statusEl.textContent = `\u300C${mmlSearchCache.query}\u300D\u306E\u691C\u7D22\u7D50\u679C\u3000${mmlSearchCache.count}\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12166
|
+
mmlSearchCache.renderResults(results);
|
|
12167
|
+
}
|
|
12115
12168
|
const runSearch = async () => {
|
|
12116
12169
|
const q2 = input.value.trim();
|
|
12117
12170
|
if (!q2) return;
|
|
@@ -12119,37 +12172,85 @@ var mountDAW = (target, options = {}) => {
|
|
|
12119
12172
|
searchBtn.disabled = true;
|
|
12120
12173
|
searchBtn.textContent = "\u691C\u7D22\u4E2D...";
|
|
12121
12174
|
results.innerHTML = "";
|
|
12175
|
+
statusEl.textContent = "";
|
|
12122
12176
|
try {
|
|
12123
12177
|
const songs = await midiSearchClient.searchSongs({ title: q2 });
|
|
12124
12178
|
if (songs.length === 0) {
|
|
12179
|
+
statusEl.textContent = `\u300C${q2}\u300D\u306E\u691C\u7D22\u7D50\u679C\u30000\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12125
12180
|
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F</span>';
|
|
12181
|
+
mmlSearchCache = {
|
|
12182
|
+
query: q2,
|
|
12183
|
+
count: 0,
|
|
12184
|
+
renderResults: (c) => {
|
|
12185
|
+
c.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F</span>';
|
|
12186
|
+
}
|
|
12187
|
+
};
|
|
12126
12188
|
return;
|
|
12127
12189
|
}
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
const
|
|
12132
|
-
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
|
|
12142
|
-
|
|
12143
|
-
|
|
12144
|
-
|
|
12145
|
-
|
|
12146
|
-
|
|
12147
|
-
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
|
|
12190
|
+
statusEl.textContent = `\u300C${q2}\u300D\u306E\u691C\u7D22\u7D50\u679C\u3000${songs.length}\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12191
|
+
const renderMmlResults = (container) => {
|
|
12192
|
+
container.innerHTML = "";
|
|
12193
|
+
for (const song of songs) {
|
|
12194
|
+
const box = document.createElement("div");
|
|
12195
|
+
box.className = "dtm-modal-sample-box";
|
|
12196
|
+
const row = document.createElement("div");
|
|
12197
|
+
row.className = "dtm-row";
|
|
12198
|
+
row.style.cssText = "flex-wrap:nowrap;gap:4px;padding:2px 0";
|
|
12199
|
+
const label = document.createElement("span");
|
|
12200
|
+
label.className = "dtm-label";
|
|
12201
|
+
label.style.cssText = "flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
|
|
12202
|
+
label.textContent = `${song.title} - ${song.user}`;
|
|
12203
|
+
const previewBtn = document.createElement("button");
|
|
12204
|
+
previewBtn.className = "dtm-btn dtm-btn--ghost";
|
|
12205
|
+
previewBtn.style.cssText = "flex-shrink:0";
|
|
12206
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
12207
|
+
const loadBtn = document.createElement("button");
|
|
12208
|
+
loadBtn.className = "dtm-btn dtm-btn--primary";
|
|
12209
|
+
loadBtn.style.cssText = "flex-shrink:0";
|
|
12210
|
+
loadBtn.textContent = "\u8AAD\u307F\u8FBC\u307F";
|
|
12211
|
+
const playerContainer = document.createElement("div");
|
|
12212
|
+
playerContainer.className = "dtm-modal-sample-player-container";
|
|
12213
|
+
previewBtn.addEventListener("click", async () => {
|
|
12214
|
+
if (searchPreviewBtn === previewBtn) {
|
|
12215
|
+
if (searchPreviewPlayer?.isPlaying()) {
|
|
12216
|
+
searchPreviewPlayer.stop();
|
|
12217
|
+
} else {
|
|
12218
|
+
stop();
|
|
12219
|
+
previewBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
12220
|
+
try {
|
|
12221
|
+
const midi = await fetchVerifiedMidi(song.file);
|
|
12222
|
+
const mml = buildPreviewMml(midi);
|
|
12223
|
+
playerContainer.innerHTML = "";
|
|
12224
|
+
const player = mountMmlPlayer(playerContainer, mml, {
|
|
12225
|
+
onPlayNote: options.onPlayNote,
|
|
12226
|
+
onPlayDrum: options.onPlayDrum,
|
|
12227
|
+
onResumeAudio: options.onResumeAudio,
|
|
12228
|
+
getAudioTime: options.getAudioTime,
|
|
12229
|
+
singingVoices: options.singingVoices,
|
|
12230
|
+
drumPatterns: options.drumPatterns,
|
|
12231
|
+
volume: masterVolume,
|
|
12232
|
+
_skipInfoModals: true,
|
|
12233
|
+
onStop: () => {
|
|
12234
|
+
if (searchPreviewBtn === previewBtn) {
|
|
12235
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
12236
|
+
previewBtn.classList.remove("dtm-btn--danger");
|
|
12237
|
+
previewBtn.classList.add("dtm-btn--ghost");
|
|
12238
|
+
}
|
|
12239
|
+
}
|
|
12240
|
+
});
|
|
12241
|
+
searchPreviewPlayer = player;
|
|
12242
|
+
searchPreviewBtn = previewBtn;
|
|
12243
|
+
player.play();
|
|
12244
|
+
previewBtn.textContent = "\u25A0 \u505C\u6B62";
|
|
12245
|
+
previewBtn.classList.remove("dtm-btn--ghost");
|
|
12246
|
+
previewBtn.classList.add("dtm-btn--danger");
|
|
12247
|
+
} catch (e) {
|
|
12248
|
+
console.error("[dtm] MIDI preview failed", e);
|
|
12249
|
+
previewBtn.textContent = "\u5931\u6557";
|
|
12250
|
+
}
|
|
12251
|
+
}
|
|
12152
12252
|
} else {
|
|
12253
|
+
collapseSearchPreview();
|
|
12153
12254
|
stop();
|
|
12154
12255
|
previewBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
12155
12256
|
try {
|
|
@@ -12184,31 +12285,169 @@ var mountDAW = (target, options = {}) => {
|
|
|
12184
12285
|
previewBtn.textContent = "\u5931\u6557";
|
|
12185
12286
|
}
|
|
12186
12287
|
}
|
|
12288
|
+
});
|
|
12289
|
+
loadBtn.addEventListener("click", async () => {
|
|
12290
|
+
loadBtn.disabled = true;
|
|
12291
|
+
loadBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
12292
|
+
try {
|
|
12293
|
+
const pending = await fetchVerifiedMidi(song.file);
|
|
12294
|
+
const analysis = analyzeMidiTracks(pending);
|
|
12295
|
+
const sel = analysis.filter((a) => a.selected).map((a) => a.index);
|
|
12296
|
+
collapseSearchPreview();
|
|
12297
|
+
overlayDuring(() => applyMidiSelection(pending, sel));
|
|
12298
|
+
refs.modalOverlay.setAttribute("hidden", "");
|
|
12299
|
+
} catch (e) {
|
|
12300
|
+
console.error("[dtm] MIDI fetch failed", e);
|
|
12301
|
+
loadBtn.textContent = "\u5931\u6557";
|
|
12302
|
+
} finally {
|
|
12303
|
+
loadBtn.disabled = false;
|
|
12304
|
+
}
|
|
12305
|
+
});
|
|
12306
|
+
row.appendChild(label);
|
|
12307
|
+
row.appendChild(previewBtn);
|
|
12308
|
+
row.appendChild(loadBtn);
|
|
12309
|
+
box.appendChild(row);
|
|
12310
|
+
box.appendChild(playerContainer);
|
|
12311
|
+
container.appendChild(box);
|
|
12312
|
+
}
|
|
12313
|
+
};
|
|
12314
|
+
renderMmlResults(results);
|
|
12315
|
+
mmlSearchCache = {
|
|
12316
|
+
query: q2,
|
|
12317
|
+
count: songs.length,
|
|
12318
|
+
renderResults: renderMmlResults
|
|
12319
|
+
};
|
|
12320
|
+
} catch (e) {
|
|
12321
|
+
console.error("[dtm] MIDI search failed", e);
|
|
12322
|
+
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u691C\u7D22\u306B\u5931\u6557\u3057\u307E\u3057\u305F</span>';
|
|
12323
|
+
} finally {
|
|
12324
|
+
searchBtn.disabled = false;
|
|
12325
|
+
searchBtn.textContent = "\u691C\u7D22";
|
|
12326
|
+
}
|
|
12327
|
+
};
|
|
12328
|
+
searchBtn.addEventListener("click", () => void runSearch());
|
|
12329
|
+
input.addEventListener("keydown", (e) => {
|
|
12330
|
+
if (e.key === "Enter") void runSearch();
|
|
12331
|
+
});
|
|
12332
|
+
input.focus();
|
|
12333
|
+
});
|
|
12334
|
+
};
|
|
12335
|
+
const openChordSearchModal = (chordTextArea) => {
|
|
12336
|
+
if (!midiSearchClient) return;
|
|
12337
|
+
const active = trackStates.find((t) => t.config.id === activeTrackId);
|
|
12338
|
+
if (!active) return;
|
|
12339
|
+
showModal(
|
|
12340
|
+
"\u30B3\u30FC\u30C9\u9032\u884C\u691C\u7D22",
|
|
12341
|
+
`
|
|
12342
|
+
<div class="dtm-row" style="flex-wrap:nowrap">
|
|
12343
|
+
<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">
|
|
12344
|
+
<button class="dtm-btn dtm-btn--primary" data-dtm="modal-chord-search-btn" style="flex-shrink:0">\u691C\u7D22</button>
|
|
12345
|
+
</div>
|
|
12346
|
+
<div data-dtm="modal-chord-search-status" style="font-size:11px;color:rgba(255,255,255,0.5);min-height:1.4em"></div>
|
|
12347
|
+
<div class="dtm-row" data-dtm="modal-chord-search-results" style="flex-direction:column;align-items:stretch;gap:4px"></div>
|
|
12348
|
+
`
|
|
12349
|
+
);
|
|
12350
|
+
const input = refs.modalBody.querySelector(
|
|
12351
|
+
'[data-dtm="modal-chord-search-input"]'
|
|
12352
|
+
);
|
|
12353
|
+
const searchBtn = refs.modalBody.querySelector(
|
|
12354
|
+
'[data-dtm="modal-chord-search-btn"]'
|
|
12355
|
+
);
|
|
12356
|
+
const statusEl = refs.modalBody.querySelector(
|
|
12357
|
+
'[data-dtm="modal-chord-search-status"]'
|
|
12358
|
+
);
|
|
12359
|
+
const results = refs.modalBody.querySelector(
|
|
12360
|
+
'[data-dtm="modal-chord-search-results"]'
|
|
12361
|
+
);
|
|
12362
|
+
if (chordSearchCache) {
|
|
12363
|
+
input.value = chordSearchCache.query;
|
|
12364
|
+
statusEl.textContent = `\u300C${chordSearchCache.query}\u300D\u306E\u691C\u7D22\u7D50\u679C\u3000${chordSearchCache.count}\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12365
|
+
chordSearchCache.renderResults(results);
|
|
12366
|
+
}
|
|
12367
|
+
const runSearch = async () => {
|
|
12368
|
+
const q2 = input.value.trim();
|
|
12369
|
+
if (!q2) return;
|
|
12370
|
+
collapseSearchPreview();
|
|
12371
|
+
searchBtn.disabled = true;
|
|
12372
|
+
searchBtn.textContent = "\u691C\u7D22\u4E2D...";
|
|
12373
|
+
results.innerHTML = "";
|
|
12374
|
+
statusEl.textContent = "";
|
|
12375
|
+
try {
|
|
12376
|
+
const scores = await midiSearchClient.searchRechord(q2);
|
|
12377
|
+
if (scores.length === 0) {
|
|
12378
|
+
statusEl.textContent = `\u300C${q2}\u300D\u306E\u691C\u7D22\u7D50\u679C\u30000\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12379
|
+
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F</span>';
|
|
12380
|
+
chordSearchCache = {
|
|
12381
|
+
query: q2,
|
|
12382
|
+
count: 0,
|
|
12383
|
+
renderResults: (c) => {
|
|
12384
|
+
c.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F</span>';
|
|
12385
|
+
}
|
|
12386
|
+
};
|
|
12387
|
+
return;
|
|
12388
|
+
}
|
|
12389
|
+
statusEl.textContent = `\u300C${q2}\u300D\u306E\u691C\u7D22\u7D50\u679C\u3000${scores.length}\u4EF6\u306E\u30D2\u30C3\u30C8`;
|
|
12390
|
+
const renderChordResults = (container) => {
|
|
12391
|
+
container.innerHTML = "";
|
|
12392
|
+
for (const score of scores) {
|
|
12393
|
+
const box = document.createElement("div");
|
|
12394
|
+
box.className = "dtm-modal-sample-box";
|
|
12395
|
+
const row = document.createElement("div");
|
|
12396
|
+
row.className = "dtm-row";
|
|
12397
|
+
row.style.cssText = "flex-wrap:nowrap;gap:4px;padding:2px 0";
|
|
12398
|
+
const label = document.createElement("span");
|
|
12399
|
+
label.className = "dtm-label";
|
|
12400
|
+
label.style.cssText = "flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap";
|
|
12401
|
+
label.textContent = `${score.title}${score.user?.screen_name ? ` - ${score.user.screen_name}` : ""}`;
|
|
12402
|
+
const previewBtn = document.createElement("button");
|
|
12403
|
+
previewBtn.className = "dtm-btn dtm-btn--ghost";
|
|
12404
|
+
previewBtn.style.cssText = "flex-shrink:0";
|
|
12405
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
12406
|
+
const loadBtn = document.createElement("button");
|
|
12407
|
+
loadBtn.className = "dtm-btn dtm-btn--primary";
|
|
12408
|
+
loadBtn.style.cssText = "flex-shrink:0";
|
|
12409
|
+
loadBtn.textContent = "\u8AAD\u307F\u8FBC\u307F";
|
|
12410
|
+
const playerContainer = document.createElement("div");
|
|
12411
|
+
playerContainer.className = "dtm-modal-sample-player-container";
|
|
12412
|
+
previewBtn.addEventListener("click", async () => {
|
|
12413
|
+
if (searchPreviewBtn === previewBtn) {
|
|
12414
|
+
if (searchPreviewPlayer?.isPlaying()) {
|
|
12415
|
+
searchPreviewPlayer.stop();
|
|
12416
|
+
} else {
|
|
12417
|
+
stop();
|
|
12418
|
+
previewBtn.textContent = "\u518D\u751F\u4E2D...";
|
|
12419
|
+
try {
|
|
12420
|
+
searchPreviewPlayer?.play();
|
|
12421
|
+
previewBtn.textContent = "\u25A0 \u505C\u6B62";
|
|
12422
|
+
previewBtn.classList.remove("dtm-btn--ghost");
|
|
12423
|
+
previewBtn.classList.add("dtm-btn--danger");
|
|
12424
|
+
} catch (e) {
|
|
12425
|
+
console.error("[dtm] Chord preview play failed", e);
|
|
12426
|
+
previewBtn.textContent = "\u5931\u6557";
|
|
12427
|
+
}
|
|
12428
|
+
}
|
|
12187
12429
|
} else {
|
|
12188
12430
|
collapseSearchPreview();
|
|
12189
12431
|
stop();
|
|
12190
12432
|
previewBtn.textContent = "\u8AAD\u8FBC\u4E2D...";
|
|
12191
12433
|
try {
|
|
12192
|
-
const midi = await fetchVerifiedMidi(song.file);
|
|
12193
|
-
const mml = buildPreviewMml(midi);
|
|
12194
12434
|
playerContainer.innerHTML = "";
|
|
12195
|
-
const player =
|
|
12196
|
-
|
|
12197
|
-
|
|
12198
|
-
|
|
12199
|
-
|
|
12200
|
-
|
|
12201
|
-
|
|
12202
|
-
|
|
12203
|
-
|
|
12204
|
-
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
|
|
12208
|
-
previewBtn.classList.add("dtm-btn--ghost");
|
|
12435
|
+
const player = mountChordPlayer(
|
|
12436
|
+
playerContainer,
|
|
12437
|
+
score.content,
|
|
12438
|
+
{
|
|
12439
|
+
volume: masterVolume,
|
|
12440
|
+
bpm: score.bpm ?? bpm ?? 120,
|
|
12441
|
+
_skipInfoModals: true,
|
|
12442
|
+
onStop: () => {
|
|
12443
|
+
if (searchPreviewBtn === previewBtn) {
|
|
12444
|
+
previewBtn.textContent = "\u25B6 \u8A66\u8074";
|
|
12445
|
+
previewBtn.classList.remove("dtm-btn--danger");
|
|
12446
|
+
previewBtn.classList.add("dtm-btn--ghost");
|
|
12447
|
+
}
|
|
12209
12448
|
}
|
|
12210
12449
|
}
|
|
12211
|
-
|
|
12450
|
+
);
|
|
12212
12451
|
searchPreviewPlayer = player;
|
|
12213
12452
|
searchPreviewBtn = previewBtn;
|
|
12214
12453
|
player.play();
|
|
@@ -12216,49 +12455,48 @@ var mountDAW = (target, options = {}) => {
|
|
|
12216
12455
|
previewBtn.classList.remove("dtm-btn--ghost");
|
|
12217
12456
|
previewBtn.classList.add("dtm-btn--danger");
|
|
12218
12457
|
} catch (e) {
|
|
12219
|
-
console.error("[dtm]
|
|
12458
|
+
console.error("[dtm] Chord preview mount failed", e);
|
|
12220
12459
|
previewBtn.textContent = "\u5931\u6557";
|
|
12221
12460
|
}
|
|
12222
12461
|
}
|
|
12223
12462
|
});
|
|
12224
|
-
loadBtn.addEventListener("click",
|
|
12225
|
-
|
|
12226
|
-
|
|
12227
|
-
|
|
12228
|
-
|
|
12229
|
-
|
|
12230
|
-
const sel = analysis.filter((a) => a.selected).map((a) => a.index);
|
|
12231
|
-
collapseSearchPreview();
|
|
12232
|
-
overlayDuring(() => applyMidiSelection(pending, sel));
|
|
12233
|
-
refs.modalOverlay.setAttribute("hidden", "");
|
|
12234
|
-
} catch (e) {
|
|
12235
|
-
console.error("[dtm] MIDI fetch failed", e);
|
|
12236
|
-
loadBtn.textContent = "\u5931\u6557";
|
|
12237
|
-
} finally {
|
|
12238
|
-
loadBtn.disabled = false;
|
|
12463
|
+
loadBtn.addEventListener("click", () => {
|
|
12464
|
+
collapseSearchPreview();
|
|
12465
|
+
chordTextArea.value = score.content;
|
|
12466
|
+
active.savedChordInput = score.content;
|
|
12467
|
+
if (score.bpm) {
|
|
12468
|
+
setBpm(score.bpm);
|
|
12239
12469
|
}
|
|
12470
|
+
applyChord();
|
|
12471
|
+
refs.modalOverlay.setAttribute("hidden", "");
|
|
12240
12472
|
});
|
|
12241
12473
|
row.appendChild(label);
|
|
12242
12474
|
row.appendChild(previewBtn);
|
|
12243
12475
|
row.appendChild(loadBtn);
|
|
12244
12476
|
box.appendChild(row);
|
|
12245
12477
|
box.appendChild(playerContainer);
|
|
12246
|
-
|
|
12478
|
+
container.appendChild(box);
|
|
12247
12479
|
}
|
|
12248
|
-
}
|
|
12249
|
-
|
|
12250
|
-
|
|
12251
|
-
|
|
12252
|
-
|
|
12253
|
-
|
|
12254
|
-
}
|
|
12255
|
-
}
|
|
12256
|
-
|
|
12257
|
-
|
|
12258
|
-
|
|
12259
|
-
|
|
12260
|
-
|
|
12480
|
+
};
|
|
12481
|
+
renderChordResults(results);
|
|
12482
|
+
chordSearchCache = {
|
|
12483
|
+
query: q2,
|
|
12484
|
+
count: scores.length,
|
|
12485
|
+
renderResults: renderChordResults
|
|
12486
|
+
};
|
|
12487
|
+
} catch (e) {
|
|
12488
|
+
console.error("[dtm] Chord search failed", e);
|
|
12489
|
+
results.innerHTML = '<span class="dtm-label" style="color:var(--dtm-warn)">\u691C\u7D22\u306B\u5931\u6557\u3057\u307E\u3057\u305F</span>';
|
|
12490
|
+
} finally {
|
|
12491
|
+
searchBtn.disabled = false;
|
|
12492
|
+
searchBtn.textContent = "\u691C\u7D22";
|
|
12493
|
+
}
|
|
12494
|
+
};
|
|
12495
|
+
searchBtn.addEventListener("click", () => void runSearch());
|
|
12496
|
+
input.addEventListener("keydown", (e) => {
|
|
12497
|
+
if (e.key === "Enter") void runSearch();
|
|
12261
12498
|
});
|
|
12499
|
+
input.focus();
|
|
12262
12500
|
};
|
|
12263
12501
|
const onKeyDown = (e) => {
|
|
12264
12502
|
if (!(e.ctrlKey || e.metaKey)) return;
|
|
@@ -12420,6 +12658,21 @@ var mountDAW = (target, options = {}) => {
|
|
|
12420
12658
|
getCurrentPlayStep,
|
|
12421
12659
|
forcePauseAt,
|
|
12422
12660
|
setLoading,
|
|
12661
|
+
setMasterVolume: (volume) => {
|
|
12662
|
+
masterVolume = clamp3(volume, 0, 100);
|
|
12663
|
+
refs.masterVolume.value = String(masterVolume);
|
|
12664
|
+
refs.masterVolumeLabel.textContent = `${masterVolume}%`;
|
|
12665
|
+
},
|
|
12666
|
+
setVolume: (volume) => {
|
|
12667
|
+
masterVolume = clamp3(volume, 0, 100);
|
|
12668
|
+
refs.masterVolume.value = String(masterVolume);
|
|
12669
|
+
refs.masterVolumeLabel.textContent = `${masterVolume}%`;
|
|
12670
|
+
},
|
|
12671
|
+
setDrumVolume: (volume) => {
|
|
12672
|
+
drumVolume = clamp3(volume, 0, 100);
|
|
12673
|
+
refs.drumVolume.value = String(drumVolume);
|
|
12674
|
+
refs.drumVolumeLabel.textContent = `${drumVolume}%`;
|
|
12675
|
+
},
|
|
12423
12676
|
applyPatch: (trackId, added, removed) => {
|
|
12424
12677
|
const track = trackStates.find((t) => t.config.id === trackId);
|
|
12425
12678
|
if (!track) return;
|