1use std::{self, rc::Rc};
2use log;
3use riff_wave;
4use num_derive::FromPrimitive;
5use crate::{ll, fmod_result, dsp, reverb3d, sound, vector, ChannelGroup,
6 ChannelGroupRef, CpuUsage, DriverState, Dsp, Error, Guid, ListenerAttributes,
7 Mode, PluginHandle, Plugintype, Reverb3d, Sound, SoundRam, Speaker,
8 Speakermode, Timeunit};
9
10static FMOD_SYSTEM_CREATE_DESTROY_MUTEX : std::sync::LazyLock <std::sync::Mutex <()>> =
11 std::sync::LazyLock::new (std::sync::Mutex::default);
12
13#[derive(Clone, Debug, PartialEq)]
50pub struct System {
51 inner : Rc <Inner>
52}
53
54#[derive(PartialEq)]
55struct Inner (*mut ll::FMOD_SYSTEM);
56
57#[derive(Debug)]
58pub struct DriverInfo {
59 pub name : String,
60 pub guid : Guid,
61 pub systemrate : i32,
62 pub speakermode : Speakermode,
63 pub speakermodechannels : i32
64}
65
66bitflags!{
67 #[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
68 pub struct CallbackType : u32 {
69 const DEVICELISTCHANGED = ll::FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED;
70 const DEVICELOST = ll::FMOD_SYSTEM_CALLBACK_DEVICELOST;
71 const MEMORYALLOCATIONFAILED = ll::FMOD_SYSTEM_CALLBACK_MEMORYALLOCATIONFAILED;
72 const THREADCREATED = ll::FMOD_SYSTEM_CALLBACK_THREADCREATED;
73 const BADDSPCONNECTION = ll::FMOD_SYSTEM_CALLBACK_BADDSPCONNECTION;
74 const PREMIX = ll::FMOD_SYSTEM_CALLBACK_PREMIX;
75 const POSTMIX = ll::FMOD_SYSTEM_CALLBACK_POSTMIX;
76 const ERROR = ll::FMOD_SYSTEM_CALLBACK_ERROR;
77 const MIDMIX = ll::FMOD_SYSTEM_CALLBACK_MIDMIX;
78 const THREADDESTROYED = ll::FMOD_SYSTEM_CALLBACK_THREADDESTROYED;
79 const PREUPDATE = ll::FMOD_SYSTEM_CALLBACK_PREUPDATE;
80 const POSTUPDATE = ll::FMOD_SYSTEM_CALLBACK_POSTUPDATE;
81 const RECORDLISTCHANGED = ll::FMOD_SYSTEM_CALLBACK_RECORDLISTCHANGED;
82 const ALL = ll::FMOD_SYSTEM_CALLBACK_ALL;
83 }
84}
85
86bitflags!{
87 #[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
88 pub struct Initflags : u32 {
89 const NORMAL = ll::FMOD_INIT_NORMAL;
90 const STREAM_FROM_UPDATE = ll::FMOD_INIT_STREAM_FROM_UPDATE;
91 const MIX_FROM_UPDATE = ll::FMOD_INIT_MIX_FROM_UPDATE;
92 const _3D_RIGHTHANDED = ll::FMOD_INIT_3D_RIGHTHANDED;
93 const CHANNEL_LOWPASS = ll::FMOD_INIT_CHANNEL_LOWPASS;
94 const CHANNEL_DISTANCEFILTER = ll::FMOD_INIT_CHANNEL_DISTANCEFILTER;
95 const PROFILE_ENABLE = ll::FMOD_INIT_PROFILE_ENABLE;
96 const VOL0_BECOMES_VIRTUAL = ll::FMOD_INIT_VOL0_BECOMES_VIRTUAL;
97 const GEOMETRY_USECLOSEST = ll::FMOD_INIT_GEOMETRY_USECLOSEST;
98 const PREFER_DOLBY_DOWNMIX = ll::FMOD_INIT_PREFER_DOLBY_DOWNMIX;
99 const THREAD_UNSAFE = ll::FMOD_INIT_THREAD_UNSAFE;
100 const PROFILE_METER_ALL = ll::FMOD_INIT_PROFILE_METER_ALL;
101 const DISABLE_SRS_HIGHPASSFILTER = ll::FMOD_INIT_DISABLE_SRS_HIGHPASSFILTER;
102 }
103}
104
105#[derive(Copy, Clone, Debug, Eq, PartialEq, FromPrimitive)]
106pub enum Outputtype {
107 Autodetect = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUTODETECT as isize,
108 Unknown = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_UNKNOWN as isize,
109 Nosound = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_NOSOUND as isize,
110 Wavwriter = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WAVWRITER as isize,
111 NosoundNrt = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_NOSOUND_NRT as isize,
112 WavwriterNrt = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WAVWRITER_NRT as isize,
113 Dsound = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_DSOUND as isize,
114 Winmm = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WINMM as isize,
115 Wasapi = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WASAPI as isize,
116 Asio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_ASIO as isize,
117 Pulseaudio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_PULSEAUDIO as isize,
118 Alsa = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_ALSA as isize,
119 Coreaudio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_COREAUDIO as isize,
120 Xaudio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_XAUDIO as isize,
121 Ps3 = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_PS3 as isize,
122 Audiotrack = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUDIOTRACK as isize,
123 Opensl = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_OPENSL as isize,
124 Wiiu = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WIIU as isize,
125 Audioout = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUDIOOUT as isize,
126 Audio3d = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUDIO3D as isize,
127 Atmos = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_ATMOS as isize,
128 Webaudio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WEBAUDIO as isize,
129 Nnaudio = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_NNAUDIO as isize,
130 Winsonic = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WINSONIC as isize,
131 MAX = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_MAX as isize
132}
133
134impl System {
135 #[inline]
138 #[expect(clippy::should_implement_trait)]
139 pub fn default() -> Result <Self, Error> {
140 Self::new (None, 256, Initflags::NORMAL)
141 }
142
143 #[inline]
149 pub fn new (
150 num_software_channels : Option <u16>,
151 num_virtual_channels : u16,
152 initflags : Initflags
153 ) -> Result <Self, Error> {
154 let mut system = Self::create()?;
155 if let Some (n) = num_software_channels {
156 system.set_software_channels (n as i32)?;
157 }
158 #[cfg(not(target_os = "windows"))]
162 system.set_output (Outputtype::Alsa)?;
163 system.init (num_virtual_channels, initflags)?;
164 Ok (system)
165 }
166
167 #[inline]
172 fn raw (&self) -> *mut ll::FMOD_SYSTEM {
173 self.inner.0
174 }
175
176 #[inline]
177 #[expect(clippy::needless_pass_by_ref_mut)]
178 pub (crate) fn raw_mut (&mut self) -> *mut ll::FMOD_SYSTEM {
179 self.inner.0
180 }
181
182 #[inline]
183 pub fn update (&mut self) -> Result <(), Error> {
184 unsafe {
185 fmod_result!(ll::FMOD_System_Update (self.raw()))
186 }
187 }
188
189 #[inline]
190 pub fn get_3d_listener_attributes (&self, listener : i32)
191 -> Result <ListenerAttributes, Error>
192 {
193 let zero = ll::FMOD_VECTOR { x: 0.0, y: 0.0, z: 0.0 };
194 let mut pos = zero;
195 let mut vel = zero;
196 let mut forward = zero;
197 let mut up = zero;
198 unsafe {
199 fmod_result!(
200 ll::FMOD_System_Get3DListenerAttributes (
201 self.raw(), listener, &mut pos, &mut vel, &mut forward, &mut up)
202 )?;
203 }
204 let listener_attributes =
205 ListenerAttributes::from_ll (pos, vel, forward, up);
206 Ok (listener_attributes)
207 }
208
209 #[inline]
210 pub fn get_3d_num_listeners (&self) -> Result <i32, Error> {
211 let mut numlisteners = 0;
212 unsafe {
213 fmod_result!(ll::FMOD_System_Get3DNumListeners (
214 self.raw(), &mut numlisteners)
215 )?;
216 }
217 Ok (numlisteners)
218 }
219
220 #[inline]
223 pub fn get_3d_settings (&self) -> Result <(f32, f32, f32), Error> {
224 let mut dopplerscale = 0.0;
225 let mut distancefactor = 0.0;
226 let mut rolloffscale = 0.0;
227 unsafe {
228 fmod_result!(ll::FMOD_System_Get3DSettings (
229 self.raw(), &mut dopplerscale, &mut distancefactor, &mut rolloffscale)
230 )?;
231 }
232 Ok ((dopplerscale, distancefactor, rolloffscale))
233 }
234
235 #[inline]
236 pub fn get_channels_playing (&self) -> Result <(i32, i32), Error> {
237 let mut channels = 0;
238 let mut realchannels = 0;
239 unsafe {
240 fmod_result!(
241 ll::FMOD_System_GetChannelsPlaying (
242 self.raw(), &mut channels, &mut realchannels)
243 )?;
244 }
245 Ok ((channels, realchannels))
246 }
247
248 #[inline]
249 pub fn get_cpu_usage (&self) -> Result <CpuUsage, Error> {
250 let mut usage = CpuUsage::default();
251 unsafe {
252 fmod_result!(
253 ll::FMOD_System_GetCPUUsage (
254 self.raw(),
255 &mut usage.dsp,
256 &mut usage.stream,
257 &mut usage.geometry,
258 &mut usage.update,
259 &mut usage.total)
260 )?;
261 }
262 Ok (usage)
263 }
264
265 #[inline]
267 pub fn get_driver (&self) -> Result <i32, Error> {
268 let mut driver = 0;
269 unsafe {
270 fmod_result!(ll::FMOD_System_GetDriver (self.raw(), &mut driver))?;
271 }
272 Ok (driver)
273 }
274
275 #[inline]
276 pub fn get_driver_info (&self, id : i32) -> Result <DriverInfo, Error> {
277 let name_len = 256i32;
279 #[expect(clippy::cast_sign_loss)]
280 let mut name = vec![0; name_len as usize];
281 let mut guid = ll::FMOD_GUID {
282 Data1: 0, Data2: 0, Data3: 0, Data4: [0; 8]
283 };
284 let mut systemrate = 0;
285 let mut speakermode = 0;
286 let mut speakermodechannels = 0;
287 unsafe {
288 use std::os::raw;
289 fmod_result!(ll::FMOD_System_GetDriverInfo (
290 self.raw(),
291 id as raw::c_int,
292 name.as_mut_ptr() as *mut raw::c_char,
293 name_len as raw::c_int,
294 &mut guid,
295 &mut systemrate,
296 &mut speakermode,
297 &mut speakermodechannels
298 ))?;
299 }
300 let name = {
301 name.retain (|c| *c != 0x0);
302 String::from_utf8 (name).map_err (|e|{
303 log::error!("system driver name string invalid utf8: {e}");
304 Error::InvalidString
305 })?
306 };
307 let guid = Guid::from (guid);
308 let speakermode = Speakermode::from_ll (speakermode);
309 let info = DriverInfo {
310 name, guid, systemrate, speakermode, speakermodechannels
311 };
312 Ok (info)
313 }
314
315 #[inline]
328 pub fn get_dsp_buffer_size (&self) -> Result <(u32, i32), Error> {
329 let mut bufferlength = 0;
330 let mut numbuffers = 0;
331 unsafe {
332 fmod_result!(
333 ll::FMOD_System_GetDSPBufferSize (
334 self.raw(), &mut bufferlength, &mut numbuffers)
335 )?;
336 }
337 Ok ((bufferlength, numbuffers))
338 }
339
340 #[inline]
344 pub fn get_geometry_occlusion (&self, listener : [f32; 3], source : [f32; 3])
345 -> Result <(f32, f32), Error>
346 {
347 let listener = vector::to_ll (listener);
348 let source = vector::to_ll (source);
349 let mut direct = 0.0;
350 let mut reverb = 0.0;
351 unsafe {
352 fmod_result!(
353 ll::FMOD_System_GetGeometryOcclusion (self.raw(),
354 &listener, &source, &mut direct, &mut reverb)
355 )?;
356 }
357 Ok ((direct, reverb))
358 }
359
360 #[inline]
362 pub fn get_geometry_settings (&self) -> Result <f32, Error> {
363 let mut maxworldsize = 0.0;
364 unsafe {
365 fmod_result!(
366 ll::FMOD_System_GetGeometrySettings (self.raw(), &mut maxworldsize)
367 )?;
368 }
369 Ok (maxworldsize)
370 }
371
372 #[inline]
373 pub fn get_master_channel_group (&self) -> Result <ChannelGroupRef, Error> {
374 let mut raw = std::ptr::null_mut();
375 unsafe {
376 fmod_result!(
377 ll::FMOD_System_GetMasterChannelGroup (self.raw(), &mut raw)
378 )?;
379 }
380 let channel_group =
381 ChannelGroup::from_raw_parts (raw, false, self.clone());
382 Ok (ChannelGroupRef { channel_group })
383 }
384
385 #[inline]
386 pub fn get_num_drivers (&self) -> Result <i32, Error> {
387 let mut numdrivers = 0;
388 unsafe {
389 fmod_result!(ll::FMOD_System_GetNumDrivers (self.raw(), &mut numdrivers))?;
390 }
391 Ok (numdrivers)
392 }
393
394 #[inline]
395 pub fn get_num_plugins (&self, plugintype : Plugintype)
396 -> Result <i32, Error>
397 {
398 let mut numplugins = 0;
399 unsafe {
400 fmod_result!(ll::FMOD_System_GetNumPlugins (
401 self.raw(), plugintype as ll::FMOD_PLUGINTYPE, &mut numplugins)
402 )?;
403 }
404 Ok (numplugins)
405 }
406
407 #[inline]
408 pub fn get_output (&self) -> Result <Outputtype, Error> {
409 let mut outputtype = 0;
410 unsafe {
411 fmod_result!(ll::FMOD_System_GetOutput (self.raw(), &mut outputtype))?;
412 }
413 Ok (Outputtype::from_ll (outputtype))
414 }
415
416 #[inline]
419 pub fn get_output_by_plugin (&self) -> Result <PluginHandle, Error> {
420 let mut handle = 0;
421 unsafe {
422 fmod_result!(ll::FMOD_System_GetOutputByPlugin (self.raw(), &mut handle))?;
423 }
424 Ok (PluginHandle (handle))
425 }
426
427 #[inline]
428 pub fn get_record_driver_info (&self, id : i32)
429 -> Result <(DriverInfo, DriverState), Error>
430 {
431 let name_len = 256i32;
433 #[expect(clippy::cast_sign_loss)]
434 let mut name = vec![0; name_len as usize];
435 let mut guid = ll::FMOD_GUID {
436 Data1: 0, Data2: 0, Data3: 0, Data4: [0; 8]
437 };
438 let mut systemrate = 0;
439 let mut speakermode = 0;
440 let mut speakermodechannels = 0;
441 let mut state = 0;
442 unsafe {
443 use std::os::raw;
444 fmod_result!(ll::FMOD_System_GetRecordDriverInfo (
445 self.raw(),
446 id as raw::c_int,
447 name.as_mut_ptr() as *mut raw::c_char,
448 name_len as raw::c_int,
449 &mut guid,
450 &mut systemrate,
451 &mut speakermode,
452 &mut speakermodechannels,
453 &mut state
454 ))?;
455 }
456 let name = {
457 name.retain (|c| *c != 0x0);
458 String::from_utf8 (name).map_err (|e|{
459 log::error!("system record driver name string invalid utf8: {e}");
460 Error::InvalidString
461 })?
462 };
463 let guid = Guid::from (guid);
464 let speakermode = Speakermode::from_ll (speakermode);
465 let info = DriverInfo {
466 name, guid, systemrate, speakermode, speakermodechannels
467 };
468 let state = DriverState::from_bits (state).ok_or_else (||{
469 log::error!("system driver state bits not valid: {state:032b}");
470 Error::InvalidParam
471 })?;
472 Ok ((info, state))
473 }
474
475 #[inline]
478 pub fn get_record_num_drivers (&self) -> Result <(i32, i32), Error> {
479 let mut numdrivers = 0;
480 let mut numconnected = 0;
481 unsafe {
482 fmod_result!(ll::FMOD_System_GetRecordNumDrivers (
483 self.raw(), &mut numdrivers, &mut numconnected
484 ))?;
485 }
486 Ok ((numdrivers, numconnected))
487 }
488
489 #[inline]
490 pub fn get_reverb_properties (&self, instance : i32)
491 -> Result <reverb3d::Properties, Error>
492 {
493 let mut properties = ll::FMOD_REVERB_PROPERTIES {
494 DecayTime: 0.0,
495 EarlyDelay: 0.0,
496 LateDelay: 0.0,
497 HFReference: 0.0,
498 HFDecayRatio: 0.0,
499 Diffusion: 0.0,
500 Density: 0.0,
501 LowShelfFrequency: 0.0,
502 LowShelfGain: 0.0,
503 HighCut: 0.0,
504 EarlyLateMix: 0.0,
505 WetLevel: 0.0
506 };
507 unsafe {
508 fmod_result!(
509 ll::FMOD_System_GetReverbProperties (self.raw(),
510 instance, &mut properties)
511 )?;
512 }
513 let properties = reverb3d::Properties::from_ll (&properties);
514 Ok (properties)
515 }
516
517 #[inline]
518 pub fn get_software_channels (&self) -> Result <i32, Error> {
519 let mut numsoftwarechannels = 0;
520 unsafe {
521 fmod_result!(
522 ll::FMOD_System_GetSoftwareChannels (
523 self.raw(), &mut numsoftwarechannels)
524 )?;
525 }
526 Ok (numsoftwarechannels)
527 }
528
529 #[inline]
533 pub fn get_software_format (&self)
534 -> Result <(i32, Speakermode, i32), Error>
535 {
536 let mut samplerate = 0;
537 let mut speakermode = 0;
538 let mut numrawspeakers = 0;
539 unsafe {
540 fmod_result!(
541 ll::FMOD_System_GetSoftwareFormat (
542 self.raw(), &mut samplerate, &mut speakermode, &mut numrawspeakers)
543 )?;
544 }
545 let speakermode = Speakermode::from_ll (speakermode);
546 Ok ((samplerate, speakermode, numrawspeakers))
547 }
548
549 #[inline]
550 pub fn get_sound_ram (&self) -> Result <SoundRam, Error> {
551 let mut ram = SoundRam::default();
552 unsafe {
553 fmod_result!(
554 ll::FMOD_System_GetSoundRAM (self.raw(),
555 &mut ram.currentalloced, &mut ram.maxalloced, &mut ram.total)
556 )?;
557 }
558 Ok (ram)
559 }
560
561 #[inline]
562 pub fn get_speaker_mode_channels (&self, mode : Speakermode)
563 -> Result <i32, Error>
564 {
565 let mut channels = 0;
566 unsafe {
567 fmod_result!(
568 ll::FMOD_System_GetSpeakerModeChannels (
569 self.raw(), mode as ll::FMOD_SPEAKERMODE, &mut channels)
570 )?;
571 }
572 Ok (channels)
573 }
574
575 #[inline]
580 pub fn get_speaker_position (&self, speaker : Speaker)
581 -> Result <(f32, f32, bool), Error>
582 {
583 let mut x = 0.0;
584 let mut y = 0.0;
585 let mut active = 0;
586 unsafe {
587 fmod_result!(
588 ll::FMOD_System_GetSpeakerPosition (
589 self.raw(), speaker as ll::FMOD_SPEAKER, &mut x, &mut y, &mut active)
590 )?;
591 }
592 Ok ((x, y, active != 0))
593 }
594
595 #[inline]
597 pub fn get_stream_buffer_size (&self)
598 -> Result <(u32, Timeunit), Error>
599 {
600 let mut filebuffersize = 0;
601 let mut filebuffersizetype = 0;
602 unsafe {
603 fmod_result!(
604 ll::FMOD_System_GetStreamBufferSize (
605 self.raw(), &mut filebuffersize, &mut filebuffersizetype)
606 )?;
607 }
608 let timeunit = Timeunit::from_bits (filebuffersizetype).ok_or_else (||{
609 log::error!("system stream buffer timeunit bits not valid: \
610 {filebuffersizetype:032b}");
611 Error::InvalidParam
612 })?;
613 Ok ((filebuffersize, timeunit))
614 }
615
616 #[inline]
622 pub fn get_version (&self) -> Result <u32, Error> {
623 let mut version = 0;
624 unsafe {
625 fmod_result!(ll::FMOD_System_GetVersion (self.raw(), &mut version))?;
626 }
627 Ok (version)
628 }
629
630 #[inline]
632 pub fn get_version_string (&self) -> Result <String, Error> {
633 self.get_version().map (crate::version_string)
634 }
635
636 #[inline]
641 pub fn create_channel_group (&mut self, name : Option <&str>)
642 -> Result <ChannelGroup, Error>
643 {
644 let mut raw = std::ptr::null_mut();
645 let name_str = name.unwrap_or ("");
646 let name_string = std::ffi::CString::new (name_str).map_err (|e|{
647 log::error!("create channel group name \"{name_str}\" contains a null byte: {e}");
648 Error::InvalidString
649 })?;
650 let name_ptr = if name.is_some() {
651 name_string.as_ptr()
652 } else {
653 std::ptr::null()
654 };
655 unsafe {
656 fmod_result!(ll::FMOD_System_CreateChannelGroup (self.raw(), name_ptr, &mut raw))?
657 }
658 Ok (ChannelGroup::from_raw_parts (raw, true, self.clone()))
659 }
660
661 #[inline]
662 pub fn create_dsp (&mut self, description : &'static dsp::Description)
663 -> Result <Dsp, Error>
664 {
665 let mut raw = std::ptr::null_mut();
666 unsafe {
667 fmod_result!(
668 ll::FMOD_System_CreateDSP (self.raw(),
669 std::ptr::from_ref (description.as_ref()), &mut raw)
670 )?
671 }
672 Ok (Dsp::from_raw_parts (raw, true, self.clone()))
673 }
674
675 #[inline]
676 pub fn create_dsp_by_type (&mut self, type_ : dsp::Type)
677 -> Result <Dsp, Error>
678 {
679 let mut raw = std::ptr::null_mut();
680 unsafe {
681 fmod_result!(
682 ll::FMOD_System_CreateDSPByType (self.raw(), type_ as ll::FMOD_DSP_TYPE,
683 &mut raw)
684 )?;
685 }
686 Ok (Dsp::from_raw_parts (raw, true, self.clone()))
687 }
688
689 pub fn create_dsp_sfxreverb (&mut self,
692 properties : &reverb3d::Properties, dry_level : f32
693 ) -> Result <Dsp, Error> {
694 let mut raw = std::ptr::null_mut();
695 unsafe {
696 fmod_result!(
697 ll::FMOD_System_CreateDSPByType (
698 self.raw(),
699 dsp::Type::Sfxreverb as ll::FMOD_DSP_TYPE,
700 &mut raw
701 )
702 )?;
703 }
704 let mut dsp = Dsp::from_raw_parts (raw, true, self.clone());
705 dsp.set_parameters_sfxreverb (properties, dry_level)?;
706 Ok (dsp)
707 }
708
709 #[inline]
710 pub fn create_reverb3d (&mut self) -> Result <Reverb3d, Error> {
711 let mut raw = std::ptr::null_mut();
712 unsafe {
713 fmod_result!(ll::FMOD_System_CreateReverb3D (self.raw(), &mut raw))?;
714 }
715 Ok (Reverb3d::from_raw_parts (raw, self.clone()))
716 }
717
718 pub fn create_sound_from_file (&mut self,
719 filename : &str,
720 mode : Mode,
721 exinfo : Option <&mut sound::Createsoundexinfo>
722 ) -> Result <Sound, Error> {
723 let filename = std::ffi::CString::new (filename).map_err (|e|{
724 log::error!("create sound filename \"{filename}\" contains a null byte: {e}");
725 Error::InvalidString
726 })?;
727 let mut exinfo = exinfo.map (sound::Createsoundexinfo::to_ll);
728 let mut raw = std::ptr::null_mut();
729 unsafe {
730 fmod_result!(
731 ll::FMOD_System_CreateSound (
732 self.raw(),
733 filename.as_ptr(),
734 mode.bits(),
735 exinfo.as_mut().map_or (
736 std::ptr::null_mut(), std::ptr::from_mut::<ll::FMOD_CREATESOUNDEXINFO>),
737 &mut raw)
738 )?;
739 }
740 Ok (Sound::from_raw_parts (raw, true, self.clone()))
741 }
742
743 pub fn create_sound_from_memory (&mut self,
744 data : &[u8],
745 mut mode : Mode,
746 exinfo : Option <&mut sound::Createsoundexinfo>
747 ) -> Result <Sound, Error> {
748 mode |= Mode::OPENMEMORY;
749 let mut exinfo_default = Default::default();
750 let mut exinfo = {
751 let exinfo = exinfo.unwrap_or (&mut exinfo_default);
752 exinfo.length = u32::try_from (data.len()).map_err (|_|{
753 log::error!("create sound from memory data too big: {}", data.len());
754 Error::InvalidParam
755 })?;
756 sound::Createsoundexinfo::to_ll (exinfo)
757 };
758 let mut raw = std::ptr::null_mut();
759 let data = if !data.is_empty() {
760 data.as_ptr() as *const std::os::raw::c_char
761 } else {
762 std::ptr::null()
763 };
764 unsafe {
765 fmod_result!(
766 ll::FMOD_System_CreateSound (
767 self.raw(),
768 data,
769 mode.bits(),
770 &mut exinfo,
771 &mut raw)
772 )?;
773 }
774 Ok (Sound::from_raw_parts (raw, true, self.clone()))
775 }
776
777 pub fn create_sound_from_pcm (&mut self,
781 pcm : &[i16],
782 mode : Mode,
783 exinfo : Option <&mut sound::Createsoundexinfo>
784 ) -> Result <Sound, Error> {
785 const WAV_HEADER_LEN : usize = 44;
786 let pcm_bytelen = pcm.len() * 2;
787 let wav_bytelen = WAV_HEADER_LEN + pcm_bytelen;
788 let mut wav = vec![0; wav_bytelen];
789 {
790 let cursor = std::io::Cursor::new (&mut wav);
791 let writer = std::io::BufWriter::new (cursor);
792 let mut wav_writer = riff_wave::WaveWriter::new (1, 44100, 16, writer)
793 .unwrap();
794 for sample in pcm.iter() {
795 wav_writer.write_sample_i16 (*sample).unwrap();
796 }
797 }
798 self.create_sound_from_memory (wav.as_slice(), mode, exinfo)
799 }
800
801 #[inline]
803 pub fn create_sound_from_file_default (&mut self, filename : &str)
804 -> Result <Sound, Error>
805 {
806 self.create_sound_from_file (filename, Mode::DEFAULT, None)
807 }
808
809 #[inline]
810 pub fn create_sound_from_memory_default (&mut self, data : &[u8])
811 -> Result <Sound, Error>
812 {
813 self.create_sound_from_memory (data, Mode::DEFAULT, None)
814 }
815
816 #[inline]
817 pub fn create_sound_from_pcm_default (&mut self, pcm : &[i16])
818 -> Result <Sound, Error>
819 {
820 self.create_sound_from_pcm (pcm, Mode::DEFAULT, None)
821 }
822
823 #[inline]
824 pub fn set_3d_listener_attributes (&mut self,
825 listener : i32, attributes : &ListenerAttributes
826 ) -> Result <(), Error> {
827 let pos = vector::to_ll (attributes.pos);
828 let vel = vector::to_ll (attributes.vel);
829 let forward = vector::to_ll (attributes.forward);
830 let up = vector::to_ll (attributes.up);
831 unsafe {
832 fmod_result!(
833 ll::FMOD_System_Set3DListenerAttributes (self.raw(),
834 listener, &pos, &vel, &forward, &up)
835 )
836 }
837 }
838
839 #[inline]
840 pub fn set_output (&mut self, output : Outputtype) -> Result <(), Error> {
841 unsafe {
842 fmod_result!(
843 ll::FMOD_System_SetOutput (self.raw(), output as ll::FMOD_OUTPUTTYPE))
844 }
845 }
846
847 #[inline]
856 pub fn set_reverb_properties (&mut self,
857 instance : i32, properties : &reverb3d::Properties
858 ) -> Result <(), Error> {
859 let properties = properties.to_ll();
860 unsafe {
861 fmod_result!(
862 ll::FMOD_System_SetReverbProperties (self.raw(), instance, &properties)
863 )
864 }
865 }
866
867 #[inline]
872 fn create() -> Result <Self, Error> {
873 let raw = {
874 let _lock = FMOD_SYSTEM_CREATE_DESTROY_MUTEX.lock().unwrap();
875 let mut raw = std::ptr::null_mut();
876 unsafe {
877 fmod_result!(ll::FMOD_System_Create (&mut raw))?;
878 }
879 raw
880 };
882 let inner = Rc::new (Inner (raw));
883 let system = System { inner };
884 let system_version = system.get_version_string()?;
885 if system_version != *crate::FMOD_VERSION_STRING {
886 log::error!(
887 "FMOD created system got shared library version {:?}, \
888 bindings were generated for version {:?}",
889 system_version, *crate::FMOD_VERSION_STRING);
890 panic!(
891 "FMOD created system got shared library version {:?}, \
892 bindings were generated for version {:?}",
893 system_version, *crate::FMOD_VERSION_STRING);
894 }
895 Ok (system)
896 }
897
898 #[inline]
900 fn init (&mut self, max_channels : u16, init_flags : Initflags)
901 -> Result <(), Error>
902 {
903 let max_channels = max_channels as i32;
904 unsafe {
905 fmod_result!(ll::FMOD_System_Init (
906 self.raw(), max_channels, init_flags.bits(), std::ptr::null_mut()))
907 }
908 }
909
910 #[inline]
913 fn set_software_channels (&mut self, numsoftwarechannels : i32)
914 -> Result <(), Error>
915 {
916 unsafe {
917 fmod_result!(
918 ll::FMOD_System_SetSoftwareChannels (self.raw(), numsoftwarechannels)
919 )
920 }
921 }
922
923}
924
925impl std::fmt::Debug for Inner {
926 fn fmt (&self, f : &mut std::fmt::Formatter) -> std::fmt::Result {
927 write!(f, "{:p}", self.0)
928 }
929}
930
931impl Drop for Inner {
932 fn drop (&mut self) {
933 let _lock = FMOD_SYSTEM_CREATE_DESTROY_MUTEX.lock().unwrap();
934 unsafe {
935 let _ = fmod_result!(ll::FMOD_System_Release (self.0)).map_err (
936 |err| log::error!("error releasing FMOD System@{:p}: {:?}", self.0, err));
937 }
938 }
940}
941
942impl From <ll::FMOD_GUID> for Guid {
943 fn from (guid : ll::FMOD_GUID) -> Self {
944 Guid {
945 data1: guid.Data1,
946 data2: guid.Data2,
947 data3: guid.Data3,
948 data4: guid.Data4
949 }
950 }
951}
952
953impl Outputtype {
954 pub fn from_ll (ll : ll::FMOD_OUTPUTTYPE) -> Self {
958 use num_traits::FromPrimitive;
959 #[allow(clippy::allow_attributes, clippy::unnecessary_cast)]
961 Self::from_u32 (ll as u32).unwrap()
962 }
963}