fmod/
system.rs

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
10lazy_static!{
11  static ref FMOD_SYSTEM_CREATE_DESTROY_MUTEX : std::sync::Mutex <()> =
12    std::sync::Mutex::default();
13}
14
15/// Fmod system object.
16///
17/// This is a single reference counted pointer, so it can be freely cloned.
18///
19/// # Channels
20///
21/// There are three types of *channel* considered by the FMOD system:
22///
23/// 1. hardware output channels or "speakermode channels" -- the number of
24///    speakermode channels is returned in the `DriverInfo` structure by the
25///    `system.get_driver_info()` method
26/// 2. software channels -- "mixable voices"; unless specified, the FMOD default
27///    number of software channels is 64
28/// 3. virtual channels -- these are virtual voices that can be dynamically
29///    mapped to an available software channel depending on how audible it is
30///
31/// When playing a `Sound` with `sound.play()`, that sound is assigned to the
32/// returned virtual channel. If there are more playing virtual channels than
33/// the number of software channels, some channels will be dynamically
34/// *virtualized* and excluded from mixing, although other aspects such as
35/// playback position will continue to be updated.
36///
37/// If, at the time of the call to `sound.play()`, all virtual channels are in
38/// use, the virtual channel with the lowest *priority* will be 'stolen' from
39/// the currently playing sound, i.e. the sound currently playing on that
40/// channel is stopped *and* any subsequent function calls on the stolen sound's
41/// previously returned `Channel` will return `Error::ChannelStolen`.
42///
43/// The default priority for playback is 128. In practice if a number of default
44/// priority `play()` calls exceeding the virtual channel count are made all at
45/// once, the last played channel is re-stolen on each subsequent call to
46/// `play`.
47///
48/// # Reverb
49///
50/// TODO
51#[derive(Clone, Debug, PartialEq)]
52pub struct System {
53  inner : Rc <Inner>
54}
55
56#[derive(PartialEq)]
57struct Inner (*mut ll::FMOD_SYSTEM);
58
59#[derive(Debug)]
60pub struct DriverInfo {
61  pub name                : String,
62  pub guid                : Guid,
63  pub systemrate          : i32,
64  pub speakermode         : Speakermode,
65  pub speakermodechannels : i32
66}
67
68bitflags!{
69  #[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
70  pub struct CallbackType : u32 {
71    const DEVICELISTCHANGED      = ll::FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED;
72    const DEVICELOST             = ll::FMOD_SYSTEM_CALLBACK_DEVICELOST;
73    const MEMORYALLOCATIONFAILED = ll::FMOD_SYSTEM_CALLBACK_MEMORYALLOCATIONFAILED;
74    const THREADCREATED          = ll::FMOD_SYSTEM_CALLBACK_THREADCREATED;
75    const BADDSPCONNECTION       = ll::FMOD_SYSTEM_CALLBACK_BADDSPCONNECTION;
76    const PREMIX                 = ll::FMOD_SYSTEM_CALLBACK_PREMIX;
77    const POSTMIX                = ll::FMOD_SYSTEM_CALLBACK_POSTMIX;
78    const ERROR                  = ll::FMOD_SYSTEM_CALLBACK_ERROR;
79    const MIDMIX                 = ll::FMOD_SYSTEM_CALLBACK_MIDMIX;
80    const THREADDESTROYED        = ll::FMOD_SYSTEM_CALLBACK_THREADDESTROYED;
81    const PREUPDATE              = ll::FMOD_SYSTEM_CALLBACK_PREUPDATE;
82    const POSTUPDATE             = ll::FMOD_SYSTEM_CALLBACK_POSTUPDATE;
83    const RECORDLISTCHANGED      = ll::FMOD_SYSTEM_CALLBACK_RECORDLISTCHANGED;
84    const ALL                    = ll::FMOD_SYSTEM_CALLBACK_ALL;
85  }
86}
87
88bitflags!{
89  #[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
90  pub struct Initflags : u32 {
91    const NORMAL                     = ll::FMOD_INIT_NORMAL;
92    const STREAM_FROM_UPDATE         = ll::FMOD_INIT_STREAM_FROM_UPDATE;
93    const MIX_FROM_UPDATE            = ll::FMOD_INIT_MIX_FROM_UPDATE;
94    const _3D_RIGHTHANDED            = ll::FMOD_INIT_3D_RIGHTHANDED;
95    const CHANNEL_LOWPASS            = ll::FMOD_INIT_CHANNEL_LOWPASS;
96    const CHANNEL_DISTANCEFILTER     = ll::FMOD_INIT_CHANNEL_DISTANCEFILTER;
97    const PROFILE_ENABLE             = ll::FMOD_INIT_PROFILE_ENABLE;
98    const VOL0_BECOMES_VIRTUAL       = ll::FMOD_INIT_VOL0_BECOMES_VIRTUAL;
99    const GEOMETRY_USECLOSEST        = ll::FMOD_INIT_GEOMETRY_USECLOSEST;
100    const PREFER_DOLBY_DOWNMIX       = ll::FMOD_INIT_PREFER_DOLBY_DOWNMIX;
101    const THREAD_UNSAFE              = ll::FMOD_INIT_THREAD_UNSAFE;
102    const PROFILE_METER_ALL          = ll::FMOD_INIT_PROFILE_METER_ALL;
103    const DISABLE_SRS_HIGHPASSFILTER = ll::FMOD_INIT_DISABLE_SRS_HIGHPASSFILTER;
104  }
105}
106
107#[derive(Copy, Clone, Debug, Eq, PartialEq, FromPrimitive)]
108pub enum Outputtype {
109  Autodetect    = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUTODETECT    as isize,
110  Unknown       = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_UNKNOWN       as isize,
111  Nosound       = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_NOSOUND       as isize,
112  Wavwriter     = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WAVWRITER     as isize,
113  NosoundNrt    = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_NOSOUND_NRT   as isize,
114  WavwriterNrt  = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WAVWRITER_NRT as isize,
115  Dsound        = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_DSOUND        as isize,
116  Winmm         = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WINMM         as isize,
117  Wasapi        = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WASAPI        as isize,
118  Asio          = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_ASIO          as isize,
119  Pulseaudio    = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_PULSEAUDIO    as isize,
120  Alsa          = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_ALSA          as isize,
121  Coreaudio     = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_COREAUDIO     as isize,
122  Xaudio        = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_XAUDIO        as isize,
123  Ps3           = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_PS3           as isize,
124  Audiotrack    = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUDIOTRACK    as isize,
125  Opensl        = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_OPENSL        as isize,
126  Wiiu          = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WIIU          as isize,
127  Audioout      = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUDIOOUT      as isize,
128  Audio3d       = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_AUDIO3D       as isize,
129  Atmos         = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_ATMOS         as isize,
130  Webaudio      = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WEBAUDIO      as isize,
131  Nnaudio       = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_NNAUDIO       as isize,
132  Winsonic      = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_WINSONIC      as isize,
133  MAX           = ll::FMOD_OUTPUTTYPE_FMOD_OUTPUTTYPE_MAX           as isize
134}
135
136impl System {
137  /// Create and initialize with 256 max virtual channels, the default number of
138  /// software channels (64), and `Initflags::NORMAL`.
139  #[inline]
140  pub fn default() -> Result <Self, Error> {
141    Self::new (None, 256, Initflags::NORMAL)
142  }
143
144  /// Create with the given number of software channels, max number of virtual
145  /// channels, and initflags.
146  ///
147  /// If the number of software channels is not provided, by default FMOD will
148  /// create a system with 64 software channels.
149  #[inline]
150  pub fn new (
151    num_software_channels : Option <u16>,
152    num_virtual_channels  : u16,
153    initflags             : Initflags
154  ) -> Result <Self, Error> {
155    let mut system = Self::create()?;
156    if let Some (n) = num_software_channels {
157      system.set_software_channels (n as i32)?;
158    }
159    // TODO: make this a parameter; when FMOD sees the pulseaudio daemon, it
160    // defaults to pulseaudio and init returns `FileNotFound` error, so we
161    // manually set the output to always be Alsa
162    #[cfg(not(target_os = "windows"))]
163    system.set_output (Outputtype::Alsa)?;
164    system.init (num_virtual_channels, initflags)?;
165    Ok (system)
166  }
167
168  //
169  //  &self
170  //
171
172  #[inline]
173  fn raw (&self) -> *mut ll::FMOD_SYSTEM {
174    (*self.inner).0
175  }
176
177  #[inline]
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_mut()))
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  /// Retrieves the global doppler scale, distance factor and rolloff scale for
221  /// all 3D sound in FMOD
222  #[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  /// Returns the currently selected driver number
266  #[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    // NB: assuming names are not longer than 256 bytes
278    let name_len = 256;
279    let mut name = vec![0; name_len];
280    let mut guid = ll::FMOD_GUID {
281      Data1: 0, Data2: 0, Data3: 0, Data4: [0; 8]
282    };
283    let mut systemrate = 0;
284    let mut speakermode = 0;
285    let mut speakermodechannels = 0;
286    unsafe {
287      use std::os::raw;
288      fmod_result!(ll::FMOD_System_GetDriverInfo (
289        self.raw(),
290        id as raw::c_int,
291        name.as_mut_ptr() as *mut raw::c_char,
292        name_len as raw::c_int,
293        &mut guid,
294        &mut systemrate,
295        &mut speakermode,
296        &mut speakermodechannels
297      ))?;
298    }
299    let name = {
300      let name = name.split (|x| *x == 0).next().unwrap().to_vec();
301      String::from_utf8 (name).unwrap()
302    };
303    let guid = Guid::from (guid);
304    let speakermode = Speakermode::from_ll (speakermode);
305    let info = DriverInfo {
306      name, guid, systemrate, speakermode, speakermodechannels
307    };
308    Ok (info)
309  }
310
311  /// Retrieves the buffer size settings for the FMOD software mixing engine.
312  ///
313  /// Returns `(bufferlength, numbuffers)`:
314  ///
315  /// - `buffelength` -- Address of a variable that receives the mixer engine
316  ///   block size in samples. Default = 1024. (milliseconds = 1024 at 48khz =
317  ///   1024 / 48000 * 1000 = 10.66ms). This means the mixer updates every
318  ///   21.3ms.
319  /// - `numbuffers` -- Address of a variable that receives the mixer engine
320  ///   number of buffers used. Default = 4. To get the total buffersize
321  ///   multiply the bufferlength by the numbuffers value. By default this would
322  ///   be 4*1024.
323  #[inline]
324  pub fn get_dsp_buffer_size (&self) -> Result <(u32, i32), Error> {
325    let mut bufferlength = 0;
326    let mut numbuffers = 0;
327    unsafe {
328      fmod_result!(
329        ll::FMOD_System_GetDSPBufferSize (
330          self.raw(), &mut bufferlength, &mut numbuffers)
331      )?;
332    }
333    Ok ((bufferlength, numbuffers))
334  }
335
336  /// Calculates geometry occlusion between a listener and a sound source.
337  ///
338  /// Returns `(direct, reverb)`.
339  #[inline]
340  pub fn get_geometry_occlusion (&self, listener : [f32; 3], source : [f32; 3])
341    -> Result <(f32, f32), Error>
342  {
343    let listener = vector::to_ll (listener);
344    let source   = vector::to_ll (source);
345    let mut direct = 0.0;
346    let mut reverb = 0.0;
347    unsafe {
348      fmod_result!(
349        ll::FMOD_System_GetGeometryOcclusion (self.raw(),
350          &listener, &source, &mut direct, &mut reverb)
351      )?;
352    }
353    Ok ((direct, reverb))
354  }
355
356  /// Retrieves the maximum world size for the geometry engine
357  #[inline]
358  pub fn get_geometry_settings (&self) -> Result <f32, Error> {
359    let mut maxworldsize = 0.0;
360    unsafe {
361      fmod_result!(
362        ll::FMOD_System_GetGeometrySettings (self.raw(), &mut maxworldsize)
363      )?;
364    }
365    Ok (maxworldsize)
366  }
367
368  #[inline]
369  pub fn get_master_channel_group (&self) -> Result <ChannelGroupRef, Error> {
370    let mut raw = std::ptr::null_mut();
371    unsafe {
372      fmod_result!(
373        ll::FMOD_System_GetMasterChannelGroup (self.raw(), &mut raw)
374      )?;
375    }
376    let channel_group =
377      ChannelGroup::from_raw_parts (raw, false, self.clone());
378    Ok (ChannelGroupRef { channel_group })
379  }
380
381  #[inline]
382  pub fn get_num_drivers (&self) -> Result <i32, Error> {
383    let mut numdrivers = 0;
384    unsafe {
385      fmod_result!(ll::FMOD_System_GetNumDrivers (self.raw(), &mut numdrivers))?;
386    }
387    Ok (numdrivers)
388  }
389
390  #[inline]
391  pub fn get_num_plugins (&self, plugintype : Plugintype)
392    -> Result <i32, Error>
393  {
394    let mut numplugins = 0;
395    unsafe {
396      fmod_result!(ll::FMOD_System_GetNumPlugins (
397        self.raw(), plugintype as ll::FMOD_PLUGINTYPE, &mut numplugins)
398      )?;
399    }
400    Ok (numplugins)
401  }
402
403  #[inline]
404  pub fn get_output (&self) -> Result <Outputtype, Error> {
405    let mut outputtype = 0;
406    unsafe {
407      fmod_result!(ll::FMOD_System_GetOutput (self.raw(), &mut outputtype))?;
408    }
409    Ok (Outputtype::from_ll (outputtype))
410  }
411
412  /// Returns the currently selected output as an id in the list of output
413  /// plugins
414  #[inline]
415  pub fn get_output_by_plugin (&self) -> Result <PluginHandle, Error> {
416    let mut handle = 0;
417    unsafe {
418      fmod_result!(ll::FMOD_System_GetOutputByPlugin (self.raw(), &mut handle))?;
419    }
420    Ok (PluginHandle (handle))
421  }
422
423  #[inline]
424  pub fn get_record_driver_info (&self, id : i32)
425    -> Result <(DriverInfo, DriverState), Error>
426  {
427    // NB: assuming names are not longer than 256 bytes
428    let name_len = 256;
429    let mut name = vec![0; name_len];
430    let mut guid = ll::FMOD_GUID {
431      Data1: 0, Data2: 0, Data3: 0, Data4: [0; 8]
432    };
433    let mut systemrate = 0;
434    let mut speakermode = 0;
435    let mut speakermodechannels = 0;
436    let mut state = 0;
437    unsafe {
438      use std::os::raw;
439      fmod_result!(ll::FMOD_System_GetRecordDriverInfo (
440        self.raw(),
441        id as raw::c_int,
442        name.as_mut_ptr() as *mut raw::c_char,
443        name_len as raw::c_int,
444        &mut guid,
445        &mut systemrate,
446        &mut speakermode,
447        &mut speakermodechannels,
448        &mut state
449      ))?;
450    }
451    let name = {
452      let name = name.split (|x| *x == 0).next().unwrap().to_vec();
453      String::from_utf8 (name).unwrap()
454    };
455    let guid = Guid::from (guid);
456    let speakermode = Speakermode::from_ll (speakermode);
457    let info = DriverInfo {
458      name, guid, systemrate, speakermode, speakermodechannels
459    };
460    let state = DriverState::from_bits (state).unwrap();
461    Ok ((info, state))
462  }
463
464  /// Returns the number of recording drivers available for this output mode and
465  /// the number of recording drivers currently plugged in
466  #[inline]
467  pub fn get_record_num_drivers (&self) -> Result <(i32, i32), Error> {
468    let mut numdrivers   = 0;
469    let mut numconnected = 0;
470    unsafe {
471      fmod_result!(ll::FMOD_System_GetRecordNumDrivers (
472        self.raw(), &mut numdrivers, &mut numconnected
473      ))?;
474    }
475    Ok ((numdrivers, numconnected))
476  }
477
478  #[inline]
479  pub fn get_reverb_properties (&self, instance : i32)
480    -> Result <reverb3d::Properties, Error>
481  {
482    let mut properties = ll::FMOD_REVERB_PROPERTIES {
483      DecayTime:          0.0,
484      EarlyDelay:         0.0,
485      LateDelay:          0.0,
486      HFReference:        0.0,
487      HFDecayRatio:       0.0,
488      Diffusion:          0.0,
489      Density:            0.0,
490      LowShelfFrequency:  0.0,
491      LowShelfGain:       0.0,
492      HighCut:            0.0,
493      EarlyLateMix:       0.0,
494      WetLevel:           0.0
495    };
496    unsafe {
497      fmod_result!(
498        ll::FMOD_System_GetReverbProperties (self.raw(),
499          instance, &mut properties)
500      )?;
501    }
502    let properties = reverb3d::Properties::from_ll (&properties);
503    Ok (properties)
504  }
505
506  #[inline]
507  pub fn get_software_channels (&self) -> Result <i32, Error> {
508    let mut numsoftwarechannels = 0;
509    unsafe {
510      fmod_result!(
511        ll::FMOD_System_GetSoftwareChannels (
512          self.raw(), &mut numsoftwarechannels)
513      )?;
514    }
515    Ok (numsoftwarechannels)
516  }
517
518  /// Retrieves the output format for the software mixer:
519  ///
520  /// `(samplerate, speakermode, numrawspeakers)`
521  #[inline]
522  pub fn get_software_format (&self)
523    -> Result <(i32, Speakermode, i32), Error>
524  {
525    let mut samplerate = 0;
526    let mut speakermode = 0;
527    let mut numrawspeakers = 0;
528    unsafe {
529      fmod_result!(
530        ll::FMOD_System_GetSoftwareFormat (
531          self.raw(), &mut samplerate, &mut speakermode, &mut numrawspeakers)
532      )?;
533    }
534    let speakermode = Speakermode::from_ll (speakermode);
535    Ok ((samplerate, speakermode, numrawspeakers))
536  }
537
538  #[inline]
539  pub fn get_sound_ram (&self) -> Result <SoundRam, Error> {
540    let mut ram = SoundRam::default();
541    unsafe {
542      fmod_result!(
543        ll::FMOD_System_GetSoundRAM (self.raw(),
544          &mut ram.currentalloced, &mut ram.maxalloced, &mut ram.total)
545      )?;
546    }
547    Ok (ram)
548  }
549
550  #[inline]
551  pub fn get_speaker_mode_channels (&self, mode : Speakermode)
552    -> Result <i32, Error>
553  {
554    let mut channels = 0;
555    unsafe {
556      fmod_result!(
557        ll::FMOD_System_GetSpeakerModeChannels (
558          self.raw(), mode as ll::FMOD_SPEAKERMODE, &mut channels)
559      )?;
560    }
561    Ok (channels)
562  }
563
564  /// Retrieves the current speaker position information for the selected
565  /// speaker.
566  ///
567  /// Returns `(x, y, active)`.
568  #[inline]
569  pub fn get_speaker_position (&self, speaker : Speaker)
570    -> Result <(f32, f32, bool), Error>
571  {
572    let mut x      = 0.0;
573    let mut y      = 0.0;
574    let mut active = 0;
575    unsafe {
576      fmod_result!(
577        ll::FMOD_System_GetSpeakerPosition (
578          self.raw(), speaker as ll::FMOD_SPEAKER, &mut x, &mut y, &mut active)
579      )?;
580    }
581    Ok ((x, y, active != 0))
582  }
583
584  /// Returns the current internal buffersize settings for streamable sounds
585  #[inline]
586  pub fn get_stream_buffer_size (&self)
587    -> Result <(u32, Timeunit), Error>
588  {
589    let mut filebuffersize     = 0;
590    let mut filebuffersizetype = 0;
591    unsafe {
592      fmod_result!(
593        ll::FMOD_System_GetStreamBufferSize (
594          self.raw(), &mut filebuffersize, &mut filebuffersizetype)
595      )?;
596    }
597    Ok ((filebuffersize, Timeunit::from_bits (filebuffersizetype).unwrap()))
598  }
599
600  /// Version of linked FMOD shared library.
601  ///
602  /// The version is a 32 bit hexadecimal value formated as 16:8:8, with the
603  /// upper 16 bits being the product version, the middle 8 bits being the major
604  /// version and the bottom 8 bits being the minor version.
605  #[inline]
606  pub fn get_version (&self) -> Result <u32, Error> {
607    let mut version = 0;
608    unsafe {
609      fmod_result!(ll::FMOD_System_GetVersion (self.raw(), &mut version))?;
610    }
611    Ok (version)
612  }
613
614  /// Version of linked FMOD shared library
615  #[inline]
616  pub fn get_version_string (&self) -> Result <String, Error> {
617    self.get_version().map (crate::version_string)
618  }
619
620  //
621  //  &mut self
622  //
623
624  #[inline]
625  pub fn create_channel_group (&mut self, name : Option <&str>)
626    -> Result <ChannelGroup, Error>
627  {
628    let mut raw     = std::ptr::null_mut();
629    let name_string = std::ffi::CString::new (name.unwrap_or ("")).unwrap();
630    let name_ptr    = if name.is_some() {
631      name_string.as_ptr()
632    } else {
633      std::ptr::null()
634    };
635    unsafe {
636      fmod_result!(
637        ll::FMOD_System_CreateChannelGroup (self.raw(), name_ptr, &mut raw)
638      )?;
639    }
640    Ok (ChannelGroup::from_raw_parts (raw, true, self.clone()))
641  }
642
643  #[inline]
644  pub fn create_dsp (&mut self, description : &'static dsp::Description)
645    -> Result <Dsp, Error>
646  {
647    let mut raw = std::ptr::null_mut();
648    unsafe {
649      fmod_result!(
650        ll::FMOD_System_CreateDSP (self.raw(),
651          description.as_ref() as *const _, &mut raw)
652      )?;
653    }
654    Ok (Dsp::from_raw_parts (raw, true, self.clone()))
655  }
656
657  #[inline]
658  pub fn create_dsp_by_type (&mut self, type_ : dsp::Type)
659    -> Result <Dsp, Error>
660  {
661    let mut raw = std::ptr::null_mut();
662    unsafe {
663      fmod_result!(
664        ll::FMOD_System_CreateDSPByType (self.raw(), type_ as ll::FMOD_DSP_TYPE,
665          &mut raw)
666      )?;
667    }
668    Ok (Dsp::from_raw_parts (raw, true, self.clone()))
669  }
670
671  /// A convenience method that creates a `dsp::Sfxreverb` from a given
672  /// `reverb3d::Properties` and dry level.
673  pub fn create_dsp_sfxreverb (&mut self,
674    properties : &reverb3d::Properties, dry_level : f32
675  ) -> Result <Dsp, Error> {
676    let mut raw = std::ptr::null_mut();
677    unsafe {
678      fmod_result!(
679        ll::FMOD_System_CreateDSPByType (
680          self.raw(),
681          dsp::Type::Sfxreverb as ll::FMOD_DSP_TYPE,
682          &mut raw
683        )
684      )?;
685    }
686    let mut dsp = Dsp::from_raw_parts (raw, true, self.clone());
687    dsp.set_parameters_sfxreverb (properties, dry_level)?;
688    Ok (dsp)
689  }
690
691  #[inline]
692  pub fn create_reverb3d (&mut self) -> Result <Reverb3d, Error> {
693    let mut raw = std::ptr::null_mut();
694    unsafe {
695      fmod_result!(ll::FMOD_System_CreateReverb3D (self.raw(), &mut raw))?;
696    }
697    Ok (Reverb3d::from_raw_parts (raw, self.clone()))
698  }
699
700  pub fn create_sound_from_file (&mut self,
701    filename : &str,
702    mode     : Mode,
703    exinfo   : Option <&mut sound::Createsoundexinfo>
704  ) -> Result <Sound, Error> {
705    let filename   = std::ffi::CString::new (filename).unwrap();
706    let mut exinfo = exinfo.map (sound::Createsoundexinfo::to_ll);
707    let mut raw    = std::ptr::null_mut();
708    unsafe {
709      fmod_result!(
710        ll::FMOD_System_CreateSound (
711          self.raw(),
712          filename.as_ptr(),
713          mode.bits(),
714          exinfo.as_mut()
715            .map (|exinfo| exinfo as *mut ll::FMOD_CREATESOUNDEXINFO)
716            .unwrap_or (std::ptr::null_mut()),
717          &mut raw)
718      )?;
719    }
720    Ok (Sound::from_raw_parts (raw, true, self.clone()))
721  }
722
723  pub fn create_sound_from_memory (&mut self,
724    data     : &[u8],
725    mut mode : Mode,
726    exinfo   : Option <&mut sound::Createsoundexinfo>
727  ) -> Result <Sound, Error> {
728    mode |= Mode::OPENMEMORY;
729    let mut exinfo_default = Default::default();
730    let mut exinfo = {
731      let exinfo    = exinfo.unwrap_or (&mut exinfo_default);
732      exinfo.length = data.len() as u32;
733      sound::Createsoundexinfo::to_ll (exinfo)
734    };
735    let mut raw = std::ptr::null_mut();
736    let data = if data.len() > 0 {
737      data.as_ptr() as *const std::os::raw::c_char
738    } else {
739      std::ptr::null()
740    };
741    unsafe {
742      fmod_result!(
743        ll::FMOD_System_CreateSound (
744          self.raw(),
745          data,
746          mode.bits(),
747          &mut exinfo,
748          &mut raw)
749      )?;
750    }
751    Ok (Sound::from_raw_parts (raw, true, self.clone()))
752  }
753
754  pub fn create_sound_from_pcm (&mut self,
755    pcm    : &[i16],
756    mode   : Mode,
757    exinfo : Option <&mut sound::Createsoundexinfo>
758  ) -> Result <Sound, Error> {
759    const WAV_HEADER_LEN : usize = 44;
760    let pcm_bytelen = pcm.len() as usize * 2;
761    let wav_bytelen = WAV_HEADER_LEN + pcm_bytelen;
762    let mut wav     = vec![0; wav_bytelen];
763    {
764      let cursor = std::io::Cursor::new (&mut wav);
765      let writer = std::io::BufWriter::new (cursor);
766      let mut wav_writer = riff_wave::WaveWriter::new (1, 44100, 16, writer)
767        .unwrap();
768      for sample in pcm.iter() {
769        wav_writer.write_sample_i16 (*sample).unwrap();
770      }
771    }
772    self.create_sound_from_memory (wav.as_slice(), mode, exinfo)
773  }
774
775  /// Open a sound in `DEFAULT` mode with no exinfo argument
776  #[inline]
777  pub fn create_sound_from_file_default (&mut self, filename : &str)
778    -> Result <Sound, Error>
779  {
780    self.create_sound_from_file (filename, Mode::DEFAULT, None)
781  }
782
783  #[inline]
784  pub fn create_sound_from_memory_default (&mut self, data : &[u8])
785    -> Result <Sound, Error>
786  {
787    self.create_sound_from_memory (data, Mode::DEFAULT, None)
788  }
789
790  #[inline]
791  pub fn create_sound_from_pcm_default (&mut self, pcm : &[i16])
792    -> Result <Sound, Error>
793  {
794    self.create_sound_from_pcm (pcm, Mode::DEFAULT, None)
795  }
796
797  #[inline]
798  pub fn set_3d_listener_attributes (&mut self,
799    listener : i32, attributes : &ListenerAttributes
800  ) -> Result <(), Error> {
801    let pos     = vector::to_ll (attributes.pos);
802    let vel     = vector::to_ll (attributes.vel);
803    let forward = vector::to_ll (attributes.forward);
804    let up      = vector::to_ll (attributes.up);
805    unsafe {
806      fmod_result!(
807        ll::FMOD_System_Set3DListenerAttributes (self.raw(),
808          listener, &pos, &vel, &forward, &up)
809      )
810    }
811  }
812
813  #[inline]
814  pub fn set_output (&mut self, output : Outputtype) -> Result <(), Error> {
815    unsafe {
816      fmod_result!(
817        ll::FMOD_System_SetOutput (self.raw(), output as ll::FMOD_OUTPUTTYPE))
818    }
819  }
820
821  /// Sets parameters for the global reverb environment.
822  ///
823  /// `instance` -- Index of the particular reverb instance to target, from 0 to
824  /// `fmod::dsp::REVERB_MAXINSTANCES`.
825  ///
826  /// When using each instance for the first time, FMOD will create a physical
827  /// SFX reverb DSP unit that takes up several hundred kilobytes of memory and
828  /// some CPU.
829  #[inline]
830  pub fn set_reverb_properties (&mut self,
831    instance : i32, properties : &reverb3d::Properties
832  ) -> Result <(), Error> {
833    let properties = properties.to_ll();
834    unsafe {
835      fmod_result!(
836        ll::FMOD_System_SetReverbProperties (self.raw(), instance, &properties)
837      )
838    }
839  }
840
841  //
842  //  private
843  //
844
845  #[inline]
846  fn create() -> Result <Self, Error> {
847    let raw = {
848      let _lock = FMOD_SYSTEM_CREATE_DESTROY_MUTEX.lock().unwrap();
849      let mut raw = std::ptr::null_mut();
850      unsafe {
851        fmod_result!(ll::FMOD_System_Create (&mut raw))?;
852      }
853      raw
854      // unlock
855    };
856    let inner          = Rc::new (Inner (raw));
857    let system         = System { inner };
858    let system_version = system.get_version_string()?;
859    if system_version != *crate::FMOD_VERSION_STRING {
860      log::error!(
861        "FMOD created system got shared library version {:?}, \
862          bindings were generated for version {:?}",
863        system_version, *crate::FMOD_VERSION_STRING);
864      panic!(
865        "FMOD created system got shared library version {:?}, \
866          bindings were generated for version {:?}",
867        system_version, *crate::FMOD_VERSION_STRING);
868    }
869    Ok (system)
870  }
871
872  /// `max_channels` is the maximum number of *virtual channels*
873  #[inline]
874  fn init (&mut self, max_channels : u16, init_flags : Initflags)
875    -> Result <(), Error>
876  {
877    let max_channels = max_channels as i32;
878    unsafe {
879      fmod_result!(ll::FMOD_System_Init (
880        self.raw(), max_channels, init_flags.bits(), std::ptr::null_mut()))
881    }
882  }
883
884  // /!\ NOTE /!\: this method can only be called when the system has not yet
885  // been initialized
886  #[inline]
887  fn set_software_channels (&mut self, numsoftwarechannels : i32)
888    -> Result <(), Error>
889  {
890    unsafe {
891      fmod_result!(
892        ll::FMOD_System_SetSoftwareChannels (self.raw(), numsoftwarechannels)
893      )
894    }
895  }
896
897}
898
899impl std::fmt::Debug for Inner {
900  fn fmt (&self, f : &mut std::fmt::Formatter) -> std::fmt::Result {
901    write!(f, "{:p}", self.0)
902  }
903}
904
905impl Drop for Inner {
906  fn drop (&mut self) {
907    let _lock = FMOD_SYSTEM_CREATE_DESTROY_MUTEX.lock().unwrap();
908    unsafe {
909      let _ = fmod_result!(ll::FMOD_System_Release (self.0)).map_err (
910        |err| log::error!("error releasing FMOD System@{:p}: {:?}", self.0, err));
911    }
912    // unlock
913  }
914}
915
916impl From <ll::FMOD_GUID> for Guid {
917  fn from (guid : ll::FMOD_GUID) -> Self {
918    Guid {
919      data1: guid.Data1,
920      data2: guid.Data2,
921      data3: guid.Data3,
922      data4: guid.Data4
923    }
924  }
925}
926
927impl Outputtype {
928  pub fn from_ll (ll : ll::FMOD_OUTPUTTYPE) -> Self {
929    use num_traits::FromPrimitive;
930    Self::from_u32 (ll as u32).unwrap()
931  }
932}