1
0
Fork 0

Replace VST3 category string with enum slice

I've been putting this off for a while, but now is finally the day. We
already did this for CLAP a while back. This is both simpler and less
error prone.
This commit is contained in:
Robbert van der Helm 2023-02-01 16:09:03 +01:00
parent 7fe339987a
commit d6184ea06e
23 changed files with 91 additions and 38 deletions

View file

@ -6,6 +6,14 @@ new and what's changed, this document lists all breaking changes in reverse
chronological order. If a new feature did not require any changes to existing chronological order. If a new feature did not require any changes to existing
code then it will not be listed here. code then it will not be listed here.
## [2023-02-01]
- The `Vst3Plugin::VST3_CATEGORIES` string constant has been replaced by a
`Vst3Plugin::VST3_SUBCATEGORIES` constant of type `&[Vst3SubCategory]`.
`Vst3SubCategory` is an enum containing all of VST3's predefined categories,
and it behaves similarly to the `ClapFeature` enum used for CLAP plugins. This
makes defining subcategories for VST3 plugins easier and less error prone.
## [2023-01-31] ## [2023-01-31]
- NIH-plug has gained support MIDI SysEx in a simple, type-safe, and - NIH-plug has gained support MIDI SysEx in a simple, type-safe, and

View file

@ -431,6 +431,7 @@ impl ClapPlugin for BuffrGlitch {
const CLAP_SUPPORT_URL: Option<&'static str> = None; const CLAP_SUPPORT_URL: Option<&'static str> = None;
const CLAP_FEATURES: &'static [ClapFeature] = &[ const CLAP_FEATURES: &'static [ClapFeature] = &[
ClapFeature::AudioEffect, ClapFeature::AudioEffect,
ClapFeature::Synthesizer,
ClapFeature::Stereo, ClapFeature::Stereo,
ClapFeature::Glitch, ClapFeature::Glitch,
]; ];
@ -438,7 +439,11 @@ impl ClapPlugin for BuffrGlitch {
impl Vst3Plugin for BuffrGlitch { impl Vst3Plugin for BuffrGlitch {
const VST3_CLASS_ID: [u8; 16] = *b"BuffrGlitch.RvdH"; const VST3_CLASS_ID: [u8; 16] = *b"BuffrGlitch.RvdH";
const VST3_CATEGORIES: &'static str = "Fx"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[
Vst3SubCategory::Fx,
Vst3SubCategory::Synth,
Vst3SubCategory::Custom("Glitch"),
];
} }
nih_export_clap!(BuffrGlitch); nih_export_clap!(BuffrGlitch);

View file

@ -507,7 +507,11 @@ impl ClapPlugin for Crisp {
impl Vst3Plugin for Crisp { impl Vst3Plugin for Crisp {
const VST3_CLASS_ID: [u8; 16] = *b"CrispPluginRvdH."; const VST3_CLASS_ID: [u8; 16] = *b"CrispPluginRvdH.";
const VST3_CATEGORIES: &'static str = "Fx|Filter|Distortion"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[
Vst3SubCategory::Fx,
Vst3SubCategory::Filter,
Vst3SubCategory::Distortion,
];
} }
nih_export_clap!(Crisp); nih_export_clap!(Crisp);

View file

@ -401,7 +401,8 @@ impl ClapPlugin for Crossover {
impl Vst3Plugin for Crossover { impl Vst3Plugin for Crossover {
const VST3_CLASS_ID: [u8; 16] = *b"CrossoverRvdH..."; const VST3_CLASS_ID: [u8; 16] = *b"CrossoverRvdH...";
const VST3_CATEGORIES: &'static str = "Fx|Tools"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Fx, Vst3SubCategory::Tools];
} }
nih_export_clap!(Crossover); nih_export_clap!(Crossover);

View file

@ -355,7 +355,8 @@ impl ClapPlugin for Diopser {
impl Vst3Plugin for Diopser { impl Vst3Plugin for Diopser {
const VST3_CLASS_ID: [u8; 16] = *b"DiopserPlugRvdH."; const VST3_CLASS_ID: [u8; 16] = *b"DiopserPlugRvdH.";
const VST3_CATEGORIES: &'static str = "Fx|Filter"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Fx, Vst3SubCategory::Filter];
} }
nih_export_clap!(Diopser); nih_export_clap!(Diopser);

View file

@ -195,7 +195,8 @@ impl ClapPlugin for Gain {
impl Vst3Plugin for Gain { impl Vst3Plugin for Gain {
const VST3_CLASS_ID: [u8; 16] = *b"GainMoistestPlug"; const VST3_CLASS_ID: [u8; 16] = *b"GainMoistestPlug";
const VST3_CATEGORIES: &'static str = "Fx|Dynamics"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Fx, Vst3SubCategory::Tools];
} }
nih_export_clap!(Gain); nih_export_clap!(Gain);

View file

@ -225,7 +225,8 @@ impl ClapPlugin for Gain {
impl Vst3Plugin for Gain { impl Vst3Plugin for Gain {
const VST3_CLASS_ID: [u8; 16] = *b"GainGuiYeahBoyyy"; const VST3_CLASS_ID: [u8; 16] = *b"GainGuiYeahBoyyy";
const VST3_CATEGORIES: &'static str = "Fx|Dynamics"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Fx, Vst3SubCategory::Tools];
} }
nih_export_clap!(Gain); nih_export_clap!(Gain);

View file

@ -167,7 +167,8 @@ impl ClapPlugin for Gain {
impl Vst3Plugin for Gain { impl Vst3Plugin for Gain {
const VST3_CLASS_ID: [u8; 16] = *b"GainGuiIcedAaAAa"; const VST3_CLASS_ID: [u8; 16] = *b"GainGuiIcedAaAAa";
const VST3_CATEGORIES: &'static str = "Fx|Dynamics"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Fx, Vst3SubCategory::Tools];
} }
nih_export_clap!(Gain); nih_export_clap!(Gain);

View file

@ -166,7 +166,8 @@ impl ClapPlugin for Gain {
impl Vst3Plugin for Gain { impl Vst3Plugin for Gain {
const VST3_CLASS_ID: [u8; 16] = *b"GainGuiVIIIZIAAA"; const VST3_CLASS_ID: [u8; 16] = *b"GainGuiVIIIZIAAA";
const VST3_CATEGORIES: &'static str = "Fx|Dynamics"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Fx, Vst3SubCategory::Tools];
} }
nih_export_clap!(Gain); nih_export_clap!(Gain);

View file

@ -227,7 +227,8 @@ impl ClapPlugin for MidiInverter {
impl Vst3Plugin for MidiInverter { impl Vst3Plugin for MidiInverter {
const VST3_CLASS_ID: [u8; 16] = *b"M1d1Inv3r70rzAaA"; const VST3_CLASS_ID: [u8; 16] = *b"M1d1Inv3r70rzAaA";
const VST3_CATEGORIES: &'static str = "Instrument|Tools"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Instrument, Vst3SubCategory::Tools];
} }
nih_export_clap!(MidiInverter); nih_export_clap!(MidiInverter);

View file

@ -612,7 +612,8 @@ impl ClapPlugin for PolyModSynth {
// modulation // modulation
impl Vst3Plugin for PolyModSynth { impl Vst3Plugin for PolyModSynth {
const VST3_CLASS_ID: [u8; 16] = *b"PolyM0dSynth1337"; const VST3_CLASS_ID: [u8; 16] = *b"PolyM0dSynth1337";
const VST3_CATEGORIES: &'static str = "Instrument|Synth"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Instrument, Vst3SubCategory::Synth];
} }
nih_export_clap!(PolyModSynth); nih_export_clap!(PolyModSynth);

View file

@ -213,7 +213,11 @@ impl ClapPlugin for Sine {
impl Vst3Plugin for Sine { impl Vst3Plugin for Sine {
const VST3_CLASS_ID: [u8; 16] = *b"SineMoistestPlug"; const VST3_CLASS_ID: [u8; 16] = *b"SineMoistestPlug";
const VST3_CATEGORIES: &'static str = "Instrument|Synth|Tools"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[
Vst3SubCategory::Instrument,
Vst3SubCategory::Synth,
Vst3SubCategory::Tools,
];
} }
nih_export_clap!(Sine); nih_export_clap!(Sine);

View file

@ -179,7 +179,8 @@ impl ClapPlugin for Stft {
impl Vst3Plugin for Stft { impl Vst3Plugin for Stft {
const VST3_CLASS_ID: [u8; 16] = *b"StftMoistestPlug"; const VST3_CLASS_ID: [u8; 16] = *b"StftMoistestPlug";
const VST3_CATEGORIES: &'static str = "Fx|Tools"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Fx, Vst3SubCategory::Tools];
} }
nih_export_clap!(Stft); nih_export_clap!(Stft);

View file

@ -102,7 +102,11 @@ impl ClapPlugin for SysEx {
impl Vst3Plugin for SysEx { impl Vst3Plugin for SysEx {
const VST3_CLASS_ID: [u8; 16] = *b"SysExCoolPluginn"; const VST3_CLASS_ID: [u8; 16] = *b"SysExCoolPluginn";
const VST3_CATEGORIES: &'static str = "Fx|Instrument|Tools"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[
Vst3SubCategory::Fx,
Vst3SubCategory::Instrument,
Vst3SubCategory::Tools,
];
} }
nih_export_clap!(SysEx); nih_export_clap!(SysEx);

View file

@ -261,7 +261,12 @@ impl ClapPlugin for LoudnessWarWinner {
impl Vst3Plugin for LoudnessWarWinner { impl Vst3Plugin for LoudnessWarWinner {
const VST3_CLASS_ID: [u8; 16] = *b"LoudnessWar.RvdH"; const VST3_CLASS_ID: [u8; 16] = *b"LoudnessWar.RvdH";
const VST3_CATEGORIES: &'static str = "Fx|Dynamics|Distortion"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[
Vst3SubCategory::Fx,
Vst3SubCategory::Dynamics,
Vst3SubCategory::Distortion,
Vst3SubCategory::Custom("Pain"),
];
} }
nih_export_clap!(LoudnessWarWinner); nih_export_clap!(LoudnessWarWinner);

View file

@ -431,7 +431,8 @@ impl ClapPlugin for PubertySimulator {
impl Vst3Plugin for PubertySimulator { impl Vst3Plugin for PubertySimulator {
const VST3_CLASS_ID: [u8; 16] = *b"PubertySim..RvdH"; const VST3_CLASS_ID: [u8; 16] = *b"PubertySim..RvdH";
const VST3_CATEGORIES: &'static str = "Fx|Pitch Shift"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Fx, Vst3SubCategory::PitchShift];
} }
nih_export_clap!(PubertySimulator); nih_export_clap!(PubertySimulator);

View file

@ -340,7 +340,8 @@ impl ClapPlugin for SafetyLimiter {
impl Vst3Plugin for SafetyLimiter { impl Vst3Plugin for SafetyLimiter {
const VST3_CLASS_ID: [u8; 16] = *b"SafetyLimtrRvdH."; const VST3_CLASS_ID: [u8; 16] = *b"SafetyLimtrRvdH.";
const VST3_CATEGORIES: &'static str = "Fx|Tools"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Fx, Vst3SubCategory::Tools];
} }
nih_export_clap!(SafetyLimiter); nih_export_clap!(SafetyLimiter);

View file

@ -581,7 +581,11 @@ impl ClapPlugin for SpectralCompressor {
impl Vst3Plugin for SpectralCompressor { impl Vst3Plugin for SpectralCompressor {
const VST3_CLASS_ID: [u8; 16] = *b"SpectrlComprRvdH"; const VST3_CLASS_ID: [u8; 16] = *b"SpectrlComprRvdH";
const VST3_CATEGORIES: &'static str = "Fx|Dynamics|Spectral"; const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = &[
Vst3SubCategory::Fx,
Vst3SubCategory::Dynamics,
Vst3SubCategory::Custom("Spectral"),
];
} }
nih_export_clap!(SpectralCompressor); nih_export_clap!(SpectralCompressor);

View file

@ -12,6 +12,7 @@ use crate::midi::MidiConfig;
use crate::params::Params; use crate::params::Params;
use crate::wrapper::clap::features::ClapFeature; use crate::wrapper::clap::features::ClapFeature;
use crate::wrapper::state::PluginState; use crate::wrapper::state::PluginState;
pub use crate::wrapper::vst3::subcategories::Vst3SubCategory;
/// A function that can execute a plugin's [`BackgroundTask`][Plugin::BackgroundTask]s. A plugin can /// A function that can execute a plugin's [`BackgroundTask`][Plugin::BackgroundTask]s. A plugin can
/// dispatch these tasks from the `initialize()` function, the `process()` function, or the GUI, so /// dispatch these tasks from the `initialize()` function, the `process()` function, or the GUI, so
@ -249,12 +250,11 @@ pub trait Vst3Plugin: Plugin {
/// ///
/// This will be shuffled into a different byte order on Windows for project-compatibility. /// This will be shuffled into a different byte order on Windows for project-compatibility.
const VST3_CLASS_ID: [u8; 16]; const VST3_CLASS_ID: [u8; 16];
/// One or more categories, separated by pipe characters (`|`), up to 127 characters. Anything /// One or more subcategories. The host may use these to categorize the plugin. Internally this
/// longer than that will be truncated. See the VST3 SDK for examples of common categories: /// slice will be converted to a string where each character is separated by a pipe character
/// <https://github.com/steinbergmedia/vst3_pluginterfaces/blob/2ad397ade5b51007860bedb3b01b8afd2c5f6fba/vst/ivstaudioprocessor.h#L49-L90> /// (`|`). This string has a limit of 127 characters, and anything longer than that will be
// /// truncated.
// TODO: Create a category enum similar to ClapFeature const VST3_SUBCATEGORIES: &'static [Vst3SubCategory];
const VST3_CATEGORIES: &'static str;
/// [`VST3_CLASS_ID`][Self::VST3_CLASS_ID`] in the correct order for the current platform so /// [`VST3_CLASS_ID`][Self::VST3_CLASS_ID`] in the correct order for the current platform so
/// projects and presets can be shared between platforms. This should not be overridden. /// projects and presets can be shared between platforms. This should not be overridden.

View file

@ -30,3 +30,4 @@ pub use crate::plugin::{
}; };
pub use crate::wrapper::clap::features::ClapFeature; pub use crate::wrapper::clap::features::ClapFeature;
pub use crate::wrapper::state::PluginState; pub use crate::wrapper::state::PluginState;
pub use crate::wrapper::vst3::subcategories::Vst3SubCategory;

View file

@ -4,6 +4,7 @@
/// A keyword for a CLAP plugin. See /// A keyword for a CLAP plugin. See
/// <https://github.com/free-audio/clap/blob/main/include/clap/plugin-features.h> for more /// <https://github.com/free-audio/clap/blob/main/include/clap/plugin-features.h> for more
/// information. /// information.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClapFeature { pub enum ClapFeature {
// These are the main categories, every plugin should have at least one of these // These are the main categories, every plugin should have at least one of these
Instrument, Instrument,

View file

@ -8,6 +8,7 @@ use vst3_sys::VST3;
// Alias needed for the VST3 attribute macro // Alias needed for the VST3 attribute macro
use vst3_sys as vst3_com; use vst3_sys as vst3_com;
use super::subcategories::Vst3SubCategory;
use super::util::u16strlcpy; use super::util::u16strlcpy;
use super::wrapper::Wrapper; use super::wrapper::Wrapper;
use crate::plugin::Vst3Plugin; use crate::plugin::Vst3Plugin;
@ -102,20 +103,7 @@ impl<P: Vst3Plugin> IPluginFactory2 for Factory<P> {
strlcpy(&mut info.category, "Audio Module Class"); strlcpy(&mut info.category, "Audio Module Class");
strlcpy(&mut info.name, P::NAME); strlcpy(&mut info.name, P::NAME);
info.class_flags = 1 << 1; // kSimpleModeSupported info.class_flags = 1 << 1; // kSimpleModeSupported
strlcpy(&mut info.subcategories, &make_subcategories_string::<P>());
// No idea if any hosts do something with this, but it's part of VST3's example categories
// list
if P::HARD_REALTIME_ONLY {
nih_debug_assert!(!P::VST3_CATEGORIES.ends_with('|'));
nih_debug_assert!(!P::VST3_CATEGORIES.contains("OnlyRT"));
strlcpy(
&mut info.subcategories,
&format!("{}|OnlyRT", P::VST3_CATEGORIES),
);
} else {
strlcpy(&mut info.subcategories, P::VST3_CATEGORIES);
};
strlcpy(&mut info.vendor, P::VENDOR); strlcpy(&mut info.vendor, P::VENDOR);
strlcpy(&mut info.version, P::VERSION); strlcpy(&mut info.version, P::VERSION);
strlcpy(&mut info.sdk_version, VST3_SDK_VERSION); strlcpy(&mut info.sdk_version, VST3_SDK_VERSION);
@ -142,7 +130,7 @@ impl<P: Vst3Plugin> IPluginFactory3 for Factory<P> {
strlcpy(&mut info.category, "Audio Module Class"); strlcpy(&mut info.category, "Audio Module Class");
u16strlcpy(&mut info.name, P::NAME); u16strlcpy(&mut info.name, P::NAME);
info.class_flags = 1 << 1; // kSimpleModeSupported info.class_flags = 1 << 1; // kSimpleModeSupported
strlcpy(&mut info.subcategories, P::VST3_CATEGORIES); strlcpy(&mut info.subcategories, &make_subcategories_string::<P>());
u16strlcpy(&mut info.vendor, P::VENDOR); u16strlcpy(&mut info.vendor, P::VENDOR);
u16strlcpy(&mut info.version, P::VERSION); u16strlcpy(&mut info.version, P::VERSION);
u16strlcpy(&mut info.sdk_version, VST3_SDK_VERSION); u16strlcpy(&mut info.sdk_version, VST3_SDK_VERSION);
@ -155,3 +143,20 @@ impl<P: Vst3Plugin> IPluginFactory3 for Factory<P> {
kResultOk kResultOk
} }
} }
fn make_subcategories_string<P: Vst3Plugin>() -> String {
// No idea if any hosts do something with OnlyRT, but it's part of VST3's example categories
// list. Plugins should not be adding this feature manually
nih_debug_assert!(!P::VST3_SUBCATEGORIES.contains(&Vst3SubCategory::Custom("OnlyRT")));
let category_string = P::VST3_SUBCATEGORIES
.iter()
.map(Vst3SubCategory::as_str)
.collect::<Vec<&str>>()
.join("|");
if P::HARD_REALTIME_ONLY {
format!("{category_string}|OnlyRT")
} else {
category_string
}
}

View file

@ -5,6 +5,7 @@
/// <https://github.com/steinbergmedia/vst3_pluginterfaces/blob/bc5ff0f87aaa3cd28c114810f4f03c384421ad2c/vst/ivstaudioprocessor.h#L49-L90> /// <https://github.com/steinbergmedia/vst3_pluginterfaces/blob/bc5ff0f87aaa3cd28c114810f4f03c384421ad2c/vst/ivstaudioprocessor.h#L49-L90>
/// for a list of all predefined subcategories. Multiple subcategories are concatenated to a string /// for a list of all predefined subcategories. Multiple subcategories are concatenated to a string
/// separated by pipe characters, and the total length of this string may not exceed 127 characters. /// separated by pipe characters, and the total length of this string may not exceed 127 characters.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Vst3SubCategory { pub enum Vst3SubCategory {
// These are the main categories, every plugin should have at least one of these, I think // These are the main categories, every plugin should have at least one of these, I think
Fx, Fx,