NeuralAmpModeler-rs 3.0.2

An opinionated, high-performance Neural Amp Modeler (NAM) client and core implementation in Rust for Linux/PipeWire and CLAP plugins.
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2026 Fábio Henrique de Lima Silva (fhl.bsb@gmail.com) All rights reserved.
//! Zone 2 (center): Controls — Input Gain, Output Gain, Gate Threshold knobs,
//! and Oversampling segmented control.

use crate::clap::plugin::NamClapShared;
use clack_plugin::host::HostSharedHandle;
use std::sync::atomic::Ordering;

use crate::clap::gui::ui::{
    colors::{COL_AMBER, resolve_color},
    knob::handle_knob,
};

pub(crate) fn draw_zone2_controls(
    ui: &mut egui::Ui,
    shared: &NamClapShared,
    host: &HostSharedHandle,
    current_bypass: bool,
    accent_color: egui::Color32,
) {
    ui.allocate_ui(egui::vec2(240.0, 250.0), |ui| {
        if current_bypass {
            ui.disable();
        }
        ui.vertical(|ui| {
            ui.add_space(12.0);
            let ind_input = shared.cold.param_indication
                [crate::clap::extensions::params::PARAM_INPUT_GAIN as usize]
                .load(Ordering::Relaxed);
            let ind_input_color = resolve_color(
                shared.cold.param_indication_color
                    [crate::clap::extensions::params::PARAM_INPUT_GAIN as usize]
                    .load(Ordering::Relaxed),
                egui::Color32::from_rgb(94, 129, 172),
            );

            let ind_output = shared.cold.param_indication
                [crate::clap::extensions::params::PARAM_OUTPUT_GAIN as usize]
                .load(Ordering::Relaxed);
            let ind_output_color = resolve_color(
                shared.cold.param_indication_color
                    [crate::clap::extensions::params::PARAM_OUTPUT_GAIN as usize]
                    .load(Ordering::Relaxed),
                egui::Color32::from_rgb(94, 129, 172),
            );

            let ind_gate = shared.cold.param_indication
                [crate::clap::extensions::params::PARAM_GATE_THRESH as usize]
                .load(Ordering::Relaxed);
            let ind_gate_color = resolve_color(
                shared.cold.param_indication_color
                    [crate::clap::extensions::params::PARAM_GATE_THRESH as usize]
                    .load(Ordering::Relaxed),
                egui::Color32::from_rgb(94, 129, 172),
            );

            ui.horizontal(|ui| {
                ui.allocate_ui(egui::vec2(78.0, 125.0), |ui| {
                    handle_knob(
                        ui,
                        ui.make_persistent_id("input_gain_knob"),
                        "INPUT",
                        crate::math::constants::GAIN_MIN_DB..=crate::math::constants::GAIN_MAX_DB,
                        0.0,
                        &shared.ui_to_rt.param_input_gain,
                        &shared.ui_to_rt.gesture_flags,
                        &shared.ui_to_rt.gui_param_generation,
                        crate::clap::extensions::params::PARAM_INPUT_GAIN as usize,
                        accent_color,
                        accent_color,
                        host,
                        egui::vec2(70.0, 70.0),
                        ind_input,
                        ind_input_color,
                        " dB",
                    );
                });
                ui.add_space(2.0);
                ui.allocate_ui(egui::vec2(78.0, 125.0), |ui| {
                    handle_knob(
                        ui,
                        ui.make_persistent_id("output_gain_knob"),
                        "OUTPUT",
                        crate::math::constants::GAIN_MIN_DB..=crate::math::constants::GAIN_MAX_DB,
                        0.0,
                        &shared.ui_to_rt.param_output_gain,
                        &shared.ui_to_rt.gesture_flags,
                        &shared.ui_to_rt.gui_param_generation,
                        crate::clap::extensions::params::PARAM_OUTPUT_GAIN as usize,
                        accent_color,
                        accent_color,
                        host,
                        egui::vec2(70.0, 70.0),
                        ind_output,
                        ind_output_color,
                        " dB",
                    );
                });
                ui.add_space(2.0);
                ui.allocate_ui(egui::vec2(70.0, 125.0), |ui| {
                    handle_knob(
                        ui,
                        ui.make_persistent_id("gate_thresh_knob"),
                        "GATE",
                        -90.0..=-40.0,
                        -70.0,
                        &shared.ui_to_rt.param_gate_thresh,
                        &shared.ui_to_rt.gesture_flags,
                        &shared.ui_to_rt.gui_param_generation,
                        crate::clap::extensions::params::PARAM_GATE_THRESH as usize,
                        COL_AMBER,
                        accent_color,
                        host,
                        egui::vec2(42.0, 42.0),
                        ind_gate,
                        ind_gate_color,
                        " dB (Threshold)",
                    );
                });
            });

            // Oversampling segmented control
            ui.add_space(4.0);
            let ind_os = shared.cold.param_indication
                [crate::clap::extensions::params::PARAM_OVERSAMPLE as usize]
                .load(Ordering::Relaxed);
            let ind_os_color = resolve_color(
                shared.cold.param_indication_color
                    [crate::clap::extensions::params::PARAM_OVERSAMPLE as usize]
                    .load(Ordering::Relaxed),
                accent_color,
            );
            let os_val = shared.ui_to_rt.param_oversample.load(Ordering::Relaxed);
            let os_val_i32 = os_val as i32;

            ui.allocate_ui(egui::vec2(210.0, 26.0), |ui| {
                ui.horizontal_centered(|ui| {
                    ui.label(
                        egui::RichText::new("Oversampling")
                            .font(egui::FontId::proportional(10.0))
                            .color(egui::Color32::GRAY),
                    );
                    let resp = ui.selectable_value(
                        &mut (os_val_i32 == 0),
                        true,
                        egui::RichText::new("Off").font(egui::FontId::proportional(11.0)),
                    );
                    if resp.clicked() && os_val_i32 != 0 {
                        shared.ui_to_rt.param_oversample.store(0, Ordering::Relaxed);
                        shared.set_gesture(
                            crate::clap::extensions::params::PARAM_OVERSAMPLE as usize,
                            0,
                        );
                        shared.bump_generation();
                    }
                    let resp = ui.selectable_value(
                        &mut (os_val_i32 == 1),
                        true,
                        egui::RichText::new("").font(egui::FontId::proportional(11.0)),
                    );
                    if resp.clicked() && os_val_i32 != 1 {
                        shared.ui_to_rt.param_oversample.store(1, Ordering::Relaxed);
                        shared.set_gesture(
                            crate::clap::extensions::params::PARAM_OVERSAMPLE as usize,
                            0,
                        );
                        shared.bump_generation();
                    }
                    let resp = ui.selectable_value(
                        &mut (os_val_i32 == 2),
                        true,
                        egui::RichText::new("").font(egui::FontId::proportional(11.0)),
                    );
                    if resp.clicked() && os_val_i32 != 2 {
                        shared.ui_to_rt.param_oversample.store(2, Ordering::Relaxed);
                        shared.set_gesture(
                            crate::clap::extensions::params::PARAM_OVERSAMPLE as usize,
                            0,
                        );
                        shared.bump_generation();
                    }
                });
                if ind_os & 1 != 0 {
                    let painter = ui.painter();
                    let rect = ui.min_rect();
                    let dots = [
                        egui::pos2(rect.left() + 4.0, rect.top() + 4.0),
                        egui::pos2(rect.right() - 4.0, rect.top() + 4.0),
                        egui::pos2(rect.left() + 4.0, rect.bottom() - 4.0),
                        egui::pos2(rect.right() - 4.0, rect.bottom() - 4.0),
                    ];
                    for dot in dots {
                        painter.circle_filled(dot, 1.5, ind_os_color);
                    }
                }
            });

            // Activation Precision segmented control
            ui.add_space(4.0);
            let ind_act = shared.cold.param_indication
                [crate::clap::extensions::params::PARAM_ACTIVATION as usize]
                .load(Ordering::Relaxed);
            let ind_act_color = resolve_color(
                shared.cold.param_indication_color
                    [crate::clap::extensions::params::PARAM_ACTIVATION as usize]
                    .load(Ordering::Relaxed),
                accent_color,
            );
            let act_val = shared.ui_to_rt.param_activation.load(Ordering::Relaxed);
            let act_val_i32 = act_val as i32;

            ui.allocate_ui(egui::vec2(210.0, 26.0), |ui| {
                ui.horizontal_centered(|ui| {
                    ui.label(
                        egui::RichText::new("Activation")
                            .font(egui::FontId::proportional(10.0))
                            .color(egui::Color32::GRAY),
                    );
                    // Value 1 = Standard (exact-grade, universal default);
                    // Value 0 = Fast (Padé/minimax approximation, opt-in).
                    let resp = ui.selectable_value(
                        &mut (act_val_i32 == 1),
                        true,
                        egui::RichText::new("Standard").font(egui::FontId::proportional(11.0)),
                    );
                    if resp.clicked() && act_val_i32 != 1 {
                        shared.ui_to_rt.param_activation.store(1, Ordering::Relaxed);
                        shared.set_gesture(
                            crate::clap::extensions::params::PARAM_ACTIVATION as usize,
                            0,
                        );
                        shared.bump_generation();
                    }
                    let resp = ui.selectable_value(
                        &mut (act_val_i32 == 0),
                        true,
                        egui::RichText::new("Fast").font(egui::FontId::proportional(11.0)),
                    );
                    if resp.clicked() && act_val_i32 != 0 {
                        shared.ui_to_rt.param_activation.store(0, Ordering::Relaxed);
                        shared.set_gesture(
                            crate::clap::extensions::params::PARAM_ACTIVATION as usize,
                            0,
                        );
                        shared.bump_generation();
                    }
                });
                if ind_act & 1 != 0 {
                    let painter = ui.painter();
                    let rect = ui.min_rect();
                    let dots = [
                        egui::pos2(rect.left() + 4.0, rect.top() + 4.0),
                        egui::pos2(rect.right() - 4.0, rect.top() + 4.0),
                        egui::pos2(rect.left() + 4.0, rect.bottom() - 4.0),
                        egui::pos2(rect.right() - 4.0, rect.bottom() - 4.0),
                    ];
                    for dot in dots {
                        painter.circle_filled(dot, 1.5, ind_act_color);
                    }
                }
            });
        });
    });
}