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 #[expect(trivial_numeric_casts)]
290 fmod_result!(ll::FMOD_System_GetDriverInfo (
291 self.raw(),
292 id as raw::c_int,
293 name.as_mut_ptr() as *mut raw::c_char,
294 name_len as raw::c_int,
295 &mut guid,
296 &mut systemrate,
297 &mut speakermode,
298 &mut speakermodechannels
299 ))?;
300 }
301 let name = {
302 name.retain (|c| *c != 0x0);
303 String::from_utf8 (name).map_err (|e|{
304 log::error!("system driver name string invalid utf8: {e}");
305 Error::InvalidString
306 })?
307 };
308 let guid = Guid::from (guid);
309 let speakermode = Speakermode::from_ll (speakermode);
310 let info = DriverInfo {
311 name, guid, systemrate, speakermode, speakermodechannels
312 };
313 Ok (info)
314 }
315
316 #[inline]
329 pub fn get_dsp_buffer_size (&self) -> Result <(u32, i32), Error> {
330 let mut bufferlength = 0;
331 let mut numbuffers = 0;
332 unsafe {
333 fmod_result!(
334 ll::FMOD_System_GetDSPBufferSize (
335 self.raw(), &mut bufferlength, &mut numbuffers)
336 )?;
337 }
338 Ok ((bufferlength, numbuffers))
339 }
340
341 #[inline]
345 pub fn get_geometry_occlusion (&self, listener : [f32; 3], source : [f32; 3])
346 -> Result <(f32, f32), Error>
347 {
348 let listener = vector::to_ll (listener);
349 let source = vector::to_ll (source);
350 let mut direct = 0.0;
351 let mut reverb = 0.0;
352 unsafe {
353 fmod_result!(
354 ll::FMOD_System_GetGeometryOcclusion (self.raw(),
355 &listener, &source, &mut direct, &mut reverb)
356 )?;
357 }
358 Ok ((direct, reverb))
359 }
360
361 #[inline]
363 pub fn get_geometry_settings (&self) -> Result <f32, Error> {
364 let mut maxworldsize = 0.0;
365 unsafe {
366 fmod_result!(
367 ll::FMOD_System_GetGeometrySettings (self.raw(), &mut maxworldsize)
368 )?;
369 }
370 Ok (maxworldsize)
371 }
372
373 #[inline]
374 pub fn get_master_channel_group (&self) -> Result <ChannelGroupRef, Error> {
375 let mut raw = std::ptr::null_mut();
376 unsafe {
377 fmod_result!(
378 ll::FMOD_System_GetMasterChannelGroup (self.raw(), &mut raw)
379 )?;
380 }
381 let channel_group =
382 ChannelGroup::from_raw_parts (raw, false, self.clone());
383 Ok (ChannelGroupRef { channel_group })
384 }
385
386 #[inline]
387 pub fn get_num_drivers (&self) -> Result <i32, Error> {
388 let mut numdrivers = 0;
389 unsafe {
390 fmod_result!(ll::FMOD_System_GetNumDrivers (self.raw(), &mut numdrivers))?;
391 }
392 Ok (numdrivers)
393 }
394
395 #[inline]
396 pub fn get_num_plugins (&self, plugintype : Plugintype)
397 -> Result <i32, Error>
398 {
399 let mut numplugins = 0;
400 unsafe {
401 fmod_result!(ll::FMOD_System_GetNumPlugins (
402 self.raw(), plugintype as ll::FMOD_PLUGINTYPE, &mut numplugins)
403 )?;
404 }
405 Ok (numplugins)
406 }
407
408 #[inline]
409 pub fn get_output (&self) -> Result <Outputtype, Error> {
410 let mut outputtype = 0;
411 unsafe {
412 fmod_result!(ll::FMOD_System_GetOutput (self.raw(), &mut outputtype))?;
413 }
414 Ok (Outputtype::from_ll (outputtype))
415 }
416
417 #[inline]
420 pub fn get_output_by_plugin (&self) -> Result <PluginHandle, Error> {
421 let mut handle = 0;
422 unsafe {
423 fmod_result!(ll::FMOD_System_GetOutputByPlugin (self.raw(), &mut handle))?;
424 }
425 Ok (PluginHandle (handle))
426 }
427
428 #[inline]
429 pub fn get_record_driver_info (&self, id : i32)
430 -> Result <(DriverInfo, DriverState), Error>
431 {
432 let name_len = 256i32;
434 #[expect(clippy::cast_sign_loss)]
435 let mut name = vec![0; name_len as usize];
436 let mut guid = ll::FMOD_GUID {
437 Data1: 0, Data2: 0, Data3: 0, Data4: [0; 8]
438 };
439 let mut systemrate = 0;
440 let mut speakermode = 0;
441 let mut speakermodechannels = 0;
442 let mut state = 0;
443 unsafe {
444 use std::os::raw;
445 #[expect(trivial_numeric_casts)]
446 fmod_result!(ll::FMOD_System_GetRecordDriverInfo (
447 self.raw(),
448 id as raw::c_int,
449 name.as_mut_ptr() as *mut raw::c_char,
450 name_len as raw::c_int,
451 &mut guid,
452 &mut systemrate,
453 &mut speakermode,
454 &mut speakermodechannels,
455 &mut state
456 ))?;
457 }
458 let name = {
459 name.retain (|c| *c != 0x0);
460 String::from_utf8 (name).map_err (|e|{
461 log::error!("system record driver name string invalid utf8: {e}");
462 Error::InvalidString
463 })?
464 };
465 let guid = Guid::from (guid);
466 let speakermode = Speakermode::from_ll (speakermode);
467 let info = DriverInfo {
468 name, guid, systemrate, speakermode, speakermodechannels
469 };
470 let state = DriverState::from_bits (state).ok_or_else (||{
471 log::error!("system driver state bits not valid: {state:032b}");
472 Error::InvalidParam
473 })?;
474 Ok ((info, state))
475 }
476
477 #[inline]
480 pub fn get_record_num_drivers (&self) -> Result <(i32, i32), Error> {
481 let mut numdrivers = 0;
482 let mut numconnected = 0;
483 unsafe {
484 fmod_result!(ll::FMOD_System_GetRecordNumDrivers (
485 self.raw(), &mut numdrivers, &mut numconnected
486 ))?;
487 }
488 Ok ((numdrivers, numconnected))
489 }
490
491 #[inline]
492 pub fn get_reverb_properties (&self, instance : i32)
493 -> Result <reverb3d::Properties, Error>
494 {
495 let mut properties = ll::FMOD_REVERB_PROPERTIES {
496 DecayTime: 0.0,
497 EarlyDelay: 0.0,
498 LateDelay: 0.0,
499 HFReference: 0.0,
500 HFDecayRatio: 0.0,
501 Diffusion: 0.0,
502 Density: 0.0,
503 LowShelfFrequency: 0.0,
504 LowShelfGain: 0.0,
505 HighCut: 0.0,
506 EarlyLateMix: 0.0,
507 WetLevel: 0.0
508 };
509 unsafe {
510 fmod_result!(
511 ll::FMOD_System_GetReverbProperties (self.raw(),
512 instance, &mut properties)
513 )?;
514 }
515 let properties = reverb3d::Properties::from_ll (&properties);
516 Ok (properties)
517 }
518
519 #[inline]
520 pub fn get_software_channels (&self) -> Result <i32, Error> {
521 let mut numsoftwarechannels = 0;
522 unsafe {
523 fmod_result!(
524 ll::FMOD_System_GetSoftwareChannels (
525 self.raw(), &mut numsoftwarechannels)
526 )?;
527 }
528 Ok (numsoftwarechannels)
529 }
530
531 #[inline]
535 pub fn get_software_format (&self)
536 -> Result <(i32, Speakermode, i32), Error>
537 {
538 let mut samplerate = 0;
539 let mut speakermode = 0;
540 let mut numrawspeakers = 0;
541 unsafe {
542 fmod_result!(
543 ll::FMOD_System_GetSoftwareFormat (
544 self.raw(), &mut samplerate, &mut speakermode, &mut numrawspeakers)
545 )?;
546 }
547 let speakermode = Speakermode::from_ll (speakermode);
548 Ok ((samplerate, speakermode, numrawspeakers))
549 }
550
551 #[inline]
552 pub fn get_sound_ram (&self) -> Result <SoundRam, Error> {
553 let mut ram = SoundRam::default();
554 unsafe {
555 fmod_result!(
556 ll::FMOD_System_GetSoundRAM (self.raw(),
557 &mut ram.currentalloced, &mut ram.maxalloced, &mut ram.total)
558 )?;
559 }
560 Ok (ram)
561 }
562
563 #[inline]
564 pub fn get_speaker_mode_channels (&self, mode : Speakermode)
565 -> Result <i32, Error>
566 {
567 let mut channels = 0;
568 unsafe {
569 fmod_result!(
570 ll::FMOD_System_GetSpeakerModeChannels (
571 self.raw(), mode as ll::FMOD_SPEAKERMODE, &mut channels)
572 )?;
573 }
574 Ok (channels)
575 }
576
577 #[inline]
582 pub fn get_speaker_position (&self, speaker : Speaker)
583 -> Result <(f32, f32, bool), Error>
584 {
585 let mut x = 0.0;
586 let mut y = 0.0;
587 let mut active = 0;
588 unsafe {
589 fmod_result!(
590 ll::FMOD_System_GetSpeakerPosition (
591 self.raw(), speaker as ll::FMOD_SPEAKER, &mut x, &mut y, &mut active)
592 )?;
593 }
594 Ok ((x, y, active != 0))
595 }
596
597 #[inline]
599 pub fn get_stream_buffer_size (&self)
600 -> Result <(u32, Timeunit), Error>
601 {
602 let mut filebuffersize = 0;
603 let mut filebuffersizetype = 0;
604 unsafe {
605 fmod_result!(
606 ll::FMOD_System_GetStreamBufferSize (
607 self.raw(), &mut filebuffersize, &mut filebuffersizetype)
608 )?;
609 }
610 let timeunit = Timeunit::from_bits (filebuffersizetype).ok_or_else (||{
611 log::error!("system stream buffer timeunit bits not valid: \
612 {filebuffersizetype:032b}");
613 Error::InvalidParam
614 })?;
615 Ok ((filebuffersize, timeunit))
616 }
617
618 #[inline]
624 pub fn get_version (&self) -> Result <u32, Error> {
625 let mut version = 0;
626 unsafe {
627 fmod_result!(ll::FMOD_System_GetVersion (self.raw(), &mut version))?;
628 }
629 Ok (version)
630 }
631
632 #[inline]
634 pub fn get_version_string (&self) -> Result <String, Error> {
635 self.get_version().map (crate::version_string)
636 }
637
638 #[inline]
643 pub fn create_channel_group (&mut self, name : Option <&str>)
644 -> Result <ChannelGroup, Error>
645 {
646 let mut raw = std::ptr::null_mut();
647 let name_str = name.unwrap_or ("");
648 let name_string = std::ffi::CString::new (name_str).map_err (|e|{
649 log::error!("create channel group name \"{name_str}\" contains a null byte: {e}");
650 Error::InvalidString
651 })?;
652 let name_ptr = if name.is_some() {
653 name_string.as_ptr()
654 } else {
655 std::ptr::null()
656 };
657 unsafe {
658 fmod_result!(ll::FMOD_System_CreateChannelGroup (self.raw(), name_ptr, &mut raw))?
659 }
660 Ok (ChannelGroup::from_raw_parts (raw, true, self.clone()))
661 }
662
663 #[inline]
664 pub fn create_dsp (&mut self, description : &'static dsp::Description)
665 -> Result <Dsp, Error>
666 {
667 let mut raw = std::ptr::null_mut();
668 unsafe {
669 fmod_result!(
670 ll::FMOD_System_CreateDSP (self.raw(),
671 std::ptr::from_ref (description.as_ref()), &mut raw)
672 )?
673 }
674 Ok (Dsp::from_raw_parts (raw, true, self.clone()))
675 }
676
677 #[inline]
678 pub fn create_dsp_by_type (&mut self, type_ : dsp::Type)
679 -> Result <Dsp, Error>
680 {
681 let mut raw = std::ptr::null_mut();
682 unsafe {
683 fmod_result!(
684 ll::FMOD_System_CreateDSPByType (self.raw(), type_ as ll::FMOD_DSP_TYPE,
685 &mut raw)
686 )?;
687 }
688 Ok (Dsp::from_raw_parts (raw, true, self.clone()))
689 }
690
691 pub fn create_dsp_sfxreverb (&mut self,
694 properties : &reverb3d::Properties, dry_level : f32
695 ) -> Result <Dsp, Error> {
696 let mut raw = std::ptr::null_mut();
697 unsafe {
698 fmod_result!(
699 ll::FMOD_System_CreateDSPByType (
700 self.raw(),
701 dsp::Type::Sfxreverb as ll::FMOD_DSP_TYPE,
702 &mut raw
703 )
704 )?;
705 }
706 let mut dsp = Dsp::from_raw_parts (raw, true, self.clone());
707 dsp.set_parameters_sfxreverb (properties, dry_level)?;
708 Ok (dsp)
709 }
710
711 #[inline]
712 pub fn create_reverb3d (&mut self) -> Result <Reverb3d, Error> {
713 let mut raw = std::ptr::null_mut();
714 unsafe {
715 fmod_result!(ll::FMOD_System_CreateReverb3D (self.raw(), &mut raw))?;
716 }
717 Ok (Reverb3d::from_raw_parts (raw, self.clone()))
718 }
719
720 pub fn create_sound_from_file (&mut self,
721 filename : &str,
722 mode : Mode,
723 exinfo : Option <&mut sound::Createsoundexinfo>
724 ) -> Result <Sound, Error> {
725 let filename = std::ffi::CString::new (filename).map_err (|e|{
726 log::error!("create sound filename \"{filename}\" contains a null byte: {e}");
727 Error::InvalidString
728 })?;
729 let mut exinfo = exinfo.map (sound::Createsoundexinfo::to_ll);
730 let mut raw = std::ptr::null_mut();
731 unsafe {
732 fmod_result!(
733 ll::FMOD_System_CreateSound (
734 self.raw(),
735 filename.as_ptr(),
736 mode.bits(),
737 exinfo.as_mut().map_or (
738 std::ptr::null_mut(), std::ptr::from_mut::<ll::FMOD_CREATESOUNDEXINFO>),
739 &mut raw)
740 )?;
741 }
742 Ok (Sound::from_raw_parts (raw, true, self.clone()))
743 }
744
745 pub fn create_sound_from_memory (&mut self,
746 data : &[u8],
747 mut mode : Mode,
748 exinfo : Option <&mut sound::Createsoundexinfo>
749 ) -> Result <Sound, Error> {
750 mode |= Mode::OPENMEMORY;
751 let mut exinfo_default = Default::default();
752 let mut exinfo = {
753 let exinfo = exinfo.unwrap_or (&mut exinfo_default);
754 exinfo.length = u32::try_from (data.len()).map_err (|_|{
755 log::error!("create sound from memory data too big: {}", data.len());
756 Error::InvalidParam
757 })?;
758 sound::Createsoundexinfo::to_ll (exinfo)
759 };
760 let mut raw = std::ptr::null_mut();
761 let data = if !data.is_empty() {
762 data.as_ptr() as *const std::os::raw::c_char
763 } else {
764 std::ptr::null()
765 };
766 unsafe {
767 fmod_result!(
768 ll::FMOD_System_CreateSound (
769 self.raw(),
770 data,
771 mode.bits(),
772 &mut exinfo,
773 &mut raw)
774 )?;
775 }
776 Ok (Sound::from_raw_parts (raw, true, self.clone()))
777 }
778
779 pub fn create_sound_from_pcm (&mut self,
783 pcm : &[i16],
784 mode : Mode,
785 exinfo : Option <&mut sound::Createsoundexinfo>
786 ) -> Result <Sound, Error> {
787 const WAV_HEADER_LEN : usize = 44;
788 let pcm_bytelen = pcm.len() * 2;
789 let wav_bytelen = WAV_HEADER_LEN + pcm_bytelen;
790 let mut wav = vec![0; wav_bytelen];
791 {
792 let cursor = std::io::Cursor::new (&mut wav);
793 let writer = std::io::BufWriter::new (cursor);
794 let mut wav_writer = riff_wave::WaveWriter::new (1, 44100, 16, writer)
795 .unwrap();
796 for sample in pcm.iter() {
797 wav_writer.write_sample_i16 (*sample).unwrap();
798 }
799 }
800 self.create_sound_from_memory (wav.as_slice(), mode, exinfo)
801 }
802
803 #[inline]
805 pub fn create_sound_from_file_default (&mut self, filename : &str)
806 -> Result <Sound, Error>
807 {
808 self.create_sound_from_file (filename, Mode::DEFAULT, None)
809 }
810
811 #[inline]
812 pub fn create_sound_from_memory_default (&mut self, data : &[u8])
813 -> Result <Sound, Error>
814 {
815 self.create_sound_from_memory (data, Mode::DEFAULT, None)
816 }
817
818 #[inline]
819 pub fn create_sound_from_pcm_default (&mut self, pcm : &[i16])
820 -> Result <Sound, Error>
821 {
822 self.create_sound_from_pcm (pcm, Mode::DEFAULT, None)
823 }
824
825 #[inline]
826 pub fn set_3d_listener_attributes (&mut self,
827 listener : i32, attributes : &ListenerAttributes
828 ) -> Result <(), Error> {
829 let pos = vector::to_ll (attributes.pos);
830 let vel = vector::to_ll (attributes.vel);
831 let forward = vector::to_ll (attributes.forward);
832 let up = vector::to_ll (attributes.up);
833 unsafe {
834 fmod_result!(
835 ll::FMOD_System_Set3DListenerAttributes (self.raw(),
836 listener, &pos, &vel, &forward, &up)
837 )
838 }
839 }
840
841 #[inline]
842 pub fn set_output (&mut self, output : Outputtype) -> Result <(), Error> {
843 unsafe {
844 fmod_result!(
845 ll::FMOD_System_SetOutput (self.raw(), output as ll::FMOD_OUTPUTTYPE))
846 }
847 }
848
849 #[inline]
858 pub fn set_reverb_properties (&mut self,
859 instance : i32, properties : &reverb3d::Properties
860 ) -> Result <(), Error> {
861 let properties = properties.to_ll();
862 unsafe {
863 fmod_result!(
864 ll::FMOD_System_SetReverbProperties (self.raw(), instance, &properties)
865 )
866 }
867 }
868
869 #[inline]
874 fn create() -> Result <Self, Error> {
875 let raw = {
876 let _lock = FMOD_SYSTEM_CREATE_DESTROY_MUTEX.lock().unwrap();
877 let mut raw = std::ptr::null_mut();
878 unsafe {
879 fmod_result!(ll::FMOD_System_Create (&mut raw))?;
880 }
881 raw
882 };
884 let inner = Rc::new (Inner (raw));
885 let system = System { inner };
886 let system_version = system.get_version_string()?;
887 if system_version != *crate::FMOD_VERSION_STRING {
888 log::error!(
889 "FMOD created system got shared library version {:?}, \
890 bindings were generated for version {:?}",
891 system_version, *crate::FMOD_VERSION_STRING);
892 panic!(
893 "FMOD created system got shared library version {:?}, \
894 bindings were generated for version {:?}",
895 system_version, *crate::FMOD_VERSION_STRING);
896 }
897 Ok (system)
898 }
899
900 #[inline]
902 fn init (&mut self, max_channels : u16, init_flags : Initflags)
903 -> Result <(), Error>
904 {
905 let max_channels = max_channels as i32;
906 unsafe {
907 fmod_result!(ll::FMOD_System_Init (
908 self.raw(), max_channels, init_flags.bits(), std::ptr::null_mut()))
909 }
910 }
911
912 #[inline]
915 fn set_software_channels (&mut self, numsoftwarechannels : i32)
916 -> Result <(), Error>
917 {
918 unsafe {
919 fmod_result!(
920 ll::FMOD_System_SetSoftwareChannels (self.raw(), numsoftwarechannels)
921 )
922 }
923 }
924
925}
926
927impl std::fmt::Debug for Inner {
928 fn fmt (&self, f : &mut std::fmt::Formatter) -> std::fmt::Result {
929 write!(f, "{:p}", self.0)
930 }
931}
932
933impl Drop for Inner {
934 fn drop (&mut self) {
935 let _lock = FMOD_SYSTEM_CREATE_DESTROY_MUTEX.lock().unwrap();
936 unsafe {
937 let _ = fmod_result!(ll::FMOD_System_Release (self.0)).map_err (
938 |err| log::error!("error releasing FMOD System@{:p}: {:?}", self.0, err));
939 }
940 }
942}
943
944impl From <ll::FMOD_GUID> for Guid {
945 fn from (guid : ll::FMOD_GUID) -> Self {
946 Guid {
947 data1: guid.Data1,
948 data2: guid.Data2,
949 data3: guid.Data3,
950 data4: guid.Data4
951 }
952 }
953}
954
955impl Outputtype {
956 pub fn from_ll (ll : ll::FMOD_OUTPUTTYPE) -> Self {
960 use num_traits::FromPrimitive;
961 #[allow(clippy::allow_attributes, clippy::unnecessary_cast, trivial_numeric_casts)]
963 Self::from_u32 (ll as u32).unwrap()
964 }
965}