import React from 'react'; import { useAudio } from './AudioContext'; import { Slider } from '../Slider/Slider'; import { Stack } from '../Stack/Stack'; import { Text } from '../Text/Text'; import { Card } from '../Card/Card'; import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '../Accordion/Accordion'; import { Checkbox } from '../Checkbox/Checkbox'; const EQSection: React.FC = () => { const { eqBands, setEqBands } = useAudio(); const handleGainChange = (index: number, newGain: number) => { setEqBands(currentBands => currentBands.map((band, i) => i === index ? { ...band, gain: newGain } : band) ); }; return ( {eqBands.map((band, index) => ( {band.label || `${band.freq} Hz`} handleGainChange(index, gain)} min={-12} max={12} step={1} showValue /> ))} ); }; interface ParamConfig { key: string; label: string; min: number; max: number; step: number; } const EffectSection: React.FC<{ effectName: string; paramsConfig: ParamConfig[] }> = ({ effectName, paramsConfig }) => { const { effectsState, setEffectsState } = useAudio(); const effect = effectsState[effectName]; if (!effect) return null; const handleToggle = (e: React.ChangeEvent) => { setEffectsState(prev => ({ ...prev, [effectName]: { ...prev[effectName], enabled: e.target.checked } })); }; const handleOptionChange = (optionKey: string, value: number) => { setEffectsState(prev => ({ ...prev, [effectName]: { ...prev[effectName], options: { ...prev[effectName].options, [optionKey]: value } } })); }; return ( e.stopPropagation()} /> {effect.enabled && paramsConfig.map(param => ( {param.label} ({effect.options[param.key]}) handleOptionChange(param.key, val)} min={param.min} max={param.max} step={param.step} showValue /> ))} ); }; const CurveSmartEQSection: React.FC = () => { const { effectsState, setEffectsState } = useAudio(); const effect = effectsState.curveSmartEQ; if (!effect) return null; const handleToggle = (e: React.ChangeEvent) => { setEffectsState(prev => ({ ...prev, curveSmartEQ: { ...prev.curveSmartEQ, enabled: e.target.checked } })); }; const handleGainChange = (index: number, newGain: number) => { setEffectsState(prev => { const newCurvePoints = [...prev.curveSmartEQ.options.curvePoints]; newCurvePoints[index] = { ...newCurvePoints[index], g: newGain }; return { ...prev, curveSmartEQ: { ...prev.curveSmartEQ, options: { ...prev.curveSmartEQ.options, curvePoints: newCurvePoints, }, }, }; }); }; return ( e.stopPropagation()} /> {effect.enabled && effect.options.curvePoints.map((point: {f: number, g: number}, index: number) => ( {point.f} Hz Gain ({point.g}dB) handleGainChange(index, gain)} min={-12} max={12} step={1} showValue /> ))} ); }; const effectParams: Record = { bassBoost: [ { key: 'gain', label: 'Gain (dB)', min: 0, max: 24, step: 1 }, { key: 'frequency', label: 'Frequency (Hz)', min: 20, max: 400, step: 10 }, ], chorus: [ { key: 'rate', label: 'Rate (Hz)', min: 0.1, max: 8, step: 0.1 }, { key: 'depth', label: 'Depth', min: 0.001, max: 0.01, step: 0.001 }, { key: 'mix', label: 'Mix', min: 0, max: 1, step: 0.05 }, ], compressor: [ { key: 'threshold', label: 'Threshold (dB)', min: -60, max: 0, step: 1 }, { key: 'ratio', label: 'Ratio', min: 1, max: 20, step: 1 }, { key: 'attack', label: 'Attack (s)', min: 0.001, max: 0.1, step: 0.001 }, { key: 'release', label: 'Release (s)', min: 0.01, max: 1, step: 0.01 }, ], delay: [ { key: 'delayTime', label: 'Time (s)', min: 0, max: 1, step: 0.05 }, { key: 'feedback', label: 'Feedback', min: 0, max: 0.9, step: 0.05 }, { key: 'mix', label: 'Mix', min: 0, max: 1, step: 0.05 }, ], phaser: [ { key: 'rate', label: 'Rate (Hz)', min: 0.1, max: 5, step: 0.1 }, { key: 'depth', label: 'Depth', min: 0, max: 1, step: 0.1 }, { key: 'feedback', label: 'Feedback', min: 0, max: 0.9, step: 0.05 }, { key: 'mix', label: 'Mix', min: 0, max: 1, step: 0.05 }, ], reverb: [ { key: 'roomSize', label: 'Room Size', min: 0, max: 1, step: 0.05 }, { key: 'damping', label: 'Damping', min: 0, max: 1, step: 0.05 }, { key: 'mix', label: 'Mix', min: 0, max: 1, step: 0.05 }, ], pitchShifter: [ { key: 'shift', label: 'Shift (semitones)', min: -20, max: 20, step: 1 }, ], eqJs: [ { key: 'lowGain', label: 'Low Gain', min: 0, max: 2, step: 0.1 }, { key: 'midGain', label: 'Mid Gain', min: 0, max: 2, step: 0.1 }, { key: 'highGain', label: 'High Gain', min: 0, max: 2, step: 0.1 }, ], hq: [ { key: 'clarity', label: 'Clarity', min: 0, max: 1, step: 0.05 }, ], }; export const AudioEffectsPanel: React.FC = () => { const { isGraphReady } = useAudio(); if (!isGraphReady) { return Play audio to enable effects panel.; } return ( Equalizer (Native) {Object.entries(effectParams).map(([key, params]) => { const title = key.charAt(0).toUpperCase() + key.slice(1).replace(/([A-Z])/g, ' $1').replace('Js', ' (JS)'); return ( {title} ) })} Curve Smart EQ ); };