port over astra scope fixes

This commit is contained in:
Boof2015
2026-03-28 00:41:49 -04:00
parent f065a75912
commit fd9eb3da18
17 changed files with 944 additions and 399 deletions
+13 -5
View File
@@ -9,11 +9,13 @@ import { Spectrogram, type SpectrogramDataSource } from '../visualizers/Spectrog
import { VUMeter, type VUMeterDataSource } from '../visualizers/VUMeter'
import { LUFSMeter, type LUFSMeterDataSource } from '../visualizers/LUFSMeter'
import { Waveform, type WaveformDataSource } from '../visualizers/Waveform'
import type { FrameScheduler } from '../visualizers/frameScheduler'
interface ScopeModuleProps {
scopeKind: ScopeKind
lineColor?: string
settings?: ScopeSettings[ScopeKind]
frameScheduler?: FrameScheduler
dataSource?:
| SpectrumAnalyzerDataSource
| OscilloscopeDataSource
@@ -90,9 +92,10 @@ function createVisualizer(
canvas: HTMLCanvasElement,
mySettings: ScopeSettings[ScopeKind],
lineColor: string,
frameScheduler?: FrameScheduler,
dataSource?: ScopeModuleProps['dataSource'],
): Visualizer | null {
const opts = scopeSettingsToOptions(scopeKind, mySettings, lineColor)
const opts = { ...scopeSettingsToOptions(scopeKind, mySettings, lineColor), frameScheduler }
switch (scopeKind) {
case 'spectrum':
return new SpectrumAnalyzer(canvas, {
@@ -138,6 +141,7 @@ export default function ScopeModule({
scopeKind,
lineColor = '#38bdf8',
settings,
frameScheduler,
dataSource,
}: ScopeModuleProps): JSX.Element {
const containerRef = useRef<HTMLDivElement>(null)
@@ -154,7 +158,7 @@ export default function ScopeModule({
if (!canvas) return
initializedRef.current = false
const viz = createVisualizer(scopeKind, canvas, mySettings, lineColor, dataSource)
const viz = createVisualizer(scopeKind, canvas, mySettings, lineColor, frameScheduler, dataSource)
if (!viz) return
visualizerRef.current = viz
@@ -168,14 +172,18 @@ export default function ScopeModule({
visualizerRef.current = null
initializedRef.current = false
}
}, [dataSource, scopeKind])
}, [dataSource, frameScheduler, scopeKind])
// Push settings + lineColor changes to live visualizer (skip initial — constructor already handled it)
useEffect(() => {
if (!visualizerRef.current || !initializedRef.current) return
const opts = { ...scopeSettingsToOptions(scopeKind, mySettings, lineColor), ...(dataSource ? { dataSource } : {}) }
const opts = {
...scopeSettingsToOptions(scopeKind, mySettings, lineColor),
frameScheduler,
...(dataSource ? { dataSource } : {}),
}
visualizerRef.current.setOptions(opts)
}, [dataSource, lineColor, mySettings, scopeKind])
}, [dataSource, frameScheduler, lineColor, mySettings, scopeKind])
// ResizeObserver for DPI-aware canvas sizing
useEffect(() => {
+28 -2
View File
@@ -65,6 +65,7 @@ export default function ScopePopoutBridge(): null {
[hiddenScopes, scopePopouts],
)
const activePopoutKindsRef = useRef<ScopeKind[]>(activePopoutKinds)
const sessionStateRef = useRef(audioRouter.getSessionState())
useEffect(() => {
activePopoutKindsRef.current = activePopoutKinds
@@ -155,23 +156,48 @@ export default function ScopePopoutBridge(): null {
let frameId = 0
const flushFrame = (): void => {
frameId = 0
if (!sessionStateRef.current.capturing || activePopoutKindsRef.current.length === 0) {
return
}
for (const kind of activePopoutKindsRef.current) {
const batch = flushScopeAudioBatch(kind)
if (batch.length > 0) {
window.electronAPI.sendScopePopoutAudio(kind, batch)
}
}
frameId = window.requestAnimationFrame(flushFrame)
}
if (activePopoutKinds.length > 0) {
frameId = window.requestAnimationFrame(flushFrame)
const syncFlushLoop = (): void => {
const shouldRun = sessionStateRef.current.capturing && activePopoutKindsRef.current.length > 0
if (!shouldRun) {
if (frameId) {
window.cancelAnimationFrame(frameId)
frameId = 0
}
return
}
if (!frameId) {
frameId = window.requestAnimationFrame(flushFrame)
}
}
sessionStateRef.current = audioRouter.getSessionState()
const unsubscribeSession = audioRouter.subscribeToSessionChanges((state) => {
sessionStateRef.current = state
syncFlushLoop()
})
syncFlushLoop()
return () => {
if (frameId) {
window.cancelAnimationFrame(frameId)
}
unsubscribeSession()
}
}, [activePopoutKinds])
+3
View File
@@ -6,6 +6,7 @@ import type { WindowBounds } from '../../types/popout'
import ScopeModule from './ScopeModule'
import { buildAnalyzerGridTemplateColumns } from '../analyzerLayout'
import { audioRouter } from '../audio/AudioRouter'
import { FrameScheduler } from '../visualizers/frameScheduler'
export default function Strip(): JSX.Element {
const scopeOrder = useSettingsStore((s) => s.scopeOrder)
@@ -15,6 +16,7 @@ export default function Strip(): JSX.Element {
const setScopeWidthWeight = useSettingsStore((s) => s.setScopeWidthWeight)
const popOutScope = useSettingsStore((s) => s.popOutScope)
const accent = useThemeStore((s) => s.accent)
const frameScheduler = useMemo(() => new FrameScheduler(), [])
const stripRef = useRef<HTMLDivElement>(null)
const gridRef = useRef<HTMLDivElement>(null)
const scopeRefs = useRef<Partial<Record<ScopeKind, HTMLDivElement | null>>>({})
@@ -214,6 +216,7 @@ export default function Strip(): JSX.Element {
<ScopeModule
scopeKind={kind}
lineColor={accent}
frameScheduler={frameScheduler}
/>
</div>
))}