# Feature: Lydmixer (Virtuelt studioverktøy) **Filsti:** `docs/features/lydmixer.md` ## 1. Konsept En nettleserbasert lydmixer inspirert av RødeCaster Pro II. Gir programledere og møtedeltakere kontroll over lydnivåer, lydeffekter og stemmeeffekter direkte i Synops — uten behov for ekstern maskinvare. Bygget på Web Audio API med LiveKit-integrasjon. Alle lydstrømmer (mikrofon, remote-deltakere, sound pads) rutes gjennom en Web Audio-graf som gir per-kanal prosessering før avspilling. ## 2. Brukeropplevelse 1. Brukeren åpner studioet/møterommet og kobler seg til LiveKit-rommet. 2. I bunnen av skjermen vises en **mixerstripe** med én kanal per deltaker. 3. Hver kanal har: volumslider, mute-knapp, og valgfri effektkjede. 4. Over mixeren ligger et **pad-brett** med konfigurerbare lydeffekter. 5. En **effektvelger** per kanal lar brukeren slå av/på stemmeeffekter (monster, robot) og lydbehandling (fat bottom, exciter, sparkle). ## 3. Kjernekomponenter ### 3.1 Kanalstripe (per deltaker) Hver LiveKit-deltaker får en dedikert kanalstripe i mixeren: | Element | Funksjon | Web Audio | |---|---|---| | **Volumslider** | Visuell fader 0–150% | `GainNode` (0.0–1.5) | | **Nød-mute** | Stor, rød knapp — umiddelbar demping | `gain.setValueAtTime(0, now)` | | **Nivåmeter** | VU-meter som viser live lydnivå | `AnalyserNode` → canvas | | **Navnelabel** | Deltakerens display_name | Fra LiveKit participant | ### 3.2 Effektkjede (per kanal, valgfri) Hver kanal kan ha en kjede av prosesseringsmoduler som slås av/på individuelt: | Effekt | Beskrivelse | Web Audio | |---|---|---| | **Fat bottom** | Lavfrekvent fylde (~200Hz, +6–12dB) | `BiquadFilterNode` lowshelf | | **Exciter** | Harmonisk tilstedeværelse (3–5kHz) | `WaveShaperNode` + highshelf | | **Sparkle** | Høyfrekvent luft (~10–16kHz, +3–6dB) | `BiquadFilterNode` highshelf | | **Monsterstemme** | Pitch ned 4–8 halvtoner | `AudioWorkletNode` (phase vocoder) | | **Robotstemme** | Metallisk ring-modulasjon | `OscillatorNode` → `GainNode.gain` | Signalflyt per kanal: ``` Kilde → HighPass(80Hz) → FatBottom → Exciter → Sparkle → RobotMod → PitchShift → GainNode(fader) → Master ``` ### 3.3 Sound Pads Et grid med konfigurerbare lyd-pads (inspirert av RødeCaster Pro II sine 8×8 pads): | Egenskap | Detalj | |---|---| | **Layout** | Grid, f.eks. 4×2 (utvidbart) | | **Avspilling** | Trykk → spill fra start til slutt | | **Lydkilde** | Forhåndslastede `AudioBuffer` fra CAS | | **Volum** | Egen `GainNode` per pad | | **Synkronisering** | LiveKit Data Message → alle klienter spiller samtidig | | **Konfigurasjon** | Velg lydfil, farge, label per pad | Eksempler på standard-pads: jingle/intro, applaus, latter, dramatisk pause, "breaking news"-sting, rim shot, sad trombone, airhorn. ### 3.4 Delt mixer-kontroll (flerbruker) Alle deltakere i rommet kan se og bruke mixeren samtidig. Mixer-state synkroniseres i sanntid via PG LISTEN/NOTIFY + WebSocket, slik at volumendringer, mutes, effekttogles og pad-avspilling reflekteres hos alle klienter umiddelbart. | Element | Synkronisering | |---|---| | **Volumslider** | PG: `mixer_channels`-tabell med `gain`-verdi per kanal | | **Mute** | PG: `is_muted` boolean per kanal | | **Effekt av/på** | PG: `active_effects` JSON per kanal | | **Pad-trigger** | LiveKit Data Message (lav latens) | | **Pad-konfig** | Node metadata (persistent, sjelden endring) | **Tilgangsnivåer:** - **Full kontroll** (default): alle deltakere kan justere alle kanaler, trigge pads og endre effekter. Tilsvarer at alle sitter rundt samme RødeCaster. - **Begrenset**: eier/admin kan låse enkeltdeltakere til kun "viewer" — de ser mixeren live men kan ikke interagere. Bruker eksisterende rolle-system (owner/admin/member-edges). **Konflikthåndtering:** Last-write-wins. Volumslidere er kontinuerlige verdier som oppdateres via maskinrommet. Ved samtidig endring av samme kanal vinner siste skriving — i praksis uproblematisk fordi endringer er visuelt synlige for alle og deltakerne koordinerer naturlig. **PG-tabell:** `mixer_channels` med NOTIFY-trigger for sanntidspropagering via WebSocket. **API-endepunkter (maskinrommet):** - `POST /intentions/create_mixer_channel` — idempotent opprettelse - `POST /intentions/set_gain` — clamped 0.0–1.5, viewer-sjekk - `POST /intentions/set_mute` — viewer-sjekk - `POST /intentions/toggle_effect` — JSON-toggle - `POST /intentions/set_mixer_role` — sett editor/viewer Mixer-kanaler ryddes automatisk ved `close_live_room` og `clear_all`. ### 3.5 Master-seksjon | Element | Funksjon | |---|---| | **Master fader** | Samlet utgangsnivå | | **Master mute** | Demper all lyd | | **Master VU** | Stereo nivåmeter for utgangen | ## 4. Teknisk arkitektur ### 4.1 Web Audio-graf ``` ┌─────────────────────────────────┐ │ AudioContext │ │ │ Remote Track 1 ──→ MediaStreamSource → EffektKjede → GainNode ─┐ Remote Track 2 ──→ MediaStreamSource → EffektKjede → GainNode ─┤ Lokal mikrofon ──→ MediaStreamSource → EffektKjede → GainNode ─┼→ MasterGain → destination Sound Pad ──→ AudioBufferSource ─────────────→ GainNode ─┘ │ │ └─────────────────────────────────┘ ``` ### 4.2 LiveKit-integrasjon - **Innkommende lyd:** Deaktiver LiveKit sin auto-attach av `