Skip to content

Commit

Permalink
Change Element datatype to be u32.
Browse files Browse the repository at this point in the history
As i understand it, an audio unit can have several inputs and several outputs,
and an 'element' is just an index of one of those (https://developer.apple.com/library/archive/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).

Therefore, it's should be possible, for example, to have several render callbacks for a single audio unit.
An example would be a crossfade unit with 2 inputs: it'll have 2 elements in its input scope
and 1 in output scope, and it'll require either two render callbacks (one for each input),
or two upstream audio units.

This changes Element to be just a number and adds explicit element parameter to all the places
where it hasn't been present before (i.e. setting callbacks and input/output stream formats).

This relates to the issue RustAudio#60 and PR RustAudio#47.
  • Loading branch information
dmski committed May 9, 2019
1 parent 08c8b79 commit e51eaf0
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 34 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ homepage = "https://github.com/RustAudio/coreaudio-rs"
[lib]
name = "coreaudio"

[[bin]]
name = "example-sine"
path = "examples/sine.rs"

[features]
default = ["audio_toolbox", "audio_unit", "core_audio", "open_al", "core_midi"]
audio_toolbox = ["coreaudio-sys/audio_toolbox"]
Expand Down
14 changes: 7 additions & 7 deletions examples/sine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,26 @@ fn run() -> Result<(), coreaudio::Error> {
.map(|phase| (phase * PI * 2.0).sin() as f32 * 0.15);

// Construct an Output audio unit that delivers audio to the default output device.
let mut audio_unit = try!(AudioUnit::new(IOType::DefaultOutput));
let mut audio_unit = AudioUnit::new(IOType::DefaultOutput)?;

let stream_format = try!(audio_unit.output_stream_format());
let stream_format = audio_unit.output_stream_format(0)?;
println!("{:#?}", &stream_format);

// For this example, our sine wave expects `f32` data.
assert!(SampleFormat::F32 == stream_format.sample_format);
assert_eq!(SampleFormat::F32, stream_format.sample_format);

type Args = render_callback::Args<data::NonInterleaved<f32>>;
try!(audio_unit.set_render_callback(move |args| {
audio_unit.set_render_callback(move |args| {
let Args { num_frames, mut data, .. } = args;
for i in 0..num_frames {
let sample = samples.next().unwrap();
for channel in data.channels_mut() {
for mut channel in data.channels_mut() {
channel[i] = sample;
}
}
Ok(())
}));
try!(audio_unit.start());
}, 0)?;
audio_unit.start()?;

std::thread::sleep(std::time::Duration::from_millis(3000));

Expand Down
34 changes: 15 additions & 19 deletions src/audio_unit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,9 @@ pub enum Scope {
LayerItem = 7,
}

/// Represents the **Input** and **Output** **Element**s.
///
/// These are used when specifying which **Element** we're setting the properties of.
#[derive(Copy, Clone, Debug)]
pub enum Element {
Output = 0,
Input = 1,
}
/// These are used when specifying which **Element** (bus) we're setting the properties of.
/// [The anatomy of an AudioUnit](https://developer.apple.com/library/archive/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html#//apple_ref/doc/uid/TP40003278-CH12-SW11)
type Element = u32;


/// A rust representation of the sys::AudioUnit, including a pointer to the current rendering callback.
Expand Down Expand Up @@ -229,15 +224,15 @@ impl AudioUnit {
/// Set the **AudioUnit**'s sample rate.
///
/// **Available** in iOS 2.0 and later.
pub fn set_sample_rate(&mut self, sample_rate: f64) -> Result<(), Error> {
pub fn set_sample_rate(&mut self, element: u32, sample_rate: f64) -> Result<(), Error> {
let id = sys::kAudioUnitProperty_SampleRate;
self.set_property(id, Scope::Input, Element::Output, Some(&sample_rate))
self.set_property(id, Scope::Input, element, Some(&sample_rate))
}

/// Get the **AudioUnit**'s sample rate.
pub fn sample_rate(&self) -> Result<f64, Error> {
pub fn sample_rate(&self, element: Element) -> Result<f64, Error> {
let id = sys::kAudioUnitProperty_SampleRate;
self.get_property(id, Scope::Input, Element::Output)
self.get_property(id, Scope::Input, element)
}

/// Sets the current **StreamFormat** for the AudioUnit.
Expand All @@ -258,27 +253,28 @@ impl AudioUnit {
&mut self,
stream_format: StreamFormat,
scope: Scope,
element: Element,
) -> Result<(), Error> {
let id = sys::kAudioUnitProperty_StreamFormat;
let asbd = stream_format.to_asbd();
self.set_property(id, scope, Element::Output, Some(&asbd))
self.set_property(id, scope, element, Some(&asbd))
}

/// Return the current Stream Format for the AudioUnit.
pub fn stream_format(&self, scope: Scope) -> Result<StreamFormat, Error> {
pub fn stream_format(&self, scope: Scope, element: Element) -> Result<StreamFormat, Error> {
let id = sys::kAudioUnitProperty_StreamFormat;
let asbd = try!(self.get_property(id, scope, Element::Output));
let asbd = self.get_property(id, scope, element)?;
StreamFormat::from_asbd(asbd)
}

/// Return the current output Stream Format for the AudioUnit.
pub fn output_stream_format(&self) -> Result<StreamFormat, Error> {
self.stream_format(Scope::Output)
pub fn output_stream_format(&self, element: Element) -> Result<StreamFormat, Error> {
self.stream_format(Scope::Output, element)
}

/// Return the current input Stream Format for the AudioUnit.
pub fn input_stream_format(&self) -> Result<StreamFormat, Error> {
self.stream_format(Scope::Input)
pub fn input_stream_format(&self, element: Element) -> Result<StreamFormat, Error> {
self.stream_format(Scope::Input, element)
}
}

Expand Down
16 changes: 8 additions & 8 deletions src/audio_unit/render_callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,15 +390,15 @@ pub mod action_flags {

impl AudioUnit {
/// Pass a render callback (aka "Input Procedure") to the **AudioUnit**.
pub fn set_render_callback<F, D>(&mut self, mut f: F) -> Result<(), Error>
pub fn set_render_callback<F, D>(&mut self, mut f: F, element: Element) -> Result<(), Error>
where
F: FnMut(Args<D>) -> Result<(), ()> + 'static,
D: Data,
{
// First, we'll retrieve the stream format so that we can ensure that the given callback
// format matches the audio unit's format.
let id = sys::kAudioUnitProperty_StreamFormat;
let asbd = try!(self.get_property(id, Scope::Output, Element::Output));
let asbd = self.get_property(id, Scope::Output, element)?;
let stream_format = super::StreamFormat::from_asbd(asbd)?;

// If the stream format does not match, return an error indicating this.
Expand Down Expand Up @@ -453,7 +453,7 @@ impl AudioUnit {
self.set_property(
sys::kAudioUnitProperty_SetRenderCallback,
Scope::Input,
Element::Output,
element,
Some(&render_callback),
)?;

Expand All @@ -463,15 +463,15 @@ impl AudioUnit {
}

/// Pass an input callback (aka "Input Procedure") to the **AudioUnit**.
pub fn set_input_callback<F, D>(&mut self, mut f: F) -> Result<(), Error>
pub fn set_input_callback<F, D>(&mut self, mut f: F, element: Element) -> Result<(), Error>
where
F: FnMut(Args<D>) -> Result<(), ()> + 'static,
D: Data,
{
// First, we'll retrieve the stream format so that we can ensure that the given callback
// format matches the audio unit's format.
let id = sys::kAudioUnitProperty_StreamFormat;
let asbd = self.get_property(id, Scope::Input, Element::Input)?;
let asbd = self.get_property(id, Scope::Input, element)?;
let stream_format = super::StreamFormat::from_asbd(asbd)?;

// If the stream format does not match, return an error indicating this.
Expand All @@ -483,7 +483,7 @@ impl AudioUnit {
//
// First, get the current buffer size for pre-allocating the `AudioBuffer`s.
let id = sys::kAudioDevicePropertyBufferFrameSize;
let mut buffer_frame_size: u32 = self.get_property(id, Scope::Global, Element::Output)?;
let mut buffer_frame_size: u32 = self.get_property(id, Scope::Global, 0)?; // Always 0 bus for Scope::Global
let mut data: Vec<u8> = vec![];
let sample_bytes = stream_format.sample_format.size_in_bytes();
let n_channels = stream_format.channels_per_frame;
Expand Down Expand Up @@ -525,7 +525,7 @@ impl AudioUnit {
unsafe {
// Retrieve the up-to-date stream format.
let id = sys::kAudioUnitProperty_StreamFormat;
let asbd = match super::get_property(audio_unit, id, Scope::Input, Element::Output) {
let asbd = match super::get_property(audio_unit, id, Scope::Input, in_bus_number) {
Err(err) => return err.to_os_status(),
Ok(asbd) => asbd,
};
Expand Down Expand Up @@ -607,7 +607,7 @@ impl AudioUnit {
self.set_property(
sys::kAudioOutputUnitProperty_SetInputCallback,
Scope::Global,
Element::Output,
element,
Some(&render_callback),
)?;

Expand Down

0 comments on commit e51eaf0

Please sign in to comment.