import VerticalSlider from '../Slider/VerticalSlider'; import { invoke } from '@tauri-apps/api/core'; import { InputChannel, Channel, OutputChannel } from '../../../types/dsp408State'; import { DSP } from '../../../types/types'; import { NotificationType } from '../../../types/types'; import Button from '../../Button/Button'; import ChannelGroup from '../ChannelGroup/ChannelGroup'; import { LinearGraph } from '../LinearGraph/LinearGraph'; import { useEffect, useRef, useState } from 'react'; import './GainSection.css'; const PANEL_DESIGN_WIDTH = 90; const PANEL_DESIGN_HEIGHT = 400; function ChannelGroupScaled({ title, children }: { title: string; children: React.ReactNode }) { const wrapperRef = useRef(null); const [scale, setScale] = useState(1); useEffect(() => { const el = wrapperRef.current; if (!el) return; const observer = new ResizeObserver((entries) => { const { height } = entries[0].contentRect; if (height === 0) return; setScale(height / PANEL_DESIGN_HEIGHT); // height is the only free axis here }); observer.observe(el); return () => observer.disconnect(); }, []); return (
{children}
); } function GainPanel({ dsp, notify, channel, title, }: { dsp: DSP; notify: (message: string, type?: NotificationType, dspName?: string) => void; channel: Channel; title: string; }) { const setGain = async (value: number) => { try { const success = await invoke('set_channel_gain', { id: dsp.id, channel, db: value, }); if (success) { notify(`Input A gain set to ${value} dB`, 'success', dsp.name); } else { notify('Failed to set input gain', 'error', dsp.name); } } catch (err) { notify(`Gain update failed: ${String(err)}`, 'error', dsp.name); } }; const setMute = async (muted: boolean) => { try { const success = await invoke('set_mute', { id: dsp.id, channel, muted, }); if (success) { notify(`Input A ${muted ? 'muted' : 'unmuted'}`, 'success', dsp.name); } else { notify('Failed to change mute state', 'error', dsp.name); } } catch (err) { notify(`Mute update failed: ${String(err)}`, 'error', dsp.name); } }; const setInverse = async (inverted: boolean) => { try { const success = await invoke('set_channel_inverse_gain', { id: dsp.id, channel, inverted, }); if (success) { notify(`Input A phase ${inverted ? 'inverted' : 'normal'}`, 'success', dsp.name); } else { notify('Failed to change phase', 'error', dsp.name); } } catch (err) { notify(`Phase update failed: ${String(err)}`, 'error', dsp.name); } }; const [muted, setMuted] = useState(false); const [inverted, setInverted] = useState(false); const viewportRef = useRef(null); const [scale, setScale] = useState(1); const toggleMute = async () => { const next = !muted; setMuted(next); await setMute(next); }; const toggleInverse = async () => { const next = !inverted; setInverted(next); await setInverse(next); }; useEffect(() => { const el = viewportRef.current; if (!el) return; const observer = new ResizeObserver((entries) => { const { width, height } = entries[0].contentRect; if (width === 0 || height === 0) return; setScale(Math.min(width / PANEL_DESIGN_WIDTH, height / PANEL_DESIGN_HEIGHT)); }); observer.observe(el); return () => observer.disconnect(); }, []); return (
{title}
); } function GainSection({ dsp, notify, }: { dsp: DSP; notify: (message: string, type?: NotificationType, dspName?: string) => void; }) { const inputs: { channel: Channel; title: string }[] = [ { channel: { Input: InputChannel.InA }, title: 'In A' }, { channel: { Input: InputChannel.InB }, title: 'In B' }, { channel: { Input: InputChannel.InC }, title: 'In C' }, { channel: { Input: InputChannel.InD }, title: 'In D' }, ]; const outputs: { channel: Channel; title: string }[] = [ { channel: { Output: OutputChannel.Out1 }, title: 'Out 1' }, { channel: { Output: OutputChannel.Out2 }, title: 'Out 2' }, { channel: { Output: OutputChannel.Out3 }, title: 'Out 3' }, { channel: { Output: OutputChannel.Out4 }, title: 'Out 4' }, { channel: { Output: OutputChannel.Out5 }, title: 'Out 5' }, { channel: { Output: OutputChannel.Out6 }, title: 'Out 6' }, { channel: { Output: OutputChannel.Out7 }, title: 'Out 7' }, { channel: { Output: OutputChannel.Out8 }, title: 'Out 8' }, ]; return ( <>
{ // placeholder flat 0 dB response — swap for real EQ/filter data. // NOTE: this maps x linearly; for a real frequency response you'll // likely want a log-frequency x-axis instead (see chat notes). ctx.strokeStyle = '#4ade80'; ctx.lineWidth = 2; const [x0, y0] = toPx(20, 0); const [x1, y1] = toPx(20000, 0); ctx.beginPath(); ctx.moveTo(x0, y0); ctx.lineTo(x1, y1); ctx.stroke(); }} />
{inputs.map(({ channel, title }) => ( ))} {outputs.map(({ channel, title }) => ( ))}
); } export default GainSection;