@onjmin/dtm 0.1.15 → 0.1.16

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
@@ -522,7 +522,7 @@ type PlayDrumEvent = {
522
522
  /** 秒 */
523
523
  duration: number;
524
524
  };
525
- type ParseMidiFn = (bytes: Uint8Array) => unknown;
525
+ type ParseMidiFn = (bytes: Uint8Array) => unknown | Promise<unknown>;
526
526
  /**
527
527
  * 永続化対象の表示・出力設定。利用側がブラウザ再訪時に復元する用途に使う。
528
528
  * (ノートやMML本体ではなく、エディタの見え方/出力の挙動の設定)
@@ -604,7 +604,7 @@ type DawInstance = {
604
604
  /** 表示・出力設定を復元する(指定したキーのみ反映。UIにも反映する)。 */
605
605
  setViewState: (state: Partial<DawViewState>) => void;
606
606
  loadMML: (mml: string) => void;
607
- loadMIDI: (bytes: Uint8Array) => void;
607
+ loadMIDI: (bytes: Uint8Array) => void | Promise<void>;
608
608
  exportMIDI: () => Blob;
609
609
  setBpm: (bpm: number) => void;
610
610
  getPlaybackState: () => PlaybackState;
@@ -1218,7 +1218,6 @@ declare const DEFAULT_CDN: {
1218
1218
  readonly soundFont: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont.mjs";
1219
1219
  readonly soundFontDrum: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_drum.mjs";
1220
1220
  readonly soundFontList: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_list.mjs";
1221
- readonly midiParser: "https://cdn.jsdelivr.net/npm/midi-parser-js@4.0.4/+esm";
1222
1221
  };
1223
1222
  type DtmStudioOptions = {
1224
1223
  /** 既存の AudioContext を使う(未指定なら内部生成)。 */
package/dist/index.d.ts CHANGED
@@ -522,7 +522,7 @@ type PlayDrumEvent = {
522
522
  /** 秒 */
523
523
  duration: number;
524
524
  };
525
- type ParseMidiFn = (bytes: Uint8Array) => unknown;
525
+ type ParseMidiFn = (bytes: Uint8Array) => unknown | Promise<unknown>;
526
526
  /**
527
527
  * 永続化対象の表示・出力設定。利用側がブラウザ再訪時に復元する用途に使う。
528
528
  * (ノートやMML本体ではなく、エディタの見え方/出力の挙動の設定)
@@ -604,7 +604,7 @@ type DawInstance = {
604
604
  /** 表示・出力設定を復元する(指定したキーのみ反映。UIにも反映する)。 */
605
605
  setViewState: (state: Partial<DawViewState>) => void;
606
606
  loadMML: (mml: string) => void;
607
- loadMIDI: (bytes: Uint8Array) => void;
607
+ loadMIDI: (bytes: Uint8Array) => void | Promise<void>;
608
608
  exportMIDI: () => Blob;
609
609
  setBpm: (bpm: number) => void;
610
610
  getPlaybackState: () => PlaybackState;
@@ -1218,7 +1218,6 @@ declare const DEFAULT_CDN: {
1218
1218
  readonly soundFont: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont.mjs";
1219
1219
  readonly soundFontDrum: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_drum.mjs";
1220
1220
  readonly soundFontList: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_list.mjs";
1221
- readonly midiParser: "https://cdn.jsdelivr.net/npm/midi-parser-js@4.0.4/+esm";
1222
1221
  };
1223
1222
  type DtmStudioOptions = {
1224
1223
  /** 既存の AudioContext を使う(未指定なら内部生成)。 */
package/dist/index.js CHANGED
@@ -1627,8 +1627,8 @@ function parseKoeHeader(headerBytes) {
1627
1627
  }
1628
1628
  var pcmBase = (jsonLength) => 8 + jsonLength;
1629
1629
  var BlobVoiceSource = class {
1630
- constructor(blob, base) {
1631
- this.blob = blob;
1630
+ constructor(blob2, base) {
1631
+ this.blob = blob2;
1632
1632
  this.base = base;
1633
1633
  }
1634
1634
  blob;
@@ -1639,8 +1639,8 @@ var BlobVoiceSource = class {
1639
1639
  }
1640
1640
  };
1641
1641
  var RangeVoiceSource = class {
1642
- constructor(url, base) {
1643
- this.url = url;
1642
+ constructor(url2, base) {
1643
+ this.url = url2;
1644
1644
  this.base = base;
1645
1645
  }
1646
1646
  url;
@@ -1656,8 +1656,8 @@ var RangeVoiceSource = class {
1656
1656
  return res.arrayBuffer();
1657
1657
  }
1658
1658
  };
1659
- async function rangeFetch(url, start, length) {
1660
- const res = await fetch(url, {
1659
+ async function rangeFetch(url2, start, length) {
1660
+ const res = await fetch(url2, {
1661
1661
  headers: { Range: `bytes=${start}-${start + length - 1}` }
1662
1662
  });
1663
1663
  if (!res.ok && res.status !== 206)
@@ -2428,22 +2428,22 @@ var createLocalBackend = async (options) => {
2428
2428
  }
2429
2429
  };
2430
2430
  };
2431
- var spawnVoiceWorker = async (url) => {
2432
- const sameOrigin = new URL(url, location.href).origin === location.origin;
2433
- if (sameOrigin) return new Worker(url);
2434
- const text = await fetch(url).then((r) => r.text());
2431
+ var spawnVoiceWorker = async (url2) => {
2432
+ const sameOrigin = new URL(url2, location.href).origin === location.origin;
2433
+ if (sameOrigin) return new Worker(url2);
2434
+ const text = await fetch(url2).then((r) => r.text());
2435
2435
  return new Worker(
2436
2436
  URL.createObjectURL(new Blob([text], { type: "text/javascript" }))
2437
2437
  );
2438
2438
  };
2439
2439
  var createWorkerBackend = async (workerUrl, options) => {
2440
- const worker = await spawnVoiceWorker(workerUrl);
2440
+ const worker2 = await spawnVoiceWorker(workerUrl);
2441
2441
  const aliasSet = /* @__PURE__ */ new Set();
2442
2442
  const pending = /* @__PURE__ */ new Map();
2443
2443
  let reqId = 0;
2444
2444
  let onReady = null;
2445
2445
  let onFail = null;
2446
- worker.onmessage = (ev) => {
2446
+ worker2.onmessage = (ev) => {
2447
2447
  const m = ev.data;
2448
2448
  if (m.type === "ready") {
2449
2449
  for (const a of m.aliases) aliasSet.add(a);
@@ -2458,14 +2458,14 @@ var createWorkerBackend = async (workerUrl, options) => {
2458
2458
  }
2459
2459
  }
2460
2460
  };
2461
- worker.onerror = (e) => {
2461
+ worker2.onerror = (e) => {
2462
2462
  const ev = e;
2463
2463
  onFail?.(new Error(ev.message || ev.error || `Event: ${ev.type}`));
2464
2464
  };
2465
2465
  await new Promise((resolve, reject) => {
2466
2466
  onReady = resolve;
2467
2467
  onFail = reject;
2468
- worker.postMessage({
2468
+ worker2.postMessage({
2469
2469
  type: "init",
2470
2470
  koe: options.koe,
2471
2471
  worldlineScriptUrl: options.worldlineScriptUrl ?? DEFAULT_WORLDLINE_SCRIPT,
@@ -2482,7 +2482,7 @@ var createWorkerBackend = async (workerUrl, options) => {
2482
2482
  m.pcm ? { pcm: m.pcm, preSec: m.preSec ?? 0, rate: m.rate ?? 1 } : null
2483
2483
  )
2484
2484
  );
2485
- worker.postMessage({
2485
+ worker2.postMessage({
2486
2486
  type: "render",
2487
2487
  id,
2488
2488
  alias,
@@ -2494,7 +2494,7 @@ var createWorkerBackend = async (workerUrl, options) => {
2494
2494
  hasAlias: (a) => aliasSet.has(a),
2495
2495
  pitchTokens: collectPitchTokens(aliasSet),
2496
2496
  renderAlias,
2497
- dispose: () => worker.terminate()
2497
+ dispose: () => worker2.terminate()
2498
2498
  };
2499
2499
  };
2500
2500
  var createKoeVoice = async (ctx, destination, options) => {
@@ -2629,7 +2629,7 @@ var createSingingVoices = (ctx, destination, options = {}) => {
2629
2629
  [FALLBACK_MODEL, createKlattVoice(ctx, destination)]
2630
2630
  ]);
2631
2631
  const loading = /* @__PURE__ */ new Map();
2632
- const load = (model) => {
2632
+ const load2 = (model) => {
2633
2633
  const m = model.toLowerCase();
2634
2634
  const ready = loaded.get(m);
2635
2635
  if (ready) return Promise.resolve(ready);
@@ -2661,7 +2661,7 @@ var createSingingVoices = (ctx, destination, options = {}) => {
2661
2661
  const loadModels = async (models) => {
2662
2662
  const set = /* @__PURE__ */ new Set();
2663
2663
  for (const m of models) if (m) set.add(m.toLowerCase());
2664
- await Promise.all([...set].map((m) => load(m)));
2664
+ await Promise.all([...set].map((m) => load2(m)));
2665
2665
  };
2666
2666
  const forEachSungNote = (track, fn) => {
2667
2667
  let prevVowel = "";
@@ -2883,21 +2883,26 @@ var shiftNotes = (cores, shiftSteps) => {
2883
2883
  // src/midi-io.ts
2884
2884
  var STEPS_PER_BEAT = 48;
2885
2885
  var analyzeMidiTracks = (midi) => {
2886
- const { track } = midi;
2886
+ const { tracks } = midi;
2887
2887
  const result = [];
2888
- for (let i = 0; i < track.length; i++) {
2888
+ for (let i = 0; i < tracks.length; i++) {
2889
2889
  const notes = [];
2890
2890
  let currentTime = 0;
2891
- for (const event of track[i].event) {
2892
- currentTime += event.deltaTime;
2893
- const data = event.data;
2894
- if (event.type === 9 && data && data[1]) {
2895
- notes.push({ pitch: data[0], channel: event.channel ?? 0 });
2896
- } else if (event.type === 8) {
2897
- for (let k = notes.length - 1; k >= 0; k--) {
2898
- if (notes[k].pitch === data[0] && notes[k].end === void 0) {
2899
- notes[k].end = currentTime;
2900
- break;
2891
+ for (const event of tracks[i]) {
2892
+ currentTime += event.delta;
2893
+ if (event.noteOn && event.noteOn.velocity > 0) {
2894
+ notes.push({
2895
+ pitch: event.noteOn.noteNumber,
2896
+ channel: event.channel ?? 0
2897
+ });
2898
+ } else if (event.noteOff || event.noteOn && event.noteOn.velocity === 0) {
2899
+ const noteOff = event.noteOff || event.noteOn;
2900
+ if (noteOff) {
2901
+ for (let k = notes.length - 1; k >= 0; k--) {
2902
+ if (notes[k].pitch === noteOff.noteNumber && notes[k].end === void 0) {
2903
+ notes[k].end = currentTime;
2904
+ break;
2905
+ }
2901
2906
  }
2902
2907
  }
2903
2908
  }
@@ -2915,51 +2920,54 @@ var analyzeMidiTracks = (midi) => {
2915
2920
  return result;
2916
2921
  };
2917
2922
  var getMidiBPM = (midi) => {
2918
- const { track } = midi;
2919
- for (const { event } of track) {
2920
- for (const { type, metaType, data } of event) {
2921
- if (type !== 255 || metaType !== 81) continue;
2922
- if (typeof data === "number") {
2923
- return 6e7 / data;
2923
+ const { tracks } = midi;
2924
+ for (const track of tracks) {
2925
+ for (const event of track) {
2926
+ if (event.setTempo && typeof event.setTempo.microsecondsPerQuarter === "number") {
2927
+ return 6e7 / event.setTempo.microsecondsPerQuarter;
2924
2928
  }
2925
- const [b1, b2, b3] = data;
2926
- return 6e7 / (b1 << 16 | b2 << 8 | b3);
2927
2929
  }
2928
2930
  }
2929
2931
  return 120;
2930
2932
  };
2931
2933
  var extractMidiPlacements = (midi, selectedTrackIndices) => {
2932
- const { track, timeDivision } = midi;
2933
- const ticksPerBeat = timeDivision;
2934
+ const { tracks, division } = midi;
2935
+ const ticksPerBeat = division;
2934
2936
  const bpm = getMidiBPM(midi);
2935
2937
  const channelNotes = {};
2936
2938
  for (const trackIdx of selectedTrackIndices) {
2937
- const trackData = track[trackIdx];
2939
+ const trackData = tracks[trackIdx];
2938
2940
  if (!trackData) continue;
2939
2941
  let currentTime = 0;
2940
- for (const event of trackData.event) {
2941
- currentTime += event.deltaTime;
2942
+ for (const event of trackData) {
2943
+ currentTime += event.delta;
2942
2944
  if (event.channel === 9) continue;
2943
- if (event.type !== 8 && event.type !== 9) continue;
2944
- const [pitch, velocity] = event.data;
2945
- const isNoteOff = event.type === 8 || !velocity;
2946
- const channel = event.channel ?? 0;
2947
- if (!channelNotes[channel]) channelNotes[channel] = [];
2948
- if (isNoteOff) {
2949
- for (let i = channelNotes[channel].length - 1; i >= 0; i--) {
2950
- const note = channelNotes[channel][i];
2951
- if (note.pitch === pitch && note.end === null) {
2952
- note.end = currentTime;
2953
- break;
2954
- }
2955
- }
2956
- } else {
2945
+ if (event.noteOn && event.noteOn.velocity > 0) {
2946
+ const pitch = event.noteOn.noteNumber;
2947
+ const velocity = event.noteOn.velocity;
2948
+ const channel = event.channel ?? 0;
2949
+ if (!channelNotes[channel]) channelNotes[channel] = [];
2957
2950
  channelNotes[channel].push({
2958
2951
  pitch,
2959
2952
  velocity,
2960
2953
  start: currentTime,
2961
2954
  end: null
2962
2955
  });
2956
+ } else if (event.noteOff || event.noteOn && event.noteOn.velocity === 0) {
2957
+ const noteOff = event.noteOff || event.noteOn;
2958
+ if (noteOff) {
2959
+ const pitch = noteOff.noteNumber;
2960
+ const channel = event.channel ?? 0;
2961
+ if (channelNotes[channel]) {
2962
+ for (let i = channelNotes[channel].length - 1; i >= 0; i--) {
2963
+ const note = channelNotes[channel][i];
2964
+ if (note.pitch === pitch && note.end === null) {
2965
+ note.end = currentTime;
2966
+ break;
2967
+ }
2968
+ }
2969
+ }
2970
+ }
2963
2971
  }
2964
2972
  }
2965
2973
  }
@@ -3072,33 +3080,36 @@ var extractMidiPlacements = (midi, selectedTrackIndices) => {
3072
3080
  return { placements, bpm };
3073
3081
  };
3074
3082
  var extractMidiPlacementsByTrack = (midi, selectedIndices, trackIds) => {
3075
- const { track, timeDivision } = midi;
3076
- const ticksPerBeat = timeDivision;
3083
+ const { tracks, division } = midi;
3084
+ const ticksPerBeat = division;
3077
3085
  const bpm = getMidiBPM(midi);
3078
3086
  const ticksPerStep = ticksPerBeat / STEPS_PER_BEAT;
3079
3087
  const placements = [];
3080
3088
  selectedIndices.forEach((midiIdx, lane) => {
3081
3089
  if (lane >= trackIds.length) return;
3082
- const trackData = track[midiIdx];
3090
+ const trackData = tracks[midiIdx];
3083
3091
  if (!trackData) return;
3084
3092
  const trackId = trackIds[lane];
3085
3093
  const active = [];
3086
3094
  let currentTime = 0;
3087
- for (const event of trackData.event) {
3088
- currentTime += event.deltaTime;
3095
+ for (const event of trackData) {
3096
+ currentTime += event.delta;
3089
3097
  if (event.channel === 9) continue;
3090
- if (event.type !== 8 && event.type !== 9) continue;
3091
- const [pitch, velocity] = event.data;
3092
- const isOff = event.type === 8 || !velocity;
3093
- if (isOff) {
3094
- for (let i = active.length - 1; i >= 0; i--) {
3095
- if (active[i].pitch === pitch && active[i].end === null) {
3096
- active[i].end = currentTime;
3097
- break;
3098
+ if (event.noteOn && event.noteOn.velocity > 0) {
3099
+ const pitch = event.noteOn.noteNumber;
3100
+ const velocity = event.noteOn.velocity;
3101
+ active.push({ pitch, velocity, start: currentTime, end: null });
3102
+ } else if (event.noteOff || event.noteOn && event.noteOn.velocity === 0) {
3103
+ const noteOff = event.noteOff || event.noteOn;
3104
+ if (noteOff) {
3105
+ const pitch = noteOff.noteNumber;
3106
+ for (let i = active.length - 1; i >= 0; i--) {
3107
+ if (active[i].pitch === pitch && active[i].end === null) {
3108
+ active[i].end = currentTime;
3109
+ break;
3110
+ }
3098
3111
  }
3099
3112
  }
3100
- } else {
3101
- active.push({ pitch, velocity, start: currentTime, end: null });
3102
3113
  }
3103
3114
  }
3104
3115
  for (const note of active) {
@@ -6430,11 +6441,11 @@ var mountDAW = (target, options = {}) => {
6430
6441
  lyricCount.textContent = active.lyricModel && n > 0 ? `${n}\u97F3\u7BC0` : "";
6431
6442
  };
6432
6443
  const syncLyricTerms = () => {
6433
- const url = active.lyricModel ? KOE_VOICEBANK_TERMS[active.lyricModel] : void 0;
6434
- if (url) {
6444
+ const url2 = active.lyricModel ? KOE_VOICEBANK_TERMS[active.lyricModel] : void 0;
6445
+ if (url2) {
6435
6446
  const label = lyricModelLabel(active.lyricModel);
6436
6447
  lyricTermsLink.textContent = `${label}UTAU\u97F3\u6E90`;
6437
- lyricTermsLink.href = url;
6448
+ lyricTermsLink.href = url2;
6438
6449
  lyricTerms.classList.remove("dtm-hidden");
6439
6450
  } else {
6440
6451
  lyricTerms.classList.add("dtm-hidden");
@@ -6772,9 +6783,9 @@ var mountDAW = (target, options = {}) => {
6772
6783
  chordTrack.core.addHistoryOnce();
6773
6784
  redrawAll();
6774
6785
  };
6775
- const loadMIDI = (bytes) => {
6786
+ const loadMIDI = async (bytes) => {
6776
6787
  if (!options.parseMidi) return;
6777
- const midi = options.parseMidi(bytes);
6788
+ const midi = await options.parseMidi(bytes);
6778
6789
  const analysis = analyzeMidiTracks(midi);
6779
6790
  const selected = analysis.filter((a) => a.selected).map((a) => a.index);
6780
6791
  applyMidiSelection(midi, selected);
@@ -6938,13 +6949,13 @@ var mountDAW = (target, options = {}) => {
6938
6949
  });
6939
6950
  refs.generateMmlBtn.addEventListener("click", showMML);
6940
6951
  refs.exportMidiBtn.addEventListener("click", () => {
6941
- const blob = exportMIDI2();
6942
- const url = URL.createObjectURL(blob);
6952
+ const blob2 = exportMIDI2();
6953
+ const url2 = URL.createObjectURL(blob2);
6943
6954
  const a = document.createElement("a");
6944
- a.href = url;
6955
+ a.href = url2;
6945
6956
  a.download = "dtm.mid";
6946
6957
  a.click();
6947
- URL.revokeObjectURL(url);
6958
+ URL.revokeObjectURL(url2);
6948
6959
  });
6949
6960
  const copy = (text, btn) => {
6950
6961
  navigator.clipboard?.writeText(text);
@@ -7011,7 +7022,7 @@ var mountDAW = (target, options = {}) => {
7011
7022
  refs.overlay.hidden = false;
7012
7023
  setLoading(true);
7013
7024
  const buffer = new Uint8Array(await file.arrayBuffer());
7014
- pendingMidi = options.parseMidi(buffer);
7025
+ pendingMidi = await options.parseMidi(buffer);
7015
7026
  detectedTracks = analyzeMidiTracks(pendingMidi);
7016
7027
  refs.midiTrackSelection.innerHTML = `<span class="dtm-label">\u30C8\u30E9\u30C3\u30AF</span>`;
7017
7028
  detectedTracks.forEach((t, i) => {
@@ -7640,12 +7651,12 @@ var mountMmlPlayer = (target, mml, options = {}) => {
7640
7651
  termsRow.style.gap = "4px";
7641
7652
  termsRow.style.flexWrap = "wrap";
7642
7653
  const label = KOE_VOICEBANK_LABELS[model] ?? model;
7643
- const url = KOE_VOICEBANK_TERMS[model];
7654
+ const url2 = KOE_VOICEBANK_TERMS[model];
7644
7655
  const span1 = doc.createElement("span");
7645
7656
  span1.textContent = "\u4F7F\u7528\u6642\u306B\u306F";
7646
7657
  const a = doc.createElement("a");
7647
7658
  a.textContent = `${label}UTAU\u97F3\u6E90`;
7648
- a.href = url;
7659
+ a.href = url2;
7649
7660
  a.target = "_blank";
7650
7661
  a.rel = "noopener";
7651
7662
  a.style.color = "var(--dtm-primary)";
@@ -8114,13 +8125,173 @@ var createPianoRoll = (options, handlers) => {
8114
8125
  };
8115
8126
  };
8116
8127
 
8128
+ // node_modules/.pnpm/fast-unique-numbers@9.0.27/node_modules/fast-unique-numbers/build/es2019/factories/add-unique-number.js
8129
+ var createAddUniqueNumber = (generateUniqueNumber2) => {
8130
+ return (set) => {
8131
+ const number = generateUniqueNumber2(set);
8132
+ set.add(number);
8133
+ return number;
8134
+ };
8135
+ };
8136
+
8137
+ // node_modules/.pnpm/fast-unique-numbers@9.0.27/node_modules/fast-unique-numbers/build/es2019/factories/cache.js
8138
+ var createCache = (lastNumberWeakMap) => {
8139
+ return (collection, nextNumber) => {
8140
+ lastNumberWeakMap.set(collection, nextNumber);
8141
+ return nextNumber;
8142
+ };
8143
+ };
8144
+
8145
+ // node_modules/.pnpm/fast-unique-numbers@9.0.27/node_modules/fast-unique-numbers/build/es2019/factories/generate-unique-number.js
8146
+ var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER === void 0 ? 9007199254740991 : Number.MAX_SAFE_INTEGER;
8147
+ var TWO_TO_THE_POWER_OF_TWENTY_NINE = 536870912;
8148
+ var TWO_TO_THE_POWER_OF_THIRTY = TWO_TO_THE_POWER_OF_TWENTY_NINE * 2;
8149
+ var createGenerateUniqueNumber = (cache2, lastNumberWeakMap) => {
8150
+ return (collection) => {
8151
+ const lastNumber = lastNumberWeakMap.get(collection);
8152
+ let nextNumber = lastNumber === void 0 ? collection.size : lastNumber < TWO_TO_THE_POWER_OF_THIRTY ? lastNumber + 1 : 0;
8153
+ if (!collection.has(nextNumber)) {
8154
+ return cache2(collection, nextNumber);
8155
+ }
8156
+ if (collection.size < TWO_TO_THE_POWER_OF_TWENTY_NINE) {
8157
+ while (collection.has(nextNumber)) {
8158
+ nextNumber = Math.floor(Math.random() * TWO_TO_THE_POWER_OF_THIRTY);
8159
+ }
8160
+ return cache2(collection, nextNumber);
8161
+ }
8162
+ if (collection.size > MAX_SAFE_INTEGER) {
8163
+ throw new Error("Congratulations, you created a collection of unique numbers which uses all available integers!");
8164
+ }
8165
+ while (collection.has(nextNumber)) {
8166
+ nextNumber = Math.floor(Math.random() * MAX_SAFE_INTEGER);
8167
+ }
8168
+ return cache2(collection, nextNumber);
8169
+ };
8170
+ };
8171
+
8172
+ // node_modules/.pnpm/fast-unique-numbers@9.0.27/node_modules/fast-unique-numbers/build/es2019/module.js
8173
+ var LAST_NUMBER_WEAK_MAP = /* @__PURE__ */ new WeakMap();
8174
+ var cache = createCache(LAST_NUMBER_WEAK_MAP);
8175
+ var generateUniqueNumber = createGenerateUniqueNumber(cache, LAST_NUMBER_WEAK_MAP);
8176
+ var addUniqueNumber = createAddUniqueNumber(generateUniqueNumber);
8177
+
8178
+ // node_modules/.pnpm/broker-factory@3.1.15/node_modules/broker-factory/build/es2019/factories/create-broker.js
8179
+ var createBrokerFactory = (createOrGetOngoingRequests, extendBrokerImplementation, generateUniqueNumber2, isMessagePort2) => (brokerImplementation) => {
8180
+ const fullBrokerImplementation = extendBrokerImplementation(brokerImplementation);
8181
+ return (sender) => {
8182
+ const ongoingRequests = createOrGetOngoingRequests(sender);
8183
+ sender.addEventListener("message", (({ data: message }) => {
8184
+ const { id } = message;
8185
+ if (id !== null && ongoingRequests.has(id)) {
8186
+ const { reject, resolve } = ongoingRequests.get(id);
8187
+ ongoingRequests.delete(id);
8188
+ if (message.error === void 0) {
8189
+ resolve(message.result);
8190
+ } else {
8191
+ reject(new Error(message.error.message));
8192
+ }
8193
+ }
8194
+ }));
8195
+ if (isMessagePort2(sender)) {
8196
+ sender.start();
8197
+ }
8198
+ const call = (method, params = null, transferables = []) => {
8199
+ return new Promise((resolve, reject) => {
8200
+ const id = generateUniqueNumber2(ongoingRequests);
8201
+ ongoingRequests.set(id, { reject, resolve });
8202
+ if (params === null) {
8203
+ sender.postMessage({ id, method }, transferables);
8204
+ } else {
8205
+ sender.postMessage({ id, method, params }, transferables);
8206
+ }
8207
+ });
8208
+ };
8209
+ const notify = (method, params, transferables = []) => {
8210
+ sender.postMessage({ id: null, method, params }, transferables);
8211
+ };
8212
+ let functions = {};
8213
+ for (const [key, handler] of Object.entries(fullBrokerImplementation)) {
8214
+ functions = { ...functions, [key]: handler({ call, notify }) };
8215
+ }
8216
+ return { ...functions };
8217
+ };
8218
+ };
8219
+
8220
+ // node_modules/.pnpm/broker-factory@3.1.15/node_modules/broker-factory/build/es2019/factories/create-or-get-ongoing-requests.js
8221
+ var createCreateOrGetOngoingRequests = (ongoingRequestsMap) => (sender) => {
8222
+ if (ongoingRequestsMap.has(sender)) {
8223
+ return ongoingRequestsMap.get(sender);
8224
+ }
8225
+ const ongoingRequests = /* @__PURE__ */ new Map();
8226
+ ongoingRequestsMap.set(sender, ongoingRequests);
8227
+ return ongoingRequests;
8228
+ };
8229
+
8230
+ // node_modules/.pnpm/broker-factory@3.1.15/node_modules/broker-factory/build/es2019/factories/extend-broker-implementation.js
8231
+ var createExtendBrokerImplementation = (portMap) => (partialBrokerImplementation) => ({
8232
+ ...partialBrokerImplementation,
8233
+ connect: ({ call }) => {
8234
+ return async () => {
8235
+ const { port1, port2 } = new MessageChannel();
8236
+ const portId = await call("connect", { port: port1 }, [port1]);
8237
+ portMap.set(port2, portId);
8238
+ return port2;
8239
+ };
8240
+ },
8241
+ disconnect: ({ call }) => {
8242
+ return async (port) => {
8243
+ const portId = portMap.get(port);
8244
+ if (portId === void 0) {
8245
+ throw new Error("The given port is not connected.");
8246
+ }
8247
+ await call("disconnect", { portId });
8248
+ };
8249
+ },
8250
+ isSupported: ({ call }) => {
8251
+ return () => call("isSupported");
8252
+ }
8253
+ });
8254
+
8255
+ // node_modules/.pnpm/broker-factory@3.1.15/node_modules/broker-factory/build/es2019/guards/message-port.js
8256
+ var isMessagePort = (sender) => {
8257
+ return typeof sender.start === "function";
8258
+ };
8259
+
8260
+ // node_modules/.pnpm/broker-factory@3.1.15/node_modules/broker-factory/build/es2019/module.js
8261
+ var createBroker = createBrokerFactory(createCreateOrGetOngoingRequests(/* @__PURE__ */ new WeakMap()), createExtendBrokerImplementation(/* @__PURE__ */ new WeakMap()), generateUniqueNumber, isMessagePort);
8262
+
8263
+ // node_modules/.pnpm/midi-json-parser-broker@4.0.132/node_modules/midi-json-parser-broker/build/es2019/module.js
8264
+ var wrap = createBroker({
8265
+ parseArrayBuffer: ({ call }) => {
8266
+ return async (arrayBuffer) => {
8267
+ return call("parse", { arrayBuffer }, [arrayBuffer]);
8268
+ };
8269
+ }
8270
+ });
8271
+ var load = (url2) => {
8272
+ const worker2 = new Worker(url2);
8273
+ return wrap(worker2);
8274
+ };
8275
+
8276
+ // node_modules/.pnpm/midi-json-parser@8.1.74/node_modules/midi-json-parser/build/es2019/worker/worker.js
8277
+ var worker = `(()=>{var e={455(e,t){!function(e){"use strict";var t=function(e){return function(t){var n=e(t);return t.add(n),n}},n=function(e){return function(t,n){return e.set(t,n),n}},r=void 0===Number.MAX_SAFE_INTEGER?9007199254740991:Number.MAX_SAFE_INTEGER,o=536870912,s=2*o,i=function(e,t){return function(n){var i=t.get(n),a=void 0===i?n.size:i<s?i+1:0;if(!n.has(a))return e(n,a);if(n.size<o){for(;n.has(a);)a=Math.floor(Math.random()*s);return e(n,a)}if(n.size>r)throw new Error("Congratulations, you created a collection of unique numbers which uses all available integers!");for(;n.has(a);)a=Math.floor(Math.random()*r);return e(n,a)}},a=new WeakMap,f=n(a),c=i(f,a),u=t(c);e.addUniqueNumber=u,e.generateUniqueNumber=c}(t)}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var s=t[r]={exports:{}};return e[r].call(s.exports,s,s.exports,n),s.exports}(()=>{"use strict";const e=-32603,t=-32602,r=-32601,o=(e,t)=>Object.assign(new Error(e),{status:t}),s=t=>o('The handler of the method called "'.concat(t,'" returned an unexpected result.'),e),i=(t,n)=>async({data:{id:i,method:a,params:f}})=>{const c=n[a];try{if(void 0===c)throw(e=>o('The requested method called "'.concat(e,'" is not supported.'),r))(a);const n=void 0===f?c():c(f);if(void 0===n)throw(t=>o('The handler of the method called "'.concat(t,'" returned no required result.'),e))(a);const u=n instanceof Promise?await n:n;if(null===i){if(void 0!==u.result)throw s(a)}else{if(void 0===u.result)throw s(a);const{result:e,transferables:n=[]}=u;t.postMessage({id:i,result:e},n)}}catch(e){const{message:n,status:r=-32603}=e;t.postMessage({error:{code:r,message:n},id:i})}};var a=n(455);const f=new Map,c=(e,n,r)=>({...n,connect:({port:t})=>{t.start();const r=e(t,n),o=(0,a.generateUniqueNumber)(f);return f.set(o,()=>{r(),t.close(),f.delete(o)}),{result:o}},disconnect:({portId:e})=>{const n=f.get(e);if(void 0===n)throw(e=>o('The specified parameter called "portId" with the given value "'.concat(e,'" does not identify a port connected to this worker.'),t))(e);return n(),{result:null}},isSupported:async()=>{if(await new Promise(e=>{const t=new ArrayBuffer(0),{port1:n,port2:r}=new MessageChannel;n.onmessage=({data:t})=>e(null!==t),r.postMessage(t,[t])})){const e=r();return{result:e instanceof Promise?await e:e}}return{result:!1}}}),u=(e,t,n=()=>!0)=>{const r=c(u,t,n),o=i(e,r);return e.addEventListener("message",o),()=>e.removeEventListener("message",o)},l=e=>void 0!==e.channel,d=e=>e.toString(16).toUpperCase().padStart(2,"0"),g=(e,t=0,n=e.byteLength-(t-e.byteOffset))=>{const r=t+e.byteOffset,o=[],s=new Uint8Array(e.buffer,r,n);for(let e=0;e<n;e+=1)o[e]=d(s[e]);return o.join("")},h=(e,t=0,n=e.byteLength-(t-e.byteOffset))=>{const r=t+e.byteOffset,o=new Uint8Array(e.buffer,r,n);return String.fromCharCode.apply(null,o)},m=e=>{const t=new DataView(e),n=v(t);let r=14;const o=[];for(let e=0,s=n.numberOfTracks;e<s;e+=1){let e;({offset:r,track:e}=b(t,r)),o.push(e)}return{division:n.division,format:n.format,tracks:o}},p=(e,t,n)=>{let r;const{offset:o,value:s}=T(e,t),i=e.getUint8(o);return r=240===i?y(e,o+1):255===i?U(e,o+1):w(i,e,o+1,n),{...r,event:{...r.event,delta:s},eventTypeByte:i}},v=e=>{if(e.byteLength<14)throw new Error("Expected at least 14 bytes instead of ".concat(e.byteLength));if("MThd"!==h(e,0,4))throw new Error('Unexpected characters "'.concat(h(e,0,4),'" found instead of "MThd"'));if(6!==e.getUint32(4))throw new Error("The header has an unexpected length of ".concat(e.getUint32(4)," instead of 6"));const t=e.getUint16(8),n=e.getUint16(10);return{division:e.getUint16(12),format:t,numberOfTracks:n}},U=(e,t)=>{let n;const r=e.getUint8(t),{offset:o,value:s}=T(e,t+1);if(1===r)n={text:h(e,o,s)};else if(2===r)n={copyrightNotice:h(e,o,s)};else if(3===r)n={trackName:h(e,o,s)};else if(4===r)n={instrumentName:h(e,o,s)};else if(5===r)n={lyric:h(e,o,s)};else if(6===r)n={marker:h(e,o,s)};else if(7===r)n={cuePoint:h(e,o,s)};else if(8===r)n={programName:h(e,o,s)};else if(9===r)n={deviceName:h(e,o,s)};else if(10===r||11===r||12===r||13===r||14===r||15===r)n={metaTypeByte:d(r),text:h(e,o,s)};else if(32===r)n={channelPrefix:e.getUint8(o)};else if(33===r)n={midiPort:e.getUint8(o)};else if(47===r)n={endOfTrack:!0};else if(81===r)n={setTempo:{microsecondsPerQuarter:(e.getUint8(o)<<16)+(e.getUint8(o+1)<<8)+e.getUint8(o+2)}};else if(84===r){let t;const r=e.getUint8(o);96&r?32==(96&r)?t=25:64==(96&r)?t=29:96&~r||(t=30):t=24,n={smpteOffset:{frame:e.getUint8(o+3),frameRate:t,hour:31&r,minutes:e.getUint8(o+1),seconds:e.getUint8(o+2),subFrame:e.getUint8(o+4)}}}else if(88===r)n={timeSignature:{denominator:Math.pow(2,e.getUint8(o+1)),metronome:e.getUint8(o+2),numerator:e.getUint8(o),thirtyseconds:e.getUint8(o+3)}};else if(89===r)n={keySignature:{key:e.getInt8(o),scale:e.getInt8(o+1)}};else{if(127!==r)throw new Error('Cannot parse a meta event with a type of "'.concat(d(r),'"'));n={sequencerSpecificData:g(e,o,s)}}return{event:n,offset:o+s}},w=(e,t,n,r)=>{const o=128&e?null:r,s=(null===o?e:o)>>4;let i,a=null===o?n:n-1;if(8===s)i={noteOff:{noteNumber:t.getUint8(a),velocity:t.getUint8(a+1)}},a+=2;else if(9===s){const e=t.getUint8(a),n=t.getUint8(a+1);i=0===n?{noteOff:{noteNumber:e,velocity:n}}:{noteOn:{noteNumber:e,velocity:n}},a+=2}else if(10===s)i={keyPressure:{noteNumber:t.getUint8(a),pressure:t.getUint8(a+1)}},a+=2;else if(11===s)i={controlChange:{type:t.getUint8(a),value:t.getUint8(a+1)}},a+=2;else if(12===s)i={programChange:{programNumber:t.getUint8(a)}},a+=1;else if(13===s)i={channelPressure:{pressure:t.getUint8(a)}},a+=1;else{if(14!==s)throw new Error('Cannot parse a midi event with a type of "'.concat(d(s),'"'));i={pitchBend:t.getUint8(a)|t.getUint8(a+1)<<7},a+=2}return i.channel=15&(null===o?e:o),{event:i,offset:a}},y=(e,t)=>{const{offset:n,value:r}=T(e,t);return{event:{sysex:g(e,n,r)},offset:n+r}},b=(e,t)=>{if("MTrk"!==h(e,t,4))throw new Error('Unexpected characters "'.concat(h(e,t,4),'" found instead of "MTrk"'));const n=[],r=e.getUint32(t+4)+t+8;let o=null,s=t+8;for(;s<r;){const t=p(e,s,o),{event:r,eventTypeByte:i}=t;n.push(r),s=t.offset,l(r)&&(128&i)>0&&(o=i)}return{offset:s,track:n}},T=(e,t)=>{let n=t,r=0;for(;;){const t=e.getUint8(n);if(n+=1,!(t>127))return r+=t,{offset:n,value:r};r+=127&t,r<<=7}};u(self,{parse:({arrayBuffer:e})=>({result:m(e)})})})()})();`;
8278
+
8279
+ // node_modules/.pnpm/midi-json-parser@8.1.74/node_modules/midi-json-parser/build/es2019/module.js
8280
+ var blob = new Blob([worker], { type: "application/javascript; charset=utf-8" });
8281
+ var url = URL.createObjectURL(blob);
8282
+ var midiJsonParser = load(url);
8283
+ var connect = midiJsonParser.connect;
8284
+ var disconnect = midiJsonParser.disconnect;
8285
+ var isSupported = midiJsonParser.isSupported;
8286
+ var parseArrayBuffer = midiJsonParser.parseArrayBuffer;
8287
+ URL.revokeObjectURL(url);
8288
+
8117
8289
  // src/studio.ts
8118
8290
  var import_meta = {};
8119
8291
  var DEFAULT_CDN = {
8120
8292
  soundFont: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont.mjs",
8121
8293
  soundFontDrum: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_drum.mjs",
8122
- soundFontList: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_list.mjs",
8123
- midiParser: "https://cdn.jsdelivr.net/npm/midi-parser-js@4.0.4/+esm"
8294
+ soundFontList: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_list.mjs"
8124
8295
  };
8125
8296
  var SOUNDFONT_NAME = "FluidR3_GM_sf2_file";
8126
8297
  var TRACK_ROLES = ["melody", "submelody", "bass", "chord"];
@@ -8131,10 +8302,10 @@ var resolveDefaultVoiceWorkerUrl = () => {
8131
8302
  return void 0;
8132
8303
  }
8133
8304
  };
8134
- var importFrom = async (url, name) => {
8305
+ var importFrom = async (url2, name) => {
8135
8306
  const mod = await import(
8136
8307
  /* @vite-ignore */
8137
- url
8308
+ url2
8138
8309
  );
8139
8310
  return mod[name] ?? mod.default;
8140
8311
  };
@@ -8163,23 +8334,17 @@ var createDtmStudio = async (options = {}) => {
8163
8334
  eng.SoundFont_drum ?? importFrom(cdn.soundFontDrum, "SoundFont_drum"),
8164
8335
  eng.SoundFont_list ?? importFrom(cdn.soundFontList, "SoundFont_list")
8165
8336
  ]);
8166
- let midiParser = null;
8167
8337
  let parseMidi;
8168
8338
  if (features.midi) {
8169
- parseMidi = eng.parseMidi;
8170
- if (!parseMidi) {
8171
- const midiPromise = importFrom(
8172
- cdn.midiParser,
8173
- "default"
8174
- ).then((m) => {
8175
- midiParser = m;
8176
- }).catch((e) => console.warn("[dtm] midi-parser \u306E\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557", e));
8177
- void midiPromise;
8178
- parseMidi = (bytes) => {
8179
- if (!midiParser) throw new Error("midi-parser not ready");
8180
- return midiParser.parse(bytes);
8181
- };
8182
- }
8339
+ parseMidi = eng.parseMidi || ((bytes) => {
8340
+ const buffer = bytes.buffer;
8341
+ if (buffer instanceof ArrayBuffer) {
8342
+ return parseArrayBuffer(
8343
+ buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)
8344
+ );
8345
+ }
8346
+ throw new Error("SharedArrayBuffer is not supported for MIDI parsing");
8347
+ });
8183
8348
  }
8184
8349
  const voiceWorkerUrl = options.voiceWorkerUrl === null ? void 0 : options.voiceWorkerUrl ?? resolveDefaultVoiceWorkerUrl();
8185
8350
  const singingVoices = createSingingVoices(audioCtx, masterGain, {
@@ -8230,13 +8395,13 @@ var createDtmStudio = async (options = {}) => {
8230
8395
  clamp4(Math.round(wave[i] * 32768), -32768, 32767),
8231
8396
  true
8232
8397
  );
8233
- const blob = new Blob([view], { type: "audio/wav" });
8234
- const url = URL.createObjectURL(blob);
8398
+ const blob2 = new Blob([view], { type: "audio/wav" });
8399
+ const url2 = URL.createObjectURL(blob2);
8235
8400
  const a = document.createElement("a");
8236
- a.href = url;
8401
+ a.href = url2;
8237
8402
  a.download = "record.wav";
8238
8403
  a.click();
8239
- URL.revokeObjectURL(url);
8404
+ URL.revokeObjectURL(url2);
8240
8405
  };
8241
8406
  const onToggleRecord = recorder ? () => {
8242
8407
  if (recorder.isRecording()) {
package/dist/index.mjs CHANGED
@@ -1522,8 +1522,8 @@ function parseKoeHeader(headerBytes) {
1522
1522
  }
1523
1523
  var pcmBase = (jsonLength) => 8 + jsonLength;
1524
1524
  var BlobVoiceSource = class {
1525
- constructor(blob, base) {
1526
- this.blob = blob;
1525
+ constructor(blob2, base) {
1526
+ this.blob = blob2;
1527
1527
  this.base = base;
1528
1528
  }
1529
1529
  blob;
@@ -1534,8 +1534,8 @@ var BlobVoiceSource = class {
1534
1534
  }
1535
1535
  };
1536
1536
  var RangeVoiceSource = class {
1537
- constructor(url, base) {
1538
- this.url = url;
1537
+ constructor(url2, base) {
1538
+ this.url = url2;
1539
1539
  this.base = base;
1540
1540
  }
1541
1541
  url;
@@ -1551,8 +1551,8 @@ var RangeVoiceSource = class {
1551
1551
  return res.arrayBuffer();
1552
1552
  }
1553
1553
  };
1554
- async function rangeFetch(url, start, length) {
1555
- const res = await fetch(url, {
1554
+ async function rangeFetch(url2, start, length) {
1555
+ const res = await fetch(url2, {
1556
1556
  headers: { Range: `bytes=${start}-${start + length - 1}` }
1557
1557
  });
1558
1558
  if (!res.ok && res.status !== 206)
@@ -2323,22 +2323,22 @@ var createLocalBackend = async (options) => {
2323
2323
  }
2324
2324
  };
2325
2325
  };
2326
- var spawnVoiceWorker = async (url) => {
2327
- const sameOrigin = new URL(url, location.href).origin === location.origin;
2328
- if (sameOrigin) return new Worker(url);
2329
- const text = await fetch(url).then((r) => r.text());
2326
+ var spawnVoiceWorker = async (url2) => {
2327
+ const sameOrigin = new URL(url2, location.href).origin === location.origin;
2328
+ if (sameOrigin) return new Worker(url2);
2329
+ const text = await fetch(url2).then((r) => r.text());
2330
2330
  return new Worker(
2331
2331
  URL.createObjectURL(new Blob([text], { type: "text/javascript" }))
2332
2332
  );
2333
2333
  };
2334
2334
  var createWorkerBackend = async (workerUrl, options) => {
2335
- const worker = await spawnVoiceWorker(workerUrl);
2335
+ const worker2 = await spawnVoiceWorker(workerUrl);
2336
2336
  const aliasSet = /* @__PURE__ */ new Set();
2337
2337
  const pending = /* @__PURE__ */ new Map();
2338
2338
  let reqId = 0;
2339
2339
  let onReady = null;
2340
2340
  let onFail = null;
2341
- worker.onmessage = (ev) => {
2341
+ worker2.onmessage = (ev) => {
2342
2342
  const m = ev.data;
2343
2343
  if (m.type === "ready") {
2344
2344
  for (const a of m.aliases) aliasSet.add(a);
@@ -2353,14 +2353,14 @@ var createWorkerBackend = async (workerUrl, options) => {
2353
2353
  }
2354
2354
  }
2355
2355
  };
2356
- worker.onerror = (e) => {
2356
+ worker2.onerror = (e) => {
2357
2357
  const ev = e;
2358
2358
  onFail?.(new Error(ev.message || ev.error || `Event: ${ev.type}`));
2359
2359
  };
2360
2360
  await new Promise((resolve, reject) => {
2361
2361
  onReady = resolve;
2362
2362
  onFail = reject;
2363
- worker.postMessage({
2363
+ worker2.postMessage({
2364
2364
  type: "init",
2365
2365
  koe: options.koe,
2366
2366
  worldlineScriptUrl: options.worldlineScriptUrl ?? DEFAULT_WORLDLINE_SCRIPT,
@@ -2377,7 +2377,7 @@ var createWorkerBackend = async (workerUrl, options) => {
2377
2377
  m.pcm ? { pcm: m.pcm, preSec: m.preSec ?? 0, rate: m.rate ?? 1 } : null
2378
2378
  )
2379
2379
  );
2380
- worker.postMessage({
2380
+ worker2.postMessage({
2381
2381
  type: "render",
2382
2382
  id,
2383
2383
  alias,
@@ -2389,7 +2389,7 @@ var createWorkerBackend = async (workerUrl, options) => {
2389
2389
  hasAlias: (a) => aliasSet.has(a),
2390
2390
  pitchTokens: collectPitchTokens(aliasSet),
2391
2391
  renderAlias,
2392
- dispose: () => worker.terminate()
2392
+ dispose: () => worker2.terminate()
2393
2393
  };
2394
2394
  };
2395
2395
  var createKoeVoice = async (ctx, destination, options) => {
@@ -2524,7 +2524,7 @@ var createSingingVoices = (ctx, destination, options = {}) => {
2524
2524
  [FALLBACK_MODEL, createKlattVoice(ctx, destination)]
2525
2525
  ]);
2526
2526
  const loading = /* @__PURE__ */ new Map();
2527
- const load = (model) => {
2527
+ const load2 = (model) => {
2528
2528
  const m = model.toLowerCase();
2529
2529
  const ready = loaded.get(m);
2530
2530
  if (ready) return Promise.resolve(ready);
@@ -2556,7 +2556,7 @@ var createSingingVoices = (ctx, destination, options = {}) => {
2556
2556
  const loadModels = async (models) => {
2557
2557
  const set = /* @__PURE__ */ new Set();
2558
2558
  for (const m of models) if (m) set.add(m.toLowerCase());
2559
- await Promise.all([...set].map((m) => load(m)));
2559
+ await Promise.all([...set].map((m) => load2(m)));
2560
2560
  };
2561
2561
  const forEachSungNote = (track, fn) => {
2562
2562
  let prevVowel = "";
@@ -2778,21 +2778,26 @@ var shiftNotes = (cores, shiftSteps) => {
2778
2778
  // src/midi-io.ts
2779
2779
  var STEPS_PER_BEAT = 48;
2780
2780
  var analyzeMidiTracks = (midi) => {
2781
- const { track } = midi;
2781
+ const { tracks } = midi;
2782
2782
  const result = [];
2783
- for (let i = 0; i < track.length; i++) {
2783
+ for (let i = 0; i < tracks.length; i++) {
2784
2784
  const notes = [];
2785
2785
  let currentTime = 0;
2786
- for (const event of track[i].event) {
2787
- currentTime += event.deltaTime;
2788
- const data = event.data;
2789
- if (event.type === 9 && data && data[1]) {
2790
- notes.push({ pitch: data[0], channel: event.channel ?? 0 });
2791
- } else if (event.type === 8) {
2792
- for (let k = notes.length - 1; k >= 0; k--) {
2793
- if (notes[k].pitch === data[0] && notes[k].end === void 0) {
2794
- notes[k].end = currentTime;
2795
- break;
2786
+ for (const event of tracks[i]) {
2787
+ currentTime += event.delta;
2788
+ if (event.noteOn && event.noteOn.velocity > 0) {
2789
+ notes.push({
2790
+ pitch: event.noteOn.noteNumber,
2791
+ channel: event.channel ?? 0
2792
+ });
2793
+ } else if (event.noteOff || event.noteOn && event.noteOn.velocity === 0) {
2794
+ const noteOff = event.noteOff || event.noteOn;
2795
+ if (noteOff) {
2796
+ for (let k = notes.length - 1; k >= 0; k--) {
2797
+ if (notes[k].pitch === noteOff.noteNumber && notes[k].end === void 0) {
2798
+ notes[k].end = currentTime;
2799
+ break;
2800
+ }
2796
2801
  }
2797
2802
  }
2798
2803
  }
@@ -2810,51 +2815,54 @@ var analyzeMidiTracks = (midi) => {
2810
2815
  return result;
2811
2816
  };
2812
2817
  var getMidiBPM = (midi) => {
2813
- const { track } = midi;
2814
- for (const { event } of track) {
2815
- for (const { type, metaType, data } of event) {
2816
- if (type !== 255 || metaType !== 81) continue;
2817
- if (typeof data === "number") {
2818
- return 6e7 / data;
2818
+ const { tracks } = midi;
2819
+ for (const track of tracks) {
2820
+ for (const event of track) {
2821
+ if (event.setTempo && typeof event.setTempo.microsecondsPerQuarter === "number") {
2822
+ return 6e7 / event.setTempo.microsecondsPerQuarter;
2819
2823
  }
2820
- const [b1, b2, b3] = data;
2821
- return 6e7 / (b1 << 16 | b2 << 8 | b3);
2822
2824
  }
2823
2825
  }
2824
2826
  return 120;
2825
2827
  };
2826
2828
  var extractMidiPlacements = (midi, selectedTrackIndices) => {
2827
- const { track, timeDivision } = midi;
2828
- const ticksPerBeat = timeDivision;
2829
+ const { tracks, division } = midi;
2830
+ const ticksPerBeat = division;
2829
2831
  const bpm = getMidiBPM(midi);
2830
2832
  const channelNotes = {};
2831
2833
  for (const trackIdx of selectedTrackIndices) {
2832
- const trackData = track[trackIdx];
2834
+ const trackData = tracks[trackIdx];
2833
2835
  if (!trackData) continue;
2834
2836
  let currentTime = 0;
2835
- for (const event of trackData.event) {
2836
- currentTime += event.deltaTime;
2837
+ for (const event of trackData) {
2838
+ currentTime += event.delta;
2837
2839
  if (event.channel === 9) continue;
2838
- if (event.type !== 8 && event.type !== 9) continue;
2839
- const [pitch, velocity] = event.data;
2840
- const isNoteOff = event.type === 8 || !velocity;
2841
- const channel = event.channel ?? 0;
2842
- if (!channelNotes[channel]) channelNotes[channel] = [];
2843
- if (isNoteOff) {
2844
- for (let i = channelNotes[channel].length - 1; i >= 0; i--) {
2845
- const note = channelNotes[channel][i];
2846
- if (note.pitch === pitch && note.end === null) {
2847
- note.end = currentTime;
2848
- break;
2849
- }
2850
- }
2851
- } else {
2840
+ if (event.noteOn && event.noteOn.velocity > 0) {
2841
+ const pitch = event.noteOn.noteNumber;
2842
+ const velocity = event.noteOn.velocity;
2843
+ const channel = event.channel ?? 0;
2844
+ if (!channelNotes[channel]) channelNotes[channel] = [];
2852
2845
  channelNotes[channel].push({
2853
2846
  pitch,
2854
2847
  velocity,
2855
2848
  start: currentTime,
2856
2849
  end: null
2857
2850
  });
2851
+ } else if (event.noteOff || event.noteOn && event.noteOn.velocity === 0) {
2852
+ const noteOff = event.noteOff || event.noteOn;
2853
+ if (noteOff) {
2854
+ const pitch = noteOff.noteNumber;
2855
+ const channel = event.channel ?? 0;
2856
+ if (channelNotes[channel]) {
2857
+ for (let i = channelNotes[channel].length - 1; i >= 0; i--) {
2858
+ const note = channelNotes[channel][i];
2859
+ if (note.pitch === pitch && note.end === null) {
2860
+ note.end = currentTime;
2861
+ break;
2862
+ }
2863
+ }
2864
+ }
2865
+ }
2858
2866
  }
2859
2867
  }
2860
2868
  }
@@ -2967,33 +2975,36 @@ var extractMidiPlacements = (midi, selectedTrackIndices) => {
2967
2975
  return { placements, bpm };
2968
2976
  };
2969
2977
  var extractMidiPlacementsByTrack = (midi, selectedIndices, trackIds) => {
2970
- const { track, timeDivision } = midi;
2971
- const ticksPerBeat = timeDivision;
2978
+ const { tracks, division } = midi;
2979
+ const ticksPerBeat = division;
2972
2980
  const bpm = getMidiBPM(midi);
2973
2981
  const ticksPerStep = ticksPerBeat / STEPS_PER_BEAT;
2974
2982
  const placements = [];
2975
2983
  selectedIndices.forEach((midiIdx, lane) => {
2976
2984
  if (lane >= trackIds.length) return;
2977
- const trackData = track[midiIdx];
2985
+ const trackData = tracks[midiIdx];
2978
2986
  if (!trackData) return;
2979
2987
  const trackId = trackIds[lane];
2980
2988
  const active = [];
2981
2989
  let currentTime = 0;
2982
- for (const event of trackData.event) {
2983
- currentTime += event.deltaTime;
2990
+ for (const event of trackData) {
2991
+ currentTime += event.delta;
2984
2992
  if (event.channel === 9) continue;
2985
- if (event.type !== 8 && event.type !== 9) continue;
2986
- const [pitch, velocity] = event.data;
2987
- const isOff = event.type === 8 || !velocity;
2988
- if (isOff) {
2989
- for (let i = active.length - 1; i >= 0; i--) {
2990
- if (active[i].pitch === pitch && active[i].end === null) {
2991
- active[i].end = currentTime;
2992
- break;
2993
+ if (event.noteOn && event.noteOn.velocity > 0) {
2994
+ const pitch = event.noteOn.noteNumber;
2995
+ const velocity = event.noteOn.velocity;
2996
+ active.push({ pitch, velocity, start: currentTime, end: null });
2997
+ } else if (event.noteOff || event.noteOn && event.noteOn.velocity === 0) {
2998
+ const noteOff = event.noteOff || event.noteOn;
2999
+ if (noteOff) {
3000
+ const pitch = noteOff.noteNumber;
3001
+ for (let i = active.length - 1; i >= 0; i--) {
3002
+ if (active[i].pitch === pitch && active[i].end === null) {
3003
+ active[i].end = currentTime;
3004
+ break;
3005
+ }
2993
3006
  }
2994
3007
  }
2995
- } else {
2996
- active.push({ pitch, velocity, start: currentTime, end: null });
2997
3008
  }
2998
3009
  }
2999
3010
  for (const note of active) {
@@ -6325,11 +6336,11 @@ var mountDAW = (target, options = {}) => {
6325
6336
  lyricCount.textContent = active.lyricModel && n > 0 ? `${n}\u97F3\u7BC0` : "";
6326
6337
  };
6327
6338
  const syncLyricTerms = () => {
6328
- const url = active.lyricModel ? KOE_VOICEBANK_TERMS[active.lyricModel] : void 0;
6329
- if (url) {
6339
+ const url2 = active.lyricModel ? KOE_VOICEBANK_TERMS[active.lyricModel] : void 0;
6340
+ if (url2) {
6330
6341
  const label = lyricModelLabel(active.lyricModel);
6331
6342
  lyricTermsLink.textContent = `${label}UTAU\u97F3\u6E90`;
6332
- lyricTermsLink.href = url;
6343
+ lyricTermsLink.href = url2;
6333
6344
  lyricTerms.classList.remove("dtm-hidden");
6334
6345
  } else {
6335
6346
  lyricTerms.classList.add("dtm-hidden");
@@ -6667,9 +6678,9 @@ var mountDAW = (target, options = {}) => {
6667
6678
  chordTrack.core.addHistoryOnce();
6668
6679
  redrawAll();
6669
6680
  };
6670
- const loadMIDI = (bytes) => {
6681
+ const loadMIDI = async (bytes) => {
6671
6682
  if (!options.parseMidi) return;
6672
- const midi = options.parseMidi(bytes);
6683
+ const midi = await options.parseMidi(bytes);
6673
6684
  const analysis = analyzeMidiTracks(midi);
6674
6685
  const selected = analysis.filter((a) => a.selected).map((a) => a.index);
6675
6686
  applyMidiSelection(midi, selected);
@@ -6833,13 +6844,13 @@ var mountDAW = (target, options = {}) => {
6833
6844
  });
6834
6845
  refs.generateMmlBtn.addEventListener("click", showMML);
6835
6846
  refs.exportMidiBtn.addEventListener("click", () => {
6836
- const blob = exportMIDI2();
6837
- const url = URL.createObjectURL(blob);
6847
+ const blob2 = exportMIDI2();
6848
+ const url2 = URL.createObjectURL(blob2);
6838
6849
  const a = document.createElement("a");
6839
- a.href = url;
6850
+ a.href = url2;
6840
6851
  a.download = "dtm.mid";
6841
6852
  a.click();
6842
- URL.revokeObjectURL(url);
6853
+ URL.revokeObjectURL(url2);
6843
6854
  });
6844
6855
  const copy = (text, btn) => {
6845
6856
  navigator.clipboard?.writeText(text);
@@ -6906,7 +6917,7 @@ var mountDAW = (target, options = {}) => {
6906
6917
  refs.overlay.hidden = false;
6907
6918
  setLoading(true);
6908
6919
  const buffer = new Uint8Array(await file.arrayBuffer());
6909
- pendingMidi = options.parseMidi(buffer);
6920
+ pendingMidi = await options.parseMidi(buffer);
6910
6921
  detectedTracks = analyzeMidiTracks(pendingMidi);
6911
6922
  refs.midiTrackSelection.innerHTML = `<span class="dtm-label">\u30C8\u30E9\u30C3\u30AF</span>`;
6912
6923
  detectedTracks.forEach((t, i) => {
@@ -7535,12 +7546,12 @@ var mountMmlPlayer = (target, mml, options = {}) => {
7535
7546
  termsRow.style.gap = "4px";
7536
7547
  termsRow.style.flexWrap = "wrap";
7537
7548
  const label = KOE_VOICEBANK_LABELS[model] ?? model;
7538
- const url = KOE_VOICEBANK_TERMS[model];
7549
+ const url2 = KOE_VOICEBANK_TERMS[model];
7539
7550
  const span1 = doc.createElement("span");
7540
7551
  span1.textContent = "\u4F7F\u7528\u6642\u306B\u306F";
7541
7552
  const a = doc.createElement("a");
7542
7553
  a.textContent = `${label}UTAU\u97F3\u6E90`;
7543
- a.href = url;
7554
+ a.href = url2;
7544
7555
  a.target = "_blank";
7545
7556
  a.rel = "noopener";
7546
7557
  a.style.color = "var(--dtm-primary)";
@@ -8009,12 +8020,172 @@ var createPianoRoll = (options, handlers) => {
8009
8020
  };
8010
8021
  };
8011
8022
 
8023
+ // node_modules/.pnpm/fast-unique-numbers@9.0.27/node_modules/fast-unique-numbers/build/es2019/factories/add-unique-number.js
8024
+ var createAddUniqueNumber = (generateUniqueNumber2) => {
8025
+ return (set) => {
8026
+ const number = generateUniqueNumber2(set);
8027
+ set.add(number);
8028
+ return number;
8029
+ };
8030
+ };
8031
+
8032
+ // node_modules/.pnpm/fast-unique-numbers@9.0.27/node_modules/fast-unique-numbers/build/es2019/factories/cache.js
8033
+ var createCache = (lastNumberWeakMap) => {
8034
+ return (collection, nextNumber) => {
8035
+ lastNumberWeakMap.set(collection, nextNumber);
8036
+ return nextNumber;
8037
+ };
8038
+ };
8039
+
8040
+ // node_modules/.pnpm/fast-unique-numbers@9.0.27/node_modules/fast-unique-numbers/build/es2019/factories/generate-unique-number.js
8041
+ var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER === void 0 ? 9007199254740991 : Number.MAX_SAFE_INTEGER;
8042
+ var TWO_TO_THE_POWER_OF_TWENTY_NINE = 536870912;
8043
+ var TWO_TO_THE_POWER_OF_THIRTY = TWO_TO_THE_POWER_OF_TWENTY_NINE * 2;
8044
+ var createGenerateUniqueNumber = (cache2, lastNumberWeakMap) => {
8045
+ return (collection) => {
8046
+ const lastNumber = lastNumberWeakMap.get(collection);
8047
+ let nextNumber = lastNumber === void 0 ? collection.size : lastNumber < TWO_TO_THE_POWER_OF_THIRTY ? lastNumber + 1 : 0;
8048
+ if (!collection.has(nextNumber)) {
8049
+ return cache2(collection, nextNumber);
8050
+ }
8051
+ if (collection.size < TWO_TO_THE_POWER_OF_TWENTY_NINE) {
8052
+ while (collection.has(nextNumber)) {
8053
+ nextNumber = Math.floor(Math.random() * TWO_TO_THE_POWER_OF_THIRTY);
8054
+ }
8055
+ return cache2(collection, nextNumber);
8056
+ }
8057
+ if (collection.size > MAX_SAFE_INTEGER) {
8058
+ throw new Error("Congratulations, you created a collection of unique numbers which uses all available integers!");
8059
+ }
8060
+ while (collection.has(nextNumber)) {
8061
+ nextNumber = Math.floor(Math.random() * MAX_SAFE_INTEGER);
8062
+ }
8063
+ return cache2(collection, nextNumber);
8064
+ };
8065
+ };
8066
+
8067
+ // node_modules/.pnpm/fast-unique-numbers@9.0.27/node_modules/fast-unique-numbers/build/es2019/module.js
8068
+ var LAST_NUMBER_WEAK_MAP = /* @__PURE__ */ new WeakMap();
8069
+ var cache = createCache(LAST_NUMBER_WEAK_MAP);
8070
+ var generateUniqueNumber = createGenerateUniqueNumber(cache, LAST_NUMBER_WEAK_MAP);
8071
+ var addUniqueNumber = createAddUniqueNumber(generateUniqueNumber);
8072
+
8073
+ // node_modules/.pnpm/broker-factory@3.1.15/node_modules/broker-factory/build/es2019/factories/create-broker.js
8074
+ var createBrokerFactory = (createOrGetOngoingRequests, extendBrokerImplementation, generateUniqueNumber2, isMessagePort2) => (brokerImplementation) => {
8075
+ const fullBrokerImplementation = extendBrokerImplementation(brokerImplementation);
8076
+ return (sender) => {
8077
+ const ongoingRequests = createOrGetOngoingRequests(sender);
8078
+ sender.addEventListener("message", (({ data: message }) => {
8079
+ const { id } = message;
8080
+ if (id !== null && ongoingRequests.has(id)) {
8081
+ const { reject, resolve } = ongoingRequests.get(id);
8082
+ ongoingRequests.delete(id);
8083
+ if (message.error === void 0) {
8084
+ resolve(message.result);
8085
+ } else {
8086
+ reject(new Error(message.error.message));
8087
+ }
8088
+ }
8089
+ }));
8090
+ if (isMessagePort2(sender)) {
8091
+ sender.start();
8092
+ }
8093
+ const call = (method, params = null, transferables = []) => {
8094
+ return new Promise((resolve, reject) => {
8095
+ const id = generateUniqueNumber2(ongoingRequests);
8096
+ ongoingRequests.set(id, { reject, resolve });
8097
+ if (params === null) {
8098
+ sender.postMessage({ id, method }, transferables);
8099
+ } else {
8100
+ sender.postMessage({ id, method, params }, transferables);
8101
+ }
8102
+ });
8103
+ };
8104
+ const notify = (method, params, transferables = []) => {
8105
+ sender.postMessage({ id: null, method, params }, transferables);
8106
+ };
8107
+ let functions = {};
8108
+ for (const [key, handler] of Object.entries(fullBrokerImplementation)) {
8109
+ functions = { ...functions, [key]: handler({ call, notify }) };
8110
+ }
8111
+ return { ...functions };
8112
+ };
8113
+ };
8114
+
8115
+ // node_modules/.pnpm/broker-factory@3.1.15/node_modules/broker-factory/build/es2019/factories/create-or-get-ongoing-requests.js
8116
+ var createCreateOrGetOngoingRequests = (ongoingRequestsMap) => (sender) => {
8117
+ if (ongoingRequestsMap.has(sender)) {
8118
+ return ongoingRequestsMap.get(sender);
8119
+ }
8120
+ const ongoingRequests = /* @__PURE__ */ new Map();
8121
+ ongoingRequestsMap.set(sender, ongoingRequests);
8122
+ return ongoingRequests;
8123
+ };
8124
+
8125
+ // node_modules/.pnpm/broker-factory@3.1.15/node_modules/broker-factory/build/es2019/factories/extend-broker-implementation.js
8126
+ var createExtendBrokerImplementation = (portMap) => (partialBrokerImplementation) => ({
8127
+ ...partialBrokerImplementation,
8128
+ connect: ({ call }) => {
8129
+ return async () => {
8130
+ const { port1, port2 } = new MessageChannel();
8131
+ const portId = await call("connect", { port: port1 }, [port1]);
8132
+ portMap.set(port2, portId);
8133
+ return port2;
8134
+ };
8135
+ },
8136
+ disconnect: ({ call }) => {
8137
+ return async (port) => {
8138
+ const portId = portMap.get(port);
8139
+ if (portId === void 0) {
8140
+ throw new Error("The given port is not connected.");
8141
+ }
8142
+ await call("disconnect", { portId });
8143
+ };
8144
+ },
8145
+ isSupported: ({ call }) => {
8146
+ return () => call("isSupported");
8147
+ }
8148
+ });
8149
+
8150
+ // node_modules/.pnpm/broker-factory@3.1.15/node_modules/broker-factory/build/es2019/guards/message-port.js
8151
+ var isMessagePort = (sender) => {
8152
+ return typeof sender.start === "function";
8153
+ };
8154
+
8155
+ // node_modules/.pnpm/broker-factory@3.1.15/node_modules/broker-factory/build/es2019/module.js
8156
+ var createBroker = createBrokerFactory(createCreateOrGetOngoingRequests(/* @__PURE__ */ new WeakMap()), createExtendBrokerImplementation(/* @__PURE__ */ new WeakMap()), generateUniqueNumber, isMessagePort);
8157
+
8158
+ // node_modules/.pnpm/midi-json-parser-broker@4.0.132/node_modules/midi-json-parser-broker/build/es2019/module.js
8159
+ var wrap = createBroker({
8160
+ parseArrayBuffer: ({ call }) => {
8161
+ return async (arrayBuffer) => {
8162
+ return call("parse", { arrayBuffer }, [arrayBuffer]);
8163
+ };
8164
+ }
8165
+ });
8166
+ var load = (url2) => {
8167
+ const worker2 = new Worker(url2);
8168
+ return wrap(worker2);
8169
+ };
8170
+
8171
+ // node_modules/.pnpm/midi-json-parser@8.1.74/node_modules/midi-json-parser/build/es2019/worker/worker.js
8172
+ var worker = `(()=>{var e={455(e,t){!function(e){"use strict";var t=function(e){return function(t){var n=e(t);return t.add(n),n}},n=function(e){return function(t,n){return e.set(t,n),n}},r=void 0===Number.MAX_SAFE_INTEGER?9007199254740991:Number.MAX_SAFE_INTEGER,o=536870912,s=2*o,i=function(e,t){return function(n){var i=t.get(n),a=void 0===i?n.size:i<s?i+1:0;if(!n.has(a))return e(n,a);if(n.size<o){for(;n.has(a);)a=Math.floor(Math.random()*s);return e(n,a)}if(n.size>r)throw new Error("Congratulations, you created a collection of unique numbers which uses all available integers!");for(;n.has(a);)a=Math.floor(Math.random()*r);return e(n,a)}},a=new WeakMap,f=n(a),c=i(f,a),u=t(c);e.addUniqueNumber=u,e.generateUniqueNumber=c}(t)}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var s=t[r]={exports:{}};return e[r].call(s.exports,s,s.exports,n),s.exports}(()=>{"use strict";const e=-32603,t=-32602,r=-32601,o=(e,t)=>Object.assign(new Error(e),{status:t}),s=t=>o('The handler of the method called "'.concat(t,'" returned an unexpected result.'),e),i=(t,n)=>async({data:{id:i,method:a,params:f}})=>{const c=n[a];try{if(void 0===c)throw(e=>o('The requested method called "'.concat(e,'" is not supported.'),r))(a);const n=void 0===f?c():c(f);if(void 0===n)throw(t=>o('The handler of the method called "'.concat(t,'" returned no required result.'),e))(a);const u=n instanceof Promise?await n:n;if(null===i){if(void 0!==u.result)throw s(a)}else{if(void 0===u.result)throw s(a);const{result:e,transferables:n=[]}=u;t.postMessage({id:i,result:e},n)}}catch(e){const{message:n,status:r=-32603}=e;t.postMessage({error:{code:r,message:n},id:i})}};var a=n(455);const f=new Map,c=(e,n,r)=>({...n,connect:({port:t})=>{t.start();const r=e(t,n),o=(0,a.generateUniqueNumber)(f);return f.set(o,()=>{r(),t.close(),f.delete(o)}),{result:o}},disconnect:({portId:e})=>{const n=f.get(e);if(void 0===n)throw(e=>o('The specified parameter called "portId" with the given value "'.concat(e,'" does not identify a port connected to this worker.'),t))(e);return n(),{result:null}},isSupported:async()=>{if(await new Promise(e=>{const t=new ArrayBuffer(0),{port1:n,port2:r}=new MessageChannel;n.onmessage=({data:t})=>e(null!==t),r.postMessage(t,[t])})){const e=r();return{result:e instanceof Promise?await e:e}}return{result:!1}}}),u=(e,t,n=()=>!0)=>{const r=c(u,t,n),o=i(e,r);return e.addEventListener("message",o),()=>e.removeEventListener("message",o)},l=e=>void 0!==e.channel,d=e=>e.toString(16).toUpperCase().padStart(2,"0"),g=(e,t=0,n=e.byteLength-(t-e.byteOffset))=>{const r=t+e.byteOffset,o=[],s=new Uint8Array(e.buffer,r,n);for(let e=0;e<n;e+=1)o[e]=d(s[e]);return o.join("")},h=(e,t=0,n=e.byteLength-(t-e.byteOffset))=>{const r=t+e.byteOffset,o=new Uint8Array(e.buffer,r,n);return String.fromCharCode.apply(null,o)},m=e=>{const t=new DataView(e),n=v(t);let r=14;const o=[];for(let e=0,s=n.numberOfTracks;e<s;e+=1){let e;({offset:r,track:e}=b(t,r)),o.push(e)}return{division:n.division,format:n.format,tracks:o}},p=(e,t,n)=>{let r;const{offset:o,value:s}=T(e,t),i=e.getUint8(o);return r=240===i?y(e,o+1):255===i?U(e,o+1):w(i,e,o+1,n),{...r,event:{...r.event,delta:s},eventTypeByte:i}},v=e=>{if(e.byteLength<14)throw new Error("Expected at least 14 bytes instead of ".concat(e.byteLength));if("MThd"!==h(e,0,4))throw new Error('Unexpected characters "'.concat(h(e,0,4),'" found instead of "MThd"'));if(6!==e.getUint32(4))throw new Error("The header has an unexpected length of ".concat(e.getUint32(4)," instead of 6"));const t=e.getUint16(8),n=e.getUint16(10);return{division:e.getUint16(12),format:t,numberOfTracks:n}},U=(e,t)=>{let n;const r=e.getUint8(t),{offset:o,value:s}=T(e,t+1);if(1===r)n={text:h(e,o,s)};else if(2===r)n={copyrightNotice:h(e,o,s)};else if(3===r)n={trackName:h(e,o,s)};else if(4===r)n={instrumentName:h(e,o,s)};else if(5===r)n={lyric:h(e,o,s)};else if(6===r)n={marker:h(e,o,s)};else if(7===r)n={cuePoint:h(e,o,s)};else if(8===r)n={programName:h(e,o,s)};else if(9===r)n={deviceName:h(e,o,s)};else if(10===r||11===r||12===r||13===r||14===r||15===r)n={metaTypeByte:d(r),text:h(e,o,s)};else if(32===r)n={channelPrefix:e.getUint8(o)};else if(33===r)n={midiPort:e.getUint8(o)};else if(47===r)n={endOfTrack:!0};else if(81===r)n={setTempo:{microsecondsPerQuarter:(e.getUint8(o)<<16)+(e.getUint8(o+1)<<8)+e.getUint8(o+2)}};else if(84===r){let t;const r=e.getUint8(o);96&r?32==(96&r)?t=25:64==(96&r)?t=29:96&~r||(t=30):t=24,n={smpteOffset:{frame:e.getUint8(o+3),frameRate:t,hour:31&r,minutes:e.getUint8(o+1),seconds:e.getUint8(o+2),subFrame:e.getUint8(o+4)}}}else if(88===r)n={timeSignature:{denominator:Math.pow(2,e.getUint8(o+1)),metronome:e.getUint8(o+2),numerator:e.getUint8(o),thirtyseconds:e.getUint8(o+3)}};else if(89===r)n={keySignature:{key:e.getInt8(o),scale:e.getInt8(o+1)}};else{if(127!==r)throw new Error('Cannot parse a meta event with a type of "'.concat(d(r),'"'));n={sequencerSpecificData:g(e,o,s)}}return{event:n,offset:o+s}},w=(e,t,n,r)=>{const o=128&e?null:r,s=(null===o?e:o)>>4;let i,a=null===o?n:n-1;if(8===s)i={noteOff:{noteNumber:t.getUint8(a),velocity:t.getUint8(a+1)}},a+=2;else if(9===s){const e=t.getUint8(a),n=t.getUint8(a+1);i=0===n?{noteOff:{noteNumber:e,velocity:n}}:{noteOn:{noteNumber:e,velocity:n}},a+=2}else if(10===s)i={keyPressure:{noteNumber:t.getUint8(a),pressure:t.getUint8(a+1)}},a+=2;else if(11===s)i={controlChange:{type:t.getUint8(a),value:t.getUint8(a+1)}},a+=2;else if(12===s)i={programChange:{programNumber:t.getUint8(a)}},a+=1;else if(13===s)i={channelPressure:{pressure:t.getUint8(a)}},a+=1;else{if(14!==s)throw new Error('Cannot parse a midi event with a type of "'.concat(d(s),'"'));i={pitchBend:t.getUint8(a)|t.getUint8(a+1)<<7},a+=2}return i.channel=15&(null===o?e:o),{event:i,offset:a}},y=(e,t)=>{const{offset:n,value:r}=T(e,t);return{event:{sysex:g(e,n,r)},offset:n+r}},b=(e,t)=>{if("MTrk"!==h(e,t,4))throw new Error('Unexpected characters "'.concat(h(e,t,4),'" found instead of "MTrk"'));const n=[],r=e.getUint32(t+4)+t+8;let o=null,s=t+8;for(;s<r;){const t=p(e,s,o),{event:r,eventTypeByte:i}=t;n.push(r),s=t.offset,l(r)&&(128&i)>0&&(o=i)}return{offset:s,track:n}},T=(e,t)=>{let n=t,r=0;for(;;){const t=e.getUint8(n);if(n+=1,!(t>127))return r+=t,{offset:n,value:r};r+=127&t,r<<=7}};u(self,{parse:({arrayBuffer:e})=>({result:m(e)})})})()})();`;
8173
+
8174
+ // node_modules/.pnpm/midi-json-parser@8.1.74/node_modules/midi-json-parser/build/es2019/module.js
8175
+ var blob = new Blob([worker], { type: "application/javascript; charset=utf-8" });
8176
+ var url = URL.createObjectURL(blob);
8177
+ var midiJsonParser = load(url);
8178
+ var connect = midiJsonParser.connect;
8179
+ var disconnect = midiJsonParser.disconnect;
8180
+ var isSupported = midiJsonParser.isSupported;
8181
+ var parseArrayBuffer = midiJsonParser.parseArrayBuffer;
8182
+ URL.revokeObjectURL(url);
8183
+
8012
8184
  // src/studio.ts
8013
8185
  var DEFAULT_CDN = {
8014
8186
  soundFont: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont.mjs",
8015
8187
  soundFontDrum: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_drum.mjs",
8016
- soundFontList: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_list.mjs",
8017
- midiParser: "https://cdn.jsdelivr.net/npm/midi-parser-js@4.0.4/+esm"
8188
+ soundFontList: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_list.mjs"
8018
8189
  };
8019
8190
  var SOUNDFONT_NAME = "FluidR3_GM_sf2_file";
8020
8191
  var TRACK_ROLES = ["melody", "submelody", "bass", "chord"];
@@ -8025,10 +8196,10 @@ var resolveDefaultVoiceWorkerUrl = () => {
8025
8196
  return void 0;
8026
8197
  }
8027
8198
  };
8028
- var importFrom = async (url, name) => {
8199
+ var importFrom = async (url2, name) => {
8029
8200
  const mod = await import(
8030
8201
  /* @vite-ignore */
8031
- url
8202
+ url2
8032
8203
  );
8033
8204
  return mod[name] ?? mod.default;
8034
8205
  };
@@ -8057,23 +8228,17 @@ var createDtmStudio = async (options = {}) => {
8057
8228
  eng.SoundFont_drum ?? importFrom(cdn.soundFontDrum, "SoundFont_drum"),
8058
8229
  eng.SoundFont_list ?? importFrom(cdn.soundFontList, "SoundFont_list")
8059
8230
  ]);
8060
- let midiParser = null;
8061
8231
  let parseMidi;
8062
8232
  if (features.midi) {
8063
- parseMidi = eng.parseMidi;
8064
- if (!parseMidi) {
8065
- const midiPromise = importFrom(
8066
- cdn.midiParser,
8067
- "default"
8068
- ).then((m) => {
8069
- midiParser = m;
8070
- }).catch((e) => console.warn("[dtm] midi-parser \u306E\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557", e));
8071
- void midiPromise;
8072
- parseMidi = (bytes) => {
8073
- if (!midiParser) throw new Error("midi-parser not ready");
8074
- return midiParser.parse(bytes);
8075
- };
8076
- }
8233
+ parseMidi = eng.parseMidi || ((bytes) => {
8234
+ const buffer = bytes.buffer;
8235
+ if (buffer instanceof ArrayBuffer) {
8236
+ return parseArrayBuffer(
8237
+ buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)
8238
+ );
8239
+ }
8240
+ throw new Error("SharedArrayBuffer is not supported for MIDI parsing");
8241
+ });
8077
8242
  }
8078
8243
  const voiceWorkerUrl = options.voiceWorkerUrl === null ? void 0 : options.voiceWorkerUrl ?? resolveDefaultVoiceWorkerUrl();
8079
8244
  const singingVoices = createSingingVoices(audioCtx, masterGain, {
@@ -8124,13 +8289,13 @@ var createDtmStudio = async (options = {}) => {
8124
8289
  clamp4(Math.round(wave[i] * 32768), -32768, 32767),
8125
8290
  true
8126
8291
  );
8127
- const blob = new Blob([view], { type: "audio/wav" });
8128
- const url = URL.createObjectURL(blob);
8292
+ const blob2 = new Blob([view], { type: "audio/wav" });
8293
+ const url2 = URL.createObjectURL(blob2);
8129
8294
  const a = document.createElement("a");
8130
- a.href = url;
8295
+ a.href = url2;
8131
8296
  a.download = "record.wav";
8132
8297
  a.click();
8133
- URL.revokeObjectURL(url);
8298
+ URL.revokeObjectURL(url2);
8134
8299
  };
8135
8300
  const onToggleRecord = recorder ? () => {
8136
8301
  if (recorder.isRecording()) {
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.15",
5
+ "version": "0.1.16",
6
6
  "description": "MMLを中間言語に用いた、モバイルファーストなDAW / ピアノロール打ち込みコンポーネント",
7
7
  "homepage": "https://onjmin.github.io/dtm",
8
8
  "repository": {
@@ -54,7 +54,8 @@
54
54
  "dependencies": {
55
55
  "@onjmin/chord-parser": "1.0.2",
56
56
  "@onjmin/dtm": "0.1.14",
57
- "@onjmin/koe": "1.0.3"
57
+ "@onjmin/koe": "1.0.3",
58
+ "midi-json-parser": "8.1.74"
58
59
  },
59
60
  "scripts": {
60
61
  "dev": "rimraf dist && tsup && biome format src --write && tsx demo/server.ts",