191 lines
5.9 KiB
JavaScript
191 lines
5.9 KiB
JavaScript
// js/state.js
|
|
import { initializePatternState } from "./pattern/pattern_state.js";
|
|
import { audioState, initializeAudioState, getAudioSnapshot, applyAudioSnapshot } from "./audio/audio_state.js";
|
|
import { DEFAULT_VOLUME, DEFAULT_PAN } from "./config.js";
|
|
import { generateMmpFile } from "./file.js"; // Vamos usar uma adaptação disto ou criar um helper
|
|
import { parseMmpContent } from "./file.js"; // Importante para restaurar o XML
|
|
|
|
// Estado global da aplicação
|
|
const globalState = {
|
|
sliceToolActive: false,
|
|
isPlaying: false,
|
|
isAudioEditorPlaying: false,
|
|
playbackIntervalId: null,
|
|
currentStep: 0,
|
|
metronomeEnabled: false,
|
|
originalXmlDoc: null,
|
|
currentBeatBasslineName: "Novo Projeto",
|
|
masterVolume: DEFAULT_VOLUME,
|
|
masterPan: DEFAULT_PAN,
|
|
zoomLevelIndex: 2,
|
|
isLoopActive: false,
|
|
loopStartTime: 0,
|
|
loopEndTime: 8,
|
|
resizeMode: "trim",
|
|
selectedClipId: null,
|
|
isRecording: false,
|
|
clipboard: null,
|
|
lastRulerClickTime: 0,
|
|
justReset: false,
|
|
// Configs Globais que devem persistir
|
|
bpm: 140,
|
|
compassoA: 4,
|
|
compassoB: 4,
|
|
bars: 1,
|
|
syncMode: "global" // Adicionado para persistir a escolha
|
|
};
|
|
|
|
const patternState = {
|
|
tracks: [],
|
|
activeTrackId: null,
|
|
activePatternIndex: 0,
|
|
};
|
|
|
|
// Combina todos os estados em um único objeto namespaced
|
|
export let appState = {
|
|
global: globalState,
|
|
pattern: patternState,
|
|
audio: audioState,
|
|
};
|
|
window.appState = appState;
|
|
|
|
export function resetProjectState() {
|
|
console.log("Executando resetProjectState completo...");
|
|
|
|
Object.assign(appState.global, {
|
|
sliceToolActive: false,
|
|
isPlaying: false,
|
|
isAudioEditorPlaying: false,
|
|
playbackIntervalId: null,
|
|
currentStep: 0,
|
|
metronomeEnabled: false,
|
|
originalXmlDoc: null,
|
|
currentBeatBasslineName: "Novo Projeto",
|
|
masterVolume: DEFAULT_VOLUME,
|
|
masterPan: DEFAULT_PAN,
|
|
zoomLevelIndex: 2,
|
|
isLoopActive: false,
|
|
loopStartTime: 0,
|
|
loopEndTime: 8,
|
|
resizeMode: "trim",
|
|
selectedClipId: null,
|
|
isRecording: false,
|
|
clipboard: null,
|
|
lastRulerClickTime: 0,
|
|
justReset: false,
|
|
});
|
|
|
|
Object.assign(appState.pattern, {
|
|
tracks: [],
|
|
activeTrackId: null,
|
|
activePatternIndex: 0,
|
|
});
|
|
|
|
initializeAudioState();
|
|
}
|
|
|
|
// --- NOVA IMPLEMENTAÇÃO DE PERSISTÊNCIA ---
|
|
|
|
/**
|
|
* Helper: Gera a string XML do estado atual.
|
|
* Precisamos "emprestar" a lógica do file.js sem baixar o arquivo.
|
|
* A maneira mais limpa é importar generateXmlFromState de file.js,
|
|
* mas como ela não é exportada lá, vamos usar uma estratégia via DOM
|
|
* ou mover a lógica. Para simplificar sem quebrar o file.js,
|
|
* vamos salvar apenas o "essencial" do patternState se o XML falhar,
|
|
* mas o ideal é garantir que o XML seja gerado.
|
|
* * NOTA: Para que isso funcione perfeitamente, certifique-se de exportar
|
|
* 'generateXmlFromState' no seu file.js ou usar a lógica abaixo.
|
|
*/
|
|
import { generateXmlFromStateExported } from "./file.js"; // Vamos assumir que você vai exportar isso no file.js
|
|
|
|
export function saveStateToSession() {
|
|
// Só salva se estiver em uma sala (contexto colaborativo/online)
|
|
if (!window.ROOM_NAME) return;
|
|
|
|
try {
|
|
// 1. Snapshot do Áudio (inclui blobs Base64 das gravações)
|
|
const audioSnap = getAudioSnapshot();
|
|
|
|
// 2. Snapshot do Pattern (XML)
|
|
// Se não conseguirmos o XML exato, salvamos os dados brutos do pattern
|
|
let xmlContent = null;
|
|
try {
|
|
// Tenta usar a função exportada (veja nota abaixo sobre file.js)
|
|
if(typeof generateXmlFromStateExported === 'function') {
|
|
xmlContent = generateXmlFromStateExported();
|
|
}
|
|
} catch(e) {
|
|
console.warn("Não foi possível gerar XML para backup:", e);
|
|
}
|
|
|
|
const stateToSave = {
|
|
timestamp: Date.now(),
|
|
xml: xmlContent,
|
|
// Fallback: Salva o pattern bruto se o XML falhar
|
|
patternRaw: !xmlContent ? appState.pattern : null,
|
|
audio: audioSnap,
|
|
global: {
|
|
bpm: appState.global.bpm, // Pega do state, que deve estar syncado com o DOM
|
|
compassoA: appState.global.compassoA,
|
|
compassoB: appState.global.compassoB,
|
|
bars: appState.global.bars,
|
|
syncMode: appState.global.syncMode
|
|
}
|
|
};
|
|
|
|
const roomName = window.ROOM_NAME;
|
|
sessionStorage.setItem(`mmp_backup_${roomName}`, JSON.stringify(stateToSave));
|
|
// console.log("Estado salvo na sessão local (F5 safe).");
|
|
|
|
} catch (e) {
|
|
console.error("Falha crítica ao salvar sessão (Quota Excedida?):", e);
|
|
}
|
|
}
|
|
|
|
export async function loadStateFromSession() {
|
|
const roomName = window.ROOM_NAME;
|
|
if (!roomName) return false;
|
|
|
|
try {
|
|
const raw = sessionStorage.getItem(`mmp_backup_${roomName}`);
|
|
if (!raw) return false;
|
|
|
|
const backup = JSON.parse(raw);
|
|
console.log(`[Session] Recuperando backup de ${new Date(backup.timestamp).toLocaleTimeString()}`);
|
|
|
|
// 1. Restaura Globais
|
|
if (backup.global) {
|
|
appState.global.bpm = backup.global.bpm;
|
|
appState.global.compassoA = backup.global.compassoA;
|
|
appState.global.compassoB = backup.global.compassoB;
|
|
appState.global.bars = backup.global.bars;
|
|
appState.global.syncMode = backup.global.syncMode || "global";
|
|
|
|
// Atualiza DOM imediatamente para evitar desincronia visual
|
|
const bpmInput = document.getElementById("bpm-input");
|
|
if(bpmInput) bpmInput.value = backup.global.bpm;
|
|
// ... (outros inputs se necessário, mas o renderAll cuida da maioria)
|
|
}
|
|
|
|
// 2. Restaura Pattern (XML é preferível)
|
|
if (backup.xml) {
|
|
await parseMmpContent(backup.xml);
|
|
} else if (backup.patternRaw) {
|
|
// Fallback simples (menos robusto que XML)
|
|
console.warn("Restaurando de Pattern Raw (backup antigo/incompleto)");
|
|
Object.assign(appState.pattern, backup.patternRaw);
|
|
}
|
|
|
|
// 3. Restaura Áudio (Clipes + Gravações)
|
|
if (backup.audio) {
|
|
await applyAudioSnapshot(backup.audio);
|
|
}
|
|
|
|
return true; // Sucesso
|
|
|
|
} catch (e) {
|
|
console.error("Erro ao restaurar sessão:", e);
|
|
return false;
|
|
}
|
|
} |