@onjmin/dtm 0.1.14 → 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.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) {
@@ -5424,13 +5435,6 @@ var TRACKS_ADVANCED = [
5424
5435
  color: [100, 255, 160],
5425
5436
  instrument: 14,
5426
5437
  volume: 100
5427
- },
5428
- {
5429
- id: "t15",
5430
- name: "TRACK 16",
5431
- color: [255, 150, 200],
5432
- instrument: 15,
5433
- volume: 100
5434
5438
  }
5435
5439
  ];
5436
5440
  var DEFAULT_TRACKS = TRACKS_SIMPLE;
@@ -6332,11 +6336,11 @@ var mountDAW = (target, options = {}) => {
6332
6336
  lyricCount.textContent = active.lyricModel && n > 0 ? `${n}\u97F3\u7BC0` : "";
6333
6337
  };
6334
6338
  const syncLyricTerms = () => {
6335
- const url = active.lyricModel ? KOE_VOICEBANK_TERMS[active.lyricModel] : void 0;
6336
- if (url) {
6339
+ const url2 = active.lyricModel ? KOE_VOICEBANK_TERMS[active.lyricModel] : void 0;
6340
+ if (url2) {
6337
6341
  const label = lyricModelLabel(active.lyricModel);
6338
6342
  lyricTermsLink.textContent = `${label}UTAU\u97F3\u6E90`;
6339
- lyricTermsLink.href = url;
6343
+ lyricTermsLink.href = url2;
6340
6344
  lyricTerms.classList.remove("dtm-hidden");
6341
6345
  } else {
6342
6346
  lyricTerms.classList.add("dtm-hidden");
@@ -6674,9 +6678,9 @@ var mountDAW = (target, options = {}) => {
6674
6678
  chordTrack.core.addHistoryOnce();
6675
6679
  redrawAll();
6676
6680
  };
6677
- const loadMIDI = (bytes) => {
6681
+ const loadMIDI = async (bytes) => {
6678
6682
  if (!options.parseMidi) return;
6679
- const midi = options.parseMidi(bytes);
6683
+ const midi = await options.parseMidi(bytes);
6680
6684
  const analysis = analyzeMidiTracks(midi);
6681
6685
  const selected = analysis.filter((a) => a.selected).map((a) => a.index);
6682
6686
  applyMidiSelection(midi, selected);
@@ -6840,13 +6844,13 @@ var mountDAW = (target, options = {}) => {
6840
6844
  });
6841
6845
  refs.generateMmlBtn.addEventListener("click", showMML);
6842
6846
  refs.exportMidiBtn.addEventListener("click", () => {
6843
- const blob = exportMIDI2();
6844
- const url = URL.createObjectURL(blob);
6847
+ const blob2 = exportMIDI2();
6848
+ const url2 = URL.createObjectURL(blob2);
6845
6849
  const a = document.createElement("a");
6846
- a.href = url;
6850
+ a.href = url2;
6847
6851
  a.download = "dtm.mid";
6848
6852
  a.click();
6849
- URL.revokeObjectURL(url);
6853
+ URL.revokeObjectURL(url2);
6850
6854
  });
6851
6855
  const copy = (text, btn) => {
6852
6856
  navigator.clipboard?.writeText(text);
@@ -6913,7 +6917,7 @@ var mountDAW = (target, options = {}) => {
6913
6917
  refs.overlay.hidden = false;
6914
6918
  setLoading(true);
6915
6919
  const buffer = new Uint8Array(await file.arrayBuffer());
6916
- pendingMidi = options.parseMidi(buffer);
6920
+ pendingMidi = await options.parseMidi(buffer);
6917
6921
  detectedTracks = analyzeMidiTracks(pendingMidi);
6918
6922
  refs.midiTrackSelection.innerHTML = `<span class="dtm-label">\u30C8\u30E9\u30C3\u30AF</span>`;
6919
6923
  detectedTracks.forEach((t, i) => {
@@ -7542,12 +7546,12 @@ var mountMmlPlayer = (target, mml, options = {}) => {
7542
7546
  termsRow.style.gap = "4px";
7543
7547
  termsRow.style.flexWrap = "wrap";
7544
7548
  const label = KOE_VOICEBANK_LABELS[model] ?? model;
7545
- const url = KOE_VOICEBANK_TERMS[model];
7549
+ const url2 = KOE_VOICEBANK_TERMS[model];
7546
7550
  const span1 = doc.createElement("span");
7547
7551
  span1.textContent = "\u4F7F\u7528\u6642\u306B\u306F";
7548
7552
  const a = doc.createElement("a");
7549
7553
  a.textContent = `${label}UTAU\u97F3\u6E90`;
7550
- a.href = url;
7554
+ a.href = url2;
7551
7555
  a.target = "_blank";
7552
7556
  a.rel = "noopener";
7553
7557
  a.style.color = "var(--dtm-primary)";
@@ -8016,12 +8020,172 @@ var createPianoRoll = (options, handlers) => {
8016
8020
  };
8017
8021
  };
8018
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
+
8019
8184
  // src/studio.ts
8020
8185
  var DEFAULT_CDN = {
8021
8186
  soundFont: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont.mjs",
8022
8187
  soundFontDrum: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_drum.mjs",
8023
- soundFontList: "https://rpgen3.github.io/soundfont/mjs/surikov/SoundFont_list.mjs",
8024
- 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"
8025
8189
  };
8026
8190
  var SOUNDFONT_NAME = "FluidR3_GM_sf2_file";
8027
8191
  var TRACK_ROLES = ["melody", "submelody", "bass", "chord"];
@@ -8032,10 +8196,10 @@ var resolveDefaultVoiceWorkerUrl = () => {
8032
8196
  return void 0;
8033
8197
  }
8034
8198
  };
8035
- var importFrom = async (url, name) => {
8199
+ var importFrom = async (url2, name) => {
8036
8200
  const mod = await import(
8037
8201
  /* @vite-ignore */
8038
- url
8202
+ url2
8039
8203
  );
8040
8204
  return mod[name] ?? mod.default;
8041
8205
  };
@@ -8064,23 +8228,17 @@ var createDtmStudio = async (options = {}) => {
8064
8228
  eng.SoundFont_drum ?? importFrom(cdn.soundFontDrum, "SoundFont_drum"),
8065
8229
  eng.SoundFont_list ?? importFrom(cdn.soundFontList, "SoundFont_list")
8066
8230
  ]);
8067
- let midiParser = null;
8068
8231
  let parseMidi;
8069
8232
  if (features.midi) {
8070
- parseMidi = eng.parseMidi;
8071
- if (!parseMidi) {
8072
- const midiPromise = importFrom(
8073
- cdn.midiParser,
8074
- "default"
8075
- ).then((m) => {
8076
- midiParser = m;
8077
- }).catch((e) => console.warn("[dtm] midi-parser \u306E\u8AAD\u307F\u8FBC\u307F\u306B\u5931\u6557", e));
8078
- void midiPromise;
8079
- parseMidi = (bytes) => {
8080
- if (!midiParser) throw new Error("midi-parser not ready");
8081
- return midiParser.parse(bytes);
8082
- };
8083
- }
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
+ });
8084
8242
  }
8085
8243
  const voiceWorkerUrl = options.voiceWorkerUrl === null ? void 0 : options.voiceWorkerUrl ?? resolveDefaultVoiceWorkerUrl();
8086
8244
  const singingVoices = createSingingVoices(audioCtx, masterGain, {
@@ -8131,13 +8289,13 @@ var createDtmStudio = async (options = {}) => {
8131
8289
  clamp4(Math.round(wave[i] * 32768), -32768, 32767),
8132
8290
  true
8133
8291
  );
8134
- const blob = new Blob([view], { type: "audio/wav" });
8135
- const url = URL.createObjectURL(blob);
8292
+ const blob2 = new Blob([view], { type: "audio/wav" });
8293
+ const url2 = URL.createObjectURL(blob2);
8136
8294
  const a = document.createElement("a");
8137
- a.href = url;
8295
+ a.href = url2;
8138
8296
  a.download = "record.wav";
8139
8297
  a.click();
8140
- URL.revokeObjectURL(url);
8298
+ URL.revokeObjectURL(url2);
8141
8299
  };
8142
8300
  const onToggleRecord = recorder ? () => {
8143
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.14",
5
+ "version": "0.1.16",
6
6
  "description": "MMLを中間言語に用いた、モバイルファーストなDAW / ピアノロール打ち込みコンポーネント",
7
7
  "homepage": "https://onjmin.github.io/dtm",
8
8
  "repository": {
@@ -53,7 +53,9 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@onjmin/chord-parser": "1.0.2",
56
- "@onjmin/koe": "1.0.3"
56
+ "@onjmin/dtm": "0.1.14",
57
+ "@onjmin/koe": "1.0.3",
58
+ "midi-json-parser": "8.1.74"
57
59
  },
58
60
  "scripts": {
59
61
  "dev": "rimraf dist && tsup && biome format src --write && tsx demo/server.ts",