// author: doomy #[macro_use] extern crate vst; use std::sync::Arc; use vst::prelude::*; /// Simple Gain Effect. /// Note that this does not use a proper scale for sound and shouldn't be used in /// a production amplification effect! This is purely for demonstration purposes, /// as well as to keep things simple as this is meant to be a starting point for /// any effect. struct GainEffect { // Store a handle to the plugin's parameter object. params: Arc, } /// The plugin's parameter object contains the values of parameters that can be /// adjusted from the host. If we were creating an effect that didn't allow the /// user to modify it at runtime or have any controls, we could omit this part. /// /// The parameters object is shared between the processing and GUI threads. /// For this reason, all mutable state in the object has to be represented /// through thread-safe interior mutability. The easiest way to achieve this /// is to store the parameters in atomic containers. struct GainEffectParameters { // The plugin's state consists of a single parameter: amplitude. amplitude: AtomicFloat, } impl Default for GainEffectParameters { fn default() -> GainEffectParameters { GainEffectParameters { amplitude: AtomicFloat::new(0.5), } } } // All plugins using `vst` also need to implement the `Plugin` trait. Here, we // define functions that give necessary info to our host. impl Plugin for GainEffect { fn new(_host: HostCallback) -> Self { // Note that controls will always return a value from 0 - 1. // Setting a default to 0.5 means it's halfway up. GainEffect { params: Arc::new(GainEffectParameters::default()), } } fn get_info(&self) -> Info { Info { name: "Gain Effect in Rust".to_string(), vendor: "Rust DSP".to_string(), unique_id: 243723072, version: 1, inputs: 2, outputs: 2, // This `parameters` bit is important; without it, none of our // parameters will be shown! parameters: 1, category: Category::Effect, ..Default::default() } } // Here is where the bulk of our audio processing code goes. fn process(&mut self, buffer: &mut AudioBuffer) { // Read the amplitude from the parameter object let amplitude = self.params.amplitude.get(); // First, we destructure our audio buffer into an arbitrary number of // input and output buffers. Usually, we'll be dealing with stereo (2 of each) // but that might change. for (input_buffer, output_buffer) in buffer.zip() { // Next, we'll loop through each individual sample so we can apply the amplitude // value to it. for (input_sample, output_sample) in input_buffer.iter().zip(output_buffer) { *output_sample = *input_sample * amplitude; } } } // Return the parameter object. This method can be omitted if the // plugin has no parameters. fn get_parameter_object(&mut self) -> Arc { Arc::clone(&self.params) as Arc } } impl PluginParameters for GainEffectParameters { // the `get_parameter` function reads the value of a parameter. fn get_parameter(&self, index: i32) -> f32 { match index { 0 => self.amplitude.get(), _ => 0.0, } } // the `set_parameter` function sets the value of a parameter. fn set_parameter(&self, index: i32, val: f32) { #[allow(clippy::single_match)] match index { 0 => self.amplitude.set(val), _ => (), } } // This is what will display underneath our control. We can // format it into a string that makes the most since. fn get_parameter_text(&self, index: i32) -> String { match index { 0 => format!("{:.2}", (self.amplitude.get() - 0.5) * 2f32), _ => "".to_string(), } } // This shows the control's name. fn get_parameter_name(&self, index: i32) -> String { match index { 0 => "Amplitude", _ => "", } .to_string() } } // This part is important! Without it, our plugin won't work. plugin_main!(GainEffect);