import { ChevronDown, ChevronRight, GripVertical, Plus, Power, X } from "lucide-react" import { useEffect, useRef, useState } from "react" import { useTranslation } from "react-i18next" import { cn } from "@/lib/utils" import { Compressor } from "./compressor" import { Equalizer } from "./equalizer" import { Reverb } from "./reverb" export type EffectType = "equalizer" | "compressor" | "reverb" export interface Effect { id: string type: EffectType enabled: boolean expanded: boolean } interface EffectsRackProps { channelId: string onEffectAdd?: (effect: Effect) => void onEffectRemove?: (effectId: string) => void onEffectToggle?: (effectId: string, enabled: boolean) => void onEffectParameterChange?: (effectId: string, param: string, value: number) => void getCompressorGainReduction?: (effectId: string) => number className?: string } export function EffectsRack({ onEffectAdd, onEffectRemove, onEffectToggle, onEffectParameterChange, getCompressorGainReduction, className, }: EffectsRackProps) { const { t } = useTranslation() const [effects, setEffects] = useState([]) const [showAddMenu, setShowAddMenu] = useState(false) const [gainReductions, setGainReductions] = useState>({}) const animationFrameRef = useRef(null) const AVAILABLE_EFFECTS: { type: EffectType; label: string }[] = [ { type: "equalizer", label: t("fairlightAudio.effectsRack.effects.eq") }, { type: "compressor", label: t("fairlightAudio.effectsRack.effects.compressor") }, { type: "reverb", label: t("fairlightAudio.effectsRack.effects.reverb") }, ] const addEffect = (type: EffectType) => { const newEffect: Effect = { id: `${type}-${Date.now()}`, type, enabled: true, expanded: true, } setEffects([...effects, newEffect]) onEffectAdd?.(newEffect) setShowAddMenu(false) } const removeEffect = (effectId: string) => { setEffects(effects.filter((e) => e.id !== effectId)) onEffectRemove?.(effectId) } const toggleEffect = (effectId: string) => { setEffects(effects.map((e) => (e.id === effectId ? { ...e, enabled: !e.enabled } : e))) const effect = effects.find((e) => e.id === effectId) if (effect) { onEffectToggle?.(effectId, !effect.enabled) } } const toggleExpanded = (effectId: string) => { setEffects(effects.map((e) => (e.id === effectId ? { ...e, expanded: !e.expanded } : e))) } const renderEffect = (effect: Effect) => { const handleParameterChange = (param: string, value: number) => { onEffectParameterChange?.(effect.id, param, value) } const effectContent = () => { switch (effect.type) { case "equalizer": return ( { handleParameterChange(`band-${index}`, band.gain) }} /> ) case "compressor": return case "reverb": return default: return null } } return (
{/* Effect Header */}
{AVAILABLE_EFFECTS.find((e) => e.type === effect.type)?.label}
{/* Effect Content */} {effect.expanded && (
{effectContent()}
)}
) } // Update gain reduction values for compressors useEffect(() => { if (!getCompressorGainReduction) return const updateGainReduction = () => { const newGainReductions: Record = {} effects.forEach((effect) => { if (effect.type === "compressor" && effect.enabled) { newGainReductions[effect.id] = getCompressorGainReduction(effect.id) } }) setGainReductions(newGainReductions) animationFrameRef.current = requestAnimationFrame(updateGainReduction) } updateGainReduction() return () => { if (animationFrameRef.current) { cancelAnimationFrame(animationFrameRef.current) } } }, [effects, getCompressorGainReduction]) return (

{t("fairlightAudio.effectsRack.title")}

{showAddMenu && ( <>
setShowAddMenu(false)} />
{AVAILABLE_EFFECTS.map(({ type, label }) => ( ))}
)}
{/* Effects List */} {effects.length === 0 ? (
{t("fairlightAudio.effectsRack.noEffectsAdded")}
) : (
{effects.map(renderEffect)}
)}
) }