renderizando projetos com sample tracks. basslines ok

This commit is contained in:
JotaChina committed 2025-12-28 16:56:31 -03:00
1 parent be5b12e845
commit 43a9aff447
3 files changed
+130 -32

No files matched your search

+44 -4
View File
@@ -912,6 +912,40 @@ async function generateAndDownloadMmpz(baseName) {
}
export async function buildRenderPackageBlob(baseName = "projeto") {
initializeAudioContext();
const baseXmlString = generateXmlFromState(); // patterns
const xmlDoc = new DOMParser().parseFromString(baseXmlString, "application/xml");
const zip = new JSZip();
await applySampleTracksToXmlAndZip(xmlDoc, zip); // ✅ coloca sampletco + samples/*.wav
const finalXml = new XMLSerializer().serializeToString(xmlDoc);
zip.file(`${baseName}.mmp`, finalXml);
const blob = await zip.generateAsync({ type: "blob", compression: "DEFLATE" });
// pode ser .mmpz (LMMS costuma aceitar) ou .zip (você já usa)
return { blob, fileName: `${baseName}.mmpz` };
}
export async function buildRenderPackageBase64(baseName = "projeto") {
const { blob, fileName } = await buildRenderPackageBlob(baseName);
const base64 = await blobToBase64(blob);
return { mmpzBase64: base64, mmpzName: fileName };
}
function blobToBase64(blob) {
return new Promise((resolve, reject) => {
const r = new FileReader();
r.onload = () => resolve(String(r.result).split(",")[1]); // remove data:...
r.onerror = reject;
r.readAsDataURL(blob);
});
}
function downloadBlob(blob, fileName) {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
@@ -1085,6 +1119,10 @@ async function _decodeAudioBufferCached(url) {
return decoded;
}
function _isProbablyWavUrl(url) {
return /\.wav(\?|#|$)/i.test(String(url || ""));
}
// -------------------- XML: SampleTracks + zip --------------------
async function applySampleTracksToXmlAndZip(xmlDoc, zip) {
@@ -1179,17 +1217,17 @@ async function applySampleTracksToXmlAndZip(xmlDoc, zip) {
// ✅ OTIMIZAÇÃO 2: sem offset + sem bake mix
// -> usa arquivo original no zip (sem decode/encode)
// -----------------------------------------
const needsOffset = Math.abs(offsetSec) > 1e-6;
const needsBake = Math.abs((vol ?? 1) - 1) > 1e-6 || Math.abs((pan ?? 0) - 0) > 1e-6;
const isWav = _isProbablyWavUrl(srcUrl);
if (!needsOffset && !needsBake) {
if (!needsOffset && !needsBake && isWav) {
const raw = await _fetchArrayBufferCached(srcUrl);
const name =
`${_sanitizeFileName(laneName)}__${_sanitizeFileName(clip.name || "clip")}` +
`__raw__${_sanitizeFileName(clip.id || String(cidx))}.wav`;
const zipPath = `samples/${name}`;
// evita regravar o mesmo raw várias vezes
if (!zip.file(zipPath)) zip.file(zipPath, raw);
const tco = xmlDoc.createElement("sampletco");
@@ -1201,6 +1239,8 @@ async function applySampleTracksToXmlAndZip(xmlDoc, zip) {
continue;
}
// se NÃO for wav, cai no “bake” (decode+encode wav) abaixo ✅
// -----------------------------------------
// ✅ OTIMIZAÇÃO 3: cache de slice idêntico
// -----------------------------------------