1use std;
2use std::rc::Rc;
3use std::ops::{Deref, DerefMut};
4use log;
5use crate::{ll, fmod_result, vector, Channel, ChannelControl, Dsp, DspRef,
6 Delay, Error, Mode, Sound, System};
7
8#[derive(Clone, Debug, PartialEq)]
9pub struct ChannelGroup {
10 inner : Rc <Inner>,
11 system : System
12}
13
14#[derive(Clone, Debug, PartialEq)]
15pub struct ChannelGroupRef {
16 pub (crate) channel_group : ChannelGroup
17}
18
19#[derive(PartialEq)]
20struct Inner {
21 raw : *mut ll::FMOD_CHANNELGROUP,
22 owned : bool
23}
24
25impl ChannelGroup {
26 #[inline]
27 pub (crate) fn from_raw_parts (
28 raw : *mut ll::FMOD_CHANNELGROUP,
29 owned : bool,
30 system : System
31 ) -> Self {
32 let inner = Rc::new (Inner { raw, owned });
33 ChannelGroup { inner, system }
34 }
35
36 #[inline]
37 pub fn is_master (&self) -> Result <bool, Error> {
38 let master = self.system.get_master_channel_group()?;
39 Ok (self.raw() == master.raw())
40 }
41
42 #[inline]
43 pub fn raw (&self) -> *mut ll::FMOD_CHANNELGROUP {
44 self.inner.raw
45 }
46
47 #[inline]
48 pub (crate) fn raw_mut (&mut self) -> *mut ll::FMOD_CHANNELGROUP {
49 self.inner.raw
50 }
51
52 #[inline]
53 pub fn channel_group_ref (&self) -> ChannelGroupRef {
54 let channel_group = {
55 let inner = Rc::new (Inner {
56 raw: self.raw(),
57 owned: false
58 });
59 let system = self.system.clone();
60 ChannelGroup { inner, system }
61 };
62 ChannelGroupRef { channel_group }
63 }
64
65 #[inline]
68 pub fn get_channel (&self, index : i32) -> Result <Channel, Error> {
69 let mut raw_channel = std::ptr::null_mut();
70 let mut raw_sound = std::ptr::null_mut();
71 unsafe {
72 fmod_result!(
73 ll::FMOD_ChannelGroup_GetChannel (self.raw(), index, &mut raw_channel)
74 )?;
75 }
76 unsafe {
77 fmod_result!(
78 ll::FMOD_Channel_GetCurrentSound (raw_channel, &mut raw_sound)
79 )?;
80 }
81 let sound = Sound::from_raw_parts (raw_sound, false, self.system.clone());
82 Ok (Channel::from_raw_parts (raw_channel, sound.sound_ref()))
83 }
84
85 #[inline]
87 pub fn get_group (&self, index : i32) -> Result <ChannelGroupRef, Error> {
88 let mut raw = std::ptr::null_mut();
89 unsafe {
90 fmod_result!(
91 ll::FMOD_ChannelGroup_GetGroup (self.raw(), index, &mut raw)
92 )?;
93 }
94 let channel_group =
96 ChannelGroup::from_raw_parts (raw, false, self.system.clone());
97 Ok (ChannelGroupRef { channel_group })
98 }
99
100 #[inline]
101 pub fn get_name (&self) -> Result <String, Error> {
102 let namelen = 256i32;
104 #[expect(clippy::cast_sign_loss)]
105 let mut name = vec![0; namelen as usize];
106 unsafe {
107 fmod_result!(ll::FMOD_ChannelGroup_GetName (self.raw(),
108 name.as_mut_ptr() as *mut i8, namelen
109 ))?;
110 }
111 name.retain (|c| *c != 0x0);
112 String::from_utf8 (name).map_err (|e|{
113 log::error!("channel group get name string invalid utf8: {e}");
114 Error::InvalidString
115 })
116 }
117
118 #[inline]
119 pub fn get_num_channels (&self) -> Result <i32, Error> {
120 let mut numchannels = 0;
121 unsafe {
122 fmod_result!(
123 ll::FMOD_ChannelGroup_GetNumChannels (self.raw(), &mut numchannels)
124 )?;
125 }
126 Ok (numchannels)
127 }
128
129 #[inline]
130 pub fn get_num_groups (&self) -> Result <i32, Error> {
131 let mut numgroups = 0;
132 unsafe {
133 fmod_result!(
134 ll::FMOD_ChannelGroup_GetNumGroups (self.raw(), &mut numgroups)
135 )?;
136 }
137 Ok (numgroups)
138 }
139
140 #[inline]
144 pub fn get_parent_group (&self) -> Result <Option <ChannelGroupRef>, Error> {
145 let mut raw = std::ptr::null_mut();
146 unsafe {
147 fmod_result!(
150 ll::FMOD_ChannelGroup_GetParentGroup (self.raw(), &mut raw)
151 )?;
152 }
153 if !self.is_master()? {
154 let channel_group =
155 ChannelGroup::from_raw_parts (raw, false, self.system.clone());
156 Ok (Some (ChannelGroupRef { channel_group }))
157 } else {
158 debug_assert_eq!(raw, std::ptr::null_mut());
159 Ok (None)
160 }
161 }
162
163}
164
165impl ChannelControl for ChannelGroup {
166 #[inline]
177 fn add_dsp (&mut self, index : i32, dsp : &mut Dsp) -> Result <(), Error> {
178 unsafe {
179 fmod_result!(
180 ll::FMOD_ChannelGroup_AddDSP (self.raw(), index, dsp.raw())
181 )?;
182 }
183 Ok (())
184 }
185
186 #[inline]
187 fn add_fade_point (&mut self, dspclock : u64, volume : f32)
188 -> Result <(), Error>
189 {
190 unsafe {
191 fmod_result!(ll::FMOD_ChannelGroup_AddFadePoint (
192 self.raw_mut(), dspclock, volume))
193 }
194 }
195
196 #[inline]
197 fn get_3d_attributes (&self) -> Result <([f32; 3], [f32; 3]), Error> {
198 let mut pos = vector::to_ll ([0.0; 3]);
199 let mut vel = vector::to_ll ([0.0; 3]);
200 let mut alt_pan_pos = vector::to_ll ([0.0; 3]); unsafe {
202 fmod_result!(ll::FMOD_ChannelGroup_Get3DAttributes (self.raw(),
203 &mut pos, &mut vel, &mut alt_pan_pos)
204 )?;
205 }
206 Ok ((vector::from_ll (pos), vector::from_ll (vel)))
207 }
208
209 #[inline]
210 fn get_3d_cone_orientation (&self) -> Result <[f32; 3], Error> {
211 let mut orientation = vector::to_ll ([0.0; 3]);
212 unsafe {
213 fmod_result!(
214 ll::FMOD_ChannelGroup_Get3DConeOrientation (self.raw(), &mut orientation)
215 )?;
216 }
217 Ok (vector::from_ll (orientation))
218 }
219
220 #[inline]
225 fn get_3d_cone_settings (&self) -> Result <(f32, f32, f32), Error> {
226 let mut insideconeangle = 0.0;
227 let mut outsideconeangle = 0.0;
228 let mut outsidevolume = 0.0;
229 unsafe {
230 fmod_result!(ll::FMOD_ChannelGroup_Get3DConeSettings (self.raw(),
231 &mut insideconeangle, &mut outsideconeangle, &mut outsidevolume
232 ))?;
233 }
234 Ok ((insideconeangle, outsideconeangle, outsidevolume))
235 }
236
237 fn get_3d_custom_rolloff (&self) -> Result <Vec <[f32; 3]>, Error> {
238 let mut points = std::ptr::null_mut();
239 let mut numpoints = 0;
240 unsafe {
241 fmod_result!(
242 ll::FMOD_ChannelGroup_Get3DCustomRolloff (self.raw(),
243 &mut points, &mut numpoints)
244 )?;
245 }
246 #[expect(clippy::cast_sign_loss)]
247 let mut curve = Vec::with_capacity (numpoints as usize);
248 for i in 0..numpoints as isize {
249 let point = unsafe {
250 std::ptr::read (points.offset (i) as *const ll::FMOD_VECTOR)
251 };
252 curve.push (vector::from_ll (point));
253 }
254 Ok (curve)
255 }
256
257 #[inline]
262 fn get_3d_distance_filter (&self) -> Result <(bool, f32, f32), Error> {
263 let mut custom = 0;
264 let mut customlevel = 0.0;
265 let mut centerfreq = 0.0;
266 unsafe {
267 fmod_result!(ll::FMOD_ChannelGroup_Get3DDistanceFilter (self.raw(),
268 &mut custom, &mut customlevel, &mut centerfreq)
269 )?;
270 }
271 let custom = custom != 0;
272 Ok ((custom, customlevel, centerfreq))
273 }
274
275 #[inline]
276 fn get_3d_doppler_level (&self) -> Result <f32, Error> {
277 let mut level = 0.0;
278 unsafe {
279 fmod_result!(
280 ll::FMOD_ChannelGroup_Get3DDopplerLevel (self.raw(), &mut level)
281 )?;
282 }
283 Ok (level)
284 }
285
286 #[inline]
288 fn get_3d_min_max_distance (&self) -> Result <(f32, f32), Error> {
289 let mut mindistance = 0.0;
290 let mut maxdistance = 0.0;
291 unsafe {
292 fmod_result!(ll::FMOD_ChannelGroup_Get3DMinMaxDistance (self.raw(),
293 &mut mindistance, &mut maxdistance)
294 )?;
295 }
296 Ok ((mindistance, maxdistance))
297 }
298
299 #[inline]
303 fn get_3d_occlusion (&self) -> Result <(f32, f32), Error> {
304 let mut directocclusion = 0.0;
305 let mut reverbocclusion = 0.0;
306 unsafe {
307 fmod_result!(ll::FMOD_ChannelGroup_Get3DOcclusion (self.raw(),
308 &mut directocclusion, &mut reverbocclusion)
309 )?;
310 }
311 Ok ((directocclusion, reverbocclusion))
312 }
313
314 #[inline]
318 fn get_3d_spread (&self) -> Result <f32, Error> {
319 let mut angle = 0.0;
320 unsafe {
321 fmod_result!(ll::FMOD_ChannelGroup_Get3DSpread (self.raw(), &mut angle))?;
322 }
323 Ok (angle)
324 }
325
326 #[inline]
327 fn get_audibility (&self) -> Result <f32, Error> {
328 let mut audibility = 0.0;
329 unsafe {
330 fmod_result!(ll::FMOD_ChannelGroup_GetAudibility (self.raw(), &mut audibility))?;
331 }
332 Ok (audibility)
333 }
334
335 #[inline]
336 fn get_delay (&self) -> Result <Delay, Error> {
337 let mut dspclock_start = 0;
338 let mut dspclock_end = 0;
339 let mut stopchannels = 0;
340 unsafe {
341 fmod_result!(ll::FMOD_ChannelGroup_GetDelay (self.raw(),
342 &mut dspclock_start,
343 &mut dspclock_end,
344 &mut stopchannels
345 ))?;
346 }
347 let stopchannels = stopchannels != 0;
348 Ok (Delay { dspclock_start, dspclock_end, stopchannels })
349 }
350
351 #[inline]
353 fn get_dsp (&self, index : i32) -> Result <DspRef, Error> {
354 let mut raw = std::ptr::null_mut();
355 unsafe {
356 fmod_result!(
357 ll::FMOD_ChannelGroup_GetDSP (self.raw(), index, &mut raw)
358 )?;
359 }
360 let dsp = Dsp::from_raw_parts (raw, false, self.system.clone());
361 Ok (DspRef { dsp })
362 }
363
364 #[inline]
366 fn get_dsp_clock (&self) -> Result <u64, Error> {
367 let mut dspclock = 0;
368 let parentclock = std::ptr::null_mut();
369 unsafe {
370 fmod_result!(
371 ll::FMOD_ChannelGroup_GetDSPClock (self.raw(), &mut dspclock, parentclock)
372 )?;
373 }
374 Ok (dspclock)
375 }
376
377 #[inline]
379 fn get_dsp_clock_parent (&self) -> Result <u64, Error> {
380 let dspclock = std::ptr::null_mut();
381 let mut parentclock = 0;
382 unsafe {
383 fmod_result!(
384 ll::FMOD_ChannelGroup_GetDSPClock (self.raw(), dspclock, &mut parentclock)
385 )?;
386 }
387 Ok (parentclock)
388 }
389
390 #[inline]
392 fn get_dsp_index (&self, dsp : &Dsp) -> Result <i32, Error> {
393 let mut index = 0;
394 unsafe {
395 fmod_result!(
396 ll::FMOD_ChannelGroup_GetDSPIndex (self.raw(), dsp.raw(), &mut index)
397 )?;
398 }
399 Ok (index)
400 }
401
402 #[inline]
403 fn get_low_pass_gain (&self) -> Result <f32, Error> {
404 let mut gain = 0.0;
405 unsafe {
406 fmod_result!(ll::FMOD_ChannelGroup_GetLowPassGain (self.raw(), &mut gain))?;
407 }
408 Ok (gain)
409 }
410
411 #[inline]
412 fn get_mode (&self) -> Result <Mode, Error> {
413 let mut mode = 0;
414 unsafe {
415 fmod_result!(ll::FMOD_ChannelGroup_GetMode (self.raw(), &mut mode))?;
416 }
417 Ok (Mode::from_bits (mode).unwrap())
418 }
419
420 fn get_mute (&self) -> Result <bool, Error> {
421 let mut mute = 0;
422 unsafe {
423 fmod_result!(ll::FMOD_ChannelGroup_GetMute (self.raw(), &mut mute))?;
424 }
425 Ok (mute != 0)
426 }
427
428 #[inline]
430 fn get_num_dsps (&self) -> Result <u32, Error> {
431 let mut num = 0;
432 unsafe {
433 fmod_result!(ll::FMOD_ChannelGroup_GetNumDSPs (self.raw(), &mut num))?;
434 }
435 debug_assert!(num >= 0);
436 #[expect(clippy::cast_sign_loss)]
437 Ok (num as u32)
438 }
439
440 #[inline]
441 fn get_paused (&self) -> Result <bool, Error> {
442 let mut paused = 0;
443 unsafe {
444 fmod_result!(ll::FMOD_ChannelGroup_GetPaused (self.raw(), &mut paused))?;
445 }
446 Ok (paused != 0)
447 }
448
449 #[inline]
457 fn get_reverb_properties (&self, instance : i32) -> Result <f32, Error> {
458 let mut wet = 0.0;
459 unsafe {
460 fmod_result!(
461 ll::FMOD_ChannelGroup_GetReverbProperties (self.raw(), instance, &mut wet)
462 )?;
463 }
464 Ok (wet)
465 }
466
467 #[inline]
468 fn get_volume (&self) -> Result <f32, Error> {
469 let mut volume = 0.0;
470 unsafe {
471 fmod_result!(ll::FMOD_ChannelGroup_GetVolume (self.raw(), &mut volume))?;
472 }
473 Ok (volume)
474 }
475
476 #[inline]
477 fn is_playing (&self) -> Result <bool, Error> {
478 let mut isplaying = 0;
479 unsafe {
480 fmod_result!(ll::FMOD_ChannelGroup_IsPlaying (self.raw(), &mut isplaying))?;
481 }
482 Ok (isplaying != 0)
483 }
484
485 #[inline]
486 fn remove_dsp (&mut self, dsp : &mut Dsp) -> Result <(), Error> {
487 unsafe {
488 fmod_result!(
489 ll::FMOD_ChannelGroup_RemoveDSP (self.raw_mut(), dsp.raw())
490 )
491 }
492 }
493
494 #[inline]
495 fn set_3d_attributes (&mut self, pos : [f32; 3], vel : [f32; 3])
496 -> Result <(), Error>
497 {
498 let pos = vector::to_ll (pos);
499 let vel = vector::to_ll (vel);
500 const ALT_PAN_POS : ll::FMOD_VECTOR = vector::to_ll ([0.0; 3]);
502 unsafe {
503 fmod_result!(
504 ll::FMOD_ChannelGroup_Set3DAttributes (self.raw_mut(), &pos, &vel,
505 &ALT_PAN_POS)
506 )
507 }
508 }
509
510 #[inline]
511 fn set_delay (&mut self,
512 dspclock_start : u64, dspclock_end : u64, stopchannels : bool
513 ) -> Result <(), Error> {
514 unsafe {
515 fmod_result!(
516 ll::FMOD_ChannelGroup_SetDelay (self.raw_mut(), dspclock_start,
517 dspclock_end, stopchannels as i32))
518 }
519 }
520
521 #[inline]
522 fn set_fade_point_ramp (&mut self, dspclock : u64, volume : f32)
523 -> Result <(), Error>
524 {
525 unsafe {
526 fmod_result!(
527 ll::FMOD_ChannelGroup_SetFadePointRamp (self.raw_mut(), dspclock, volume))
528 }
529 }
530
531 #[inline]
532 fn set_mute (&mut self, mute : bool) -> Result <(), Error> {
533 unsafe {
534 fmod_result!(ll::FMOD_ChannelGroup_SetMute (self.raw_mut(), mute as i32))
535 }
536 }
537
538 #[inline]
539 fn set_paused (&mut self, paused : bool) -> Result <(), Error> {
540 unsafe {
541 fmod_result!(ll::FMOD_ChannelGroup_SetPaused (self.raw_mut(), paused as i32))
542 }
543 }
544
545 #[inline]
546 fn set_reverb_properties (&mut self, instance : i32, wet : f32)
547 -> Result <(), Error>
548 {
549 unsafe {
550 fmod_result!(
551 ll::FMOD_ChannelGroup_SetReverbProperties (self.raw_mut(), instance, wet))
552 }
553 }
554
555 #[inline]
556 fn set_volume (&mut self, volume : f32) -> Result <(), Error> {
557 unsafe {
558 fmod_result!(ll::FMOD_ChannelGroup_SetVolume (self.raw_mut(), volume))
559 }
560 }
561
562 #[inline]
563 fn stop (&mut self) -> Result <(), Error> {
564 unsafe {
565 fmod_result!(ll::FMOD_ChannelGroup_Stop (self.raw_mut()))
566 }
567 }
568
569}
570
571impl Deref for ChannelGroupRef {
572 type Target = ChannelGroup;
573 fn deref (&self) -> &ChannelGroup {
574 &self.channel_group
575 }
576}
577
578impl DerefMut for ChannelGroupRef {
579 fn deref_mut (&mut self) -> &mut ChannelGroup {
580 &mut self.channel_group
581 }
582}
583
584impl std::fmt::Debug for Inner {
585 fn fmt (&self, f : &mut std::fmt::Formatter) -> std::fmt::Result {
586 write!(f, "Inner {{ raw: {:p}, owned: {} }}", self.raw, self.owned)
587 }
588}
589
590impl Drop for Inner {
591 fn drop (&mut self) {
592 if self.owned {
593 unsafe {
594 let _ = fmod_result!(ll::FMOD_ChannelGroup_Release (self.raw)).map_err (
595 |err| log::error!("error releasing FMOD ChannelGroup@{:p}: {:?}",
596 self.raw, err));
597 }
598 }
599 }
600}