fmod/
channel.rs

1use std;
2use num_derive::FromPrimitive;
3use crate::{ll, fmod_result, vector, ChannelControl, ChannelGroup,
4  ChannelGroupRef, Dsp, DspRef, Delay, Error, Mode, SoundRef, Timeunit};
5
6/// A *weak* handle to a sound playing on a virtual channel.
7///
8/// If this channel is stolen by the priority system because another sound was
9/// played and no other channels were free, all subsequent method calls on this
10/// handle will return `Error::ChannelStolen`.
11///
12/// The handle will also return `Error::InvalidHandle` after the next call to
13/// `system.update()` if (non-looping) playback has reached the end of the
14/// sound, or if `channel.stop()` is called. Note that resetting the position
15/// before calling `system.update()` will *not* prevent the channel handle from
16/// being invalidated.
17///
18/// Note that the channel holds a weak reference to the sound that is playing.
19/// If the channel handle is dropped, but the sound is still alive, the channel
20/// will continue playing.
21#[derive(Clone, Debug, PartialEq)]
22pub struct Channel {
23  inner     : Inner,
24  sound_ref : SoundRef
25}
26
27// note this is a weak reference: there is no action when dropped
28#[derive(Clone, PartialEq)]
29struct Inner (*mut ll::FMOD_CHANNEL);
30
31bitflags!{
32  #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
33  pub struct Channelmask : u32 {
34    const FRONTLEFT     = ll::FMOD_CHANNELMASK_FRONT_LEFT;
35    const FRONTRIGHT    = ll::FMOD_CHANNELMASK_FRONT_RIGHT;
36    const FRONTCENTER   = ll::FMOD_CHANNELMASK_FRONT_CENTER;
37    const LOWFREQUENCY  = ll::FMOD_CHANNELMASK_LOW_FREQUENCY;
38    const SURROUNDLEFT  = ll::FMOD_CHANNELMASK_SURROUND_LEFT;
39    const SURROUNDRIGHT = ll::FMOD_CHANNELMASK_SURROUND_RIGHT;
40    const BACKLEFT      = ll::FMOD_CHANNELMASK_BACK_LEFT;
41    const BACKRIGHT     = ll::FMOD_CHANNELMASK_BACK_RIGHT;
42    const BACKCENTER    = ll::FMOD_CHANNELMASK_BACK_CENTER;
43    const MONO          = ll::FMOD_CHANNELMASK_MONO;
44    const STEREO        = ll::FMOD_CHANNELMASK_STEREO;
45    const LRC           = ll::FMOD_CHANNELMASK_LRC;
46    const QUAD          = ll::FMOD_CHANNELMASK_QUAD;
47    const SURROUND      = ll::FMOD_CHANNELMASK_SURROUND;
48    const _5POINT1      = ll::FMOD_CHANNELMASK_5POINT1;
49    const _5POINT1REARS = ll::FMOD_CHANNELMASK_5POINT1_REARS;
50    const _7POINT0      = ll::FMOD_CHANNELMASK_7POINT0;
51    const _7POINT1      = ll::FMOD_CHANNELMASK_7POINT1;
52  }
53}
54
55#[derive(Copy, Clone, Debug, Eq, PartialEq, FromPrimitive)]
56#[derive(Default)]
57pub enum Channelorder {
58  #[default]
59  Default    = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_DEFAULT    as isize,
60  Waveformat = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_WAVEFORMAT as isize,
61  Protools   = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_PROTOOLS   as isize,
62  Allmono    = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_ALLMONO    as isize,
63  Allstereo  = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_ALLSTEREO  as isize,
64  Alsa       = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_ALSA       as isize,
65  MAX        = ll::FMOD_CHANNELORDER_FMOD_CHANNELORDER_MAX        as isize
66}
67
68impl Channel {
69  #[inline]
70  pub const fn from_raw_parts (raw : *mut ll::FMOD_CHANNEL, sound_ref : SoundRef)
71    -> Self
72  {
73    let inner = Inner (raw);
74    Channel { inner, sound_ref }
75  }
76
77  /// Sound that the channel was assigned to play
78  #[inline]
79  pub fn sound_ref (&self) -> SoundRef {
80    self.sound_ref.clone()
81  }
82
83  /// Retrieves the currently assigned channel group for the channel
84  #[inline]
85  pub fn get_channel_group (&self) -> Result <ChannelGroupRef, Error> {
86    let mut raw = std::ptr::null_mut();
87    unsafe {
88      fmod_result!(ll::FMOD_Channel_GetChannelGroup (self.inner.0, &mut raw))?;
89    }
90    let channel_group = ChannelGroup::from_raw_parts (raw, false,
91      self.sound_ref.sound.system.clone());
92    Ok (ChannelGroupRef { channel_group })
93  }
94
95  #[inline]
96  pub fn get_frequency (&self) -> Result <f32, Error> {
97    let mut frequency = 0.0;
98    unsafe {
99      fmod_result!(
100        ll::FMOD_Channel_GetFrequency (self.inner.0, &mut frequency)
101      )?;
102    }
103    Ok (frequency)
104  }
105
106  /// Retrieves the internal channel index for a channel.
107  ///
108  /// Channel indices are in the range 0 to the `maxchannels` specified at
109  /// System creation.
110  #[inline]
111  pub fn get_index (&self) -> Result <i32, Error> {
112    let mut index = 0;
113    unsafe {
114      fmod_result!(ll::FMOD_Channel_GetIndex (self.inner.0, &mut index))?;
115    }
116    Ok (index)
117  }
118
119  #[inline]
120  pub fn get_loop_count (&self) -> Result <i32, Error> {
121    let mut loopcount = 0;
122    unsafe {
123      fmod_result!(ll::FMOD_Channel_GetLoopCount (self.inner.0, &mut loopcount))?;
124    }
125    Ok (loopcount)
126  }
127
128  #[inline]
129  pub fn get_loop_points (&self,
130    loopstarttype : Timeunit, loopendtype : Timeunit
131  ) -> Result <(u32, u32), Error> {
132    let mut loopstart = 0;
133    let mut loopend   = 0;
134    unsafe {
135      fmod_result!(ll::FMOD_Channel_GetLoopPoints (self.inner.0,
136        &mut loopstart, loopstarttype.bits(),
137        &mut loopend, loopendtype.bits())
138      )?;
139    }
140    Ok ((loopstart, loopend))
141  }
142
143  #[inline]
144  pub fn get_position (&self, timeunit : Timeunit) -> Result <u32, Error> {
145    let mut position = 0;
146    unsafe {
147      fmod_result!(ll::FMOD_Channel_GetPosition (self.inner.0,
148        &mut position, timeunit.bits())
149      )?;
150    }
151    Ok (position)
152  }
153
154  #[inline]
155  pub fn get_priority (&self) -> Result <i32, Error> {
156    let mut priority = 0;
157    unsafe {
158      fmod_result!(ll::FMOD_Channel_GetPriority (self.inner.0, &mut priority))?;
159    }
160    Ok (priority)
161  }
162
163  #[inline]
164  pub fn is_virtual (&self) -> Result <bool, Error> {
165    let mut isvirtual = 0;
166    unsafe {
167      fmod_result!(ll::FMOD_Channel_IsVirtual (self.inner.0, &mut isvirtual))?;
168    }
169    Ok (isvirtual != 0)
170  }
171
172  #[inline]
173  pub fn set_frequency (&mut self, frequency : f32) -> Result <(), Error> {
174    unsafe {
175      fmod_result!(ll::FMOD_Channel_SetFrequency (self.inner.0, frequency))
176    }
177  }
178
179  #[inline]
180  pub fn set_position (&mut self, position : u32, postype : Timeunit)
181    -> Result <(), Error>
182  {
183    unsafe {
184      fmod_result!(
185        ll::FMOD_Channel_SetPosition (self.inner.0, position, postype.bits())
186      )
187    }
188  }
189
190}
191
192impl ChannelControl for Channel {
193  /// Add a DSP to the DSP chain at the given index. Index must be a position
194  /// in the range $[0, numDSPs]$, or else one of the special indices:
195  ///
196  /// - `DspIndex::Head  == -1` -- head of the chain; always equal to 0
197  /// - `DspIndex::Fader == -2` -- built-in fader DSP; initially 0
198  /// - `DspIndex::Tail  == -3` -- tail of the chain; equal to $numDSPs-1$
199  ///
200  /// # Errors
201  ///
202  /// An `InvalidParam` error will be returned if `index > self.get_num_dsps()`.
203  #[inline]
204  fn add_dsp (&mut self, index : i32, dsp : &mut Dsp) -> Result <(), Error> {
205    unsafe {
206      fmod_result!(ll::FMOD_Channel_AddDSP (self.inner.0, index, dsp.raw()))?;
207    }
208    Ok (())
209  }
210
211  #[inline]
212  fn add_fade_point (&mut self, dspclock : u64, volume : f32)
213    -> Result <(), Error>
214  {
215    unsafe {
216      fmod_result!(ll::FMOD_Channel_AddFadePoint (
217        self.inner.0, dspclock, volume))
218    }
219  }
220
221  #[inline]
222  fn get_3d_attributes (&self) -> Result <([f32; 3], [f32; 3]), Error> {
223    let mut pos = vector::to_ll ([0.0; 3]);
224    let mut vel = vector::to_ll ([0.0; 3]);
225    let mut alt_pan_pos = vector::to_ll ([0.0; 3]);  // unimplemented
226    unsafe {
227      fmod_result!(ll::FMOD_Channel_Get3DAttributes (self.inner.0,
228        &mut pos, &mut vel, &mut alt_pan_pos)
229      )?;
230    }
231    Ok ((vector::from_ll (pos), vector::from_ll (vel)))
232  }
233
234  #[inline]
235  fn get_3d_cone_orientation (&self) -> Result <[f32; 3], Error> {
236    let mut orientation = vector::to_ll ([0.0; 3]);
237    unsafe {
238      fmod_result!(
239        ll::FMOD_Channel_Get3DConeOrientation (self.inner.0, &mut orientation)
240      )?;
241    }
242    Ok (vector::from_ll (orientation))
243  }
244
245  /// Retrieves the angles that define the `sound_ref` projection cone including the
246  /// volume when outside the cone.
247  ///
248  /// Returns `(insideconeangle, outsideconeangle, outsidevolume)`.
249  #[inline]
250  fn get_3d_cone_settings (&self) -> Result <(f32, f32, f32), Error> {
251    let mut insideconeangle  = 0.0;
252    let mut outsideconeangle = 0.0;
253    let mut outsidevolume    = 0.0;
254    unsafe {
255      fmod_result!(ll::FMOD_Channel_Get3DConeSettings (self.inner.0,
256        &mut insideconeangle, &mut outsideconeangle, &mut outsidevolume
257      ))?;
258    }
259    Ok ((insideconeangle, outsideconeangle, outsidevolume))
260  }
261
262  fn get_3d_custom_rolloff (&self) -> Result <Vec <[f32; 3]>, Error> {
263    let mut points = std::ptr::null_mut();
264    let mut numpoints = 0;
265    unsafe {
266      fmod_result!(
267        ll::FMOD_Channel_Get3DCustomRolloff (self.inner.0,
268          &mut points, &mut numpoints)
269      )?;
270    }
271    debug_assert!(numpoints >= 0);
272    #[expect(clippy::cast_sign_loss)]
273    let mut curve = Vec::with_capacity (numpoints as usize);
274    for i in 0..numpoints as isize {
275      let point = unsafe {
276        std::ptr::read (points.offset (i) as *const ll::FMOD_VECTOR)
277      };
278      curve.push (vector::from_ll (point));
279    }
280    Ok (curve)
281  }
282
283  /// Retrieve the settings for the 3D distance filter properties for a Channel
284  /// or Channel Group.
285  ///
286  /// Returns `(custom, customlevel, centerfreq)`.
287  #[inline]
288  fn get_3d_distance_filter (&self) -> Result <(bool, f32, f32), Error> {
289    let mut custom      = 0;
290    let mut customlevel = 0.0;
291    let mut centerfreq  = 0.0;
292    unsafe {
293      fmod_result!(ll::FMOD_Channel_Get3DDistanceFilter (self.inner.0,
294        &mut custom, &mut customlevel, &mut centerfreq)
295      )?;
296    }
297    let custom = custom != 0;
298    Ok ((custom, customlevel, centerfreq))
299  }
300
301  #[inline]
302  fn get_3d_doppler_level (&self) -> Result <f32, Error> {
303    let mut level = 0.0;
304    unsafe {
305      fmod_result!(ll::FMOD_Channel_Get3DDopplerLevel (self.inner.0, &mut level))?;
306    }
307    Ok (level)
308  }
309
310  /// Retrieves the minimum and maximum audible distance
311  #[inline]
312  fn get_3d_min_max_distance (&self) -> Result <(f32, f32), Error> {
313    let mut mindistance = 0.0;
314    let mut maxdistance = 0.0;
315    unsafe {
316      fmod_result!(ll::FMOD_Channel_Get3DMinMaxDistance (self.inner.0,
317        &mut mindistance, &mut maxdistance)
318      )?;
319    }
320    Ok ((mindistance, maxdistance))
321  }
322
323  /// Retrieves the occlusion factors.
324  ///
325  /// Returns `(directocclusion, reverbocclusion)`.
326  #[inline]
327  fn get_3d_occlusion (&self) -> Result <(f32, f32), Error> {
328    let mut directocclusion = 0.0;
329    let mut reverbocclusion = 0.0;
330    unsafe {
331      fmod_result!(ll::FMOD_Channel_Get3DOcclusion (self.inner.0,
332        &mut directocclusion, &mut reverbocclusion)
333      )?;
334    }
335    Ok ((directocclusion, reverbocclusion))
336  }
337
338  /// Retrieves the spread of a 3D `sound_ref` in speaker space.
339  ///
340  /// Returns the speaker spread angle.
341  #[inline]
342  fn get_3d_spread (&self) -> Result <f32, Error> {
343    let mut angle = 0.0;
344    unsafe {
345      fmod_result!(ll::FMOD_Channel_Get3DSpread (self.inner.0, &mut angle))?;
346    }
347    Ok (angle)
348  }
349
350  #[inline]
351  fn get_audibility (&self) -> Result <f32, Error> {
352    let mut audibility = 0.0;
353    unsafe {
354      fmod_result!(
355        ll::FMOD_Channel_GetAudibility (self.inner.0, &mut audibility)
356      )?;
357    }
358    Ok (audibility)
359  }
360
361  #[inline]
362  fn get_delay (&self) -> Result <Delay, Error> {
363    let mut dspclock_start = 0;
364    let mut dspclock_end   = 0;
365    let mut stopchannels   = 0;
366    unsafe {
367      fmod_result!(ll::FMOD_Channel_GetDelay (self.inner.0,
368        &mut dspclock_start,
369        &mut dspclock_end,
370        &mut stopchannels
371      ))?;
372    }
373    let stopchannels = stopchannels != 0;
374    Ok (Delay { dspclock_start, dspclock_end, stopchannels })
375  }
376
377  /// Retrieve the DSP unit at the specified index
378  #[inline]
379  fn get_dsp (&self, index : i32) -> Result <DspRef, Error> {
380    let mut raw = std::ptr::null_mut();
381    unsafe {
382      fmod_result!(ll::FMOD_Channel_GetDSP (self.inner.0, index, &mut raw))?;
383    }
384    let dsp =
385      Dsp::from_raw_parts (raw, false, self.sound_ref.sound.system.clone());
386    Ok (DspRef { dsp })
387  }
388
389  /// DSP clock value for the head DSP node
390  #[inline]
391  fn get_dsp_clock (&self) -> Result <u64, Error> {
392    let mut dspclock = 0;
393    let parentclock = std::ptr::null_mut();
394    unsafe {
395      fmod_result!(
396        ll::FMOD_Channel_GetDSPClock (self.inner.0, &mut dspclock, parentclock)
397      )?;
398    }
399    Ok (dspclock)
400  }
401
402  /// DSP clock value for the tail DSP node
403  #[inline]
404  fn get_dsp_clock_parent (&self) -> Result <u64, Error> {
405    let dspclock = std::ptr::null_mut();
406    let mut parentclock = 0;
407    unsafe {
408      fmod_result!(
409        ll::FMOD_Channel_GetDSPClock (self.inner.0, dspclock, &mut parentclock)
410      )?;
411    }
412    Ok (parentclock)
413  }
414
415  /// Retrieve the index in the DSP chain of the provided DSP
416  #[inline]
417  fn get_dsp_index (&self, dsp : &Dsp) -> Result <i32, Error> {
418    let mut index = 0;
419    unsafe {
420      fmod_result!(
421        ll::FMOD_Channel_GetDSPIndex (self.inner.0, dsp.raw(), &mut index)
422      )?;
423    }
424    Ok (index)
425  }
426
427  #[inline]
428  fn get_low_pass_gain (&self) -> Result <f32, Error> {
429    let mut gain = 0.0;
430    unsafe {
431      fmod_result!(ll::FMOD_Channel_GetLowPassGain (self.inner.0, &mut gain))?;
432    }
433    Ok (gain)
434  }
435
436  #[inline]
437  fn get_mode (&self) -> Result <Mode, Error> {
438    let mut mode = 0;
439    unsafe {
440      fmod_result!(ll::FMOD_Channel_GetMode (self.inner.0, &mut mode))?;
441    }
442    Ok (Mode::from_bits (mode).unwrap())
443  }
444
445  #[inline]
446  fn get_mute (&self) -> Result <bool, Error> {
447    let mut mute = 0;
448    unsafe {
449      fmod_result!(ll::FMOD_Channel_GetMute (self.inner.0, &mut mute))?;
450    }
451    Ok (mute != 0)
452  }
453
454  /// Retrieves the number of DSP units in the DSP chain
455  #[inline]
456  fn get_num_dsps (&self) -> Result <u32, Error> {
457    let mut num = 0;
458    unsafe {
459      fmod_result!(ll::FMOD_Channel_GetNumDSPs (self.inner.0, &mut num))?;
460    }
461    debug_assert!(num >= 0);
462    #[expect(clippy::cast_sign_loss)]
463    Ok (num as u32)
464  }
465
466  #[inline]
467  fn get_paused (&self) -> Result <bool, Error> {
468    let mut paused = 0;
469    unsafe {
470      fmod_result!(ll::FMOD_Channel_GetPaused (self.inner.0, &mut paused))?;
471    }
472    Ok (paused != 0)
473  }
474
475  /// Retrieves the wet level (or send level) for a particular reverb instance.
476  ///
477  /// Returns the send level for the signal to the reverb, from 0 (none) to 1.0
478  /// (full).
479  ///
480  /// `instance` -- Index of the particular reverb instance to target, from 0 to
481  /// `dsp::REVERB_MAXINSTANCES`.
482  #[inline]
483  fn get_reverb_properties (&self, instance : i32) -> Result <f32, Error> {
484    let mut wet = 0.0;
485    unsafe {
486      fmod_result!(
487        ll::FMOD_Channel_GetReverbProperties (self.inner.0, instance, &mut wet)
488      )?;
489    }
490    Ok (wet)
491  }
492
493  #[inline]
494  fn get_volume (&self) -> Result <f32, Error> {
495    let mut volume = 0.0;
496    unsafe {
497      fmod_result!(ll::FMOD_Channel_GetVolume (self.inner.0, &mut volume))?;
498    }
499    Ok (volume)
500  }
501
502  #[inline]
503  fn is_playing (&self) -> Result <bool, Error> {
504    let mut isplaying = 0;
505    unsafe {
506      fmod_result!(ll::FMOD_Channel_IsPlaying (self.inner.0, &mut isplaying))?;
507    }
508    Ok (isplaying != 0)
509  }
510
511  #[inline]
512  fn remove_dsp (&mut self, dsp : &mut Dsp) -> Result <(), Error> {
513    unsafe {
514      fmod_result!(ll::FMOD_Channel_RemoveDSP (self.inner.0, dsp.raw()))?;
515    }
516    Ok (())
517  }
518
519  #[inline]
520  fn set_3d_attributes (&mut self, pos : [f32; 3], vel : [f32; 3])
521    -> Result <(), Error>
522  {
523    let pos = vector::to_ll (pos);
524    let vel = vector::to_ll (vel);
525    // FMOD1.10: unimplemented
526    const ALT_PAN_POS : ll::FMOD_VECTOR = vector::to_ll ([0.0; 3]);
527    unsafe {
528      fmod_result!(
529        ll::FMOD_Channel_Set3DAttributes (self.inner.0, &pos, &vel, &ALT_PAN_POS)
530      )?;
531    };
532    Ok (())
533  }
534
535  #[inline]
536  fn set_delay (&mut self,
537    dspclock_start : u64, dspclock_end : u64, stopchannels : bool
538  ) -> Result <(), Error> {
539    unsafe {
540      fmod_result!(
541        ll::FMOD_Channel_SetDelay (self.inner.0, dspclock_start, dspclock_end,
542          stopchannels as i32))
543    }
544  }
545
546  #[inline]
547  fn set_fade_point_ramp (&mut self, dspclock : u64, volume : f32)
548    -> Result <(), Error>
549  {
550    unsafe {
551      fmod_result!(
552        ll::FMOD_Channel_SetFadePointRamp (self.inner.0, dspclock, volume))
553    }
554  }
555
556  #[inline]
557  fn set_mute (&mut self, mute : bool) -> Result <(), Error> {
558    unsafe {
559      fmod_result!(ll::FMOD_Channel_SetMute (self.inner.0, mute as i32))
560    }
561  }
562
563  #[inline]
564  fn set_paused (&mut self, paused : bool) -> Result <(), Error> {
565    unsafe {
566      fmod_result!(ll::FMOD_Channel_SetPaused (self.inner.0, paused as i32))
567    }
568  }
569
570  #[inline]
571  fn set_reverb_properties (&mut self, instance : i32, wet : f32)
572    -> Result <(), Error>
573  {
574    unsafe {
575      fmod_result!(
576        ll::FMOD_Channel_SetReverbProperties (self.inner.0, instance, wet))
577    }
578  }
579
580  #[inline]
581  fn set_volume (&mut self, volume : f32) -> Result <(), Error> {
582    unsafe {
583      fmod_result!(ll::FMOD_Channel_SetVolume (self.inner.0, volume))
584    }
585  }
586
587  #[inline]
588  fn stop (&mut self) -> Result <(), Error> {
589    unsafe {
590      fmod_result!(ll::FMOD_Channel_Stop (self.inner.0))
591    }
592  }
593
594}
595
596
597impl Default for Channelmask {
598  fn default() -> Self {
599    Channelmask::empty()
600  }
601}
602
603impl std::fmt::Debug for Inner {
604  fn fmt (&self, f : &mut std::fmt::Formatter) -> std::fmt::Result {
605    write!(f, "{:p}", self.0)
606  }
607}