Skip to content

Commit 762d78e

Browse files
committed
fix: cover native scrub and automation fallback
1 parent 29f9846 commit 762d78e

3 files changed

Lines changed: 25 additions & 2 deletions

File tree

src/hooks/__tests__/useTransport.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ vi.mock('../useToast', () => ({
130130
toastError: vi.fn(),
131131
}));
132132

133-
import { useTransport } from '../useTransport';
133+
import { canUseNativeClipPlayback, useTransport } from '../useTransport';
134134
import { useProjectStore } from '../../store/projectStore';
135135
import { useTransportStore } from '../../store/transportStore';
136136
import { useUIStore } from '../../store/uiStore';
@@ -198,6 +198,23 @@ describe('useTransport', () => {
198198
);
199199
});
200200

201+
it('disables native clip playback when automation lanes are active', () => {
202+
const project = useProjectStore.getState().project!;
203+
expect(canUseNativeClipPlayback(project, [])).toBe(true);
204+
205+
project.automationLanes = [{
206+
id: 'automation-1',
207+
trackId: 'track-1',
208+
parameter: { type: 'mixer', param: 'volume' },
209+
points: [
210+
{ time: 0, value: 0.25 },
211+
{ time: 1, value: 0.75 },
212+
],
213+
}];
214+
215+
expect(canUseNativeClipPlayback(project, [])).toBe(false);
216+
});
217+
201218
// ── pause() ──
202219

203220
it('stops all engines and strudel when pausing', async () => {

src/hooks/useTransport.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,10 @@ function trackNeedsWebAudio(track: Track): boolean {
115115
|| (track.sends?.some((send) => send.amount > 0.000001) ?? false);
116116
}
117117

118-
function canUseNativeClipPlayback(project: Project, entries: NativePlaybackEntry[]): boolean {
118+
export function canUseNativeClipPlayback(project: Project, entries: NativePlaybackEntry[]): boolean {
119119
if (project.mastering?.enabled) return false;
120120
if ((project.returnTracks?.length ?? 0) > 0) return false;
121+
if (project.automationLanes?.some((lane) => lane.points.length > 0)) return false;
121122
if (entries.some(clipNeedsWebAudio)) return false;
122123
return !project.tracks.some(trackNeedsWebAudio);
123124
}
@@ -922,6 +923,7 @@ export function useTransport() {
922923

923924
const startScrub = useCallback(async (time: number) => {
924925
const engine = getAudioEngine();
926+
const bridge = getAudioBridge(engine);
925927
const transport = useTransportStore.getState();
926928
const scrubProject = useProjectStore.getState().project;
927929
if (!scrubProject) return;
@@ -932,6 +934,8 @@ export function useTransport() {
932934
const resumePlayback = transport.isPlaying || engine.playing;
933935
if (resumePlayback) {
934936
engine.stop();
937+
setTauriPlaybackClockOwner('web-audio');
938+
bridge.stopAllSources();
935939
synthEngine.releaseAll();
936940
subtractiveEngine.releaseAll();
937941
wavetableEngine.releaseAll();

tests/unit/useTransportScrubLifecycle.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const engineMock = {
1616
startTimelineScrub: vi.fn().mockResolvedValue(undefined),
1717
updateTimelineScrub: vi.fn().mockResolvedValue(undefined),
1818
stopTimelineScrub: vi.fn(),
19+
stopAllSources: vi.fn(),
1920
stop: vi.fn(),
2021
getCurrentTime: vi.fn(() => 6.5),
2122
setOnEndedCallback: vi.fn(),
@@ -133,6 +134,7 @@ describe('useTransport scrub lifecycle', () => {
133134
});
134135

135136
expect(engineMock.stop).toHaveBeenCalledTimes(1);
137+
expect(engineMock.stopAllSources).toHaveBeenCalledTimes(1);
136138
expect(useTransportStore.getState().isPlaying).toBe(false);
137139
expect(useTransportStore.getState().isScrubbing).toBe(true);
138140
expect(engineMock.startTimelineScrub).toHaveBeenCalledWith(expect.any(Array), expect.any(Array), 4, 0);

0 commit comments

Comments
 (0)