Merge pull request #112 from Furyhunter/coreaudio-get-period
[osx] Add get_period to Voice
This commit is contained in:
commit
7e4f9f00d1
|
@ -3,6 +3,7 @@ extern crate libc;
|
||||||
|
|
||||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
@ -47,6 +48,7 @@ pub struct Buffer<'a, T: 'a> {
|
||||||
samples: Vec<T>,
|
samples: Vec<T>,
|
||||||
num_channels: NumChannels,
|
num_channels: NumChannels,
|
||||||
marker: PhantomData<&'a T>,
|
marker: PhantomData<&'a T>,
|
||||||
|
pending_samples: Arc<AtomicUsize>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Buffer<'a, T> {
|
impl<'a, T> Buffer<'a, T> {
|
||||||
|
@ -62,10 +64,12 @@ impl<'a, T> Buffer<'a, T> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn finish(self) {
|
pub fn finish(self) {
|
||||||
let Buffer { samples_sender, samples, num_channels, .. } = self;
|
let Buffer { samples_sender, samples, num_channels, pending_samples, .. } = self;
|
||||||
// TODO: At the moment this assumes the Vec<T> is a Vec<f32>.
|
// TODO: At the moment this assumes the Vec<T> is a Vec<f32>.
|
||||||
// Need to add T: Sample and use Sample::to_vec_f32.
|
// Need to add T: Sample and use Sample::to_vec_f32.
|
||||||
|
let num_samples = samples.len();
|
||||||
let samples = unsafe { mem::transmute(samples) };
|
let samples = unsafe { mem::transmute(samples) };
|
||||||
|
pending_samples.fetch_add(num_samples, Ordering::SeqCst);
|
||||||
match samples_sender.send((samples, num_channels)) {
|
match samples_sender.send((samples, num_channels)) {
|
||||||
Err(_) => panic!("Failed to send samples to audio unit callback."),
|
Err(_) => panic!("Failed to send samples to audio unit callback."),
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
|
@ -82,7 +86,8 @@ pub struct Voice {
|
||||||
ready_receiver: Receiver<(NumChannels, NumFrames)>,
|
ready_receiver: Receiver<(NumChannels, NumFrames)>,
|
||||||
samples_sender: Sender<(Vec<f32>, NumChannels)>,
|
samples_sender: Sender<(Vec<f32>, NumChannels)>,
|
||||||
underflow: Arc<Mutex<RefCell<bool>>>,
|
underflow: Arc<Mutex<RefCell<bool>>>,
|
||||||
last_ready: Arc<Mutex<RefCell<Option<(NumChannels, NumFrames)>>>>
|
last_ready: Arc<Mutex<RefCell<Option<(NumChannels, NumFrames)>>>>,
|
||||||
|
pending_samples: Arc<AtomicUsize>
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Sync for Voice {}
|
unsafe impl Sync for Voice {}
|
||||||
|
@ -98,6 +103,10 @@ impl Voice {
|
||||||
let underflow = Arc::new(Mutex::new(RefCell::new(false)));
|
let underflow = Arc::new(Mutex::new(RefCell::new(false)));
|
||||||
let uf_clone = underflow.clone();
|
let uf_clone = underflow.clone();
|
||||||
|
|
||||||
|
let pending_samples: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));
|
||||||
|
|
||||||
|
let pending_samples_c = pending_samples.clone();
|
||||||
|
|
||||||
let audio_unit_result = AudioUnit::new(IOType::HalOutput);
|
let audio_unit_result = AudioUnit::new(IOType::HalOutput);
|
||||||
|
|
||||||
if let Ok(mut audio_unit) = audio_unit_result {
|
if let Ok(mut audio_unit) = audio_unit_result {
|
||||||
|
@ -112,11 +121,14 @@ impl Voice {
|
||||||
*(uf.borrow_mut()) = num_frames > samples.len() / num_channels;
|
*(uf.borrow_mut()) = num_frames > samples.len() / num_channels;
|
||||||
} else { return Err("Couldn't lock underflow flag field.".to_string()) }
|
} else { return Err("Couldn't lock underflow flag field.".to_string()) }
|
||||||
|
|
||||||
|
pending_samples_c.fetch_sub(samples.len(), Ordering::SeqCst);
|
||||||
|
|
||||||
for (i, frame) in samples.chunks(num_channels).enumerate() {
|
for (i, frame) in samples.chunks(num_channels).enumerate() {
|
||||||
for (channel, sample) in channels.iter_mut().zip(frame.iter()) {
|
for (channel, sample) in channels.iter_mut().zip(frame.iter()) {
|
||||||
channel[i] = *sample;
|
channel[i] = *sample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -129,7 +141,8 @@ impl Voice {
|
||||||
ready_receiver: ready_receiver,
|
ready_receiver: ready_receiver,
|
||||||
samples_sender: samples_sender,
|
samples_sender: samples_sender,
|
||||||
underflow: underflow,
|
underflow: underflow,
|
||||||
last_ready: Arc::new(Mutex::new(RefCell::new(None)))
|
last_ready: Arc::new(Mutex::new(RefCell::new(None))),
|
||||||
|
pending_samples: pending_samples
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,7 +159,8 @@ impl Voice {
|
||||||
samples_sender: self.samples_sender.clone(),
|
samples_sender: self.samples_sender.clone(),
|
||||||
samples: vec![unsafe { mem::uninitialized() }; buffer_size],
|
samples: vec![unsafe { mem::uninitialized() }; buffer_size],
|
||||||
num_channels: channels as usize,
|
num_channels: channels as usize,
|
||||||
marker: PhantomData
|
marker: PhantomData,
|
||||||
|
pending_samples: self.pending_samples.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +175,7 @@ impl Voice {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_pending_samples(&self) -> usize {
|
pub fn get_period(&self) -> usize {
|
||||||
if let Some(ready) = self.update_last_ready() {
|
if let Some(ready) = self.update_last_ready() {
|
||||||
(ready.0 * ready.1) as usize
|
(ready.0 * ready.1) as usize
|
||||||
} else {
|
} else {
|
||||||
|
@ -169,6 +183,11 @@ impl Voice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_pending_samples(&self) -> usize {
|
||||||
|
self.pending_samples.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
/// Attempts to store the most recent ready message into the internal
|
/// Attempts to store the most recent ready message into the internal
|
||||||
/// ref cell, then return the last ready message. If the last ready hasn't
|
/// ref cell, then return the last ready message. If the last ready hasn't
|
||||||
/// been reset with `clear_last_ready`, then it will not be set and the
|
/// been reset with `clear_last_ready`, then it will not be set and the
|
||||||
|
|
Loading…
Reference in New Issue