Sequencer Persistence — Serialization & State Restoration
Handles all localStorage persistence for the sequencer: auto-save, full state
restore, project snapshots, and sound card snapshots. Extracted from the main
sequencer.js to isolate I/O-dependent code.
Files
static/js/synth/sequencer-persistence.js (363 lines)
Storage Keys
| Key | Purpose | Format |
|---|---|---|
sequencer_state |
Auto-save (debounced 150ms) | Full project JSON |
sequencer_snapshots |
Project snapshots | [{name, date, data}] |
sequencer_sound_snapshots |
Sound card snapshots | {soundId: [{name, date, data}]} |
sequencer_song_mode |
Song mode slices | {slices: [...], activeSlice: N} |
sequencer_active_snapshot |
Currently loaded project snapshot name | String |
sequencer_active_sound_snapshot_{id} |
Currently loaded sound snapshot name | String |
Exports
| Export | Signature | Purpose |
|---|---|---|
serialize |
(engine) |
Full project state → plain JSON object |
save |
(engine) |
Debounced (150ms) localStorage write |
restore |
(engine, data) |
Async — full state restoration |
listSnapshots |
() |
Returns [{name, date}] |
saveSnapshot |
(engine, name) |
Saves current state as named snapshot |
loadSnapshot |
(name) |
Writes snapshot to auto-save key, reloads page |
deleteSnapshot |
(name) |
Removes one project snapshot |
exportSnapshot |
(name) |
Returns snapshot data for JSON download |
importSnapshot |
(engine, data) |
Saves as snapshot + reloads |
Serialization (serialize(engine))
Captures the complete sequencer state:
{
bpm, scaleRoot, scaleName, defaultOctave,
masterVolume,
glueThreshold, glueRatio, glueAttack, glueRelease,
reverbMix, reverbDecay, reverbPreDelay, reverbLowCut, reverbHighCut,
ruinaMode, ruinaDrive, ruinaFold, ruinaCrush, ruinaMix, ruinaWidth,
strips: [{ id, name, soundIds, volume, mute, solo, pan,
compressor, saturation, eq, filter,
activePattern, patterns: [{ id, name, snapshots }] }],
sounds: [{ id, name, engineId, presetName, activeSteps, maxSteps,
params, stages, steps, modRoute, eq, sidechain, sends,
_snapshotName }],
soundSnapshots: (from localStorage),
songData: (from engine.songMode.serialize())
}
Restoration (restore(engine, data))
Async function that populates the engine from saved data:
- Restore master settings (BPM, glue, reverb, ruina)
- For each sound: create engine instance, load defaults, apply saved params
- Restore preset manager presets if
presetNameis set - Restore strips with patterns and active pattern's step snapshots
- Old-format saves (flat sounds without strips) auto-migrated to a single strip
- Pad all step arrays to
totalSteps(128) - Restore sound card snapshots to localStorage (from
data.soundSnapshots)
Step Object Construction
Steps are stored as arrays of objects with defaults applied during save/restore:
function createStep(active, velocity, chance, mod, note) {
return { active: !!active,
velocity: velocity !== undefined ? velocity : 0.85,
chance: chance !== undefined ? chance : 100,
mod: mod !== undefined ? mod : 0,
note: note !== undefined ? note : -1 };
}
ModRoute Normalization
function _normalizeModRoute(mr)
Normalizes mod route entries from saved data (handles string, array, and object formats). Backward-compatible with older save formats.
Auto-Save Flow
Mutation → setVelocity / setStep / etc.
→ this._save()
→ persist.save(this)
→ if _saveTimer active: skip
→ setTimeout 150ms:
→ serialize(engine)
→ localStorage.setItem('sequencer_state', JSON.stringify(...))
Project Snapshots
Snapshots store the full serialized state plus metadata:
{ name: 'My Song', date: 1700000000000, data: { ... full serialized state ... } }
- Save (New button) — prompt for name, create snapshot, set as active
- Save (overwrite) — updates the currently active snapshot in-place
- Snapshots button — modal with Load/Export/Del per entry, plus Import
Sound Card Snapshots
Stored separately from project snapshots, keyed by soundId:
// storage format
{ 'sound-1': [{ name: 'Bass A', date: ..., data: { ... } }],
'sound-2': [{ name: 'Kick 1', date: ..., data: { ... } }] }
Each snapshot stores the full sound state: engineId, params, stages, steps,
activeSteps, maxSteps, eq, sidechain, sends, modRoute.
Included in project snapshot export via data.soundSnapshots.
Dependencies
registry.js—get()for engine lookuppreset-manager.js— dynamic import for preset reload during restorelocalStorage— browser storage API
See Also
docs/synth/sequencer.md— SequencerEngine overviewdocs/synth/preset-manager.md— preset management