feat: added shortcut N for sheet music view

This commit is contained in:
Xiaohan-Tian
2026-05-18 19:12:08 -07:00
parent 4cf474be7e
commit 97dad696b2
7 changed files with 253 additions and 8 deletions
+35
View File
@@ -3,6 +3,10 @@ import { act } from '@testing-library/react';
import { KGTrack } from '../core/track/KGTrack';
import { KGMidiTrack } from '../core/track/KGMidiTrack';
const pianoRollStateMocks = vi.hoisted(() => ({
setSheetMusicViewEnabled: vi.fn(),
}));
let mockTracks: KGTrack[] = [new KGMidiTrack('Track 1', 0, 'acoustic_grand_piano')];
const mockProject = {
getTimeSignature: () => ({ numerator: 4, denominator: 4 }),
@@ -76,10 +80,17 @@ vi.mock('../core/config/ConfigManager', () => ({
},
}));
vi.mock('../core/state/KGPianoRollState', () => ({
KGPianoRollState: {
instance: () => pianoRollStateMocks,
},
}));
describe('projectStore piano roll state', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.resetModules();
pianoRollStateMocks.setSheetMusicViewEnabled.mockReset();
mockTracks = [new KGMidiTrack('Track 1', 0, 'acoustic_grand_piano')];
mockCore.startPlaying.mockReset();
mockCore.startPlaying.mockResolvedValue(undefined);
@@ -118,10 +129,34 @@ describe('projectStore piano roll state', () => {
});
state = useProjectStore.getState();
expect(pianoRollStateMocks.setSheetMusicViewEnabled).toHaveBeenCalledWith(false);
expect(state.showPianoRoll).toBe(true);
expect(state.pianoRollMode).toBe('midi-edit');
expect(state.activeRegionId).toBe('midi-b');
expect(state.hybridAudioRegionId).toBeNull();
expect(state.requestedSheetMusicViewEnabled).toBe(false);
expect(state.pianoRollViewRequestVersion).toBe(1);
});
it('opens a MIDI region in sheet music view when requested', async () => {
const { useProjectStore } = await import('./projectStore');
act(() => {
useProjectStore.getState().openHybridMode('midi-a', 'audio-a');
});
act(() => {
useProjectStore.getState().openMidiPianoRollWithSheetMusicView('midi-b', true);
});
const state = useProjectStore.getState();
expect(pianoRollStateMocks.setSheetMusicViewEnabled).toHaveBeenCalledWith(true);
expect(state.showPianoRoll).toBe(true);
expect(state.pianoRollMode).toBe('midi-edit');
expect(state.activeRegionId).toBe('midi-b');
expect(state.hybridAudioRegionId).toBeNull();
expect(state.requestedSheetMusicViewEnabled).toBe(true);
expect(state.pianoRollViewRequestVersion).toBe(1);
});
it('tracks playback preparation around startPlaying success', async () => {
+42 -3
View File
@@ -98,6 +98,8 @@ interface ProjectState {
activeRegionId: string | null;
pianoRollMode: 'midi-edit' | 'spectrogram' | 'hybrid';
hybridAudioRegionId: string | null;
requestedSheetMusicViewEnabled: boolean;
pianoRollViewRequestVersion: number;
automationRedrawVersion: number;
activeTrackAutomationTrackId: string | null;
activeTrackAutomationType: TrackAutomationType | null;
@@ -194,6 +196,7 @@ interface ProjectState {
setShowPianoRoll: (show: boolean) => void;
setActiveRegionId: (regionId: string | null) => void;
openMidiPianoRoll: (regionId: string) => void;
openMidiPianoRollWithSheetMusicView: (regionId: string, sheetMusicViewEnabled: boolean) => void;
openSpectrogramViewer: (regionId: string) => void;
openHybridMode: (midiRegionId: string, audioRegionId: string) => void;
bumpAutomationRedrawVersion: () => void;
@@ -430,6 +433,8 @@ export const useProjectStore = create<ProjectState>((set, get) => {
activeRegionId: null,
pianoRollMode: 'midi-edit' as const,
hybridAudioRegionId: null,
requestedSheetMusicViewEnabled: false,
pianoRollViewRequestVersion: 0,
automationRedrawVersion: 0,
activeTrackAutomationTrackId: null,
activeTrackAutomationType: null,
@@ -1560,15 +1565,47 @@ export const useProjectStore = create<ProjectState>((set, get) => {
},
openMidiPianoRoll: (regionId: string) => {
set({ showPianoRoll: true, activeRegionId: regionId, pianoRollMode: 'midi-edit', hybridAudioRegionId: null });
KGPianoRollState.instance().setSheetMusicViewEnabled(false);
set(state => ({
showPianoRoll: true,
activeRegionId: regionId,
pianoRollMode: 'midi-edit',
hybridAudioRegionId: null,
requestedSheetMusicViewEnabled: false,
pianoRollViewRequestVersion: state.pianoRollViewRequestVersion + 1,
}));
},
openMidiPianoRollWithSheetMusicView: (regionId: string, sheetMusicViewEnabled: boolean) => {
KGPianoRollState.instance().setSheetMusicViewEnabled(sheetMusicViewEnabled);
set(state => ({
showPianoRoll: true,
activeRegionId: regionId,
pianoRollMode: 'midi-edit',
hybridAudioRegionId: null,
requestedSheetMusicViewEnabled: sheetMusicViewEnabled,
pianoRollViewRequestVersion: state.pianoRollViewRequestVersion + 1,
}));
},
openSpectrogramViewer: (regionId: string) => {
set({ showPianoRoll: true, activeRegionId: regionId, pianoRollMode: 'spectrogram', hybridAudioRegionId: null });
set({
showPianoRoll: true,
activeRegionId: regionId,
pianoRollMode: 'spectrogram',
hybridAudioRegionId: null,
requestedSheetMusicViewEnabled: false,
});
},
openHybridMode: (midiRegionId: string, audioRegionId: string) => {
set({ showPianoRoll: true, activeRegionId: midiRegionId, hybridAudioRegionId: audioRegionId, pianoRollMode: 'hybrid' });
set({
showPianoRoll: true,
activeRegionId: midiRegionId,
hybridAudioRegionId: audioRegionId,
pianoRollMode: 'hybrid',
requestedSheetMusicViewEnabled: false,
});
},
bumpAutomationRedrawVersion: () => {
set(state => ({ automationRedrawVersion: state.automationRedrawVersion + 1 }));
@@ -1587,6 +1624,8 @@ export const useProjectStore = create<ProjectState>((set, get) => {
activeRegionId: null,
hybridAudioRegionId: null,
pianoRollMode: 'midi-edit',
requestedSheetMusicViewEnabled: false,
pianoRollViewRequestVersion: 0,
activeTrackAutomationTrackId: null,
activeTrackAutomationType: null,
trackAutomationRedrawVersion: 0,