fix(export): offline render tu tai file ve exportDir sau khi hoan thanh
renderMasteringExport truoc day chi hien toast 'Tai ve' (phai click) -> user tuong khong co file. Gio tu fetch res.url -> saveExportViaDialog (ghi thang vao exportDir da chon hoac save-dialog), toast kem path.
This commit is contained in:
+19
-8
@@ -28199,20 +28199,31 @@ const App = () => {
|
|||||||
_lastMasterStats = { lufs: res.lufs, true_peak_db: res.true_peak_db };
|
_lastMasterStats = { lufs: res.lufs, true_peak_db: res.true_peak_db };
|
||||||
const lufsTxt = (res.lufs !== null && res.lufs !== undefined) ? res.lufs + ' LUFS' : '-- LUFS';
|
const lufsTxt = (res.lufs !== null && res.lufs !== undefined) ? res.lufs + ' LUFS' : '-- LUFS';
|
||||||
const tpTxt = (res.true_peak_db !== null && res.true_peak_db !== undefined) ? res.true_peak_db + ' dBTP' : '-- dBTP';
|
const tpTxt = (res.true_peak_db !== null && res.true_peak_db !== undefined) ? res.true_peak_db + ' dBTP' : '-- dBTP';
|
||||||
showToast(`Mastering xong — ${lufsTxt} / ${tpTxt}${res.mono_warning ? ' • ' + res.mono_warning : ''}`, 'success', 'Tải về', async () => {
|
// Tự tải file về exportDir đã chọn (không chờ click "Tải về") — giống
|
||||||
try {
|
// bounce cũ: render xong là file xuất hiện ngay.
|
||||||
const br = await fetch(res.url);
|
try {
|
||||||
if (!br.ok) throw new Error('HTTP ' + br.status);
|
const br = await fetch(res.url);
|
||||||
|
if (br.ok) {
|
||||||
const b = await br.blob();
|
const b = await br.blob();
|
||||||
const sp = await saveExportViaDialog((projectName || 'Project') + '_master.' + outExt, b);
|
const sp = await saveExportViaDialog((projectName || 'Project') + '_master.' + outExt, b);
|
||||||
if (sp) showToast(`Đã lưu → ${sp}`, 'success');
|
if (sp) showToast(`Đã lưu → ${sp} • ${lufsTxt} / ${tpTxt}`, 'success');
|
||||||
} catch (e) {
|
else showToast(`Mastering xong — ${lufsTxt} / ${tpTxt}`, 'success');
|
||||||
|
} else {
|
||||||
|
showToast(`Mastering xong — ${lufsTxt} / ${tpTxt}`, 'success', 'Tải về', async () => {
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = res.url;
|
||||||
|
a.download = 'master.' + outExt;
|
||||||
|
a.click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
showToast(`Mastering xong — ${lufsTxt} / ${tpTxt}`, 'success', 'Tải về', async () => {
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = res.url;
|
a.href = res.url;
|
||||||
a.download = 'master.' + outExt;
|
a.download = 'master.' + outExt;
|
||||||
a.click();
|
a.click();
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showToast('Render mastering lỗi: ' + (e.message || e), 'error');
|
showToast('Render mastering lỗi: ' + (e.message || e), 'error');
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -2139,7 +2139,9 @@ clientSideExport(exportTracks);}finally{setIsExporting(false);setShowExportProgr
|
|||||||
clientSideExport(exportTracks,{loopStart,loopDur});}};// ── D4: Mastering render qua engine (D3 export stage) ──
|
clientSideExport(exportTracks,{loopStart,loopDur});}};// ── D4: Mastering render qua engine (D3 export stage) ──
|
||||||
// /api/v1/plugins/render — project schema + mastering chain qua native_bridge
|
// /api/v1/plugins/render — project schema + mastering chain qua native_bridge
|
||||||
// (VST3 masterbus), resample/normalize/dither PCM, mono side/mid check.
|
// (VST3 masterbus), resample/normalize/dither PCM, mono side/mid check.
|
||||||
const renderMasteringExport=async()=>{if(isExporting)return;if(serverStatus!=='connected'){showToast('Cần kết nối server để render mastering.','warning');return;}setIsExporting(true);try{const schema=serializeProjectToSchema(currentProjectId||'temp_project',projectName||'Dự án tạm chưa lưu',bpm,tracks,subTabs,sessionTabs,masteringSettings,masterVolume,{volL:masterVolL,volR:masterVolR,link:masterLink,muted:masterMuted});const isFloat=exportSettings.bitDepth==='float';const outExt=exportSettings.format==='ogg'?'ogg':'wav';const res=await window.SonicAPI.renderProject(schema,'master_'+Date.now()+'.'+outExt,{bit_depth:isFloat?32:parseInt(exportSettings.bitDepth)||16,sample_rate:parseInt(exportSettings.sampleRate)||44100,dither:!!exportSettings.dither,normalize:!!exportSettings.normalize,normalize_target:exportSettings.normalizeTarget||'-1dbtp',mono_check:!!exportSettings.monoCheck,metadata:{title:exportSettings.metaTitle||'',artist:exportSettings.metaArtist||'',isrc:exportSettings.metaIsrc||''}});_lastMasterStats={lufs:res.lufs,true_peak_db:res.true_peak_db};const lufsTxt=res.lufs!==null&&res.lufs!==undefined?res.lufs+' LUFS':'-- LUFS';const tpTxt=res.true_peak_db!==null&&res.true_peak_db!==undefined?res.true_peak_db+' dBTP':'-- dBTP';showToast(`Mastering xong — ${lufsTxt} / ${tpTxt}${res.mono_warning?' • '+res.mono_warning:''}`,'success','Tải về',async()=>{try{const br=await fetch(res.url);if(!br.ok)throw new Error('HTTP '+br.status);const b=await br.blob();const sp=await saveExportViaDialog((projectName||'Project')+'_master.'+outExt,b);if(sp)showToast(`Đã lưu → ${sp}`,'success');}catch(e){const a=document.createElement('a');a.href=res.url;a.download='master.'+outExt;a.click();}});}catch(e){showToast('Render mastering lỗi: '+(e.message||e),'error');}finally{setIsExporting(false);}};// ── Realtime Bounce Export (đầy đủ MIDI + FX Rack + Mastering) ──
|
const renderMasteringExport=async()=>{if(isExporting)return;if(serverStatus!=='connected'){showToast('Cần kết nối server để render mastering.','warning');return;}setIsExporting(true);try{const schema=serializeProjectToSchema(currentProjectId||'temp_project',projectName||'Dự án tạm chưa lưu',bpm,tracks,subTabs,sessionTabs,masteringSettings,masterVolume,{volL:masterVolL,volR:masterVolR,link:masterLink,muted:masterMuted});const isFloat=exportSettings.bitDepth==='float';const outExt=exportSettings.format==='ogg'?'ogg':'wav';const res=await window.SonicAPI.renderProject(schema,'master_'+Date.now()+'.'+outExt,{bit_depth:isFloat?32:parseInt(exportSettings.bitDepth)||16,sample_rate:parseInt(exportSettings.sampleRate)||44100,dither:!!exportSettings.dither,normalize:!!exportSettings.normalize,normalize_target:exportSettings.normalizeTarget||'-1dbtp',mono_check:!!exportSettings.monoCheck,metadata:{title:exportSettings.metaTitle||'',artist:exportSettings.metaArtist||'',isrc:exportSettings.metaIsrc||''}});_lastMasterStats={lufs:res.lufs,true_peak_db:res.true_peak_db};const lufsTxt=res.lufs!==null&&res.lufs!==undefined?res.lufs+' LUFS':'-- LUFS';const tpTxt=res.true_peak_db!==null&&res.true_peak_db!==undefined?res.true_peak_db+' dBTP':'-- dBTP';// Tự tải file về exportDir đã chọn (không chờ click "Tải về") — giống
|
||||||
|
// bounce cũ: render xong là file xuất hiện ngay.
|
||||||
|
try{const br=await fetch(res.url);if(br.ok){const b=await br.blob();const sp=await saveExportViaDialog((projectName||'Project')+'_master.'+outExt,b);if(sp)showToast(`Đã lưu → ${sp} • ${lufsTxt} / ${tpTxt}`,'success');else showToast(`Mastering xong — ${lufsTxt} / ${tpTxt}`,'success');}else{showToast(`Mastering xong — ${lufsTxt} / ${tpTxt}`,'success','Tải về',async()=>{const a=document.createElement('a');a.href=res.url;a.download='master.'+outExt;a.click();});}}catch(e){showToast(`Mastering xong — ${lufsTxt} / ${tpTxt}`,'success','Tải về',async()=>{const a=document.createElement('a');a.href=res.url;a.download='master.'+outExt;a.click();});}}catch(e){showToast('Render mastering lỗi: '+(e.message||e),'error');}finally{setIsExporting(false);}};// ── Realtime Bounce Export (đầy đủ MIDI + FX Rack + Mastering) ──
|
||||||
// MIDI/soundfont chạy qua FluidSynth (ScriptProcessor) — không render được
|
// MIDI/soundfont chạy qua FluidSynth (ScriptProcessor) — không render được
|
||||||
// trong OfflineAudioContext. Vì vậy bounce REALTIME: chạy lại toàn bộ project
|
// trong OfflineAudioContext. Vì vậy bounce REALTIME: chạy lại toàn bộ project
|
||||||
// (audio + MIDI + sections qua FX racks + mastering chain, đúng như nghe) và
|
// (audio + MIDI + sections qua FX racks + mastering chain, đúng như nghe) và
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
<script src="/static/js/services/promptTemplateManager.js?v=202607281039"></script>
|
<script src="/static/js/services/promptTemplateManager.js?v=202607281039"></script>
|
||||||
<script src="/static/js/services/undoRedoEngine.js?v=202607290941"></script>
|
<script src="/static/js/services/undoRedoEngine.js?v=202607290941"></script>
|
||||||
<script src="/static/js/services/chordTheory.js?v=202608211300"></script>
|
<script src="/static/js/services/chordTheory.js?v=202608211300"></script>
|
||||||
<script src="/static/js/app.precompiled.js?v=202608250103" defer></script>
|
<script src="/static/js/app.precompiled.js?v=202608250104" defer></script>
|
||||||
<link rel="stylesheet" href="/static/css/styles.css?v=202607271016">
|
<link rel="stylesheet" href="/static/css/styles.css?v=202607271016">
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
|
|||||||
Reference in New Issue
Block a user