forked from averyfelts/Lofi_Generator
work in progress implementation of: - mixer with channel strips, faders, pan knobs, level meters - timeline with ruler, playhead, sections, keyframe tracks - pattern and progression pickers for drums/chords - automation lanes and mute tracks - loop bracket for loop region selection - export modal placeholder known issues: - drum pattern changes don't update audio engine - timeline keyframes not connected to scheduler - some UI bugs remain this is a checkpoint commit for further iteration
79 lines
2.1 KiB
TypeScript
79 lines
2.1 KiB
TypeScript
'use client';
|
|
|
|
import { Drum, Music, Cloud, Volume2 } from 'lucide-react';
|
|
import { ChannelStrip } from './ChannelStrip';
|
|
import { LayerName, MeterLevels } from '@/types/audio';
|
|
|
|
interface MixerProps {
|
|
volumes: Record<LayerName | 'master', number>;
|
|
pans: Record<LayerName, number>;
|
|
muted: Record<LayerName, boolean>;
|
|
soloed: Record<LayerName, boolean>;
|
|
levels: MeterLevels;
|
|
onVolumeChange: (layer: LayerName | 'master', volume: number) => void;
|
|
onPanChange: (layer: LayerName, pan: number) => void;
|
|
onMuteToggle: (layer: LayerName) => void;
|
|
onSoloToggle: (layer: LayerName) => void;
|
|
}
|
|
|
|
const layerConfig: {
|
|
name: LayerName;
|
|
label: string;
|
|
icon: React.ReactNode;
|
|
}[] = [
|
|
{ name: 'drums', label: 'Drums', icon: <Drum className="h-3 w-3" /> },
|
|
{ name: 'chords', label: 'Chords', icon: <Music className="h-3 w-3" /> },
|
|
{ name: 'ambient', label: 'Ambient', icon: <Cloud className="h-3 w-3" /> },
|
|
];
|
|
|
|
export function Mixer({
|
|
volumes,
|
|
pans,
|
|
muted,
|
|
soloed,
|
|
levels,
|
|
onVolumeChange,
|
|
onPanChange,
|
|
onMuteToggle,
|
|
onSoloToggle,
|
|
}: MixerProps) {
|
|
return (
|
|
<div className="flex gap-2 overflow-x-auto pb-2">
|
|
{layerConfig.map(({ name, label, icon }) => (
|
|
<ChannelStrip
|
|
key={name}
|
|
name={label}
|
|
icon={icon}
|
|
volume={volumes[name]}
|
|
pan={pans[name]}
|
|
muted={muted[name]}
|
|
soloed={soloed[name]}
|
|
level={levels[name]}
|
|
onVolumeChange={(v) => onVolumeChange(name, v)}
|
|
onPanChange={(p) => onPanChange(name, p)}
|
|
onMuteToggle={() => onMuteToggle(name)}
|
|
onSoloToggle={() => onSoloToggle(name)}
|
|
/>
|
|
))}
|
|
|
|
<div className="w-px bg-border/50 mx-1" />
|
|
|
|
<ChannelStrip
|
|
name="Master"
|
|
icon={<Volume2 className="h-3 w-3" />}
|
|
volume={volumes.master}
|
|
pan={0}
|
|
muted={false}
|
|
soloed={false}
|
|
level={levels.master}
|
|
onVolumeChange={(v) => onVolumeChange('master', v)}
|
|
onPanChange={() => {}}
|
|
onMuteToggle={() => {}}
|
|
onSoloToggle={() => {}}
|
|
showPan={false}
|
|
showSolo={false}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|