feat: added shortcut N for sheet music view
This commit is contained in:
@@ -35,6 +35,8 @@ const storeState = {
|
|||||||
storeState.activeRegionId = regionId;
|
storeState.activeRegionId = regionId;
|
||||||
}),
|
}),
|
||||||
pianoRollMode: 'midi-edit' as const,
|
pianoRollMode: 'midi-edit' as const,
|
||||||
|
requestedSheetMusicViewEnabled: false,
|
||||||
|
pianoRollViewRequestVersion: 0,
|
||||||
openMidiPianoRoll: vi.fn(),
|
openMidiPianoRoll: vi.fn(),
|
||||||
openSpectrogramViewer: vi.fn(),
|
openSpectrogramViewer: vi.fn(),
|
||||||
openHybridMode: vi.fn(),
|
openHybridMode: vi.fn(),
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ const MainContent: React.FC<MainContentProps> = ({
|
|||||||
setShowPianoRoll,
|
setShowPianoRoll,
|
||||||
setActiveRegionId,
|
setActiveRegionId,
|
||||||
pianoRollMode,
|
pianoRollMode,
|
||||||
|
requestedSheetMusicViewEnabled,
|
||||||
|
pianoRollViewRequestVersion,
|
||||||
openMidiPianoRoll,
|
openMidiPianoRoll,
|
||||||
openSpectrogramViewer,
|
openSpectrogramViewer,
|
||||||
openHybridMode,
|
openHybridMode,
|
||||||
@@ -1052,6 +1054,8 @@ const MainContent: React.FC<MainContentProps> = ({
|
|||||||
onClose={handlePianoRollClose}
|
onClose={handlePianoRollClose}
|
||||||
regionId={activeRegionId}
|
regionId={activeRegionId}
|
||||||
mode={pianoRollMode}
|
mode={pianoRollMode}
|
||||||
|
requestedSheetMusicViewEnabled={requestedSheetMusicViewEnabled}
|
||||||
|
pianoRollViewRequestVersion={pianoRollViewRequestVersion}
|
||||||
audioRegion={(() => {
|
audioRegion={(() => {
|
||||||
// spectrogram mode: audio region IS the activeRegionId
|
// spectrogram mode: audio region IS the activeRegionId
|
||||||
// hybrid mode: audio region is hybridAudioRegionId
|
// hybrid mode: audio region is hybridAudioRegionId
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ interface PianoRollProps {
|
|||||||
initialPosition?: { x: number; y: number };
|
initialPosition?: { x: number; y: number };
|
||||||
initialSize?: { width: number; height: number };
|
initialSize?: { width: number; height: number };
|
||||||
mode?: 'midi-edit' | 'spectrogram' | 'hybrid';
|
mode?: 'midi-edit' | 'spectrogram' | 'hybrid';
|
||||||
|
requestedSheetMusicViewEnabled?: boolean;
|
||||||
|
pianoRollViewRequestVersion?: number;
|
||||||
audioRegion?: KGAudioRegion;
|
audioRegion?: KGAudioRegion;
|
||||||
trackId?: string;
|
trackId?: string;
|
||||||
projectName?: string;
|
projectName?: string;
|
||||||
@@ -74,6 +76,8 @@ const PianoRoll: React.FC<PianoRollProps> = ({
|
|||||||
initialPosition,
|
initialPosition,
|
||||||
initialSize,
|
initialSize,
|
||||||
mode = 'midi-edit',
|
mode = 'midi-edit',
|
||||||
|
requestedSheetMusicViewEnabled = false,
|
||||||
|
pianoRollViewRequestVersion = 0,
|
||||||
audioRegion,
|
audioRegion,
|
||||||
trackId,
|
trackId,
|
||||||
projectName,
|
projectName,
|
||||||
@@ -153,6 +157,7 @@ const PianoRoll: React.FC<PianoRollProps> = ({
|
|||||||
const pendingModeSwitchRequestRef = useRef<PendingModeSwitchRequest | null>(null);
|
const pendingModeSwitchRequestRef = useRef<PendingModeSwitchRequest | null>(null);
|
||||||
const previousSheetMusicViewEnabledRef = useRef<boolean>(false);
|
const previousSheetMusicViewEnabledRef = useRef<boolean>(false);
|
||||||
const previousActiveRegionIdRef = useRef<string | null>(null);
|
const previousActiveRegionIdRef = useRef<string | null>(null);
|
||||||
|
const lastAppliedViewRequestVersionRef = useRef<number>(0);
|
||||||
|
|
||||||
// Ref for storing the setNoteUpdateCounter function
|
// Ref for storing the setNoteUpdateCounter function
|
||||||
const triggerNoteUpdateRef = useRef<React.Dispatch<React.SetStateAction<number>> | null>(null);
|
const triggerNoteUpdateRef = useRef<React.Dispatch<React.SetStateAction<number>> | null>(null);
|
||||||
@@ -268,6 +273,42 @@ const PianoRoll: React.FC<PianoRollProps> = ({
|
|||||||
}
|
}
|
||||||
}, []); // Empty dependency array means this runs once on mount
|
}, []); // Empty dependency array means this runs once on mount
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSpectrogram) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pianoRollViewRequestVersion === 0 || lastAppliedViewRequestVersionRef.current === pianoRollViewRequestVersion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastAppliedViewRequestVersionRef.current = pianoRollViewRequestVersion;
|
||||||
|
|
||||||
|
if (activeRegion) {
|
||||||
|
pendingModeSwitchRequestRef.current = createPendingModeSwitchRequest({
|
||||||
|
playheadBeat: playheadPosition,
|
||||||
|
regionStartBeat: activeRegion.getStartFromBeat(),
|
||||||
|
regionEndBeat: activeRegion.getStartFromBeat() + activeRegion.getLength(),
|
||||||
|
sourceSheetMusicViewEnabled: sheetMusicViewEnabled,
|
||||||
|
destinationSheetMusicViewEnabled: requestedSheetMusicViewEnabled,
|
||||||
|
destinationSheetMusicTrackScopeEnabled: requestedSheetMusicViewEnabled && sheetMusicTrackScopeEnabled,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
pendingModeSwitchRequestRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSheetMusicViewEnabled(requestedSheetMusicViewEnabled);
|
||||||
|
KGPianoRollState.instance().setSheetMusicViewEnabled(requestedSheetMusicViewEnabled);
|
||||||
|
}, [
|
||||||
|
activeRegion,
|
||||||
|
isSpectrogram,
|
||||||
|
pianoRollViewRequestVersion,
|
||||||
|
playheadPosition,
|
||||||
|
requestedSheetMusicViewEnabled,
|
||||||
|
sheetMusicTrackScopeEnabled,
|
||||||
|
sheetMusicViewEnabled,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let unsubscribe: (() => void) | undefined;
|
let unsubscribe: (() => void) | undefined;
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,27 @@ import React from 'react';
|
|||||||
import { fireEvent, render, waitFor } from '@testing-library/react';
|
import { fireEvent, render, waitFor } from '@testing-library/react';
|
||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import { useGlobalKeyboardHandler } from './useGlobalKeyboardHandler';
|
import { useGlobalKeyboardHandler } from './useGlobalKeyboardHandler';
|
||||||
|
import { showAlert } from '../util/dialogUtil';
|
||||||
|
|
||||||
const regionEditUtilMocks = vi.hoisted(() => ({
|
const regionEditUtilMocks = vi.hoisted(() => ({
|
||||||
splitSelectedRegionAtPlayhead: vi.fn(),
|
splitSelectedRegionAtPlayhead: vi.fn(),
|
||||||
mergeSelectedMidiRegions: vi.fn(),
|
mergeSelectedMidiRegions: vi.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const MockMidiRegion = vi.hoisted(() => class {
|
||||||
|
private readonly id: string;
|
||||||
|
|
||||||
|
constructor(id: string) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mockTracks: Array<{ getRegions: () => Array<{ getId: () => string }> }> = [];
|
||||||
|
|
||||||
const storeState = {
|
const storeState = {
|
||||||
undo: vi.fn(),
|
undo: vi.fn(),
|
||||||
redo: vi.fn(),
|
redo: vi.fn(),
|
||||||
@@ -30,6 +45,7 @@ const storeState = {
|
|||||||
setShowPianoRoll: vi.fn(),
|
setShowPianoRoll: vi.fn(),
|
||||||
showPianoRoll: false,
|
showPianoRoll: false,
|
||||||
openMidiPianoRoll: vi.fn(),
|
openMidiPianoRoll: vi.fn(),
|
||||||
|
openMidiPianoRollWithSheetMusicView: vi.fn(),
|
||||||
openSpectrogramViewer: vi.fn(),
|
openSpectrogramViewer: vi.fn(),
|
||||||
playheadPosition: 12,
|
playheadPosition: 12,
|
||||||
refreshProjectState: vi.fn(),
|
refreshProjectState: vi.fn(),
|
||||||
@@ -101,7 +117,7 @@ vi.mock('../core/KGCore', () => ({
|
|||||||
KGCore: {
|
KGCore: {
|
||||||
instance: () => ({
|
instance: () => ({
|
||||||
getCurrentProject: () => ({
|
getCurrentProject: () => ({
|
||||||
getTracks: () => [],
|
getTracks: () => mockTracks,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@@ -116,7 +132,7 @@ vi.mock('../core/midi-input/KGMidiInput', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('../core/region/KGMidiRegion', () => ({
|
vi.mock('../core/region/KGMidiRegion', () => ({
|
||||||
KGMidiRegion: class {},
|
KGMidiRegion: MockMidiRegion,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('../core/track/KGAudioTrack', () => ({
|
vi.mock('../core/track/KGAudioTrack', () => ({
|
||||||
@@ -139,9 +155,18 @@ const HookHarness = () => {
|
|||||||
|
|
||||||
describe('useGlobalKeyboardHandler region shortcuts', () => {
|
describe('useGlobalKeyboardHandler region shortcuts', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
mockTracks = [];
|
||||||
regionEditUtilMocks.splitSelectedRegionAtPlayhead.mockReset();
|
regionEditUtilMocks.splitSelectedRegionAtPlayhead.mockReset();
|
||||||
regionEditUtilMocks.mergeSelectedMidiRegions.mockReset();
|
regionEditUtilMocks.mergeSelectedMidiRegions.mockReset();
|
||||||
storeState.setStatus.mockClear();
|
storeState.setStatus.mockClear();
|
||||||
|
storeState.setShowPianoRoll.mockClear();
|
||||||
|
storeState.showPianoRoll = false;
|
||||||
|
storeState.activeRegionId = null;
|
||||||
|
storeState.selectedRegionIds = ['region-a', 'region-b'];
|
||||||
|
storeState.openMidiPianoRoll.mockClear();
|
||||||
|
storeState.openMidiPianoRollWithSheetMusicView.mockClear();
|
||||||
|
storeState.openSpectrogramViewer.mockClear();
|
||||||
|
vi.mocked(showAlert).mockClear();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('triggers split on Ctrl+T', async () => {
|
it('triggers split on Ctrl+T', async () => {
|
||||||
@@ -180,4 +205,76 @@ describe('useGlobalKeyboardHandler region shortcuts', () => {
|
|||||||
expect(storeState.setStatus).toHaveBeenCalledWith('Merged 2 MIDI regions');
|
expect(storeState.setStatus).toHaveBeenCalledWith('Merged 2 MIDI regions');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('opens a selected MIDI region in piano roll view on E', () => {
|
||||||
|
mockTracks = [
|
||||||
|
{
|
||||||
|
getRegions: () => [new MockMidiRegion('region-b')],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
render(<HookHarness />);
|
||||||
|
fireEvent.keyDown(document.body, { key: 'e' });
|
||||||
|
|
||||||
|
expect(storeState.openMidiPianoRollWithSheetMusicView).toHaveBeenCalledWith('region-b', false);
|
||||||
|
expect(storeState.openSpectrogramViewer).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('opens a selected MIDI region in sheet music view on N', () => {
|
||||||
|
mockTracks = [
|
||||||
|
{
|
||||||
|
getRegions: () => [new MockMidiRegion('region-b')],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
render(<HookHarness />);
|
||||||
|
fireEvent.keyDown(document.body, { key: 'n' });
|
||||||
|
|
||||||
|
expect(storeState.openMidiPianoRollWithSheetMusicView).toHaveBeenCalledWith('region-b', true);
|
||||||
|
expect(storeState.setShowPianoRoll).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows the editor alert on N when no region is selected', () => {
|
||||||
|
storeState.selectedRegionIds = [];
|
||||||
|
|
||||||
|
render(<HookHarness />);
|
||||||
|
fireEvent.keyDown(document.body, { key: 'n' });
|
||||||
|
|
||||||
|
expect(showAlert).toHaveBeenCalledWith('Please select a region to open the editor.');
|
||||||
|
expect(storeState.openMidiPianoRollWithSheetMusicView).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not open spectrogram on N for an audio region', () => {
|
||||||
|
mockTracks = [
|
||||||
|
{
|
||||||
|
getRegions: () => [
|
||||||
|
{
|
||||||
|
getId: () => 'region-b',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
render(<HookHarness />);
|
||||||
|
fireEvent.keyDown(document.body, { key: 'n' });
|
||||||
|
|
||||||
|
expect(showAlert).toHaveBeenCalledWith('Sheet music view is only available for MIDI regions.');
|
||||||
|
expect(storeState.openSpectrogramViewer).not.toHaveBeenCalled();
|
||||||
|
expect(storeState.openMidiPianoRollWithSheetMusicView).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not close the editor when N is pressed while piano roll is already open', () => {
|
||||||
|
storeState.showPianoRoll = true;
|
||||||
|
mockTracks = [
|
||||||
|
{
|
||||||
|
getRegions: () => [new MockMidiRegion('region-b')],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
render(<HookHarness />);
|
||||||
|
fireEvent.keyDown(document.body, { key: 'n' });
|
||||||
|
|
||||||
|
expect(storeState.setShowPianoRoll).not.toHaveBeenCalled();
|
||||||
|
expect(storeState.openMidiPianoRollWithSheetMusicView).toHaveBeenCalledWith('region-b', true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { showAlert } from '../util/dialogUtil';
|
|||||||
* Handles keyboard shortcuts defined in the configuration
|
* Handles keyboard shortcuts defined in the configuration
|
||||||
*/
|
*/
|
||||||
export const useGlobalKeyboardHandler = () => {
|
export const useGlobalKeyboardHandler = () => {
|
||||||
const { undo, redo, setStatus, isPlaying, startPlaying, stopTransport, toggleLoop, projectName, savedProjectName, setSavedProjectName, setProjectName, isRecording, startRecording, stopRecording, activeRegionId, selectedRegionIds, setActiveRegionId, setShowPianoRoll, showPianoRoll, openMidiPianoRoll, openSpectrogramViewer, playheadPosition, refreshProjectState } = useProjectStore();
|
const { undo, redo, setStatus, isPlaying, startPlaying, stopTransport, toggleLoop, projectName, savedProjectName, setSavedProjectName, setProjectName, isRecording, startRecording, stopRecording, activeRegionId, selectedRegionIds, setActiveRegionId, setShowPianoRoll, showPianoRoll, openMidiPianoRollWithSheetMusicView, openSpectrogramViewer, playheadPosition, refreshProjectState } = useProjectStore();
|
||||||
const lastSelectedRegionId = selectedRegionIds[selectedRegionIds.length - 1] ?? null;
|
const lastSelectedRegionId = selectedRegionIds[selectedRegionIds.length - 1] ?? null;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -256,13 +256,40 @@ export const useGlobalKeyboardHandler = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (foundMidi) {
|
if (foundMidi) {
|
||||||
openMidiPianoRoll(candidateId);
|
openMidiPianoRollWithSheetMusicView(candidateId, false);
|
||||||
} else if (foundAudio) {
|
} else if (foundAudio) {
|
||||||
openSpectrogramViewer(candidateId);
|
openSpectrogramViewer(candidateId);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for sheet music shortcut (N) — open piano roll for MIDI in sheet music view
|
||||||
|
if (event.key.toLowerCase() === 'n' && !event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
const candidateId = activeRegionId ?? lastSelectedRegionId;
|
||||||
|
if (!candidateId) {
|
||||||
|
void showAlert('Please select a region to open the editor.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tracks = KGCore.instance().getCurrentProject().getTracks();
|
||||||
|
let foundMidi = false;
|
||||||
|
let foundAudio = false;
|
||||||
|
for (const track of tracks) {
|
||||||
|
const region = track.getRegions().find(r => r.getId() === candidateId);
|
||||||
|
if (region) {
|
||||||
|
if (region instanceof KGMidiRegion) foundMidi = true;
|
||||||
|
else foundAudio = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundMidi) {
|
||||||
|
openMidiPianoRollWithSheetMusicView(candidateId, true);
|
||||||
|
} else if (foundAudio) {
|
||||||
|
void showAlert('Sheet music view is only available for MIDI regions.');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for save shortcut
|
// Check for save shortcut
|
||||||
if (saveShortcut && matchesKeyboardShortcut(event, saveShortcut)) {
|
if (saveShortcut && matchesKeyboardShortcut(event, saveShortcut)) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -307,7 +334,7 @@ export const useGlobalKeyboardHandler = () => {
|
|||||||
setActiveRegionId,
|
setActiveRegionId,
|
||||||
setShowPianoRoll,
|
setShowPianoRoll,
|
||||||
showPianoRoll,
|
showPianoRoll,
|
||||||
openMidiPianoRoll,
|
openMidiPianoRollWithSheetMusicView,
|
||||||
openSpectrogramViewer,
|
openSpectrogramViewer,
|
||||||
playheadPosition,
|
playheadPosition,
|
||||||
refreshProjectState,
|
refreshProjectState,
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import { act } from '@testing-library/react';
|
|||||||
import { KGTrack } from '../core/track/KGTrack';
|
import { KGTrack } from '../core/track/KGTrack';
|
||||||
import { KGMidiTrack } from '../core/track/KGMidiTrack';
|
import { KGMidiTrack } from '../core/track/KGMidiTrack';
|
||||||
|
|
||||||
|
const pianoRollStateMocks = vi.hoisted(() => ({
|
||||||
|
setSheetMusicViewEnabled: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
let mockTracks: KGTrack[] = [new KGMidiTrack('Track 1', 0, 'acoustic_grand_piano')];
|
let mockTracks: KGTrack[] = [new KGMidiTrack('Track 1', 0, 'acoustic_grand_piano')];
|
||||||
const mockProject = {
|
const mockProject = {
|
||||||
getTimeSignature: () => ({ numerator: 4, denominator: 4 }),
|
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', () => {
|
describe('projectStore piano roll state', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
vi.resetModules();
|
vi.resetModules();
|
||||||
|
pianoRollStateMocks.setSheetMusicViewEnabled.mockReset();
|
||||||
mockTracks = [new KGMidiTrack('Track 1', 0, 'acoustic_grand_piano')];
|
mockTracks = [new KGMidiTrack('Track 1', 0, 'acoustic_grand_piano')];
|
||||||
mockCore.startPlaying.mockReset();
|
mockCore.startPlaying.mockReset();
|
||||||
mockCore.startPlaying.mockResolvedValue(undefined);
|
mockCore.startPlaying.mockResolvedValue(undefined);
|
||||||
@@ -118,10 +129,34 @@ describe('projectStore piano roll state', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
state = useProjectStore.getState();
|
state = useProjectStore.getState();
|
||||||
|
expect(pianoRollStateMocks.setSheetMusicViewEnabled).toHaveBeenCalledWith(false);
|
||||||
expect(state.showPianoRoll).toBe(true);
|
expect(state.showPianoRoll).toBe(true);
|
||||||
expect(state.pianoRollMode).toBe('midi-edit');
|
expect(state.pianoRollMode).toBe('midi-edit');
|
||||||
expect(state.activeRegionId).toBe('midi-b');
|
expect(state.activeRegionId).toBe('midi-b');
|
||||||
expect(state.hybridAudioRegionId).toBeNull();
|
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 () => {
|
it('tracks playback preparation around startPlaying success', async () => {
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ interface ProjectState {
|
|||||||
activeRegionId: string | null;
|
activeRegionId: string | null;
|
||||||
pianoRollMode: 'midi-edit' | 'spectrogram' | 'hybrid';
|
pianoRollMode: 'midi-edit' | 'spectrogram' | 'hybrid';
|
||||||
hybridAudioRegionId: string | null;
|
hybridAudioRegionId: string | null;
|
||||||
|
requestedSheetMusicViewEnabled: boolean;
|
||||||
|
pianoRollViewRequestVersion: number;
|
||||||
automationRedrawVersion: number;
|
automationRedrawVersion: number;
|
||||||
activeTrackAutomationTrackId: string | null;
|
activeTrackAutomationTrackId: string | null;
|
||||||
activeTrackAutomationType: TrackAutomationType | null;
|
activeTrackAutomationType: TrackAutomationType | null;
|
||||||
@@ -194,6 +196,7 @@ interface ProjectState {
|
|||||||
setShowPianoRoll: (show: boolean) => void;
|
setShowPianoRoll: (show: boolean) => void;
|
||||||
setActiveRegionId: (regionId: string | null) => void;
|
setActiveRegionId: (regionId: string | null) => void;
|
||||||
openMidiPianoRoll: (regionId: string) => void;
|
openMidiPianoRoll: (regionId: string) => void;
|
||||||
|
openMidiPianoRollWithSheetMusicView: (regionId: string, sheetMusicViewEnabled: boolean) => void;
|
||||||
openSpectrogramViewer: (regionId: string) => void;
|
openSpectrogramViewer: (regionId: string) => void;
|
||||||
openHybridMode: (midiRegionId: string, audioRegionId: string) => void;
|
openHybridMode: (midiRegionId: string, audioRegionId: string) => void;
|
||||||
bumpAutomationRedrawVersion: () => void;
|
bumpAutomationRedrawVersion: () => void;
|
||||||
@@ -430,6 +433,8 @@ export const useProjectStore = create<ProjectState>((set, get) => {
|
|||||||
activeRegionId: null,
|
activeRegionId: null,
|
||||||
pianoRollMode: 'midi-edit' as const,
|
pianoRollMode: 'midi-edit' as const,
|
||||||
hybridAudioRegionId: null,
|
hybridAudioRegionId: null,
|
||||||
|
requestedSheetMusicViewEnabled: false,
|
||||||
|
pianoRollViewRequestVersion: 0,
|
||||||
automationRedrawVersion: 0,
|
automationRedrawVersion: 0,
|
||||||
activeTrackAutomationTrackId: null,
|
activeTrackAutomationTrackId: null,
|
||||||
activeTrackAutomationType: null,
|
activeTrackAutomationType: null,
|
||||||
@@ -1560,15 +1565,47 @@ export const useProjectStore = create<ProjectState>((set, get) => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
openMidiPianoRoll: (regionId: string) => {
|
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) => {
|
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) => {
|
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: () => {
|
bumpAutomationRedrawVersion: () => {
|
||||||
set(state => ({ automationRedrawVersion: state.automationRedrawVersion + 1 }));
|
set(state => ({ automationRedrawVersion: state.automationRedrawVersion + 1 }));
|
||||||
@@ -1587,6 +1624,8 @@ export const useProjectStore = create<ProjectState>((set, get) => {
|
|||||||
activeRegionId: null,
|
activeRegionId: null,
|
||||||
hybridAudioRegionId: null,
|
hybridAudioRegionId: null,
|
||||||
pianoRollMode: 'midi-edit',
|
pianoRollMode: 'midi-edit',
|
||||||
|
requestedSheetMusicViewEnabled: false,
|
||||||
|
pianoRollViewRequestVersion: 0,
|
||||||
activeTrackAutomationTrackId: null,
|
activeTrackAutomationTrackId: null,
|
||||||
activeTrackAutomationType: null,
|
activeTrackAutomationType: null,
|
||||||
trackAutomationRedrawVersion: 0,
|
trackAutomationRedrawVersion: 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user