@onjmin/dtm 0.1.6 → 0.1.8
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 +18 -2
- package/dist/index.d.ts +18 -2
- package/dist/index.js +21 -29
- package/dist/index.mjs +21 -29
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -263,6 +263,11 @@ type StreamVoiceNote = {
|
|
|
263
263
|
};
|
|
264
264
|
/** ストリーミング再生する歌詞トラック1本。 */
|
|
265
265
|
type StreamVoiceTrack = {
|
|
266
|
+
/**
|
|
267
|
+
* 呼び出し側がソロ/ミュート判定に使う識別子(演奏トラックの config.id 等)。
|
|
268
|
+
* {@link StreamPlaybackOptions.isAudible} で参照する。省略時は常に可聴。
|
|
269
|
+
*/
|
|
270
|
+
id?: string;
|
|
266
271
|
/** 歌唱モデル名(koe音源キーワード or "klatt")。 */
|
|
267
272
|
model: string;
|
|
268
273
|
/** 最終ゲイン(声量×マスタ等を適用済み。1=等倍)。 */
|
|
@@ -272,6 +277,17 @@ type StreamVoiceTrack = {
|
|
|
272
277
|
/** 発音順(startSec昇順)の歌唱ノート列。 */
|
|
273
278
|
notes: StreamVoiceNote[];
|
|
274
279
|
};
|
|
280
|
+
/** {@link SingingVoices.startStream} の任意オプション。 */
|
|
281
|
+
type StreamPlaybackOptions = {
|
|
282
|
+
/**
|
|
283
|
+
* そのトラックを今この瞬間に発音してよいか(ソロ/ミュート判定)。
|
|
284
|
+
* 各ノートを合成・スケジュールする直前にライブで評価するため、再生中に
|
|
285
|
+
* ソロを切り替えると先読み地平(最大 {@link STREAM_LOOKAHEAD_SEC} 秒)以降のノートへ反映される。
|
|
286
|
+
* 既にスケジュール済みのノートは鳴り切る(楽器側のミュート挙動と同じ)。
|
|
287
|
+
* 省略時は全トラック可聴。
|
|
288
|
+
*/
|
|
289
|
+
isAudible?: (track: StreamVoiceTrack) => boolean;
|
|
290
|
+
};
|
|
275
291
|
/**
|
|
276
292
|
* 歌唱モデルをまとめて管理し、koeデモ式の「先読みストリーミング合成」で歌わせる高レベルヘルパ。
|
|
277
293
|
*
|
|
@@ -298,7 +314,7 @@ type SingingVoices = {
|
|
|
298
314
|
* AudioContextクロック秒(=シーケンサの開始時刻と一致させること)。
|
|
299
315
|
* 即座に return し、合成は裏で先回り進行する。
|
|
300
316
|
*/
|
|
301
|
-
startStream: (tracks: StreamVoiceTrack[], anchorTime: number) => void;
|
|
317
|
+
startStream: (tracks: StreamVoiceTrack[], anchorTime: number, opts?: StreamPlaybackOptions) => void;
|
|
302
318
|
/** 進行中のストリームを中断し、スケジュール済みの発音をすべて止める(停止・一時停止・シーク)。 */
|
|
303
319
|
stopStream: () => void;
|
|
304
320
|
/** ストリーム停止+各モデルの内部状態を初期化する。 */
|
|
@@ -1266,4 +1282,4 @@ declare const DAW_CSS = "\n@font-face {\n font-family: 'k8x12';\n src: url('ht
|
|
|
1266
1282
|
*/
|
|
1267
1283
|
declare const injectStyles: (doc?: Document) => void;
|
|
1268
1284
|
|
|
1269
|
-
export { type AddNoteOptions, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ConsumedSyllable, type CoreEventHandlers, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawOptions, type DawViewState, type DrumPattern, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LyricSyllable, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, type MidiExtraction, type MidiNotePlacement, type MidiTrackAnalysis, type MmlMeta, type MmlPlayerInstance, type MmlPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, PITCH_MAP, PREWARM_NOTES, type ParseChordFn, type ParseChordsFn, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PitchToken, type PlayDrumEvent, type PlayNoteEvent, type PlaybackState, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamVoiceNote, type StreamVoiceTrack, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VOICE_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createVoiceRegistry, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, exportMIDI, extractMidiPlacements, extractMidiPlacementsByTrack, fetchSoundFontList, formatMmlMeta, generateRandomPattern, getDrawOffset, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, koeUrl, mountDAW, mountMmlPlayer, normalizeLyrics, onClick, panToStereo, parseLyrics, parseMML, parseMmlMeta, setDrawOffset, setupRecorder, shiftNotes, stripLyrics, stripMmlMeta, vocalVolumeToGain };
|
|
1285
|
+
export { type AddNoteOptions, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ConsumedSyllable, type CoreEventHandlers, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawOptions, type DawViewState, type DrumPattern, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LyricSyllable, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, type MidiExtraction, type MidiNotePlacement, type MidiTrackAnalysis, type MmlMeta, type MmlPlayerInstance, type MmlPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, PITCH_MAP, PREWARM_NOTES, type ParseChordFn, type ParseChordsFn, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PitchToken, type PlayDrumEvent, type PlayNoteEvent, type PlaybackState, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VOICE_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createVoiceRegistry, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, exportMIDI, extractMidiPlacements, extractMidiPlacementsByTrack, fetchSoundFontList, formatMmlMeta, generateRandomPattern, getDrawOffset, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, koeUrl, mountDAW, mountMmlPlayer, normalizeLyrics, onClick, panToStereo, parseLyrics, parseMML, parseMmlMeta, setDrawOffset, setupRecorder, shiftNotes, stripLyrics, stripMmlMeta, vocalVolumeToGain };
|
package/dist/index.d.ts
CHANGED
|
@@ -263,6 +263,11 @@ type StreamVoiceNote = {
|
|
|
263
263
|
};
|
|
264
264
|
/** ストリーミング再生する歌詞トラック1本。 */
|
|
265
265
|
type StreamVoiceTrack = {
|
|
266
|
+
/**
|
|
267
|
+
* 呼び出し側がソロ/ミュート判定に使う識別子(演奏トラックの config.id 等)。
|
|
268
|
+
* {@link StreamPlaybackOptions.isAudible} で参照する。省略時は常に可聴。
|
|
269
|
+
*/
|
|
270
|
+
id?: string;
|
|
266
271
|
/** 歌唱モデル名(koe音源キーワード or "klatt")。 */
|
|
267
272
|
model: string;
|
|
268
273
|
/** 最終ゲイン(声量×マスタ等を適用済み。1=等倍)。 */
|
|
@@ -272,6 +277,17 @@ type StreamVoiceTrack = {
|
|
|
272
277
|
/** 発音順(startSec昇順)の歌唱ノート列。 */
|
|
273
278
|
notes: StreamVoiceNote[];
|
|
274
279
|
};
|
|
280
|
+
/** {@link SingingVoices.startStream} の任意オプション。 */
|
|
281
|
+
type StreamPlaybackOptions = {
|
|
282
|
+
/**
|
|
283
|
+
* そのトラックを今この瞬間に発音してよいか(ソロ/ミュート判定)。
|
|
284
|
+
* 各ノートを合成・スケジュールする直前にライブで評価するため、再生中に
|
|
285
|
+
* ソロを切り替えると先読み地平(最大 {@link STREAM_LOOKAHEAD_SEC} 秒)以降のノートへ反映される。
|
|
286
|
+
* 既にスケジュール済みのノートは鳴り切る(楽器側のミュート挙動と同じ)。
|
|
287
|
+
* 省略時は全トラック可聴。
|
|
288
|
+
*/
|
|
289
|
+
isAudible?: (track: StreamVoiceTrack) => boolean;
|
|
290
|
+
};
|
|
275
291
|
/**
|
|
276
292
|
* 歌唱モデルをまとめて管理し、koeデモ式の「先読みストリーミング合成」で歌わせる高レベルヘルパ。
|
|
277
293
|
*
|
|
@@ -298,7 +314,7 @@ type SingingVoices = {
|
|
|
298
314
|
* AudioContextクロック秒(=シーケンサの開始時刻と一致させること)。
|
|
299
315
|
* 即座に return し、合成は裏で先回り進行する。
|
|
300
316
|
*/
|
|
301
|
-
startStream: (tracks: StreamVoiceTrack[], anchorTime: number) => void;
|
|
317
|
+
startStream: (tracks: StreamVoiceTrack[], anchorTime: number, opts?: StreamPlaybackOptions) => void;
|
|
302
318
|
/** 進行中のストリームを中断し、スケジュール済みの発音をすべて止める(停止・一時停止・シーク)。 */
|
|
303
319
|
stopStream: () => void;
|
|
304
320
|
/** ストリーム停止+各モデルの内部状態を初期化する。 */
|
|
@@ -1266,4 +1282,4 @@ declare const DAW_CSS = "\n@font-face {\n font-family: 'k8x12';\n src: url('ht
|
|
|
1266
1282
|
*/
|
|
1267
1283
|
declare const injectStyles: (doc?: Document) => void;
|
|
1268
1284
|
|
|
1269
|
-
export { type AddNoteOptions, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ConsumedSyllable, type CoreEventHandlers, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawOptions, type DawViewState, type DrumPattern, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LyricSyllable, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, type MidiExtraction, type MidiNotePlacement, type MidiTrackAnalysis, type MmlMeta, type MmlPlayerInstance, type MmlPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, PITCH_MAP, PREWARM_NOTES, type ParseChordFn, type ParseChordsFn, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PitchToken, type PlayDrumEvent, type PlayNoteEvent, type PlaybackState, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamVoiceNote, type StreamVoiceTrack, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VOICE_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createVoiceRegistry, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, exportMIDI, extractMidiPlacements, extractMidiPlacementsByTrack, fetchSoundFontList, formatMmlMeta, generateRandomPattern, getDrawOffset, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, koeUrl, mountDAW, mountMmlPlayer, normalizeLyrics, onClick, panToStereo, parseLyrics, parseMML, parseMmlMeta, setDrawOffset, setupRecorder, shiftNotes, stripLyrics, stripMmlMeta, vocalVolumeToGain };
|
|
1285
|
+
export { type AddNoteOptions, type ApplyChordOptions, type ChordPatternType, type ChordPlacement, type ConsumedSyllable, type CoreEventHandlers, DAW_CSS, DEFAULT_BPM, DEFAULT_GATE, DEFAULT_PAN, DEFAULT_PLAYBACK_VELOCITY, DEFAULT_STEPS_PER_BAR, DEFAULT_VELOCITY, DEFAULT_VOCAL_VOLUME, DRUM_FONT, DRUM_KEYS, DRUM_PATTERNS, type DawInstance, type DawOptions, type DawViewState, type DrumPattern, type DtmStudio, type DtmStudioEngines, type DtmStudioOptions, type ExportMidiOptions, INSTRUMENT_PRESETS, type InstrumentPreset, KOE_BASE_URL, KOE_VOICEBANKS, KOE_VOICEBANK_LABELS, KOE_VOICEBANK_TERMS, type KoeVoiceOptions, LinkedList, type LyricSyllable, type LyricTrack, type LyricsConductor, MAX_VOCAL_VOLUME, MMLCore, type MMLDisplayToken, type MMLNotePlacement, type MidiExtraction, type MidiNotePlacement, type MidiTrackAnalysis, type MmlMeta, type MmlPlayerInstance, type MmlPlayerOptions, type MountEditorOptions, type MountPlayerOptions, type Note, PITCH_MAP, PREWARM_NOTES, type ParseChordFn, type ParseChordsFn, type ParseMMLOptions, type ParseMidiFn, type ParsedMML, type PianoRollInstance, type PianoRollOptions, type PitchToken, type PlayDrumEvent, type PlayNoteEvent, type PlaybackState, type PreviewSoundCallback, type RenderConfig, type Sequencer, type SequencerOptions, type SequencerTrack, type SingingVoices, type SingingVoicesOptions, type StreamPlaybackOptions, type StreamVoiceNote, type StreamVoiceTrack, TRACKS_ADVANCED, TRACKS_SIMPLE, type ToolMode, type TrackConfig, VOICE_IMAGE_KEY, type VoiceModel, type VoiceRegistry, analyzeMidiTracks, applyHarmonicFilter, applyMonophonic, buildChordPlacements, buildNameToKeyMapping, collectPitchTokens, createAudioContext, createDtmStudio, createKlattVoice, createKoeVoice, createLyricsConductor, createPianoRoll, createSequencer, createSingingVoices, createVoiceRegistry, decomposeToMonophonic, drawGrid, drawHeader, drawKeyboard, drawNotes, drawSelectedNotes, drawSelectionRect, exportMIDI, extractMidiPlacements, extractMidiPlacementsByTrack, fetchSoundFontList, formatMmlMeta, generateRandomPattern, getDrawOffset, getGridCanvas, getGridContext, getGridPosition, getHeaderCanvas, getMidiBPM, getRenderConfig, getXY, icon, init, injectStyles, isChordHeavyTrack, koeUrl, mountDAW, mountMmlPlayer, normalizeLyrics, onClick, panToStereo, parseLyrics, parseMML, parseMmlMeta, setDrawOffset, setupRecorder, shiftNotes, stripLyrics, stripMmlMeta, vocalVolumeToGain };
|
package/dist/index.js
CHANGED
|
@@ -1789,42 +1789,33 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
1789
1789
|
}
|
|
1790
1790
|
await Promise.all(promises);
|
|
1791
1791
|
};
|
|
1792
|
-
const startStream = (tracks, anchorTime) => {
|
|
1792
|
+
const startStream = (tracks, anchorTime, opts) => {
|
|
1793
1793
|
const session = ++streamSession;
|
|
1794
|
-
const
|
|
1795
|
-
for (const track of tracks) {
|
|
1794
|
+
const runTrack = async (track) => {
|
|
1796
1795
|
const model = loaded.get(track.model.toLowerCase());
|
|
1797
|
-
if (!model)
|
|
1796
|
+
if (!model) return;
|
|
1797
|
+
const items = [];
|
|
1798
1798
|
forEachSungNote(track, (note, prevVowel) => {
|
|
1799
|
-
items.push({
|
|
1800
|
-
model,
|
|
1801
|
-
note,
|
|
1802
|
-
prevVowel,
|
|
1803
|
-
volume: track.volume,
|
|
1804
|
-
pan: track.pan
|
|
1805
|
-
});
|
|
1799
|
+
items.push({ note, prevVowel });
|
|
1806
1800
|
});
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
void (async () => {
|
|
1810
|
-
for (const item of items) {
|
|
1801
|
+
const peak = Math.max(1e-4, track.volume);
|
|
1802
|
+
for (const { note, prevVowel } of items) {
|
|
1811
1803
|
if (session !== streamSession) return;
|
|
1812
|
-
while (
|
|
1804
|
+
while (note.startSec - (ctx.currentTime - anchorTime) > STREAM_LOOKAHEAD_SEC) {
|
|
1813
1805
|
await new Promise((resolve) => setTimeout(resolve, STREAM_POLL_MS));
|
|
1814
1806
|
if (session !== streamSession) return;
|
|
1815
1807
|
}
|
|
1816
|
-
|
|
1817
|
-
const
|
|
1818
|
-
const { model, note } = item;
|
|
1808
|
+
if (opts?.isAudible && !opts.isAudible(track)) continue;
|
|
1809
|
+
const t0 = anchorTime + note.startSec;
|
|
1819
1810
|
if (model.renderToCache && model.scheduleCached) {
|
|
1820
1811
|
const key = await model.renderToCache(
|
|
1821
1812
|
note.syllable,
|
|
1822
|
-
|
|
1813
|
+
prevVowel,
|
|
1823
1814
|
note.pitch,
|
|
1824
1815
|
note.durationSec * 1e3
|
|
1825
1816
|
);
|
|
1826
1817
|
if (session !== streamSession) return;
|
|
1827
|
-
if (key) model.scheduleCached(key, t0, peak,
|
|
1818
|
+
if (key) model.scheduleCached(key, t0, peak, track.pan);
|
|
1828
1819
|
} else {
|
|
1829
1820
|
const when = t0 - ctx.currentTime;
|
|
1830
1821
|
model(note.syllable, {
|
|
@@ -1834,12 +1825,13 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
1834
1825
|
volume: peak,
|
|
1835
1826
|
when,
|
|
1836
1827
|
duration: note.durationSec,
|
|
1837
|
-
pan:
|
|
1828
|
+
pan: track.pan
|
|
1838
1829
|
});
|
|
1830
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1839
1831
|
}
|
|
1840
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1841
1832
|
}
|
|
1842
|
-
}
|
|
1833
|
+
};
|
|
1834
|
+
for (const track of tracks) void runTrack(track);
|
|
1843
1835
|
};
|
|
1844
1836
|
const stopStream = () => {
|
|
1845
1837
|
streamSession++;
|
|
@@ -3379,13 +3371,10 @@ var createSequencer = (options) => {
|
|
|
3379
3371
|
}
|
|
3380
3372
|
while (nowIndex < timeline.length) {
|
|
3381
3373
|
const ev = timeline[nowIndex];
|
|
3382
|
-
if (soloId && ev.trackId !== soloId) {
|
|
3383
|
-
nowIndex++;
|
|
3384
|
-
continue;
|
|
3385
|
-
}
|
|
3386
3374
|
const _when = ev.when - time;
|
|
3387
3375
|
if (_when > PLAN_TIME) break;
|
|
3388
3376
|
nowIndex++;
|
|
3377
|
+
if (soloId && ev.trackId !== soloId) continue;
|
|
3389
3378
|
const velocityVolume = ev.velocity / 127;
|
|
3390
3379
|
const currentVolume = (trackVolumeMap.get(ev.trackId) ?? ev.volume * 100) / 100;
|
|
3391
3380
|
options.onPlayNote({
|
|
@@ -5080,6 +5069,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
5080
5069
|
});
|
|
5081
5070
|
}
|
|
5082
5071
|
return {
|
|
5072
|
+
id: trackState?.config.id,
|
|
5083
5073
|
model: lt.model,
|
|
5084
5074
|
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * (masterVolume / 100),
|
|
5085
5075
|
pan: panToStereo(lt.pan ?? DEFAULT_PAN),
|
|
@@ -5110,7 +5100,9 @@ var mountDAW = (target, options = {}) => {
|
|
|
5110
5100
|
playbackState = "playing";
|
|
5111
5101
|
sequencer.start(fromStep);
|
|
5112
5102
|
if (streaming && voices) {
|
|
5113
|
-
voices.startStream(streamTracks, sequencer.getStartTime()
|
|
5103
|
+
voices.startStream(streamTracks, sequencer.getStartTime(), {
|
|
5104
|
+
isAudible: (t) => !isSolo || t.id === activeTrackId
|
|
5105
|
+
});
|
|
5114
5106
|
}
|
|
5115
5107
|
updateTransport();
|
|
5116
5108
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -1685,42 +1685,33 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
1685
1685
|
}
|
|
1686
1686
|
await Promise.all(promises);
|
|
1687
1687
|
};
|
|
1688
|
-
const startStream = (tracks, anchorTime) => {
|
|
1688
|
+
const startStream = (tracks, anchorTime, opts) => {
|
|
1689
1689
|
const session = ++streamSession;
|
|
1690
|
-
const
|
|
1691
|
-
for (const track of tracks) {
|
|
1690
|
+
const runTrack = async (track) => {
|
|
1692
1691
|
const model = loaded.get(track.model.toLowerCase());
|
|
1693
|
-
if (!model)
|
|
1692
|
+
if (!model) return;
|
|
1693
|
+
const items = [];
|
|
1694
1694
|
forEachSungNote(track, (note, prevVowel) => {
|
|
1695
|
-
items.push({
|
|
1696
|
-
model,
|
|
1697
|
-
note,
|
|
1698
|
-
prevVowel,
|
|
1699
|
-
volume: track.volume,
|
|
1700
|
-
pan: track.pan
|
|
1701
|
-
});
|
|
1695
|
+
items.push({ note, prevVowel });
|
|
1702
1696
|
});
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
void (async () => {
|
|
1706
|
-
for (const item of items) {
|
|
1697
|
+
const peak = Math.max(1e-4, track.volume);
|
|
1698
|
+
for (const { note, prevVowel } of items) {
|
|
1707
1699
|
if (session !== streamSession) return;
|
|
1708
|
-
while (
|
|
1700
|
+
while (note.startSec - (ctx.currentTime - anchorTime) > STREAM_LOOKAHEAD_SEC) {
|
|
1709
1701
|
await new Promise((resolve) => setTimeout(resolve, STREAM_POLL_MS));
|
|
1710
1702
|
if (session !== streamSession) return;
|
|
1711
1703
|
}
|
|
1712
|
-
|
|
1713
|
-
const
|
|
1714
|
-
const { model, note } = item;
|
|
1704
|
+
if (opts?.isAudible && !opts.isAudible(track)) continue;
|
|
1705
|
+
const t0 = anchorTime + note.startSec;
|
|
1715
1706
|
if (model.renderToCache && model.scheduleCached) {
|
|
1716
1707
|
const key = await model.renderToCache(
|
|
1717
1708
|
note.syllable,
|
|
1718
|
-
|
|
1709
|
+
prevVowel,
|
|
1719
1710
|
note.pitch,
|
|
1720
1711
|
note.durationSec * 1e3
|
|
1721
1712
|
);
|
|
1722
1713
|
if (session !== streamSession) return;
|
|
1723
|
-
if (key) model.scheduleCached(key, t0, peak,
|
|
1714
|
+
if (key) model.scheduleCached(key, t0, peak, track.pan);
|
|
1724
1715
|
} else {
|
|
1725
1716
|
const when = t0 - ctx.currentTime;
|
|
1726
1717
|
model(note.syllable, {
|
|
@@ -1730,12 +1721,13 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
1730
1721
|
volume: peak,
|
|
1731
1722
|
when,
|
|
1732
1723
|
duration: note.durationSec,
|
|
1733
|
-
pan:
|
|
1724
|
+
pan: track.pan
|
|
1734
1725
|
});
|
|
1726
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1735
1727
|
}
|
|
1736
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1737
1728
|
}
|
|
1738
|
-
}
|
|
1729
|
+
};
|
|
1730
|
+
for (const track of tracks) void runTrack(track);
|
|
1739
1731
|
};
|
|
1740
1732
|
const stopStream = () => {
|
|
1741
1733
|
streamSession++;
|
|
@@ -3275,13 +3267,10 @@ var createSequencer = (options) => {
|
|
|
3275
3267
|
}
|
|
3276
3268
|
while (nowIndex < timeline.length) {
|
|
3277
3269
|
const ev = timeline[nowIndex];
|
|
3278
|
-
if (soloId && ev.trackId !== soloId) {
|
|
3279
|
-
nowIndex++;
|
|
3280
|
-
continue;
|
|
3281
|
-
}
|
|
3282
3270
|
const _when = ev.when - time;
|
|
3283
3271
|
if (_when > PLAN_TIME) break;
|
|
3284
3272
|
nowIndex++;
|
|
3273
|
+
if (soloId && ev.trackId !== soloId) continue;
|
|
3285
3274
|
const velocityVolume = ev.velocity / 127;
|
|
3286
3275
|
const currentVolume = (trackVolumeMap.get(ev.trackId) ?? ev.volume * 100) / 100;
|
|
3287
3276
|
options.onPlayNote({
|
|
@@ -4976,6 +4965,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
4976
4965
|
});
|
|
4977
4966
|
}
|
|
4978
4967
|
return {
|
|
4968
|
+
id: trackState?.config.id,
|
|
4979
4969
|
model: lt.model,
|
|
4980
4970
|
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME) * (masterVolume / 100),
|
|
4981
4971
|
pan: panToStereo(lt.pan ?? DEFAULT_PAN),
|
|
@@ -5006,7 +4996,9 @@ var mountDAW = (target, options = {}) => {
|
|
|
5006
4996
|
playbackState = "playing";
|
|
5007
4997
|
sequencer.start(fromStep);
|
|
5008
4998
|
if (streaming && voices) {
|
|
5009
|
-
voices.startStream(streamTracks, sequencer.getStartTime()
|
|
4999
|
+
voices.startStream(streamTracks, sequencer.getStartTime(), {
|
|
5000
|
+
isAudible: (t) => !isSolo || t.id === activeTrackId
|
|
5001
|
+
});
|
|
5010
5002
|
}
|
|
5011
5003
|
updateTransport();
|
|
5012
5004
|
};
|
package/package.json
CHANGED