@onjmin/dtm 0.1.68 → 0.1.70
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 +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +124 -14
- package/dist/index.mjs +124 -14
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1827,6 +1827,12 @@ type DtmStudio = {
|
|
|
1827
1827
|
mountChordPlayer: (target: HTMLElement, chords: string, options?: Omit<MountChordPlayerOptions, "studio">) => ChordPlayerInstance;
|
|
1828
1828
|
/** UIなしで高品質な楽器再生(SoundFont)を行う */
|
|
1829
1829
|
play: (mml: string, options?: Omit<PlayMmlOptions, "audioContext" | "destination" | "onPlayNote" | "onPlayDrum" | "synth">) => MmlPlayback;
|
|
1830
|
+
/** UIなしで高品質な楽器再生(SoundFont)+歌声合成を行う */
|
|
1831
|
+
playSingingMML: (mml: string, options?: Omit<PlaySingingMmlOptions, "audioContext" | "destination" | "onPlayNote" | "onPlayDrum" | "synth">) => Promise<MmlPlayback>;
|
|
1832
|
+
/** SoundFontへ PlayNoteEvent を鳴らす(headless API の onPlayNote フック用) */
|
|
1833
|
+
playNoteEvent: (e: PlayNoteEvent) => void;
|
|
1834
|
+
/** SoundFontへ PlayDrumEvent を鳴らす(headless API の onPlayDrum フック用) */
|
|
1835
|
+
playDrumEvent: (e: PlayDrumEvent) => void;
|
|
1830
1836
|
/** SoundFontを用いた単音再生を行う */
|
|
1831
1837
|
playNote: (options: {
|
|
1832
1838
|
pitch: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -1827,6 +1827,12 @@ type DtmStudio = {
|
|
|
1827
1827
|
mountChordPlayer: (target: HTMLElement, chords: string, options?: Omit<MountChordPlayerOptions, "studio">) => ChordPlayerInstance;
|
|
1828
1828
|
/** UIなしで高品質な楽器再生(SoundFont)を行う */
|
|
1829
1829
|
play: (mml: string, options?: Omit<PlayMmlOptions, "audioContext" | "destination" | "onPlayNote" | "onPlayDrum" | "synth">) => MmlPlayback;
|
|
1830
|
+
/** UIなしで高品質な楽器再生(SoundFont)+歌声合成を行う */
|
|
1831
|
+
playSingingMML: (mml: string, options?: Omit<PlaySingingMmlOptions, "audioContext" | "destination" | "onPlayNote" | "onPlayDrum" | "synth">) => Promise<MmlPlayback>;
|
|
1832
|
+
/** SoundFontへ PlayNoteEvent を鳴らす(headless API の onPlayNote フック用) */
|
|
1833
|
+
playNoteEvent: (e: PlayNoteEvent) => void;
|
|
1834
|
+
/** SoundFontへ PlayDrumEvent を鳴らす(headless API の onPlayDrum フック用) */
|
|
1835
|
+
playDrumEvent: (e: PlayDrumEvent) => void;
|
|
1830
1836
|
/** SoundFontを用いた単音再生を行う */
|
|
1831
1837
|
playNote: (options: {
|
|
1832
1838
|
pitch: number;
|
package/dist/index.js
CHANGED
|
@@ -3417,6 +3417,13 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
3417
3417
|
const wave = tone.wave ?? "square";
|
|
3418
3418
|
const attack = tone.attack ?? 0;
|
|
3419
3419
|
const gainScale = tone.gain ?? 1;
|
|
3420
|
+
const compressor = ctx.createDynamicsCompressor();
|
|
3421
|
+
compressor.threshold.value = -12;
|
|
3422
|
+
compressor.knee.value = 6;
|
|
3423
|
+
compressor.ratio.value = 8;
|
|
3424
|
+
compressor.attack.value = 3e-3;
|
|
3425
|
+
compressor.release.value = 0.15;
|
|
3426
|
+
compressor.connect(destination);
|
|
3420
3427
|
const playNote3 = (e) => {
|
|
3421
3428
|
const osc = ctx.createOscillator();
|
|
3422
3429
|
const gain = ctx.createGain();
|
|
@@ -3449,9 +3456,9 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
3449
3456
|
panner = ctx.createStereoPanner();
|
|
3450
3457
|
panner.pan.value = Math.max(-1, Math.min(1, e.pan));
|
|
3451
3458
|
gain.connect(panner);
|
|
3452
|
-
panner.connect(
|
|
3459
|
+
panner.connect(compressor);
|
|
3453
3460
|
} else {
|
|
3454
|
-
gain.connect(
|
|
3461
|
+
gain.connect(compressor);
|
|
3455
3462
|
}
|
|
3456
3463
|
osc.start(t0);
|
|
3457
3464
|
osc.stop(t0 + e.duration + 0.02);
|
|
@@ -3473,7 +3480,7 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
3473
3480
|
osc.frequency.exponentialRampToValueAtTime(50, t0 + 0.12);
|
|
3474
3481
|
g2.gain.setValueAtTime(vol * 0.135, t0);
|
|
3475
3482
|
g2.gain.exponentialRampToValueAtTime(1e-3, t0 + 0.18);
|
|
3476
|
-
osc.connect(g2).connect(
|
|
3483
|
+
osc.connect(g2).connect(compressor);
|
|
3477
3484
|
osc.start(t0);
|
|
3478
3485
|
osc.stop(t0 + 0.2);
|
|
3479
3486
|
osc.onended = () => osc.disconnect();
|
|
@@ -3492,7 +3499,7 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
3492
3499
|
const g = ctx.createGain();
|
|
3493
3500
|
g.gain.setValueAtTime(vol * (isSnareLike ? 0.105 : 0.06), t0);
|
|
3494
3501
|
g.gain.exponentialRampToValueAtTime(1e-3, t0 + dur);
|
|
3495
|
-
src.connect(filter).connect(g).connect(
|
|
3502
|
+
src.connect(filter).connect(g).connect(compressor);
|
|
3496
3503
|
src.start(t0);
|
|
3497
3504
|
src.stop(t0 + dur);
|
|
3498
3505
|
src.onended = () => {
|
|
@@ -3506,6 +3513,7 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
3506
3513
|
|
|
3507
3514
|
// src/headless-player.ts
|
|
3508
3515
|
var STEPS_PER_BAR = 192;
|
|
3516
|
+
var TRACK_ID_BY_INDEX = ["melody", "submelody", "bass", "chord"];
|
|
3509
3517
|
var playPlacements = (placements, options) => {
|
|
3510
3518
|
const bpm = options.bpm;
|
|
3511
3519
|
const drumPatternDict = options.drumPatterns ?? DRUM_PATTERNS;
|
|
@@ -3524,7 +3532,11 @@ var playPlacements = (placements, options) => {
|
|
|
3524
3532
|
pitch: p.pitch,
|
|
3525
3533
|
velocity: p.velocity
|
|
3526
3534
|
}));
|
|
3527
|
-
return {
|
|
3535
|
+
return {
|
|
3536
|
+
id: TRACK_ID_BY_INDEX[index] ?? `t${index}`,
|
|
3537
|
+
volume: masterVolume,
|
|
3538
|
+
notes
|
|
3539
|
+
};
|
|
3528
3540
|
});
|
|
3529
3541
|
const ownsCtx = !options.audioContext;
|
|
3530
3542
|
const ctx = options.audioContext ?? new AudioContext();
|
|
@@ -13150,6 +13162,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13150
13162
|
// src/headless-singing-player.ts
|
|
13151
13163
|
var STEPS_PER_BEAT4 = 48;
|
|
13152
13164
|
var STEPS_PER_BAR3 = 192;
|
|
13165
|
+
var TRACK_ID_BY_INDEX2 = ["melody", "submelody", "bass", "chord"];
|
|
13153
13166
|
var playSingingMML = async (mml, options = {}) => {
|
|
13154
13167
|
const {
|
|
13155
13168
|
placements,
|
|
@@ -13183,7 +13196,7 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
13183
13196
|
velocity: p.velocity
|
|
13184
13197
|
}));
|
|
13185
13198
|
return {
|
|
13186
|
-
id:
|
|
13199
|
+
id: TRACK_ID_BY_INDEX2[index] ?? `t${index}`,
|
|
13187
13200
|
volume: trackVolume / 100 * masterVolume,
|
|
13188
13201
|
notes
|
|
13189
13202
|
};
|
|
@@ -13198,7 +13211,9 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
13198
13211
|
let destroyed = false;
|
|
13199
13212
|
let voices = options.singingVoices ?? null;
|
|
13200
13213
|
const buildStreamTracks = (fromStep) => [...lyricTracks.entries()].map(([index, lt]) => {
|
|
13201
|
-
const seqTrack = seqTracks.find(
|
|
13214
|
+
const seqTrack = seqTracks.find(
|
|
13215
|
+
(t) => t.id === (TRACK_ID_BY_INDEX2[index] ?? `t${index}`)
|
|
13216
|
+
);
|
|
13202
13217
|
const sorted = [...seqTrack?.notes ?? []].sort(
|
|
13203
13218
|
(a, b) => a.startStep - b.startStep
|
|
13204
13219
|
);
|
|
@@ -13217,7 +13232,7 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
13217
13232
|
});
|
|
13218
13233
|
}
|
|
13219
13234
|
return {
|
|
13220
|
-
id:
|
|
13235
|
+
id: TRACK_ID_BY_INDEX2[index] ?? `t${index}`,
|
|
13221
13236
|
model: lt.model,
|
|
13222
13237
|
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
|
|
13223
13238
|
pan: panToStereo(lt.pan ?? DEFAULT_PAN),
|
|
@@ -13235,7 +13250,10 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
13235
13250
|
onCue: options.onCue,
|
|
13236
13251
|
getAudioTime: () => ctx.currentTime,
|
|
13237
13252
|
onPlayNote: (e) => {
|
|
13238
|
-
const
|
|
13253
|
+
const namedIdx = TRACK_ID_BY_INDEX2.indexOf(
|
|
13254
|
+
e.trackId
|
|
13255
|
+
);
|
|
13256
|
+
const trackIdx = namedIdx >= 0 ? namedIdx : Number(e.trackId);
|
|
13239
13257
|
if (lyricTracks.has(trackIdx)) return;
|
|
13240
13258
|
options.onPlayNote?.(e);
|
|
13241
13259
|
synth?.playNote(e);
|
|
@@ -13931,6 +13949,23 @@ var TRACK_ROLES = [
|
|
|
13931
13949
|
"t13",
|
|
13932
13950
|
"t14"
|
|
13933
13951
|
];
|
|
13952
|
+
var resolveTrackIdxAndRole = (trackId) => {
|
|
13953
|
+
const roleIdx = TRACK_ROLES.indexOf(trackId);
|
|
13954
|
+
if (roleIdx >= 0) {
|
|
13955
|
+
return { trackIdx: roleIdx, role: trackId };
|
|
13956
|
+
}
|
|
13957
|
+
if (trackId.startsWith("t")) {
|
|
13958
|
+
const parsed2 = Number(trackId.slice(1));
|
|
13959
|
+
const validIdx2 = Number.isNaN(parsed2) ? 0 : parsed2;
|
|
13960
|
+
return {
|
|
13961
|
+
trackIdx: validIdx2,
|
|
13962
|
+
role: TRACK_ROLES[validIdx2] ?? `t${validIdx2}`
|
|
13963
|
+
};
|
|
13964
|
+
}
|
|
13965
|
+
const parsed = Number(trackId);
|
|
13966
|
+
const validIdx = Number.isNaN(parsed) ? 0 : parsed;
|
|
13967
|
+
return { trackIdx: validIdx, role: TRACK_ROLES[validIdx] ?? `t${validIdx}` };
|
|
13968
|
+
};
|
|
13934
13969
|
var resolveDefaultVoiceWorkerUrl = () => {
|
|
13935
13970
|
try {
|
|
13936
13971
|
return new URL("./voice-worker.js", import_meta.url).href;
|
|
@@ -14494,19 +14529,19 @@ var createDtmStudio = async (options = {}) => {
|
|
|
14494
14529
|
loadPlayerTrackInstruments()
|
|
14495
14530
|
]);
|
|
14496
14531
|
const playPlayerNote = (e) => {
|
|
14497
|
-
const
|
|
14498
|
-
const overrideKey = playerTrackInstKeys.get(
|
|
14532
|
+
const { trackIdx, role } = resolveTrackIdxAndRole(e.trackId);
|
|
14533
|
+
const overrideKey = playerTrackInstKeys.get(trackIdx);
|
|
14499
14534
|
let sfInst;
|
|
14500
14535
|
if (overrideKey) {
|
|
14501
14536
|
sfInst = soundFonts.get(overrideKey);
|
|
14502
14537
|
} else {
|
|
14503
|
-
const
|
|
14504
|
-
|
|
14538
|
+
const roleFromIdx = getRoleForTrackIndex(
|
|
14539
|
+
trackIdx,
|
|
14505
14540
|
isAdvancedMode ? "advanced" : "simple"
|
|
14506
14541
|
);
|
|
14507
14542
|
sfInst = resolveSoundFont(
|
|
14508
14543
|
playerPreset,
|
|
14509
|
-
|
|
14544
|
+
roleFromIdx,
|
|
14510
14545
|
isAdvancedMode ? "advanced" : "simple"
|
|
14511
14546
|
);
|
|
14512
14547
|
}
|
|
@@ -14530,6 +14565,78 @@ var createDtmStudio = async (options = {}) => {
|
|
|
14530
14565
|
onResumeAudio: resumeAudio
|
|
14531
14566
|
});
|
|
14532
14567
|
};
|
|
14568
|
+
const playSingingMMLInstance = (mml, opts = {}) => {
|
|
14569
|
+
const { placements } = parseMML(mml);
|
|
14570
|
+
const trackIndices = [...new Set(placements.map((p) => p.trackIndex))].sort(
|
|
14571
|
+
(a, b) => a - b
|
|
14572
|
+
);
|
|
14573
|
+
const isAdvancedMode = trackIndices.some((idx) => idx >= 4);
|
|
14574
|
+
const playerPreset = defaultPreset;
|
|
14575
|
+
void loadPreset(
|
|
14576
|
+
playerPreset,
|
|
14577
|
+
trackIndices.map(String),
|
|
14578
|
+
isAdvancedMode ? "advanced" : "simple"
|
|
14579
|
+
);
|
|
14580
|
+
const playPlayerNote = (e) => {
|
|
14581
|
+
const { role } = resolveTrackIdxAndRole(e.trackId);
|
|
14582
|
+
let sfInst = resolveSoundFont(
|
|
14583
|
+
playerPreset,
|
|
14584
|
+
role,
|
|
14585
|
+
isAdvancedMode ? "advanced" : "simple"
|
|
14586
|
+
);
|
|
14587
|
+
if (!sfInst) {
|
|
14588
|
+
void loadPreset(
|
|
14589
|
+
playerPreset,
|
|
14590
|
+
[role],
|
|
14591
|
+
isAdvancedMode ? "advanced" : "simple"
|
|
14592
|
+
);
|
|
14593
|
+
sfInst = resolveSoundFont(
|
|
14594
|
+
playerPreset,
|
|
14595
|
+
role,
|
|
14596
|
+
isAdvancedMode ? "advanced" : "simple"
|
|
14597
|
+
);
|
|
14598
|
+
}
|
|
14599
|
+
if (!sfInst) return;
|
|
14600
|
+
sfInst.play({
|
|
14601
|
+
ctx: audioCtx,
|
|
14602
|
+
destination: masterGain,
|
|
14603
|
+
pitch: e.pitch,
|
|
14604
|
+
volume: e.volume,
|
|
14605
|
+
when: e.when,
|
|
14606
|
+
duration: e.duration
|
|
14607
|
+
});
|
|
14608
|
+
};
|
|
14609
|
+
return playSingingMML(mml, {
|
|
14610
|
+
...opts,
|
|
14611
|
+
audioContext: audioCtx,
|
|
14612
|
+
destination: masterGain,
|
|
14613
|
+
synth: false,
|
|
14614
|
+
singingVoices,
|
|
14615
|
+
onPlayNote: playPlayerNote,
|
|
14616
|
+
onPlayDrum: playDrum,
|
|
14617
|
+
onResumeAudio: resumeAudio
|
|
14618
|
+
});
|
|
14619
|
+
};
|
|
14620
|
+
const playNoteEvent = (e) => {
|
|
14621
|
+
const { role } = resolveTrackIdxAndRole(e.trackId);
|
|
14622
|
+
let sfInst = resolveSoundFont(defaultPreset, role, "simple");
|
|
14623
|
+
if (!sfInst) {
|
|
14624
|
+
void loadPreset(defaultPreset, [role], "simple");
|
|
14625
|
+
sfInst = resolveSoundFont(defaultPreset, role, "simple");
|
|
14626
|
+
}
|
|
14627
|
+
if (!sfInst) return;
|
|
14628
|
+
sfInst.play({
|
|
14629
|
+
ctx: audioCtx,
|
|
14630
|
+
destination: masterGain,
|
|
14631
|
+
pitch: e.pitch,
|
|
14632
|
+
volume: e.volume,
|
|
14633
|
+
when: e.when,
|
|
14634
|
+
duration: e.duration
|
|
14635
|
+
});
|
|
14636
|
+
};
|
|
14637
|
+
const playDrumEvent = (e) => {
|
|
14638
|
+
playDrum(e);
|
|
14639
|
+
};
|
|
14533
14640
|
const playNote3 = async (options2) => {
|
|
14534
14641
|
await listReady;
|
|
14535
14642
|
const key = options2.instrument ? resolveNameToKey(options2.instrument) : void 0;
|
|
@@ -14635,6 +14742,9 @@ var createDtmStudio = async (options = {}) => {
|
|
|
14635
14742
|
mountPlayer,
|
|
14636
14743
|
mountChordPlayer: mountChordPlayerInstance,
|
|
14637
14744
|
play,
|
|
14745
|
+
playSingingMML: playSingingMMLInstance,
|
|
14746
|
+
playNoteEvent,
|
|
14747
|
+
playDrumEvent,
|
|
14638
14748
|
playNote: playNote3,
|
|
14639
14749
|
playChords: playChords3,
|
|
14640
14750
|
loadPreset,
|
package/dist/index.mjs
CHANGED
|
@@ -3294,6 +3294,13 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
3294
3294
|
const wave = tone.wave ?? "square";
|
|
3295
3295
|
const attack = tone.attack ?? 0;
|
|
3296
3296
|
const gainScale = tone.gain ?? 1;
|
|
3297
|
+
const compressor = ctx.createDynamicsCompressor();
|
|
3298
|
+
compressor.threshold.value = -12;
|
|
3299
|
+
compressor.knee.value = 6;
|
|
3300
|
+
compressor.ratio.value = 8;
|
|
3301
|
+
compressor.attack.value = 3e-3;
|
|
3302
|
+
compressor.release.value = 0.15;
|
|
3303
|
+
compressor.connect(destination);
|
|
3297
3304
|
const playNote3 = (e) => {
|
|
3298
3305
|
const osc = ctx.createOscillator();
|
|
3299
3306
|
const gain = ctx.createGain();
|
|
@@ -3326,9 +3333,9 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
3326
3333
|
panner = ctx.createStereoPanner();
|
|
3327
3334
|
panner.pan.value = Math.max(-1, Math.min(1, e.pan));
|
|
3328
3335
|
gain.connect(panner);
|
|
3329
|
-
panner.connect(
|
|
3336
|
+
panner.connect(compressor);
|
|
3330
3337
|
} else {
|
|
3331
|
-
gain.connect(
|
|
3338
|
+
gain.connect(compressor);
|
|
3332
3339
|
}
|
|
3333
3340
|
osc.start(t0);
|
|
3334
3341
|
osc.stop(t0 + e.duration + 0.02);
|
|
@@ -3350,7 +3357,7 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
3350
3357
|
osc.frequency.exponentialRampToValueAtTime(50, t0 + 0.12);
|
|
3351
3358
|
g2.gain.setValueAtTime(vol * 0.135, t0);
|
|
3352
3359
|
g2.gain.exponentialRampToValueAtTime(1e-3, t0 + 0.18);
|
|
3353
|
-
osc.connect(g2).connect(
|
|
3360
|
+
osc.connect(g2).connect(compressor);
|
|
3354
3361
|
osc.start(t0);
|
|
3355
3362
|
osc.stop(t0 + 0.2);
|
|
3356
3363
|
osc.onended = () => osc.disconnect();
|
|
@@ -3369,7 +3376,7 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
3369
3376
|
const g = ctx.createGain();
|
|
3370
3377
|
g.gain.setValueAtTime(vol * (isSnareLike ? 0.105 : 0.06), t0);
|
|
3371
3378
|
g.gain.exponentialRampToValueAtTime(1e-3, t0 + dur);
|
|
3372
|
-
src.connect(filter).connect(g).connect(
|
|
3379
|
+
src.connect(filter).connect(g).connect(compressor);
|
|
3373
3380
|
src.start(t0);
|
|
3374
3381
|
src.stop(t0 + dur);
|
|
3375
3382
|
src.onended = () => {
|
|
@@ -3383,6 +3390,7 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
3383
3390
|
|
|
3384
3391
|
// src/headless-player.ts
|
|
3385
3392
|
var STEPS_PER_BAR = 192;
|
|
3393
|
+
var TRACK_ID_BY_INDEX = ["melody", "submelody", "bass", "chord"];
|
|
3386
3394
|
var playPlacements = (placements, options) => {
|
|
3387
3395
|
const bpm = options.bpm;
|
|
3388
3396
|
const drumPatternDict = options.drumPatterns ?? DRUM_PATTERNS;
|
|
@@ -3401,7 +3409,11 @@ var playPlacements = (placements, options) => {
|
|
|
3401
3409
|
pitch: p.pitch,
|
|
3402
3410
|
velocity: p.velocity
|
|
3403
3411
|
}));
|
|
3404
|
-
return {
|
|
3412
|
+
return {
|
|
3413
|
+
id: TRACK_ID_BY_INDEX[index] ?? `t${index}`,
|
|
3414
|
+
volume: masterVolume,
|
|
3415
|
+
notes
|
|
3416
|
+
};
|
|
3405
3417
|
});
|
|
3406
3418
|
const ownsCtx = !options.audioContext;
|
|
3407
3419
|
const ctx = options.audioContext ?? new AudioContext();
|
|
@@ -13027,6 +13039,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13027
13039
|
// src/headless-singing-player.ts
|
|
13028
13040
|
var STEPS_PER_BEAT4 = 48;
|
|
13029
13041
|
var STEPS_PER_BAR3 = 192;
|
|
13042
|
+
var TRACK_ID_BY_INDEX2 = ["melody", "submelody", "bass", "chord"];
|
|
13030
13043
|
var playSingingMML = async (mml, options = {}) => {
|
|
13031
13044
|
const {
|
|
13032
13045
|
placements,
|
|
@@ -13060,7 +13073,7 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
13060
13073
|
velocity: p.velocity
|
|
13061
13074
|
}));
|
|
13062
13075
|
return {
|
|
13063
|
-
id:
|
|
13076
|
+
id: TRACK_ID_BY_INDEX2[index] ?? `t${index}`,
|
|
13064
13077
|
volume: trackVolume / 100 * masterVolume,
|
|
13065
13078
|
notes
|
|
13066
13079
|
};
|
|
@@ -13075,7 +13088,9 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
13075
13088
|
let destroyed = false;
|
|
13076
13089
|
let voices = options.singingVoices ?? null;
|
|
13077
13090
|
const buildStreamTracks = (fromStep) => [...lyricTracks.entries()].map(([index, lt]) => {
|
|
13078
|
-
const seqTrack = seqTracks.find(
|
|
13091
|
+
const seqTrack = seqTracks.find(
|
|
13092
|
+
(t) => t.id === (TRACK_ID_BY_INDEX2[index] ?? `t${index}`)
|
|
13093
|
+
);
|
|
13079
13094
|
const sorted = [...seqTrack?.notes ?? []].sort(
|
|
13080
13095
|
(a, b) => a.startStep - b.startStep
|
|
13081
13096
|
);
|
|
@@ -13094,7 +13109,7 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
13094
13109
|
});
|
|
13095
13110
|
}
|
|
13096
13111
|
return {
|
|
13097
|
-
id:
|
|
13112
|
+
id: TRACK_ID_BY_INDEX2[index] ?? `t${index}`,
|
|
13098
13113
|
model: lt.model,
|
|
13099
13114
|
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
|
|
13100
13115
|
pan: panToStereo(lt.pan ?? DEFAULT_PAN),
|
|
@@ -13112,7 +13127,10 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
13112
13127
|
onCue: options.onCue,
|
|
13113
13128
|
getAudioTime: () => ctx.currentTime,
|
|
13114
13129
|
onPlayNote: (e) => {
|
|
13115
|
-
const
|
|
13130
|
+
const namedIdx = TRACK_ID_BY_INDEX2.indexOf(
|
|
13131
|
+
e.trackId
|
|
13132
|
+
);
|
|
13133
|
+
const trackIdx = namedIdx >= 0 ? namedIdx : Number(e.trackId);
|
|
13116
13134
|
if (lyricTracks.has(trackIdx)) return;
|
|
13117
13135
|
options.onPlayNote?.(e);
|
|
13118
13136
|
synth?.playNote(e);
|
|
@@ -13807,6 +13825,23 @@ var TRACK_ROLES = [
|
|
|
13807
13825
|
"t13",
|
|
13808
13826
|
"t14"
|
|
13809
13827
|
];
|
|
13828
|
+
var resolveTrackIdxAndRole = (trackId) => {
|
|
13829
|
+
const roleIdx = TRACK_ROLES.indexOf(trackId);
|
|
13830
|
+
if (roleIdx >= 0) {
|
|
13831
|
+
return { trackIdx: roleIdx, role: trackId };
|
|
13832
|
+
}
|
|
13833
|
+
if (trackId.startsWith("t")) {
|
|
13834
|
+
const parsed2 = Number(trackId.slice(1));
|
|
13835
|
+
const validIdx2 = Number.isNaN(parsed2) ? 0 : parsed2;
|
|
13836
|
+
return {
|
|
13837
|
+
trackIdx: validIdx2,
|
|
13838
|
+
role: TRACK_ROLES[validIdx2] ?? `t${validIdx2}`
|
|
13839
|
+
};
|
|
13840
|
+
}
|
|
13841
|
+
const parsed = Number(trackId);
|
|
13842
|
+
const validIdx = Number.isNaN(parsed) ? 0 : parsed;
|
|
13843
|
+
return { trackIdx: validIdx, role: TRACK_ROLES[validIdx] ?? `t${validIdx}` };
|
|
13844
|
+
};
|
|
13810
13845
|
var resolveDefaultVoiceWorkerUrl = () => {
|
|
13811
13846
|
try {
|
|
13812
13847
|
return new URL("./voice-worker.js", import.meta.url).href;
|
|
@@ -14370,19 +14405,19 @@ var createDtmStudio = async (options = {}) => {
|
|
|
14370
14405
|
loadPlayerTrackInstruments()
|
|
14371
14406
|
]);
|
|
14372
14407
|
const playPlayerNote = (e) => {
|
|
14373
|
-
const
|
|
14374
|
-
const overrideKey = playerTrackInstKeys.get(
|
|
14408
|
+
const { trackIdx, role } = resolveTrackIdxAndRole(e.trackId);
|
|
14409
|
+
const overrideKey = playerTrackInstKeys.get(trackIdx);
|
|
14375
14410
|
let sfInst;
|
|
14376
14411
|
if (overrideKey) {
|
|
14377
14412
|
sfInst = soundFonts.get(overrideKey);
|
|
14378
14413
|
} else {
|
|
14379
|
-
const
|
|
14380
|
-
|
|
14414
|
+
const roleFromIdx = getRoleForTrackIndex(
|
|
14415
|
+
trackIdx,
|
|
14381
14416
|
isAdvancedMode ? "advanced" : "simple"
|
|
14382
14417
|
);
|
|
14383
14418
|
sfInst = resolveSoundFont(
|
|
14384
14419
|
playerPreset,
|
|
14385
|
-
|
|
14420
|
+
roleFromIdx,
|
|
14386
14421
|
isAdvancedMode ? "advanced" : "simple"
|
|
14387
14422
|
);
|
|
14388
14423
|
}
|
|
@@ -14406,6 +14441,78 @@ var createDtmStudio = async (options = {}) => {
|
|
|
14406
14441
|
onResumeAudio: resumeAudio
|
|
14407
14442
|
});
|
|
14408
14443
|
};
|
|
14444
|
+
const playSingingMMLInstance = (mml, opts = {}) => {
|
|
14445
|
+
const { placements } = parseMML(mml);
|
|
14446
|
+
const trackIndices = [...new Set(placements.map((p) => p.trackIndex))].sort(
|
|
14447
|
+
(a, b) => a - b
|
|
14448
|
+
);
|
|
14449
|
+
const isAdvancedMode = trackIndices.some((idx) => idx >= 4);
|
|
14450
|
+
const playerPreset = defaultPreset;
|
|
14451
|
+
void loadPreset(
|
|
14452
|
+
playerPreset,
|
|
14453
|
+
trackIndices.map(String),
|
|
14454
|
+
isAdvancedMode ? "advanced" : "simple"
|
|
14455
|
+
);
|
|
14456
|
+
const playPlayerNote = (e) => {
|
|
14457
|
+
const { role } = resolveTrackIdxAndRole(e.trackId);
|
|
14458
|
+
let sfInst = resolveSoundFont(
|
|
14459
|
+
playerPreset,
|
|
14460
|
+
role,
|
|
14461
|
+
isAdvancedMode ? "advanced" : "simple"
|
|
14462
|
+
);
|
|
14463
|
+
if (!sfInst) {
|
|
14464
|
+
void loadPreset(
|
|
14465
|
+
playerPreset,
|
|
14466
|
+
[role],
|
|
14467
|
+
isAdvancedMode ? "advanced" : "simple"
|
|
14468
|
+
);
|
|
14469
|
+
sfInst = resolveSoundFont(
|
|
14470
|
+
playerPreset,
|
|
14471
|
+
role,
|
|
14472
|
+
isAdvancedMode ? "advanced" : "simple"
|
|
14473
|
+
);
|
|
14474
|
+
}
|
|
14475
|
+
if (!sfInst) return;
|
|
14476
|
+
sfInst.play({
|
|
14477
|
+
ctx: audioCtx,
|
|
14478
|
+
destination: masterGain,
|
|
14479
|
+
pitch: e.pitch,
|
|
14480
|
+
volume: e.volume,
|
|
14481
|
+
when: e.when,
|
|
14482
|
+
duration: e.duration
|
|
14483
|
+
});
|
|
14484
|
+
};
|
|
14485
|
+
return playSingingMML(mml, {
|
|
14486
|
+
...opts,
|
|
14487
|
+
audioContext: audioCtx,
|
|
14488
|
+
destination: masterGain,
|
|
14489
|
+
synth: false,
|
|
14490
|
+
singingVoices,
|
|
14491
|
+
onPlayNote: playPlayerNote,
|
|
14492
|
+
onPlayDrum: playDrum,
|
|
14493
|
+
onResumeAudio: resumeAudio
|
|
14494
|
+
});
|
|
14495
|
+
};
|
|
14496
|
+
const playNoteEvent = (e) => {
|
|
14497
|
+
const { role } = resolveTrackIdxAndRole(e.trackId);
|
|
14498
|
+
let sfInst = resolveSoundFont(defaultPreset, role, "simple");
|
|
14499
|
+
if (!sfInst) {
|
|
14500
|
+
void loadPreset(defaultPreset, [role], "simple");
|
|
14501
|
+
sfInst = resolveSoundFont(defaultPreset, role, "simple");
|
|
14502
|
+
}
|
|
14503
|
+
if (!sfInst) return;
|
|
14504
|
+
sfInst.play({
|
|
14505
|
+
ctx: audioCtx,
|
|
14506
|
+
destination: masterGain,
|
|
14507
|
+
pitch: e.pitch,
|
|
14508
|
+
volume: e.volume,
|
|
14509
|
+
when: e.when,
|
|
14510
|
+
duration: e.duration
|
|
14511
|
+
});
|
|
14512
|
+
};
|
|
14513
|
+
const playDrumEvent = (e) => {
|
|
14514
|
+
playDrum(e);
|
|
14515
|
+
};
|
|
14409
14516
|
const playNote3 = async (options2) => {
|
|
14410
14517
|
await listReady;
|
|
14411
14518
|
const key = options2.instrument ? resolveNameToKey(options2.instrument) : void 0;
|
|
@@ -14511,6 +14618,9 @@ var createDtmStudio = async (options = {}) => {
|
|
|
14511
14618
|
mountPlayer,
|
|
14512
14619
|
mountChordPlayer: mountChordPlayerInstance,
|
|
14513
14620
|
play,
|
|
14621
|
+
playSingingMML: playSingingMMLInstance,
|
|
14622
|
+
playNoteEvent,
|
|
14623
|
+
playDrumEvent,
|
|
14514
14624
|
playNote: playNote3,
|
|
14515
14625
|
playChords: playChords3,
|
|
14516
14626
|
loadPreset,
|
package/package.json
CHANGED