@onjmin/dtm 0.1.60 → 0.1.61

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.mts CHANGED
@@ -406,6 +406,13 @@ type SingingVoices = {
406
406
  stopStream: () => void;
407
407
  /** ストリーム停止+各モデルの内部状態を初期化する。 */
408
408
  reset: () => void;
409
+ /**
410
+ * マスタ音量(0〜1のゲイン)をリアルタイムに反映する。
411
+ * 発音時にゲインを焼き込む方式だと再生中の音量変更が既にスケジュール済み・
412
+ * ストリーミング中の音符に効かないため、全モデル共通の GainNode を介して
413
+ * 常時ライブ反映できるようにする。
414
+ */
415
+ setVolume: (gain: number) => void;
409
416
  };
410
417
  /** {@link SingingVoices.warm} の既定先合成数(各トラック先頭からの音数)。 */
411
418
  declare const PREWARM_NOTES = 3;
package/dist/index.d.ts CHANGED
@@ -406,6 +406,13 @@ type SingingVoices = {
406
406
  stopStream: () => void;
407
407
  /** ストリーム停止+各モデルの内部状態を初期化する。 */
408
408
  reset: () => void;
409
+ /**
410
+ * マスタ音量(0〜1のゲイン)をリアルタイムに反映する。
411
+ * 発音時にゲインを焼き込む方式だと再生中の音量変更が既にスケジュール済み・
412
+ * ストリーミング中の音符に効かないため、全モデル共通の GainNode を介して
413
+ * 常時ライブ反映できるようにする。
414
+ */
415
+ setVolume: (gain: number) => void;
409
416
  };
410
417
  /** {@link SingingVoices.warm} の既定先合成数(各トラック先頭からの音数)。 */
411
418
  declare const PREWARM_NOTES = 3;
package/dist/index.js CHANGED
@@ -2676,8 +2676,10 @@ var createSingingVoices = (ctx, destination, options = {}) => {
2676
2676
  for (const [k, v] of Object.entries(options.voicebanks ?? {}))
2677
2677
  catalog[k.toLowerCase()] = v;
2678
2678
  let streamSession = 0;
2679
+ const masterGain = ctx.createGain();
2680
+ masterGain.connect(destination);
2679
2681
  const loaded = /* @__PURE__ */ new Map([
2680
- [FALLBACK_MODEL, createKlattVoice(ctx, destination)]
2682
+ [FALLBACK_MODEL, createKlattVoice(ctx, masterGain)]
2681
2683
  ]);
2682
2684
  const loading = /* @__PURE__ */ new Map();
2683
2685
  const load2 = (model) => {
@@ -2693,7 +2695,7 @@ var createSingingVoices = (ctx, destination, options = {}) => {
2693
2695
  // マニフェストだけ先読みし、音素PCMは歌う直前にオンデマンド取得する
2694
2696
  // (= 初回に .koe 全体をDLしない。モバイル初回ロードの待ちを解消)。
2695
2697
  // Blob/File が直接渡されたケース(ローカル読み込み)はそのまま BlobVoiceSource。
2696
- createKoeVoice(ctx, destination, {
2698
+ createKoeVoice(ctx, masterGain, {
2697
2699
  koe,
2698
2700
  worldlineScriptUrl: options.worldlineScriptUrl,
2699
2701
  lightweight: options.lightweight,
@@ -2830,13 +2832,17 @@ var createSingingVoices = (ctx, destination, options = {}) => {
2830
2832
  stopStream();
2831
2833
  for (const v of loaded.values()) v.reset?.();
2832
2834
  };
2835
+ const setVolume = (gain) => {
2836
+ masterGain.gain.value = Math.max(0, gain);
2837
+ };
2833
2838
  return {
2834
2839
  loadModels,
2835
2840
  registerVoicebanks,
2836
2841
  warm,
2837
2842
  startStream,
2838
2843
  stopStream,
2839
- reset
2844
+ reset,
2845
+ setVolume
2840
2846
  };
2841
2847
  };
2842
2848
  var createVoiceRegistry = (models = {}, fallback = "klatt") => {
@@ -5605,6 +5611,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
5605
5611
  if (!voices) {
5606
5612
  const ctx = ensureCtx();
5607
5613
  voices = createSingingVoices(ctx, ctx.destination);
5614
+ voices.setVolume(masterVolume / 100);
5608
5615
  }
5609
5616
  return voices;
5610
5617
  };
@@ -6350,6 +6357,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
6350
6357
  };
6351
6358
  const setVolume = (volume) => {
6352
6359
  masterVolume = volume;
6360
+ peekVoices()?.setVolume(masterVolume / 100);
6353
6361
  };
6354
6362
  const buildStreamTracks = () => [...lyricTracks.entries()].map(([index, lt]) => {
6355
6363
  const seqTrack = seqTracks.find((t) => Number(t.id) === index);
@@ -6372,7 +6380,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
6372
6380
  return {
6373
6381
  id: String(index),
6374
6382
  model: lt.model,
6375
- volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * (trackVolume / 100) * (masterVolume / 100),
6383
+ volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * (trackVolume / 100),
6376
6384
  pan: panToStereo(lt.pan ?? DEFAULT_PAN),
6377
6385
  notes
6378
6386
  };
@@ -10023,6 +10031,7 @@ var mountDAW = (target, options = {}) => {
10023
10031
  let zoomY = 100;
10024
10032
  let bpm = options.defaultBpm ?? DEFAULT_BPM;
10025
10033
  let masterVolume = options.masterVolume ?? 50;
10034
+ options.singingVoices?.setVolume(masterVolume / 100);
10026
10035
  let drumVolume = options.drumVolume ?? 80;
10027
10036
  let currentDrumPattern = refs.drumSelect.value;
10028
10037
  let currentInstrument = "";
@@ -10900,7 +10909,7 @@ var mountDAW = (target, options = {}) => {
10900
10909
  return {
10901
10910
  id: trackState?.config.id,
10902
10911
  model: lt.model,
10903
- volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * (masterVolume / 100),
10912
+ volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
10904
10913
  pan: panToStereo(lt.pan ?? DEFAULT_PAN),
10905
10914
  notes
10906
10915
  };
@@ -11909,6 +11918,7 @@ var mountDAW = (target, options = {}) => {
11909
11918
  refs.masterVolume.addEventListener("input", () => {
11910
11919
  masterVolume = Number.parseInt(refs.masterVolume.value, 10) || 0;
11911
11920
  refs.masterVolumeLabel.textContent = `${masterVolume}%`;
11921
+ options.singingVoices?.setVolume(masterVolume / 100);
11912
11922
  });
11913
11923
  refs.drumSelect.addEventListener("change", () => {
11914
11924
  currentDrumPattern = refs.drumSelect.value;
@@ -12785,11 +12795,13 @@ var mountDAW = (target, options = {}) => {
12785
12795
  masterVolume = clamp3(volume, 0, 100);
12786
12796
  refs.masterVolume.value = String(masterVolume);
12787
12797
  refs.masterVolumeLabel.textContent = `${masterVolume}%`;
12798
+ options.singingVoices?.setVolume(masterVolume / 100);
12788
12799
  },
12789
12800
  setVolume: (volume) => {
12790
12801
  masterVolume = clamp3(volume, 0, 100);
12791
12802
  refs.masterVolume.value = String(masterVolume);
12792
12803
  refs.masterVolumeLabel.textContent = `${masterVolume}%`;
12804
+ options.singingVoices?.setVolume(masterVolume / 100);
12793
12805
  },
12794
12806
  setDrumVolume: (volume) => {
12795
12807
  drumVolume = clamp3(volume, 0, 100);
package/dist/index.mjs CHANGED
@@ -2554,8 +2554,10 @@ var createSingingVoices = (ctx, destination, options = {}) => {
2554
2554
  for (const [k, v] of Object.entries(options.voicebanks ?? {}))
2555
2555
  catalog[k.toLowerCase()] = v;
2556
2556
  let streamSession = 0;
2557
+ const masterGain = ctx.createGain();
2558
+ masterGain.connect(destination);
2557
2559
  const loaded = /* @__PURE__ */ new Map([
2558
- [FALLBACK_MODEL, createKlattVoice(ctx, destination)]
2560
+ [FALLBACK_MODEL, createKlattVoice(ctx, masterGain)]
2559
2561
  ]);
2560
2562
  const loading = /* @__PURE__ */ new Map();
2561
2563
  const load2 = (model) => {
@@ -2571,7 +2573,7 @@ var createSingingVoices = (ctx, destination, options = {}) => {
2571
2573
  // マニフェストだけ先読みし、音素PCMは歌う直前にオンデマンド取得する
2572
2574
  // (= 初回に .koe 全体をDLしない。モバイル初回ロードの待ちを解消)。
2573
2575
  // Blob/File が直接渡されたケース(ローカル読み込み)はそのまま BlobVoiceSource。
2574
- createKoeVoice(ctx, destination, {
2576
+ createKoeVoice(ctx, masterGain, {
2575
2577
  koe,
2576
2578
  worldlineScriptUrl: options.worldlineScriptUrl,
2577
2579
  lightweight: options.lightweight,
@@ -2708,13 +2710,17 @@ var createSingingVoices = (ctx, destination, options = {}) => {
2708
2710
  stopStream();
2709
2711
  for (const v of loaded.values()) v.reset?.();
2710
2712
  };
2713
+ const setVolume = (gain) => {
2714
+ masterGain.gain.value = Math.max(0, gain);
2715
+ };
2711
2716
  return {
2712
2717
  loadModels,
2713
2718
  registerVoicebanks,
2714
2719
  warm,
2715
2720
  startStream,
2716
2721
  stopStream,
2717
- reset
2722
+ reset,
2723
+ setVolume
2718
2724
  };
2719
2725
  };
2720
2726
  var createVoiceRegistry = (models = {}, fallback = "klatt") => {
@@ -5483,6 +5489,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
5483
5489
  if (!voices) {
5484
5490
  const ctx = ensureCtx();
5485
5491
  voices = createSingingVoices(ctx, ctx.destination);
5492
+ voices.setVolume(masterVolume / 100);
5486
5493
  }
5487
5494
  return voices;
5488
5495
  };
@@ -6228,6 +6235,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
6228
6235
  };
6229
6236
  const setVolume = (volume) => {
6230
6237
  masterVolume = volume;
6238
+ peekVoices()?.setVolume(masterVolume / 100);
6231
6239
  };
6232
6240
  const buildStreamTracks = () => [...lyricTracks.entries()].map(([index, lt]) => {
6233
6241
  const seqTrack = seqTracks.find((t) => Number(t.id) === index);
@@ -6250,7 +6258,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
6250
6258
  return {
6251
6259
  id: String(index),
6252
6260
  model: lt.model,
6253
- volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * (trackVolume / 100) * (masterVolume / 100),
6261
+ volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * (trackVolume / 100),
6254
6262
  pan: panToStereo(lt.pan ?? DEFAULT_PAN),
6255
6263
  notes
6256
6264
  };
@@ -9901,6 +9909,7 @@ var mountDAW = (target, options = {}) => {
9901
9909
  let zoomY = 100;
9902
9910
  let bpm = options.defaultBpm ?? DEFAULT_BPM;
9903
9911
  let masterVolume = options.masterVolume ?? 50;
9912
+ options.singingVoices?.setVolume(masterVolume / 100);
9904
9913
  let drumVolume = options.drumVolume ?? 80;
9905
9914
  let currentDrumPattern = refs.drumSelect.value;
9906
9915
  let currentInstrument = "";
@@ -10778,7 +10787,7 @@ var mountDAW = (target, options = {}) => {
10778
10787
  return {
10779
10788
  id: trackState?.config.id,
10780
10789
  model: lt.model,
10781
- volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * (masterVolume / 100),
10790
+ volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
10782
10791
  pan: panToStereo(lt.pan ?? DEFAULT_PAN),
10783
10792
  notes
10784
10793
  };
@@ -11787,6 +11796,7 @@ var mountDAW = (target, options = {}) => {
11787
11796
  refs.masterVolume.addEventListener("input", () => {
11788
11797
  masterVolume = Number.parseInt(refs.masterVolume.value, 10) || 0;
11789
11798
  refs.masterVolumeLabel.textContent = `${masterVolume}%`;
11799
+ options.singingVoices?.setVolume(masterVolume / 100);
11790
11800
  });
11791
11801
  refs.drumSelect.addEventListener("change", () => {
11792
11802
  currentDrumPattern = refs.drumSelect.value;
@@ -12663,11 +12673,13 @@ var mountDAW = (target, options = {}) => {
12663
12673
  masterVolume = clamp3(volume, 0, 100);
12664
12674
  refs.masterVolume.value = String(masterVolume);
12665
12675
  refs.masterVolumeLabel.textContent = `${masterVolume}%`;
12676
+ options.singingVoices?.setVolume(masterVolume / 100);
12666
12677
  },
12667
12678
  setVolume: (volume) => {
12668
12679
  masterVolume = clamp3(volume, 0, 100);
12669
12680
  refs.masterVolume.value = String(masterVolume);
12670
12681
  refs.masterVolumeLabel.textContent = `${masterVolume}%`;
12682
+ options.singingVoices?.setVolume(masterVolume / 100);
12671
12683
  },
12672
12684
  setDrumVolume: (volume) => {
12673
12685
  drumVolume = clamp3(volume, 0, 100);
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.60",
5
+ "version": "0.1.61",
6
6
  "description": "MMLを中間言語に用いた、モバイルファーストなDAW / ピアノロール打ち込みコンポーネント",
7
7
  "homepage": "https://onjmin.github.io/dtm",
8
8
  "repository": {