fix: rewrite the plugin skeleton against the pinned NIH-plug API
The scaffold did not compile. src/lib.rs was written against an API that does not exist at the pinned rev (f36931f): - `impl Params` declared six methods that are not trait members (`as_slice`, `param_by_id`, `param_by_name` and their `_mut` pairs) over two types that appear nowhere in the crate (`AtomicParam`, `ParamId`). The real trait is `unsafe trait Params` with one required method, `param_map`, and is meant to be derived rather than hand-written. - `type SysSysexMessage` misspells the associated type `SysExMessage`. - `ChannelSamples` has no immutable `get`, so the passthrough loop's `*frame.get_mut(ch).unwrap() = *frame.get(ch).unwrap()` could not resolve. Replaced with `#[derive(Params)]` over an example gain parameter, so the skeleton demonstrates the smoother and dB formatters a real plugin needs instead of leaving an empty struct that teaches nothing. The passthrough loop becomes an actual gain application for the same reason. `editor()` is wired to a real `create_egui_editor` window in the same change rather than a follow-up: nih_plug_egui was already a declared dependency that nothing used, and the persisted `editor_state` field the editor needs is part of the same params struct being rewritten here. Splitting them would leave a commit whose params struct exists only to serve an editor that is not there yet. Verified against a local checkout of nih-plug at the pinned rev rather than from memory, and confirmed by building. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WHt4DykxXaQnyaJfyS8KCn
This commit is contained in:
+56
-48
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nih_plug::prelude::*;
|
||||
use nih_plug_egui::{create_egui_editor, egui, widgets, EguiState};
|
||||
use std::sync::Arc;
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
@@ -8,31 +9,36 @@ use std::sync::Arc;
|
||||
// See musiikki/codename-206/src/params.rs for a real example.
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
struct PluginParams;
|
||||
#[derive(Params)]
|
||||
struct PluginParams {
|
||||
/// Editor window size, persisted with the plugin state.
|
||||
#[persist = "editor-state"]
|
||||
editor_state: Arc<EguiState>,
|
||||
|
||||
impl Params for PluginParams {
|
||||
fn as_slice(&self) -> &[AtomicParam] {
|
||||
&[]
|
||||
}
|
||||
/// Example parameter — replace with your own. The `id` is the stable key the host
|
||||
/// stores automation against, so never change it once you've shipped.
|
||||
#[id = "gain"]
|
||||
gain: FloatParam,
|
||||
}
|
||||
|
||||
fn as_mut_slice(&mut self) -> &mut [AtomicParam] {
|
||||
&mut []
|
||||
}
|
||||
|
||||
fn param_by_id(&self, _id: ParamId) -> Option<&AtomicParam> {
|
||||
None
|
||||
}
|
||||
|
||||
fn param_by_id_mut(&mut self, _id: ParamId) -> Option<&mut AtomicParam> {
|
||||
None
|
||||
}
|
||||
|
||||
fn param_by_name(&self, _name: &str) -> Option<&AtomicParam> {
|
||||
None
|
||||
}
|
||||
|
||||
fn param_by_name_mut(&mut self, _name: &str) -> Option<&mut AtomicParam> {
|
||||
None
|
||||
impl Default for PluginParams {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
editor_state: EguiState::from_size(320, 160),
|
||||
gain: FloatParam::new(
|
||||
"Gain",
|
||||
util::db_to_gain(0.0),
|
||||
FloatRange::Skewed {
|
||||
min: util::db_to_gain(-30.0),
|
||||
max: util::db_to_gain(30.0),
|
||||
factor: FloatRange::gain_skew_factor(-30.0, 30.0),
|
||||
},
|
||||
)
|
||||
.with_smoother(SmoothingStyle::Logarithmic(50.0))
|
||||
.with_unit(" dB")
|
||||
.with_value_to_string(formatters::v2s_f32_gain_to_db(2))
|
||||
.with_string_to_value(formatters::s2v_f32_gain_to_db()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,18 +46,11 @@ impl Params for PluginParams {
|
||||
// Plugin
|
||||
// ──────────────────────────────────────────────
|
||||
|
||||
#[derive(Default)]
|
||||
struct MyPlugin {
|
||||
params: Arc<PluginParams>,
|
||||
}
|
||||
|
||||
impl Default for MyPlugin {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
params: Arc::new(PluginParams),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for MyPlugin {
|
||||
// TODO: Replace these placeholder values with your plugin's metadata.
|
||||
const NAME: &'static str = "Plugin Name";
|
||||
@@ -61,20 +60,18 @@ impl Plugin for MyPlugin {
|
||||
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
const AUDIO_IO_LAYOUTS: &'static [AudioIOLayout] = &[
|
||||
AudioIOLayout {
|
||||
main_input_channels: NonZeroU32::new(2),
|
||||
main_output_channels: NonZeroU32::new(2),
|
||||
..AudioIOLayout::const_default()
|
||||
},
|
||||
];
|
||||
const AUDIO_IO_LAYOUTS: &'static [AudioIOLayout] = &[AudioIOLayout {
|
||||
main_input_channels: NonZeroU32::new(2),
|
||||
main_output_channels: NonZeroU32::new(2),
|
||||
..AudioIOLayout::const_default()
|
||||
}];
|
||||
|
||||
const MIDI_INPUT: MidiConfig = MidiConfig::None;
|
||||
const MIDI_OUTPUT: MidiConfig = MidiConfig::None;
|
||||
|
||||
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
|
||||
|
||||
type SysSysexMessage = ();
|
||||
type SysExMessage = ();
|
||||
type BackgroundTask = ();
|
||||
|
||||
fn params(&self) -> Arc<dyn Params> {
|
||||
@@ -82,9 +79,19 @@ impl Plugin for MyPlugin {
|
||||
}
|
||||
|
||||
fn editor(&mut self, _async_executor: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
|
||||
// TODO: Implement your egui editor here.
|
||||
// return Some(Box::new(MyEditor::new(self.params.clone())));
|
||||
None
|
||||
// TODO: Build your own egui layout here.
|
||||
let params = self.params.clone();
|
||||
create_egui_editor(
|
||||
self.params.editor_state.clone(),
|
||||
(),
|
||||
|_, _| {},
|
||||
move |egui_ctx, setter, _state| {
|
||||
egui::CentralPanel::default().show(egui_ctx, |ui| {
|
||||
ui.label("Gain");
|
||||
ui.add(widgets::ParamSlider::for_param(¶ms.gain, setter));
|
||||
});
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
@@ -104,13 +111,15 @@ impl Plugin for MyPlugin {
|
||||
_aux: &mut AuxiliaryBuffers,
|
||||
_context: &mut impl ProcessContext<Self>,
|
||||
) -> ProcessStatus {
|
||||
// TODO: Implement your DSP here.
|
||||
// This is a passthrough — replace with your audio processing.
|
||||
// TODO: Implement your DSP here. This applies the example gain parameter; note that
|
||||
// the smoother is advanced once per frame so automation doesn't zipper.
|
||||
for mut frame in buffer.iter_samples() {
|
||||
for ch in 0..frame.len() {
|
||||
*frame.get_mut(ch).unwrap() = *frame.get(ch).unwrap();
|
||||
let gain = self.params.gain.smoothed.next();
|
||||
for sample in frame.iter_mut() {
|
||||
*sample *= gain;
|
||||
}
|
||||
}
|
||||
|
||||
ProcessStatus::Normal
|
||||
}
|
||||
}
|
||||
@@ -128,8 +137,7 @@ impl Vst3Plugin for MyPlugin {
|
||||
// TODO: Replace with a unique 16-byte Class ID.
|
||||
// Must be exactly 16 bytes — padded with '!' if shorter.
|
||||
const VST3_CLASS_ID: [u8; 16] = *b"Unique16CharId!!";
|
||||
const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
|
||||
&[Vst3SubCategory::Fx];
|
||||
const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[Vst3SubCategory::Fx];
|
||||
}
|
||||
|
||||
nih_export_clap!(MyPlugin);
|
||||
|
||||
Reference in New Issue
Block a user