Skip to main content

audio_toolbox/
audio_unit.rs

1use std::{mem, ptr::NonNull};
2
3use core_audio_types::{AudioBufferList, AudioTimeStamp};
4use core_foundation::base::OSStatus;
5use libc::c_void;
6use objc2_audio_toolbox as sys;
7pub use sys::{AudioUnitElement, AudioUnitParameterID, AudioUnitParameterValue, AudioUnitPropertyID, AudioUnitRenderActionFlags, AudioUnitScope};
8
9use crate::{audio_component::ComponentInstance, base::status_to_result};
10
11pub type Unit = ComponentInstance;
12
13impl Unit {
14    #[inline]
15    pub fn initialize(&self) -> Result<(), OSStatus> {
16        let status = unsafe { sys::AudioUnitInitialize(self.as_raw()) };
17        status_to_result(status)
18    }
19
20    #[inline]
21    pub fn uninitialize(&self) -> Result<(), OSStatus> {
22        let status = unsafe { sys::AudioUnitUninitialize(self.as_raw()) };
23        status_to_result(status)
24    }
25
26    #[inline]
27    pub fn start_output_unit(&self) -> Result<(), OSStatus> {
28        let status = unsafe { sys::AudioOutputUnitStart(self.as_raw()) };
29        status_to_result(status)
30    }
31
32    #[inline]
33    pub fn stop_output_unit(&self) -> Result<(), OSStatus> {
34        let status = unsafe { sys::AudioOutputUnitStop(self.as_raw()) };
35        status_to_result(status)
36    }
37
38    pub fn property_info(&self, property_id: AudioUnitPropertyID, scope: AudioUnitScope, element: AudioUnitElement) -> Result<(u32, bool), OSStatus> {
39        let mut size: u32 = 0;
40        let mut writable: u8 = 0;
41        let status = unsafe { sys::AudioUnitGetPropertyInfo(self.as_raw(), property_id, scope, element, &mut size, &mut writable) };
42        status_to_result(status).map(|_| (size, writable != 0))
43    }
44
45    #[inline]
46    pub fn get_property<T: Copy>(&self, property_id: AudioUnitPropertyID, scope: AudioUnitScope, element: AudioUnitElement) -> Result<T, OSStatus> {
47        let mut value = mem::MaybeUninit::<T>::uninit();
48        let mut size = mem::size_of::<T>() as u32;
49        let status = unsafe {
50            sys::AudioUnitGetProperty(
51                self.as_raw(),
52                property_id,
53                scope,
54                element,
55                NonNull::new_unchecked(value.as_mut_ptr().cast()),
56                NonNull::from(&mut size),
57            )
58        };
59        status_to_result(status)?;
60        Ok(unsafe { value.assume_init() })
61    }
62
63    pub fn get_property_bytes(
64        &self,
65        property_id: AudioUnitPropertyID,
66        scope: AudioUnitScope,
67        element: AudioUnitElement,
68    ) -> Result<Vec<u8>, OSStatus> {
69        let (size, _) = self.property_info(property_id, scope, element)?;
70        let mut bytes = vec![0u8; size as usize];
71        let mut io_size = size;
72        let out_data = NonNull::new(bytes.as_mut_ptr().cast::<c_void>()).unwrap_or_else(NonNull::dangling);
73        let status = unsafe { sys::AudioUnitGetProperty(self.as_raw(), property_id, scope, element, out_data, NonNull::from(&mut io_size)) };
74        status_to_result(status)?;
75        bytes.truncate(io_size as usize);
76        Ok(bytes)
77    }
78
79    #[inline]
80    pub fn set_property<T: Copy>(
81        &self,
82        property_id: AudioUnitPropertyID,
83        scope: AudioUnitScope,
84        element: AudioUnitElement,
85        value: &T,
86    ) -> Result<(), OSStatus> {
87        let status = unsafe {
88            sys::AudioUnitSetProperty(self.as_raw(), property_id, scope, element, (value as *const T).cast::<c_void>(), mem::size_of::<T>() as u32)
89        };
90        status_to_result(status)
91    }
92
93    pub fn set_property_bytes(
94        &self,
95        property_id: AudioUnitPropertyID,
96        scope: AudioUnitScope,
97        element: AudioUnitElement,
98        bytes: &[u8],
99    ) -> Result<(), OSStatus> {
100        let status =
101            unsafe { sys::AudioUnitSetProperty(self.as_raw(), property_id, scope, element, bytes.as_ptr().cast::<c_void>(), bytes.len() as u32) };
102        status_to_result(status)
103    }
104
105    #[inline]
106    pub fn clear_property(&self, property_id: AudioUnitPropertyID, scope: AudioUnitScope, element: AudioUnitElement) -> Result<(), OSStatus> {
107        let status = unsafe { sys::AudioUnitSetProperty(self.as_raw(), property_id, scope, element, std::ptr::null(), 0) };
108        status_to_result(status)
109    }
110
111    pub fn get_parameter(
112        &self,
113        parameter_id: AudioUnitParameterID,
114        scope: AudioUnitScope,
115        element: AudioUnitElement,
116    ) -> Result<AudioUnitParameterValue, OSStatus> {
117        let mut value: AudioUnitParameterValue = 0.0;
118        let status = unsafe { sys::AudioUnitGetParameter(self.as_raw(), parameter_id, scope, element, NonNull::from(&mut value)) };
119        status_to_result(status).map(|_| value)
120    }
121
122    #[inline]
123    pub fn set_parameter(
124        &self,
125        parameter_id: AudioUnitParameterID,
126        scope: AudioUnitScope,
127        element: AudioUnitElement,
128        value: AudioUnitParameterValue,
129        buffer_offset_in_frames: u32,
130    ) -> Result<(), OSStatus> {
131        let status = unsafe { sys::AudioUnitSetParameter(self.as_raw(), parameter_id, scope, element, value, buffer_offset_in_frames) };
132        status_to_result(status)
133    }
134
135    #[inline]
136    pub fn reset(&self, scope: AudioUnitScope, element: AudioUnitElement) -> Result<(), OSStatus> {
137        let status = unsafe { sys::AudioUnitReset(self.as_raw(), scope, element) };
138        status_to_result(status)
139    }
140
141    pub unsafe fn render(
142        &self,
143        action_flags: Option<&mut AudioUnitRenderActionFlags>,
144        time_stamp: &AudioTimeStamp,
145        output_bus_number: u32,
146        number_frames: u32,
147        io_data: &mut AudioBufferList,
148    ) -> Result<(), OSStatus> {
149        let action_flags = action_flags.map_or(std::ptr::null_mut(), |flags| flags as *mut AudioUnitRenderActionFlags);
150        let status =
151            sys::AudioUnitRender(self.as_raw(), action_flags, NonNull::from(time_stamp), output_bus_number, number_frames, NonNull::from(io_data));
152        status_to_result(status)
153    }
154}