use std::borrow::Cow;
use std::fmt::Debug;
use std::fmt::Display;
use std::ops::{Bound, RangeBounds};
use crate::types::{BusMode, Device, ParameterNameRef, VoicemeeterApplication, ZIndex};
use crate::VoicemeeterRemote;
mod errors;
pub mod bus;
pub mod eq;
pub mod fx;
pub mod get_parameters;
pub mod option;
pub mod recorder;
pub mod set_parameters;
pub mod strip;
pub mod vban;
pub use bus::*;
pub use eq::*;
pub use errors::*;
pub use fx::*;
pub use option::*;
pub use recorder::*;
pub use strip::*;
pub use vban::*;
use self::get_parameters::GetParameterError;
use self::set_parameters::SetParameterError;
pub(crate) static BUS: &str = "Bus";
pub(crate) static FX: &str = "Recorder";
pub(crate) static RECORDER: &str = "Recorder";
pub(crate) static STRIP: &str = "Strip";
pub(crate) static VOICEMEETER_OPTION: &str = "Option";
pub(crate) static VBAN: &str = "vban";
impl VoicemeeterRemote {
pub fn parameters(&self) -> Parameters {
Parameters { remote: self }
}
}
#[must_use = "set or get the value of the parameter"]
pub struct FloatParameter<'a, const WRITE: bool = true, const READ: bool = true> {
pub name: Cow<'a, ParameterNameRef>,
remote: &'a VoicemeeterRemote,
_range: Option<(Bound<f32>, Bound<f32>)>,
}
impl<'a, const WRITE: bool, const READ: bool> FloatParameter<'a, WRITE, READ> {
fn new<R>(name: Cow<'a, ParameterNameRef>, remote: &'a VoicemeeterRemote, range: R) -> Self
where
R: RangeBounds<f32>,
{
Self {
name,
remote,
_range: Some((range.start_bound().cloned(), range.end_bound().cloned())),
}
}
fn new_unranged(name: Cow<'a, ParameterNameRef>, remote: &'a VoicemeeterRemote) -> Self {
Self {
name,
remote,
_range: None,
}
}
}
impl<'a, const READ: bool> FloatParameter<'a, true, READ> {
pub fn set(&self, val: f32) -> Result<(), SetParameterError> {
self.remote.set_parameter_float(&self.name, val)
}
}
impl<'a, const WRITE: bool> FloatParameter<'a, WRITE, true> {
pub fn get(&self) -> Result<f32, GetParameterError> {
self.remote.get_parameter_float(&self.name)
}
}
#[must_use = "set or get the value of the parameter"]
pub struct StringParameter<'a, const WRITE: bool = true, const READ: bool = true> {
pub name: Cow<'a, ParameterNameRef>,
remote: &'a VoicemeeterRemote,
}
impl<'a, const WRITE: bool, const READ: bool> StringParameter<'a, WRITE, READ> {
fn new(name: Cow<'a, ParameterNameRef>, remote: &'a VoicemeeterRemote) -> Self {
Self { name, remote }
}
}
impl<'a, const READ: bool> StringParameter<'a, true, READ> {
pub fn set(&self, val: &str) -> Result<(), SetParameterError> {
self.remote.set_parameter_string(&self.name, val)
}
}
impl<'a, const WRITE: bool> StringParameter<'a, WRITE, true> {
pub fn get(&self) -> Result<String, GetParameterError> {
self.remote.get_parameter_string(&self.name)
}
}
#[must_use = "set or get the value of the parameter"]
pub struct TupleParameter<'a, A, B, const WRITE: bool = true, const READ: bool = true> {
pub name: Cow<'a, ParameterNameRef>,
remote: &'a VoicemeeterRemote,
_pd: std::marker::PhantomData<(A, B)>,
}
impl<'a, A, B, const WRITE: bool, const READ: bool> TupleParameter<'a, A, B, WRITE, READ> {
fn new(name: Cow<'a, ParameterNameRef>, remote: &'a VoicemeeterRemote) -> Self {
Self {
name,
remote,
_pd: Default::default(),
}
}
}
impl<'a, A, B, const READ: bool> TupleParameter<'a, A, B, true, READ>
where
A: Debug,
B: Debug,
{
pub fn set(&self, val_a: A, val_b: B) -> Result<(), SetParameterError> {
self.remote
.set_parameter_string(&self.name, &format!("({:?}, {:?})", val_a, val_b))
}
}
#[must_use = "set or get the value of the parameter"]
pub struct BoolParameter<'a, const WRITE: bool = true, const READ: bool = true> {
pub name: Cow<'a, ParameterNameRef>,
remote: &'a VoicemeeterRemote,
}
impl<'a, const WRITE: bool, const READ: bool> BoolParameter<'a, WRITE, READ> {
fn new(name: Cow<'a, ParameterNameRef>, remote: &'a VoicemeeterRemote) -> Self {
Self { name, remote }
}
}
impl<'a, const READ: bool> BoolParameter<'a, true, READ> {
pub fn set(&self, val: bool) -> Result<(), SetParameterError> {
self.remote
.set_parameter_float(&self.name, if val { 1.0 } else { 0.0 })
}
}
impl<'a, const WRITE: bool> BoolParameter<'a, WRITE, true> {
pub fn get(&self) -> Result<bool, GetParameterError> {
Ok(self.remote.get_parameter_float(&self.name)? == 1.0)
}
}
#[must_use = "set or get the value of the parameter"]
pub struct IntParameter<'a, const WRITE: bool = true, const READ: bool = true> {
pub name: Cow<'a, ParameterNameRef>,
remote: &'a VoicemeeterRemote,
_range: Option<(Bound<i32>, Bound<i32>)>,
}
impl<'a, const WRITE: bool, const READ: bool> IntParameter<'a, WRITE, READ> {
fn new<R>(name: Cow<'a, ParameterNameRef>, remote: &'a VoicemeeterRemote, range: R) -> Self
where
R: RangeBounds<i32>,
{
Self {
name,
remote,
_range: Some((range.start_bound().cloned(), range.end_bound().cloned())),
}
}
fn new_unranged(name: Cow<'a, ParameterNameRef>, remote: &'a VoicemeeterRemote) -> Self {
Self {
name,
remote,
_range: None,
}
}
}
impl<'a, const READ: bool> IntParameter<'a, true, READ> {
pub fn set(&self, val: i32) -> Result<(), SetParameterError> {
self.remote.set_parameter_float(&self.name, val as f32)
}
}
impl<'a, const WRITE: bool> IntParameter<'a, WRITE, true> {
pub fn get(&self) -> Result<i32, GetParameterError> {
Ok(self.remote.get_parameter_float(&self.name)? as i32)
}
}
pub trait StripIndex {
fn into_strip_index(self, program: &VoicemeeterApplication) -> Result<ZIndex, ParameterError>;
}
impl StripIndex for i32 {
fn into_strip_index(self, _: &VoicemeeterApplication) -> Result<ZIndex, ParameterError> {
Ok(ZIndex(self))
}
}
impl StripIndex for usize {
fn into_strip_index(self, _: &VoicemeeterApplication) -> Result<ZIndex, ParameterError> {
Ok(ZIndex(self as _))
}
}
impl StripIndex for ZIndex {
fn into_strip_index(self, _: &VoicemeeterApplication) -> Result<ZIndex, ParameterError> {
Ok(self)
}
}
impl StripIndex for Device {
fn into_strip_index(self, program: &VoicemeeterApplication) -> Result<ZIndex, ParameterError> {
if !self.is_strip() {
return Err(InvalidTypeError::ExpectedStrip {
device: format!("{:?}", self),
}
.into());
}
self.as_strip_index(program).ok_or_else(|| {
DeviceError {
program: *program,
device: self,
}
.into()
})
}
}
pub trait BusIndex {
fn into_bus_index(self, program: &VoicemeeterApplication) -> Result<ZIndex, ParameterError>;
}
impl BusIndex for i32 {
fn into_bus_index(self, _: &VoicemeeterApplication) -> Result<ZIndex, ParameterError> {
Ok(ZIndex(self))
}
}
impl BusIndex for usize {
fn into_bus_index(self, _: &VoicemeeterApplication) -> Result<ZIndex, ParameterError> {
Ok(ZIndex(self as _))
}
}
impl BusIndex for ZIndex {
fn into_bus_index(self, _: &VoicemeeterApplication) -> Result<ZIndex, ParameterError> {
Ok(self)
}
}
impl BusIndex for Device {
fn into_bus_index(self, program: &VoicemeeterApplication) -> Result<ZIndex, ParameterError> {
if !self.is_bus() {
return Err(InvalidTypeError::ExpectedBus {
device: format!("{:?}", self),
}
.into());
}
self.as_bus_index(program)
.ok_or_else(|| {
DeviceError {
program: *program,
device: self,
}
.into()
})
.map(|i| i.0)
}
}
pub struct Parameters<'a> {
remote: &'a VoicemeeterRemote,
}
impl<'a> Parameters<'a> {
pub fn strip(&self, index: impl StripIndex) -> Result<Strip<'a>, ParameterError> {
let index = index.into_strip_index(&self.remote.program)?;
Ok(match (self.remote.program, index.0) {
(VoicemeeterApplication::Voicemeeter, 0..=2) => Strip::new(self.remote, index),
(VoicemeeterApplication::VoicemeeterBanana, 0..=4) => Strip::new(self.remote, index),
(VoicemeeterApplication::VoicemeeterPotato, 0..=7)
| (VoicemeeterApplication::PotatoX64Bits, 0..=7) => Strip::new(self.remote, index),
_ => {
return Err(Into::into(OutOfRangeError {
name: STRIP.to_owned(),
index,
program: self.remote.program,
}));
}
})
}
pub fn bus(&self, index: impl BusIndex) -> Result<Bus<'a>, ParameterError> {
let index = index.into_bus_index(&self.remote.program)?;
Ok(match (self.remote.program, index.0) {
(VoicemeeterApplication::Voicemeeter, 0..=1) => Bus::new(self.remote, index),
(VoicemeeterApplication::VoicemeeterBanana, 0..=4) => Bus::new(self.remote, index),
(VoicemeeterApplication::VoicemeeterPotato, 0..=7)
| (VoicemeeterApplication::PotatoX64Bits, 0..=7) => Bus::new(self.remote, index),
_ => {
return Err(Into::into(OutOfRangeError {
name: BUS.to_owned(),
index,
program: self.remote.program,
}));
}
})
}
pub fn option(&self) -> VoicemeeterOption<'a> {
VoicemeeterOption::new(self.remote)
}
pub fn recorder(&self) -> Result<VoicemeeterRecorder<'a>, ParameterError> {
const VALID: &[VoicemeeterApplication] = &[
VoicemeeterApplication::VoicemeeterBanana,
VoicemeeterApplication::VoicemeeterPotato,
VoicemeeterApplication::PotatoX64Bits,
];
if !VALID.contains(&self.remote.program) {
Err(ParameterError::Version(InvalidVoicemeeterVersion {
expected: VALID,
found: self.remote.program,
parameter: RECORDER.to_owned(),
}))
} else {
Ok(VoicemeeterRecorder::new(self.remote))
}
}
pub fn fx(&self) -> Result<VoicemeeterFx<'a>, ParameterError> {
const VALID: &[VoicemeeterApplication] = &[
VoicemeeterApplication::VoicemeeterPotato,
VoicemeeterApplication::PotatoX64Bits,
];
if !VALID.contains(&self.remote.program) {
Err(ParameterError::Version(InvalidVoicemeeterVersion {
expected: VALID,
found: self.remote.program,
parameter: FX.to_owned(),
}))
} else {
Ok(VoicemeeterFx::new(self.remote))
}
}
pub fn vban(&self) -> VoicemeeterVban<'a> {
VoicemeeterVban::new(self.remote)
}
}