@onjmin/dtm 1.0.8 → 2.0.3

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.ts CHANGED
@@ -57,6 +57,151 @@ type ChordPlayerInstance = {
57
57
  */
58
58
  declare const mountChordPlayer: (target: HTMLElement, chords: string, options?: MountChordPlayerOptions) => ChordPlayerInstance;
59
59
 
60
+ /**
61
+ * 音律(12平均律 / 31平均律)と、ピッチの内部表現。
62
+ *
63
+ * ## 単位
64
+ *
65
+ * ノートのピッチは **1/372オクターブの整数** で持つ。372 = 12 × 31 で、12と31は
66
+ * 互いに素なので最小公倍数がこれになり、**12平均律と31平均律の両方が誤差ゼロで
67
+ * 同じ数直線に乗る**。
68
+ *
69
+ * 12平均律 1半音 = 31 units
70
+ * 31平均律 1度 = 12 units
71
+ * 1 unit = 1200/372 ≒ 3.2258 セント
72
+ *
73
+ * 整数のままなので `a.pitchUnits === b.pitchUnits` の同値判定が全部生き残る
74
+ * (重複判定・当たり判定・協調編集の (startStep, pitchUnits) キー)。小数にすると
75
+ * ここが軒並み壊れるため、細かい整数単位を選んでいる。
76
+ *
77
+ * ## 音律は音声経路に入らない
78
+ *
79
+ * ピッチが絶対値なので、シーケンサも発音器も音律を知らなくてよい。音律は
80
+ * 「格子・記譜・表示」だけに効く編集上の概念で、`RenderConfig.edo` に置く。
81
+ */
82
+ /**
83
+ * ピッチの単位を型で区別するためのブランド。
84
+ *
85
+ * `Units` と `MidiNote` はどちらも実体は number だが、互いに代入できない。
86
+ * これは「半音の数値を units のつもりで使う」「units を SoundFont の
87
+ * MIDIノート番号として渡す」といった取り違えを**コンパイラに検出させる**ため。
88
+ * 単位の取り違えは型が同じ number である限り一切検出できず、実際に
89
+ * 「楽器音が無音」「オクターブユニゾンが0.4半音ずれる」「多音階音源のサンプル
90
+ * 選択が常に最高音になる」といった不具合を作り込んだ。
91
+ *
92
+ * 生の number から作るときは {@link units} / {@link midiNote} を通す。
93
+ * 変換は {@link midiToUnits} / {@link unitsToMidi} など、この module の関数に集約する。
94
+ */
95
+ declare const UNITS_BRAND: unique symbol;
96
+ declare const MIDI_BRAND: unique symbol;
97
+ /** ピッチ。1/372オクターブの整数。 */
98
+ type Units = number & {
99
+ readonly [UNITS_BRAND]: true;
100
+ };
101
+ /** MIDIノート番号(半音)。0-127。SoundFont のゾーン選択やMIDI入出力で使う。 */
102
+ type MidiNote = number & {
103
+ readonly [MIDI_BRAND]: true;
104
+ };
105
+ /** 生の数値を units として扱う。単位が units であると確信できる箇所だけで使う。 */
106
+ declare const units: (n: number) => Units;
107
+ /** 生の数値をMIDIノート番号として扱う。MIDI入出力の境界だけで使う。 */
108
+ declare const midiNote: (n: number) => MidiNote;
109
+ /** units 同士・units と生の差分の加算。結果も units。 */
110
+ declare const addUnits: (a: Units, delta: number) => Units;
111
+ /** 1オクターブあたりの units。12 × 31。 */
112
+ declare const UNITS_PER_OCTAVE = 372;
113
+ /** 12平均律の1半音あたりの units。 */
114
+ declare const UNITS_PER_SEMITONE: number;
115
+ /** 31平均律の1度あたりの units。 */
116
+ declare const UNITS_PER_EDO31_DEGREE: number;
117
+ /** 1 unit のセント値。 */
118
+ declare const CENTS_PER_UNIT: number;
119
+ /** A4 (MIDI 69) の units。周波数計算の基準。 */
120
+ declare const A4_UNITS: Units;
121
+ /** A4 の周波数(Hz)。 */
122
+ declare const A4_HZ = 440;
123
+ /** 対応する音律(1オクターブの分割数)。 */
124
+ type Edo = 12 | 31;
125
+ /** 既定の音律。宣言のない曲はすべてこれ(=既存データは素通り)。 */
126
+ declare const DEFAULT_EDO: Edo;
127
+ /** その音律の1格子ステップが何 units か。 */
128
+ declare const unitsPerStep: (edo: Edo) => number;
129
+ /** MIDIノート番号 → units。 */
130
+ declare const midiToUnits: (midi: MidiNote | number) => Units;
131
+ /**
132
+ * units → MIDIノート番号(小数)。
133
+ * 歌声合成(koe)は Hz を受けるためこの小数値をそのまま渡してよい。
134
+ * SoundFont のように整数ゾーンしか持たない発音器は {@link unitsToMidiDetune} を使う。
135
+ */
136
+ declare const unitsToMidi: (u: Units) => number;
137
+ /** units → 周波数(Hz)。 */
138
+ declare const unitsToHz: (u: Units) => number;
139
+ /**
140
+ * units → 「最寄りの整数MIDIノート番号 + セント補正」。
141
+ *
142
+ * SoundFont は音高ごとに整数キーでゾーンを持つため小数ピッチを直接鳴らせない。
143
+ * 最寄りのゾーンを鳴らして残差を `AudioBufferSourceNode.detune` で補正する。
144
+ * 31平均律での残差は最大 ±48.4 セントで、detune の可動域に十分収まる。
145
+ */
146
+ declare const unitsToMidiDetune: (u: Units) => {
147
+ midi: MidiNote;
148
+ detuneCents: number;
149
+ };
150
+ /**
151
+ * 臨時記号1つあたりの格子ステップ数。
152
+ *
153
+ * - `#` / `+`(12平均律) … クロマチック半音上げ
154
+ * - `-` … クロマチック半音下げ
155
+ * - `+`(31平均律) … 格子1ステップ上げ(微分音)
156
+ * - `_` … 格子1ステップ下げ(微分音)
157
+ *
158
+ * 12平均律ではクロマチック半音=1格子ステップなので4記号すべてが従来の意味に潰れ、
159
+ * 既存MMLの解釈は1文字も変わらない。31平均律でのみ `#`/`-`(±2度)と
160
+ * `+`/`_`(±1度)が分岐する。
161
+ */
162
+ declare const chromaticStep: (edo: Edo) => number;
163
+ /** 微分音記号 `+` / `_` 1つあたりの格子ステップ数。常に1。 */
164
+ declare const MICRO_STEP = 1;
165
+ /** 幹音の文字か。 */
166
+ declare const isNaturalLetter: (ch: string) => boolean;
167
+ /** 幹音の文字 → オクターブ内の格子ステップ。未知の文字は null。 */
168
+ declare const naturalStep: (ch: string, edo: Edo) => number | null;
169
+ /**
170
+ * 音名・オクターブ・臨時記号から units を組み立てる。
171
+ *
172
+ * `octave` はMMLの `o` 指定(MIDI慣習で o4 の c が中央ド = MIDI 60)。
173
+ * 臨時記号でオクターブを跨ぐ綴り(`b##` が次オクターブへ、`c--` が前オクターブへ)も
174
+ * そのまま加算されるので、度数を 0〜edo-1 にクランプしてはいけない。
175
+ */
176
+ declare const spellingToUnits: (letter: string, octave: number, chromatic: number, micro: number, edo: Edo) => number | null;
177
+ /**
178
+ * 五度圏インデックス(C=0, G=1, F=-1, C#=7, Db=-5)→ オクターブ内の格子ステップ。
179
+ *
180
+ * ミーントーン系の音律はすべて「五度を何ステップとするか」だけで決まるため、
181
+ * 綴りを持つ音(chord-parser の `rootFifth` / `noteFifths` など)はこの一本で
182
+ * どちらの音律へも正確に写せる。12平均律では C# と Db が同じ値に潰れ、
183
+ * 31平均律では 2 と 3 に分かれる。
184
+ */
185
+ declare const fifthToStep: (fifthIndex: number, edo: Edo) => number;
186
+ /** 五度圏インデックス → オクターブ内の units。 */
187
+ declare const fifthToUnits: (fifthIndex: number, edo: Edo) => number;
188
+ /**
189
+ * ピッチ表現のバージョン。
190
+ *
191
+ * - v1 … `pitch` が半音(MIDIノート番号)。dtm 1.x
192
+ * - v2 … `pitchUnits` が 1/372オクターブ単位。dtm 2.x
193
+ *
194
+ * dtm 自身は通信路を持たず `onNotesPatch` / `applyPatch` のフックを出すだけなので、
195
+ * バージョンの突き合わせは利用側アプリのハンドシェイクの責務になる。変換の知識だけを
196
+ * ここに置く。v1→v2 は無損失だが、**v2→v1 は12平均律の曲でしか成立しない**
197
+ * (31平均律を半音へ丸めると最大48.4セント動く)。
198
+ */
199
+ declare const PITCH_ENCODING_VERSION = 2;
200
+ /** v1(半音)→ v2(units)。無損失。 */
201
+ declare const pitchV1ToUnits: (pitch: number) => Units;
202
+ /** v2(units)→ v1(半音)。12平均律の曲でのみ無損失。 */
203
+ declare const unitsToPitchV1: (u: Units) => number;
204
+
60
205
  /**
61
206
  * コード進行文字列を伴奏トラックのノート配置へ展開する。
62
207
  *
@@ -64,24 +209,28 @@ declare const mountChordPlayer: (target: HTMLElement, chords: string, options?:
64
209
  * 旧 demo/index.html の applyChordProgression を移植・整理し、
65
210
  * 実際のノート追加を行わず配置(placement)の配列を返す純関数にした。
66
211
  */
212
+
67
213
  type ChordPatternType = "block" | "arpeggio" | "arpeggio-fast" | "offbeat" | "yatsume" | "alternating";
68
214
  type ChordPlacement = {
69
215
  startStep: number;
70
- pitch: number;
216
+ /**
217
+ * 1/372オクターブ単位。chord-parser が返すのは12平均律の半音なので、
218
+ * ここへ入れる時点で音律に応じた格子へ写している。
219
+ */
220
+ pitchUnits: Units;
71
221
  durationSteps: number;
72
222
  velocity: number;
73
223
  };
74
224
  type ApplyChordOptions = {
75
225
  chordStr: string;
226
+ /** 曲の音律(1オクターブの分割数)。省略時は12平均律。 */
227
+ edo?: number;
76
228
  patternType: ChordPatternType;
77
229
  /** ルートのセミトーンシフト(0-11) */
78
230
  rootShift: number;
79
231
  bpm: number;
80
232
  stepsPerBar: number;
81
233
  };
82
- /**
83
- * コード進行 → 伴奏ノート配置。
84
- */
85
234
  declare const buildChordPlacements: (options: ApplyChordOptions) => ChordPlacement[];
86
235
 
87
236
  type SongDrumInstruction = {
@@ -412,8 +561,11 @@ declare const createKoeVoice: (ctx: AudioContext, destination: AudioNode, option
412
561
  /** ストリーミング再生する歌唱ノート1つ(絶対時刻ベース)。 */
413
562
  type StreamVoiceNote = {
414
563
  syllable: LyricSyllable;
415
- /** MIDIノート番号 */
416
- pitch: number;
564
+ /**
565
+ * ピッチ。単位は units(1/372オクターブ)。koe は Hz を受けるので、
566
+ * ここから直接 Hz へ変換して歌わせる(整数MIDIノートに丸めない)。
567
+ */
568
+ pitch: Units;
417
569
  /** アンカー(再生開始時刻)からの相対秒。実発音時刻 = anchorTime + startSec。 */
418
570
  startSec: number;
419
571
  /** ゲート適用済みの発音長(秒)。 */
@@ -650,19 +802,55 @@ declare const DEFAULT_VELOCITY = 100;
650
802
  declare const DEFAULT_PLAYBACK_VELOCITY = 127;
651
803
  declare const DEFAULT_STEPS_PER_BAR = 192;
652
804
  declare const MML_END_MARKER = "#end;";
805
+ /**
806
+ * ピアノロールが扱う音域の下端・上端(両端含む)。音律に依らず固定で、MIDI 0-127 に相当する。
807
+ * 「音律を変えても鳴らせる音の高さの範囲は変わらない」を保証するための不変条件。
808
+ */
809
+ declare const PITCH_RANGE_START = 0;
810
+ /** MIDI 127 相当。単位は 1/372オクターブ(127 × 31)。 */
811
+ declare const PITCH_RANGE_END = 3937;
812
+ /**
813
+ * 1行が受け持つピッチ幅(units)。12平均律は1半音 = 31、31平均律は1度 = 12。
814
+ * 行数はここから導出されるので、12平均律で128行・31平均律で328行になる。
815
+ */
816
+ declare const unitsPerRow: (edo: number) => number;
817
+ /** その音律での行数。音域と1行あたりのピッチ幅から導出する(直接指定しないこと)。 */
818
+ declare const keyCountFor: (edo: number) => number;
819
+ /** 12平均律の行数(従来と同じ128)。 */
820
+ declare const KEY_COUNT: number;
653
821
  type Note = {
654
822
  id: number;
655
823
  startStep: number;
656
824
  durationSteps: number;
657
- pitch: number;
825
+ /**
826
+ * ピッチ。単位は **1/372オクターブの整数**(`tuning.ts` 参照)。
827
+ * 12平均律の1半音 = 31、31平均律の1度 = 12。MIDIノート番号ではないので注意。
828
+ * dtm 1.x の `pitch`(半音)から意味が変わっている。
829
+ */
830
+ pitchUnits: Units;
658
831
  velocity?: number;
659
832
  };
660
833
  type RenderConfig = {
661
834
  stepsPerBar: number;
835
+ /**
836
+ * 行数。{@link KEY_COUNT} のように「音域 ÷ 1行あたりのピッチ幅」から導出した値を渡す。
837
+ * 音律ごとに直接指定しないこと(31平均律で音域が勝手に縮む)。
838
+ */
662
839
  keyCount: number;
840
+ /** 音域の下端。単位は units(1/372オクターブ)。 */
663
841
  pitchRangeStart: number;
842
+ /** 1行が受け持つ units。{@link unitsPerRow} から導出した値を渡す。省略時は31(12平均律)。 */
843
+ unitsPerRow?: number;
664
844
  keyHeight: number;
665
845
  stepWidth: number;
846
+ /**
847
+ * 曲全体の音律(1オクターブの分割数)。省略時は12(12平均律)。
848
+ *
849
+ * 音律はデータにも音声経路にも入らず、格子・記譜・表示だけに効く編集上の概念なので、
850
+ * 描画設定と同じ場所に置く。MMLCore も `getConfig()` 経由でここから音律を読み、
851
+ * 綴り(`#`=2度 / `+`=1度 など)を切り替える。
852
+ */
853
+ edo?: number;
666
854
  };
667
855
  type CoreEventHandlers = {
668
856
  onMMLGenerated: (mml: string) => void;
@@ -693,14 +881,16 @@ type LyricSyncData = {
693
881
  /** パッチ送受信用ノートデータ(ローカルIDを持たない)。 */
694
882
  type NoteData = {
695
883
  startStep: number;
696
- pitch: number;
884
+ /** 1/372オクターブ単位。{@link Note.pitchUnits} と同じ。 */
885
+ pitchUnits: Units;
697
886
  durationSteps: number;
698
887
  velocity?: number;
699
888
  };
700
- /** パッチ削除指定(startStep + pitch で音符を特定)。 */
889
+ /** パッチ削除指定(startStep + pitchUnits で音符を特定)。 */
701
890
  type NoteRemove = {
702
891
  startStep: number;
703
- pitch: number;
892
+ /** 1/372オクターブ単位。{@link Note.pitchUnits} と同じ。 */
893
+ pitchUnits: Units;
704
894
  };
705
895
  type PianoRollOptions = {
706
896
  mountTarget: HTMLElement;
@@ -740,7 +930,13 @@ type TrackConfig = {
740
930
  };
741
931
  type PlayNoteEvent = {
742
932
  trackId: string;
743
- pitch: number;
933
+ /**
934
+ * ピッチ。単位は 1/372オクターブの整数({@link Note.pitchUnits} と同じ)。
935
+ * 周波数へは `tuning.ts` の `unitsToHz`、SoundFont のような整数ゾーンの音源へは
936
+ * `unitsToMidiDetune` を使う。{@link PlayDrumEvent.pitch} はGM打楽器のキー番号で
937
+ * 音高ではないため、こちらとは別物。
938
+ */
939
+ pitchUnits: Units;
744
940
  /** 元ノートのvelocity (0-127) */
745
941
  velocity: number;
746
942
  /** トラックvolume×velocityを反映した 0-1 程度の音量係数 */
@@ -822,7 +1018,7 @@ type LyricTrack = {
822
1018
  */
823
1019
  pan: number;
824
1020
  /**
825
- * オクターブシフト -2〜+2(半音換算で octave×12 だけ歌唱ピッチを上下する)。既定0。
1021
+ * オクターブシフト -2〜+2octave×372 units = octave オクターブぶん歌唱ピッチを上下する)。既定0。
826
1022
  * 音源ごとに得意な音域が異なるため、演奏ノート(@n)のピッチをそのまま使わず
827
1023
  * オクターブ単位でずらして歌わせるための合成専用パラメータ。
828
1024
  * MMLでは `@@n klatt o-1 …` のように o トークンで付与する。
@@ -1195,11 +1391,12 @@ type DawInstance = {
1195
1391
  */
1196
1392
  setTrackAudible: (trackId: string, audible: boolean) => void;
1197
1393
  /**
1198
- * 指定ノート位置(step, pitch)のキャンバス上のピクセル座標を返す。
1394
+ * 指定ノート位置(step, pitchUnits)のキャンバス上のピクセル座標を返す。
1395
+ * `pitch` の単位は units(1/372オクターブ)。
1199
1396
  * 画面外の場合は onScreen=false と方角 side を返す。
1200
1397
  * 協力DAWでのカーソル表示に使う。
1201
1398
  */
1202
- noteToCanvas: (step: number, pitch: number) => {
1399
+ noteToCanvas: (step: number, pitch: Units) => {
1203
1400
  x: number;
1204
1401
  y: number;
1205
1402
  onScreen: boolean;
@@ -1353,7 +1550,8 @@ declare const playPlacements: (placements: Array<{
1353
1550
  trackIndex: number;
1354
1551
  startStep: number;
1355
1552
  durationSteps: number;
1356
- pitch: number;
1553
+ /** ピッチ。単位は units(1/372オクターブ)。 */
1554
+ pitchUnits: Units;
1357
1555
  velocity: number;
1358
1556
  }>, options: PlayPlacementsOptions) => MmlPlayback;
1359
1557
  /**
@@ -1364,7 +1562,7 @@ declare const playMML: (mml: string, options?: PlayMmlOptions) => MmlPlayback;
1364
1562
  type PlayNoteOptions = {
1365
1563
  audioContext?: AudioContext;
1366
1564
  destination?: AudioNode;
1367
- pitch: number;
1565
+ pitchUnits: Units;
1368
1566
  volume?: number;
1369
1567
  duration?: number;
1370
1568
  };
@@ -1475,6 +1673,15 @@ declare class LinkedList<T> {
1475
1673
  }
1476
1674
 
1477
1675
  declare const PITCH_MAP: string[];
1676
+ /**
1677
+ * 31平均律の綴り表(度数0〜30)。
1678
+ *
1679
+ * 五度連鎖の伝統的綴りを基本にしつつ、重複臨時記号(`##`/`--`)を要する度数だけ
1680
+ * 微分音記号(`+`/`_`)の短縮形を採る。結果として全31度が2文字以内に収まる。
1681
+ * どの綴りもオクターブを跨がないものを選んであるので、`o<n>` の直後に置ける
1682
+ * (たとえば29度は `c-` ではなく `b+`。`c-` はCの2度下=前オクターブになってしまう)。
1683
+ */
1684
+ declare const EDO31_NAMES: string[];
1478
1685
  /**
1479
1686
  * ノートデータ管理とMML生成の責務を持つDOM非依存のコアロジック
1480
1687
  */
@@ -1491,7 +1698,9 @@ declare class MMLCore {
1491
1698
  private lastUndoTime;
1492
1699
  private static readonly UNDO_DEBOUNCE_MS;
1493
1700
  private toolMode;
1494
- constructor(handlers: CoreEventHandlers, volume?: number);
1701
+ /** グリッド寸法の供給元(描画器ではなく呼び出し側が持つ設定を読む) */
1702
+ private getConfig;
1703
+ constructor(handlers: CoreEventHandlers, volume: number | undefined, getConfig: () => RenderConfig);
1495
1704
  beginBatch(): void;
1496
1705
  endBatch(): void;
1497
1706
  saveHistory(): void;
@@ -1512,10 +1721,10 @@ declare class MMLCore {
1512
1721
  * @param pitch ピッチ番号
1513
1722
  * @param options ノート長などの設定
1514
1723
  */
1515
- addNote(step: number, pitch: number, options: AddNoteOptions): void;
1724
+ addNote(step: number, pitch: Units, options: AddNoteOptions): void;
1516
1725
  deleteNoteById(noteId: number): void;
1517
1726
  private getMaxStep;
1518
- moveNote(noteId: number, startStep: number, pitch: number): void;
1727
+ moveNote(noteId: number, startStep: number, pitch: Units): void;
1519
1728
  moveNoteEnd(_: number): void;
1520
1729
  resizeNote(noteId: number, durationSteps: number): void;
1521
1730
  resizeNoteEnd(_: number): void;
@@ -1533,6 +1742,8 @@ declare class MMLCore {
1533
1742
  * ギャップに収まる最大の音符を探す(減算アルゴリズム用)
1534
1743
  */
1535
1744
  private findBestFitDuration;
1745
+ /** ピッチ(units) → その音律での「オクターブ番号」と「音名」。 */
1746
+ private spell;
1536
1747
  /**
1537
1748
  * ピッチからオクターブ最適化のある音名を取得
1538
1749
  */
@@ -1577,13 +1788,12 @@ declare const isChordHeavyTrack: (notes: Note[], threshold?: number) => boolean;
1577
1788
  * applyMonophonicMacro / shiftAllNotes を移植・整理したもの。
1578
1789
  */
1579
1790
 
1580
- /**
1581
- * アクティブトラックにスケールに沿ったランダムなノートを8小節分配置する。
1582
- */
1583
1791
  declare const generateRandomPattern: (core: MMLCore, options: {
1584
1792
  stepsPerBar: number;
1585
1793
  startStep: number;
1586
1794
  pitchRangeStart: number;
1795
+ /** 曲の音律。省略時は12平均律。 */
1796
+ edo?: number;
1587
1797
  }) => void;
1588
1798
  /**
1589
1799
  * 半小節ごとに伴奏トラックの構成音(pitch class)に合致しない音を削除する。
@@ -1602,11 +1812,16 @@ declare const applyMonophonic: (targetCore: MMLCore, chordCore: MMLCore, options
1602
1812
  */
1603
1813
  declare const shiftNotes: (cores: MMLCore[], shiftSteps: number) => void;
1604
1814
  /**
1605
- * 全トラックのノートを一括で移調する(半音単位)。歌唱ピッチもノート由来なので、
1606
- * 歌詞トラックの歌声も一緒に移調される。MIDI範囲(0-127)を超える場合はクランプする
1607
- * (音域外に飛んで無音・破綻するのを防ぐ)。
1815
+ * 全トラックのノートを一括で移調する。歌唱ピッチもノート由来なので、歌詞トラックの
1816
+ * 歌声も一緒に移調される。音域({@link PITCH_RANGE_START}〜{@link PITCH_RANGE_END})を
1817
+ * 超える場合はクランプする(音域外に飛んで無音・破綻するのを防ぐ)。
1818
+ *
1819
+ * 単位は「半音」ではなく**格子1ステップ**。12平均律では1ステップ=1半音だが、
1820
+ * 31平均律では1ステップ=1度(≒38.7セント)になる。31平均律で「半音」は
1821
+ * クロマチック半音(2度)とダイアトニック半音(3度)に分岐して一意に定まらないため、
1822
+ * 画面の「移調」操作と同じ格子基準に揃えてある。
1608
1823
  */
1609
- declare const transposeNotes: (cores: MMLCore[], semitones: number) => void;
1824
+ declare const transposeNotes: (cores: MMLCore[], steps: number) => void;
1610
1825
 
1611
1826
  type MidiTrackAnalysis = {
1612
1827
  index: number;
@@ -1752,6 +1967,11 @@ type MmlMeta = {
1752
1967
  fadeOut?: number;
1753
1968
  /** DAWの動作モード(simple | advanced) */
1754
1969
  mode?: "simple" | "advanced";
1970
+ /**
1971
+ * 曲全体の音律(1オクターブの分割数)。`#edo=31` で埋め込む。省略時は12(12平均律)。
1972
+ * 12と31のみ対応。音律は曲単位で、トラックや小節では変えられない。
1973
+ */
1974
+ edo?: number;
1755
1975
  /**
1756
1976
  * トラックごとの個別楽器名(GM楽器名)。`#t<n>inst=<名前>` で埋め込む。
1757
1977
  * 省略されたトラックはプリセットが適用される。
@@ -1801,7 +2021,8 @@ type MMLNotePlacement = {
1801
2021
  /** 0:melody 1:submelody 2:bass 3:chord */
1802
2022
  trackIndex: number;
1803
2023
  startStep: number;
1804
- pitch: number;
2024
+ /** 1/372オクターブ単位({@link Note.pitchUnits} と同じ)。 */
2025
+ pitchUnits: Units;
1805
2026
  durationSteps: number;
1806
2027
  /** v コマンドで指定されたベロシティ(0-127、既定100) */
1807
2028
  velocity: number;
@@ -1961,87 +2182,55 @@ type PianoRollInstance = {
1961
2182
  };
1962
2183
  declare const createPianoRoll: (options: PianoRollOptions, handlers: CoreEventHandlers) => PianoRollInstance;
1963
2184
 
1964
- declare const getRenderConfig: () => RenderConfig;
1965
2185
  /**
1966
- * カスタム背景画像の有無を設定します。
1967
- * 有効時はグリッド/ヘッダーの塗りつぶしを半透明にし、背景を透過させます。
1968
- */
1969
- declare const setBackgroundActive: (active: boolean) => void;
1970
- declare const getDrawOffset: () => {
1971
- x: number;
1972
- y: number;
1973
- };
1974
- declare const getGridCanvas: () => HTMLCanvasElement;
1975
- declare const getGridContext: () => CanvasRenderingContext2D;
1976
- declare const getHeaderCanvas: () => HTMLCanvasElement;
1977
- /**
1978
- * Canvasを初期化し、指定されたターゲット要素にマウントします。
1979
- * ヘッダー用、鍵盤用、ノート用の3つのCanvasを作成します。
1980
- */
1981
- declare const init: (mountTarget: HTMLElement, width: number | undefined, height: number | undefined, config: RenderConfig) => void;
1982
- /**
1983
- * 鍵盤を描画します。
1984
- * - 白鍵: クリーム色、全幅
1985
- * - 黒鍵: 左 62% を黒塗り、右 38% は白鍵色(奥に伸びて見える)
1986
- * - E→F / C→B(下オクターブ) の白白境界に区切り線
1987
- */
1988
- declare const drawKeyboard: () => void;
1989
- declare const drawHeader: () => void;
1990
- /**
1991
- * グリッドと背景を描画します。(グリッドCanvasと鍵盤/ヘッダー描画の呼び出し)
1992
- * @param noteLengthSteps ノート長ステップ数(この値ごとに縦線を表示)
1993
- */
1994
- declare const drawGrid: (noteLengthSteps?: number) => void;
1995
- /**
1996
- * 指定されたノートの配列を描画します。
1997
- * @param notes 描画対象のノートリスト
1998
- * @param color [r, g, b, a] のカラー値
1999
- * @param isActive アクティブトラックかどうか(アクティブ時は立体ハイライト・鮮明表示、非アクティブ時はゴースト表示)
2000
- */
2001
- declare const drawNotes: (notes: Note[], color?: number[], isActive?: boolean) => void;
2002
- /**
2003
- * ノートの上に歌詞(かな)を重ねて描画します。
2004
- *
2005
- * 音節の割り当ては発音側(StreamVoiceTrack の組み立て)と同じ規則で、
2006
- * startStep 昇順に並べたノートの i 番目へ syllables[i] を対応させます。
2007
- * 音節が足りないぶんのノートには何も描きません。
2186
+ * 1つのピアノロール描画面(ヘッダー/鍵盤/グリッドの3枚のCanvas)を表す描画器。
2008
2187
  *
2009
- * 文字はノート矩形でクリップするため、隣のノートへはみ出しません。
2010
- */
2011
- declare const drawNoteLyrics: (notes: Note[], syllables: string[]) => void;
2012
- /**
2013
- * 選択範囲の四角形を描画します。
2014
- */
2015
- declare const drawSelectionRect: (rect: {
2016
- x: number;
2017
- y: number;
2018
- width: number;
2019
- height: number;
2020
- } | null) => void;
2021
- /**
2022
- * 選択されたノートをハイライト描画します。(濃い色で描画、枠なし)
2023
- */
2024
- declare const drawSelectedNotes: (notes: Note[], selectedIds: Set<number>, baseColor?: number[]) => void;
2025
- /**
2026
- * カーソルの座標取得
2027
- * (グリッドCanvasの相対座標を取得)
2028
- */
2029
- declare const getXY: (e: MouseEvent | PointerEvent) => [number, number, number];
2030
- declare const getGridPosition: (e: MouseEvent | PointerEvent) => {
2031
- step: number;
2032
- pitch: number;
2033
- x: number;
2034
- y: number;
2188
+ * 以前はモジュールグローバル(`g_config` / 各Canvas / 描画オフセット)を直に触る
2189
+ * 関数群だったが、それだと1ページに2つ以上のエディタをマウントしたとき後からマウント
2190
+ * した側がグローバルを奪い、先にマウントした側の描画が相手のCanvasへ流れ込んでいた。
2191
+ * 曲ごとに音律(12平均律 / 31平均律)が違うと格子まで食い違うため、描画状態は
2192
+ * インスタンスに閉じ込める。
2193
+ */
2194
+ type Renderer = {
2195
+ getRenderConfig: () => RenderConfig;
2196
+ setBackgroundActive: (active: boolean) => void;
2197
+ getDrawOffset: () => {
2198
+ x: number;
2199
+ y: number;
2200
+ };
2201
+ getGridCanvas: () => HTMLCanvasElement;
2202
+ getGridContext: () => CanvasRenderingContext2D;
2203
+ getHeaderCanvas: () => HTMLCanvasElement;
2204
+ drawKeyboard: () => void;
2205
+ drawHeader: () => void;
2206
+ drawGrid: (noteLengthSteps?: number) => void;
2207
+ drawNotes: (notes: Note[], color?: number[], isActive?: boolean) => void;
2208
+ drawNoteLyrics: (notes: Note[], syllables: string[]) => void;
2209
+ drawSelectionRect: (rect: {
2210
+ x: number;
2211
+ y: number;
2212
+ width: number;
2213
+ height: number;
2214
+ } | null) => void;
2215
+ drawSelectedNotes: (notes: Note[], selectedIds: Set<number>, baseColor?: number[]) => void;
2216
+ getXY: (e: MouseEvent | PointerEvent) => [number, number, number];
2217
+ getGridPosition: (e: MouseEvent | PointerEvent) => {
2218
+ step: number;
2219
+ /** ピッチ。単位は units(1/372オクターブ)。 */
2220
+ pitch: Units;
2221
+ x: number;
2222
+ y: number;
2223
+ };
2224
+ onClick: (callback: (step: number, pitch: Units) => void) => void;
2225
+ setDrawOffset: (x: number, y: number) => void;
2226
+ /** Canvasをマウント先から取り外す。 */
2227
+ destroy: () => void;
2035
2228
  };
2036
2229
  /**
2037
- * ユーザーのクリックイベントを抽象化し、グリッド座標をコールバックに渡します。
2038
- * イベントリスナーをグリッドCanvasにのみ追加します。
2039
- */
2040
- declare const onClick: (callback: (step: number, pitch: number) => void) => void;
2041
- /**
2042
- * 描画オフセット(描画開始ピクセル位置)を設定します。
2230
+ * Canvasを生成してマウントし、そのマウント面専用の描画器を返す。
2231
+ * 同じページに複数生成しても互いの状態を踏まない。
2043
2232
  */
2044
- declare const setDrawOffset: (x: number, y: number) => void;
2233
+ declare const createRenderer: (mountTarget: HTMLElement, width: number | undefined, height: number | undefined, config: RenderConfig) => Renderer;
2045
2234
 
2046
2235
  /**
2047
2236
  * 再生シーケンサ。タイムライン計算と先読みスケジューリングを担い、
@@ -2097,10 +2286,13 @@ type SoundFontInstance = {
2097
2286
  play: (o: {
2098
2287
  ctx: AudioContext;
2099
2288
  destination: AudioNode;
2289
+ /** 最寄りの整数MIDIノート番号(ゾーン選択用)。 */
2100
2290
  pitch: number;
2101
2291
  volume: number;
2102
2292
  /** 元ノートのvelocity(0-127)。音量ではなく音色の明るさにだけ効く。 */
2103
2293
  velocity?: number;
2294
+ /** pitch からの微調整(セント)。31平均律など整数ノートに乗らない音高用。 */
2295
+ detuneCents?: number;
2104
2296
  when: number;
2105
2297
  duration: number;
2106
2298
  }) => void;
@@ -2352,7 +2544,8 @@ type DtmStudio = {
2352
2544
  playDrumEvent: (e: PlayDrumEvent) => void;
2353
2545
  /** SoundFontを用いた単音再生を行う */
2354
2546
  playNote: (options: {
2355
- pitch: number;
2547
+ /** ピッチ。単位は units(1/372オクターブ)。`pitchV1ToUnits` でMIDI番号から変換できる。 */
2548
+ pitchUnits: Units;
2356
2549
  volume?: number;
2357
2550
  duration?: number;
2358
2551
  instrument?: string;
@@ -2444,8 +2637,11 @@ declare const showLoadingOverlay: (container: HTMLElement, options?: {
2444
2637
  * ミキサーへルーティングしたり、SE と AudioContext を共有したりできるようにするため。
2445
2638
  */
2446
2639
 
2447
- /** MIDIピッチ番号 → 周波数(Hz)。A4(69)=440Hz 基準。 */
2448
- declare const freqFromPitch: (pitch: number) => number;
2640
+ /**
2641
+ * ピッチ(units) → 周波数(Hz)。A4 = 2139 units = 440Hz 基準。
2642
+ * 単位は 1/372オクターブの整数(`tuning.ts` 参照)。12平均律・31平均律とも同じ式で鳴る。
2643
+ */
2644
+ declare const freqFromPitch: (pitchUnits: Units) => number;
2449
2645
  type Synth = {
2450
2646
  /** メロディックノートを発音する(PlayNoteEvent.when は ctx.currentTime からの相対秒) */
2451
2647
  playNote: (e: PlayNoteEvent) => void;
@@ -2486,4 +2682,4 @@ declare const encodeWavPCM16: (channels: Float32Array[], sampleRate: number) =>
2486
2682
  /** Float32Array のチャンクを1本へ連結する。 */
2487
2683
  declare const concatFloat32: (chunks: Float32Array[]) => Float32Array;
2488
2684
 
2489
- export { type AddNoteOptions, type AnyDrumPattern, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ChordPlayerInstance, type ConsumedSyllable, type CoreEventHandlers, type CustomVocalDef, 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 DrumPatternDef, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, type FadeScheduleParams, GM_INSTRUMENT_NAMES, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LoopConfig, type LoopPoint, type LyricSyllable, type LyricSyncData, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNotePlacement, MidiSearchClient, type MidiSearchConfig, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountChordPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, type NoteData, type NoteRemove, type OctaveUnisonMode, PITCH_MAP, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PicotuneSearchParams, type PicotuneSong, type PitchToken, type PlayChordsOptions, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlayNoteOptions, type PlayPlacementsOptions, type PlaySingingMmlOptions, type PlaybackCue, type PlaybackState, type PresetSelectInstance, type PresetSelectOptions, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, type Synth, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VIBRATO_MIN_SEC, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceExpression, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildDrumPatternJson, buildNameToKeyMapping, collectPitchTokens, concatFloat32, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNoteLyrics, drawNotes, drawSelectedNotes, drawSelectionRect, encodeMml, encodeWavPCM16, exportMIDI, extractDrumPatternFromNotes, extractMidiDrumPattern, extractMidiPlacements, extractMidiPlacementsByTrack, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrawOffset, getDrumPatternKeys, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, isPlausibleMidiTranscription, isValidHttpUrl, koeUrl, mountChordPlayer, mountDAW, mountMmlPlayer, normalizeDrumPatterns, normalizeLyrics, onClick, panToStereo, parseCustomVocals, parseLyrics, parseMML, parseMmlMeta, playChords, playMML, playNote, playPlacements, playSingingMML, resolveDrumPattern, resolveLoopPoint, setBackgroundActive, setDrawOffset, shiftNotes, showLoadingOverlay, stripCustomVocals, stripLyrics, stripMmlMeta, transposeNotes, vocalVolumeToGain };
2685
+ export { A4_HZ, A4_UNITS, type AddNoteOptions, type AnyDrumPattern, type ApplyChordOptions, CENTS_PER_UNIT, type ChordPatternType, type ChordPlacement, type ChordPlayerInstance, type ConsumedSyllable, type CoreEventHandlers, type CustomVocalDef, DAW_CSS, DEFAULT_BPM, DEFAULT_EDO, 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 DrumPatternDef, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, EDO31_NAMES, type Edo, type ExportMidiOptions, type FadeScheduleParams, GM_INSTRUMENT_NAMES, INSTRUMENT_PRESETS, type InstrumentPreset, KEY_COUNT, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LoopConfig, type LoopPoint, type LyricSyllable, type LyricSyncData, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MICRO_STEP, MMLCore, type MMLDisplayToken, type MMLNotePlacement, MML_END_MARKER, type MidiExtraction, type MidiNote, type MidiNotePlacement, MidiSearchClient, type MidiSearchConfig, type MidiTrackAnalysis, type MmlMeta, type MmlPlayback, type MmlPlayerInstance, type MmlPlayerOptions, type ModeSwitchInstance, type ModeSwitchOptions, type MountChordPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, type NoteData, type NoteRemove, type OctaveUnisonMode, PITCH_ENCODING_VERSION, PITCH_MAP, PITCH_RANGE_END, PITCH_RANGE_START, PREWARM_NOTES, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PicotuneSearchParams, type PicotuneSong, type PitchToken, type PlayChordsOptions, type PlayDrumEvent, type PlayMmlOptions, type PlayNoteEvent, type PlayNoteOptions, type PlayPlacementsOptions, type PlaySingingMmlOptions, type PlaybackCue, type PlaybackState, type PresetSelectInstance, type PresetSelectOptions, type PreviewSoundCallback, type RenderConfig, type Renderer, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, type Synth, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, UNITS_PER_EDO31_DEGREE, UNITS_PER_OCTAVE, UNITS_PER_SEMITONE, type Units, VIBRATO_MIN_SEC, VOICE_IMAGES, VOICE_IMAGE_KEY, type VoiceExpression, type VoiceModel, type VoiceRegistry, addUnits, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildDrumPatternJson, buildNameToKeyMapping, chromaticStep, collectPitchTokens, concatFloat32, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createRenderer, createSequencer, createSingingVoices, createSynth, createVoiceRegistry, decodeMml, decomposeToMonophonic, encodeMml, encodeWavPCM16, exportMIDI, extractDrumPatternFromNotes, extractMidiDrumPattern, extractMidiPlacements, extractMidiPlacementsByTrack, fifthToStep, fifthToUnits, formatMmlMeta, freqFromPitch, generateRandomPattern, getDrumPatternKeys, getMidiBPM, icon, injectStyles, isChordHeavyTrack, isNaturalLetter, isPlausibleMidiTranscription, isValidHttpUrl, keyCountFor, koeUrl, midiNote, midiToUnits, mountChordPlayer, mountDAW, mountMmlPlayer, naturalStep, normalizeDrumPatterns, normalizeLyrics, panToStereo, parseCustomVocals, parseLyrics, parseMML, parseMmlMeta, pitchV1ToUnits, playChords, playMML, playNote, playPlacements, playSingingMML, resolveDrumPattern, resolveLoopPoint, shiftNotes, showLoadingOverlay, spellingToUnits, stripCustomVocals, stripLyrics, stripMmlMeta, transposeNotes, units, unitsPerRow, unitsPerStep, unitsToHz, unitsToMidi, unitsToMidiDetune, unitsToPitchV1, vocalVolumeToGain };