Skip to main content

Descriptor

Trait Descriptor 

Source
pub trait Descriptor: HasParameters + Default {
    type Setup: PluginSetup;
    type Processor: Processor<Descriptor = Self, Parameters = Self::Parameters>;

Show 22 methods // Required method fn prepare(self, setup: Self::Setup) -> Self::Processor; // Provided methods fn input_bus_count(&self) -> usize { ... } fn output_bus_count(&self) -> usize { ... } fn input_bus_info(&self, index: usize) -> Option<BusInfo> { ... } fn output_bus_info(&self, index: usize) -> Option<BusInfo> { ... } fn wants_midi(&self) -> bool { ... } fn midi_cc_to_parameter( &self, bus_index: i32, channel: i16, cc: u8, ) -> Option<u32> { ... } fn midi_cc_config(&self) -> Option<MidiCcConfig> { ... } fn on_midi_learn(&mut self, bus_index: i32, channel: i16, cc: u8) -> bool { ... } fn midi1_assignments(&self) -> &[Midi1Assignment] { ... } fn midi2_assignments(&self) -> &[Midi2Assignment] { ... } fn on_midi1_learn(&mut self, bus_index: i32, channel: u8, cc: u8) -> bool { ... } fn on_midi2_learn( &mut self, bus_index: i32, channel: u8, controller: Midi2Controller, ) -> bool { ... } fn note_expression_count(&self, bus_index: i32, channel: i16) -> usize { ... } fn note_expression_info( &self, bus_index: i32, channel: i16, index: usize, ) -> Option<NoteExpressionTypeInfo> { ... } fn note_expression_value_to_string( &self, bus_index: i32, channel: i16, type_id: u32, value: f64, ) -> String { ... } fn note_expression_string_to_value( &self, bus_index: i32, channel: i16, type_id: u32, string: &str, ) -> Option<f64> { ... } fn keyswitch_count(&self, bus_index: i32, channel: i16) -> usize { ... } fn keyswitch_info( &self, bus_index: i32, channel: i16, index: usize, ) -> Option<KeyswitchInfo> { ... } fn physical_ui_mappings( &self, bus_index: i32, channel: i16, ) -> &[PhysicalUIMap] { ... } fn enable_mpe_input_processing(&mut self, enabled: bool) -> bool { ... } fn set_mpe_input_device_settings( &mut self, settings: MpeInputDeviceSettings, ) -> bool { ... }
}
Expand description

The unprepared plugin definition - holds parameters before audio config is known.

This is the primary trait that plugin authors implement to create a complete audio plugin. It holds parameters and configuration that doesn’t depend on sample rate, and transforms into a Processor via Descriptor::prepare() when audio configuration becomes available.

§Two-Phase Lifecycle

Descriptor::default() -> Descriptor (unprepared, holds parameters)
                     |
                     v  Descriptor::prepare(config)
                     |
                     v
               Processor (prepared, ready for audio)
                     |
                     v  Processor::unprepare()
                     |
                     v
                Descriptor (unprepared, parameters preserved)

§Example: Simple Gain (no setup)

#[derive(Default, HasParameters)]
pub struct GainPlugin {
    #[parameters]
    parameters: GainParameters,
}

impl Descriptor for GainPlugin {
    type Setup = ();
    type Processor = GainProcessor;

    fn prepare(self, _: ()) -> GainProcessor {
        GainProcessor { parameters: self.parameters }
    }
}

#[derive(HasParameters)]
pub struct GainProcessor {
    #[parameters]
    parameters: GainParameters,
}

impl Processor for GainProcessor {
    type Descriptor = GainPlugin;

    fn process(&mut self, buffer: &mut Buffer, _aux: &mut AuxiliaryBuffers, _context: &ProcessContext) {
        let gain = self.parameters.gain_linear();
        for (input, output) in buffer.zip_channels() {
            for (i, o) in input.iter().zip(output.iter_mut()) {
                *o = *i * gain;
            }
        }
    }

    fn unprepare(self) -> GainPlugin {
        GainPlugin { parameters: self.parameters }
    }
}

§Example: Delay (SampleRate)

#[derive(Default, HasParameters)]
pub struct DelayPlugin {
    #[parameters]
    parameters: DelayParameters,
}

impl Descriptor for DelayPlugin {
    type Setup = SampleRate;
    type Processor = DelayProcessor;

    fn prepare(self, setup: SampleRate) -> DelayProcessor {
        let buffer_size = (MAX_DELAY_SECONDS * setup.hz()) as usize;
        DelayProcessor {
            parameters: self.parameters,
            sample_rate: setup.hz(),  // Real value from start!
            buffer: vec![0.0; buffer_size],   // Correct allocation!
        }
    }
}

§Note on HasParameters

The Descriptor trait requires HasParameters as a supertrait, which provides the parameters() and parameters_mut() methods. Use #[derive(HasParameters)] with a #[parameters] field annotation to implement this automatically.

Required Associated Types§

Source

type Setup: PluginSetup

The setup information this plugin needs to prepare.

Request exactly what you need:

  • (): No setup needed (gain, pan)
  • SampleRate: Time-based DSP (delay, filter, envelope) - most common
  • (SampleRate, MaxBufferSize): FFT, lookahead
  • (SampleRate, MainOutputChannels): Surround, per-channel state

See PluginSetup for all available types.

Source

type Processor: Processor<Descriptor = Self, Parameters = Self::Parameters>

The prepared processor type created by Descriptor::prepare().

Required Methods§

Source

fn prepare(self, setup: Self::Setup) -> Self::Processor

Transform this definition into a prepared processor.

This is called when audio configuration becomes available (in VST3, during setupProcessing()). The definition is consumed and transformed into a processor with valid configuration - no placeholder values.

§Arguments
  • setup - The setup information (sample rate, buffer size, layout)
§Returns

A prepared processor ready for audio processing.

Provided Methods§

Source

fn input_bus_count(&self) -> usize

Returns the number of audio input buses.

Default returns 1 (single stereo input).

Source

fn output_bus_count(&self) -> usize

Returns the number of audio output buses.

Default returns 1 (single stereo output).

Source

fn input_bus_info(&self, index: usize) -> Option<BusInfo>

Returns information about an input bus.

Default returns a stereo main bus for index 0.

Source

fn output_bus_info(&self, index: usize) -> Option<BusInfo>

Returns information about an output bus.

Default returns a stereo main bus for index 0.

Source

fn wants_midi(&self) -> bool

Returns whether this plugin processes MIDI events.

Override to return true if your plugin needs MIDI input/output. This is used by the host to determine event bus configuration.

Note: This method is also on Processor, but the Descriptor version is queried during bus configuration (before prepare). Both should return the same value.

Default returns false.

Source

fn midi_cc_to_parameter( &self, bus_index: i32, channel: i16, cc: u8, ) -> Option<u32>

Get the parameter ID mapped to a MIDI CC.

Override this to enable DAW MIDI learn for your parameters. When the DAW queries which parameter is assigned to a MIDI CC, this method is called.

§Arguments
  • bus_index - MIDI bus index (usually 0)
  • channel - MIDI channel (0-15), or -1 to query all channels
  • cc - MIDI CC number (0-127)
§Returns

Some(parameter_id) if this CC is mapped to a parameter, None otherwise.

§Example
fn midi_cc_to_parameter(&self, _bus: i32, _channel: i16, cc: u8) -> Option<u32> {
    match cc {
        cc::MOD_WHEEL => Some(PARAM_VIBRATO_DEPTH),
        cc::EXPRESSION => Some(PARAM_VOLUME),
        _ => None,
    }
}
Source

fn midi_cc_config(&self) -> Option<MidiCcConfig>

Returns MIDI CC configuration for automatic host mapping.

Override to enable MIDI CC/pitch bend/aftertouch reception via IMidiMapping. The framework will:

  1. Create hidden parameters for each enabled controller
  2. Handle IMidiMapping queries from the DAW
  3. Convert parameter changes to MidiEvents in process_midi()
  4. Provide direct CC value access via ProcessContext::midi_cc()

This solves the VST3 MIDI input problem where most DAWs don’t send kLegacyMIDICCOutEvent for input. Instead, they use the IMidiMapping interface to map MIDI controllers to parameters.

§Example
impl Descriptor for MySynth {
    fn midi_cc_config(&self) -> Option<MidiCcConfig> {
        Some(MidiCcConfig::new()
            .with_pitch_bend()
            .with_mod_wheel()
            .with_aftertouch()
            .with_ccs(&[7, 10, 11, 64]))  // Volume, Pan, Expression, Sustain
    }
}

// Access CC values during processing:
fn process(&mut self, buffer: &mut Buffer, _aux: &mut AuxiliaryBuffers, context: &ProcessContext) {
    if let Some(cc) = context.midi_cc() {
        let pitch_bend = cc.pitch_bend();  // -1.0 to 1.0
        let mod_wheel = cc.mod_wheel();    // 0.0 to 1.0
    }
}
Source

fn on_midi_learn(&mut self, bus_index: i32, channel: i16, cc: u8) -> bool

Called by DAW when live MIDI CC input is received during learn mode.

Override this to implement MIDI learn in your plugin UI. When the user enables “MIDI Learn” mode and moves a MIDI CC knob, the DAW calls this method so the plugin can map that CC to a parameter.

§Arguments
  • bus_index - MIDI bus index (usually 0)
  • channel - MIDI channel (0-15)
  • cc - MIDI CC number that was moved
§Returns

true if the input was handled (learned), false otherwise.

Source

fn midi1_assignments(&self) -> &[Midi1Assignment]

Get all MIDI 1.0 CC assignments for bulk query.

Override to provide mappings for DAW queries. This is more efficient than individual midi_cc_to_parameter queries when there are many mappings.

Default returns empty slice (no mappings).

Source

fn midi2_assignments(&self) -> &[Midi2Assignment]

Get all MIDI 2.0 controller assignments for bulk query.

Override to provide MIDI 2.0 Registered/Assignable controller mappings.

Default returns empty slice (no mappings).

Source

fn on_midi1_learn(&mut self, bus_index: i32, channel: u8, cc: u8) -> bool

Called when MIDI 1.0 CC input is received during learn mode.

This is the MIDI 2.0 version of on_midi_learn with separate methods for MIDI 1.0 and MIDI 2.0 controllers.

Default returns false (not handled).

Source

fn on_midi2_learn( &mut self, bus_index: i32, channel: u8, controller: Midi2Controller, ) -> bool

Called when MIDI 2.0 controller input is received during learn mode.

Override to implement MIDI 2.0 controller learning.

Default returns false (not handled).

Source

fn note_expression_count(&self, bus_index: i32, channel: i16) -> usize

Returns the number of supported note expression types.

Override to advertise which note expressions your plugin supports (e.g., volume, pan, tuning for MPE instruments).

Default returns 0 (no note expressions).

Source

fn note_expression_info( &self, bus_index: i32, channel: i16, index: usize, ) -> Option<NoteExpressionTypeInfo>

Returns information about a note expression type by index.

Override to provide details about each supported expression type.

Default returns None.

Source

fn note_expression_value_to_string( &self, bus_index: i32, channel: i16, type_id: u32, value: f64, ) -> String

Converts a normalized note expression value to a display string.

Override to provide custom formatting (e.g., “2.5 semitones” for tuning).

Default returns the value as a percentage.

Source

fn note_expression_string_to_value( &self, bus_index: i32, channel: i16, type_id: u32, string: &str, ) -> Option<f64>

Parses a string to a normalized note expression value.

Override to support custom parsing.

Default returns None (parsing not supported).

Source

fn keyswitch_count(&self, bus_index: i32, channel: i16) -> usize

Returns the number of keyswitches (articulations).

Override for sample libraries and orchestral instruments that support keyswitching between articulations.

Default returns 0 (no keyswitches).

Source

fn keyswitch_info( &self, bus_index: i32, channel: i16, index: usize, ) -> Option<KeyswitchInfo>

Returns information about a keyswitch by index.

Override to provide keyswitch details for DAW expression maps.

Default returns None.

Source

fn physical_ui_mappings(&self, bus_index: i32, channel: i16) -> &[PhysicalUIMap]

Returns mappings from physical UI controllers to note expressions.

Override to define how MPE controllers (X-axis, Y-axis, Pressure) map to your plugin’s note expression types.

§Example
fn physical_ui_mappings(&self, _bus: i32, _channel: i16) -> &[PhysicalUIMap] {
    &[
        PhysicalUIMap::y_axis(note_expression::BRIGHTNESS),
        PhysicalUIMap::pressure(note_expression::EXPRESSION),
    ]
}

Default returns empty slice (no mappings).

Source

fn enable_mpe_input_processing(&mut self, enabled: bool) -> bool

Called to enable or disable MPE input processing.

Override to handle MPE enable/disable notifications from wrappers.

Default does nothing and returns true.

Source

fn set_mpe_input_device_settings( &mut self, settings: MpeInputDeviceSettings, ) -> bool

Called when the MPE input device settings change.

Override to receive MPE zone configuration from wrappers.

Default does nothing and returns true.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§