voicemeeter\interface\parameters/
get_parameters.rs

1//! Parameter related functions and types
2//!
3//! # Functions
4//!
5//! * [`parameters`](VoicemeeterRemote::parameters)
6//! * [`is_parameters_dirty`](VoicemeeterRemote::is_parameters_dirty)
7//! * [`get_parameter_float`](VoicemeeterRemote::get_parameter_float)
8//! * [`get_parameter_string`](VoicemeeterRemote::get_parameter_string)
9use std::{
10    ffi::{CStr, CString, NulError},
11    os::raw::c_char,
12    ptr,
13};
14
15use crate::types::ParameterNameRef;
16
17use crate::VoicemeeterRemote;
18
19impl VoicemeeterRemote {
20    // TODO: Only call from one thread, limit it
21    /// Check if parameters have changed
22    ///
23    /// Call this function periodically to check if parameters have changed, typically every 10ms.
24    /// This function will also make sure voicemeeter processes any new pushed values for a parameter.
25    ///
26    /// # Security
27    ///
28    /// This method must only be called from one thread.
29    pub fn is_parameters_dirty(&self) -> Result<bool, IsParametersDirtyError> {
30        let res = unsafe { self.raw.VBVMR_IsParametersDirty() };
31        match res {
32            0 => Ok(false),
33            1 => Ok(true),
34            -1 => Err(IsParametersDirtyError::CannotGetClient),
35            -2 => Err(IsParametersDirtyError::NoServer),
36            s => Err(IsParametersDirtyError::Other(s)),
37        }
38    }
39
40    /// Get the float value of a parameter. See also [`VoicemeeterRemote::parameters()`] to do this with functions.
41    #[tracing::instrument(skip(self))]
42    pub fn get_parameter_float(&self, param: &ParameterNameRef) -> Result<f32, GetParameterError> {
43        let mut f = 0.0f32;
44        let param = CString::new(param.as_ref())?;
45        tracing::debug!("getting float parameter");
46        let res = unsafe {
47            self.raw
48                .VBVMR_GetParameterFloat(param.as_ptr() as *mut _, &mut f)
49        };
50        match res {
51            0 => Ok(f),
52            -1 => Err(GetParameterError::CannotGetClient),
53            -2 => Err(GetParameterError::NoServer),
54            -3 => Err(GetParameterError::UnknownParameter(
55                param.to_string_lossy().into_owned(),
56            )), // NOTE: Lossless always (assuming vmr doesn't modify :) ), unsafe?
57            -5 => Err(GetParameterError::StructureMismatch(
58                param.to_string_lossy().into_owned(),
59                "float",
60            )),
61            s => Err(GetParameterError::Other(s)),
62        }
63    }
64
65    /// Get the string value of a parameter. See also [`VoicemeeterRemote::parameters()`] to do this with functions.
66    #[tracing::instrument(skip(self))]
67    pub fn get_parameter_string(
68        &self,
69        param: &ParameterNameRef,
70    ) -> Result<String, GetParameterError> {
71        let param = CString::new(param.as_ref()).unwrap();
72        let mut output = [0 as c_char; 512];
73        tracing::debug!("getting string parameter");
74        let res = unsafe {
75            self.raw
76                .VBVMR_GetParameterStringA(param.as_ptr() as *mut _, ptr::addr_of_mut!(output[0]))
77        };
78        match res {
79            0 => {
80                let output = unsafe { CStr::from_ptr(ptr::addr_of!(output[0])) }
81                    .to_string_lossy()
82                    .into_owned();
83                Ok(output)
84            }
85            -1 => Err(GetParameterError::CannotGetClient),
86            -2 => Err(GetParameterError::NoServer),
87            -3 => Err(GetParameterError::UnknownParameter(
88                param.to_string_lossy().into_owned(),
89            )), // NOTE: Lossless always (assuming vmr doesn't modify :) ), unsafe?
90            -5 => Err(GetParameterError::StructureMismatch(
91                param.to_string_lossy().into_owned(),
92                "float",
93            )),
94            s => Err(GetParameterError::Other(s)),
95        }
96    }
97}
98
99/// Errors that can happen when getting a parameter.
100#[derive(Debug, thiserror::Error, Clone)]
101#[non_exhaustive]
102pub enum GetParameterError {
103    /// Could not make a c-compatible string. This is a bug.
104    #[error("could not make into a c-string")]
105    NulError(#[from] NulError),
106    /// Unexpected error
107    #[error("error (unexpected)")]
108    CannotGetClient,
109    /// No server.
110    #[error("no server")]
111    NoServer,
112    /// Unknown parameter.
113    #[error("unknown parameter: {0}")]
114    UnknownParameter(String),
115    /// Structure mismatch.
116    #[error("tried to parse parameter {0:?} as a {1} but it is not")]
117    StructureMismatch(String, &'static str),
118    /// An unknown error code occured.
119    #[error("unexpected error occurred: error code {0}")]
120    Other(i32),
121}
122
123/// Errors that can happen when querying parameter "dirty" flag.
124#[derive(Debug, thiserror::Error, Clone)]
125#[non_exhaustive]
126pub enum IsParametersDirtyError {
127    /// Unexpected error
128    #[error("error (unexpected)")]
129    CannotGetClient,
130    /// No server.
131    #[error("no server")]
132    NoServer,
133    /// An unknown error code occured.
134    #[error("unexpected error occurred: error code {0}")]
135    Other(i32),
136}