@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/README.md +21 -1
- package/dist/index.d.mts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +272 -114
- package/dist/index.mjs +272 -114
- package/package.json +4 -2
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(
|
|
1526
|
-
this.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(
|
|
1538
|
-
this.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(
|
|
1555
|
-
const res = await fetch(
|
|
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 (
|
|
2327
|
-
const sameOrigin = new URL(
|
|
2328
|
-
if (sameOrigin) return new Worker(
|
|
2329
|
-
const text = await fetch(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: () =>
|
|
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
|
|
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) =>
|
|
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 {
|
|
2781
|
+
const { tracks } = midi;
|
|
2782
2782
|
const result = [];
|
|
2783
|
-
for (let i = 0; i <
|
|
2783
|
+
for (let i = 0; i < tracks.length; i++) {
|
|
2784
2784
|
const notes = [];
|
|
2785
2785
|
let currentTime = 0;
|
|
2786
|
-
for (const event of
|
|
2787
|
-
currentTime += event.
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
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 {
|
|
2814
|
-
for (const
|
|
2815
|
-
for (const
|
|
2816
|
-
if (
|
|
2817
|
-
|
|
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 {
|
|
2828
|
-
const ticksPerBeat =
|
|
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 =
|
|
2834
|
+
const trackData = tracks[trackIdx];
|
|
2833
2835
|
if (!trackData) continue;
|
|
2834
2836
|
let currentTime = 0;
|
|
2835
|
-
for (const event of trackData
|
|
2836
|
-
currentTime += event.
|
|
2837
|
+
for (const event of trackData) {
|
|
2838
|
+
currentTime += event.delta;
|
|
2837
2839
|
if (event.channel === 9) continue;
|
|
2838
|
-
if (event.
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
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 {
|
|
2971
|
-
const ticksPerBeat =
|
|
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 =
|
|
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
|
|
2983
|
-
currentTime += event.
|
|
2990
|
+
for (const event of trackData) {
|
|
2991
|
+
currentTime += event.delta;
|
|
2984
2992
|
if (event.channel === 9) continue;
|
|
2985
|
-
if (event.
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
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
|
|
6336
|
-
if (
|
|
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 =
|
|
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
|
|
6844
|
-
const
|
|
6847
|
+
const blob2 = exportMIDI2();
|
|
6848
|
+
const url2 = URL.createObjectURL(blob2);
|
|
6845
6849
|
const a = document.createElement("a");
|
|
6846
|
-
a.href =
|
|
6850
|
+
a.href = url2;
|
|
6847
6851
|
a.download = "dtm.mid";
|
|
6848
6852
|
a.click();
|
|
6849
|
-
URL.revokeObjectURL(
|
|
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
|
|
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 =
|
|
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 (
|
|
8199
|
+
var importFrom = async (url2, name) => {
|
|
8036
8200
|
const mod = await import(
|
|
8037
8201
|
/* @vite-ignore */
|
|
8038
|
-
|
|
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
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
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
|
|
8135
|
-
const
|
|
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 =
|
|
8295
|
+
a.href = url2;
|
|
8138
8296
|
a.download = "record.wav";
|
|
8139
8297
|
a.click();
|
|
8140
|
-
URL.revokeObjectURL(
|
|
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.
|
|
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/
|
|
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",
|