feat: switch track volume to dB scale with Logic Pro-style fader (−∞dB ~ +12dB)
This commit is contained in:
@@ -5,6 +5,7 @@ import { upgradeToV3 } from './upgradeToV3';
|
||||
import { upgradeToV4 } from './upgradeToV4';
|
||||
import { upgradeToV5 } from './upgradeToV5';
|
||||
import { upgradeToV6 } from './upgradeToV6';
|
||||
import { upgradeToV7 } from './upgradeToV7';
|
||||
|
||||
/**
|
||||
* Upgrade the given project to the latest structure version, one version at a time.
|
||||
@@ -48,6 +49,10 @@ export function upgradeProjectToLatest(project: KGProject): KGProject {
|
||||
workingProject = upgradeToV6(workingProject);
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
workingProject = upgradeToV7(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}`);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { KGProject } from '../KGProject';
|
||||
import { KGMidiTrack } from '../track/KGMidiTrack';
|
||||
import { upgradeToV7 } from './upgradeToV7';
|
||||
import { AUDIO_INTERFACE_CONSTANTS } from '../../constants/coreConstants';
|
||||
|
||||
function makeProject(volumes: number[]): KGProject {
|
||||
const tracks = volumes.map((v, i) => {
|
||||
const track = new KGMidiTrack(`Track ${i}`, i);
|
||||
// Bypass setVolume clamping to simulate old 0–1 linear values stored in JSON
|
||||
(track as unknown as { volume: number }).volume = v;
|
||||
return track;
|
||||
});
|
||||
const project = new KGProject('Test', 32, 0, 125, undefined, undefined, undefined, undefined, undefined, undefined, tracks, 6);
|
||||
return project;
|
||||
}
|
||||
|
||||
describe('upgradeToV7', () => {
|
||||
it('converts 1.0 linear to 0 dB', () => {
|
||||
const project = makeProject([1.0]);
|
||||
upgradeToV7(project);
|
||||
expect(project.getTracks()[0].getVolume()).toBeCloseTo(0, 5);
|
||||
});
|
||||
|
||||
it('converts 0.8 linear to ~−1.94 dB', () => {
|
||||
const project = makeProject([0.8]);
|
||||
upgradeToV7(project);
|
||||
expect(project.getTracks()[0].getVolume()).toBeCloseTo(20 * Math.log10(0.8), 3);
|
||||
});
|
||||
|
||||
it('converts 0.5 linear to ~−6.02 dB', () => {
|
||||
const project = makeProject([0.5]);
|
||||
upgradeToV7(project);
|
||||
expect(project.getTracks()[0].getVolume()).toBeCloseTo(-6.021, 2);
|
||||
});
|
||||
|
||||
it('converts 0.0 linear to MIN_TRACK_VOLUME_DB', () => {
|
||||
const project = makeProject([0.0]);
|
||||
upgradeToV7(project);
|
||||
expect(project.getTracks()[0].getVolume()).toBe(AUDIO_INTERFACE_CONSTANTS.MIN_TRACK_VOLUME_DB);
|
||||
});
|
||||
|
||||
it('clamps values that exceed MAX_TRACK_VOLUME_DB', () => {
|
||||
// linear > 1.0 would give positive dB; cap at +6
|
||||
const project = makeProject([2.0]);
|
||||
upgradeToV7(project);
|
||||
expect(project.getTracks()[0].getVolume()).toBe(AUDIO_INTERFACE_CONSTANTS.MAX_TRACK_VOLUME_DB);
|
||||
});
|
||||
|
||||
it('bumps project structure version to 7', () => {
|
||||
const project = makeProject([1.0]);
|
||||
upgradeToV7(project);
|
||||
expect(project.getProjectStructureVersion()).toBe(7);
|
||||
});
|
||||
|
||||
it('handles multiple tracks independently', () => {
|
||||
const project = makeProject([1.0, 0.5, 0.0]);
|
||||
upgradeToV7(project);
|
||||
const tracks = project.getTracks();
|
||||
expect(tracks[0].getVolume()).toBeCloseTo(0, 5);
|
||||
expect(tracks[1].getVolume()).toBeCloseTo(-6.021, 2);
|
||||
expect(tracks[2].getVolume()).toBe(AUDIO_INTERFACE_CONSTANTS.MIN_TRACK_VOLUME_DB);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { KGProject } from '../KGProject';
|
||||
import { AUDIO_INTERFACE_CONSTANTS } from '../../constants/coreConstants';
|
||||
|
||||
export function upgradeToV7(project: KGProject): KGProject {
|
||||
try {
|
||||
// Convert track volumes from 0–1 linear scale to dB
|
||||
for (const track of project.getTracks()) {
|
||||
const linear = track.getVolume();
|
||||
let db: number;
|
||||
if (linear <= 0) {
|
||||
db = AUDIO_INTERFACE_CONSTANTS.MIN_TRACK_VOLUME_DB;
|
||||
} else {
|
||||
db = 20 * Math.log10(linear);
|
||||
db = Math.max(AUDIO_INTERFACE_CONSTANTS.MIN_TRACK_VOLUME_DB,
|
||||
Math.min(AUDIO_INTERFACE_CONSTANTS.MAX_TRACK_VOLUME_DB, db));
|
||||
}
|
||||
track.setVolume(db);
|
||||
}
|
||||
} finally {
|
||||
project.setProjectStructureVersion(7);
|
||||
}
|
||||
return project;
|
||||
}
|
||||
Reference in New Issue
Block a user