use std::borrow::{Borrow, BorrowMut};
use std::ffi::CStr;
use std::ptr::null;
use crate::sample;
use crate::channelmap::{Map, Position, PositionMask, POSITION_MASK_ALL};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Volume(pub capi::pa_volume_t);
impl Default for Volume {
fn default() -> Self {
Self::NORMAL
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct VolumeDB(pub f64);
impl Default for VolumeDB {
fn default() -> Self {
VolumeDB(0.0)
}
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct VolumeLinear(pub f64);
impl Default for VolumeLinear {
fn default() -> Self {
VolumeLinear(0.0)
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, Default)]
pub struct ChannelVolumes {
channels: u8,
values: [Volume; Self::CHANNELS_MAX as usize],
}
#[test]
fn set_compare_capi() {
assert_eq!(std::mem::size_of::<ChannelVolumes>(), std::mem::size_of::<capi::pa_cvolume>());
assert_eq!(std::mem::align_of::<ChannelVolumes>(), std::mem::align_of::<capi::pa_cvolume>());
}
impl Borrow<[Volume]> for ChannelVolumes {
fn borrow(&self) -> &[Volume] {
&self.values[..self.channels as usize]
}
}
impl BorrowMut<[Volume]> for ChannelVolumes {
fn borrow_mut(&mut self) -> &mut [Volume] {
&mut self.values[..self.channels as usize]
}
}
impl AsRef<capi::pa_cvolume> for ChannelVolumes {
#[inline]
fn as_ref(&self) -> &capi::pa_cvolume {
unsafe { &*(self as *const Self as *const capi::pa_cvolume) }
}
}
impl AsMut<capi::pa_cvolume> for ChannelVolumes {
#[inline]
fn as_mut(&mut self) -> &mut capi::pa_cvolume {
unsafe { &mut *(self as *mut Self as *mut capi::pa_cvolume) }
}
}
impl From<capi::pa_cvolume> for ChannelVolumes {
#[inline]
fn from(cv: capi::pa_cvolume) -> Self {
unsafe { std::mem::transmute(cv) }
}
}
impl PartialEq for ChannelVolumes {
#[inline]
fn eq(&self, other: &Self) -> bool {
unsafe { capi::pa_cvolume_equal(self.as_ref(), other.as_ref()) != 0 }
}
}
impl PartialEq<Volume> for ChannelVolumes {
#[inline]
fn eq(&self, v: &Volume) -> bool {
unsafe { capi::pa_cvolume_channels_equal_to(self.as_ref(), v.0) != 0 }
}
}
impl From<VolumeDB> for Volume {
#[inline]
fn from(v: VolumeDB) -> Self {
Volume(unsafe { capi::pa_sw_volume_from_dB(v.0) })
}
}
impl From<Volume> for VolumeDB {
#[inline]
fn from(v: Volume) -> Self {
VolumeDB(unsafe { capi::pa_sw_volume_to_dB(v.0) })
}
}
impl From<VolumeLinear> for Volume {
#[inline]
fn from(v: VolumeLinear) -> Self {
Volume(unsafe { capi::pa_sw_volume_from_linear(v.0) })
}
}
impl From<Volume> for VolumeLinear {
#[inline]
fn from(v: Volume) -> Self {
VolumeLinear(unsafe { capi::pa_sw_volume_to_linear(v.0) })
}
}
impl From<VolumeLinear> for VolumeDB {
#[inline]
fn from(v: VolumeLinear) -> Self {
VolumeDB::from(Volume::from(v))
}
}
impl From<VolumeDB> for VolumeLinear {
#[inline]
fn from(v: VolumeDB) -> Self {
VolumeLinear::from(Volume::from(v))
}
}
impl VolumeLinear {
#[inline]
pub fn is_muted(&self) -> bool {
self.0 <= 0.0
}
#[inline]
pub fn is_normal(&self) -> bool {
self.0 == 1.0
}
}
impl Volume {
pub const NORMAL: Self = Self(capi::PA_VOLUME_NORM);
pub const MUTED: Self = Self(capi::PA_VOLUME_MUTED);
pub const MAX: Self = Self(capi::PA_VOLUME_MAX);
pub const INVALID: Self = Self(capi::PA_VOLUME_INVALID);
#[inline]
pub fn is_muted(&self) -> bool {
*self == Self::MUTED
}
#[inline]
pub fn is_normal(&self) -> bool {
*self == Self::NORMAL
}
#[inline]
pub fn is_max(&self) -> bool {
*self == Self::MAX
}
#[inline]
pub fn ui_max() -> Self {
Volume(capi::pa_volume_ui_max())
}
#[inline]
pub const fn is_valid(&self) -> bool {
capi::pa_volume_is_valid(self.0)
}
#[inline]
pub fn clamp(&mut self) {
self.0 = capi::pa_clamp_volume(self.0)
}
#[inline]
pub fn multiply(a: Self, b: Self) -> Self {
Volume(unsafe { capi::pa_sw_volume_multiply(a.0, b.0) })
}
#[inline]
pub fn divide(a: Self, b: Self) -> Self {
Volume(unsafe { capi::pa_sw_volume_divide(a.0, b.0) })
}
pub fn print(&self) -> String {
const PRINT_MAX: usize = capi::PA_VOLUME_SNPRINT_MAX;
let mut tmp = Vec::with_capacity(PRINT_MAX);
unsafe {
capi::pa_volume_snprint(tmp.as_mut_ptr(), PRINT_MAX, self.0);
CStr::from_ptr(tmp.as_mut_ptr()).to_string_lossy().into_owned()
}
}
pub fn print_db(&self) -> String {
const PRINT_DB_MAX: usize = capi::PA_SW_VOLUME_SNPRINT_DB_MAX;
let mut tmp = Vec::with_capacity(PRINT_DB_MAX);
unsafe {
capi::pa_sw_volume_snprint_dB(tmp.as_mut_ptr(), PRINT_DB_MAX, self.0);
CStr::from_ptr(tmp.as_mut_ptr()).to_string_lossy().into_owned()
}
}
pub fn print_verbose(&self, print_db: bool) -> String {
const PRINT_VERBOSE_MAX: usize = capi::PA_VOLUME_SNPRINT_VERBOSE_MAX;
let mut tmp = Vec::with_capacity(PRINT_VERBOSE_MAX);
unsafe {
capi::pa_volume_snprint_verbose(tmp.as_mut_ptr(), PRINT_VERBOSE_MAX, self.0,
print_db as i32);
CStr::from_ptr(tmp.as_mut_ptr()).to_string_lossy().into_owned()
}
}
}
impl std::fmt::Display for Volume {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", &self.print())
}
}
impl VolumeDB {
pub const MINUS_INFINITY: Self = Self(capi::PA_DECIBEL_MININFTY);
}
impl ChannelVolumes {
pub const CHANNELS_MAX: u8 = capi::PA_CHANNELS_MAX;
#[inline]
pub fn init(&mut self) -> &Self {
unsafe { capi::pa_cvolume_init(self.as_mut()) };
self
}
#[inline]
pub fn is_valid(&self) -> bool {
unsafe { capi::pa_cvolume_valid(self.as_ref()) != 0 }
}
#[inline]
pub fn len(&self) -> u8 {
self.channels
}
#[inline]
pub fn set_len(&mut self, channels: u8) {
assert!(channels <= Self::CHANNELS_MAX);
self.channels = channels;
}
#[inline]
pub fn get(&self) -> &[Volume] {
self.borrow()
}
#[inline]
pub fn get_mut(&mut self) -> &mut [Volume] {
self.borrow_mut()
}
#[inline]
pub fn set(&mut self, channels: u8, v: Volume) -> &Self {
unsafe { capi::pa_cvolume_set(self.as_mut(), channels as u32, v.0) };
self
}
#[inline]
pub fn reset(&mut self, channels: u8) -> &Self {
self.set(channels, Volume::NORMAL)
}
#[inline]
pub fn mute(&mut self, channels: u8) -> &Self {
self.set(channels, Volume::MUTED)
}
#[inline]
pub fn is_muted(&self) -> bool {
self.eq(&Volume::MUTED)
}
#[inline]
pub fn is_norm(&self) -> bool {
self.eq(&Volume::NORMAL)
}
#[inline]
pub fn avg(&self) -> Volume {
Volume(unsafe { capi::pa_cvolume_avg(self.as_ref()) })
}
#[inline]
pub fn avg_mask(&self, cm: &Map, mask: Option<PositionMask>) -> Volume {
let mask_actual = mask.unwrap_or(POSITION_MASK_ALL);
Volume(unsafe { capi::pa_cvolume_avg_mask(self.as_ref(), cm.as_ref(), mask_actual) })
}
#[inline]
pub fn max(&self) -> Volume {
Volume(unsafe { capi::pa_cvolume_max(self.as_ref()) })
}
#[inline]
pub fn max_mask(&self, cm: &Map, mask: Option<PositionMask>) -> Volume {
let mask_actual = mask.unwrap_or(POSITION_MASK_ALL);
Volume(unsafe { capi::pa_cvolume_max_mask(self.as_ref(), cm.as_ref(), mask_actual) })
}
#[inline]
pub fn min(&self) -> Volume {
Volume(unsafe { capi::pa_cvolume_min(self.as_ref()) })
}
#[inline]
pub fn min_mask(&self, cm: &Map, mask: Option<PositionMask>) -> Volume {
let mask_actual = mask.unwrap_or(POSITION_MASK_ALL);
Volume(unsafe { capi::pa_cvolume_min_mask(self.as_ref(), cm.as_ref(), mask_actual) })
}
#[inline]
pub fn sw_multiply(&mut self, with: Option<&Self>) -> &mut Self {
unsafe { capi::pa_sw_cvolume_multiply(self.as_mut(), self.as_mut(),
with.unwrap_or(self).as_ref()) };
self
}
#[inline]
pub fn sw_multiply_scalar(&mut self, with: Volume) -> &mut Self {
unsafe { capi::pa_sw_cvolume_multiply_scalar(self.as_mut(), self.as_ref(), with.0) };
self
}
#[inline]
pub fn sw_divide(&mut self, with: Option<&Self>) -> &mut Self {
unsafe { capi::pa_sw_cvolume_divide(self.as_mut(), self.as_mut(),
with.unwrap_or(self).as_ref()) };
self
}
#[inline]
pub fn sw_divide_scalar(&mut self, with: Volume) -> &mut Self {
unsafe { capi::pa_sw_cvolume_divide_scalar(self.as_mut(), self.as_ref(), with.0) };
self
}
#[inline]
pub fn remap(&mut self, from: &Map, to: &Map) -> &mut Self {
unsafe { capi::pa_cvolume_remap(self.as_mut(), from.as_ref(), to.as_ref()) };
self
}
#[inline]
pub fn is_compatible_with_ss(&self, ss: &sample::Spec) -> bool {
unsafe { capi::pa_cvolume_compatible(self.as_ref(), ss.as_ref()) != 0 }
}
#[inline]
pub fn is_compatible_with_cm(&self, cm: &Map) -> bool {
unsafe { capi::pa_cvolume_compatible_with_channel_map(self.as_ref(), cm.as_ref()) != 0 }
}
#[inline]
pub fn get_balance(&self, map: &Map) -> f32 {
unsafe { capi::pa_cvolume_get_balance(self.as_ref(), map.as_ref()) }
}
#[inline]
pub fn set_balance(&mut self, map: &Map, new_balance: f32) -> Option<&mut Self> {
let ptr = unsafe { capi::pa_cvolume_set_balance(self.as_mut(), map.as_ref(), new_balance) };
match ptr.is_null() {
false => Some(self),
true => None,
}
}
#[inline]
pub fn get_fade(&self, map: &Map) -> f32 {
unsafe { capi::pa_cvolume_get_fade(self.as_ref(), map.as_ref()) }
}
#[inline]
pub fn set_fade(&mut self, map: &Map, new_fade: f32) -> Option<&mut Self> {
let ptr = unsafe { capi::pa_cvolume_set_fade(self.as_mut(), map.as_ref(), new_fade) };
match ptr.is_null() {
false => Some(self),
true => None,
}
}
#[inline]
#[cfg(any(doc, feature = "pa_v8"))]
#[cfg_attr(docsrs, doc(cfg(feature = "pa_v8")))]
pub fn get_lfe_balance(&self, map: &Map) -> f32 {
unsafe { capi::pa_cvolume_get_lfe_balance(self.as_ref(), map.as_ref()) }
}
#[inline]
#[cfg(any(doc, feature = "pa_v8"))]
#[cfg_attr(docsrs, doc(cfg(feature = "pa_v8")))]
pub fn set_lfe_balance(&mut self, map: &Map, new_balance: f32) -> Option<&mut Self> {
let ptr =
unsafe { capi::pa_cvolume_set_lfe_balance(self.as_mut(), map.as_ref(), new_balance) };
match ptr.is_null() {
false => Some(self),
true => None,
}
}
#[inline]
pub fn scale(&mut self, max: Volume) -> Option<&mut Self> {
let ptr = unsafe { capi::pa_cvolume_scale(self.as_mut(), max.0) };
match ptr.is_null() {
false => Some(self),
true => None,
}
}
#[inline]
pub fn scale_mask(&mut self, max: Volume, cm: &mut Map, mask: Option<PositionMask>)
-> Option<&mut Self>
{
let mask_actual = mask.unwrap_or(POSITION_MASK_ALL);
let ptr =
unsafe { capi::pa_cvolume_scale_mask(self.as_mut(), max.0, cm.as_ref(), mask_actual) };
match ptr.is_null() {
false => Some(self),
true => None,
}
}
#[inline]
pub fn set_position(&mut self, map: &Map, p: Position, v: Volume) -> Option<&mut Self> {
let ptr =
unsafe { capi::pa_cvolume_set_position(self.as_mut(), map.as_ref(), p.into(), v.0) };
match ptr.is_null() {
false => Some(self),
true => None,
}
}
#[inline]
pub fn get_position(&self, map: &Map, p: Position) -> Volume {
Volume(unsafe { capi::pa_cvolume_get_position(self.as_ref(), map.as_ref(), p.into()) })
}
#[inline]
pub fn merge(&mut self, with: &Self) -> Option<&mut Self> {
let ptr = unsafe { capi::pa_cvolume_merge(self.as_mut(), self.as_ref(), with.as_ref()) };
match ptr.is_null() {
false => Some(self),
true => None,
}
}
#[inline]
pub fn inc_clamp(&mut self, inc: Volume, limit: Volume) -> Option<&mut Self> {
let ptr = unsafe { capi::pa_cvolume_inc_clamp(self.as_mut(), inc.0, limit.0) };
match ptr.is_null() {
false => Some(self),
true => None,
}
}
#[inline]
pub fn increase(&mut self, inc: Volume) -> Option<&mut Self> {
let ptr = unsafe { capi::pa_cvolume_inc(self.as_mut(), inc.0) };
match ptr.is_null() {
false => Some(self),
true => None,
}
}
#[inline]
pub fn decrease(&mut self, dec: Volume) -> Option<&mut Self> {
let ptr = unsafe { capi::pa_cvolume_dec(self.as_mut(), dec.0) };
match ptr.is_null() {
false => Some(self),
true => None,
}
}
pub fn print(&self) -> String {
const PRINT_MAX: usize = capi::PA_CVOLUME_SNPRINT_MAX;
let mut tmp = Vec::with_capacity(PRINT_MAX);
unsafe {
capi::pa_cvolume_snprint(tmp.as_mut_ptr(), PRINT_MAX, self.as_ref());
CStr::from_ptr(tmp.as_mut_ptr()).to_string_lossy().into_owned()
}
}
pub fn print_db(&self) -> String {
const PRINT_DB_MAX: usize = capi::PA_SW_CVOLUME_SNPRINT_DB_MAX;
let mut tmp = Vec::with_capacity(PRINT_DB_MAX);
unsafe {
capi::pa_sw_cvolume_snprint_dB(tmp.as_mut_ptr(), PRINT_DB_MAX, self.as_ref());
CStr::from_ptr(tmp.as_mut_ptr()).to_string_lossy().into_owned()
}
}
pub fn print_verbose(&self, map: Option<&Map>, print_db: bool) -> String {
const PRINT_VERBOSE_MAX: usize = capi::PA_CVOLUME_SNPRINT_VERBOSE_MAX;
let p_map = map.map_or(null::<capi::pa_channel_map>(), |m| m.as_ref());
let mut tmp = Vec::with_capacity(PRINT_VERBOSE_MAX);
unsafe {
capi::pa_cvolume_snprint_verbose(tmp.as_mut_ptr(), PRINT_VERBOSE_MAX, self.as_ref(),
p_map, print_db as i32);
CStr::from_ptr(tmp.as_mut_ptr()).to_string_lossy().into_owned()
}
}
}
impl std::fmt::Display for ChannelVolumes {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", &self.print())
}
}