feat: VSTi live playback 100% client-side (không Carla) — autosample SF2 backend (pedalboard) → FluidSynth WASM qua masterBus → mastering → main out; SonicVstiAutosample ensure+dedup+cooldown; runtime gating __enableCarlaLivePlayback; âm bắt qua ensureMidiCapture → clientSideExport

This commit is contained in:
2026-08-11 14:28:42 +07:00
parent 7293d7ac7e
commit cadb5402a3
12 changed files with 676 additions and 44 deletions
+31 -2
View File
@@ -464,7 +464,7 @@
bank = bank !== undefined ? bank : (synthEngine.soundfont_bank || 0);
program = program !== undefined ? program : (synthEngine.soundfont_program || 0);
}
var sfId = synthEngine && synthEngine.soundfont_id;
var sfId = synthEngine && (synthEngine.soundfont_id || synthEngine.autosampled_sf_id);
var engKey = (sfId || '') + ':' + bank + ':' + program;
if (!_engineChMap[engKey]) {
var channel = this.allocateChannel(bank);
@@ -587,7 +587,36 @@
if (isNaN(finalBank) || !isFinite(finalBank)) finalBank = 0;
var finalProg = parseInt(usedProg);
if (isNaN(finalProg) || !isFinite(finalProg)) finalProg = 0;
var finalSfId = synthEngine ? synthEngine.soundfont_id : undefined;
var finalSfId = synthEngine ? (synthEngine.soundfont_id || synthEngine.autosampled_sf_id) : undefined;
// VSTi live playback (không Carla): chưa có SF2 autosampled → chờ
// SonicVstiAutosample.ensure (1 request backend / plugin+preset) rồi
// play qua FluidSynth WASM như soundfont thường — âm đi qua masterBus
// → mastering → main out. ensure dedup in-flight + cooldown lỗi 60s.
if (!finalSfId && window.SonicVstiAutosample && synthEngine && !synthEngine.soundfont_id
&& String(synthEngine.type || '').indexOf('vst') !== -1 && !!synthEngine.plugin_id) {
var _pendKey = ch + ':' + midiPitch;
var _gen = _noteGeneration;
_pendingNoteOns[_pendKey] = (_pendingNoteOns[_pendKey] || 0) + 1;
window.SonicVstiAutosample.ensure(synthEngine).then(function (sfId) {
if (_gen !== _noteGeneration) return;
var _pend = _pendingNoteOns[_pendKey];
if (_pend) {
_pendingNoteOns[_pendKey] = _pend - 1;
if (_pendingNoteOns[_pendKey] <= 0) delete _pendingNoteOns[_pendKey];
} else {
return;
}
if (!sfId) {
// Không autosample được (404/501) → fallback oscillator để note
// KHÔNG câm; cooldown trong ensure chặn re-request.
try { self._playNoteFallback(note, velocity, durationMs, startTime, program, null, channel, synthEngine); } catch (e) {}
return;
}
synthEngine.autosampled_sf_id = sfId;
doNote();
});
return;
}
var cachedCh = _channels[ch];
// The note's own synth engine (track instrument) is
// authoritative. Channel state is only a cache: it must never