{
pub fn new() -> Box {
num_input_channels: P::DEFAULT_NUM_INPUTS,
num_output_channels: P::DEFAULT_NUM_OUTPUTS,
},
- )
+ );
+
+ // This is a mapping from the parameter IDs specified by the plugin to pointers to thsoe
+ // parameters. Since the object returned by `params()` is pinned, these pointers are safe to
+ // dereference as long as `wrapper.plugin` is alive
+ wrapper.param_map = wrapper.plugin.params().param_map();
+ wrapper.param_ids = wrapper.param_map.keys().copied().collect();
+ wrapper.param_defaults_normalized = wrapper
+ .param_ids
+ .iter()
+ .map(|id| unsafe { wrapper.param_map[id].normalized_value() })
+ .collect();
+ wrapper.param_id_hashes = wrapper
+ .param_ids
+ .iter()
+ .map(|id| (hash_param_id(id), *id))
+ .collect();
+
+ nih_debug_assert!(
+ !wrapper.param_map.contains_key(BYPASS_PARAM_ID),
+ "The wrapper alread yadds its own bypass parameter"
+ );
+
+ wrapper
}
}
@@ -177,6 +238,138 @@ impl {
}
}
+impl {
+ unsafe fn set_component_state(&self, _state: *mut c_void) -> tresult {
+ // We have a single file component, so we don't need to do anything here
+ kResultOk
+ }
+
+ unsafe fn set_state(&self, state: *mut c_void) -> tresult {
+ // We have a single file component, so there's only one `set_state()` function. Unlike C++,
+ // Rust allows you to have multiple methods with the same name when they're provided by
+ // different treats, but because of the Rust implementation the host may call either of
+ // these functions depending on how they're implemented
+ IComponent::set_state(self, state)
+ }
+
+ unsafe fn get_state(&self, state: *mut c_void) -> tresult {
+ // Same for this function
+ IComponent::get_state(self, state)
+ }
+
+ unsafe fn get_parameter_count(&self) -> i32 {
+ // NOTE: We add a bypass parameter ourselves on index `self.param_ids.len()`, so these
+ // indices are all off by one
+ self.param_ids.len() as i32 + 1
+ }
+
+ unsafe fn get_parameter_info(
+ &self,
+ param_index: i32,
+ info: *mut vst3_sys::vst::ParameterInfo,
+ ) -> tresult {
+ // Parameter index `self.param_ids.len()` is our own bypass parameter
+ if param_index < 0 || param_index > self.param_ids.len() as i32 {
+ return kInvalidArgument;
+ }
+
+ *info = std::mem::zeroed();
+
+ let info = &mut *info;
+ if param_index == self.param_ids.len() as i32 {
+ info.id = hash_param_id(BYPASS_PARAM_ID);
+ u16strlcpy(&mut info.title, "Bypass");
+ u16strlcpy(&mut info.short_title, "Bypass");
+ u16strlcpy(&mut info.units, "");
+ info.step_count = 0;
+ info.default_normalized_value = 0.0;
+ info.unit_id = vst3_sys::vst::kRootUnitId;
+ info.flags = vst3_sys::vst::ParameterFlags::kCanAutomate as i32
+ | vst3_sys::vst::ParameterFlags::kIsBypass as i32;
+ } else {
+ let param_id = &self.param_ids[param_index as usize];
+ let default_value = &self.param_defaults_normalized[param_index as usize];
+ let param_ptr = &self.param_map[param_id];
+
+ info.id = hash_param_id(param_id);
+ u16strlcpy(&mut info.title, param_ptr.name());
+ u16strlcpy(&mut info.short_title, param_ptr.name());
+ u16strlcpy(&mut info.units, param_ptr.unit());
+ // TODO: Don't forget this when we add enum parameters
+ info.step_count = 0;
+ info.default_normalized_value = *default_value as f64;
+ info.unit_id = vst3_sys::vst::kRootUnitId;
+ info.flags = vst3_sys::vst::ParameterFlags::kCanAutomate as i32;
+ }
+
+ kResultOk
+ }
+
+ unsafe fn get_param_string_by_value(
+ &self,
+ id: u32,
+ value_normalized: f64,
+ string: *mut TChar,
+ ) -> tresult {
+ // Somehow there's no length there, so we'll assume our own maximum
+ let dest = &mut *(string as *mut [TChar; 128]);
+
+ if id == *BYPASS_PARAM_HASH {
+ if value_normalized > 0.5 {
+ u16strlcpy(dest, "Bypassed")
+ } else {
+ u16strlcpy(dest, "Enabled")
+ }
+
+ kResultOk
+ } else if self.param_id_hashes.contains_key(&id) {
+ let param_id = &self.param_id_hashes[&id];
+ let param_ptr = &self.param_map[param_id];
+ u16strlcpy(
+ dest,
+ ¶m_ptr.normalized_value_to_string(value_normalized as f32),
+ );
+
+ kResultOk
+ } else {
+ kInvalidArgument
+ }
+ }
+
+ unsafe fn get_param_value_by_string(
+ &self,
+ id: u32,
+ string: *const TChar,
+ value_normalized: *mut f64,
+ ) -> tresult {
+ todo!()
+ }
+
+ unsafe fn normalized_param_to_plain(&self, id: u32, value_normalized: f64) -> f64 {
+ todo!()
+ }
+
+ unsafe fn plain_param_to_normalized(&self, id: u32, plain_value: f64) -> f64 {
+ todo!()
+ }
+
+ unsafe fn get_param_normalized(&self, id: u32) -> f64 {
+ todo!()
+ }
+
+ unsafe fn set_param_normalized(&self, id: u32, value: f64) -> tresult {
+ todo!()
+ }
+
+ unsafe fn set_component_handler(&self, handler: *mut c_void) -> tresult {
+ todo!()
+ }
+
+ unsafe fn create_view(&self, name: vst3_sys::base::FIDString) -> *mut c_void {
+ todo!()
+ }
+}
+
#[VST3(implements(IPluginFactory, IPluginFactory2, IPluginFactory3))]
pub struct Factory