Files
bruitiste/src/components/EngineControls.tsx
2025-10-06 03:03:38 +02:00

80 lines
2.7 KiB
TypeScript

import { ENGINE_CONTROLS } from '../config/effects'
import { getComplexityLabel, getBitDepthLabel, getSampleRateLabel } from '../utils/formatters'
import type { EffectValues } from '../types/effects'
import { Knob } from './Knob'
interface EngineControlsProps {
values: EffectValues
onChange: (parameterId: string, value: number) => void
onMapClick?: (paramId: string, lfoIndex: number) => void
getMappedLFOs?: (paramId: string) => number[]
}
const KNOB_PARAMS = ['masterVolume', 'pitch', 'a', 'b', 'c', 'd']
export function EngineControls({ values, onChange, onMapClick, getMappedLFOs }: EngineControlsProps) {
const formatValue = (id: string, value: number): string => {
switch (id) {
case 'sampleRate':
return getSampleRateLabel(value)
case 'complexity':
return getComplexityLabel(value)
case 'bitDepth':
return getBitDepthLabel(value)
default: {
const param = ENGINE_CONTROLS[0].parameters.find(p => p.id === id)
return `${value}${param?.unit || ''}`
}
}
}
return (
<div className="flex items-center gap-6">
{ENGINE_CONTROLS[0].parameters.map(param => {
const useKnob = KNOB_PARAMS.includes(param.id)
if (useKnob) {
return (
<Knob
key={param.id}
label={param.label}
value={(values[param.id] as number) ?? param.default}
min={param.min as number}
max={param.max as number}
step={param.step as number}
unit={param.unit}
onChange={(value) => onChange(param.id, value)}
formatValue={formatValue}
valueId={param.id}
paramId={param.id}
onMapClick={onMapClick}
mappedLFOs={getMappedLFOs ? getMappedLFOs(param.id) : []}
/>
)
}
return (
<div key={param.id} className="flex flex-col gap-1 min-w-[100px]">
<div className="flex justify-between items-baseline">
<label className="font-mono text-[9px] tracking-[0.15em] text-white">
{param.label.toUpperCase()}
</label>
<span className="font-mono text-[9px] text-white">
{formatValue(param.id, (values[param.id] as number) ?? param.default)}
</span>
</div>
<input
type="range"
min={param.min}
max={param.max}
step={param.step}
value={(values[param.id] as number) ?? param.default}
onChange={(e) => onChange(param.id, Number(e.target.value))}
className="w-full h-[2px] bg-white appearance-none cursor-pointer"
/>
</div>
)
})}
</div>
)
}