@onjmin/dtm 0.1.87 → 0.1.88

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.mjs CHANGED
@@ -2189,7 +2189,7 @@ var parseLyrics = (mml) => {
2189
2189
  let delay = 0;
2190
2190
  let gender = 50;
2191
2191
  let breathiness = 50;
2192
- let octaveDouble = false;
2192
+ let octaveUnison = "none";
2193
2193
  const modelMatch = rest.match(
2194
2194
  /^([a-z_][a-z0-9_]*?)(?=(?:[vqpobrghew]-?\d)|[^a-z0-9_]|$)(?::(\d+))?/i
2195
2195
  );
@@ -2267,9 +2267,9 @@ var parseLyrics = (mml) => {
2267
2267
  rest = rest.substring(eMatch[0].length).trim();
2268
2268
  continue;
2269
2269
  }
2270
- const wMatch = rest.match(/^w([01])/i);
2270
+ const wMatch = rest.match(/^w([0-3])/i);
2271
2271
  if (wMatch) {
2272
- octaveDouble = wMatch[1] === "1";
2272
+ octaveUnison = ["none", "down", "up", "both"][Number.parseInt(wMatch[1], 10)];
2273
2273
  metaTokens.push(wMatch[0]);
2274
2274
  rest = rest.substring(wMatch[0].length).trim();
2275
2275
  continue;
@@ -2293,7 +2293,7 @@ var parseLyrics = (mml) => {
2293
2293
  delay,
2294
2294
  gender,
2295
2295
  breathiness,
2296
- octaveDouble,
2296
+ octaveUnison,
2297
2297
  syllables,
2298
2298
  metaText: metaTokens.join(" "),
2299
2299
  ...lineBreaks.length > 0 ? { lineBreaks } : {}
@@ -2890,8 +2890,19 @@ var createKoeVoice = async (ctx, destination, options) => {
2890
2890
  var PREWARM_NOTES = 3;
2891
2891
  var STREAM_LOOKAHEAD_SEC = 1.5;
2892
2892
  var STREAM_POLL_MS = 100;
2893
- var OCTAVE_DOUBLE_SEMITONES = -12;
2894
- var OCTAVE_DOUBLE_PEAK_SCALE = 0.6;
2893
+ var OCTAVE_UNISON_PEAK_SCALE = 0.6;
2894
+ var octaveUnisonOffsets = (mode) => {
2895
+ switch (mode) {
2896
+ case "down":
2897
+ return [-12];
2898
+ case "up":
2899
+ return [12];
2900
+ case "both":
2901
+ return [-12, 12];
2902
+ default:
2903
+ return [];
2904
+ }
2905
+ };
2895
2906
  var FALLBACK_MODEL = "klatt";
2896
2907
  var createSingingVoices = (ctx, destination, options = {}) => {
2897
2908
  const catalog = {};
@@ -2986,12 +2997,12 @@ var createSingingVoices = (ctx, destination, options = {}) => {
2986
2997
  vibrato: track.vibrato,
2987
2998
  expr
2988
2999
  });
2989
- if (track.octaveDouble) {
3000
+ for (const offset of octaveUnisonOffsets(track.octaveUnison)) {
2990
3001
  tasks.push({
2991
3002
  model: m,
2992
3003
  note,
2993
3004
  prevVowel,
2994
- pitch: note.pitch + OCTAVE_DOUBLE_SEMITONES,
3005
+ pitch: note.pitch + offset,
2995
3006
  vibrato: track.vibrato,
2996
3007
  expr
2997
3008
  });
@@ -3106,11 +3117,8 @@ var createSingingVoices = (ctx, destination, options = {}) => {
3106
3117
  }
3107
3118
  };
3108
3119
  dispatchNote(note.pitch, 1);
3109
- if (track.octaveDouble) {
3110
- dispatchNote(
3111
- note.pitch + OCTAVE_DOUBLE_SEMITONES,
3112
- OCTAVE_DOUBLE_PEAK_SCALE
3113
- );
3120
+ for (const offset of octaveUnisonOffsets(track.octaveUnison)) {
3121
+ dispatchNote(note.pitch + offset, OCTAVE_UNISON_PEAK_SCALE);
3114
3122
  }
3115
3123
  if (!(model.renderToCache && model.scheduleCached)) {
3116
3124
  await new Promise((resolve) => setTimeout(resolve, 0));
@@ -3175,6 +3183,7 @@ var META_DIRECTIVE = /#(inst|drum|drumfont|volume|drumvolume|reverb|reverbdecay|
3175
3183
  var TRACK_INST_DIRECTIVE = /#t(\d+)inst=([^#;\r\n]+)/gi;
3176
3184
  var TRACK_COMP_DIRECTIVE = /#t(\d+)comp=(\d+)/gi;
3177
3185
  var TRACK_WIDTH_DIRECTIVE = /#t(\d+)width=(\d+)/gi;
3186
+ var TRACK_REVERBSEND_DIRECTIVE = /#t(\d+)rev=(\d+)/gi;
3178
3187
  var TRACK_EQLOW_DIRECTIVE = /#t(\d+)eqlo=(-?\d+)/gi;
3179
3188
  var TRACK_EQMID_DIRECTIVE = /#t(\d+)eqmid=(-?\d+)/gi;
3180
3189
  var TRACK_EQHIGH_DIRECTIVE = /#t(\d+)eqhi=(-?\d+)/gi;
@@ -3241,6 +3250,14 @@ var parseMmlMeta = (mml) => {
3241
3250
  meta.trackWidth[idx] = val;
3242
3251
  }
3243
3252
  }
3253
+ for (const m of mml.matchAll(TRACK_REVERBSEND_DIRECTIVE)) {
3254
+ const idx = Number.parseInt(m[1], 10);
3255
+ const val = clamp2(Number.parseInt(m[2], 10), 0, 100);
3256
+ if (!Number.isNaN(idx) && !Number.isNaN(val)) {
3257
+ meta.trackReverbSend ??= {};
3258
+ meta.trackReverbSend[idx] = val;
3259
+ }
3260
+ }
3244
3261
  for (const m of mml.matchAll(TRACK_EQLOW_DIRECTIVE)) {
3245
3262
  const idx = Number.parseInt(m[1], 10);
3246
3263
  const val = clamp2(Number.parseInt(m[2], 10), -12, 12);
@@ -3267,7 +3284,7 @@ var parseMmlMeta = (mml) => {
3267
3284
  }
3268
3285
  return meta;
3269
3286
  };
3270
- var stripMmlMeta = (mml) => mml.replace(META_DIRECTIVE, "").replace(TRACK_INST_DIRECTIVE, "").replace(TRACK_COMP_DIRECTIVE, "").replace(TRACK_WIDTH_DIRECTIVE, "").replace(TRACK_EQLOW_DIRECTIVE, "").replace(TRACK_EQMID_DIRECTIVE, "").replace(TRACK_EQHIGH_DIRECTIVE, "");
3287
+ var stripMmlMeta = (mml) => mml.replace(META_DIRECTIVE, "").replace(TRACK_INST_DIRECTIVE, "").replace(TRACK_COMP_DIRECTIVE, "").replace(TRACK_WIDTH_DIRECTIVE, "").replace(TRACK_REVERBSEND_DIRECTIVE, "").replace(TRACK_EQLOW_DIRECTIVE, "").replace(TRACK_EQMID_DIRECTIVE, "").replace(TRACK_EQHIGH_DIRECTIVE, "");
3271
3288
  var formatMmlMeta = (meta, space = "") => {
3272
3289
  const parts = [];
3273
3290
  if (meta.instrument) parts.push(`#inst=${meta.instrument}`);
@@ -3306,6 +3323,11 @@ var formatMmlMeta = (meta, space = "") => {
3306
3323
  if (val !== 100) parts.push(`#t${idx}width=${val}`);
3307
3324
  }
3308
3325
  }
3326
+ if (meta.trackReverbSend) {
3327
+ for (const [idx, val] of Object.entries(meta.trackReverbSend)) {
3328
+ if (val !== 0) parts.push(`#t${idx}rev=${val}`);
3329
+ }
3330
+ }
3309
3331
  if (meta.trackEqLow) {
3310
3332
  for (const [idx, val] of Object.entries(meta.trackEqLow)) {
3311
3333
  if (val !== 0) parts.push(`#t${idx}eqlo=${val}`);
@@ -7621,11 +7643,14 @@ var DAW_CSS = `
7621
7643
  user-select: none;
7622
7644
  }
7623
7645
  .dtm-player-balloon {
7624
- position: absolute;
7625
- bottom: calc(100% + 6px);
7626
- left: 50%;
7627
- transform: translateX(-50%);
7628
- z-index: 100;
7646
+ /* body \u76F4\u4E0B\u306B\u751F\u6210\u3055\u308C\u3001JS(positionBalloon)\u304C\u6BCE\u56DE left/top \u3092\u30A2\u30F3\u30AB\u30FC\u306E\u753B\u9762\u5EA7\u6A19\u3067
7647
+ \u8A2D\u5B9A\u3059\u308B\u3002overflow:hidden \u306A\u7956\u5148\uFF08\u6295\u7A3F\u30AB\u30FC\u30C9\u7B49\uFF09\u306B\u30AF\u30EA\u30C3\u30D7\u3055\u308C\u306A\u3044\u3088\u3046 fixed \u3067\u6D6E\u304B\u305B\u308B\u3002
7648
+ top \u306F\u30A2\u30F3\u30AB\u30FC\u4E0A\u7AEF-6px\u3001transform \u3067\u81EA\u8EAB\u306E\u5DE6\u4E0B\u89D2\u3092\u305D\u306E\u70B9\u306B\u5408\u308F\u305B\u308B\u3002 */
7649
+ position: fixed;
7650
+ left: 0;
7651
+ top: 0;
7652
+ transform: translate(-50%, -100%);
7653
+ z-index: 1000;
7629
7654
  display: none;
7630
7655
  pointer-events: none;
7631
7656
  font-family: var(--dtm-font);
@@ -7654,8 +7679,8 @@ var DAW_CSS = `
7654
7679
  animation: dtm-balloon-fade-in 0.1s steps(2);
7655
7680
  }
7656
7681
  @keyframes dtm-balloon-fade-in {
7657
- from { opacity: 0; transform: translateX(-50%) translateY(4px); }
7658
- to { opacity: 1; transform: translateX(-50%) translateY(0); }
7682
+ from { opacity: 0; transform: translate(-50%, -100%) translateY(4px); }
7683
+ to { opacity: 1; transform: translate(-50%, -100%) translateY(0); }
7659
7684
  }
7660
7685
  @keyframes dtm-emoji-jump {
7661
7686
  0% { transform: translateY(0); }
@@ -8078,6 +8103,27 @@ var LYRIC_MODEL_LABELS = {
8078
8103
  };
8079
8104
  var activeBalloonEl = null;
8080
8105
  var activeBalloonTimer = null;
8106
+ var balloonAnchors = /* @__PURE__ */ new WeakMap();
8107
+ var positionBalloon = (balloonEl) => {
8108
+ const anchor = balloonAnchors.get(balloonEl);
8109
+ if (!anchor) return;
8110
+ const rect = anchor.getBoundingClientRect();
8111
+ balloonEl.style.left = `${rect.left + rect.width / 2}px`;
8112
+ balloonEl.style.top = `${rect.top - 6}px`;
8113
+ };
8114
+ var balloonListenersBound = false;
8115
+ var ensureBalloonListeners = () => {
8116
+ if (balloonListenersBound || typeof window === "undefined") return;
8117
+ balloonListenersBound = true;
8118
+ const reposition = () => {
8119
+ if (activeBalloonEl) positionBalloon(activeBalloonEl);
8120
+ };
8121
+ window.addEventListener("scroll", reposition, {
8122
+ capture: true,
8123
+ passive: true
8124
+ });
8125
+ window.addEventListener("resize", reposition, { passive: true });
8126
+ };
8081
8127
  var hideActiveBalloon = () => {
8082
8128
  if (activeBalloonEl) {
8083
8129
  activeBalloonEl.classList.remove("dtm-player-balloon--visible");
@@ -8089,6 +8135,7 @@ var hideActiveBalloon = () => {
8089
8135
  }
8090
8136
  };
8091
8137
  var showBalloon = (balloonEl) => {
8138
+ positionBalloon(balloonEl);
8092
8139
  if (activeBalloonEl === balloonEl) {
8093
8140
  if (activeBalloonTimer) {
8094
8141
  clearTimeout(activeBalloonTimer);
@@ -8353,6 +8400,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
8353
8400
  const doc = target.ownerDocument ?? document;
8354
8401
  const root = doc.createElement("div");
8355
8402
  root.className = "dtm-daw dtm-player";
8403
+ const playerBalloons = [];
8356
8404
  const head = doc.createElement("div");
8357
8405
  head.className = "dtm-player-head";
8358
8406
  const playBtn = doc.createElement("button");
@@ -8698,7 +8746,10 @@ var mountMmlPlayer = (target, mml, options = {}) => {
8698
8746
  balloon.className = "dtm-player-balloon";
8699
8747
  const modelKey = lt.model.toLowerCase();
8700
8748
  balloon.textContent = LYRIC_MODEL_LABELS[modelKey] ?? lt.model;
8701
- em.appendChild(balloon);
8749
+ balloonAnchors.set(balloon, em);
8750
+ doc.body.appendChild(balloon);
8751
+ playerBalloons.push(balloon);
8752
+ ensureBalloonListeners();
8702
8753
  em.addEventListener("mouseenter", () => {
8703
8754
  showBalloon(balloon);
8704
8755
  });
@@ -9159,7 +9210,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
9159
9210
  delaySend: (lt.delay ?? 0) / 100,
9160
9211
  gender: (lt.gender ?? 50) / 100,
9161
9212
  breathiness: (lt.breathiness ?? 50) / 100,
9162
- octaveDouble: lt.octaveDouble,
9213
+ octaveUnison: lt.octaveUnison,
9163
9214
  notes
9164
9215
  };
9165
9216
  });
@@ -9295,9 +9346,10 @@ var mountMmlPlayer = (target, mml, options = {}) => {
9295
9346
  }
9296
9347
  for (const t of blinkTimers) clearTimeout(t);
9297
9348
  clearJumpTimers();
9298
- if (activeBalloonEl && root.contains(activeBalloonEl)) {
9349
+ if (activeBalloonEl && playerBalloons.includes(activeBalloonEl)) {
9299
9350
  hideActiveBalloon();
9300
9351
  }
9352
+ for (const balloon of playerBalloons) balloon.remove();
9301
9353
  root.remove();
9302
9354
  consentOverlayEl?.remove();
9303
9355
  closeInfoModal();
@@ -12999,14 +13051,22 @@ var VIBRATO_INFO_HTML = `
12999
13051
  <p>\u30D4\u30C3\u30C1\u3092\u63FA\u3089\u3059\u52B9\u679C\u306A\u306E\u3067\u3001\u58F0\u8CEA\u305D\u306E\u3082\u306E\u3092\u5909\u3048\u308B\u30B8\u30A7\u30F3\u30C0\u30FC/\u30D6\u30EC\u30B7\u30CD\u30B9\u3068\u306F\u72EC\u7ACB\u3057\u3066\u7D44\u307F\u5408\u308F\u305B\u3089\u308C\u307E\u3059\u3002\u901F\u3055\u30FB\u6DF1\u3055\u306F\u8ABF\u6574\u3067\u304D\u307E\u305B\u3093\uFF08\u6B4C\u3068\u3057\u3066\u7834\u7DBB\u3057\u306B\u304F\u3044\u63A7\u3048\u3081\u306A\u91CF\u306B\u56FA\u5B9A\uFF09\u3002\u66F2\u3084\u7B87\u6240\u3054\u3068\u306B\u639B\u3051\u305F\u3044/\u639B\u3051\u305F\u304F\u306A\u3044\u304C\u3042\u308B\u5834\u5408\u306F\u3001\u30C8\u30E9\u30C3\u30AF\u3092\u5206\u3051\u3066\u6B4C\u8A5E\u3092\u66F8\u3044\u3066\u304F\u3060\u3055\u3044\u3002</p>
13000
13052
  </div>
13001
13053
  `;
13002
- var OCTAVE_DOUBLE_INFO_HTML = `
13054
+ var OCTAVE_UNISON_TOKEN = {
13055
+ none: "",
13056
+ down: "w1",
13057
+ up: "w2",
13058
+ both: "w3"
13059
+ };
13060
+ var OCTAVE_UNISON_INFO_HTML = `
13003
13061
  <div class="dtm-modal-body-content">
13004
13062
  <h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
13005
- <p>ON\u306B\u3059\u308B\u3068\u3001\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u306E\u5404\u97F3\u7BC0\u30921\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0B\uFF08\u63A7\u3048\u3081\u306A\u97F3\u91CF\uFF09\u3067\u540C\u6642\u306B\u91CD\u306D\u3066\u767A\u97F3\u3057\u307E\u3059\u3002\u58F0\u306B\u539A\u307F\u30FB\u30D1\u30EF\u30FC\u3092\u8DB3\u3059\u300C\u30AA\u30AF\u30BF\u30FC\u30D6\u30C0\u30D6\u30EA\u30F3\u30B0\u300D\u3068\u3044\u3046\u5B9A\u756A\u306E\u30DC\u30FC\u30AB\u30EB\u52A0\u5DE5\u3067\u3059\u3002</p>
13063
+ <p>\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u306E\u5404\u97F3\u7BC0\u306B\u3001\u3082\u30461\u58F0\u30921\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0A/\u4E0B/\u4E21\u65B9\uFF08\u63A7\u3048\u3081\u306A\u97F3\u91CF\uFF09\u3067\u540C\u6642\u306B\u91CD\u306D\u3066\u767A\u97F3\u3057\u307E\u3059\u3002\u58F0\u306B\u539A\u307F\u30FB\u30D1\u30EF\u30FC\u3092\u8DB3\u3059\u300C\u30AA\u30AF\u30BF\u30FC\u30D6\u30E6\u30CB\u30BE\u30F3\uFF08\u30C0\u30D6\u30EA\u30F3\u30B0\uFF09\u300D\u3068\u3044\u3046\u5B9A\u756A\u306E\u30DC\u30FC\u30AB\u30EB\u52A0\u5DE5\u3067\u3059\u3002</p>
13064
+ <h4>\u4E0B\u30FB\u4E0A\u30FB\u4E21\u65B9\u306E\u9055\u3044</h4>
13065
+ <p>\u300C\u4E0B\u300D\u306F\u58F0\u306B\u91CD\u307F\u30FB\u30D1\u30EF\u30FC\u3092\u8DB3\u3059\u5B9A\u756A\u306E\u4F7F\u3044\u65B9\uFF08\u30ED\u30C3\u30AF/EDM\u306E\u30D0\u30C3\u30AD\u30F3\u30B0\u7B49\uFF09\u3002\u300C\u4E0A\u300D\u306F\u592A\u3055\u3067\u306F\u306A\u304F\u714C\u3073\u3084\u304B\u3055\u30FB\u53EF\u6190\u3055\u3092\u8DB3\u3059\u4F7F\u3044\u65B9\uFF08\u30A2\u30CB\u30BD\u30F3/\u30CF\u30E2\u30EA\u7B49\uFF09\u3002\u300C\u4E21\u65B9\u300D\u306F\u4E0A\u4E0B\u540C\u6642\u306B\u91CD\u306D\u308B\u7279\u6B8A\u306A\u52B9\u679C\u3067\u3001\u30AD\u30E3\u30E9\u30AF\u30BF\u30FC\u6027\u3092\u5F37\u304F\u51FA\u3057\u305F\u3044\u3068\u304D\u306B\u3002</p>
13006
13066
  <h4>\u4F7F\u3044\u3069\u3053\u308D</h4>
13007
13067
  <p>\u30B5\u30D3\u306E\u6C7A\u3081\u306E\u30D5\u30EC\u30FC\u30BA\u3001\u30ED\u30DC\u30C3\u30C8\u7684/\u30C0\u30FC\u30AF\u306A\u8CEA\u611F\u306E\u6F14\u51FA\u3001\u30E6\u30CB\u30BE\u30F3\u30CF\u30FC\u30E2\u30CB\u30FC\u306A\u3069\u3067\u3088\u304F\u4F7F\u308F\u308C\u307E\u3059\u3002\u66F2\u5168\u4F53\u306B\u639B\u3051\u3063\u3071\u306A\u3057\u306B\u3059\u308B\u3068\u5E38\u306B\u304F\u3069\u3044\u5370\u8C61\u306B\u306A\u308A\u3084\u3059\u3044\u306E\u3067\u3001\u30C8\u30E9\u30C3\u30AF\u3092\u5206\u3051\u3066\u4F7F\u3044\u305F\u3044\u7B87\u6240\u3060\u3051\u306B\u7D5E\u308B\u306E\u304C\u304A\u3059\u3059\u3081\u3067\u3059\u3002</p>
13008
13068
  <h4>\u4ED6\u306E\u8A2D\u5B9A\u3068\u306E\u517C\u306D\u5408\u3044</h4>
13009
- <p>\u91CD\u306D\u308B\u58F0\u306B\u3082\u540C\u3058\u30D3\u30D6\u30E9\u30FC\u30C8/\u30B8\u30A7\u30F3\u30C0\u30FC/\u30D6\u30EC\u30B7\u30CD\u30B9/\u30EA\u30D0\u30FC\u30D6\u9001\u308A/\u30C7\u30A3\u30EC\u30A4\u9001\u308A\u306E\u8A2D\u5B9A\u304C\u305D\u306E\u307E\u307E\u9069\u7528\u3055\u308C\u307E\u3059\u3002\u97F3\u91CF\u6BD4\u30FB\u97F3\u7A0B\u5DEE\uFF081\u30AA\u30AF\u30BF\u30FC\u30D6\u56FA\u5B9A\uFF09\u306F\u8ABF\u6574\u3067\u304D\u307E\u305B\u3093\u3002\u5408\u6210\u304C\u5358\u7D14\u306B2\u500D\u8D70\u308B\u305F\u3081\u3001\u97F3\u6570\u306E\u591A\u3044\u30C8\u30E9\u30C3\u30AF\u3067\u306F\u3084\u3084\u91CD\u304F\u306A\u308A\u307E\u3059\u3002</p>
13069
+ <p>\u91CD\u306D\u308B\u58F0\u306B\u3082\u540C\u3058\u30D3\u30D6\u30E9\u30FC\u30C8/\u30B8\u30A7\u30F3\u30C0\u30FC/\u30D6\u30EC\u30B7\u30CD\u30B9/\u30EA\u30D0\u30FC\u30D6\u9001\u308A/\u30C7\u30A3\u30EC\u30A4\u9001\u308A\u306E\u8A2D\u5B9A\u304C\u305D\u306E\u307E\u307E\u9069\u7528\u3055\u308C\u307E\u3059\u3002\u97F3\u91CF\u6BD4\u30FB\u97F3\u7A0B\u5DEE\uFF081\u30AA\u30AF\u30BF\u30FC\u30D6\u56FA\u5B9A\uFF09\u306F\u8ABF\u6574\u3067\u304D\u307E\u305B\u3093\u3002\u300C\u4E21\u65B9\u300D\u306F\u5408\u6210\u304C3\u500D\u8D70\u308B\u305F\u3081\u3001\u97F3\u6570\u306E\u591A\u3044\u30C8\u30E9\u30C3\u30AF\u3067\u306F\u3084\u3084\u91CD\u304F\u306A\u308A\u307E\u3059\u3002</p>
13010
13070
  </div>
13011
13071
  `;
13012
13072
  var GENDER_INFO_HTML = `
@@ -13121,6 +13181,16 @@ var TRACK_WIDTH_INFO_HTML = `
13121
13181
  <p>\u30B9\u30DE\u30DB\u306E\u30B9\u30D4\u30FC\u30AB\u30FC1\u500B\u306A\u3069\u3001\u30E2\u30CE\u30E9\u30EB\u306B\u8FD1\u3044\u74B0\u5883\u3067\u518D\u751F\u3059\u308B\u3068\u97F3\u304C\u8584\u304F/\u4F4D\u76F8\u304C\u4E71\u308C\u3066\u805E\u3053\u3048\u308B\u3053\u3068\u304C\u3042\u308A\u307E\u3059\uFF08\u5DE6\u53F3\u306E\u5DEE\u5206\u3092\u8A87\u5F35\u3057\u3066\u3044\u308B\u305F\u3081\u3001\u8DB3\u3057\u5408\u308F\u305B\u308B\u3068\u6253\u3061\u6D88\u3057\u5408\u3046\u6210\u5206\u304C\u5897\u3048\u308B\uFF09\u3002\u4E3B\u65CB\u5F8B\u3084\u30DC\u30FC\u30AB\u30EB\u306F\u4E2D\u592E\u4ED8\u8FD1\u3067\u72ED\u3081\u3001\u30D1\u30C3\u30C9\u3084\u30B7\u30F3\u30BB\u306E\u88C5\u98FE\u30D1\u30FC\u30C8\u306F\u5E83\u3052\u308B\u3001\u3068\u3044\u3046\u306E\u304C\u30DF\u30C3\u30AF\u30B9\u306E\u5B9A\u77F3\u3067\u3059\u3002</p>
13122
13182
  </div>
13123
13183
  `;
13184
+ var TRACK_REVERBSEND_INFO_HTML = `
13185
+ <div class="dtm-modal-body-content">
13186
+ <h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
13187
+ <p>\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u306E\u97F3\u3092\u3001\u30DE\u30B9\u30BF\u30EA\u30D0\u30FC\u30D6\uFF08[reverb]\u30D1\u30CD\u30EB\u306EDecay/Pre Delay/Mix\uFF09\u3078\u3069\u308C\u3060\u3051\u9001\u308B\u304B\u3092 0-100% \u3067\u6C7A\u3081\u307E\u3059\u30020\u306A\u3089\u9001\u3089\u306A\u3044\uFF1D\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u306B\u306F\u30EA\u30D0\u30FC\u30D6\u304C\u639B\u304B\u308A\u307E\u305B\u3093\u3002</p>
13188
+ <h4>\u300C\u58F0\u3060\u3051\u30EA\u30D0\u30FC\u30D6\u300D\u3092\u4F5C\u308B\u306B\u306F</h4>
13189
+ <p>\u30EA\u30D0\u30FC\u30D6\u306F\u5168\u30C8\u30E9\u30C3\u30AF\u3078\u4E00\u5F8B\u3067\u639B\u304B\u308B\u308F\u3051\u3067\u306F\u306A\u304F\u3001\u3053\u306E\u9001\u308A\u91CF\u3067\u500B\u5225\u306B\u6C7A\u307E\u308A\u307E\u3059\u3002\u30DC\u30FC\u30AB\u30EB\u306E\u30C8\u30E9\u30C3\u30AF\u3060\u3051\u9001\u308A\u91CF\u3092\u4E0A\u3052\u3001\u4ED6\u306E\u697D\u5668\u30C8\u30E9\u30C3\u30AF\u306F0\u306E\u307E\u307E\u306B\u3059\u308C\u3070\u3001\u58F0\u3060\u3051\u306B\u30EA\u30D0\u30FC\u30D6\u3092\u639B\u3051\u3089\u308C\u307E\u3059\u3002\u4F4E\u57DF\u306E\u697D\u5668\uFF08\u30D9\u30FC\u30B9\u30FB\u30AD\u30C3\u30AF\u7B49\uFF09\u306F\u9001\u3089\u306A\u3044\u3001\u30DC\u30FC\u30AB\u30EB\u3084\u30D1\u30C3\u30C9\u306F\u591A\u3081\u306B\u9001\u308B\u3001\u3068\u3044\u3046\u306E\u304C\u30DF\u30C3\u30AF\u30B9\u306E\u5B9A\u77F3\u3067\u3059\u3002</p>
13190
+ <h4>[reverb]\u30D1\u30CD\u30EB\u306EMix\u3068\u306E\u95A2\u4FC2</h4>
13191
+ <p>Mix\u306F\u300C\u9001\u3089\u308C\u3066\u304D\u305F\u97F3\u3092\u3069\u308C\u3060\u3051\u8FD4\u3059\u304B\u300D\u3068\u3044\u3046\u5168\u4F53\u306E\u8FD4\u308A\u91CF\u3067\u3059\u3002\u5404\u30C8\u30E9\u30C3\u30AF\u306E\u9001\u308A\u91CF\u304C0\u306A\u3089\u3001Mix\u3092\u4E0A\u3052\u3066\u3082\u4F55\u3082\u8FD4\u3063\u3066\u304D\u307E\u305B\u3093\u3002\u307E\u305A\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u306E\u9001\u308A\u91CF\u3092\u6C7A\u3081\u3066\u304B\u3089\u3001Mix\u3067\u5168\u4F53\u306E\u639B\u304B\u308A\u5177\u5408\u3092\u5FAE\u8ABF\u6574\u3057\u3066\u304F\u3060\u3055\u3044\u3002</p>
13192
+ </div>
13193
+ `;
13124
13194
  var AUTO_MASTER_INFO_HTML = `
13125
13195
  <div class="dtm-modal-body-content">
13126
13196
  <h4>\u304A\u307E\u304B\u305B\u30DE\u30B9\u30BF\u30EA\u30F3\u30B0\u3068\u306F</h4>
@@ -13541,7 +13611,7 @@ var mountDAW = (target, options = {}) => {
13541
13611
  vocalDelay: t.vocalDelay,
13542
13612
  vocalGender: t.vocalGender,
13543
13613
  vocalBreathiness: t.vocalBreathiness,
13544
- vocalOctaveDouble: t.vocalOctaveDouble
13614
+ vocalOctaveUnison: t.vocalOctaveUnison
13545
13615
  };
13546
13616
  if (lyricsDebounceTimer) clearTimeout(lyricsDebounceTimer);
13547
13617
  lyricsDebounceTimer = setTimeout(() => {
@@ -13606,10 +13676,11 @@ var mountDAW = (target, options = {}) => {
13606
13676
  vocalDelay: 0,
13607
13677
  vocalGender: 50,
13608
13678
  vocalBreathiness: 50,
13609
- vocalOctaveDouble: false,
13679
+ vocalOctaveUnison: "none",
13610
13680
  trackInstrument: "",
13611
13681
  trackCompression: 0,
13612
13682
  trackWidth: 100,
13683
+ trackReverbSend: 0,
13613
13684
  trackEqLow: 0,
13614
13685
  trackEqMid: 0,
13615
13686
  trackEqHigh: 0
@@ -13636,7 +13707,7 @@ var mountDAW = (target, options = {}) => {
13636
13707
  delay: t.vocalDelay,
13637
13708
  gender: t.vocalGender,
13638
13709
  breathiness: t.vocalBreathiness,
13639
- octaveDouble: t.vocalOctaveDouble,
13710
+ octaveUnison: t.vocalOctaveUnison,
13640
13711
  syllables
13641
13712
  });
13642
13713
  });
@@ -14446,7 +14517,7 @@ var mountDAW = (target, options = {}) => {
14446
14517
  delaySend: (lt.delay ?? 0) / 100,
14447
14518
  gender: (lt.gender ?? 50) / 100,
14448
14519
  breathiness: (lt.breathiness ?? 50) / 100,
14449
- octaveDouble: lt.octaveDouble,
14520
+ octaveUnison: lt.octaveUnison,
14450
14521
  notes
14451
14522
  };
14452
14523
  }) : [];
@@ -14608,6 +14679,12 @@ var mountDAW = (target, options = {}) => {
14608
14679
  <span class="dtm-label" data-dtm="track-width-label"></span>
14609
14680
  <button class="dtm-infobtn" data-dtm="track-width-info" title="\u30B9\u30C6\u30EC\u30AA\u5E45\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
14610
14681
  </div>
14682
+ <div class="dtm-row">
14683
+ <span class="dtm-label">\u30EA\u30D0\u30FC\u30D6\u9001\u308A</span>
14684
+ <input type="range" class="dtm-range dtm-grow" data-dtm="track-reverb-send" min="0" max="100" aria-label="\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u306E\u30DE\u30B9\u30BF\u30EA\u30D0\u30FC\u30D6\u3078\u306E\u9001\u308A\u91CF\uFF080=\u639B\u304B\u3089\u306A\u3044\uFF09">
14685
+ <span class="dtm-label" data-dtm="track-reverb-send-label"></span>
14686
+ <button class="dtm-infobtn" data-dtm="track-reverb-send-info" title="\u30EA\u30D0\u30FC\u30D6\u9001\u308A\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
14687
+ </div>
14611
14688
  </details>`;
14612
14689
  const volInput = refs.trackBody.querySelector(
14613
14690
  '[data-dtm="track-vol"]'
@@ -14712,6 +14789,28 @@ var mountDAW = (target, options = {}) => {
14712
14789
  trackWidthInfo.addEventListener("click", () => {
14713
14790
  showModal("\u30B9\u30C6\u30EC\u30AA\u5E45\u306E\u89E3\u8AAC", TRACK_WIDTH_INFO_HTML);
14714
14791
  });
14792
+ const trackReverbSendInput = refs.trackBody.querySelector(
14793
+ '[data-dtm="track-reverb-send"]'
14794
+ );
14795
+ const trackReverbSendLabel = refs.trackBody.querySelector(
14796
+ '[data-dtm="track-reverb-send-label"]'
14797
+ );
14798
+ const trackReverbSendInfo = refs.trackBody.querySelector(
14799
+ '[data-dtm="track-reverb-send-info"]'
14800
+ );
14801
+ trackReverbSendInput.value = String(active.trackReverbSend);
14802
+ trackReverbSendLabel.textContent = `${active.trackReverbSend}%`;
14803
+ trackReverbSendInput.addEventListener("input", () => {
14804
+ active.trackReverbSend = Number.parseInt(trackReverbSendInput.value, 10);
14805
+ trackReverbSendLabel.textContent = `${active.trackReverbSend}%`;
14806
+ options.onTrackReverbSendChange?.(
14807
+ active.config.id,
14808
+ active.trackReverbSend
14809
+ );
14810
+ });
14811
+ trackReverbSendInfo.addEventListener("click", () => {
14812
+ showModal("\u30EA\u30D0\u30FC\u30D6\u9001\u308A\u306E\u89E3\u8AAC", TRACK_REVERBSEND_INFO_HTML);
14813
+ });
14715
14814
  const instRow = document.createElement("div");
14716
14815
  instRow.className = "dtm-row";
14717
14816
  instRow.innerHTML = `<span class="dtm-label">\u697D\u5668</span>`;
@@ -14848,10 +14947,14 @@ var mountDAW = (target, options = {}) => {
14848
14947
  <button class="dtm-infobtn" data-dtm="lyric-vibrato-info" title="\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
14849
14948
  </div>
14850
14949
  <div class="dtm-row">
14851
- <span class="dtm-label" style="display:inline-flex;align-items:center;gap:2px">
14852
- <input type="checkbox" data-dtm="lyric-octave-double" aria-label="\u30AA\u30AF\u30BF\u30FC\u30D6\u30C0\u30D6\u30EB">\u30AA\u30AF\u30BF\u30FC\u30D6\u30C0\u30D6\u30EB
14853
- </span>
14854
- <button class="dtm-infobtn" data-dtm="lyric-octave-double-info" title="\u30AA\u30AF\u30BF\u30FC\u30D6\u30C0\u30D6\u30EB\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
14950
+ <span class="dtm-label">\u30AA\u30AF\u30BF\u30FC\u30D6\u30E6\u30CB\u30BE\u30F3</span>
14951
+ <select class="dtm-select dtm-grow" data-dtm="lyric-octave-unison" aria-label="\u30AA\u30AF\u30BF\u30FC\u30D6\u30E6\u30CB\u30BE\u30F3\uFF08\u3082\u30461\u58F0\u3092\u4E0A/\u4E0B\u306B\u91CD\u306D\u308B\uFF09">
14952
+ <option value="none">\u306A\u3057</option>
14953
+ <option value="down">\u4E0B (-1oct)</option>
14954
+ <option value="up">\u4E0A (+1oct)</option>
14955
+ <option value="both">\u4E0A\u4E0B\u4E21\u65B9</option>
14956
+ </select>
14957
+ <button class="dtm-infobtn" data-dtm="lyric-octave-unison-info" title="\u30AA\u30AF\u30BF\u30FC\u30D6\u30E6\u30CB\u30BE\u30F3\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
14855
14958
  </div>
14856
14959
  </details>
14857
14960
  <textarea class="dtm-textarea" data-dtm="lyric-input" rows="2" placeholder="\u3072\u3089\u304C\u306A\u30FB\u30AB\u30BF\u30AB\u30CA\u3067\u6B4C\u8A5E\uFF08\u4F8B: \u3069\u308C\u307F\u3075\u3041\u305D\u3089\u3057\u3069\uFF09"></textarea>
@@ -14944,14 +15047,14 @@ var mountDAW = (target, options = {}) => {
14944
15047
  lyricVibratoInfo.addEventListener("click", () => {
14945
15048
  showModal("\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8\u89E3\u8AAC", VIBRATO_INFO_HTML);
14946
15049
  });
14947
- const lyricOctaveDouble = lyricDiv.querySelector(
14948
- '[data-dtm="lyric-octave-double"]'
15050
+ const lyricOctaveUnison = lyricDiv.querySelector(
15051
+ '[data-dtm="lyric-octave-unison"]'
14949
15052
  );
14950
- const lyricOctaveDoubleInfo = lyricDiv.querySelector(
14951
- '[data-dtm="lyric-octave-double-info"]'
15053
+ const lyricOctaveUnisonInfo = lyricDiv.querySelector(
15054
+ '[data-dtm="lyric-octave-unison-info"]'
14952
15055
  );
14953
- lyricOctaveDoubleInfo.addEventListener("click", () => {
14954
- showModal("\u30AA\u30AF\u30BF\u30FC\u30D6\u30C0\u30D6\u30EB\u89E3\u8AAC", OCTAVE_DOUBLE_INFO_HTML);
15056
+ lyricOctaveUnisonInfo.addEventListener("click", () => {
15057
+ showModal("\u30AA\u30AF\u30BF\u30FC\u30D6\u30E6\u30CB\u30BE\u30F3\u89E3\u8AAC", OCTAVE_UNISON_INFO_HTML);
14955
15058
  });
14956
15059
  const lyricTerms = lyricDiv.querySelector(
14957
15060
  '[data-dtm="lyric-terms"]'
@@ -15023,7 +15126,7 @@ var mountDAW = (target, options = {}) => {
15023
15126
  lyricBreathiness.value = String(active.vocalBreathiness);
15024
15127
  lyricBreathinessLabel.textContent = `${active.vocalBreathiness}`;
15025
15128
  lyricVibrato.checked = active.vocalVibrato;
15026
- lyricOctaveDouble.checked = active.vocalOctaveDouble;
15129
+ lyricOctaveUnison.value = active.vocalOctaveUnison;
15027
15130
  const updateLyricCount = () => {
15028
15131
  const n = normalizeLyrics(lyricInput.value).length;
15029
15132
  lyricCount.textContent = active.lyricModel && n > 0 ? `${n}\u97F3\u7BC0` : "";
@@ -15145,8 +15248,8 @@ var mountDAW = (target, options = {}) => {
15145
15248
  active.vocalVibrato = lyricVibrato.checked;
15146
15249
  fireLyricsChange(active);
15147
15250
  });
15148
- lyricOctaveDouble.addEventListener("change", () => {
15149
- active.vocalOctaveDouble = lyricOctaveDouble.checked;
15251
+ lyricOctaveUnison.addEventListener("change", () => {
15252
+ active.vocalOctaveUnison = lyricOctaveUnison.value;
15150
15253
  fireLyricsChange(active);
15151
15254
  });
15152
15255
  lyricInput.addEventListener("input", () => {
@@ -15277,6 +15380,7 @@ var mountDAW = (target, options = {}) => {
15277
15380
  const trackInstrumentsForMeta = {};
15278
15381
  const trackCompressionForMeta = {};
15279
15382
  const trackWidthForMeta = {};
15383
+ const trackReverbSendForMeta = {};
15280
15384
  const trackEqLowForMeta = {};
15281
15385
  const trackEqMidForMeta = {};
15282
15386
  const trackEqHighForMeta = {};
@@ -15285,6 +15389,8 @@ var mountDAW = (target, options = {}) => {
15285
15389
  if (t.trackCompression !== 0)
15286
15390
  trackCompressionForMeta[i2] = t.trackCompression;
15287
15391
  if (t.trackWidth !== 100) trackWidthForMeta[i2] = t.trackWidth;
15392
+ if (t.trackReverbSend !== 0)
15393
+ trackReverbSendForMeta[i2] = t.trackReverbSend;
15288
15394
  if (t.trackEqLow !== 0) trackEqLowForMeta[i2] = t.trackEqLow;
15289
15395
  if (t.trackEqMid !== 0) trackEqMidForMeta[i2] = t.trackEqMid;
15290
15396
  if (t.trackEqHigh !== 0) trackEqHighForMeta[i2] = t.trackEqHigh;
@@ -15292,6 +15398,7 @@ var mountDAW = (target, options = {}) => {
15292
15398
  const trackInstMeta = Object.keys(trackInstrumentsForMeta).length > 0 ? trackInstrumentsForMeta : void 0;
15293
15399
  const trackCompMeta = Object.keys(trackCompressionForMeta).length > 0 ? trackCompressionForMeta : void 0;
15294
15400
  const trackWidthMeta = Object.keys(trackWidthForMeta).length > 0 ? trackWidthForMeta : void 0;
15401
+ const trackReverbSendMeta = Object.keys(trackReverbSendForMeta).length > 0 ? trackReverbSendForMeta : void 0;
15295
15402
  const trackEqLowMeta = Object.keys(trackEqLowForMeta).length > 0 ? trackEqLowForMeta : void 0;
15296
15403
  const trackEqMidMeta = Object.keys(trackEqMidForMeta).length > 0 ? trackEqMidForMeta : void 0;
15297
15404
  const trackEqHighMeta = Object.keys(trackEqHighForMeta).length > 0 ? trackEqHighForMeta : void 0;
@@ -15312,6 +15419,7 @@ var mountDAW = (target, options = {}) => {
15312
15419
  trackInstruments: trackInstMeta,
15313
15420
  trackCompression: trackCompMeta,
15314
15421
  trackWidth: trackWidthMeta,
15422
+ trackReverbSend: trackReverbSendMeta,
15315
15423
  trackEqLow: trackEqLowMeta,
15316
15424
  trackEqMid: trackEqMidMeta,
15317
15425
  trackEqHigh: trackEqHighMeta
@@ -15335,6 +15443,7 @@ var mountDAW = (target, options = {}) => {
15335
15443
  trackInstruments: trackInstMeta,
15336
15444
  trackCompression: trackCompMeta,
15337
15445
  trackWidth: trackWidthMeta,
15446
+ trackReverbSend: trackReverbSendMeta,
15338
15447
  trackEqLow: trackEqLowMeta,
15339
15448
  trackEqMid: trackEqMidMeta,
15340
15449
  trackEqHigh: trackEqHighMeta
@@ -15390,7 +15499,7 @@ var mountDAW = (target, options = {}) => {
15390
15499
  del: t.vocalDelay,
15391
15500
  gen: t.vocalGender,
15392
15501
  bre: t.vocalBreathiness,
15393
- dbl: t.vocalOctaveDouble
15502
+ uni: t.vocalOctaveUnison
15394
15503
  })).filter(
15395
15504
  (x2) => x2.model.length > 0 && x2.text.length > 0 && x2.notes.length > 0
15396
15505
  ).map((x2) => {
@@ -15404,7 +15513,7 @@ var mountDAW = (target, options = {}) => {
15404
15513
  x2.del === 0 ? "" : `e${x2.del}`,
15405
15514
  x2.gen === 50 ? "" : `g${x2.gen}`,
15406
15515
  x2.bre === 50 ? "" : `h${x2.bre}`,
15407
- x2.dbl ? "w1" : ""
15516
+ OCTAVE_UNISON_TOKEN[x2.uni]
15408
15517
  ].filter((s) => s.length > 0).join(" ");
15409
15518
  const head = params ? `${x2.model} ${params}` : x2.model;
15410
15519
  return `@@${x2.i} ${head} ${x2.text}`;
@@ -15604,6 +15713,11 @@ var mountDAW = (target, options = {}) => {
15604
15713
  t.trackWidth = width;
15605
15714
  options.onTrackWidthChange?.(t.config.id, width);
15606
15715
  }
15716
+ const reverbSend = meta.trackReverbSend?.[i2] ?? 0;
15717
+ if (t.trackReverbSend !== reverbSend) {
15718
+ t.trackReverbSend = reverbSend;
15719
+ options.onTrackReverbSendChange?.(t.config.id, reverbSend);
15720
+ }
15607
15721
  const eqLow = meta.trackEqLow?.[i2] ?? 0;
15608
15722
  if (t.trackEqLow !== eqLow) {
15609
15723
  t.trackEqLow = eqLow;
@@ -15641,7 +15755,7 @@ var mountDAW = (target, options = {}) => {
15641
15755
  active.vocalDelay = 0;
15642
15756
  active.vocalGender = 50;
15643
15757
  active.vocalBreathiness = 50;
15644
- active.vocalOctaveDouble = false;
15758
+ active.vocalOctaveUnison = "none";
15645
15759
  } else {
15646
15760
  for (const t of trackStates) {
15647
15761
  t.lyrics = "";
@@ -15655,7 +15769,7 @@ var mountDAW = (target, options = {}) => {
15655
15769
  t.vocalDelay = 0;
15656
15770
  t.vocalGender = 50;
15657
15771
  t.vocalBreathiness = 50;
15658
- t.vocalOctaveDouble = false;
15772
+ t.vocalOctaveUnison = "none";
15659
15773
  }
15660
15774
  }
15661
15775
  lyrics?.forEach((lt) => {
@@ -15673,7 +15787,7 @@ var mountDAW = (target, options = {}) => {
15673
15787
  t.vocalDelay = lt.delay ?? 0;
15674
15788
  t.vocalGender = lt.gender ?? 50;
15675
15789
  t.vocalBreathiness = lt.breathiness ?? 50;
15676
- t.vocalOctaveDouble = lt.octaveDouble ?? false;
15790
+ t.vocalOctaveUnison = lt.octaveUnison ?? "none";
15677
15791
  });
15678
15792
  for (const p of placements) {
15679
15793
  if (applyActiveOnly && p.trackIndex !== activeTrackIndex) continue;
@@ -15757,7 +15871,7 @@ var mountDAW = (target, options = {}) => {
15757
15871
  active.vocalDelay = 0;
15758
15872
  active.vocalGender = 50;
15759
15873
  active.vocalBreathiness = 50;
15760
- active.vocalOctaveDouble = false;
15874
+ active.vocalOctaveUnison = "none";
15761
15875
  } else {
15762
15876
  clearAll();
15763
15877
  for (const t of trackStates) t.core.setLoadMode(true);
@@ -15773,7 +15887,7 @@ var mountDAW = (target, options = {}) => {
15773
15887
  t.vocalDelay = 0;
15774
15888
  t.vocalGender = 50;
15775
15889
  t.vocalBreathiness = 50;
15776
- t.vocalOctaveDouble = false;
15890
+ t.vocalOctaveUnison = "none";
15777
15891
  }
15778
15892
  }
15779
15893
  const { placements, bpm: parsedBpm } = isAdvanced ? extractMidiPlacementsByTrack(
@@ -16073,6 +16187,10 @@ var mountDAW = (target, options = {}) => {
16073
16187
  t.trackWidth = 115;
16074
16188
  options.onTrackCompressionChange?.(t.config.id, comp);
16075
16189
  options.onTrackWidthChange?.(t.config.id, 115);
16190
+ if (!t.lyricModel) {
16191
+ t.trackReverbSend = 15;
16192
+ options.onTrackReverbSendChange?.(t.config.id, 15);
16193
+ }
16076
16194
  if (t.lyricModel) {
16077
16195
  t.vocalVibrato = true;
16078
16196
  t.vocalReverb = isMainVocal ? 15 : 30;
@@ -17133,7 +17251,7 @@ var mountDAW = (target, options = {}) => {
17133
17251
  t.vocalDelay = data.vocalDelay ?? 0;
17134
17252
  t.vocalGender = data.vocalGender ?? 50;
17135
17253
  t.vocalBreathiness = data.vocalBreathiness ?? 50;
17136
- t.vocalOctaveDouble = data.vocalOctaveDouble ?? false;
17254
+ t.vocalOctaveUnison = data.vocalOctaveUnison ?? "none";
17137
17255
  },
17138
17256
  applyTrackInstrument: (trackIndex, instrumentName) => {
17139
17257
  const t = trackStates[trackIndex];
@@ -17255,7 +17373,7 @@ var playSingingMML = async (mml, options = {}) => {
17255
17373
  delaySend: (lt.delay ?? 0) / 100,
17256
17374
  gender: (lt.gender ?? 50) / 100,
17257
17375
  breathiness: (lt.breathiness ?? 50) / 100,
17258
- octaveDouble: lt.octaveDouble,
17376
+ octaveUnison: lt.octaveUnison,
17259
17377
  notes
17260
17378
  };
17261
17379
  });
@@ -17949,6 +18067,10 @@ var createChannelStrip = (ctx, destination, options = {}) => {
17949
18067
  eqHigh.connect(compressor);
17950
18068
  compressor.connect(splitter);
17951
18069
  merger.connect(destination);
18070
+ const reverbSendGain = ctx.createGain();
18071
+ reverbSendGain.gain.value = clamp5(options.reverbSend ?? 0, 0, 100) / 100;
18072
+ merger.connect(reverbSendGain);
18073
+ if (options.reverbBus) reverbSendGain.connect(options.reverbBus);
17952
18074
  return {
17953
18075
  input,
17954
18076
  setEqLow: (db) => {
@@ -17974,6 +18096,13 @@ var createChannelStrip = (ctx, destination, options = {}) => {
17974
18096
  },
17975
18097
  setCompression: applyCompression,
17976
18098
  setWidth,
18099
+ setReverbSend: (amount) => {
18100
+ reverbSendGain.gain.setTargetAtTime(
18101
+ clamp5(amount, 0, 100) / 100,
18102
+ ctx.currentTime,
18103
+ 0.02
18104
+ );
18105
+ },
17977
18106
  dispose: () => {
17978
18107
  input.disconnect();
17979
18108
  eqLow.disconnect();
@@ -17990,6 +18119,7 @@ var createChannelStrip = (ctx, destination, options = {}) => {
17990
18119
  outL.disconnect();
17991
18120
  outR.disconnect();
17992
18121
  merger.disconnect();
18122
+ reverbSendGain.disconnect();
17993
18123
  }
17994
18124
  };
17995
18125
  };
@@ -18211,7 +18341,6 @@ var createDtmStudio = async (options = {}) => {
18211
18341
  reverbConvolver.normalize = true;
18212
18342
  const reverbWetGain = audioCtx.createGain();
18213
18343
  reverbWetGain.gain.value = reverbAmountToGain(options.reverbAmount ?? 0);
18214
- masterGain.connect(reverbPreDelay);
18215
18344
  reverbPreDelay.connect(reverbConvolver);
18216
18345
  reverbConvolver.connect(reverbWetGain);
18217
18346
  const setReverbAmount = (amount) => {
@@ -18277,7 +18406,9 @@ var createDtmStudio = async (options = {}) => {
18277
18406
  const getChannelStrip = (trackId) => {
18278
18407
  let strip = channelStrips.get(trackId);
18279
18408
  if (!strip) {
18280
- strip = createChannelStrip(audioCtx, masterGain);
18409
+ strip = createChannelStrip(audioCtx, masterGain, {
18410
+ reverbBus: reverbPreDelay
18411
+ });
18281
18412
  channelStrips.set(trackId, strip);
18282
18413
  }
18283
18414
  return strip;
@@ -18314,7 +18445,8 @@ var createDtmStudio = async (options = {}) => {
18314
18445
  voicebanks,
18315
18446
  worldlineScriptUrl: options.worldlineScriptUrl,
18316
18447
  // ボーカルトラック個別のリバーブセンド(`r`トークン)先。マスタリバーブの
18317
- // Convolver 入力へ直接センドする(masterGain 経由のドライ段は素通り)。
18448
+ // Convolver 入力へ直接センドする(PreDelayは経由しない。チャンネルストリップの
18449
+ // reverbSend とは別経路の、音節単位でより細かく制御できるセンド)。
18318
18450
  reverbBus: reverbConvolver,
18319
18451
  // ボーカルトラック個別のディレイセンド(`e`トークン)先。
18320
18452
  delayBus: delayBus.input,
@@ -18612,6 +18744,7 @@ var createDtmStudio = async (options = {}) => {
18612
18744
  onScheduleFade: scheduleFade,
18613
18745
  onTrackCompressionChange: (trackId, amount) => getChannelStrip(trackId).setCompression(amount),
18614
18746
  onTrackWidthChange: (trackId, width) => getChannelStrip(trackId).setWidth(width),
18747
+ onTrackReverbSendChange: (trackId, amount) => getChannelStrip(trackId).setReverbSend(amount),
18615
18748
  onTrackEqLowChange: (trackId, db) => getChannelStrip(trackId).setEqLow(db),
18616
18749
  onTrackEqMidChange: (trackId, db) => getChannelStrip(trackId).setEqMid(db),
18617
18750
  onTrackEqHighChange: (trackId, db) => getChannelStrip(trackId).setEqHigh(db),
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.87",
5
+ "version": "0.1.88",
6
6
  "description": "MMLを中間言語に用いた、モバイルファーストなDAW / ピアノロール打ち込みコンポーネント",
7
7
  "homepage": "https://onjmin.github.io/dtm",
8
8
  "repository": {