2 FAMILY_LABELS,
3 SIGMA_STOPS,
4 TAP_STOPS,
5 WIDTH_STOPS,
6 frequencyStops,
7 maxCutoffHz,
8 nearestStop,
9 type FilterFamily,
10 type FilterSpec,
11} from '../model/filters'
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 12
13export interface ControlsProps {
14 sigma: number
15 setSigma: (v: number) => void
16 sampleRateHz: number
17 setSampleRateHz: (v: number) => void
18 spec: FilterSpec
19 setSpec: (v: FilterSpec) => void
20}
22function formatHz(hz: number): string {
fb1a12fSnap every parameter slider to a ladder of round valuesJeremy Magland 23 return hz >= 1000 ? `${+(hz / 1000).toFixed(1)} kHz` : `${hz} Hz`
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 24}
fb1a12fSnap every parameter slider to a ladder of round valuesJeremy Magland 26/** A slider that moves between the given values rather than a continuum. */
27function StopSlider(props: {
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 28 label: string
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 30 value: number
fb1a12fSnap every parameter slider to a ladder of round valuesJeremy Magland 31 format: (v: number) => string
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 32 onChange: (v: number) => void
33}) {
fb1a12fSnap every parameter slider to a ladder of round valuesJeremy Magland 34 const { stops } = props
35 const snapped = nearestStop(stops, props.value)
36 const index = stops.indexOf(snapped)
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 37 return (
38 <div className="control">
39 <label>
fb1a12fSnap every parameter slider to a ladder of round valuesJeremy Magland 40 {props.label} <span className="value">{props.format(snapped)}</span>
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 41 </label>
42 <input
43 type="range"
45 max={stops.length - 1}
46 step={1}
47 value={index}
48 onChange={e => props.onChange(stops[Number(e.target.value)])}
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 49 />
50 </div>
51 )
52}
54export default function Controls(p: ControlsProps) {
55 const { spec } = p
fb1a12fSnap every parameter slider to a ladder of round valuesJeremy Magland 56 const freqStops = frequencyStops(maxCutoffHz(p.sampleRateHz))
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 57 const sinc = spec.family === 'lowpass' || spec.family === 'bandpass'
58 return (
59 <div className="controls">
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 61 label="σ (quantization steps)"
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 63 value={p.sigma}
fb1a12fSnap every parameter slider to a ladder of round valuesJeremy Magland 64 format={v => String(v)}
65 onChange={p.setSigma}
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 66 />
67 <div className="control">
68 <label>filter</label>
69 <select
70 value={spec.family}
71 onChange={e => p.setSpec({ ...spec, family: e.target.value as FilterFamily })}
72 >
73 {(Object.keys(FAMILY_LABELS) as FilterFamily[]).map(f => (
74 <option key={f} value={f}>
75 {FAMILY_LABELS[f]}
76 </option>
77 ))}
78 </select>
79 </div>
80 {spec.family === 'bandpass' && (
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 82 label="low cutoff"
fb1a12fSnap every parameter slider to a ladder of round valuesJeremy Magland 83 stops={freqStops.filter(f => f < spec.highHz)}
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 84 value={spec.lowHz}
86 onChange={v => p.setSpec({ ...spec, lowHz: v })}
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 87 />
88 )}
89 {sinc && (
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 91 label={spec.family === 'bandpass' ? 'high cutoff' : 'cutoff'}
fb1a12fSnap every parameter slider to a ladder of round valuesJeremy Magland 92 stops={spec.family === 'bandpass' ? freqStops.filter(f => f > spec.lowHz) : freqStops}
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 93 value={spec.highHz}
95 onChange={v => p.setSpec({ ...spec, highHz: v })}
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 96 />
97 )}
98 {sinc && (
100 label="kernel length"
101 stops={TAP_STOPS}
102 value={spec.taps}
103 format={v => `${v} taps`}
104 onChange={v => p.setSpec({ ...spec, taps: v })}
105 />
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 106 )}
107 {spec.family === 'movingAverage' && (
109 label="width"
110 stops={WIDTH_STOPS}
111 value={spec.width}
112 format={v => `${v} samples`}
113 onChange={v => p.setSpec({ ...spec, width: v })}
114 />
36e8ceaInteractive explorer for compressibility of quantized filtered Gaussian time seriesJeremy Magland 115 )}
116 <div className="control">
117 <label>sample rate</label>
118 <select value={p.sampleRateHz} onChange={e => p.setSampleRateHz(Number(e.target.value))}>
119 {[1000, 8000, 16000, 30000, 44100, 96000].map(r => (
120 <option key={r} value={r}>
121 {formatHz(r)}
122 </option>
123 ))}
124 </select>
125 </div>
126 </div>
127 )
128}