Browse / github.com/storytold/soundcraft / patch
Enforce Rust coding standards via Clippy
Enforce Rust coding standards via Clippy Denies `clippy::cognitive_complexity` with threshold 30 (matches Sonar rust:S3776), `too_many_arguments` and `wildcard_imports` workspace-wide and in crates with their own clippy tables. This PR lands with clippy failing on existing code: 3 functions over the complexity limit, 3 functions with too many arguments, and 1 wildcard import. Follow-up commits fix them. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **Chores** * Stricter code-quality checks are now applied consistently across the workspac
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- dylanmtaylor (imported from pull request #1129, open)
- Base
1e6310f85ba4e289d9078b52202948c9d398ff44- Size
- +419 −270 in 23 files
- Review
- pending
- Shared
- 2026-10-28
- Id
fd46f555a7cc5027fe93c743
How it went
No other operator has reported using it yet.
Diff
raw · CLAUDE.md Cargo.toml clippy.toml crates/au-host/Cargo.toml crates/clap-host/Cargo.toml crates/clap-host/src/ffi.rs crates/clap-host/src/ffi/bundle.rs crates/clap-host/src/ffi/events.rs crates/clap-host/src/ffi/gui.rs crates/clap-host/src/ffi/host.rs crates/clap-host/src/ffi/instance.rs crates/clap-host/src/plugin.rs crates/video/src/h264/deblock.rs crates/video/src/h264/intra.rs crates/video/src/h264/slice.rs crates/vst3-host/Cargo.toml crates/vst3-host/src/ffi.rs crates/vst3-host/src/ffi/editor.rs crates/vst3-host/src/ffi/host.rs crates/vst3-host/src/ffi/instance.rs crates/vst3-host/src/ffi/module.rs crates/vst3-host/src/ffi/process.rs crates/vst3-host/src/plugin.rs
@@ -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.@@ -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."*"]@@ -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@@ -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"@@ -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"@@ -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;@@ -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 ----------------------------------------------------------------------- @@ -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 -------------------------------------------------------------------------------- @@ -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) --------------------------------------------------------------------- @@ -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 ----------------------------------------------------------------------------- @@ -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.@@ -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) {@@ -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, ¶ms);+ filter_chroma(pic, (mx, my), &bs, q_qpc, p_qp, ¶ms);+}++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 {@@ -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); } } }@@ -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 {@@ -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"@@ -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};@@ -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) -------------------------------------------------------------------- @@ -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 ----------------------------------------------------------------- @@ -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.@@ -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 ----------------------------------------------------------------------- @@ -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.@@ -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));