import {
FAMILY_LABELS,
SIGMA_STOPS,
TAP_STOPS,
WIDTH_STOPS,
frequencyStops,
maxCutoffHz,
nearestStop,
type FilterFamily,
type FilterSpec,
} from '../model/filters'
export interface ControlsProps {
sigma: number
setSigma: (v: number) => void
sampleRateHz: number
setSampleRateHz: (v: number) => void
spec: FilterSpec
setSpec: (v: FilterSpec) => void
}
function formatHz(hz: number): string {
return hz >= 1000 ? `${+(hz / 1000).toFixed(1)} kHz` : `${hz} Hz`
}
/** A slider that moves between the given values rather than a continuum. */
function StopSlider(props: {
label: string
stops: number[]
value: number
format: (v: number) => string
onChange: (v: number) => void
}) {
const { stops } = props
const snapped = nearestStop(stops, props.value)
const index = stops.indexOf(snapped)
return (
props.onChange(stops[Number(e.target.value)])}
/>
)
}
export default function Controls(p: ControlsProps) {
const { spec } = p
const freqStops = frequencyStops(maxCutoffHz(p.sampleRateHz))
const sinc = spec.family === 'lowpass' || spec.family === 'bandpass'
return (
String(v)}
onChange={p.setSigma}
/>
{spec.family === 'bandpass' && (
f < spec.highHz)}
value={spec.lowHz}
format={formatHz}
onChange={v => p.setSpec({ ...spec, lowHz: v })}
/>
)}
{sinc && (
f > spec.lowHz) : freqStops}
value={spec.highHz}
format={formatHz}
onChange={v => p.setSpec({ ...spec, highHz: v })}
/>
)}
{sinc && (
`${v} taps`}
onChange={v => p.setSpec({ ...spec, taps: v })}
/>
)}
{spec.family === 'movingAverage' && (
`${v} samples`}
onChange={v => p.setSpec({ ...spec, width: v })}
/>
)}
)
}