chore: scaffold minimal NIH-plug template

Based on musiikki/codename-206 patterns. Provides a clean, minimal
skeleton for new nih-plug audio plugins:

- Cargo.toml with pinned NIH-plug deps (same rev as codename-206)
- src/lib.rs — skeleton plugin with Params, Plugin impl, CLAP/VST3
- xtask/ — bundler xtask (cargo xtask bundle)
- bundler.toml — placeholder for bundle name
- .cargo/config.toml — xtask alias
- .gitignore — /target, /nih-plug, /_template
- LICENSE — Apache-2.0
- README.md — build and deploy instructions
This commit is contained in:
2026-08-21 13:07:09 +09:00
parent b0e1bee433
commit 4700376bc8
7 changed files with 193 additions and 17 deletions
+136
View File
@@ -0,0 +1,136 @@
// SPDX-License-Identifier: Apache-2.0
use nih_plug::prelude::*;
use std::sync::Arc;
// ──────────────────────────────────────────────
// Params — add your plugin parameters here.
// See musiikki/codename-206/src/params.rs for a real example.
// ──────────────────────────────────────────────
struct PluginParams;
impl Params for PluginParams {
fn as_slice(&self) -> &[AtomicParam] {
&[]
}
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
}
}
// ──────────────────────────────────────────────
// Plugin
// ──────────────────────────────────────────────
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";
const VENDOR: &'static str = "Your Name";
const URL: &'static str = env!("CARGO_PKG_HOMEPAGE");
const EMAIL: &'static str = "your@email.com";
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 MIDI_INPUT: MidiConfig = MidiConfig::None;
const MIDI_OUTPUT: MidiConfig = MidiConfig::None;
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
type SysSysexMessage = ();
type BackgroundTask = ();
fn params(&self) -> Arc<dyn Params> {
self.params.clone()
}
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
}
fn initialize(
&mut self,
_audio_io_layout: &AudioIOLayout,
_buffer_config: &BufferConfig,
_context: &mut impl InitContext<Self>,
) -> bool {
true
}
fn reset(&mut self) {}
fn process(
&mut self,
buffer: &mut Buffer,
_aux: &mut AuxiliaryBuffers,
_context: &mut impl ProcessContext<Self>,
) -> ProcessStatus {
// TODO: Implement your DSP here.
// This is a passthrough — replace with your audio processing.
for mut frame in buffer.iter_samples() {
for ch in 0..frame.len() {
*frame.get_mut(ch).unwrap() = *frame.get(ch).unwrap();
}
}
ProcessStatus::Normal
}
}
impl ClapPlugin for MyPlugin {
// TODO: Replace with a unique CLAP ID, e.g. "com.your-domain.your-plugin-name"
const CLAP_ID: &'static str = "com.your-domain.plugin-name";
const CLAP_DESCRIPTION: Option<&'static str> = Some("Your plugin description");
const CLAP_MANUAL_URL: Option<&'static str> = Some(Self::URL);
const CLAP_SUPPORT_URL: Option<&'static str> = None;
const CLAP_FEATURES: &'static [ClapFeature] = &[ClapFeature::AudioEffect];
}
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];
}
nih_export_clap!(MyPlugin);
nih_export_vst3!(MyPlugin);