This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1use super::remote_probe::RemoteProbe; 2use nih_plug::prelude::*; 3use rand::Rng; 4use std::sync::Arc; 5 6pub struct ShapemakerVST { 7 params: Arc<ShapemakerVSTParams>, 8 probe: RemoteProbe, 9} 10 11#[derive(Params)] 12struct ShapemakerVSTParams { 13 /// Used to send automation data to Shapemaker 14 #[id = "param1"] 15 pub param1: FloatParam, 16 #[id = "param2"] 17 pub param2: FloatParam, 18 #[id = "param3"] 19 pub param3: FloatParam, 20 #[id = "param4"] 21 pub param4: FloatParam, 22 #[id = "param5"] 23 pub param5: FloatParam, 24 #[id = "param6"] 25 pub param6: FloatParam, 26 #[id = "param7"] 27 pub param7: FloatParam, 28 #[id = "param8"] 29 pub param8: FloatParam, 30 #[id = "param9"] 31 pub param9: FloatParam, 32} 33 34impl Default for ShapemakerVST { 35 fn default() -> Self { 36 let probe_id = rand::rng().random_range(1..=u32::MAX); 37 Self { 38 params: Arc::new(ShapemakerVSTParams::default()), 39 probe: RemoteProbe::new(probe_id), 40 } 41 } 42} 43 44impl Default for ShapemakerVSTParams { 45 fn default() -> Self { 46 let paramdef = |id: usize| { 47 FloatParam::new( 48 format!("Param #{}", id), 49 0.0, 50 FloatRange::Linear { min: 0.0, max: 1.1 }, 51 ) 52 }; 53 Self { 54 param1: paramdef(1), 55 param2: paramdef(2), 56 param3: paramdef(3), 57 param4: paramdef(4), 58 param5: paramdef(5), 59 param6: paramdef(6), 60 param7: paramdef(7), 61 param8: paramdef(8), 62 param9: paramdef(9), 63 } 64 } 65} 66 67impl Plugin for ShapemakerVST { 68 const NAME: &'static str = "Shapemaker VST b3"; 69 const VENDOR: &'static str = "Gwenn Le Bihan"; 70 const URL: &'static str = env!("CARGO_PKG_HOMEPAGE"); 71 const EMAIL: &'static str = "gwenn.lebihan7@gmail.com"; 72 73 const VERSION: &'static str = env!("CARGO_PKG_VERSION"); 74 75 // The first audio IO layout is used as the default. The other layouts may be selected either 76 // explicitly or automatically by the host or the user depending on the plugin API/backend. 77 const AUDIO_IO_LAYOUTS: &'static [AudioIOLayout] = &[AudioIOLayout { 78 main_input_channels: NonZeroU32::new(2), 79 main_output_channels: NonZeroU32::new(2), 80 81 aux_input_ports: &[], 82 aux_output_ports: &[], 83 84 // Individual ports and the layout as a whole can be named here. By default these names 85 // are generated as needed. This layout will be called 'Stereo', while a layout with 86 // only one input and output channel would be called 'Mono'. 87 names: PortNames::const_default(), 88 }]; 89 90 const MIDI_INPUT: MidiConfig = MidiConfig::MidiCCs; 91 const MIDI_OUTPUT: MidiConfig = MidiConfig::None; 92 93 const SAMPLE_ACCURATE_AUTOMATION: bool = true; 94 95 // If the plugin can send or receive SysEx messages, it can define a type to wrap around those 96 // messages here. The type implements the `SysExMessage` trait, which allows conversion to and 97 // from plain byte buffers. 98 type SysExMessage = (); 99 // More advanced plugins can use this to run expensive background tasks. See the field's 100 // documentation for more information. `()` means that the plugin does not have any background 101 // tasks. 102 type BackgroundTask = (); 103 104 fn params(&self) -> Arc<dyn Params> { 105 self.params.clone() 106 } 107 108 fn initialize( 109 &mut self, 110 _audio_io_layout: &AudioIOLayout, 111 _buffer_config: &BufferConfig, 112 _context: &mut impl InitContext<Self>, 113 ) -> bool { 114 let _ = self.probe.register(); 115 true 116 } 117 118 fn reset(&mut self) { 119 // Reset buffers and envelopes here. This can be called from the audio thread and may not 120 // allocate. You can remove this function if you do not need it. 121 } 122 123 fn deactivate(&mut self) { 124 // probe should be removed from beacon thanks to the Drop impl 125 } 126 127 fn process( 128 &mut self, 129 _buffer: &mut Buffer, 130 _aux: &mut AuxiliaryBuffers, 131 _context: &mut impl ProcessContext<Self>, 132 ) -> ProcessStatus { 133 let ts = RemoteProbe::timestamp(); 134 // self.probe.say(format!("{} sending data", ts)); 135 let _ = self.probe.store_automation(ts, 1, &self.params.param1); 136 let _ = self.probe.store_automation(ts, 2, &self.params.param2); 137 let _ = self.probe.store_automation(ts, 3, &self.params.param3); 138 let _ = self.probe.store_automation(ts, 4, &self.params.param4); 139 let _ = self.probe.store_automation(ts, 4, &self.params.param4); 140 let _ = self.probe.store_automation(ts, 5, &self.params.param5); 141 let _ = self.probe.store_automation(ts, 6, &self.params.param6); 142 let _ = self.probe.store_automation(ts, 7, &self.params.param7); 143 let _ = self.probe.store_automation(ts, 8, &self.params.param8); 144 let _ = self.probe.store_automation(ts, 9, &self.params.param9); 145 // self.probe.say(format!("{} sent automation", ts)); 146 147 // self.probe.store_audio( 148 // ts, 149 // buffer 150 // .iter_samples() 151 // .flatten() 152 // .map(|f| *f) 153 // .collect::<Vec<f32>>(), 154 // ); 155 // self.probe.say(format!("{} sent audio", ts)); 156 157 ProcessStatus::Normal 158 } 159} 160 161impl ClapPlugin for ShapemakerVST { 162 const CLAP_ID: &'static str = "works.gwen.shapemakervst"; 163 const CLAP_DESCRIPTION: Option<&'static str> = Some( 164 "A VST plugin for Shapemaker, an experimental audiovisual SVG-based rendering engine", 165 ); 166 const CLAP_MANUAL_URL: Option<&'static str> = Some(Self::URL); 167 const CLAP_SUPPORT_URL: Option<&'static str> = None; 168 169 // Don't forget to change these features 170 const CLAP_FEATURES: &'static [ClapFeature] = 171 &[ClapFeature::AudioEffect, ClapFeature::Stereo]; 172} 173 174impl Vst3Plugin for ShapemakerVST { 175 const VST3_CLASS_ID: [u8; 16] = *b"gwennlbhshapemak"; 176 177 // And also don't forget to change these categories 178 const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = 179 &[Vst3SubCategory::Fx, Vst3SubCategory::Dynamics]; 180}