@onjmin/dtm 0.1.12 → 0.1.13

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 CHANGED
@@ -30,6 +30,38 @@ const daw = studio.mountEditor(document.getElementById("editor"), {
30
30
  studio.mountPlayer(document.getElementById("player"), daw.getMML().full);
31
31
  ```
32
32
 
33
+ ## モード(`simple` / `advanced`)
34
+
35
+ トラック構成と MIDI の取り込み方が異なる 2 つのモードがあります。`mode` オプションで切り替え、
36
+ 合わせて `tracks` に対応するトラック構成(`TRACKS_SIMPLE` / `TRACKS_ADVANCED`)を渡します。
37
+
38
+ | モード | トラック | MIDI 取り込み | 伴奏(コード進行)UI |
39
+ | --- | --- | --- | --- |
40
+ | `simple` | メロディー / サブメロ / ベース / 伴奏 の 4 本 | 各トラックの特徴から役割へ**自動分類** | `chord` トラックに表示(歌詞欄の代わり) |
41
+ | `advanced` | TRACK 01〜16 の 16 本 | MIDI トラックを**1:1 マッピング** | なし(全トラックが通常のノート+歌詞トラック) |
42
+
43
+ ```ts
44
+ import {
45
+ createDtmStudio,
46
+ TRACKS_SIMPLE,
47
+ TRACKS_ADVANCED,
48
+ } from "@onjmin/dtm";
49
+
50
+ const studio = await createDtmStudio();
51
+
52
+ // シンプルモード(既定)
53
+ studio.mountEditor(editorEl, { mode: "simple", tracks: TRACKS_SIMPLE });
54
+
55
+ // アドバンスモード
56
+ studio.mountEditor(editorEl, { mode: "advanced", tracks: TRACKS_ADVANCED });
57
+ ```
58
+
59
+ - `mode` を省略すると `tracks` の本数から推論します(4 本以下→`simple` / 5 本以上→`advanced`)。
60
+ 4 トラックでも 1:1 で取り込みたい等、意図がトラック数とずれる場合は `mode` を明示してください。
61
+ - `tracks` には任意の独自構成も渡せます(`mode` と組み合わせて挙動を決めます)。
62
+ - MIDI のドラム(ch10)はピアノロールで編集できないため、取り込み時の**トラック選択 UI には出ません**。
63
+ - `mode` / `tracks` は低レベル API の `mountDAW` でも同じく指定できます。
64
+
33
65
  ## 低レベル API(`mountDAW` / 注入式)
34
66
 
35
67
  本体は音を持たない設計で、`onPlayNote` / `onPlayDrum` に自前のシンセを繋ぐ
package/dist/index.d.mts CHANGED
@@ -537,6 +537,13 @@ type DawViewState = {
537
537
  /** 和音分解時に和音伴奏トラックを分解対象から除外するフラグ */
538
538
  ignoreChordHeavy: boolean;
539
539
  };
540
+ /**
541
+ * DAWの動作モード。
542
+ * - `simple`: 4トラック(メロディー/サブメロ/ベース/伴奏)。MIDIは役割別に自動分類して取り込み、
543
+ * id `chord` のトラックには歌詞欄の代わりに伴奏(コード進行)UIを出す。
544
+ * - `advanced`: MIDIトラックを1:1でマッピング。全トラックが通常のノートトラックとして振る舞う。
545
+ */
546
+ type DawMode = "simple" | "advanced";
540
547
  type DawOptions = {
541
548
  /** メロディックトラックのノート発音要求 */
542
549
  onPlayNote?: (e: PlayNoteEvent) => void;
@@ -559,6 +566,12 @@ type DawOptions = {
559
566
  */
560
567
  onViewStateChange?: (state: DawViewState) => void;
561
568
  parseMidi?: ParseMidiFn;
569
+ /**
570
+ * 動作モード({@link DawMode})。
571
+ * 未指定のときは後方互換のため `tracks` の本数から推論する(4本以下→simple / 5本以上→advanced)。
572
+ * 4トラック構成でも1:1取り込みをしたい等、トラック数と意図がずれる場合は明示指定する。
573
+ */
574
+ mode?: DawMode;
562
575
  /** トラック構成。既定は melody/submelody/bass/chord の4本 */
563
576
  tracks?: TrackConfig[];
564
577
  /** ドラムパターン辞書。既定は DRUM_PATTERNS */
@@ -836,6 +849,8 @@ type MidiExtraction = {
836
849
  };
837
850
  /**
838
851
  * MIDIの各トラックを走査し、ノート数などの概要を返す(トラック選択UI用)。
852
+ * ノート数はピアノロールで編集可能なノートのみを数える(ドラム ch10 は除外)。
853
+ * ドラム(ch10)だけで構成されたトラックは編集できないため、結果に含めない。
839
854
  */
840
855
  declare const analyzeMidiTracks: (midi: unknown) => MidiTrackAnalysis[];
841
856
  /** MIDIメタイベントからBPMを取得(無ければ120)。 */
@@ -1266,4 +1281,4 @@ declare const DAW_CSS = "\n@font-face {\n font-family: 'k8x12';\n src: url('ht
1266
1281
  */
1267
1282
  declare const injectStyles: (doc?: Document) => void;
1268
1283
 
1269
- export { type AddNoteOptions, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ConsumedSyllable, type CoreEventHandlers, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawOptions, type DawViewState, type DrumPattern, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LyricSyllable, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, type MidiTrackAnalysis, type MmlMeta, type MmlPlayerInstance, type MmlPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PitchToken, type PlayDrumEvent, type PlayNoteEvent, type PlaybackState, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VOICE_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createVoiceRegistry, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, exportMIDI, extractMidiPlacements, extractMidiPlacementsByTrack, fetchSoundFontList, formatMmlMeta, generateRandomPattern, getDrawOffset, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, koeUrl, mountDAW, mountMmlPlayer, normalizeLyrics, onClick, panToStereo, parseLyrics, parseMML, parseMmlMeta, setDrawOffset, setupRecorder, shiftNotes, stripLyrics, stripMmlMeta, vocalVolumeToGain };
1284
+ export { type AddNoteOptions, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ConsumedSyllable, type CoreEventHandlers, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawMode, type DawOptions, type DawViewState, type DrumPattern, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LyricSyllable, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, type MidiTrackAnalysis, type MmlMeta, type MmlPlayerInstance, type MmlPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PitchToken, type PlayDrumEvent, type PlayNoteEvent, type PlaybackState, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VOICE_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createVoiceRegistry, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, exportMIDI, extractMidiPlacements, extractMidiPlacementsByTrack, fetchSoundFontList, formatMmlMeta, generateRandomPattern, getDrawOffset, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, koeUrl, mountDAW, mountMmlPlayer, normalizeLyrics, onClick, panToStereo, parseLyrics, parseMML, parseMmlMeta, setDrawOffset, setupRecorder, shiftNotes, stripLyrics, stripMmlMeta, vocalVolumeToGain };
package/dist/index.d.ts CHANGED
@@ -537,6 +537,13 @@ type DawViewState = {
537
537
  /** 和音分解時に和音伴奏トラックを分解対象から除外するフラグ */
538
538
  ignoreChordHeavy: boolean;
539
539
  };
540
+ /**
541
+ * DAWの動作モード。
542
+ * - `simple`: 4トラック(メロディー/サブメロ/ベース/伴奏)。MIDIは役割別に自動分類して取り込み、
543
+ * id `chord` のトラックには歌詞欄の代わりに伴奏(コード進行)UIを出す。
544
+ * - `advanced`: MIDIトラックを1:1でマッピング。全トラックが通常のノートトラックとして振る舞う。
545
+ */
546
+ type DawMode = "simple" | "advanced";
540
547
  type DawOptions = {
541
548
  /** メロディックトラックのノート発音要求 */
542
549
  onPlayNote?: (e: PlayNoteEvent) => void;
@@ -559,6 +566,12 @@ type DawOptions = {
559
566
  */
560
567
  onViewStateChange?: (state: DawViewState) => void;
561
568
  parseMidi?: ParseMidiFn;
569
+ /**
570
+ * 動作モード({@link DawMode})。
571
+ * 未指定のときは後方互換のため `tracks` の本数から推論する(4本以下→simple / 5本以上→advanced)。
572
+ * 4トラック構成でも1:1取り込みをしたい等、トラック数と意図がずれる場合は明示指定する。
573
+ */
574
+ mode?: DawMode;
562
575
  /** トラック構成。既定は melody/submelody/bass/chord の4本 */
563
576
  tracks?: TrackConfig[];
564
577
  /** ドラムパターン辞書。既定は DRUM_PATTERNS */
@@ -836,6 +849,8 @@ type MidiExtraction = {
836
849
  };
837
850
  /**
838
851
  * MIDIの各トラックを走査し、ノート数などの概要を返す(トラック選択UI用)。
852
+ * ノート数はピアノロールで編集可能なノートのみを数える(ドラム ch10 は除外)。
853
+ * ドラム(ch10)だけで構成されたトラックは編集できないため、結果に含めない。
839
854
  */
840
855
  declare const analyzeMidiTracks: (midi: unknown) => MidiTrackAnalysis[];
841
856
  /** MIDIメタイベントからBPMを取得(無ければ120)。 */
@@ -1266,4 +1281,4 @@ declare const DAW_CSS = "\n@font-face {\n font-family: 'k8x12';\n src: url('ht
1266
1281
  */
1267
1282
  declare const injectStyles: (doc?: Document) => void;
1268
1283
 
1269
- export { type AddNoteOptions, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ConsumedSyllable, type CoreEventHandlers, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawOptions, type DawViewState, type DrumPattern, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LyricSyllable, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, type MidiTrackAnalysis, type MmlMeta, type MmlPlayerInstance, type MmlPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PitchToken, type PlayDrumEvent, type PlayNoteEvent, type PlaybackState, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VOICE_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createVoiceRegistry, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, exportMIDI, extractMidiPlacements, extractMidiPlacementsByTrack, fetchSoundFontList, formatMmlMeta, generateRandomPattern, getDrawOffset, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, koeUrl, mountDAW, mountMmlPlayer, normalizeLyrics, onClick, panToStereo, parseLyrics, parseMML, parseMmlMeta, setDrawOffset, setupRecorder, shiftNotes, stripLyrics, stripMmlMeta, vocalVolumeToGain };
1284
+ export { type AddNoteOptions, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ConsumedSyllable, type CoreEventHandlers, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawMode, type DawOptions, type DawViewState, type DrumPattern, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LyricSyllable, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, type MidiTrackAnalysis, type MmlMeta, type MmlPlayerInstance, type MmlPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PitchToken, type PlayDrumEvent, type PlayNoteEvent, type PlaybackState, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VOICE_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createVoiceRegistry, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, exportMIDI, extractMidiPlacements, extractMidiPlacementsByTrack, fetchSoundFontList, formatMmlMeta, generateRandomPattern, getDrawOffset, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, koeUrl, mountDAW, mountMmlPlayer, normalizeLyrics, onClick, panToStereo, parseLyrics, parseMML, parseMmlMeta, setDrawOffset, setupRecorder, shiftNotes, stripLyrics, stripMmlMeta, vocalVolumeToGain };
package/dist/index.js CHANGED
@@ -1322,7 +1322,10 @@ var buildUI = (target, options) => {
1322
1322
  <summary>MIDI / MML \u5165\u529B</summary>
1323
1323
  <div class="dtm-panel-body">
1324
1324
  <div class="dtm-row">
1325
- <span class="dtm-label">MIDI</span>
1325
+ <div style="display: inline-flex; flex-direction: column; align-items: center; gap: 4px; justify-content: center; min-width: 48px;">
1326
+ <span class="dtm-label" style="line-height: 1;">MIDI</span>
1327
+ <button class="dtm-infobtn" data-dtm="midi-info" title="MIDI\u306E\u8AAD\u307F\u8FBC\u307F\u89E3\u8AAC">${icon("info", 12)}</button>
1328
+ </div>
1326
1329
  <input type="file" class="dtm-input dtm-grow" accept=".mid,.midi" data-dtm="midi-input">
1327
1330
  <button class="dtm-btn dtm-btn--success" data-dtm="midi-load">\u8AAD\u8FBC</button>
1328
1331
  </div>
@@ -1455,6 +1458,7 @@ var buildUI = (target, options) => {
1455
1458
  drumVolumeLabel: sel("drum-volume-label"),
1456
1459
  midiInput: sel("midi-input"),
1457
1460
  midiLoadBtn: sel("midi-load"),
1461
+ midiInfoBtn: sel("midi-info"),
1458
1462
  midiTrackSelection: sel("midi-track-selection"),
1459
1463
  midiPanel: sel("midi-panel"),
1460
1464
  mmlInput: sel("mml-input"),
@@ -2888,7 +2892,7 @@ var analyzeMidiTracks = (midi) => {
2888
2892
  currentTime += event.deltaTime;
2889
2893
  const data = event.data;
2890
2894
  if (event.type === 9 && data && data[1]) {
2891
- notes.push({ pitch: data[0] });
2895
+ notes.push({ pitch: data[0], channel: event.channel ?? 0 });
2892
2896
  } else if (event.type === 8) {
2893
2897
  for (let k = notes.length - 1; k >= 0; k--) {
2894
2898
  if (notes[k].pitch === data[0] && notes[k].end === void 0) {
@@ -2899,11 +2903,13 @@ var analyzeMidiTracks = (midi) => {
2899
2903
  }
2900
2904
  }
2901
2905
  const validNotes = notes.filter((n) => n.end !== void 0);
2906
+ const editableNotes = validNotes.filter((n) => n.channel !== 9);
2907
+ if (validNotes.length > 0 && editableNotes.length === 0) continue;
2902
2908
  result.push({
2903
2909
  index: i,
2904
2910
  name: `Ch${i + 1}`,
2905
- noteCount: validNotes.length,
2906
- selected: validNotes.length > 0
2911
+ noteCount: editableNotes.length,
2912
+ selected: editableNotes.length > 0
2907
2913
  });
2908
2914
  }
2909
2915
  return result;
@@ -5280,6 +5286,7 @@ var CHORD_INFO_HTML = `
5280
5286
  <h4>1. \u57FA\u672C\u306E\u66F8\u304D\u65B9</h4>
5281
5287
  <p>\u30B3\u30FC\u30C9\u540D\uFF08\u548C\u97F3\u8A18\u53F7\uFF09\u3092\u7E26\u7DDA <code>|</code>\u3001\u30B9\u30DA\u30FC\u30B9\u3001\u307E\u305F\u306F\u30AB\u30F3\u30DE\u3067\u533A\u5207\u3063\u3066\u5165\u529B\u3057\u307E\u3059\u3002\u7E26\u7DDA\u3067\u533A\u5207\u308B\u30681\u5C0F\u7BC0\u3054\u3068\u306E\u914D\u7F6E\u306B\u306A\u308A\u307E\u3059\u3002</p>
5282
5288
  <pre>\u4F8B: C | G | Am | F</pre>
5289
+ <p style="margin-top:4px;"><small>\u30B3\u30FC\u30C9\u9032\u884C\u3092\u81EA\u5206\u3067\u8003\u3048\u308B\u306E\u304C\u96E3\u3057\u3044\u3068\u304D\u306F\u3001\u30B3\u30FC\u30C9\u9032\u884C\u306E\u5171\u6709\u30B5\u30A4\u30C8\uFF08\u4F8B: <a href="https://rechord.cc/scores" target="_blank" rel="noopener">rechord.cc</a>\uFF09\u304B\u3089\u597D\u304D\u306A\u9032\u884C\u3092\u63A2\u3057\u3066\u30B3\u30D4\u30DA\u3059\u308B\u306E\u3082\u624B\u3067\u3059\u3002\u533A\u5207\u308A\u6587\u5B57\uFF08<code>|</code> / \u30B9\u30DA\u30FC\u30B9 / \u30AB\u30F3\u30DE\uFF09\u3060\u3051\u4E0A\u306E\u5F62\u5F0F\u306B\u5408\u308F\u305B\u308C\u3070\u3001\u305D\u306E\u307E\u307E\u4F7F\u3048\u307E\u3059\u3002</small></p>
5283
5290
 
5284
5291
  <h4>2. 1\u5C0F\u7BC0\u306B\u8907\u6570\u30B3\u30FC\u30C9\u3092\u5165\u308C\u308B</h4>
5285
5292
  <p>\u5C0F\u7BC0\u306E\u533A\u5207\u308A\uFF08\u7E26\u7DDA <code>|</code>\uFF09\u306E\u4E2D\u306B\u3001\u30B9\u30DA\u30FC\u30B9\u533A\u5207\u308A\u3067\u30B3\u30FC\u30C9\u3092\u4E26\u3079\u307E\u3059\u3002\u7B49\u9593\u9694\u306B\u914D\u7F6E\u3055\u308C\u307E\u3059\u3002</p>
@@ -5354,6 +5361,38 @@ var MML_INFO_HTML = `
5354
5361
  <p style="margin-top:4px;"><small>\uFF08\u97F3\u6E90\u540D\u306F <code>klatt</code> \u3084 <code>roze</code>, <code>teto</code> \u306A\u3069\u306E\u97F3\u58F0\u30E2\u30C7\u30EB\u3092\u6307\u5B9A\u3067\u304D\u307E\u3059\uFF09</small></p>
5355
5362
  </div>
5356
5363
  `;
5364
+ var MIDI_INFO_HTML = `
5365
+ <div class="dtm-modal-body-content">
5366
+ <h4>1. MIDI\u30D5\u30A1\u30A4\u30EB\u3068\u306F</h4>
5367
+ <p>\u300C\u3069\u306E\u97F3\u3092\u30FB\u3044\u3064\u30FB\u3069\u306E\u304F\u3089\u3044\u306E\u9577\u3055\u3067\u9CF4\u3089\u3059\u304B\u300D\u3092\u8A18\u9332\u3057\u305F\u3001\u6F14\u594F\u30C7\u30FC\u30BF\u306E\u30D5\u30A1\u30A4\u30EB\uFF08\u62E1\u5F35\u5B50 <code>.mid</code> / <code>.midi</code>\uFF09\u3067\u3059\u3002\u97F3\u305D\u306E\u3082\u306E\u3067\u306F\u306A\u304F\u697D\u8B5C\u306B\u8FD1\u3044\u30C7\u30FC\u30BF\u306A\u306E\u3067\u3001\u8AAD\u307F\u8FBC\u3093\u3067\u305D\u306E\u307E\u307E\u7DE8\u96C6\u3067\u304D\u307E\u3059\u3002</p>
5368
+
5369
+ <h4>2. \u8AAD\u307F\u8FBC\u307F\u306E\u3057\u304B\u305F</h4>
5370
+ <ul>
5371
+ <li>\u300C\u30D5\u30A1\u30A4\u30EB\u3092\u9078\u629E\u300D\u304B\u3089 <code>.mid</code> \u30D5\u30A1\u30A4\u30EB\u3092\u9078\u3073\u307E\u3059\u3002</li>
5372
+ <li>\u30D5\u30A1\u30A4\u30EB\u5185\u306E\u30C8\u30E9\u30C3\u30AF\u4E00\u89A7\u304C\u51FA\u308B\u306E\u3067\u3001\u53D6\u308A\u8FBC\u307F\u305F\u3044\u30C8\u30E9\u30C3\u30AF\u3092\u9078\u3073\u307E\u3059\u3002</li>
5373
+ <li>\u300C\u8AAD\u8FBC\u300D\u3092\u62BC\u3059\u3068\u53CD\u6620\u3055\u308C\u307E\u3059\u3002</li>
5374
+ </ul>
5375
+
5376
+ <h4>3. \u30E2\u30FC\u30C9\u306B\u3088\u308B\u53D6\u308A\u8FBC\u307F\u65B9\u306E\u9055\u3044</h4>
5377
+ <ul>
5378
+ <li><strong>SIMPLE</strong>: \u5404\u30C8\u30E9\u30C3\u30AF\u306E\u7279\u5FB4\u304B\u3089\u3001\u30E1\u30ED\u30C7\u30A3\u30FC\u30FB\u30B5\u30D6\u30E1\u30ED\u30FB\u30D9\u30FC\u30B9\u30FB\u4F34\u594F\u306E4\u3064\u306E\u5F79\u5272\u306B\u81EA\u52D5\u3067\u632F\u308A\u5206\u3051\u3089\u308C\u307E\u3059\u3002</li>
5379
+ <li><strong>ADVANCED</strong>: MIDI\u306E\u30C8\u30E9\u30C3\u30AF\u69CB\u6210\u304C\u305D\u306E\u307E\u307E\u53CD\u6620\u3055\u308C\u307E\u3059\uFF081\u5BFE1\uFF09\u3002</li>
5380
+ </ul>
5381
+
5382
+ <h4>4. MIDI\u30D5\u30A1\u30A4\u30EB\u3092\u624B\u306B\u5165\u308C\u308B</h4>
5383
+ <p>\u624B\u5143\u306BMIDI\u304C\u7121\u3044\u3068\u304D\u306F\u3001\u300C<code>\u66F2\u540D midi</code>\u300D\u306A\u3069\u3067\u691C\u7D22\u3059\u308C\u3070\u3001\u7121\u6599\u3067\u914D\u5E03\u3057\u3066\u3044\u308B\u30B5\u30A4\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u3059\u3002</p>
5384
+ <p style="margin-top:4px;"><small>\u307F\u3093\u306A\u304CMIDI\u3092\u6295\u7A3F\u3067\u304D\u308B\u6295\u7A3F\u578B\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0: <a href="http://picotune.me/" target="_blank" rel="noopener">picotune.me</a>\uFF08\u3044\u308D\u3093\u306A\u30B8\u30E3\u30F3\u30EB\u306EMIDI\u3092\u7121\u6599\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3067\u304D\u307E\u3059\u3002\u30B5\u30A4\u30C8\u4E0A\u3067\u306F\u30C1\u30C3\u30D7\u30C1\u30E5\u30FC\u30F3\u98A8\u306B\u518D\u751F\u3055\u308C\u307E\u3059\uFF09</small></p>
5385
+ <p style="margin-top:4px;"><small>\u203B\u691C\u7D22\u3067\u898B\u3064\u304B\u308B\u914D\u5E03\u30B5\u30A4\u30C8\u306F\u3001\u500B\u4EBA\u904B\u55B6\u306E\u3082\u306E\u304B\u3089\u6A29\u5229\u7684\u306B\u30B0\u30EC\u30FC\u306A\u3082\u306E\u307E\u3067\u69D8\u3005\u3067\u3059\u3002\u305D\u306E\u305F\u3081\u3001\u305D\u308C\u3089\u3078\u306E\u76F4\u63A5\u30EA\u30F3\u30AF\u306F\u8F09\u305B\u3066\u3044\u307E\u305B\u3093\u3002\u5229\u7528\u306E\u969B\u306F\u914D\u5E03\u5143\u3084\u6A29\u5229\u95A2\u4FC2\u3092\u3054\u81EA\u8EAB\u3067\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044\u3002</small></p>
5386
+
5387
+ <h4>5. UST\uFF08UTAU\uFF09\u306E\u6B4C\u8A5E\u3092\u4F7F\u3046</h4>
5388
+ <p>UTAU\u306EUST\u30D5\u30A1\u30A4\u30EB\u304B\u3089\u6B4C\u8A5E\u3060\u3051\u3092\u53D6\u308A\u51FA\u3057\u3066\u3001\u6B4C\u308F\u305B\u308B\u3053\u3068\u3082\u3067\u304D\u307E\u3059\u3002</p>
5389
+ <ul>
5390
+ <li>\u97F3\u7B26: UTAU\u306A\u3069\u3067UST\u3092MIDI\u306B\u66F8\u304D\u51FA\u3057\u3001\u4E0A\u306E\u624B\u9806\u3067\u8AAD\u307F\u8FBC\u307F\u307E\u3059\u3002</li>
5391
+ <li>\u6B4C\u8A5E: \u4E0B\u8A18\u30B5\u30A4\u30C8\u3067UST\u304B\u3089\u6B4C\u8A5E\u30C6\u30AD\u30B9\u30C8\u3092\u629C\u304D\u51FA\u3057\u3001MML/\u6B4C\u8A5E\u5165\u529B\u6B04\u306E <code>@@</code> \u69CB\u6587\u306B\u8CBC\u308A\u4ED8\u3051\u307E\u3059\u3002</li>
5392
+ </ul>
5393
+ <p style="margin-top:4px;"><small>\u6B4C\u8A5E\u306E\u62BD\u51FA: <a href="https://rpgen3.github.io/ust2txt/" target="_blank" rel="noopener">ust2txt</a></small></p>
5394
+ </div>
5395
+ `;
5357
5396
  var BASE_STEP_WIDTH = 0.5;
5358
5397
  var BASE_KEY_HEIGHT = 15;
5359
5398
  var TRACKS_SIMPLE = [
@@ -5512,9 +5551,11 @@ var mountDAW = (target, options = {}) => {
5512
5551
  injectStyles();
5513
5552
  const getAudioTime = options.getAudioTime ?? (() => performance.now() / 1e3);
5514
5553
  const trackConfigs = options.tracks ?? DEFAULT_TRACKS;
5554
+ const mode = options.mode ?? (trackConfigs.length > TRACKS_SIMPLE.length ? "advanced" : "simple");
5555
+ const isAdvanced = mode === "advanced";
5515
5556
  const drumPatterns = options.drumPatterns ?? DRUM_PATTERNS;
5516
5557
  const showMidi = !!options.parseMidi;
5517
- const showChord = true;
5558
+ const showChord = !isAdvanced;
5518
5559
  const refs = buildUI(target, {
5519
5560
  tracks: trackConfigs,
5520
5561
  drumPatternNames: Object.keys(drumPatterns),
@@ -6299,7 +6340,6 @@ var mountDAW = (target, options = {}) => {
6299
6340
  active.core.setVolume(active.volume);
6300
6341
  volLabel.textContent = String(active.volume);
6301
6342
  });
6302
- const isAdvanced = trackStates.length > TRACKS_SIMPLE.length;
6303
6343
  if (isAdvanced || active.config.id !== "chord") {
6304
6344
  const lyricDiv = document.createElement("div");
6305
6345
  lyricDiv.className = "dtm-row";
@@ -6507,16 +6547,16 @@ var mountDAW = (target, options = {}) => {
6507
6547
  updateUndoRedo();
6508
6548
  redrawAll();
6509
6549
  };
6510
- const setToolMode = (mode) => {
6511
- activeToolMode = mode;
6550
+ const setToolMode = (mode2) => {
6551
+ activeToolMode = mode2;
6512
6552
  for (const [btn, m] of [
6513
6553
  [refs.toolPen, "pen"],
6514
6554
  [refs.toolSelect, "select"],
6515
6555
  [refs.toolEraser, "eraser"]
6516
6556
  ]) {
6517
- btn.classList.toggle("dtm-segbtn--active", m === mode);
6557
+ btn.classList.toggle("dtm-segbtn--active", m === mode2);
6518
6558
  }
6519
- if (mode !== "select") {
6559
+ if (mode2 !== "select") {
6520
6560
  selectionRect = null;
6521
6561
  selectedNotes = [];
6522
6562
  }
@@ -6750,7 +6790,6 @@ var mountDAW = (target, options = {}) => {
6750
6790
  const applyMidiSelection = (midi, selectedIndices) => {
6751
6791
  clearAll();
6752
6792
  for (const t of trackStates) t.core.setLoadMode(true);
6753
- const isAdvanced = trackStates.length > TRACKS_SIMPLE.length;
6754
6793
  const { placements, bpm: parsedBpm } = isAdvanced ? extractMidiPlacementsByTrack(
6755
6794
  midi,
6756
6795
  selectedIndices,
@@ -6948,6 +6987,9 @@ var mountDAW = (target, options = {}) => {
6948
6987
  refs.mmlInfoBtn.addEventListener("click", () => {
6949
6988
  showModal("MML\u306E\u66F8\u304D\u65B9\u89E3\u8AAC", MML_INFO_HTML);
6950
6989
  });
6990
+ refs.midiInfoBtn.addEventListener("click", () => {
6991
+ showModal("MIDI\u306E\u8AAD\u307F\u8FBC\u307F\u89E3\u8AAC", MIDI_INFO_HTML);
6992
+ });
6951
6993
  refs.shiftApplyBtn.addEventListener(
6952
6994
  "click",
6953
6995
  () => overlayDuring(() => {
package/dist/index.mjs CHANGED
@@ -1217,7 +1217,10 @@ var buildUI = (target, options) => {
1217
1217
  <summary>MIDI / MML \u5165\u529B</summary>
1218
1218
  <div class="dtm-panel-body">
1219
1219
  <div class="dtm-row">
1220
- <span class="dtm-label">MIDI</span>
1220
+ <div style="display: inline-flex; flex-direction: column; align-items: center; gap: 4px; justify-content: center; min-width: 48px;">
1221
+ <span class="dtm-label" style="line-height: 1;">MIDI</span>
1222
+ <button class="dtm-infobtn" data-dtm="midi-info" title="MIDI\u306E\u8AAD\u307F\u8FBC\u307F\u89E3\u8AAC">${icon("info", 12)}</button>
1223
+ </div>
1221
1224
  <input type="file" class="dtm-input dtm-grow" accept=".mid,.midi" data-dtm="midi-input">
1222
1225
  <button class="dtm-btn dtm-btn--success" data-dtm="midi-load">\u8AAD\u8FBC</button>
1223
1226
  </div>
@@ -1350,6 +1353,7 @@ var buildUI = (target, options) => {
1350
1353
  drumVolumeLabel: sel("drum-volume-label"),
1351
1354
  midiInput: sel("midi-input"),
1352
1355
  midiLoadBtn: sel("midi-load"),
1356
+ midiInfoBtn: sel("midi-info"),
1353
1357
  midiTrackSelection: sel("midi-track-selection"),
1354
1358
  midiPanel: sel("midi-panel"),
1355
1359
  mmlInput: sel("mml-input"),
@@ -2783,7 +2787,7 @@ var analyzeMidiTracks = (midi) => {
2783
2787
  currentTime += event.deltaTime;
2784
2788
  const data = event.data;
2785
2789
  if (event.type === 9 && data && data[1]) {
2786
- notes.push({ pitch: data[0] });
2790
+ notes.push({ pitch: data[0], channel: event.channel ?? 0 });
2787
2791
  } else if (event.type === 8) {
2788
2792
  for (let k = notes.length - 1; k >= 0; k--) {
2789
2793
  if (notes[k].pitch === data[0] && notes[k].end === void 0) {
@@ -2794,11 +2798,13 @@ var analyzeMidiTracks = (midi) => {
2794
2798
  }
2795
2799
  }
2796
2800
  const validNotes = notes.filter((n) => n.end !== void 0);
2801
+ const editableNotes = validNotes.filter((n) => n.channel !== 9);
2802
+ if (validNotes.length > 0 && editableNotes.length === 0) continue;
2797
2803
  result.push({
2798
2804
  index: i,
2799
2805
  name: `Ch${i + 1}`,
2800
- noteCount: validNotes.length,
2801
- selected: validNotes.length > 0
2806
+ noteCount: editableNotes.length,
2807
+ selected: editableNotes.length > 0
2802
2808
  });
2803
2809
  }
2804
2810
  return result;
@@ -5175,6 +5181,7 @@ var CHORD_INFO_HTML = `
5175
5181
  <h4>1. \u57FA\u672C\u306E\u66F8\u304D\u65B9</h4>
5176
5182
  <p>\u30B3\u30FC\u30C9\u540D\uFF08\u548C\u97F3\u8A18\u53F7\uFF09\u3092\u7E26\u7DDA <code>|</code>\u3001\u30B9\u30DA\u30FC\u30B9\u3001\u307E\u305F\u306F\u30AB\u30F3\u30DE\u3067\u533A\u5207\u3063\u3066\u5165\u529B\u3057\u307E\u3059\u3002\u7E26\u7DDA\u3067\u533A\u5207\u308B\u30681\u5C0F\u7BC0\u3054\u3068\u306E\u914D\u7F6E\u306B\u306A\u308A\u307E\u3059\u3002</p>
5177
5183
  <pre>\u4F8B: C | G | Am | F</pre>
5184
+ <p style="margin-top:4px;"><small>\u30B3\u30FC\u30C9\u9032\u884C\u3092\u81EA\u5206\u3067\u8003\u3048\u308B\u306E\u304C\u96E3\u3057\u3044\u3068\u304D\u306F\u3001\u30B3\u30FC\u30C9\u9032\u884C\u306E\u5171\u6709\u30B5\u30A4\u30C8\uFF08\u4F8B: <a href="https://rechord.cc/scores" target="_blank" rel="noopener">rechord.cc</a>\uFF09\u304B\u3089\u597D\u304D\u306A\u9032\u884C\u3092\u63A2\u3057\u3066\u30B3\u30D4\u30DA\u3059\u308B\u306E\u3082\u624B\u3067\u3059\u3002\u533A\u5207\u308A\u6587\u5B57\uFF08<code>|</code> / \u30B9\u30DA\u30FC\u30B9 / \u30AB\u30F3\u30DE\uFF09\u3060\u3051\u4E0A\u306E\u5F62\u5F0F\u306B\u5408\u308F\u305B\u308C\u3070\u3001\u305D\u306E\u307E\u307E\u4F7F\u3048\u307E\u3059\u3002</small></p>
5178
5185
 
5179
5186
  <h4>2. 1\u5C0F\u7BC0\u306B\u8907\u6570\u30B3\u30FC\u30C9\u3092\u5165\u308C\u308B</h4>
5180
5187
  <p>\u5C0F\u7BC0\u306E\u533A\u5207\u308A\uFF08\u7E26\u7DDA <code>|</code>\uFF09\u306E\u4E2D\u306B\u3001\u30B9\u30DA\u30FC\u30B9\u533A\u5207\u308A\u3067\u30B3\u30FC\u30C9\u3092\u4E26\u3079\u307E\u3059\u3002\u7B49\u9593\u9694\u306B\u914D\u7F6E\u3055\u308C\u307E\u3059\u3002</p>
@@ -5249,6 +5256,38 @@ var MML_INFO_HTML = `
5249
5256
  <p style="margin-top:4px;"><small>\uFF08\u97F3\u6E90\u540D\u306F <code>klatt</code> \u3084 <code>roze</code>, <code>teto</code> \u306A\u3069\u306E\u97F3\u58F0\u30E2\u30C7\u30EB\u3092\u6307\u5B9A\u3067\u304D\u307E\u3059\uFF09</small></p>
5250
5257
  </div>
5251
5258
  `;
5259
+ var MIDI_INFO_HTML = `
5260
+ <div class="dtm-modal-body-content">
5261
+ <h4>1. MIDI\u30D5\u30A1\u30A4\u30EB\u3068\u306F</h4>
5262
+ <p>\u300C\u3069\u306E\u97F3\u3092\u30FB\u3044\u3064\u30FB\u3069\u306E\u304F\u3089\u3044\u306E\u9577\u3055\u3067\u9CF4\u3089\u3059\u304B\u300D\u3092\u8A18\u9332\u3057\u305F\u3001\u6F14\u594F\u30C7\u30FC\u30BF\u306E\u30D5\u30A1\u30A4\u30EB\uFF08\u62E1\u5F35\u5B50 <code>.mid</code> / <code>.midi</code>\uFF09\u3067\u3059\u3002\u97F3\u305D\u306E\u3082\u306E\u3067\u306F\u306A\u304F\u697D\u8B5C\u306B\u8FD1\u3044\u30C7\u30FC\u30BF\u306A\u306E\u3067\u3001\u8AAD\u307F\u8FBC\u3093\u3067\u305D\u306E\u307E\u307E\u7DE8\u96C6\u3067\u304D\u307E\u3059\u3002</p>
5263
+
5264
+ <h4>2. \u8AAD\u307F\u8FBC\u307F\u306E\u3057\u304B\u305F</h4>
5265
+ <ul>
5266
+ <li>\u300C\u30D5\u30A1\u30A4\u30EB\u3092\u9078\u629E\u300D\u304B\u3089 <code>.mid</code> \u30D5\u30A1\u30A4\u30EB\u3092\u9078\u3073\u307E\u3059\u3002</li>
5267
+ <li>\u30D5\u30A1\u30A4\u30EB\u5185\u306E\u30C8\u30E9\u30C3\u30AF\u4E00\u89A7\u304C\u51FA\u308B\u306E\u3067\u3001\u53D6\u308A\u8FBC\u307F\u305F\u3044\u30C8\u30E9\u30C3\u30AF\u3092\u9078\u3073\u307E\u3059\u3002</li>
5268
+ <li>\u300C\u8AAD\u8FBC\u300D\u3092\u62BC\u3059\u3068\u53CD\u6620\u3055\u308C\u307E\u3059\u3002</li>
5269
+ </ul>
5270
+
5271
+ <h4>3. \u30E2\u30FC\u30C9\u306B\u3088\u308B\u53D6\u308A\u8FBC\u307F\u65B9\u306E\u9055\u3044</h4>
5272
+ <ul>
5273
+ <li><strong>SIMPLE</strong>: \u5404\u30C8\u30E9\u30C3\u30AF\u306E\u7279\u5FB4\u304B\u3089\u3001\u30E1\u30ED\u30C7\u30A3\u30FC\u30FB\u30B5\u30D6\u30E1\u30ED\u30FB\u30D9\u30FC\u30B9\u30FB\u4F34\u594F\u306E4\u3064\u306E\u5F79\u5272\u306B\u81EA\u52D5\u3067\u632F\u308A\u5206\u3051\u3089\u308C\u307E\u3059\u3002</li>
5274
+ <li><strong>ADVANCED</strong>: MIDI\u306E\u30C8\u30E9\u30C3\u30AF\u69CB\u6210\u304C\u305D\u306E\u307E\u307E\u53CD\u6620\u3055\u308C\u307E\u3059\uFF081\u5BFE1\uFF09\u3002</li>
5275
+ </ul>
5276
+
5277
+ <h4>4. MIDI\u30D5\u30A1\u30A4\u30EB\u3092\u624B\u306B\u5165\u308C\u308B</h4>
5278
+ <p>\u624B\u5143\u306BMIDI\u304C\u7121\u3044\u3068\u304D\u306F\u3001\u300C<code>\u66F2\u540D midi</code>\u300D\u306A\u3069\u3067\u691C\u7D22\u3059\u308C\u3070\u3001\u7121\u6599\u3067\u914D\u5E03\u3057\u3066\u3044\u308B\u30B5\u30A4\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u3059\u3002</p>
5279
+ <p style="margin-top:4px;"><small>\u307F\u3093\u306A\u304CMIDI\u3092\u6295\u7A3F\u3067\u304D\u308B\u6295\u7A3F\u578B\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0: <a href="http://picotune.me/" target="_blank" rel="noopener">picotune.me</a>\uFF08\u3044\u308D\u3093\u306A\u30B8\u30E3\u30F3\u30EB\u306EMIDI\u3092\u7121\u6599\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3067\u304D\u307E\u3059\u3002\u30B5\u30A4\u30C8\u4E0A\u3067\u306F\u30C1\u30C3\u30D7\u30C1\u30E5\u30FC\u30F3\u98A8\u306B\u518D\u751F\u3055\u308C\u307E\u3059\uFF09</small></p>
5280
+ <p style="margin-top:4px;"><small>\u203B\u691C\u7D22\u3067\u898B\u3064\u304B\u308B\u914D\u5E03\u30B5\u30A4\u30C8\u306F\u3001\u500B\u4EBA\u904B\u55B6\u306E\u3082\u306E\u304B\u3089\u6A29\u5229\u7684\u306B\u30B0\u30EC\u30FC\u306A\u3082\u306E\u307E\u3067\u69D8\u3005\u3067\u3059\u3002\u305D\u306E\u305F\u3081\u3001\u305D\u308C\u3089\u3078\u306E\u76F4\u63A5\u30EA\u30F3\u30AF\u306F\u8F09\u305B\u3066\u3044\u307E\u305B\u3093\u3002\u5229\u7528\u306E\u969B\u306F\u914D\u5E03\u5143\u3084\u6A29\u5229\u95A2\u4FC2\u3092\u3054\u81EA\u8EAB\u3067\u3054\u78BA\u8A8D\u304F\u3060\u3055\u3044\u3002</small></p>
5281
+
5282
+ <h4>5. UST\uFF08UTAU\uFF09\u306E\u6B4C\u8A5E\u3092\u4F7F\u3046</h4>
5283
+ <p>UTAU\u306EUST\u30D5\u30A1\u30A4\u30EB\u304B\u3089\u6B4C\u8A5E\u3060\u3051\u3092\u53D6\u308A\u51FA\u3057\u3066\u3001\u6B4C\u308F\u305B\u308B\u3053\u3068\u3082\u3067\u304D\u307E\u3059\u3002</p>
5284
+ <ul>
5285
+ <li>\u97F3\u7B26: UTAU\u306A\u3069\u3067UST\u3092MIDI\u306B\u66F8\u304D\u51FA\u3057\u3001\u4E0A\u306E\u624B\u9806\u3067\u8AAD\u307F\u8FBC\u307F\u307E\u3059\u3002</li>
5286
+ <li>\u6B4C\u8A5E: \u4E0B\u8A18\u30B5\u30A4\u30C8\u3067UST\u304B\u3089\u6B4C\u8A5E\u30C6\u30AD\u30B9\u30C8\u3092\u629C\u304D\u51FA\u3057\u3001MML/\u6B4C\u8A5E\u5165\u529B\u6B04\u306E <code>@@</code> \u69CB\u6587\u306B\u8CBC\u308A\u4ED8\u3051\u307E\u3059\u3002</li>
5287
+ </ul>
5288
+ <p style="margin-top:4px;"><small>\u6B4C\u8A5E\u306E\u62BD\u51FA: <a href="https://rpgen3.github.io/ust2txt/" target="_blank" rel="noopener">ust2txt</a></small></p>
5289
+ </div>
5290
+ `;
5252
5291
  var BASE_STEP_WIDTH = 0.5;
5253
5292
  var BASE_KEY_HEIGHT = 15;
5254
5293
  var TRACKS_SIMPLE = [
@@ -5407,9 +5446,11 @@ var mountDAW = (target, options = {}) => {
5407
5446
  injectStyles();
5408
5447
  const getAudioTime = options.getAudioTime ?? (() => performance.now() / 1e3);
5409
5448
  const trackConfigs = options.tracks ?? DEFAULT_TRACKS;
5449
+ const mode = options.mode ?? (trackConfigs.length > TRACKS_SIMPLE.length ? "advanced" : "simple");
5450
+ const isAdvanced = mode === "advanced";
5410
5451
  const drumPatterns = options.drumPatterns ?? DRUM_PATTERNS;
5411
5452
  const showMidi = !!options.parseMidi;
5412
- const showChord = true;
5453
+ const showChord = !isAdvanced;
5413
5454
  const refs = buildUI(target, {
5414
5455
  tracks: trackConfigs,
5415
5456
  drumPatternNames: Object.keys(drumPatterns),
@@ -6194,7 +6235,6 @@ var mountDAW = (target, options = {}) => {
6194
6235
  active.core.setVolume(active.volume);
6195
6236
  volLabel.textContent = String(active.volume);
6196
6237
  });
6197
- const isAdvanced = trackStates.length > TRACKS_SIMPLE.length;
6198
6238
  if (isAdvanced || active.config.id !== "chord") {
6199
6239
  const lyricDiv = document.createElement("div");
6200
6240
  lyricDiv.className = "dtm-row";
@@ -6402,16 +6442,16 @@ var mountDAW = (target, options = {}) => {
6402
6442
  updateUndoRedo();
6403
6443
  redrawAll();
6404
6444
  };
6405
- const setToolMode = (mode) => {
6406
- activeToolMode = mode;
6445
+ const setToolMode = (mode2) => {
6446
+ activeToolMode = mode2;
6407
6447
  for (const [btn, m] of [
6408
6448
  [refs.toolPen, "pen"],
6409
6449
  [refs.toolSelect, "select"],
6410
6450
  [refs.toolEraser, "eraser"]
6411
6451
  ]) {
6412
- btn.classList.toggle("dtm-segbtn--active", m === mode);
6452
+ btn.classList.toggle("dtm-segbtn--active", m === mode2);
6413
6453
  }
6414
- if (mode !== "select") {
6454
+ if (mode2 !== "select") {
6415
6455
  selectionRect = null;
6416
6456
  selectedNotes = [];
6417
6457
  }
@@ -6645,7 +6685,6 @@ var mountDAW = (target, options = {}) => {
6645
6685
  const applyMidiSelection = (midi, selectedIndices) => {
6646
6686
  clearAll();
6647
6687
  for (const t of trackStates) t.core.setLoadMode(true);
6648
- const isAdvanced = trackStates.length > TRACKS_SIMPLE.length;
6649
6688
  const { placements, bpm: parsedBpm } = isAdvanced ? extractMidiPlacementsByTrack(
6650
6689
  midi,
6651
6690
  selectedIndices,
@@ -6843,6 +6882,9 @@ var mountDAW = (target, options = {}) => {
6843
6882
  refs.mmlInfoBtn.addEventListener("click", () => {
6844
6883
  showModal("MML\u306E\u66F8\u304D\u65B9\u89E3\u8AAC", MML_INFO_HTML);
6845
6884
  });
6885
+ refs.midiInfoBtn.addEventListener("click", () => {
6886
+ showModal("MIDI\u306E\u8AAD\u307F\u8FBC\u307F\u89E3\u8AAC", MIDI_INFO_HTML);
6887
+ });
6846
6888
  refs.shiftApplyBtn.addEventListener(
6847
6889
  "click",
6848
6890
  () => overlayDuring(() => {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "onjmin",
3
3
  "license": "MIT",
4
4
  "name": "@onjmin/dtm",
5
- "version": "0.1.12",
5
+ "version": "0.1.13",
6
6
  "description": "MMLを中間言語に用いた、モバイルファーストなDAW / ピアノロール打ち込みコンポーネント",
7
7
  "homepage": "https://onjmin.github.io/dtm",
8
8
  "repository": {