feat: persist track mute/solo status

This commit is contained in:
Xiaohan-Tian
2026-05-17 13:06:47 -07:00
parent cbd66ab4f6
commit 9c197ecd08
13 changed files with 285 additions and 21 deletions
@@ -9,6 +9,7 @@ import { upgradeToV7 } from './upgradeToV7';
import { upgradeToV8 } from './upgradeToV8';
import { upgradeToV9 } from './upgradeToV9';
import { upgradeToV10 } from './upgradeToV10';
import { upgradeToV11 } from './upgradeToV11';
/**
* Upgrade the given project to the latest structure version, one version at a time.
@@ -68,6 +69,10 @@ export function upgradeProjectToLatest(project: KGProject): KGProject {
workingProject = upgradeToV10(workingProject);
break;
}
case 11: {
workingProject = upgradeToV11(workingProject);
break;
}
default: {
// If an upgrader is missing, throw to prevent loading incompatible structures
throw new Error(`No upgrader found for project structure version ${nextVersion}`);
@@ -26,7 +26,7 @@ describe('upgradeToV10', () => {
const upgraded = upgradeProjectToLatest(project);
expect(upgraded.getProjectStructureVersion()).toBe(10);
expect(upgraded.getProjectStructureVersion()).toBe(11);
expect(upgraded.getTracks()[0].getVolumeAutomation()).toHaveLength(1);
});
});
@@ -0,0 +1,45 @@
import { describe, expect, it } from 'vitest';
import { KGProject } from '../KGProject';
import { KGTrack } from '../track/KGTrack';
import { upgradeProjectToLatest } from './KGProjectUpgrader';
import { upgradeToV11 } from './upgradeToV11';
describe('upgradeToV11', () => {
it('initializes missing mute and solo flags on legacy tracks', () => {
const track = new KGTrack('Legacy Track', 1);
delete (track as unknown as { muted?: unknown }).muted;
delete (track as unknown as { solo?: unknown }).solo;
const project = new KGProject('Test', 32, 0, 125, undefined, undefined, undefined, undefined, undefined, 1, [track], 10);
upgradeToV11(project);
expect(track.getMuted()).toBe(false);
expect(track.getSolo()).toBe(false);
expect(project.getProjectStructureVersion()).toBe(11);
});
it('preserves existing mute and solo flags', () => {
const track = new KGTrack('Legacy Track', 1);
track.setMuted(true);
track.setSolo(true);
const project = new KGProject('Test', 32, 0, 125, undefined, undefined, undefined, undefined, undefined, 1, [track], 10);
upgradeToV11(project);
expect(track.getMuted()).toBe(true);
expect(track.getSolo()).toBe(true);
});
it('upgrades legacy projects through the main upgrader path', () => {
const track = new KGTrack('Legacy Track', 1);
delete (track as unknown as { muted?: unknown }).muted;
delete (track as unknown as { solo?: unknown }).solo;
const project = new KGProject('Test', 32, 0, 125, undefined, undefined, undefined, undefined, undefined, 1, [track], 10);
const upgraded = upgradeProjectToLatest(project);
expect(upgraded.getProjectStructureVersion()).toBe(11);
expect(upgraded.getTracks()[0].getMuted()).toBe(false);
expect(upgraded.getTracks()[0].getSolo()).toBe(false);
});
});
+21
View File
@@ -0,0 +1,21 @@
import { KGProject } from '../KGProject';
export function upgradeToV11(project: KGProject): KGProject {
try {
for (const track of project.getTracks()) {
const muted = (track as unknown as { muted?: unknown }).muted;
if (typeof muted !== 'boolean') {
track.setMuted(false);
}
const solo = (track as unknown as { solo?: unknown }).solo;
if (typeof solo !== 'boolean') {
track.setSolo(false);
}
}
} finally {
project.setProjectStructureVersion(11);
}
return project;
}
@@ -57,7 +57,7 @@ describe('upgradeToV8', () => {
const upgraded = upgradeProjectToLatest(project);
expect(upgraded.getProjectStructureVersion()).toBe(10);
expect(upgraded.getProjectStructureVersion()).toBe(11);
expect((upgraded.getTracks()[0].getRegions()[0] as KGMidiRegion).getPitchBends()).toEqual([]);
expect((upgraded.getTracks()[0].getRegions()[0] as KGMidiRegion).getControllerEventsByType()).toHaveLength(128);
});