62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
import { useStore } from '@nanostores/react'
|
|
import { lfoSettings } from '../stores/settings'
|
|
import { toggleMappingMode } from '../stores/mappingMode'
|
|
import { LFOScope } from './LFOScope'
|
|
import type { LFOConfig } from '../stores/settings'
|
|
import type { LFOWaveform } from '../domain/modulation/LFO'
|
|
|
|
interface LFOPanelProps {
|
|
onChange: (lfoIndex: number, config: LFOConfig) => void
|
|
onUpdateDepth: (lfoIndex: number, paramId: string, depth: number) => void
|
|
onRemoveMapping: (lfoIndex: number, paramId: string) => void
|
|
}
|
|
|
|
type LFOKey = 'lfo1' | 'lfo2' | 'lfo3' | 'lfo4'
|
|
|
|
export function LFOPanel({ onChange, onUpdateDepth, onRemoveMapping }: LFOPanelProps) {
|
|
const lfoValues = useStore(lfoSettings)
|
|
|
|
const handleLFOChange = (lfoKey: LFOKey, lfoIndex: number, frequency: number, phase: number, waveform: LFOWaveform) => {
|
|
const lfo = lfoValues[lfoKey]
|
|
const updated = { ...lfo, frequency, phase, waveform }
|
|
lfoSettings.setKey(lfoKey, updated)
|
|
onChange(lfoIndex, updated)
|
|
}
|
|
|
|
const handleMapClick = (_lfoKey: LFOKey, lfoIndex: number) => {
|
|
toggleMappingMode(lfoIndex)
|
|
}
|
|
|
|
const lfoConfigs: Array<{ key: LFOKey; index: number }> = [
|
|
{ key: 'lfo1', index: 0 },
|
|
{ key: 'lfo2', index: 1 },
|
|
{ key: 'lfo3', index: 2 },
|
|
{ key: 'lfo4', index: 3 }
|
|
]
|
|
|
|
return (
|
|
<div className="bg-black border-t-2 border-white">
|
|
<div className="grid grid-cols-2 sm:grid-cols-4 gap-[1px] bg-white p-[1px]">
|
|
{lfoConfigs.map(({ key, index }) => {
|
|
const lfo = lfoValues[key]
|
|
return (
|
|
<div key={key} className="px-2 py-2 flex items-center bg-black">
|
|
<LFOScope
|
|
lfoIndex={index}
|
|
waveform={lfo.waveform}
|
|
frequency={lfo.frequency}
|
|
phase={lfo.phase}
|
|
mappings={lfo.mappings}
|
|
onChange={(freq, phase, waveform) => handleLFOChange(key, index, freq, phase, waveform)}
|
|
onMapClick={() => handleMapClick(key, index)}
|
|
onUpdateDepth={(paramId, depth) => onUpdateDepth(index, paramId, depth)}
|
|
onRemoveMapping={(paramId) => onRemoveMapping(index, paramId)}
|
|
/>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|