Skip to content

Commit e278421

Browse files
committed
Fix erros
1 parent f8c38ee commit e278421

12 files changed

Lines changed: 97 additions & 82 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
enable-cache: true
2222

2323
- name: Install dependencies
24-
run: uv sync --dev
24+
run: uv sync --all-extras
2525

2626
- name: Lint (ruff check)
2727
run: uv run ruff check src/ tests/
@@ -47,7 +47,7 @@ jobs:
4747
enable-cache: true
4848

4949
- name: Install dependencies
50-
run: uv sync --dev
50+
run: uv sync --all-extras
5151

5252
- name: Run tests with coverage
5353
run: uv run --with pytest --with pytest-cov pytest tests/ --cov=wavedriver --cov-report=term-missing --cov-fail-under=60

src/wavedriver/web/src/App.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ function AppInner() {
5151
shuffleDwellS, setShuffleDwellS,
5252
shuffleMinFreq, setShuffleMinFreq,
5353
shuffleMaxFreq, setShuffleMaxFreq,
54-
shuffleMinStroke, setShuffleMinStroke,
55-
shuffleMaxStroke, setShuffleMaxStroke,
54+
shuffleMinStroke,
55+
shuffleMaxStroke,
5656
} = useSettings({ apiReady, sendCommand, setHistoryEnabled });
5757

5858
const settingsRef = useRef({});

src/wavedriver/web/src/ErrorBoundary.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ export class ErrorBoundary extends React.Component {
2323
handleEstop = () => {
2424
try {
2525
window.pywebview?.api?.send_command("estop", { reason: "UI crashed — Emergency Stop" });
26-
} catch (_) {}
26+
} catch {
27+
// Ignore error
28+
}
2729
};
2830

2931
handleRetry = () => {

src/wavedriver/web/src/components/AdvancedDrawer.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export function AdvancedDrawer({
6767
shuffleMaxFreq, setShuffleMaxFreq,
6868
// History
6969
historyEnabled, onHistoryEnabledChange,
70-
sessionHistory, onClearHistory,
70+
onClearHistory,
7171
onToggleHistory, showHistory,
7272
// Activity log
7373
showActivityLog, onToggleActivityLog,

src/wavedriver/web/src/components/AudioSyncPanel.jsx

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import { useState, useEffect, useRef } from 'react';
1+
import { useState, useEffect, useRef, useCallback } from 'react';
22
import { Music, Mic } from 'lucide-react';
33

44
export function AudioSyncPanel({
55
isRunning,
66
intensityPct,
77
onIntensityChange,
8-
frequencyHz,
98
onFrequencyChange,
109
}) {
1110
const [isActive, setIsActive] = useState(false);
@@ -25,54 +24,64 @@ export function AudioSyncPanel({
2524
const lastBeatTime = useRef(0);
2625
const beatTimestamps = useRef([]);
2726

28-
const startAudioSync = async () => {
29-
try {
30-
// Clean up any existing instances first
31-
stopAudioSync();
32-
33-
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
34-
streamRef.current = stream;
35-
audioCtxRef.current = new (window.AudioContext || window.webkitAudioContext)();
36-
analyserRef.current = audioCtxRef.current.createAnalyser();
37-
analyserRef.current.fftSize = 256;
38-
39-
sourceRefNode.current = audioCtxRef.current.createMediaStreamSource(stream);
40-
sourceRefNode.current.connect(analyserRef.current);
41-
42-
setIsActive(true);
43-
} catch (err) {
44-
alert("Failed to access microphone: " + err.message);
45-
}
46-
};
47-
48-
const stopAudioSync = () => {
27+
const stopAudioSync = useCallback(() => {
4928
if (rafRef.current) {
5029
cancelAnimationFrame(rafRef.current);
5130
rafRef.current = null;
5231
}
5332
if (sourceRefNode.current) {
5433
try {
5534
sourceRefNode.current.disconnect();
56-
} catch {}
35+
} catch {
36+
// Silently ignore
37+
}
5738
sourceRefNode.current = null;
5839
}
5940
if (streamRef.current) {
6041
try {
6142
streamRef.current.getTracks().forEach(track => track.stop());
62-
} catch {}
43+
} catch {
44+
// Silently ignore
45+
}
6346
streamRef.current = null;
6447
}
6548
if (audioCtxRef.current && audioCtxRef.current.state !== 'closed') {
6649
try {
6750
audioCtxRef.current.close();
68-
} catch {}
51+
} catch {
52+
// Silently ignore
53+
}
6954
audioCtxRef.current = null;
7055
}
71-
setIsActive(false);
72-
setVolumeLevel(0);
73-
setDetectedBpm(null);
56+
setTimeout(() => {
57+
setIsActive(false);
58+
setVolumeLevel(0);
59+
setDetectedBpm(null);
60+
}, 0);
7461
beatTimestamps.current = [];
75-
};
62+
}, []);
63+
64+
const startAudioSync = useCallback(async () => {
65+
try {
66+
// Clean up any existing instances first
67+
stopAudioSync();
68+
69+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
70+
streamRef.current = stream;
71+
audioCtxRef.current = new (window.AudioContext || window.webkitAudioContext)();
72+
analyserRef.current = audioCtxRef.current.createAnalyser();
73+
analyserRef.current.fftSize = 256;
74+
75+
sourceRefNode.current = audioCtxRef.current.createMediaStreamSource(stream);
76+
sourceRefNode.current.connect(analyserRef.current);
77+
78+
setTimeout(() => {
79+
setIsActive(true);
80+
}, 0);
81+
} catch (err) {
82+
alert("Failed to access microphone: " + err.message);
83+
}
84+
}, [stopAudioSync]);
7685

7786
// Sync mic activity with global running state
7887
useEffect(() => {
@@ -84,7 +93,7 @@ export function AudioSyncPanel({
8493
return () => {
8594
stopAudioSync();
8695
};
87-
}, [isRunning]);
96+
}, [isRunning, startAudioSync, stopAudioSync]);
8897

8998
useEffect(() => {
9099
if (!isActive) return;

src/wavedriver/web/src/components/InteractiveEdging.jsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,31 @@ export function InteractiveEdging({ isRunning, intensityPct, onIntensityChange }
2828
setCooldownRemaining(prev => prev - 1);
2929
}, 1000);
3030
} else if (cooldownRemaining === 0 && edgingActive) {
31-
if (surpriseDenial && Math.random() < 0.5) {
32-
setDenied(true);
33-
onIntensityChange(0);
34-
setCooldownRemaining(5);
35-
setSurpriseDenial(false);
36-
return;
37-
}
31+
setTimeout(() => {
32+
if (surpriseDenial && Math.random() < 0.5) {
33+
setDenied(true);
34+
onIntensityChange(0);
35+
setCooldownRemaining(5);
36+
setSurpriseDenial(false);
37+
return;
38+
}
3839

39-
onIntensityChange(savedIntensity.current);
40-
setEdgingActive(false);
41-
setDenied(false);
40+
onIntensityChange(savedIntensity.current);
41+
setEdgingActive(false);
42+
setDenied(false);
43+
}, 0);
4244
}
4345

4446
return () => clearTimeout(timerRef.current);
4547
}, [cooldownRemaining, edgingActive, surpriseDenial, onIntensityChange]);
4648

4749
useEffect(() => {
4850
if (!isRunning) {
49-
setEdgingActive(false);
50-
setCooldownRemaining(0);
51-
setDenied(false);
51+
setTimeout(() => {
52+
setEdgingActive(false);
53+
setCooldownRemaining(0);
54+
setDenied(false);
55+
}, 0);
5256
}
5357
}, [isRunning]);
5458

src/wavedriver/web/src/components/InteractiveEdging.test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render, screen, fireEvent, act } from '@testing-library/react';
1+
import { render, screen, fireEvent } from '@testing-library/react';
22
import { describe, it, expect, vi, beforeEach } from 'vitest';
33
import { InteractiveEdging } from './InteractiveEdging';
44

src/wavedriver/web/src/components/SequenceBuilder.jsx

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useEffect, useRef } from 'react';
1+
import { useState, useEffect, useRef, useCallback } from 'react';
22
import { Layers, Plus, Trash2, Play, Square, FastForward, Clock } from 'lucide-react';
33

44
const PATTERNS = ["Wave", "Realistic", "Thrust", "Pulse", "Tease", "Escalate", "Edge", "Depth", "Adaptive"];
@@ -50,25 +50,7 @@ export function SequenceBuilder({
5050
executeStep(steps[0]);
5151
};
5252

53-
const stopSequence = () => {
54-
setIsSequencePlaying(false);
55-
setActiveStepIdx(null);
56-
setStepTimeRemaining(0);
57-
stopPattern();
58-
};
59-
60-
const nextStep = () => {
61-
const nextIdx = activeStepIdx + 1;
62-
if (nextIdx < steps.length) {
63-
setActiveStepIdx(nextIdx);
64-
setStepTimeRemaining(steps[nextIdx].duration);
65-
executeStep(steps[nextIdx]);
66-
} else {
67-
stopSequence();
68-
}
69-
};
70-
71-
const executeStep = (step) => {
53+
const executeStep = useCallback((step) => {
7254
// Set UI states so sliders align
7355
setPatternName(step.pattern);
7456
setFrequencyHz(step.freq);
@@ -82,7 +64,25 @@ export function SequenceBuilder({
8264
strokeLengthMm: step.stroke,
8365
intensityPct: step.intensity,
8466
});
85-
};
67+
}, [setPatternName, setFrequencyHz, setStrokeLengthMm, onIntensityChange, startPattern]);
68+
69+
const stopSequence = useCallback(() => {
70+
setIsSequencePlaying(false);
71+
setActiveStepIdx(null);
72+
setStepTimeRemaining(0);
73+
stopPattern();
74+
}, [stopPattern]);
75+
76+
const nextStep = useCallback(() => {
77+
const nextIdx = activeStepIdx + 1;
78+
if (nextIdx < steps.length) {
79+
setActiveStepIdx(nextIdx);
80+
setStepTimeRemaining(steps[nextIdx].duration);
81+
executeStep(steps[nextIdx]);
82+
} else {
83+
stopSequence();
84+
}
85+
}, [activeStepIdx, steps, executeStep, stopSequence]);
8686

8787
// Timer loop for sequence playback
8888
useEffect(() => {
@@ -92,14 +92,18 @@ export function SequenceBuilder({
9292
setStepTimeRemaining(prev => prev - 1);
9393
}, 1000);
9494
} else {
95-
nextStep();
95+
setTimeout(() => {
96+
nextStep();
97+
}, 0);
9698
}
9799
} else if (!isRunning && isSequencePlaying) {
98-
stopSequence();
100+
setTimeout(() => {
101+
stopSequence();
102+
}, 0);
99103
}
100104

101105
return () => clearTimeout(timerRef.current);
102-
}, [isSequencePlaying, activeStepIdx, stepTimeRemaining, isRunning]);
106+
}, [isSequencePlaying, activeStepIdx, stepTimeRemaining, isRunning, nextStep, stopSequence]);
103107

104108
return (
105109
<div className="control-card glass">

src/wavedriver/web/src/components/SliderPanel.jsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,8 @@ export function SliderPanel({
8585
shuffleDwellS, setShuffleDwellS,
8686
shuffleMinFreq, setShuffleMinFreq,
8787
shuffleMaxFreq, setShuffleMaxFreq,
88-
shuffleMinStroke, setShuffleMinStroke,
89-
shuffleMaxStroke, setShuffleMaxStroke,
9088
safetyForceN,
91-
maxSessionS, setMaxSessionS,
89+
maxSessionS,
9290
calibratedLength,
9391
onIntensityChange,
9492
onSafetyChange,

src/wavedriver/web/src/components/WaveformCanvas.test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render, act } from '@testing-library/react';
1+
import { render } from '@testing-library/react';
22
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
33
import { WaveformCanvas } from './WaveformCanvas';
44

0 commit comments

Comments
 (0)