From dcb7dea02850ab3507481cb8aeba05f49f33a63a Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Tue, 23 Jan 2018 16:58:37 +1100 Subject: [PATCH 1/2] Implement format handling in `build_voice` macos backend --- src/coreaudio/mod.rs | 69 +++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index 8c33151..5127d22 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -117,7 +117,7 @@ impl EventLoop { } #[inline] - pub fn build_voice(&self, _endpoint: &Endpoint, _format: &Format) + pub fn build_voice(&self, _endpoint: &Endpoint, format: &Format) -> Result { let mut audio_unit = { let au_type = if cfg!(target_os = "ios") { @@ -135,15 +135,27 @@ impl EventLoop { // TODO: iOS uses integer and fixed-point data // Set the stream in interleaved mode. + let n_channels = format.channels.len(); + let sample_rate = format.samples_rate.0; + let bytes_per_channel = format.data_type.sample_size(); + let bits_per_channel = bytes_per_channel * 8; + let bytes_per_frame = n_channels * bytes_per_channel; + let frames_per_packet = 1; + let bytes_per_packet = frames_per_packet * bytes_per_frame; + let sample_format = format.data_type; + let format_flags = match sample_format { + SampleFormat::F32 => (kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked) as u32, + _ => kAudioFormatFlagIsPacked as u32, + }; let asbd = AudioStreamBasicDescription { - mBitsPerChannel: 32, - mBytesPerFrame: 8, - mChannelsPerFrame: 2, - mBytesPerPacket: 8, - mFramesPerPacket: 1, - mFormatFlags: (kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked) as u32, + mBitsPerChannel: bits_per_channel, + mBytesPerFrame: bytes_per_frame, + mChannelsPerFrame: n_channels, + mBytesPerPacket: bytes_per_packet, + mFramesPerPacket: frames_per_packet, + mFormatFlags: format_flags, mFormatID: kAudioFormatLinearPCM, - mSampleRate: 44100.0, + mSampleRate: sample_rate as _, ..Default::default() }; audio_unit.set_property( @@ -172,28 +184,37 @@ impl EventLoop { mDataByteSize: data_byte_size, mData: data } = (*args.data.data).mBuffers[0]; - let data_slice = slice::from_raw_parts_mut(data as *mut f32, (data_byte_size / 4) as usize); + let mut callbacks = active_callbacks.callbacks.lock().unwrap(); - let callback = if let Some(cb) = callbacks.get_mut(0) { - cb - } else { - for sample in data_slice.iter_mut() { - *sample = 0.0; - } - return Ok(()); - }; + // A small macro to simplify handling the callback for different sample types. + macro_rules! try_callback { + ($SampleFormat:ident, $SampleType:ty, $equilibrium:expr) => {{ + let data_len = (data_byte_size / bytes_per_channel) as usize; + let data_slice = slice::from_raw_parts_mut(data as *mut $SampleType, data_len); + let callback = match callbacks.get_mut(0) { + Some(cb) => cb, + None => { + for sample in data_slice.iter_mut() { + *sample = $equilibrium; + } + return Ok(()); + } + }; + let buffer = Buffer { buffer: data_slice }; + let unknown_type_buffer = UnknownTypeBuffer::$SampleFormat(::Buffer { target: Some(buffer) }); + callback(VoiceId(voice_id), unknown_type_buffer); + }}; + } - let buffer = { - Buffer { - buffer: data_slice - } - }; + match sample_format { + SampleFormat::F32 => try_callback!(F32, f32, 0.0), + SampleFormat::I16 => try_callback!(I16, i16, 0), + SampleFormat::U16 => try_callback!(U16, u16, ::std::u16::consts::MAX / 2), + } - callback(VoiceId(voice_id), UnknownTypeBuffer::F32(::Buffer { target: Some(buffer) })); Ok(()) - })?; // TODO: start playing now? is that consistent with the other backends? From 45f2f1b371be43f3da0d7e9e15ab5370ae5c99c9 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Wed, 24 Jan 2018 21:34:18 +1100 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 2 ++ src/coreaudio/mod.rs | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9f0e3c..bdea42a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +- Implement format handling for macos `build_voice` method. + # Version 0.6.0 (2017-12-11) - Changed the emscripten backend to consume less CPU. diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index 5127d22..2413d41 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -148,11 +148,11 @@ impl EventLoop { _ => kAudioFormatFlagIsPacked as u32, }; let asbd = AudioStreamBasicDescription { - mBitsPerChannel: bits_per_channel, - mBytesPerFrame: bytes_per_frame, - mChannelsPerFrame: n_channels, - mBytesPerPacket: bytes_per_packet, - mFramesPerPacket: frames_per_packet, + mBitsPerChannel: bits_per_channel as _, + mBytesPerFrame: bytes_per_frame as _, + mChannelsPerFrame: n_channels as _, + mBytesPerPacket: bytes_per_packet as _, + mFramesPerPacket: frames_per_packet as _, mFormatFlags: format_flags, mFormatID: kAudioFormatLinearPCM, mSampleRate: sample_rate as _, @@ -191,7 +191,7 @@ impl EventLoop { // A small macro to simplify handling the callback for different sample types. macro_rules! try_callback { ($SampleFormat:ident, $SampleType:ty, $equilibrium:expr) => {{ - let data_len = (data_byte_size / bytes_per_channel) as usize; + let data_len = (data_byte_size as usize / bytes_per_channel) as usize; let data_slice = slice::from_raw_parts_mut(data as *mut $SampleType, data_len); let callback = match callbacks.get_mut(0) { Some(cb) => cb, @@ -211,7 +211,7 @@ impl EventLoop { match sample_format { SampleFormat::F32 => try_callback!(F32, f32, 0.0), SampleFormat::I16 => try_callback!(I16, i16, 0), - SampleFormat::U16 => try_callback!(U16, u16, ::std::u16::consts::MAX / 2), + SampleFormat::U16 => try_callback!(U16, u16, ::std::u16::MAX / 2), } Ok(())