diff --git a/CLAUDE.md b/CLAUDE.md
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1 +1,5 @@
 Read `AGENTS.md`: it is the entry point for agents in this repo.
+
+New workspace crates must include `[lints] workspace = true` in `Cargo.toml` to inherit
+`[workspace.lints]`. Production crate roots must declare the required crate-level lint attributes
+before modules or other crate items; crate-level `//!` documentation may precede them.
diff --git a/Cargo.toml b/Cargo.toml
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -65,9 +65,11 @@ image = { version = "0.25", default-features = false, features = ["png"] }
 unsafe_code = "forbid"
 
 [workspace.lints.clippy]
+cognitive_complexity = "deny"
+wildcard_imports = "deny"
 dbg_macro = "warn"
 todo = "warn"
-too_many_arguments = "allow"
+too_many_arguments = "deny"
 type_complexity = "allow"
 
 [profile.dev.package."*"]
diff --git a/clippy.toml b/clippy.toml
--- a/clippy.toml
+++ b/clippy.toml
@@ -6,3 +6,4 @@ allow-indexing-slicing-in-tests = true
 disallowed-types = [
     { path = "egui::ComboBox", reason = "use craft_ui::ComboBox: egui's combo box menu can't grow back while open (egui#5225)" },
 ]
+cognitive-complexity-threshold = 30
diff --git a/crates/au-host/Cargo.toml b/crates/au-host/Cargo.toml
--- a/crates/au-host/Cargo.toml
+++ b/crates/au-host/Cargo.toml
@@ -20,7 +20,9 @@ log.workspace = true
 unsafe_code = "deny"
 
 [lints.clippy]
+cognitive_complexity = "deny"
+wildcard_imports = "deny"
 dbg_macro = "warn"
 todo = "warn"
-too_many_arguments = "allow"
+too_many_arguments = "deny"
 type_complexity = "allow"
diff --git a/crates/clap-host/Cargo.toml b/crates/clap-host/Cargo.toml
--- a/crates/clap-host/Cargo.toml
+++ b/crates/clap-host/Cargo.toml
@@ -32,7 +32,9 @@ libloading = "0.9"
 unsafe_code = "deny"
 
 [lints.clippy]
+cognitive_complexity = "deny"
+wildcard_imports = "deny"
 dbg_macro = "warn"
 todo = "warn"
-too_many_arguments = "allow"
+too_many_arguments = "deny"
 type_complexity = "allow"
diff --git a/crates/clap-host/src/ffi.rs b/crates/clap-host/src/ffi.rs
--- a/crates/clap-host/src/ffi.rs
+++ b/crates/clap-host/src/ffi.rs
@@ -54,7 +54,7 @@ pub(crate) use events::Event;
 #[cfg(test)]
 use events::transport_event;
 pub(crate) use gui::GuiLink;
-pub(crate) use instance::{Instance, NotePort, PortBuffers, PortInfo, RawParam};
+pub(crate) use instance::{Instance, NotePort, PortBuffers, PortInfo, ProcessInput, RawParam};
 
 /// Most plugins one factory may report (hostile-input cap).
 const MAX_PLUGINS_PER_FACTORY: u32 = 1024;
diff --git a/crates/clap-host/src/ffi/bundle.rs b/crates/clap-host/src/ffi/bundle.rs
--- a/crates/clap-host/src/ffi/bundle.rs
+++ b/crates/clap-host/src/ffi/bundle.rs
@@ -1,7 +1,12 @@
 use super::gui::{GuiInner, GuiLink};
 use super::host::{HostState, host_get_extension, host_request_callback, host_request_process, host_request_restart};
 use super::instance::Instance;
-use super::*;
+use super::{
+    Arc, CLAP_EXT_AUDIO_PORTS, CLAP_EXT_GUI, CLAP_EXT_LATENCY, CLAP_EXT_NOTE_PORTS, CLAP_EXT_PARAMS, CLAP_EXT_STATE, CLAP_PLUGIN_FACTORY_ID,
+    CLAP_VERSION, CString, ClapError, EVENT_CAP, HashMap, MAX_FEATURES, MAX_PLUGINS_PER_FACTORY, Mutex, OnceLock, Path, PathBuf, PoisonError, c_void,
+    clap_host, clap_plugin_audio_ports, clap_plugin_entry, clap_plugin_factory, clap_plugin_gui, clap_plugin_latency, clap_plugin_note_ports,
+    clap_plugin_params, clap_plugin_state, clap_version_is_compatible, read_cstr, scan,
+};
 
 // ---- loaded binaries -----------------------------------------------------------------------
 
diff --git a/crates/clap-host/src/ffi/events.rs b/crates/clap-host/src/ffi/events.rs
--- a/crates/clap-host/src/ffi/events.rs
+++ b/crates/clap-host/src/ffi/events.rs
@@ -1,4 +1,10 @@
-use super::*;
+use super::{
+    CLAP_BEATTIME_FACTOR, CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_MIDI, CLAP_EVENT_NOTE_OFF, CLAP_EVENT_NOTE_ON, CLAP_EVENT_PARAM_VALUE,
+    CLAP_EVENT_TRANSPORT, CLAP_SECTIME_FACTOR, CLAP_TRANSPORT_HAS_BEATS_TIMELINE, CLAP_TRANSPORT_HAS_SECONDS_TIMELINE, CLAP_TRANSPORT_HAS_TEMPO,
+    CLAP_TRANSPORT_HAS_TIME_SIGNATURE, CLAP_TRANSPORT_IS_PLAYING, CLAP_TRANSPORT_IS_RECORDING, MAX_STATE_BYTES, Transport, c_void, clap_event_header,
+    clap_event_midi, clap_event_note, clap_event_param_value, clap_event_transport, clap_input_events, clap_istream, clap_ostream,
+    clap_output_events,
+};
 
 // ---- events --------------------------------------------------------------------------------
 
diff --git a/crates/clap-host/src/ffi/gui.rs b/crates/clap-host/src/ffi/gui.rs
--- a/crates/clap-host/src/ffi/gui.rs
+++ b/crates/clap-host/src/ffi/gui.rs
@@ -1,6 +1,9 @@
 use super::events::ostream_write;
 use super::host::HostState;
-use super::*;
+use super::{
+    Arc, CStr, CString, Mutex, Ordering, PoisonError, c_void, clap_ostream, clap_plugin, clap_plugin_gui, clap_plugin_state, clap_window,
+    clap_window_handle, hostwin,
+};
 
 // ---- editor (clap.gui) ---------------------------------------------------------------------
 
diff --git a/crates/clap-host/src/ffi/host.rs b/crates/clap-host/src/ffi/host.rs
--- a/crates/clap-host/src/ffi/host.rs
+++ b/crates/clap-host/src/ffi/host.rs
@@ -1,4 +1,8 @@
-use super::*;
+use super::{
+    AtomicBool, AtomicU64, CLAP_EXT_GUI, CLAP_EXT_LATENCY, CLAP_EXT_LOG, CLAP_EXT_PARAMS, CLAP_EXT_STATE, CLAP_LOG_ERROR, CLAP_LOG_FATAL,
+    CLAP_LOG_WARNING, CStr, EDIT_CAP, Mutex, Ordering, c_char, c_void, clap_host, clap_host_gui, clap_host_latency, clap_host_log, clap_host_params,
+    clap_host_state, clap_id, clap_log_severity, clap_param_clear_flags, clap_param_rescan_flags, read_cstr,
+};
 
 // ---- host side -----------------------------------------------------------------------------
 
diff --git a/crates/clap-host/src/ffi/instance.rs b/crates/clap-host/src/ffi/instance.rs
--- a/crates/clap-host/src/ffi/instance.rs
+++ b/crates/clap-host/src/ffi/instance.rs
@@ -2,7 +2,12 @@ use super::bundle::Bundle;
 use super::events::{Event, RawEvent, ReadCursor, in_events_get, in_events_size, istream_read, out_events_try_push, transport_event};
 use super::gui::GuiLink;
 use super::host::HostState;
-use super::*;
+use super::{
+    Arc, CLAP_AUDIO_PORT_IS_MAIN, CLAP_PROCESS_ERROR, CStr, ClapError, MAX_PARAMS, MAX_PORT_CHANNELS, MAX_PORTS, Ordering, Transport, c_char, c_void,
+    clap_audio_buffer, clap_audio_port_info, clap_host, clap_input_events, clap_istream, clap_note_port_info, clap_output_events, clap_param_info,
+    clap_plugin, clap_plugin_audio_ports, clap_plugin_latency, clap_plugin_note_ports, clap_plugin_params, clap_plugin_state, clap_process,
+    read_name,
+};
 
 // ---- audio buffers -------------------------------------------------------------------------
 
@@ -312,16 +317,8 @@ impl Instance {
 
     /// Runs one `clap_process` call over `frames` frames. Events must be sorted by time; their
     /// times are made relative to `offset`. Returns the CLAP process status.
-    pub fn process(
-        &mut self,
-        frames: usize,
-        steady_time: i64,
-        inputs: &mut PortBuffers,
-        outputs: &mut PortBuffers,
-        events: &[Event],
-        offset: u32,
-        transport: Option<&Transport>,
-    ) -> Result<i32, ClapError> {
+    pub fn process(&mut self, input: ProcessInput<'_>) -> Result<i32, ClapError> {
+        let ProcessInput { frames, steady_time, inputs, outputs, events, offset, transport } = input;
         if !self.active {
             return Err(ClapError::Process("not active".into()));
         }
@@ -386,6 +383,16 @@ impl Instance {
     }
 }
 
+pub(crate) struct ProcessInput<'a> {
+    pub frames: usize,
+    pub steady_time: i64,
+    pub inputs: &'a mut PortBuffers,
+    pub outputs: &'a mut PortBuffers,
+    pub events: &'a [Event],
+    pub offset: u32,
+    pub transport: Option<&'a Transport>,
+}
+
 impl Drop for Instance {
     fn drop(&mut self) {
         // Editors first (CLAP: destroy the GUI before the plugin), and no handle may call in after.
diff --git a/crates/clap-host/src/plugin.rs b/crates/clap-host/src/plugin.rs
--- a/crates/clap-host/src/plugin.rs
+++ b/crates/clap-host/src/plugin.rs
@@ -1,6 +1,6 @@
 //! `ClapPlugin`: a loaded CLAP instance behind the safe `soundcraft_dsp::Plugin` trait.
 
-use crate::ffi::{EVENT_CAP, Event, GuiLink, Instance, NotePort, PortBuffers};
+use crate::ffi::{EVENT_CAP, Event, GuiLink, Instance, NotePort, PortBuffers, ProcessInput};
 use clap_sys::ext::note_ports::{CLAP_NOTE_DIALECT_CLAP, CLAP_NOTE_DIALECT_MIDI};
 use soundcraft_dsp::{Plugin, PluginEditor, PluginInfo, Transport};
 use std::sync::Arc;
@@ -231,7 +231,15 @@ impl Plugin for ClapPlugin {
             let k = self.queue.iter().position(|e| e.time() >= end).unwrap_or(self.queue.len());
             let offset = u32::try_from(start).unwrap_or(u32::MAX);
             let events = self.queue.get(..k).unwrap_or(&[]);
-            let r = self.inst.process(n, self.steady, &mut self.inputs, &mut self.outputs, events, offset, self.transport.as_ref());
+            let r = self.inst.process(ProcessInput {
+                frames: n,
+                steady_time: self.steady,
+                inputs: &mut self.inputs,
+                outputs: &mut self.outputs,
+                events,
+                offset,
+                transport: self.transport.as_ref(),
+            });
             self.queue.drain(..k);
             self.steady = self.steady.saturating_add(i64::try_from(n).unwrap_or(0));
             match (r, self.out_main) {
diff --git a/crates/video/src/h264/deblock.rs b/crates/video/src/h264/deblock.rs
--- a/crates/video/src/h264/deblock.rs
+++ b/crates/video/src/h264/deblock.rs
@@ -279,7 +279,6 @@ fn filter_horizontal<const N: usize>(pix: &mut [u8], stride: usize, x: usize, y:
 }
 
 /// Deblock one macroblock (macroblocks must be processed in raster order).
-#[allow(clippy::needless_range_loop)]
 pub fn deblock_mb(pic: &mut PicState, addr: usize, mb_w: usize) {
     let q = &pic.mbs[addr];
     if q.slice_num == u32::MAX {
@@ -303,6 +302,23 @@ pub fn deblock_mb(pic: &mut PicState, addr: usize, mb_w: usize) {
     let alpha_off = sq.alpha_offset;
     let beta_off = sq.beta_offset;
     let t8 = q.transform_8x8;
+    let bs = boundary_strengths(pic, q, sq, left, top, t8);
+    let qp_of = |st: &MbState| if st.kind == MbKind::IPcm { 0 } else { st.qp as i32 };
+    let q_qp = qp_of(q);
+    let q_qpc = q.qpc;
+    let p_qp = [left.map(|n| (qp_of(&pic.mbs[n]), pic.mbs[n].qpc)), top.map(|n| (qp_of(&pic.mbs[n]), pic.mbs[n].qpc))];
+    let params = |qpp: i32, qpq: i32, b: [u8; 4]| {
+        let qpav = (qpp + qpq + 1) >> 1;
+        let index_a = (qpav + alpha_off).clamp(0, 51) as usize;
+        let index_b = (qpav + beta_off).clamp(0, 51) as usize;
+        let tc = |b: u8| if (1..4).contains(&b) { TC0[index_a][b as usize - 1] as i32 } else { 0 };
+        EdgeParams { bs: b, tc0: [tc(b[0]), tc(b[1]), tc(b[2]), tc(b[3])], alpha: ALPHA[index_a] as i32, beta: BETA[index_b] as i32 }
+    };
+    filter_luma(pic, (mx, my), &bs, q_qp, p_qp, &params);
+    filter_chroma(pic, (mx, my), &bs, q_qpc, p_qp, &params);
+}
+
+fn boundary_strengths(pic: &PicState, q: &MbState, sq: &SliceInfo, left: Option<usize>, top: Option<usize>, t8: bool) -> [[[u8; 4]; 4]; 2] {
     // bS[dir][edge][segment]; dir 0 = vertical edges (x), 1 = horizontal edges (y)
     let mut bs = [[[0u8; 4]; 4]; 2];
     if q.kind.is_intra() {
@@ -356,20 +372,18 @@ pub fn deblock_mb(pic: &mut PicState, addr: usize, mb_w: usize) {
             }
         }
     }
-    let qp_of = |st: &MbState| if st.kind == MbKind::IPcm { 0 } else { st.qp as i32 };
-    let q_qp = qp_of(q);
-    let q_qpc = q.qpc;
-    let p_qp = [left.map(|n| (qp_of(&pic.mbs[n]), pic.mbs[n].qpc)), top.map(|n| (qp_of(&pic.mbs[n]), pic.mbs[n].qpc))];
-    let params = |qpp: i32, qpq: i32, b: [u8; 4]| {
-        let qpav = (qpp + qpq + 1) >> 1;
-        let index_a = (qpav + alpha_off).clamp(0, 51) as usize;
-        let index_b = (qpav + beta_off).clamp(0, 51) as usize;
-        let tc = |b: u8| if (1..4).contains(&b) { TC0[index_a][b as usize - 1] as i32 } else { 0 };
-        EdgeParams { bs: b, tc0: [tc(b[0]), tc(b[1]), tc(b[2]), tc(b[3])], alpha: ALPHA[index_a] as i32, beta: BETA[index_b] as i32 }
-    };
+    bs
+}
+
+fn filter_luma(
+    pic: &mut PicState,
+    (mx, my): (usize, usize),
+    bs: &[[[u8; 4]; 4]; 2],
+    q_qp: i32,
+    p_qp: [Option<(i32, [u8; 2])>; 2],
+    params: &impl Fn(i32, i32, [u8; 4]) -> EdgeParams,
+) {
     let width = pic.planes.width;
-    let cwidth = pic.planes.cwidth;
-    // luma
     for dir in 0..2 {
         for e in 0..4 {
             if bs[dir][e] == [0; 4] {
@@ -389,6 +403,17 @@ pub fn deblock_mb(pic: &mut PicState, addr: usize, mb_w: usize) {
             }
         }
     }
+}
+
+fn filter_chroma(
+    pic: &mut PicState,
+    (mx, my): (usize, usize),
+    bs: &[[[u8; 4]; 4]; 2],
+    q_qpc: [u8; 2],
+    p_qp: [Option<(i32, [u8; 2])>; 2],
+    params: &impl Fn(i32, i32, [u8; 4]) -> EdgeParams,
+) {
+    let cwidth = pic.planes.cwidth;
     // chroma (4:2:0): edges at chroma samples 0 and 4 use the bS of luma edges 0 and 2
     for c in 0..2 {
         for dir in 0..2 {
diff --git a/crates/video/src/h264/intra.rs b/crates/video/src/h264/intra.rs
--- a/crates/video/src/h264/intra.rs
+++ b/crates/video/src/h264/intra.rs
@@ -61,125 +61,146 @@ fn load_edge(plane: &[u8], stride: usize, x: usize, y: usize, n: usize, a: Avail
 
 /// Directional / DC prediction shared by Intra_4x4 and Intra_8x8 (8.3.1.2.x, 8.3.2.2.x).
 fn pred_nxn(mode: u8, e: &Edge, n: i32, a: Avail, out: &mut [u8], stride: usize) {
-    let mut put = |x: i32, y: i32, v: i32| out[y as usize * stride + x as usize] = v as u8;
     match mode {
-        0 => {
-            for y in 0..n {
-                for x in 0..n {
-                    put(x, y, e.t(x));
-                }
-            }
+        0 => pred_vertical(e, n, out, stride),
+        1 => pred_horizontal(e, n, out, stride),
+        2 => pred_dc(e, n, a, out, stride),
+        3 => pred_down_left(e, n, out, stride),
+        4 => pred_down_right(e, n, out, stride),
+        5 => pred_vertical_right(e, n, out, stride),
+        6 => pred_horizontal_down(e, n, out, stride),
+        7 => pred_vertical_left(e, n, out, stride),
+        _ => pred_horizontal_up(e, n, out, stride),
+    }
+}
+
+fn put(out: &mut [u8], stride: usize, x: i32, y: i32, value: i32) {
+    out[y as usize * stride + x as usize] = value as u8;
+}
+
+fn pred_vertical(e: &Edge, n: i32, out: &mut [u8], stride: usize) {
+    for y in 0..n {
+        for x in 0..n {
+            put(out, stride, x, y, e.t(x));
         }
-        1 => {
-            for y in 0..n {
-                for x in 0..n {
-                    put(x, y, e.l(y));
-                }
-            }
+    }
+}
+
+fn pred_horizontal(e: &Edge, n: i32, out: &mut [u8], stride: usize) {
+    for y in 0..n {
+        for x in 0..n {
+            put(out, stride, x, y, e.l(y));
         }
-        2 => {
-            let shift = if n == 4 { 2 } else { 3 };
-            let st: i32 = (0..n).map(|x| e.t(x)).sum();
-            let sl: i32 = (0..n).map(|y| e.l(y)).sum();
-            let dc = match (a.top, a.left) {
-                (true, true) => (st + sl + n) >> (shift + 1),
-                (false, true) => (sl + (n >> 1)) >> shift,
-                (true, false) => (st + (n >> 1)) >> shift,
-                _ => 128,
-            };
-            for y in 0..n {
-                for x in 0..n {
-                    put(x, y, dc);
-                }
-            }
+    }
+}
+
+fn pred_dc(e: &Edge, n: i32, a: Avail, out: &mut [u8], stride: usize) {
+    let shift = if n == 4 { 2 } else { 3 };
+    let st: i32 = (0..n).map(|x| e.t(x)).sum();
+    let sl: i32 = (0..n).map(|y| e.l(y)).sum();
+    let dc = match (a.top, a.left) {
+        (true, true) => (st + sl + n) >> (shift + 1),
+        (false, true) => (sl + (n >> 1)) >> shift,
+        (true, false) => (st + (n >> 1)) >> shift,
+        _ => 128,
+    };
+    for y in 0..n {
+        for x in 0..n {
+            put(out, stride, x, y, dc);
         }
-        3 => {
-            for y in 0..n {
-                for x in 0..n {
-                    let v = if x == n - 1 && y == n - 1 {
-                        (e.t(2 * n - 2) + 3 * e.t(2 * n - 1) + 2) >> 2
-                    } else {
-                        (e.t(x + y) + 2 * e.t(x + y + 1) + e.t(x + y + 2) + 2) >> 2
-                    };
-                    put(x, y, v);
-                }
-            }
+    }
+}
+
+fn pred_down_left(e: &Edge, n: i32, out: &mut [u8], stride: usize) {
+    for y in 0..n {
+        for x in 0..n {
+            let value = if x == n - 1 && y == n - 1 {
+                (e.t(2 * n - 2) + 3 * e.t(2 * n - 1) + 2) >> 2
+            } else {
+                (e.t(x + y) + 2 * e.t(x + y + 1) + e.t(x + y + 2) + 2) >> 2
+            };
+            put(out, stride, x, y, value);
         }
-        4 => {
-            for y in 0..n {
-                for x in 0..n {
-                    let v = if x > y {
-                        (e.t(x - y - 2) + 2 * e.t(x - y - 1) + e.t(x - y) + 2) >> 2
-                    } else if x < y {
-                        (e.l(y - x - 2) + 2 * e.l(y - x - 1) + e.l(y - x) + 2) >> 2
-                    } else {
-                        (e.t(0) + 2 * e.tl + e.l(0) + 2) >> 2
-                    };
-                    put(x, y, v);
-                }
-            }
+    }
+}
+
+fn pred_down_right(e: &Edge, n: i32, out: &mut [u8], stride: usize) {
+    for y in 0..n {
+        for x in 0..n {
+            let value = if x > y {
+                (e.t(x - y - 2) + 2 * e.t(x - y - 1) + e.t(x - y) + 2) >> 2
+            } else if x < y {
+                (e.l(y - x - 2) + 2 * e.l(y - x - 1) + e.l(y - x) + 2) >> 2
+            } else {
+                (e.t(0) + 2 * e.tl + e.l(0) + 2) >> 2
+            };
+            put(out, stride, x, y, value);
         }
-        5 => {
-            for y in 0..n {
-                for x in 0..n {
-                    let z = 2 * x - y;
-                    let v = if z >= 0 && z % 2 == 0 {
-                        (e.t(x - (y >> 1) - 1) + e.t(x - (y >> 1)) + 1) >> 1
-                    } else if z > 0 {
-                        (e.t(x - (y >> 1) - 2) + 2 * e.t(x - (y >> 1) - 1) + e.t(x - (y >> 1)) + 2) >> 2
-                    } else if z == -1 {
-                        (e.l(0) + 2 * e.tl + e.t(0) + 2) >> 2
-                    } else {
-                        (e.l(y - 2 * x - 1) + 2 * e.l(y - 2 * x - 2) + e.l(y - 2 * x - 3) + 2) >> 2
-                    };
-                    put(x, y, v);
-                }
-            }
+    }
+}
+
+fn pred_vertical_right(e: &Edge, n: i32, out: &mut [u8], stride: usize) {
+    for y in 0..n {
+        for x in 0..n {
+            let z = 2 * x - y;
+            let value = if z >= 0 && z % 2 == 0 {
+                (e.t(x - (y >> 1) - 1) + e.t(x - (y >> 1)) + 1) >> 1
+            } else if z > 0 {
+                (e.t(x - (y >> 1) - 2) + 2 * e.t(x - (y >> 1) - 1) + e.t(x - (y >> 1)) + 2) >> 2
+            } else if z == -1 {
+                (e.l(0) + 2 * e.tl + e.t(0) + 2) >> 2
+            } else {
+                (e.l(y - 2 * x - 1) + 2 * e.l(y - 2 * x - 2) + e.l(y - 2 * x - 3) + 2) >> 2
+            };
+            put(out, stride, x, y, value);
         }
-        6 => {
-            for y in 0..n {
-                for x in 0..n {
-                    let z = 2 * y - x;
-                    let v = if z >= 0 && z % 2 == 0 {
-                        (e.l(y - (x >> 1) - 1) + e.l(y - (x >> 1)) + 1) >> 1
-                    } else if z > 0 {
-                        (e.l(y - (x >> 1) - 2) + 2 * e.l(y - (x >> 1) - 1) + e.l(y - (x >> 1)) + 2) >> 2
-                    } else if z == -1 {
-                        (e.l(0) + 2 * e.tl + e.t(0) + 2) >> 2
-                    } else {
-                        (e.t(x - 2 * y - 1) + 2 * e.t(x - 2 * y - 2) + e.t(x - 2 * y - 3) + 2) >> 2
-                    };
-                    put(x, y, v);
-                }
-            }
+    }
+}
+
+fn pred_horizontal_down(e: &Edge, n: i32, out: &mut [u8], stride: usize) {
+    for y in 0..n {
+        for x in 0..n {
+            let z = 2 * y - x;
+            let value = if z >= 0 && z % 2 == 0 {
+                (e.l(y - (x >> 1) - 1) + e.l(y - (x >> 1)) + 1) >> 1
+            } else if z > 0 {
+                (e.l(y - (x >> 1) - 2) + 2 * e.l(y - (x >> 1) - 1) + e.l(y - (x >> 1)) + 2) >> 2
+            } else if z == -1 {
+                (e.l(0) + 2 * e.tl + e.t(0) + 2) >> 2
+            } else {
+                (e.t(x - 2 * y - 1) + 2 * e.t(x - 2 * y - 2) + e.t(x - 2 * y - 3) + 2) >> 2
+            };
+            put(out, stride, x, y, value);
         }
-        7 => {
-            for y in 0..n {
-                for x in 0..n {
-                    let i = x + (y >> 1);
-                    let v = if y % 2 == 0 { (e.t(i) + e.t(i + 1) + 1) >> 1 } else { (e.t(i) + 2 * e.t(i + 1) + e.t(i + 2) + 2) >> 2 };
-                    put(x, y, v);
-                }
-            }
+    }
+}
+
+fn pred_vertical_left(e: &Edge, n: i32, out: &mut [u8], stride: usize) {
+    for y in 0..n {
+        for x in 0..n {
+            let i = x + (y >> 1);
+            let value = if y % 2 == 0 { (e.t(i) + e.t(i + 1) + 1) >> 1 } else { (e.t(i) + 2 * e.t(i + 1) + e.t(i + 2) + 2) >> 2 };
+            put(out, stride, x, y, value);
         }
-        _ => {
-            let zmax = 2 * n - 3;
-            for y in 0..n {
-                for x in 0..n {
-                    let z = x + 2 * y;
-                    let i = y + (x >> 1);
-                    let v = if z < zmax && z % 2 == 0 {
-                        (e.l(i) + e.l(i + 1) + 1) >> 1
-                    } else if z < zmax {
-                        (e.l(i) + 2 * e.l(i + 1) + e.l(i + 2) + 2) >> 2
-                    } else if z == zmax {
-                        (e.l(n - 2) + 3 * e.l(n - 1) + 2) >> 2
-                    } else {
-                        e.l(n - 1)
-                    };
-                    put(x, y, v);
-                }
-            }
+    }
+}
+
+fn pred_horizontal_up(e: &Edge, n: i32, out: &mut [u8], stride: usize) {
+    let zmax = 2 * n - 3;
+    for y in 0..n {
+        for x in 0..n {
+            let z = x + 2 * y;
+            let i = y + (x >> 1);
+            let value = if z < zmax && z % 2 == 0 {
+                (e.l(i) + e.l(i + 1) + 1) >> 1
+            } else if z < zmax {
+                (e.l(i) + 2 * e.l(i + 1) + e.l(i + 2) + 2) >> 2
+            } else if z == zmax {
+                (e.l(n - 2) + 3 * e.l(n - 1) + 2) >> 2
+            } else {
+                e.l(n - 1)
+            };
+            put(out, stride, x, y, value);
         }
     }
 }
diff --git a/crates/video/src/h264/slice.rs b/crates/video/src/h264/slice.rs
--- a/crates/video/src/h264/slice.rs
+++ b/crates/video/src/h264/slice.rs
@@ -214,101 +214,9 @@ impl SliceHeader {
             num_ref_idx_active[0] = 0;
         }
         ensure!(nal.nal_unit_type != 20 && nal.nal_unit_type != 21, "MVC slices are not supported");
-        let mut ref_pic_list_mod = [Vec::new(), Vec::new()];
-        for (list, mods) in ref_pic_list_mod.iter_mut().enumerate() {
-            let present = if list == 0 { !slice_type.is_intra() } else { slice_type.is_b() };
-            if present && r.read_flag()? {
-                loop {
-                    let idc = r.read_ue()?;
-                    ensure!(idc <= 5, "modification_of_pic_nums_idc out of range");
-                    if idc == 3 {
-                        break;
-                    }
-                    let value = r.read_ue()?;
-                    mods.push(RefPicListMod { idc, value });
-                    ensure!(mods.len() <= 66, "too many ref_pic_list_modification entries");
-                }
-            }
-        }
-        let mut pred_weight_table = None;
-        if (pps.weighted_pred && slice_type.is_p()) || (pps.weighted_bipred_idc == 1 && slice_type.is_b()) {
-            let luma_log2_denom = r.read_ue()?;
-            ensure!(luma_log2_denom <= 7, "luma_log2_weight_denom out of range");
-            let mut chroma_log2_denom = 0;
-            if sps.chroma_array_type() != 0 {
-                chroma_log2_denom = r.read_ue()?;
-                ensure!(chroma_log2_denom <= 7, "chroma_log2_weight_denom out of range");
-            }
-            let mut lists = [Vec::new(), Vec::new()];
-            let nlists = if slice_type.is_b() { 2 } else { 1 };
-            for (l, entries) in lists.iter_mut().enumerate().take(nlists) {
-                for _ in 0..num_ref_idx_active[l] {
-                    let mut e = WeightEntry { luma_weight: 1 << luma_log2_denom, chroma_weight: [1 << chroma_log2_denom; 2], ..Default::default() };
-                    if r.read_flag()? {
-                        e.luma_flag = true;
-                        e.luma_weight = r.read_se()?;
-                        e.luma_offset = r.read_se()?;
-                        ensure!((-128..=127).contains(&e.luma_weight) && (-128..=127).contains(&e.luma_offset), "luma weight out of range");
-                    }
-                    if sps.chroma_array_type() != 0 && r.read_flag()? {
-                        e.chroma_flag = true;
-                        for j in 0..2 {
-                            e.chroma_weight[j] = r.read_se()?;
-                            e.chroma_offset[j] = r.read_se()?;
-                            ensure!(
-                                (-128..=127).contains(&e.chroma_weight[j]) && (-128..=127).contains(&e.chroma_offset[j]),
-                                "chroma weight out of range"
-                            );
-                        }
-                    }
-                    entries.push(e);
-                }
-            }
-            let [l0, l1] = lists;
-            pred_weight_table = Some(PredWeightTable { luma_log2_denom, chroma_log2_denom, l0, l1 });
-        }
-        let mut no_output_of_prior_pics = false;
-        let mut long_term_reference = false;
-        let mut adaptive_ref_pic_marking = false;
-        let mut mmcos = Vec::new();
-        if nal.nal_ref_idc != 0 {
-            if idr {
-                no_output_of_prior_pics = r.read_flag()?;
-                long_term_reference = r.read_flag()?;
-            } else {
-                adaptive_ref_pic_marking = r.read_flag()?;
-                if adaptive_ref_pic_marking {
-                    loop {
-                        let op = r.read_ue()?;
-                        ensure!(op <= 6, "memory_management_control_operation out of range");
-                        if op == 0 {
-                            break;
-                        }
-                        let mut m = Mmco {
-                            op,
-                            difference_of_pic_nums_minus1: 0,
-                            long_term_pic_num: 0,
-                            long_term_frame_idx: 0,
-                            max_long_term_frame_idx_plus1: 0,
-                        };
-                        if op == 1 || op == 3 {
-                            m.difference_of_pic_nums_minus1 = r.read_ue()?;
-                        }
-                        if op == 2 {
-                            m.long_term_pic_num = r.read_ue()?;
-                        }
-                        if op == 3 || op == 6 {
-                            m.long_term_frame_idx = r.read_ue()?;
-                        }
-                        if op == 4 {
-                            m.max_long_term_frame_idx_plus1 = r.read_ue()?;
-                        }
-                        mmcos.push(m);
-                        ensure!(mmcos.len() <= 66, "too many MMCOs");
-                    }
-                }
-            }
-        }
+        let ref_fields = parse_reference_fields(&mut r, nal, idr, slice_type, pps, sps, num_ref_idx_active)?;
+        let RefFields { ref_pic_list_mod, pred_weight_table, no_output_of_prior_pics, long_term_reference, adaptive_ref_pic_marking, mmcos } =
+            ref_fields;
         let mut cabac_init_idc = 0;
         if pps.entropy_coding_mode && !slice_type.is_intra() {
             cabac_init_idc = r.read_ue()?;
@@ -391,6 +299,134 @@ impl SliceHeader {
     }
 }
 
+struct RefFields {
+    ref_pic_list_mod: [Vec<RefPicListMod>; 2],
+    pred_weight_table: Option<PredWeightTable>,
+    no_output_of_prior_pics: bool,
+    long_term_reference: bool,
+    adaptive_ref_pic_marking: bool,
+    mmcos: Vec<Mmco>,
+}
+
+fn parse_reference_fields(
+    r: &mut BitReader<'_>,
+    nal: NalHeader,
+    idr: bool,
+    slice_type: SliceType,
+    pps: &Pps,
+    sps: &Sps,
+    num_ref_idx_active: [u32; 2],
+) -> Result<RefFields> {
+    let ref_pic_list_mod = parse_ref_pic_list_mod(r, slice_type)?;
+    let pred_weight_table = parse_pred_weight_table(r, slice_type, pps, sps, num_ref_idx_active)?;
+    let (no_output_of_prior_pics, long_term_reference, adaptive_ref_pic_marking, mmcos) = parse_ref_pic_marking(r, nal, idr)?;
+    Ok(RefFields { ref_pic_list_mod, pred_weight_table, no_output_of_prior_pics, long_term_reference, adaptive_ref_pic_marking, mmcos })
+}
+
+fn parse_ref_pic_list_mod(r: &mut BitReader<'_>, slice_type: SliceType) -> Result<[Vec<RefPicListMod>; 2]> {
+    let mut lists = [Vec::new(), Vec::new()];
+    for (list, mods) in lists.iter_mut().enumerate() {
+        let present = if list == 0 { !slice_type.is_intra() } else { slice_type.is_b() };
+        if present && r.read_flag()? {
+            loop {
+                let idc = r.read_ue()?;
+                ensure!(idc <= 5, "modification_of_pic_nums_idc out of range");
+                if idc == 3 {
+                    break;
+                }
+                mods.push(RefPicListMod { idc, value: r.read_ue()? });
+                ensure!(mods.len() <= 66, "too many ref_pic_list_modification entries");
+            }
+        }
+    }
+    Ok(lists)
+}
+
+fn parse_pred_weight_table(r: &mut BitReader<'_>, slice_type: SliceType, pps: &Pps, sps: &Sps, active: [u32; 2]) -> Result<Option<PredWeightTable>> {
+    let weighted = (pps.weighted_pred && slice_type.is_p()) || (pps.weighted_bipred_idc == 1 && slice_type.is_b());
+    if !weighted {
+        return Ok(None);
+    }
+    let luma_log2_denom = r.read_ue()?;
+    ensure!(luma_log2_denom <= 7, "luma_log2_weight_denom out of range");
+    let chroma_log2_denom = if sps.chroma_array_type() == 0 { 0 } else { r.read_ue()? };
+    ensure!(chroma_log2_denom <= 7, "chroma_log2_weight_denom out of range");
+    let mut lists = [Vec::new(), Vec::new()];
+    let list_count = if slice_type.is_b() { 2 } else { 1 };
+    for (list, entries) in lists.iter_mut().enumerate().take(list_count) {
+        for _ in 0..active[list] {
+            entries.push(parse_weight_entry(r, luma_log2_denom, chroma_log2_denom, sps.chroma_array_type() != 0)?);
+        }
+    }
+    let [l0, l1] = lists;
+    Ok(Some(PredWeightTable { luma_log2_denom, chroma_log2_denom, l0, l1 }))
+}
+
+fn parse_weight_entry(r: &mut BitReader<'_>, luma_denom: u32, chroma_denom: u32, has_chroma: bool) -> Result<WeightEntry> {
+    let mut entry = WeightEntry { luma_weight: 1 << luma_denom, chroma_weight: [1 << chroma_denom; 2], ..Default::default() };
+    if r.read_flag()? {
+        entry.luma_flag = true;
+        entry.luma_weight = r.read_se()?;
+        entry.luma_offset = r.read_se()?;
+        ensure!((-128..=127).contains(&entry.luma_weight) && (-128..=127).contains(&entry.luma_offset), "luma weight out of range");
+    }
+    if has_chroma && r.read_flag()? {
+        entry.chroma_flag = true;
+        for index in 0..2 {
+            entry.chroma_weight[index] = r.read_se()?;
+            entry.chroma_offset[index] = r.read_se()?;
+            ensure!(
+                (-128..=127).contains(&entry.chroma_weight[index]) && (-128..=127).contains(&entry.chroma_offset[index]),
+                "chroma weight out of range"
+            );
+        }
+    }
+    Ok(entry)
+}
+
+fn parse_ref_pic_marking(r: &mut BitReader<'_>, nal: NalHeader, idr: bool) -> Result<(bool, bool, bool, Vec<Mmco>)> {
+    let (mut no_output, mut long_term, mut adaptive) = (false, false, false);
+    let mut mmcos = Vec::new();
+    if nal.nal_ref_idc == 0 {
+        return Ok((no_output, long_term, adaptive, mmcos));
+    }
+    if idr {
+        no_output = r.read_flag()?;
+        long_term = r.read_flag()?;
+    } else {
+        adaptive = r.read_flag()?;
+        if adaptive {
+            parse_mmcos(r, &mut mmcos)?;
+        }
+    }
+    Ok((no_output, long_term, adaptive, mmcos))
+}
+
+fn parse_mmcos(r: &mut BitReader<'_>, mmcos: &mut Vec<Mmco>) -> Result<()> {
+    loop {
+        let op = r.read_ue()?;
+        ensure!(op <= 6, "memory_management_control_operation out of range");
+        if op == 0 {
+            return Ok(());
+        }
+        let mut m = Mmco { op, difference_of_pic_nums_minus1: 0, long_term_pic_num: 0, long_term_frame_idx: 0, max_long_term_frame_idx_plus1: 0 };
+        if op == 1 || op == 3 {
+            m.difference_of_pic_nums_minus1 = r.read_ue()?;
+        }
+        if op == 2 {
+            m.long_term_pic_num = r.read_ue()?;
+        }
+        if op == 3 || op == 6 {
+            m.long_term_frame_idx = r.read_ue()?;
+        }
+        if op == 4 {
+            m.max_long_term_frame_idx_plus1 = r.read_ue()?;
+        }
+        mmcos.push(m);
+        ensure!(mmcos.len() <= 66, "too many MMCOs");
+    }
+}
+
 /// POC decoding state carried between pictures (8.2.1).
 #[derive(Clone, Debug, Default)]
 pub struct PocState {
diff --git a/crates/vst3-host/Cargo.toml b/crates/vst3-host/Cargo.toml
--- a/crates/vst3-host/Cargo.toml
+++ b/crates/vst3-host/Cargo.toml
@@ -54,7 +54,9 @@ harness = false
 unsafe_code = "deny"
 
 [lints.clippy]
+cognitive_complexity = "deny"
+wildcard_imports = "deny"
 dbg_macro = "warn"
 todo = "warn"
-too_many_arguments = "allow"
+too_many_arguments = "deny"
 type_complexity = "allow"
diff --git a/crates/vst3-host/src/ffi.rs b/crates/vst3-host/src/ffi.rs
--- a/crates/vst3-host/src/ffi.rs
+++ b/crates/vst3-host/src/ffi.rs
@@ -39,7 +39,7 @@ mod process;
 
 pub(crate) use editor::EditorLink;
 pub(crate) use host::HostContext;
-pub(crate) use instance::{Instance, PARAM_BYPASS, PARAM_HIDDEN, PARAM_READ_ONLY, RawParam};
+pub(crate) use instance::{Instance, PARAM_BYPASS, PARAM_HIDDEN, PARAM_READ_ONLY, ProcessInput, RawParam};
 #[cfg(test)]
 use instance::{apply_transport, split_state};
 pub(crate) use module::{Bundle, exit_modules, hex};
diff --git a/crates/vst3-host/src/ffi/editor.rs b/crates/vst3-host/src/ffi/editor.rs
--- a/crates/vst3-host/src/ffi/editor.rs
+++ b/crates/vst3-host/src/ffi/editor.rs
@@ -1,5 +1,8 @@
 use super::instance::Instance;
-use super::*;
+use super::{
+    Class, ComPtr, ComWrapper, IComponentTrait, IEditControllerTrait, IPlugFrameTrait, IPlugViewTrait, Mutex, Ordering, PoisonError, STATE_MAGIC,
+    c_void, ok, read_c16, sb, sv, window,
+};
 
 // ---- editor (IPlugView) --------------------------------------------------------------------
 
diff --git a/crates/vst3-host/src/ffi/host.rs b/crates/vst3-host/src/ffi/host.rs
--- a/crates/vst3-host/src/ffi/host.rs
+++ b/crates/vst3-host/src/ffi/host.rs
@@ -1,5 +1,8 @@
 use super::module::tuid_bytes;
-use super::*;
+use super::{
+    AtomicBool, Class, ComWrapper, EDIT_CAP, FUnknown, IComponentHandlerTrait, IHostApplicationTrait, Interface, Mutex, Ordering, PoisonError,
+    c_void, sb, sv, write_c16,
+};
 
 // ---- host-side COM objects -----------------------------------------------------------------
 
diff --git a/crates/vst3-host/src/ffi/instance.rs b/crates/vst3-host/src/ffi/instance.rs
--- a/crates/vst3-host/src/ffi/instance.rs
+++ b/crates/vst3-host/src/ffi/instance.rs
@@ -2,7 +2,11 @@ use super::editor::EditorLink;
 use super::host::HostContext;
 use super::module::Bundle;
 use super::process::{BusBuffers, EventList, MemoryStream, NoteEvent, ParamChanges};
-use super::*;
+use super::{
+    Arc, ComPtr, ComWrapper, EVENT_CAP, IAudioProcessorTrait, IComponentTrait, IConnectionPointTrait, IEditControllerTrait, IMidiMappingTrait,
+    IPluginBaseTrait, MAX_BUS_CHANNELS, MAX_BUSES, MAX_PARAMS, MAX_STATE_BYTES, Mutex, Ordering, PARAM_QUEUE_CAP, PITCH_BEND, STATE_MAGIC, Transport,
+    Vst3Error, ok, read_c16, sb, sv,
+};
 
 // ---- instances -----------------------------------------------------------------------------
 
@@ -32,7 +36,9 @@ pub(crate) struct Layout {
 }
 
 pub(super) fn apply_transport(c: &mut sv::ProcessContext, t: &Transport) {
-    use sv::ProcessContext_::StatesAndFlags_::*;
+    use sv::ProcessContext_::StatesAndFlags_::{
+        kBarPositionValid, kContTimeValid, kPlaying, kProjectTimeMusicValid, kRecording, kTempoValid, kTimeSigValid,
+    };
     let mut state = kTempoValid | kTimeSigValid | kProjectTimeMusicValid | kBarPositionValid | kContTimeValid;
     if t.playing {
         state |= kPlaying;
@@ -375,18 +381,8 @@ impl Instance {
     /// `controls` (time, id, value) one point at their time when it falls in this call (the last
     /// one wins per parameter), and `notes` (sorted by time) have their times made relative to
     /// `offset`.
-    pub fn process(
-        &mut self,
-        frames: usize,
-        inputs: &mut BusBuffers,
-        outputs: &mut BusBuffers,
-        params: &[(u32, f64)],
-        controls: &[(u32, u32, f64)],
-        notes: &[NoteEvent],
-        offset: u32,
-        project_time: i64,
-        transport: Option<&Transport>,
-    ) -> Result<(), Vst3Error> {
+    pub fn process(&mut self, input: ProcessInput<'_>) -> Result<(), Vst3Error> {
+        let ProcessInput { frames, inputs, outputs, params, controls, notes, offset, project_time, transport } = input;
         if !self.active {
             return Err(Vst3Error::Process("not active".into()));
         }
@@ -450,6 +446,18 @@ impl Instance {
     }
 }
 
+pub(crate) struct ProcessInput<'a> {
+    pub frames: usize,
+    pub inputs: &'a mut BusBuffers,
+    pub outputs: &'a mut BusBuffers,
+    pub params: &'a [(u32, f64)],
+    pub controls: &'a [(u32, u32, f64)],
+    pub notes: &'a [NoteEvent],
+    pub offset: u32,
+    pub project_time: i64,
+    pub transport: Option<&'a Transport>,
+}
+
 impl Drop for Instance {
     fn drop(&mut self) {
         // Close any editor and cut its handles off before the controller goes away.
diff --git a/crates/vst3-host/src/ffi/module.rs b/crates/vst3-host/src/ffi/module.rs
--- a/crates/vst3-host/src/ffi/module.rs
+++ b/crates/vst3-host/src/ffi/module.rs
@@ -2,7 +2,11 @@ use super::editor::{EditorInner, EditorLink};
 use super::host::HostContext;
 use super::instance::Instance;
 use super::process::{EventList, ParamChanges};
-use super::*;
+use super::{
+    Arc, AtomicBool, AtomicUsize, ComPtr, ComWrapper, Duration, EVENT_CAP, FUnknown, IComponentTrait, IConnectionPointTrait, IEditControllerTrait,
+    IPluginBaseTrait, IPluginFactory2Trait, IPluginFactoryTrait, Interface, MAX_CLASSES, ManuallyDrop, Mutex, OnceLock, Ordering, PARAM_QUEUE_CAP,
+    Path, PathBuf, PoisonError, TryLockError, Vst3Error, c_char, c_int, c_void, mpsc, ok, read_c8, sb, scan, sv,
+};
 
 // ---- loaded binaries -----------------------------------------------------------------------
 
diff --git a/crates/vst3-host/src/ffi/process.rs b/crates/vst3-host/src/ffi/process.rs
--- a/crates/vst3-host/src/ffi/process.rs
+++ b/crates/vst3-host/src/ffi/process.rs
@@ -1,4 +1,7 @@
-use super::*;
+use super::{
+    AtomicI32, AtomicU32, AtomicU64, Class, ComWrapper, IBStreamTrait, IEventListTrait, IParamValueQueueTrait, IParameterChangesTrait,
+    MAX_BUS_CHANNELS, MAX_BUSES, MAX_STATE_BYTES, Mutex, Ordering, PoisonError, c_void, sb, sv,
+};
 
 /// One parameter's points for one block. SoundCraft sends at most one point per block; a
 /// plugin writing output changes may add more, of which only the last is kept.
diff --git a/crates/vst3-host/src/plugin.rs b/crates/vst3-host/src/plugin.rs
--- a/crates/vst3-host/src/plugin.rs
+++ b/crates/vst3-host/src/plugin.rs
@@ -1,6 +1,6 @@
 //! `Vst3Plugin`: a loaded VST3 instance behind the safe `soundcraft_dsp::Plugin` trait.
 
-use crate::ffi::{AFTERTOUCH, BusBuffers, EVENT_CAP, EditorLink, HostContext, Instance, NoteEvent, PARAM_QUEUE_CAP, PITCH_BEND};
+use crate::ffi::{AFTERTOUCH, BusBuffers, EVENT_CAP, EditorLink, HostContext, Instance, NoteEvent, PARAM_QUEUE_CAP, PITCH_BEND, ProcessInput};
 use soundcraft_dsp::{Plugin, PluginEditor, PluginInfo, Transport, Unit};
 use std::collections::HashMap;
 use std::sync::Arc;
@@ -324,17 +324,17 @@ impl Plugin for Vst3Plugin {
             let k = self.notes.iter().position(|e| e.time() >= end).unwrap_or(self.notes.len());
             let offset = u32::try_from(start).unwrap_or(u32::MAX);
             let notes = self.notes.get(..k).unwrap_or(&[]);
-            let r = self.inst.process(
-                n,
-                &mut self.inputs,
-                &mut self.outputs,
-                &self.pending,
-                &self.controls,
+            let r = self.inst.process(ProcessInput {
+                frames: n,
+                inputs: &mut self.inputs,
+                outputs: &mut self.outputs,
+                params: &self.pending,
+                controls: &self.controls,
                 notes,
                 offset,
-                self.position,
-                self.transport.as_ref(),
-            );
+                project_time: self.position,
+                transport: self.transport.as_ref(),
+            });
             self.pending.clear();
             self.notes.drain(..k);
             self.position = self.position.saturating_add(i64::try_from(n).unwrap_or(0));
