@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 +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.js +272 -107
- package/dist/index.mjs +272 -107
- package/package.json +3 -2
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(
|
|
1631
|
-
this.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(
|
|
1643
|
-
this.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(
|
|
1660
|
-
const res = await fetch(
|
|
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 (
|
|
2432
|
-
const sameOrigin = new URL(
|
|
2433
|
-
if (sameOrigin) return new Worker(
|
|
2434
|
-
const text = await fetch(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: () =>
|
|
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
|
|
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) =>
|
|
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 {
|
|
2886
|
+
const { tracks } = midi;
|
|
2887
2887
|
const result = [];
|
|
2888
|
-
for (let i = 0; i <
|
|
2888
|
+
for (let i = 0; i < tracks.length; i++) {
|
|
2889
2889
|
const notes = [];
|
|
2890
2890
|
let currentTime = 0;
|
|
2891
|
-
for (const event of
|
|
2892
|
-
currentTime += event.
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
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 {
|
|
2919
|
-
for (const
|
|
2920
|
-
for (const
|
|
2921
|
-
if (
|
|
2922
|
-
|
|
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 {
|
|
2933
|
-
const ticksPerBeat =
|
|
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 =
|
|
2939
|
+
const trackData = tracks[trackIdx];
|
|
2938
2940
|
if (!trackData) continue;
|
|
2939
2941
|
let currentTime = 0;
|
|
2940
|
-
for (const event of trackData
|
|
2941
|
-
currentTime += event.
|
|
2942
|
+
for (const event of trackData) {
|
|
2943
|
+
currentTime += event.delta;
|
|
2942
2944
|
if (event.channel === 9) continue;
|
|
2943
|
-
if (event.
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
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 {
|
|
3076
|
-
const ticksPerBeat =
|
|
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 =
|
|
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
|
|
3088
|
-
currentTime += event.
|
|
3095
|
+
for (const event of trackData) {
|
|
3096
|
+
currentTime += event.delta;
|
|
3089
3097
|
if (event.channel === 9) continue;
|
|
3090
|
-
if (event.
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
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
|
|
6434
|
-
if (
|
|
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 =
|
|
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
|
|
6942
|
-
const
|
|
6952
|
+
const blob2 = exportMIDI2();
|
|
6953
|
+
const url2 = URL.createObjectURL(blob2);
|
|
6943
6954
|
const a = document.createElement("a");
|
|
6944
|
-
a.href =
|
|
6955
|
+
a.href = url2;
|
|
6945
6956
|
a.download = "dtm.mid";
|
|
6946
6957
|
a.click();
|
|
6947
|
-
URL.revokeObjectURL(
|
|
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
|
|
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 =
|
|
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 (
|
|
8305
|
+
var importFrom = async (url2, name) => {
|
|
8135
8306
|
const mod = await import(
|
|
8136
8307
|
/* @vite-ignore */
|
|
8137
|
-
|
|
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
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
|
|
8177
|
-
|
|
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
|
|
8234
|
-
const
|
|
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 =
|
|
8401
|
+
a.href = url2;
|
|
8237
8402
|
a.download = "record.wav";
|
|
8238
8403
|
a.click();
|
|
8239
|
-
URL.revokeObjectURL(
|
|
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(
|
|
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) {
|
|
@@ -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
|
|
6329
|
-
if (
|
|
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 =
|
|
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
|
|
6837
|
-
const
|
|
6847
|
+
const blob2 = exportMIDI2();
|
|
6848
|
+
const url2 = URL.createObjectURL(blob2);
|
|
6838
6849
|
const a = document.createElement("a");
|
|
6839
|
-
a.href =
|
|
6850
|
+
a.href = url2;
|
|
6840
6851
|
a.download = "dtm.mid";
|
|
6841
6852
|
a.click();
|
|
6842
|
-
URL.revokeObjectURL(
|
|
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
|
|
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 =
|
|
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 (
|
|
8199
|
+
var importFrom = async (url2, name) => {
|
|
8029
8200
|
const mod = await import(
|
|
8030
8201
|
/* @vite-ignore */
|
|
8031
|
-
|
|
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
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
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
|
|
8128
|
-
const
|
|
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 =
|
|
8295
|
+
a.href = url2;
|
|
8131
8296
|
a.download = "record.wav";
|
|
8132
8297
|
a.click();
|
|
8133
|
-
URL.revokeObjectURL(
|
|
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.
|
|
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",
|