use std;
use num_derive::FromPrimitive;
use crate::{ll, fmod_result, vector, ChannelControl, ChannelGroup,
ChannelGroupRef, Dsp, DspRef, Delay, Error, Mode, SoundRef, Timeunit};
#[derive(Clone, Debug, PartialEq)]
pub struct Channel {
inner : Inner,
sound_ref : SoundRef
}
#[derive(Clone, PartialEq)]
struct Inner (*mut ll::FMOD_CHANNEL);
bitflags!{
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Channelmask : u32 {
const FRONTLEFT = ll::FMOD_CHANNELMASK_FRONT_LEFT;
const FRONTRIGHT = ll::FMOD_CHANNELMASK_FRONT_RIGHT;
const FRONTCENTER = ll::FMOD_CHANNELMASK_FRONT_CENTER;
const LOWFREQUENCY = ll::FMOD_CHANNELMASK_LOW_FREQUENCY;
const SURROUNDLEFT = ll::FMOD_CHANNELMASK_SURROUND_LEFT;
const SURROUNDRIGHT = ll::FMOD_CHANNELMASK_SURROUND_RIGHT;
const BACKLEFT = ll::FMOD_CHANNELMASK_BACK_LEFT;
const BACKRIGHT = ll::FMOD_CHANNELMASK_BACK_RIGHT;
const BACKCENTER = ll::FMOD_CHANNELMASK_BACK_CENTER;
const MONO = ll::FMOD_CHANNELMASK_MONO;
const STEREO = ll::FMOD_CHANNELMASK_STEREO;
const LRC = ll::FMOD_CHANNELMASK_LRC;
const QUAD = ll::FMOD_CHANNELMASK_QUAD;
const SURROUND = ll::FMOD_CHANNELMASK_SURROUND;
const _5POINT1 = ll::FMOD_CHANNELMASK_5POINT1;
const _5POINT1REARS = ll::FMOD_CHANNELMASK_5POINT1_REARS;
const _7POINT0 = ll::FMOD_CHANNELMASK_7POINT0;
const _7POINT1 = ll::FMOD_CHANNELMASK_7POINT1;
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, FromPrimitive)]
#[derive(Default)]
pub enum Channelorder {
#[default]
Default = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_DEFAULT as isize,
Waveformat = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_WAVEFORMAT as isize,
Protools = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_PROTOOLS as isize,
Allmono = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_ALLMONO as isize,
Allstereo = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_ALLSTEREO as isize,
Alsa = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_ALSA as isize,
MAX = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_MAX as isize
}
impl Channel {
#[inline]
pub const fn from_raw_parts (raw : *mut ll::FMOD_CHANNEL, sound_ref : SoundRef)
-> Self
{
let inner = Inner (raw);
Channel { inner, sound_ref }
}
#[inline]
pub fn sound_ref (&self) -> SoundRef {
self.sound_ref.clone()
}
#[inline]
pub fn get_channel_group (&self) -> Result <ChannelGroupRef, Error> {
let mut raw = std::ptr::null_mut();
unsafe {
fmod_result!(ll::FMOD_Channel_GetChannelGroup (self.inner.0, &mut raw))?;
}
let channel_group = ChannelGroup::from_raw_parts (raw, false,
self.sound_ref.sound.system.clone());
Ok (ChannelGroupRef { channel_group })
}
#[inline]
pub fn get_frequency (&self) -> Result <f32, Error> {
let mut frequency = 0.0;
unsafe {
fmod_result!(
ll::FMOD_Channel_GetFrequency (self.inner.0, &mut frequency)
)?;
}
Ok (frequency)
}
#[inline]
pub fn get_index (&self) -> Result <i32, Error> {
let mut index = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetIndex (self.inner.0, &mut index))?;
}
Ok (index)
}
#[inline]
pub fn get_loop_count (&self) -> Result <i32, Error> {
let mut loopcount = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetLoopCount (self.inner.0, &mut loopcount))?;
}
Ok (loopcount)
}
#[inline]
pub fn get_loop_points (&self,
loopstarttype : Timeunit, loopendtype : Timeunit
) -> Result <(u32, u32), Error> {
let mut loopstart = 0;
let mut loopend = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetLoopPoints (self.inner.0,
&mut loopstart, loopstarttype.bits(),
&mut loopend, loopendtype.bits())
)?;
}
Ok ((loopstart, loopend))
}
#[inline]
pub fn get_position (&self, timeunit : Timeunit) -> Result <u32, Error> {
let mut position = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetPosition (self.inner.0,
&mut position, timeunit.bits())
)?;
}
Ok (position)
}
#[inline]
pub fn get_priority (&self) -> Result <i32, Error> {
let mut priority = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetPriority (self.inner.0, &mut priority))?;
}
Ok (priority)
}
#[inline]
pub fn is_virtual (&self) -> Result <bool, Error> {
let mut isvirtual = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_IsVirtual (self.inner.0, &mut isvirtual))?;
}
Ok (isvirtual != 0)
}
#[inline]
pub fn set_frequency (&mut self, frequency : f32) -> Result <(), Error> {
unsafe {
fmod_result!(ll::FMOD_Channel_SetFrequency (self.inner.0, frequency))
}
}
#[inline]
pub fn set_position (&mut self, position : u32, postype : Timeunit)
-> Result <(), Error>
{
unsafe {
fmod_result!(
ll::FMOD_Channel_SetPosition (self.inner.0, position, postype.bits())
)
}
}
}
impl ChannelControl for Channel {
#[inline]
fn add_dsp (&mut self, index : i32, dsp : &mut Dsp) -> Result <(), Error> {
unsafe {
fmod_result!(ll::FMOD_Channel_AddDSP (self.inner.0, index, dsp.raw()))?;
}
Ok (())
}
#[inline]
fn add_fade_point (&mut self, dspclock : u64, volume : f32)
-> Result <(), Error>
{
unsafe {
fmod_result!(ll::FMOD_Channel_AddFadePoint (
self.inner.0, dspclock, volume))
}
}
#[inline]
fn get_3d_attributes (&self) -> Result <([f32; 3], [f32; 3]), Error> {
let mut pos = vector::to_ll ([0.0; 3]);
let mut vel = vector::to_ll ([0.0; 3]);
let mut alt_pan_pos = vector::to_ll ([0.0; 3]); unsafe {
fmod_result!(ll::FMOD_Channel_Get3DAttributes (self.inner.0,
&mut pos, &mut vel, &mut alt_pan_pos)
)?;
}
Ok ((vector::from_ll (pos), vector::from_ll (vel)))
}
#[inline]
fn get_3d_cone_orientation (&self) -> Result <[f32; 3], Error> {
let mut orientation = vector::to_ll ([0.0; 3]);
unsafe {
fmod_result!(
ll::FMOD_Channel_Get3DConeOrientation (self.inner.0, &mut orientation)
)?;
}
Ok (vector::from_ll (orientation))
}
#[inline]
fn get_3d_cone_settings (&self) -> Result <(f32, f32, f32), Error> {
let mut insideconeangle = 0.0;
let mut outsideconeangle = 0.0;
let mut outsidevolume = 0.0;
unsafe {
fmod_result!(ll::FMOD_Channel_Get3DConeSettings (self.inner.0,
&mut insideconeangle, &mut outsideconeangle, &mut outsidevolume
))?;
}
Ok ((insideconeangle, outsideconeangle, outsidevolume))
}
fn get_3d_custom_rolloff (&self) -> Result <Vec <[f32; 3]>, Error> {
let mut points = std::ptr::null_mut();
let mut numpoints = 0;
unsafe {
fmod_result!(
ll::FMOD_Channel_Get3DCustomRolloff (self.inner.0,
&mut points, &mut numpoints)
)?;
}
debug_assert!(numpoints >= 0);
#[expect(clippy::cast_sign_loss)]
let mut curve = Vec::with_capacity (numpoints as usize);
for i in 0..numpoints as isize {
let point = unsafe {
std::ptr::read (points.offset (i) as *const ll::FMOD_VECTOR)
};
curve.push (vector::from_ll (point));
}
Ok (curve)
}
#[inline]
fn get_3d_distance_filter (&self) -> Result <(bool, f32, f32), Error> {
let mut custom = 0;
let mut customlevel = 0.0;
let mut centerfreq = 0.0;
unsafe {
fmod_result!(ll::FMOD_Channel_Get3DDistanceFilter (self.inner.0,
&mut custom, &mut customlevel, &mut centerfreq)
)?;
}
let custom = custom != 0;
Ok ((custom, customlevel, centerfreq))
}
#[inline]
fn get_3d_doppler_level (&self) -> Result <f32, Error> {
let mut level = 0.0;
unsafe {
fmod_result!(ll::FMOD_Channel_Get3DDopplerLevel (self.inner.0, &mut level))?;
}
Ok (level)
}
#[inline]
fn get_3d_min_max_distance (&self) -> Result <(f32, f32), Error> {
let mut mindistance = 0.0;
let mut maxdistance = 0.0;
unsafe {
fmod_result!(ll::FMOD_Channel_Get3DMinMaxDistance (self.inner.0,
&mut mindistance, &mut maxdistance)
)?;
}
Ok ((mindistance, maxdistance))
}
#[inline]
fn get_3d_occlusion (&self) -> Result <(f32, f32), Error> {
let mut directocclusion = 0.0;
let mut reverbocclusion = 0.0;
unsafe {
fmod_result!(ll::FMOD_Channel_Get3DOcclusion (self.inner.0,
&mut directocclusion, &mut reverbocclusion)
)?;
}
Ok ((directocclusion, reverbocclusion))
}
#[inline]
fn get_3d_spread (&self) -> Result <f32, Error> {
let mut angle = 0.0;
unsafe {
fmod_result!(ll::FMOD_Channel_Get3DSpread (self.inner.0, &mut angle))?;
}
Ok (angle)
}
#[inline]
fn get_audibility (&self) -> Result <f32, Error> {
let mut audibility = 0.0;
unsafe {
fmod_result!(
ll::FMOD_Channel_GetAudibility (self.inner.0, &mut audibility)
)?;
}
Ok (audibility)
}
#[inline]
fn get_delay (&self) -> Result <Delay, Error> {
let mut dspclock_start = 0;
let mut dspclock_end = 0;
let mut stopchannels = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetDelay (self.inner.0,
&mut dspclock_start,
&mut dspclock_end,
&mut stopchannels
))?;
}
let stopchannels = stopchannels != 0;
Ok (Delay { dspclock_start, dspclock_end, stopchannels })
}
#[inline]
fn get_dsp (&self, index : i32) -> Result <DspRef, Error> {
let mut raw = std::ptr::null_mut();
unsafe {
fmod_result!(ll::FMOD_Channel_GetDSP (self.inner.0, index, &mut raw))?;
}
let dsp =
Dsp::from_raw_parts (raw, false, self.sound_ref.sound.system.clone());
Ok (DspRef { dsp })
}
#[inline]
fn get_dsp_clock (&self) -> Result <u64, Error> {
let mut dspclock = 0;
let parentclock = std::ptr::null_mut();
unsafe {
fmod_result!(
ll::FMOD_Channel_GetDSPClock (self.inner.0, &mut dspclock, parentclock)
)?;
}
Ok (dspclock)
}
#[inline]
fn get_dsp_clock_parent (&self) -> Result <u64, Error> {
let dspclock = std::ptr::null_mut();
let mut parentclock = 0;
unsafe {
fmod_result!(
ll::FMOD_Channel_GetDSPClock (self.inner.0, dspclock, &mut parentclock)
)?;
}
Ok (parentclock)
}
#[inline]
fn get_dsp_index (&self, dsp : &Dsp) -> Result <i32, Error> {
let mut index = 0;
unsafe {
fmod_result!(
ll::FMOD_Channel_GetDSPIndex (self.inner.0, dsp.raw(), &mut index)
)?;
}
Ok (index)
}
#[inline]
fn get_low_pass_gain (&self) -> Result <f32, Error> {
let mut gain = 0.0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetLowPassGain (self.inner.0, &mut gain))?;
}
Ok (gain)
}
#[inline]
fn get_mode (&self) -> Result <Mode, Error> {
let mut mode = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetMode (self.inner.0, &mut mode))?;
}
Ok (Mode::from_bits (mode).unwrap())
}
#[inline]
fn get_mute (&self) -> Result <bool, Error> {
let mut mute = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetMute (self.inner.0, &mut mute))?;
}
Ok (mute != 0)
}
#[inline]
fn get_num_dsps (&self) -> Result <u32, Error> {
let mut num = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetNumDSPs (self.inner.0, &mut num))?;
}
debug_assert!(num >= 0);
#[expect(clippy::cast_sign_loss)]
Ok (num as u32)
}
#[inline]
fn get_paused (&self) -> Result <bool, Error> {
let mut paused = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetPaused (self.inner.0, &mut paused))?;
}
Ok (paused != 0)
}
#[inline]
fn get_reverb_properties (&self, instance : i32) -> Result <f32, Error> {
let mut wet = 0.0;
unsafe {
fmod_result!(
ll::FMOD_Channel_GetReverbProperties (self.inner.0, instance, &mut wet)
)?;
}
Ok (wet)
}
#[inline]
fn get_volume (&self) -> Result <f32, Error> {
let mut volume = 0.0;
unsafe {
fmod_result!(ll::FMOD_Channel_GetVolume (self.inner.0, &mut volume))?;
}
Ok (volume)
}
#[inline]
fn is_playing (&self) -> Result <bool, Error> {
let mut isplaying = 0;
unsafe {
fmod_result!(ll::FMOD_Channel_IsPlaying (self.inner.0, &mut isplaying))?;
}
Ok (isplaying != 0)
}
#[inline]
fn remove_dsp (&mut self, dsp : &mut Dsp) -> Result <(), Error> {
unsafe {
fmod_result!(ll::FMOD_Channel_RemoveDSP (self.inner.0, dsp.raw()))?;
}
Ok (())
}
#[inline]
fn set_3d_attributes (&mut self, pos : [f32; 3], vel : [f32; 3])
-> Result <(), Error>
{
let pos = vector::to_ll (pos);
let vel = vector::to_ll (vel);
const ALT_PAN_POS : ll::FMOD_VECTOR = vector::to_ll ([0.0; 3]);
unsafe {
fmod_result!(
ll::FMOD_Channel_Set3DAttributes (self.inner.0, &pos, &vel, &ALT_PAN_POS)
)?;
};
Ok (())
}
#[inline]
fn set_delay (&mut self,
dspclock_start : u64, dspclock_end : u64, stopchannels : bool
) -> Result <(), Error> {
unsafe {
fmod_result!(
ll::FMOD_Channel_SetDelay (self.inner.0, dspclock_start, dspclock_end,
stopchannels as i32))
}
}
#[inline]
fn set_fade_point_ramp (&mut self, dspclock : u64, volume : f32)
-> Result <(), Error>
{
unsafe {
fmod_result!(
ll::FMOD_Channel_SetFadePointRamp (self.inner.0, dspclock, volume))
}
}
#[inline]
fn set_mute (&mut self, mute : bool) -> Result <(), Error> {
unsafe {
fmod_result!(ll::FMOD_Channel_SetMute (self.inner.0, mute as i32))
}
}
#[inline]
fn set_paused (&mut self, paused : bool) -> Result <(), Error> {
unsafe {
fmod_result!(ll::FMOD_Channel_SetPaused (self.inner.0, paused as i32))
}
}
#[inline]
fn set_reverb_properties (&mut self, instance : i32, wet : f32)
-> Result <(), Error>
{
unsafe {
fmod_result!(
ll::FMOD_Channel_SetReverbProperties (self.inner.0, instance, wet))
}
}
#[inline]
fn set_volume (&mut self, volume : f32) -> Result <(), Error> {
unsafe {
fmod_result!(ll::FMOD_Channel_SetVolume (self.inner.0, volume))
}
}
#[inline]
fn stop (&mut self) -> Result <(), Error> {
unsafe {
fmod_result!(ll::FMOD_Channel_Stop (self.inner.0))
}
}
}
impl Default for Channelmask {
fn default() -> Self {
Channelmask::empty()
}
}
impl std::fmt::Debug for Inner {
fn fmt (&self, f : &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:p}", self.0)
}
}