1use std::{
7 ffi::{c_char, c_float, c_int, c_short, c_uchar, c_uint, c_ushort},
8 marker::PhantomData,
9 mem::MaybeUninit,
10};
11
12use fmod_sys::*;
13use lanyard::{Utf8CStr, Utf8CString};
14
15use crate::{
16 string_from_utf16_be, string_from_utf16_le, ChannelOrder, DspParameterDataType, Mode,
17 SoundFormat, SoundGroup, SoundType, TagType, TimeUnit,
18};
19
20#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
21#[repr(C)]
23pub struct Guid {
24 pub data_1: c_uint,
25 pub data_2: c_ushort,
26 pub data_3: c_ushort,
27 pub data_4: [c_uchar; 8],
28}
29
30impl Guid {
31 pub fn parse(string: &Utf8CStr) -> Result<Self> {
32 let mut guid = MaybeUninit::uninit();
33 unsafe {
34 FMOD_Studio_ParseID(string.as_ptr(), guid.as_mut_ptr()).to_result()?;
35 Ok(guid.assume_init().into())
36 }
37 }
38}
39
40impl From<FMOD_GUID> for Guid {
41 fn from(value: FMOD_GUID) -> Self {
42 Guid {
43 data_1: value.Data1,
44 data_2: value.Data2,
45 data_3: value.Data3,
46 data_4: value.Data4,
47 }
48 }
49}
50
51impl From<Guid> for FMOD_GUID {
52 fn from(value: Guid) -> Self {
53 FMOD_GUID {
54 Data1: value.data_1,
55 Data2: value.data_2,
56 Data3: value.data_3,
57 Data4: value.data_4,
58 }
59 }
60}
61
62impl std::fmt::Display for Guid {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 let Guid {
65 data_1,
66 data_2,
67 data_3,
68 data_4,
69 } = self;
70
71 f.write_str("{")?;
72 f.write_fmt(format_args!("{data_1:0>8x}-{data_2:0>4x}-{data_3:0>4x}-"))?;
73 f.write_fmt(format_args!("{:0>2x}{:0>2x}-", data_4[0], data_4[1]))?;
74 for b in &data_4[2..] {
75 f.write_fmt(format_args!("{b:0>2x}"))?;
76 }
77 f.write_str("}")
78 }
79}
80
81#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
82#[repr(C)]
83pub struct Vector {
84 pub x: c_float,
85 pub y: c_float,
86 pub z: c_float,
87}
88
89impl From<Vector> for FMOD_VECTOR {
90 fn from(value: Vector) -> Self {
91 FMOD_VECTOR {
92 x: value.x,
93 y: value.y,
94 z: value.z,
95 }
96 }
97}
98
99impl From<FMOD_VECTOR> for Vector {
100 fn from(value: FMOD_VECTOR) -> Self {
101 Vector {
102 x: value.x,
103 y: value.y,
104 z: value.z,
105 }
106 }
107}
108
109#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
110#[repr(C)]
111pub struct Attributes3D {
112 pub position: Vector,
113 pub velocity: Vector,
114 pub forward: Vector,
115 pub up: Vector,
116}
117
118impl From<FMOD_3D_ATTRIBUTES> for Attributes3D {
119 fn from(value: FMOD_3D_ATTRIBUTES) -> Self {
120 Attributes3D {
121 position: value.position.into(),
122 velocity: value.velocity.into(),
123 forward: value.forward.into(),
124 up: value.up.into(),
125 }
126 }
127}
128
129impl From<Attributes3D> for FMOD_3D_ATTRIBUTES {
130 fn from(value: Attributes3D) -> Self {
131 FMOD_3D_ATTRIBUTES {
132 position: value.position.into(),
133 velocity: value.velocity.into(),
134 forward: value.forward.into(),
135 up: value.up.into(),
136 }
137 }
138}
139
140#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
141pub struct CpuUsage {
142 pub dsp: c_float,
143 pub stream: c_float,
144 pub geometry: c_float,
145 pub update: c_float,
146 pub convolution_1: c_float,
147 pub convolution_2: c_float,
148}
149
150impl From<FMOD_CPU_USAGE> for CpuUsage {
151 fn from(value: FMOD_CPU_USAGE) -> Self {
152 CpuUsage {
153 dsp: value.dsp,
154 stream: value.stream,
155 geometry: value.geometry,
156 update: value.update,
157 convolution_1: value.convolution1,
158 convolution_2: value.convolution2,
159 }
160 }
161}
162
163impl From<CpuUsage> for FMOD_CPU_USAGE {
164 fn from(value: CpuUsage) -> Self {
165 FMOD_CPU_USAGE {
166 dsp: value.dsp,
167 stream: value.stream,
168 geometry: value.geometry,
169 update: value.update,
170 convolution1: value.convolution_1,
171 convolution2: value.convolution_2,
172 }
173 }
174}
175
176#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
177#[repr(C)]
178pub struct ReverbProperties {
179 pub decay_time: c_float,
180 pub early_delay: c_float,
181 pub late_delay: c_float,
182 pub hf_reference: c_float,
183 pub hf_decay_ratio: c_float,
184 pub diffusion: c_float,
185 pub density: c_float,
186 pub low_shelf_frequency: c_float,
187 pub low_shelf_gain: c_float,
188 pub high_cut: c_float,
189 pub early_late_mix: c_float,
190 pub wet_level: c_float,
191}
192
193impl From<FMOD_REVERB_PROPERTIES> for ReverbProperties {
194 fn from(value: FMOD_REVERB_PROPERTIES) -> Self {
195 ReverbProperties {
196 decay_time: value.DecayTime,
197 early_delay: value.EarlyDelay,
198 late_delay: value.LateDelay,
199 hf_reference: value.HFReference,
200 hf_decay_ratio: value.HFDecayRatio,
201 diffusion: value.Diffusion,
202 density: value.Density,
203 low_shelf_frequency: value.LowShelfFrequency,
204 low_shelf_gain: value.LowShelfGain,
205 high_cut: value.HighCut,
206 early_late_mix: value.EarlyLateMix,
207 wet_level: value.WetLevel,
208 }
209 }
210}
211
212impl From<ReverbProperties> for FMOD_REVERB_PROPERTIES {
213 fn from(value: ReverbProperties) -> Self {
214 FMOD_REVERB_PROPERTIES {
215 DecayTime: value.decay_time,
216 EarlyDelay: value.early_delay,
217 LateDelay: value.late_delay,
218 HFReference: value.hf_reference,
219 HFDecayRatio: value.hf_decay_ratio,
220 Diffusion: value.diffusion,
221 Density: value.density,
222 LowShelfFrequency: value.low_shelf_frequency,
223 LowShelfGain: value.low_shelf_gain,
224 HighCut: value.high_cut,
225 EarlyLateMix: value.early_late_mix,
226 WetLevel: value.wet_level,
227 }
228 }
229}
230
231pub struct DspParameterDescription {
232 pub kind: DspParameterType,
233 pub name: Utf8CString,
234 pub label: Utf8CString,
235 pub description: Utf8CString,
236}
237
238#[derive(Clone, Debug, PartialEq)]
239pub enum DspParameterType {
240 Float {
241 min: f32,
242 max: f32,
243 default: f32,
244 mapping: FloatMapping,
245 },
246 Int {
247 min: i32,
248 max: i32,
249 default: i32,
250 goes_to_infinity: bool,
251 },
253 Bool {
254 default: bool,
255 },
257 Data {
258 data_type: DspParameterDataType,
259 },
260}
261
262#[derive(Clone, Copy, Debug, PartialEq, Eq)]
263pub struct FloatMapping {
264 }
266
267impl DspParameterDescription {
268 pub unsafe fn from_ffi(value: FMOD_DSP_PARAMETER_DESC) -> Self {
278 let name = unsafe { Utf8CStr::from_ptr_unchecked(value.name.as_ptr()).to_cstring() };
280 let label = unsafe { Utf8CStr::from_ptr_unchecked(value.label.as_ptr()).to_cstring() };
281 let description = unsafe { Utf8CStr::from_ptr_unchecked(value.description).to_cstring() };
282 let kind = match value.type_ {
283 FMOD_DSP_PARAMETER_TYPE_FLOAT => {
284 let floatdesc = unsafe { value.__bindgen_anon_1.floatdesc };
285 DspParameterType::Float {
286 min: floatdesc.min,
287 max: floatdesc.max,
288 default: floatdesc.defaultval,
289 mapping: FloatMapping {},
290 }
291 }
292 FMOD_DSP_PARAMETER_TYPE_INT => {
293 let intdesc = unsafe { value.__bindgen_anon_1.intdesc };
294 DspParameterType::Int {
295 min: intdesc.min,
296 max: intdesc.max,
297 default: intdesc.defaultval,
298 goes_to_infinity: intdesc.goestoinf.into(),
299 }
300 }
301 FMOD_DSP_PARAMETER_TYPE_BOOL => {
302 let booldesc = unsafe { value.__bindgen_anon_1.booldesc };
303 DspParameterType::Bool {
304 default: booldesc.defaultval.into(),
305 }
306 }
307 FMOD_DSP_PARAMETER_TYPE_DATA => {
308 let datadesc = unsafe { value.__bindgen_anon_1.datadesc };
309 DspParameterType::Data {
310 data_type: datadesc.datatype.try_into().unwrap(),
311 }
312 }
313 _ => panic!("invalid parameter description type"), };
315 Self {
316 kind,
317 name,
318 label,
319 description,
320 }
321 }
322
323 }
325
326#[derive(Clone, Copy, Debug, PartialEq)]
327pub struct DspMeteringInfo {
328 pub sample_count: c_int,
329 pub peak_level: [c_float; 32],
330 pub rms_level: [c_float; 32],
331 pub channel_count: c_short,
332}
333
334impl From<FMOD_DSP_METERING_INFO> for DspMeteringInfo {
335 fn from(value: FMOD_DSP_METERING_INFO) -> Self {
336 Self {
337 sample_count: value.numsamples,
338 peak_level: value.peaklevel,
339 rms_level: value.rmslevel,
340 channel_count: value.numchannels,
341 }
342 }
343}
344
345impl From<DspMeteringInfo> for FMOD_DSP_METERING_INFO {
346 fn from(value: DspMeteringInfo) -> Self {
347 FMOD_DSP_METERING_INFO {
348 numsamples: value.sample_count,
349 peaklevel: value.peak_level,
350 rmslevel: value.rms_level,
351 numchannels: value.channel_count,
352 }
353 }
354}
355
356pub struct Tag {
357 pub kind: TagType,
358 pub name: Utf8CString,
359 pub data: TagData,
360 pub updated: bool,
361}
362
363pub enum TagData {
365 Binary(Vec<u8>),
366 Integer(i64),
367 Float(f64),
368 String(String),
369 Utf8String(String),
370 Utf16StringBE(String),
371 Utf16String(String),
372}
373
374impl Tag {
375 #[allow(clippy::cast_lossless)]
383 pub unsafe fn from_ffi(value: FMOD_TAG) -> Self {
384 let kind = value.type_.try_into().unwrap();
385 let name = unsafe { Utf8CStr::from_ptr_unchecked(value.name).to_cstring() };
386 let updated = value.updated.into();
387 let data = unsafe {
388 match value.datatype {
390 FMOD_TAGDATATYPE_BINARY => {
391 let slice =
392 std::slice::from_raw_parts(value.data as *const u8, value.datalen as usize);
393 TagData::Binary(slice.to_vec())
394 }
395 FMOD_TAGDATATYPE_INT => match value.datalen {
396 1 => TagData::Integer(*value.data.cast::<i8>() as i64),
397 2 => TagData::Integer(*value.data.cast::<i16>() as i64),
398 4 => TagData::Integer(*value.data.cast::<i32>() as i64),
399 8 => TagData::Integer(*value.data.cast::<i64>()),
400 _ => panic!("unrecognized integer data len"),
401 },
402 FMOD_TAGDATATYPE_FLOAT => match value.datalen {
403 4 => TagData::Float(*value.data.cast::<f32>() as f64),
404 8 => TagData::Float(*value.data.cast::<f64>()),
405 _ => panic!("unrecognized float data len"),
406 },
407 FMOD_TAGDATATYPE_STRING => {
408 let ascii =
409 std::slice::from_raw_parts(value.data.cast(), value.datalen as usize);
410 let string = String::from_utf8_lossy(ascii).into_owned();
411 TagData::String(string)
412 }
413 FMOD_TAGDATATYPE_STRING_UTF8 => {
414 let utf8 =
415 std::slice::from_raw_parts(value.data.cast(), value.datalen as usize);
416 let string = String::from_utf8_lossy(utf8).into_owned();
417 TagData::Utf8String(string)
418 }
419 FMOD_TAGDATATYPE_STRING_UTF16 => {
423 let slice =
424 std::slice::from_raw_parts(value.data.cast(), value.datalen as usize);
425 let string = string_from_utf16_le(slice);
426 TagData::Utf16String(string)
427 }
428 FMOD_TAGDATATYPE_STRING_UTF16BE => {
429 let slice =
430 std::slice::from_raw_parts(value.data.cast(), value.datalen as usize);
431 let string = string_from_utf16_be(slice);
432 TagData::Utf16StringBE(string)
433 }
434 _ => panic!("unrecognized tag data type"), }
436 };
437 Tag {
438 kind,
439 name,
440 data,
441 updated,
442 }
443 }
444}
445
446#[derive(Debug)]
447pub struct SoundBuilder<'a> {
448 pub(crate) mode: FMOD_MODE,
449 pub(crate) create_sound_ex_info: FMOD_CREATESOUNDEXINFO,
450 pub(crate) name_or_data: *const c_char,
451 pub(crate) _phantom: PhantomData<&'a ()>,
452}
453
454const EMPTY_EXINFO: FMOD_CREATESOUNDEXINFO = unsafe {
455 FMOD_CREATESOUNDEXINFO {
456 cbsize: std::mem::size_of::<FMOD_CREATESOUNDEXINFO>() as c_int,
457 ..std::mem::MaybeUninit::zeroed().assume_init()
458 }
459};
460
461impl<'a> SoundBuilder<'a> {
463 pub const fn open(filename: &'a Utf8CStr) -> Self {
464 Self {
465 mode: 0,
466 create_sound_ex_info: EMPTY_EXINFO,
467 name_or_data: filename.as_ptr(),
468 _phantom: PhantomData,
469 }
470 }
471
472 pub const unsafe fn open_memory(data: &'a [u8]) -> Self {
479 Self {
480 mode: FMOD_OPENMEMORY,
481 create_sound_ex_info: FMOD_CREATESOUNDEXINFO {
482 length: data.len() as c_uint,
483 ..EMPTY_EXINFO
484 },
485 name_or_data: data.as_ptr().cast(),
486 _phantom: PhantomData,
487 }
488 }
489
490 pub const unsafe fn open_memory_point(data: &'a [u8]) -> Self {
495 Self {
496 mode: FMOD_OPENMEMORY_POINT,
497 create_sound_ex_info: FMOD_CREATESOUNDEXINFO {
498 length: data.len() as c_uint,
499 ..EMPTY_EXINFO
500 },
501 name_or_data: data.as_ptr().cast(),
502 _phantom: PhantomData,
503 }
504 }
505
506 #[must_use]
510 pub const unsafe fn with_raw_ex_info(mut self, ex_info: FMOD_CREATESOUNDEXINFO) -> Self {
511 self.create_sound_ex_info = ex_info;
512 self
513 }
514
515 #[must_use]
516 pub const fn with_file_offset(mut self, file_offset: c_uint) -> Self {
517 self.create_sound_ex_info.fileoffset = file_offset;
518 self
519 }
520
521 #[must_use]
522 pub const fn with_open_raw(
523 mut self,
524 channel_count: c_int,
525 default_frequency: c_int,
526 format: SoundFormat,
527 ) -> Self {
528 self.mode |= FMOD_OPENRAW;
529 self.create_sound_ex_info.numchannels = channel_count;
530 self.create_sound_ex_info.defaultfrequency = default_frequency;
531 self.create_sound_ex_info.format = format as _;
532 self
533 }
534
535 #[must_use]
536 pub const fn with_mode(mut self, mode: Mode) -> Self {
537 const DISABLE_MODES: Mode = Mode::OPEN_MEMORY
538 .union(Mode::OPEN_MEMORY_POINT)
539 .union(Mode::OPEN_USER)
540 .union(Mode::OPEN_RAW);
541
542 let mode = mode.difference(DISABLE_MODES); let mode: FMOD_MODE = mode.bits();
544 self.mode |= mode;
545 self
546 }
547
548 #[must_use]
549 pub const fn with_decode_buffer_size(mut self, size: c_uint) -> Self {
550 self.create_sound_ex_info.decodebuffersize = size;
551 self
552 }
553
554 #[must_use]
555 pub const fn with_initial_subsound(mut self, initial_subsound: c_int) -> Self {
556 self.create_sound_ex_info.initialsubsound = initial_subsound;
557 self
558 }
559
560 #[must_use]
561 pub const fn with_subsound_count(mut self, count: c_int) -> Self {
562 self.create_sound_ex_info.numsubsounds = count;
563 self
564 }
565
566 #[must_use]
568 pub const fn with_inclusion_list(mut self, list: &'a [c_int]) -> Self {
569 self.create_sound_ex_info.inclusionlist = list.as_ptr().cast_mut().cast();
570 self.create_sound_ex_info.inclusionlistnum = list.len() as c_int;
571 self
572 }
573
574 #[must_use]
576 pub const fn with_dls_name(mut self, dls_name: &'a Utf8CStr) -> Self {
577 self.create_sound_ex_info.dlsname = dls_name.as_ptr();
578 self
579 }
580
581 #[must_use]
583 pub const fn with_encryption_key(mut self, key: &'a Utf8CStr) -> Self {
584 self.create_sound_ex_info.encryptionkey = key.as_ptr();
585 self
586 }
587
588 #[must_use]
589 pub fn with_max_polyphony(mut self, max_polyphony: c_int) -> Self {
590 self.create_sound_ex_info.maxpolyphony = max_polyphony;
591 self
592 }
593
594 #[must_use]
595 pub const fn with_suggested_sound_type(mut self, sound_type: SoundType) -> Self {
596 self.create_sound_ex_info.suggestedsoundtype = sound_type as _;
597 self
598 }
599
600 #[must_use]
601 pub const fn with_file_buffer_size(mut self, size: c_int) -> Self {
602 self.create_sound_ex_info.filebuffersize = size;
603 self
604 }
605
606 #[must_use]
607 pub const fn with_channel_order(mut self, order: ChannelOrder) -> Self {
608 self.create_sound_ex_info.channelorder = order as _;
609 self
610 }
611
612 #[must_use]
613 pub fn with_initial_sound_group(mut self, group: SoundGroup) -> Self {
614 self.create_sound_ex_info.initialsoundgroup = group.into();
615 self
616 }
617
618 #[must_use]
619 pub const fn with_initial_seek_position(mut self, position: c_uint, unit: TimeUnit) -> Self {
620 self.create_sound_ex_info.initialseekposition = position;
621 self.create_sound_ex_info.initialseekpostype = unit as _;
622 self
623 }
624
625 #[must_use]
626 pub fn with_ignore_set_filesystem(mut self, ignore: bool) -> Self {
627 self.create_sound_ex_info.ignoresetfilesystem = ignore.into();
628 self
629 }
630
631 #[must_use]
632 pub const fn with_min_midi_granularity(mut self, granularity: c_uint) -> Self {
633 self.create_sound_ex_info.minmidigranularity = granularity as _;
634 self
635 }
636
637 #[must_use]
638 pub const fn with_non_block_thread_id(mut self, id: c_int) -> Self {
639 self.create_sound_ex_info.nonblockthreadid = id as _;
640 self
641 }
642
643 #[must_use]
645 pub const fn with_fsb_guid(mut self, guid: &'a Guid) -> Self {
646 self.create_sound_ex_info.fsbguid = std::ptr::from_ref(guid).cast_mut().cast();
647 self
648 }
649
650 pub(crate) fn ex_info_is_empty(&self) -> bool {
651 self.create_sound_ex_info == EMPTY_EXINFO
652 }
653}
654
655impl<'a> SoundBuilder<'a> {
657 pub const fn mode(&self) -> Mode {
658 Mode::from_bits_truncate(self.mode)
659 }
660
661 pub const fn raw_ex_info(&self) -> FMOD_CREATESOUNDEXINFO {
662 self.create_sound_ex_info
663 }
664
665 pub const fn raw_name_or_data(&self) -> *const c_char {
666 self.name_or_data
667 }
668
669 pub fn name_or_url(&self) -> Option<&Utf8CStr> {
670 if self
671 .mode()
672 .intersects(Mode::OPEN_MEMORY | Mode::OPEN_MEMORY_POINT | Mode::OPEN_USER)
673 {
674 None
675 } else {
676 Some(unsafe { Utf8CStr::from_ptr_unchecked(self.name_or_data) })
677 }
678 }
679
680 pub fn data(&self) -> Option<&[u8]> {
681 if self
682 .mode()
683 .intersects(Mode::OPEN_MEMORY | Mode::OPEN_MEMORY_POINT)
684 {
685 Some(unsafe {
686 std::slice::from_raw_parts(
687 self.name_or_data.cast(),
688 self.create_sound_ex_info.length as usize,
689 )
690 })
691 } else {
692 None
693 }
694 }
695
696 pub fn length(&self) -> c_uint {
697 self.create_sound_ex_info.length
698 }
699
700 pub fn file_offset(&self) -> c_uint {
701 self.create_sound_ex_info.fileoffset
702 }
703
704 pub fn num_channels(&self) -> c_int {
705 self.create_sound_ex_info.numchannels
706 }
707
708 pub fn default_frequency(&self) -> c_int {
709 self.create_sound_ex_info.defaultfrequency
710 }
711
712 pub fn format(&self) -> SoundFormat {
713 self.create_sound_ex_info.format.try_into().unwrap()
714 }
715
716 pub fn decode_buffer_size(&self) -> c_uint {
717 self.create_sound_ex_info.decodebuffersize
718 }
719
720 pub fn initial_subsound(&self) -> c_int {
721 self.create_sound_ex_info.initialsubsound
722 }
723
724 pub fn subsound_count(&self) -> c_int {
725 self.create_sound_ex_info.numsubsounds
726 }
727
728 pub fn inclusion_list(&self) -> Option<&'a [c_int]> {
729 if self.create_sound_ex_info.inclusionlist.is_null() {
730 None
731 } else {
732 Some(unsafe {
733 std::slice::from_raw_parts(
734 self.create_sound_ex_info.inclusionlist.cast(),
735 self.create_sound_ex_info.inclusionlistnum as usize,
736 )
737 })
738 }
739 }
740
741 pub fn dls_name(&self) -> Option<&Utf8CStr> {
742 if self.create_sound_ex_info.dlsname.is_null() {
743 None
744 } else {
745 Some(unsafe { Utf8CStr::from_ptr_unchecked(self.create_sound_ex_info.dlsname) })
746 }
747 }
748
749 pub fn encryption_key(&self) -> Option<&Utf8CStr> {
750 if self.create_sound_ex_info.encryptionkey.is_null() {
751 None
752 } else {
753 Some(unsafe { Utf8CStr::from_ptr_unchecked(self.create_sound_ex_info.encryptionkey) })
754 }
755 }
756
757 pub fn max_polyphony(&self) -> c_int {
758 self.create_sound_ex_info.maxpolyphony
759 }
760
761 pub fn suggested_sound_type(&self) -> SoundType {
762 self.create_sound_ex_info
763 .suggestedsoundtype
764 .try_into()
765 .unwrap()
766 }
767
768 pub fn file_buffer_size(&self) -> c_int {
769 self.create_sound_ex_info.filebuffersize
770 }
771
772 pub fn channel_order(&self) -> ChannelOrder {
773 self.create_sound_ex_info.channelorder.try_into().unwrap()
774 }
775
776 pub fn initial_sound_group(&self) -> SoundGroup {
777 SoundGroup::from(self.create_sound_ex_info.initialsoundgroup)
778 }
779
780 pub fn initial_seek_position(&self) -> (c_uint, TimeUnit) {
781 (
782 self.create_sound_ex_info.initialseekposition,
783 self.create_sound_ex_info
784 .initialseekpostype
785 .try_into()
786 .unwrap(),
787 )
788 }
789
790 pub fn ignore_set_filesystem(&self) -> bool {
791 self.create_sound_ex_info.ignoresetfilesystem > 0
792 }
793
794 pub fn min_midi_granularity(&self) -> c_uint {
795 self.create_sound_ex_info.minmidigranularity
796 }
797
798 pub fn non_block_thread_id(&self) -> c_int {
799 self.create_sound_ex_info.nonblockthreadid
800 }
801
802 pub fn fsb_guid(&self) -> Option<Guid> {
803 if self.create_sound_ex_info.fsbguid.is_null() {
804 None
805 } else {
806 Some(unsafe { *(self.create_sound_ex_info.fsbguid.cast()) })
807 }
808 }
809}
810
811impl<'a> SoundBuilder<'a> {
812 pub unsafe fn from_ffi(
823 name_or_data: *const c_char,
824 mode: FMOD_MODE,
825 create_sound_ex_info: FMOD_CREATESOUNDEXINFO,
826 ) -> Self {
827 Self {
828 mode,
829 create_sound_ex_info,
830 name_or_data,
831 _phantom: PhantomData,
832 }
833 }
834}