@onjmin/dtm 0.1.13 → 0.1.15

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
@@ -38,7 +38,7 @@ studio.mountPlayer(document.getElementById("player"), daw.getMML().full);
38
38
  | モード | トラック | MIDI 取り込み | 伴奏(コード進行)UI |
39
39
  | --- | --- | --- | --- |
40
40
  | `simple` | メロディー / サブメロ / ベース / 伴奏 の 4 本 | 各トラックの特徴から役割へ**自動分類** | `chord` トラックに表示(歌詞欄の代わり) |
41
- | `advanced` | TRACK 01〜1616 | MIDI トラックを**1:1 マッピング** | なし(全トラックが通常のノート+歌詞トラック) |
41
+ | `advanced` | TRACK 01〜1515 本(フラットな連番) | MIDI トラックを**1:1 マッピング** | なし(全トラックが通常のノート+歌詞トラック) |
42
42
 
43
43
  ```ts
44
44
  import {
@@ -62,6 +62,26 @@ studio.mountEditor(editorEl, { mode: "advanced", tracks: TRACKS_ADVANCED });
62
62
  - MIDI のドラム(ch10)はピアノロールで編集できないため、取り込み時の**トラック選択 UI には出ません**。
63
63
  - `mode` / `tracks` は低レベル API の `mountDAW` でも同じく指定できます。
64
64
 
65
+ ### 備考: トラック採番と MIDI チャンネルの対応(暫定仕様)
66
+
67
+ `advanced` の `@n` / タブ名は **MML 仕様に合わせたフラットな連番**(`@0`〜`@14` / TRACK 01〜15、欠番なし)です。
68
+ 「ch10 = ドラム」という MIDI の慣習は内部モデルには持ち込まず、**MIDI 入出力の変換時にだけ**扱います。
69
+
70
+ - **出力**: レーン index → MIDI チャンネルに変換する際、打楽器ch(内部 `channel 9` = 1始まり ch10)を避けます。
71
+ 結果、TRACK 01〜09 → ch1〜9 / **TRACK 10〜15 → ch11〜16** に書き出されます(タブ番号と MIDI ch は
72
+ 10 番以降ズレますが、これは出力時の変換詳細です)。15 レーン ⇄ 15 個の非打楽器ch がちょうど 1:1 で、
73
+ チャンネル衝突は起きません。
74
+ - **入力**: `channel 9`(ドラム)のノートは取り込まず、ドラムだけのトラックは選択 UI にも出しません。
75
+ 選択したトラックは**選択順に上から**レーンへ詰めます(MIDI の実トラック番号やテンポトラックの有無に
76
+ 左右されません)。
77
+ - ドラム自体はノートレーンではなく、別系統の**ドラム設定**で編集します。
78
+
79
+ > 経緯: 当初は「タブ番号 = MIDI チャンネル番号」に揃え、ドラムの ch10 をタブの欠番にする案も検討しましたが、
80
+ > このアプリの正規フォーマットは MML(0 始まり・フラット・ドラムch非依存)であり、MIDI は境界の交換
81
+ > フォーマットに過ぎません。MIDI の慣習を内部採番に漏らすと MML の一貫性が崩れる(モード間で採番が割れる、
82
+ > 永続化される MML に欠番が残る等)ため、**内部は MML 仕様に寄せ、ch10=ドラムの面倒は変換層に閉じ込める**
83
+ > 方針に決めました。
84
+
65
85
  ## 低レベル API(`mountDAW` / 注入式)
66
86
 
67
87
  本体は音を持たない設計で、`onPlayNote` / `onPlayDrum` に自前のシンセを繋ぐ
package/dist/index.d.mts CHANGED
@@ -621,7 +621,13 @@ type DawInstance = {
621
621
 
622
622
  /** シンプルモード(4トラック)— 役割別に自動分類してMIDIを読み込む */
623
623
  declare const TRACKS_SIMPLE: TrackConfig[];
624
- /** 上級者モード(16トラック)— MIDIトラックを1:1で扱う */
624
+ /**
625
+ * advancedモード(15トラック)— MIDIトラックを1:1で扱う。
626
+ * 採番はMML仕様に合わせてフラットな連番(@0〜@14 / TRACK 01〜15、欠番なし)。
627
+ * MIDIの「ch10=ドラム」の慣習は内部モデルに持ち込まず、MIDI入出力の変換時にだけ扱う:
628
+ * 出力は打楽器ch(内部 channel 9)を避けて割り当て(TRACK 10以降は ch11〜16 へ)、
629
+ * 入力は channel 9 のドラムを除外する。ドラム自体は別系統の「ドラム設定」で編集する。
630
+ */
625
631
  declare const TRACKS_ADVANCED: TrackConfig[];
626
632
  /**
627
633
  * DAWコンポーネントをマウントする。
@@ -861,8 +867,13 @@ declare const getMidiBPM: (midi: unknown) => number;
861
867
  */
862
868
  declare const extractMidiPlacements: (midi: unknown, selectedTrackIndices: number[]) => MidiExtraction;
863
869
  /**
864
- * 上級者モード用:MIDIトラックインデックス N DAW トラック trackIds[N] へ直接マッピング。
865
- * 自動分類なし。選択された MIDI トラック K のノートは DAW トラック K に入る。
870
+ * advancedモード用:選択された MIDI トラックを選択順に DAW トラックへ上から詰める
871
+ * (k番目に選んだトラック trackIds[k])。自動分類なし。
872
+ *
873
+ * MIDIの実トラック番号ではなく「選択順の位置」で割り当てるため、先頭のテンポ/コンダクタ
874
+ * トラックや、空・ドラムだけのトラックが混ざっていても DAW レーンがずれない
875
+ * (これらは選択リストに出ない/選ばれないので位置を消費しない)。
876
+ * ドラム(ch10 = channel 9)のノートはスキップする。
866
877
  */
867
878
  declare const extractMidiPlacementsByTrack: (midi: unknown, selectedIndices: number[], trackIds: string[]) => MidiExtraction;
868
879
  type ExportMidiOptions = {
package/dist/index.d.ts CHANGED
@@ -621,7 +621,13 @@ type DawInstance = {
621
621
 
622
622
  /** シンプルモード(4トラック)— 役割別に自動分類してMIDIを読み込む */
623
623
  declare const TRACKS_SIMPLE: TrackConfig[];
624
- /** 上級者モード(16トラック)— MIDIトラックを1:1で扱う */
624
+ /**
625
+ * advancedモード(15トラック)— MIDIトラックを1:1で扱う。
626
+ * 採番はMML仕様に合わせてフラットな連番(@0〜@14 / TRACK 01〜15、欠番なし)。
627
+ * MIDIの「ch10=ドラム」の慣習は内部モデルに持ち込まず、MIDI入出力の変換時にだけ扱う:
628
+ * 出力は打楽器ch(内部 channel 9)を避けて割り当て(TRACK 10以降は ch11〜16 へ)、
629
+ * 入力は channel 9 のドラムを除外する。ドラム自体は別系統の「ドラム設定」で編集する。
630
+ */
625
631
  declare const TRACKS_ADVANCED: TrackConfig[];
626
632
  /**
627
633
  * DAWコンポーネントをマウントする。
@@ -861,8 +867,13 @@ declare const getMidiBPM: (midi: unknown) => number;
861
867
  */
862
868
  declare const extractMidiPlacements: (midi: unknown, selectedTrackIndices: number[]) => MidiExtraction;
863
869
  /**
864
- * 上級者モード用:MIDIトラックインデックス N DAW トラック trackIds[N] へ直接マッピング。
865
- * 自動分類なし。選択された MIDI トラック K のノートは DAW トラック K に入る。
870
+ * advancedモード用:選択された MIDI トラックを選択順に DAW トラックへ上から詰める
871
+ * (k番目に選んだトラック trackIds[k])。自動分類なし。
872
+ *
873
+ * MIDIの実トラック番号ではなく「選択順の位置」で割り当てるため、先頭のテンポ/コンダクタ
874
+ * トラックや、空・ドラムだけのトラックが混ざっていても DAW レーンがずれない
875
+ * (これらは選択リストに出ない/選ばれないので位置を消費しない)。
876
+ * ドラム(ch10 = channel 9)のノートはスキップする。
866
877
  */
867
878
  declare const extractMidiPlacementsByTrack: (midi: unknown, selectedIndices: number[], trackIds: string[]) => MidiExtraction;
868
879
  type ExportMidiOptions = {
package/dist/index.js CHANGED
@@ -3077,13 +3077,11 @@ var extractMidiPlacementsByTrack = (midi, selectedIndices, trackIds) => {
3077
3077
  const bpm = getMidiBPM(midi);
3078
3078
  const ticksPerStep = ticksPerBeat / STEPS_PER_BEAT;
3079
3079
  const placements = [];
3080
- const selectedSet = new Set(selectedIndices);
3081
- for (let midiIdx = 0; midiIdx < track.length; midiIdx++) {
3082
- if (!selectedSet.has(midiIdx)) continue;
3083
- if (midiIdx >= trackIds.length) continue;
3084
- const trackId = trackIds[midiIdx];
3080
+ selectedIndices.forEach((midiIdx, lane) => {
3081
+ if (lane >= trackIds.length) return;
3085
3082
  const trackData = track[midiIdx];
3086
- if (!trackData) continue;
3083
+ if (!trackData) return;
3084
+ const trackId = trackIds[lane];
3087
3085
  const active = [];
3088
3086
  let currentTime = 0;
3089
3087
  for (const event of trackData.event) {
@@ -3118,7 +3116,7 @@ var extractMidiPlacementsByTrack = (midi, selectedIndices, trackIds) => {
3118
3116
  velocity: note.velocity
3119
3117
  });
3120
3118
  }
3121
- }
3119
+ });
3122
3120
  return { placements, bpm };
3123
3121
  };
3124
3122
  var to2byte = (n) => [(n & 65280) >> 8, n & 255];
@@ -3159,6 +3157,7 @@ var exportMIDI = (options) => {
3159
3157
  const midiTracks = [];
3160
3158
  tracks.forEach((track, ch) => {
3161
3159
  if (track.notes.length === 0) return;
3160
+ const channel = ch < 9 ? ch : ch + 1 & 15;
3162
3161
  const events = [];
3163
3162
  for (const n of track.notes) {
3164
3163
  const startTick = Math.round(n.startStep * tickPerStep);
@@ -3168,8 +3167,8 @@ var exportMIDI = (options) => {
3168
3167
  const vel = Math.round(
3169
3168
  (n.velocity ?? DEFAULT_VELOCITY) * (track.volume ?? 100) / 100
3170
3169
  );
3171
- events.push({ t: startTick, m: [144 | ch & 15, n.pitch, vel] });
3172
- events.push({ t: endTick, m: [144 | ch & 15, n.pitch, 0] });
3170
+ events.push({ t: startTick, m: [144 | channel, n.pitch, vel] });
3171
+ events.push({ t: endTick, m: [144 | channel, n.pitch, 0] });
3173
3172
  }
3174
3173
  events.sort((a, b) => a.t - b.t);
3175
3174
  midiTracks.push(events);
@@ -5530,13 +5529,6 @@ var TRACKS_ADVANCED = [
5530
5529
  color: [100, 255, 160],
5531
5530
  instrument: 14,
5532
5531
  volume: 100
5533
- },
5534
- {
5535
- id: "t15",
5536
- name: "TRACK 16",
5537
- color: [255, 150, 200],
5538
- instrument: 15,
5539
- volume: 100
5540
5532
  }
5541
5533
  ];
5542
5534
  var DEFAULT_TRACKS = TRACKS_SIMPLE;
package/dist/index.mjs CHANGED
@@ -2972,13 +2972,11 @@ var extractMidiPlacementsByTrack = (midi, selectedIndices, trackIds) => {
2972
2972
  const bpm = getMidiBPM(midi);
2973
2973
  const ticksPerStep = ticksPerBeat / STEPS_PER_BEAT;
2974
2974
  const placements = [];
2975
- const selectedSet = new Set(selectedIndices);
2976
- for (let midiIdx = 0; midiIdx < track.length; midiIdx++) {
2977
- if (!selectedSet.has(midiIdx)) continue;
2978
- if (midiIdx >= trackIds.length) continue;
2979
- const trackId = trackIds[midiIdx];
2975
+ selectedIndices.forEach((midiIdx, lane) => {
2976
+ if (lane >= trackIds.length) return;
2980
2977
  const trackData = track[midiIdx];
2981
- if (!trackData) continue;
2978
+ if (!trackData) return;
2979
+ const trackId = trackIds[lane];
2982
2980
  const active = [];
2983
2981
  let currentTime = 0;
2984
2982
  for (const event of trackData.event) {
@@ -3013,7 +3011,7 @@ var extractMidiPlacementsByTrack = (midi, selectedIndices, trackIds) => {
3013
3011
  velocity: note.velocity
3014
3012
  });
3015
3013
  }
3016
- }
3014
+ });
3017
3015
  return { placements, bpm };
3018
3016
  };
3019
3017
  var to2byte = (n) => [(n & 65280) >> 8, n & 255];
@@ -3054,6 +3052,7 @@ var exportMIDI = (options) => {
3054
3052
  const midiTracks = [];
3055
3053
  tracks.forEach((track, ch) => {
3056
3054
  if (track.notes.length === 0) return;
3055
+ const channel = ch < 9 ? ch : ch + 1 & 15;
3057
3056
  const events = [];
3058
3057
  for (const n of track.notes) {
3059
3058
  const startTick = Math.round(n.startStep * tickPerStep);
@@ -3063,8 +3062,8 @@ var exportMIDI = (options) => {
3063
3062
  const vel = Math.round(
3064
3063
  (n.velocity ?? DEFAULT_VELOCITY) * (track.volume ?? 100) / 100
3065
3064
  );
3066
- events.push({ t: startTick, m: [144 | ch & 15, n.pitch, vel] });
3067
- events.push({ t: endTick, m: [144 | ch & 15, n.pitch, 0] });
3065
+ events.push({ t: startTick, m: [144 | channel, n.pitch, vel] });
3066
+ events.push({ t: endTick, m: [144 | channel, n.pitch, 0] });
3068
3067
  }
3069
3068
  events.sort((a, b) => a.t - b.t);
3070
3069
  midiTracks.push(events);
@@ -5425,13 +5424,6 @@ var TRACKS_ADVANCED = [
5425
5424
  color: [100, 255, 160],
5426
5425
  instrument: 14,
5427
5426
  volume: 100
5428
- },
5429
- {
5430
- id: "t15",
5431
- name: "TRACK 16",
5432
- color: [255, 150, 200],
5433
- instrument: 15,
5434
- volume: 100
5435
5427
  }
5436
5428
  ];
5437
5429
  var DEFAULT_TRACKS = TRACKS_SIMPLE;
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.13",
5
+ "version": "0.1.15",
6
6
  "description": "MMLを中間言語に用いた、モバイルファーストなDAW / ピアノロール打ち込みコンポーネント",
7
7
  "homepage": "https://onjmin.github.io/dtm",
8
8
  "repository": {
@@ -53,6 +53,7 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@onjmin/chord-parser": "1.0.2",
56
+ "@onjmin/dtm": "0.1.14",
56
57
  "@onjmin/koe": "1.0.3"
57
58
  },
58
59
  "scripts": {