feat: add keep alive
This commit is contained in:
@ -3,13 +3,37 @@ 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 { useState } from 'react';
|
||||
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 DESIGN_WIDTH = 90;
|
||||
const DESIGN_HEIGHT = 380;
|
||||
const PANEL_DESIGN_WIDTH = 90;
|
||||
const PANEL_DESIGN_HEIGHT = 400;
|
||||
|
||||
function ChannelGroupScaled({ title, children }: { title: string; children: React.ReactNode }) {
|
||||
const wrapperRef = useRef<HTMLDivElement>(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 (
|
||||
<div ref={wrapperRef} style={{ height: '100%', '--panel-scale': scale } as React.CSSProperties}>
|
||||
<ChannelGroup title={title}>{children}</ChannelGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function GainPanel({
|
||||
dsp,
|
||||
@ -78,6 +102,8 @@ function GainPanel({
|
||||
|
||||
const [muted, setMuted] = useState(false);
|
||||
const [inverted, setInverted] = useState(false);
|
||||
const viewportRef = useRef<HTMLDivElement>(null);
|
||||
const [scale, setScale] = useState(1);
|
||||
|
||||
const toggleMute = async () => {
|
||||
const next = !muted;
|
||||
@ -91,9 +117,28 @@ function GainPanel({
|
||||
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 (
|
||||
<div className="gain-panel-frame">
|
||||
<div className="gain-panel" style={{ width: DESIGN_WIDTH, height: DESIGN_HEIGHT }}>
|
||||
<div className="gain-panel-viewport" ref={viewportRef}>
|
||||
<div
|
||||
className="gain-panel"
|
||||
style={{
|
||||
width: PANEL_DESIGN_WIDTH,
|
||||
height: PANEL_DESIGN_HEIGHT,
|
||||
transform: `translate(-50%, -50%) scale(${scale})`,
|
||||
}}
|
||||
>
|
||||
<div className="gain-panel__title">{title}</div>
|
||||
|
||||
<VerticalSlider
|
||||
@ -104,12 +149,12 @@ function GainPanel({
|
||||
switchStep={0.1}
|
||||
unit=" dB"
|
||||
onChange={setGain}
|
||||
style={{ width: 70, height: 260, flex: '0 0 auto' }} // pin to design size, disable its own auto-shrink
|
||||
/>
|
||||
|
||||
<Button variant="toggle" className={muted ? 'active-danger' : ''} onClick={toggleMute}>
|
||||
{muted ? 'Muted' : 'Mute'}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="toggle"
|
||||
className={inverted ? 'active-warning' : ''}
|
||||
@ -148,21 +193,48 @@ function GainSection({
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="gain-section">
|
||||
<div className="gain-panels">
|
||||
<ChannelGroup title="Input">
|
||||
{inputs.map(({ channel, title }) => (
|
||||
<GainPanel key={title} dsp={dsp} notify={notify} channel={channel} title={title} />
|
||||
))}
|
||||
</ChannelGroup>
|
||||
|
||||
<ChannelGroup title="Output">
|
||||
{outputs.map(({ channel, title }) => (
|
||||
<GainPanel key={title} dsp={dsp} notify={notify} channel={channel} title={title} />
|
||||
))}
|
||||
</ChannelGroup>
|
||||
<>
|
||||
<div className="linear-graph-section">
|
||||
<LinearGraph
|
||||
xMin={20}
|
||||
xMax={20000}
|
||||
yMin={-24}
|
||||
yMax={24}
|
||||
yStep={6}
|
||||
xLabel="Hz"
|
||||
yLabel="dB"
|
||||
draw={({ ctx, toPx }) => {
|
||||
// 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();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="gain-section">
|
||||
<div className="gain-panels">
|
||||
<ChannelGroup title="Input">
|
||||
{inputs.map(({ channel, title }) => (
|
||||
<GainPanel key={title} dsp={dsp} notify={notify} channel={channel} title={title} />
|
||||
))}
|
||||
</ChannelGroup>
|
||||
|
||||
<ChannelGroup title="Output">
|
||||
{outputs.map(({ channel, title }) => (
|
||||
<GainPanel key={title} dsp={dsp} notify={notify} channel={channel} title={title} />
|
||||
))}
|
||||
</ChannelGroup>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user