@onjmin/dtm 0.1.100 → 0.1.102

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
@@ -75,6 +75,33 @@ const chordPlayer = studio.mountChordPlayer(chordEl, "| C | G | Am | F |", {
75
75
  chordPlayer.setVolume(65);
76
76
  ```
77
77
 
78
+ ### 「曲自体の音量」と「聴く人の音量」を分けて扱いたい場合
79
+
80
+ 上記の `masterVolume` / `volume` は**曲データが持つ音量**です(MML の `#volume=` と往復し、
81
+ `daw.loadMML()` を呼ぶたびにそのMMLの値で上書きされます)。SNS のフィードのように、
82
+ 1つの `studio` を複数の投稿・複数の埋め込みプレイヤーで共有し、かつ「読者が自分の好みで
83
+ サイト全体の音量を1つ調整したい」というケースでは、曲側の値をいじらずに
84
+ `studio.setMasterVolume()` を使ってください。これは `studio.masterGain`(全ての
85
+ `mountEditor` / `mountPlayer` / `mountChordPlayer` / `playSingingMML` インスタンスが
86
+ 最終的に合流する出力段の GainNode)を直接動かすため、曲データやモード切替・
87
+ `loadMML()` の影響を一切受けません。
88
+
89
+ ```ts
90
+ const studio = await createDtmStudio();
91
+
92
+ // 読者側の「サイト全体の音量」— 曲を跨いで一度だけ管理すればよい
93
+ studio.setMasterVolume(userPreferredVolume); // 0-100
94
+
95
+ // 曲側の masterVolume/volume には触れない(#volume= が持つ作曲者の意図をそのまま尊重する)
96
+ const daw = studio.mountEditor(editorEl, { initialMML: mml });
97
+ const player = studio.mountPlayer(playerEl, mml);
98
+ ```
99
+
100
+ `DawInstance.setMasterVolume` / `MmlPlayerOptions.masterVolume` と
101
+ `DtmStudio.setMasterVolume` は同名ですが別物です。前者は「曲自体の音量」(`#volume=`
102
+ と同期し、曲を読み込むたびに上書きされる)、後者は「聴く人の音量」(曲データと
103
+ 無関係に出力段へ一度だけ掛かる)という別レイヤーを担っています。
104
+
78
105
  ---
79
106
 
80
107
  ## 録音・動画エンコード用音声ストリームの取得 (`MediaStream`)
package/dist/index.d.mts CHANGED
@@ -1162,9 +1162,15 @@ type DawInstance = {
1162
1162
  applyPatch: (trackId: string, added: NoteData[], removed: NoteRemove[]) => void;
1163
1163
  /** リモートから受信した歌詞・UTAU設定を適用する。 */
1164
1164
  applyLyrics: (trackId: string, data: LyricSyncData) => void;
1165
- /** マスタ音量を 0-100 で変更する。 */
1165
+ /**
1166
+ * このDAWインスタンス自身が持つ「曲自体の音量」(`#volume=`)を 0-100 で変更する。
1167
+ * `getMML()`で出力・`loadMML()`で復元される、曲データの一部として永続化される値。
1168
+ * `loadMML()` を呼ぶたびにそのMMLの `#volume=` で上書きされるため、リスナー側の
1169
+ * 音量の好みを別途乗せたい場合は代わりに `DtmStudio.setMasterVolume`
1170
+ * (`studio.masterGain`、曲データと無関係な出力段ゲイン)を使うこと。
1171
+ */
1166
1172
  setMasterVolume: (volume: number) => void;
1167
- /** マスタ音量を 0-100 で変更する(`setMasterVolume` のエイリアス)。 */
1173
+ /** `setMasterVolume` のエイリアス。 */
1168
1174
  setVolume: (volume: number) => void;
1169
1175
  /** ドラム音量を 0-100 で変更する。 */
1170
1176
  setDrumVolume: (volume: number) => void;
@@ -1885,7 +1891,7 @@ type MmlPlayerOptions = {
1885
1891
  onResumeAudio?: () => void | Promise<void>;
1886
1892
  /** 内蔵の簡易square-wave synthを使うか。既定は onPlayNote 未指定なら true */
1887
1893
  synth?: boolean;
1888
- /** マスタ音量 0-100。既定100。 */
1894
+ /** マスタ音量 0-100。既定50(DAW編集画面の全体音量スライダーの既定値に合わせている)。 */
1889
1895
  masterVolume?: number;
1890
1896
  /** BPM未検出時のフォールバック。既定120 */
1891
1897
  defaultBpm?: number;
@@ -2123,9 +2129,12 @@ type DtmStudioEngines = {
2123
2129
  type DtmStudioOptions = {
2124
2130
  /** 既存の AudioContext を使う(未指定なら内部生成)。 */
2125
2131
  audioContext?: AudioContext;
2126
- /** マスター音量 0-1(楽器・歌声)。既定 1。 */
2132
+ /**
2133
+ * マスター音量 0-100(楽器・歌声)。既定100。
2134
+ * ライブラリ内の他の音量パラメータ(`setMasterVolume` 等)と同じ0-100スケール。
2135
+ */
2127
2136
  masterVolume?: number;
2128
- /** ドラム音量 0-1。既定 1。 */
2137
+ /** ドラム音量 0-100。既定100。 */
2129
2138
  drumVolume?: number;
2130
2139
  /** マスタリバーブの掛かり具合 0-100。既定0(オフ)。全トラックへ一律で掛かる。 */
2131
2140
  reverbAmount?: number;
@@ -2351,9 +2360,18 @@ type DtmStudio = {
2351
2360
  * getDaw() で現在の DawInstance を取得できる(mountPresetSelect の getDaw に渡せる)。
2352
2361
  */
2353
2362
  mountModeSwitch: (target: HTMLElement, options: ModeSwitchOptions) => ModeSwitchInstance;
2354
- /** マスタ音量を 0-100 で変更する。 */
2363
+ /**
2364
+ * studio 全体(このstudioを共有する全ての mountEditor / mountPlayer / mountChordPlayer /
2365
+ * playSingingMML インスタンス)の出力段ゲインを 0-100 で変更する。
2366
+ *
2367
+ * これは「聴く人(リスナー)側の音量設定」用のノブで、曲データとは無関係に
2368
+ * オーディオグラフの最終段(`studio.masterGain`)に一度だけ掛かる。
2369
+ * `DawInstance.setMasterVolume` / `MmlPlayerOptions.masterVolume`(`#volume=`
2370
+ * と往復する“曲自体が持つ音量”)とは別物なので混同しないこと。
2371
+ * `daw.loadMML()` や `#volume=` の内容に一切影響されない。
2372
+ */
2355
2373
  setMasterVolume: (volume: number) => void;
2356
- /** マスタ音量を 0-100 で変更する(`setMasterVolume` のエイリアス)。 */
2374
+ /** `setMasterVolume` のエイリアス。 */
2357
2375
  setVolume: (volume: number) => void;
2358
2376
  /** マスタリバーブの掛かり具合を 0-100 で変更する。 */
2359
2377
  setReverbAmount: (amount: number) => void;
package/dist/index.d.ts CHANGED
@@ -1162,9 +1162,15 @@ type DawInstance = {
1162
1162
  applyPatch: (trackId: string, added: NoteData[], removed: NoteRemove[]) => void;
1163
1163
  /** リモートから受信した歌詞・UTAU設定を適用する。 */
1164
1164
  applyLyrics: (trackId: string, data: LyricSyncData) => void;
1165
- /** マスタ音量を 0-100 で変更する。 */
1165
+ /**
1166
+ * このDAWインスタンス自身が持つ「曲自体の音量」(`#volume=`)を 0-100 で変更する。
1167
+ * `getMML()`で出力・`loadMML()`で復元される、曲データの一部として永続化される値。
1168
+ * `loadMML()` を呼ぶたびにそのMMLの `#volume=` で上書きされるため、リスナー側の
1169
+ * 音量の好みを別途乗せたい場合は代わりに `DtmStudio.setMasterVolume`
1170
+ * (`studio.masterGain`、曲データと無関係な出力段ゲイン)を使うこと。
1171
+ */
1166
1172
  setMasterVolume: (volume: number) => void;
1167
- /** マスタ音量を 0-100 で変更する(`setMasterVolume` のエイリアス)。 */
1173
+ /** `setMasterVolume` のエイリアス。 */
1168
1174
  setVolume: (volume: number) => void;
1169
1175
  /** ドラム音量を 0-100 で変更する。 */
1170
1176
  setDrumVolume: (volume: number) => void;
@@ -1885,7 +1891,7 @@ type MmlPlayerOptions = {
1885
1891
  onResumeAudio?: () => void | Promise<void>;
1886
1892
  /** 内蔵の簡易square-wave synthを使うか。既定は onPlayNote 未指定なら true */
1887
1893
  synth?: boolean;
1888
- /** マスタ音量 0-100。既定100。 */
1894
+ /** マスタ音量 0-100。既定50(DAW編集画面の全体音量スライダーの既定値に合わせている)。 */
1889
1895
  masterVolume?: number;
1890
1896
  /** BPM未検出時のフォールバック。既定120 */
1891
1897
  defaultBpm?: number;
@@ -2123,9 +2129,12 @@ type DtmStudioEngines = {
2123
2129
  type DtmStudioOptions = {
2124
2130
  /** 既存の AudioContext を使う(未指定なら内部生成)。 */
2125
2131
  audioContext?: AudioContext;
2126
- /** マスター音量 0-1(楽器・歌声)。既定 1。 */
2132
+ /**
2133
+ * マスター音量 0-100(楽器・歌声)。既定100。
2134
+ * ライブラリ内の他の音量パラメータ(`setMasterVolume` 等)と同じ0-100スケール。
2135
+ */
2127
2136
  masterVolume?: number;
2128
- /** ドラム音量 0-1。既定 1。 */
2137
+ /** ドラム音量 0-100。既定100。 */
2129
2138
  drumVolume?: number;
2130
2139
  /** マスタリバーブの掛かり具合 0-100。既定0(オフ)。全トラックへ一律で掛かる。 */
2131
2140
  reverbAmount?: number;
@@ -2351,9 +2360,18 @@ type DtmStudio = {
2351
2360
  * getDaw() で現在の DawInstance を取得できる(mountPresetSelect の getDaw に渡せる)。
2352
2361
  */
2353
2362
  mountModeSwitch: (target: HTMLElement, options: ModeSwitchOptions) => ModeSwitchInstance;
2354
- /** マスタ音量を 0-100 で変更する。 */
2363
+ /**
2364
+ * studio 全体(このstudioを共有する全ての mountEditor / mountPlayer / mountChordPlayer /
2365
+ * playSingingMML インスタンス)の出力段ゲインを 0-100 で変更する。
2366
+ *
2367
+ * これは「聴く人(リスナー)側の音量設定」用のノブで、曲データとは無関係に
2368
+ * オーディオグラフの最終段(`studio.masterGain`)に一度だけ掛かる。
2369
+ * `DawInstance.setMasterVolume` / `MmlPlayerOptions.masterVolume`(`#volume=`
2370
+ * と往復する“曲自体が持つ音量”)とは別物なので混同しないこと。
2371
+ * `daw.loadMML()` や `#volume=` の内容に一切影響されない。
2372
+ */
2355
2373
  setMasterVolume: (volume: number) => void;
2356
- /** マスタ音量を 0-100 で変更する(`setMasterVolume` のエイリアス)。 */
2374
+ /** `setMasterVolume` のエイリアス。 */
2357
2375
  setVolume: (volume: number) => void;
2358
2376
  /** マスタリバーブの掛かり具合を 0-100 で変更する。 */
2359
2377
  setReverbAmount: (amount: number) => void;
package/dist/index.js CHANGED
@@ -8851,7 +8851,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
8851
8851
  };
8852
8852
  const drumPatternName = meta.drum ?? "none";
8853
8853
  const trackVolume = meta.volume ?? options.volume ?? 100;
8854
- let masterVolume = options.masterVolume ?? 100;
8854
+ let masterVolume = options.masterVolume ?? 50;
8855
8855
  const drumVolume = meta.drumVolume ?? 80;
8856
8856
  const colors = options.trackColors ?? DEFAULT_TRACK_COLORS;
8857
8857
  const useSynth = options.synth ?? !options.onPlayNote;
@@ -18219,6 +18219,8 @@ var playSingingMML = async (mml, options = {}) => {
18219
18219
  const drumVolume = meta.drumVolume ?? 80;
18220
18220
  const trackVolume = meta.volume ?? 100;
18221
18221
  let masterVolume = options.volume ?? 100;
18222
+ const trackVolumePercent = () => trackVolume / 100 * masterVolume;
18223
+ const masterGainScalar = () => trackVolume / 100 * (masterVolume / 100);
18222
18224
  const trackIndices = [...new Set(placements.map((p) => p.trackIndex))].sort(
18223
18225
  (a, b) => a - b
18224
18226
  );
@@ -18233,7 +18235,7 @@ var playSingingMML = async (mml, options = {}) => {
18233
18235
  }));
18234
18236
  return {
18235
18237
  id: TRACK_ID_BY_INDEX2[index] ?? `t${index}`,
18236
- volume: trackVolume / 100 * masterVolume,
18238
+ volume: trackVolumePercent(),
18237
18239
  notes
18238
18240
  };
18239
18241
  });
@@ -18270,7 +18272,7 @@ var playSingingMML = async (mml, options = {}) => {
18270
18272
  return {
18271
18273
  id: TRACK_ID_BY_INDEX2[index] ?? `t${index}`,
18272
18274
  model: lt.model,
18273
- volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
18275
+ volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * masterGainScalar(),
18274
18276
  pan: panToStereo(lt.pan ?? DEFAULT_PAN),
18275
18277
  vibrato: lt.vibrato,
18276
18278
  reverbSend: (lt.reverb ?? 0) / 100,
@@ -18305,7 +18307,7 @@ var playSingingMML = async (mml, options = {}) => {
18305
18307
  synth?.playNote(e);
18306
18308
  },
18307
18309
  onPlayDrum: (e) => {
18308
- const velocity = e.velocity * (drumVolume / 100) * (trackVolume / 100) * (masterVolume / 100);
18310
+ const velocity = e.velocity * (drumVolume / 100) * masterGainScalar();
18309
18311
  options.onPlayDrum?.({ ...e, velocity });
18310
18312
  synth?.playDrum({ ...e, velocity });
18311
18313
  },
@@ -18339,9 +18341,8 @@ var playSingingMML = async (mml, options = {}) => {
18339
18341
  };
18340
18342
  const setVolume = (volume) => {
18341
18343
  masterVolume = volume;
18342
- const effectiveTrackVolume = trackVolume / 100 * masterVolume;
18343
- for (const t of seqTracks) t.volume = effectiveTrackVolume;
18344
- voices?.setVolume(trackVolume / 100 * (masterVolume / 100));
18344
+ for (const t of seqTracks) t.volume = trackVolumePercent();
18345
+ voices?.setVolume(masterGainScalar());
18345
18346
  };
18346
18347
  const suspend = () => ctx.suspend();
18347
18348
  const resume = () => ctx.resume();
@@ -18427,7 +18428,7 @@ var playSingingMML = async (mml, options = {}) => {
18427
18428
  loopLengthSec = (loopEndStep - loopStartStep) * secondsPerStep;
18428
18429
  }
18429
18430
  seq.start(options.startStep ?? 0);
18430
- voices.setVolume(trackVolume / 100 * (masterVolume / 100));
18431
+ voices.setVolume(masterGainScalar());
18431
18432
  voices.startStream(streamTracks, seq.getStartTime(), {
18432
18433
  loopLengthSec,
18433
18434
  loopStartSec
@@ -19155,9 +19156,9 @@ var createDtmStudio = async (options = {}) => {
19155
19156
  });
19156
19157
  const audioCtx = options.audioContext ?? new AudioContext({ sampleRate: 44100 });
19157
19158
  const masterGain = audioCtx.createGain();
19158
- masterGain.gain.value = options.masterVolume ?? 1;
19159
+ masterGain.gain.value = (options.masterVolume ?? 100) / 100;
19159
19160
  const drumGain = audioCtx.createGain();
19160
- drumGain.gain.value = options.drumVolume ?? 1;
19161
+ drumGain.gain.value = (options.drumVolume ?? 100) / 100;
19161
19162
  drumGain.connect(masterGain);
19162
19163
  let reverbDecaySec = options.reverbDecay ?? DEFAULT_REVERB_DECAY_SEC;
19163
19164
  const reverbPreDelay = audioCtx.createDelay(MAX_REVERB_PREDELAY_MS / 1e3);
package/dist/index.mjs CHANGED
@@ -8718,7 +8718,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
8718
8718
  };
8719
8719
  const drumPatternName = meta.drum ?? "none";
8720
8720
  const trackVolume = meta.volume ?? options.volume ?? 100;
8721
- let masterVolume = options.masterVolume ?? 100;
8721
+ let masterVolume = options.masterVolume ?? 50;
8722
8722
  const drumVolume = meta.drumVolume ?? 80;
8723
8723
  const colors = options.trackColors ?? DEFAULT_TRACK_COLORS;
8724
8724
  const useSynth = options.synth ?? !options.onPlayNote;
@@ -18086,6 +18086,8 @@ var playSingingMML = async (mml, options = {}) => {
18086
18086
  const drumVolume = meta.drumVolume ?? 80;
18087
18087
  const trackVolume = meta.volume ?? 100;
18088
18088
  let masterVolume = options.volume ?? 100;
18089
+ const trackVolumePercent = () => trackVolume / 100 * masterVolume;
18090
+ const masterGainScalar = () => trackVolume / 100 * (masterVolume / 100);
18089
18091
  const trackIndices = [...new Set(placements.map((p) => p.trackIndex))].sort(
18090
18092
  (a, b) => a - b
18091
18093
  );
@@ -18100,7 +18102,7 @@ var playSingingMML = async (mml, options = {}) => {
18100
18102
  }));
18101
18103
  return {
18102
18104
  id: TRACK_ID_BY_INDEX2[index] ?? `t${index}`,
18103
- volume: trackVolume / 100 * masterVolume,
18105
+ volume: trackVolumePercent(),
18104
18106
  notes
18105
18107
  };
18106
18108
  });
@@ -18137,7 +18139,7 @@ var playSingingMML = async (mml, options = {}) => {
18137
18139
  return {
18138
18140
  id: TRACK_ID_BY_INDEX2[index] ?? `t${index}`,
18139
18141
  model: lt.model,
18140
- volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
18142
+ volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * masterGainScalar(),
18141
18143
  pan: panToStereo(lt.pan ?? DEFAULT_PAN),
18142
18144
  vibrato: lt.vibrato,
18143
18145
  reverbSend: (lt.reverb ?? 0) / 100,
@@ -18172,7 +18174,7 @@ var playSingingMML = async (mml, options = {}) => {
18172
18174
  synth?.playNote(e);
18173
18175
  },
18174
18176
  onPlayDrum: (e) => {
18175
- const velocity = e.velocity * (drumVolume / 100) * (trackVolume / 100) * (masterVolume / 100);
18177
+ const velocity = e.velocity * (drumVolume / 100) * masterGainScalar();
18176
18178
  options.onPlayDrum?.({ ...e, velocity });
18177
18179
  synth?.playDrum({ ...e, velocity });
18178
18180
  },
@@ -18206,9 +18208,8 @@ var playSingingMML = async (mml, options = {}) => {
18206
18208
  };
18207
18209
  const setVolume = (volume) => {
18208
18210
  masterVolume = volume;
18209
- const effectiveTrackVolume = trackVolume / 100 * masterVolume;
18210
- for (const t of seqTracks) t.volume = effectiveTrackVolume;
18211
- voices?.setVolume(trackVolume / 100 * (masterVolume / 100));
18211
+ for (const t of seqTracks) t.volume = trackVolumePercent();
18212
+ voices?.setVolume(masterGainScalar());
18212
18213
  };
18213
18214
  const suspend = () => ctx.suspend();
18214
18215
  const resume = () => ctx.resume();
@@ -18294,7 +18295,7 @@ var playSingingMML = async (mml, options = {}) => {
18294
18295
  loopLengthSec = (loopEndStep - loopStartStep) * secondsPerStep;
18295
18296
  }
18296
18297
  seq.start(options.startStep ?? 0);
18297
- voices.setVolume(trackVolume / 100 * (masterVolume / 100));
18298
+ voices.setVolume(masterGainScalar());
18298
18299
  voices.startStream(streamTracks, seq.getStartTime(), {
18299
18300
  loopLengthSec,
18300
18301
  loopStartSec
@@ -19021,9 +19022,9 @@ var createDtmStudio = async (options = {}) => {
19021
19022
  });
19022
19023
  const audioCtx = options.audioContext ?? new AudioContext({ sampleRate: 44100 });
19023
19024
  const masterGain = audioCtx.createGain();
19024
- masterGain.gain.value = options.masterVolume ?? 1;
19025
+ masterGain.gain.value = (options.masterVolume ?? 100) / 100;
19025
19026
  const drumGain = audioCtx.createGain();
19026
- drumGain.gain.value = options.drumVolume ?? 1;
19027
+ drumGain.gain.value = (options.drumVolume ?? 100) / 100;
19027
19028
  drumGain.connect(masterGain);
19028
19029
  let reverbDecaySec = options.reverbDecay ?? DEFAULT_REVERB_DECAY_SEC;
19029
19030
  const reverbPreDelay = audioCtx.createDelay(MAX_REVERB_PREDELAY_MS / 1e3);
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.100",
5
+ "version": "0.1.102",
6
6
  "description": "MMLを中間言語に用いた、モバイルファーストなDAW / ピアノロール打ち込みコンポーネント",
7
7
  "homepage": "https://onjmin.github.io/dtm",
8
8
  "repository": {