Skip to content

Commit

Permalink
Merge pull request RustAudio#366 from Ralith/polymorphic-streams
Browse files Browse the repository at this point in the history
Polymorphic streams
  • Loading branch information
mitchmindtree authored Jan 27, 2020
2 parents 5390c01 + 8d471f3 commit ae910e3
Show file tree
Hide file tree
Showing 13 changed files with 181 additions and 82 deletions.
34 changes: 22 additions & 12 deletions examples/beep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,22 @@ fn main() -> Result<(), anyhow::Error> {
.default_output_device()
.expect("failed to find a default output device");
let format = device.default_output_format()?;
let sample_rate = format.sample_rate.0 as f32;
let channels = format.channels as usize;

match format.data_type {
cpal::SampleFormat::F32 => run::<f32>(&device, &format.shape())?,
cpal::SampleFormat::I16 => run::<i16>(&device, &format.shape())?,
cpal::SampleFormat::U16 => run::<u16>(&device, &format.shape())?,
}

Ok(())
}

fn run<T>(device: &cpal::Device, shape: &cpal::Shape) -> Result<(), anyhow::Error>
where
T: cpal::Sample,
{
let sample_rate = shape.sample_rate.0 as f32;
let channels = shape.channels as usize;

// Produce a sinusoid of maximum amplitude.
let mut sample_clock = 0f32;
Expand All @@ -21,26 +35,22 @@ fn main() -> Result<(), anyhow::Error> {

let err_fn = |err| eprintln!("an error occurred on stream: {}", err);

let data_fn = move |data: &mut cpal::Data| match data.sample_format() {
cpal::SampleFormat::F32 => write_data::<f32>(data, channels, &mut next_value),
cpal::SampleFormat::I16 => write_data::<i16>(data, channels, &mut next_value),
cpal::SampleFormat::U16 => write_data::<u16>(data, channels, &mut next_value),
};

let stream = device.build_output_stream(&format, data_fn, err_fn)?;

let stream = device.build_output_stream(
shape,
move |data: &mut [T]| write_data(data, channels, &mut next_value),
err_fn,
)?;
stream.play()?;

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

Ok(())
}

fn write_data<T>(output: &mut cpal::Data, channels: usize, next_sample: &mut dyn FnMut() -> f32)
fn write_data<T>(output: &mut [T], channels: usize, next_sample: &mut dyn FnMut() -> f32)
where
T: cpal::Sample,
{
let output = output.as_slice_mut::<T>().expect("unexpected sample type");
for frame in output.chunks_mut(channels) {
let value: T = cpal::Sample::from::<f32>(&next_sample());
for sample in frame.iter_mut() {
Expand Down
22 changes: 11 additions & 11 deletions examples/feedback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ fn main() -> Result<(), anyhow::Error> {
println!("Using default output device: \"{}\"", output_device.name()?);

// We'll try and use the same format between streams to keep it simple
let mut format = input_device.default_input_format()?;
format.data_type = cpal::SampleFormat::F32;
let shape = input_device.default_input_format()?.shape();

// Create a delay in case the input and output devices aren't synced.
let latency_frames = (LATENCY_MS / 1_000.0) * format.sample_rate.0 as f32;
let latency_samples = latency_frames as usize * format.channels as usize;
let latency_frames = (LATENCY_MS / 1_000.0) * shape.sample_rate.0 as f32;
let latency_samples = latency_frames as usize * shape.channels as usize;

// The buffer to share samples
let ring = RingBuffer::new(latency_samples * 2);
Expand All @@ -47,9 +46,8 @@ fn main() -> Result<(), anyhow::Error> {
producer.push(0.0).unwrap();
}

let input_data_fn = move |data: &cpal::Data| {
let input_data_fn = move |data: &[f32]| {
let mut output_fell_behind = false;
let data = data.as_slice::<f32>().expect("unexpected sample type");
for &sample in data {
if producer.push(sample).is_err() {
output_fell_behind = true;
Expand All @@ -60,9 +58,8 @@ fn main() -> Result<(), anyhow::Error> {
}
};

let output_data_fn = move |data: &mut cpal::Data| {
let output_data_fn = move |data: &mut [f32]| {
let mut input_fell_behind = None;
let data = data.as_slice_mut::<f32>().expect("unexpected sample type");
for sample in data {
*sample = match consumer.pop() {
Ok(s) => s,
Expand All @@ -81,9 +78,12 @@ fn main() -> Result<(), anyhow::Error> {
};

// Build streams.
println!("Attempting to build both streams with `{:?}`.", format);
let input_stream = input_device.build_input_stream(&format, input_data_fn, err_fn)?;
let output_stream = output_device.build_output_stream(&format, output_data_fn, err_fn)?;
println!(
"Attempting to build both streams with f32 samples and `{:?}`.",
shape
);
let input_stream = input_device.build_input_stream(&shape, input_data_fn, err_fn)?;
let output_stream = output_device.build_output_stream(&shape, output_data_fn, err_fn)?;
println!("Successfully built streams.");

// Play the streams.
Expand Down
25 changes: 17 additions & 8 deletions examples/record_wav.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,24 @@ fn main() -> Result<(), anyhow::Error> {
eprintln!("an error occurred on stream: {}", err);
};

let data_fn = move |data: &cpal::Data| match data.sample_format() {
cpal::SampleFormat::F32 => write_input_data::<f32, f32>(data, &writer_2),
cpal::SampleFormat::I16 => write_input_data::<i16, i16>(data, &writer_2),
cpal::SampleFormat::U16 => write_input_data::<u16, i16>(data, &writer_2),
let stream = match format.data_type {
cpal::SampleFormat::F32 => device.build_input_stream(
&format.shape(),
move |data| write_input_data::<f32, f32>(data, &writer_2),
err_fn,
)?,
cpal::SampleFormat::I16 => device.build_input_stream(
&format.shape(),
move |data| write_input_data::<i16, i16>(data, &writer_2),
err_fn,
)?,
cpal::SampleFormat::U16 => device.build_input_stream(
&format.shape(),
move |data| write_input_data::<u16, i16>(data, &writer_2),
err_fn,
)?,
};

let stream = device.build_input_stream(&format, data_fn, err_fn)?;

stream.play()?;

// Let recording go for roughly three seconds.
Expand Down Expand Up @@ -77,12 +87,11 @@ fn wav_spec_from_format(format: &cpal::Format) -> hound::WavSpec {

type WavWriterHandle = Arc<Mutex<Option<hound::WavWriter<BufWriter<File>>>>>;

fn write_input_data<T, U>(input: &cpal::Data, writer: &WavWriterHandle)
fn write_input_data<T, U>(input: &[T], writer: &WavWriterHandle)
where
T: cpal::Sample,
U: cpal::Sample + hound::Sample,
{
let input = input.as_slice::<T>().expect("unexpected sample format");
if let Ok(mut guard) = writer.try_lock() {
if let Some(writer) = guard.as_mut() {
for &sample in input.iter() {
Expand Down
4 changes: 2 additions & 2 deletions src/host/alsa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl DeviceTrait for Device {
Device::default_output_format(self)
}

fn build_input_stream<D, E>(
fn build_input_stream_raw<D, E>(
&self,
format: &Format,
data_callback: D,
Expand All @@ -95,7 +95,7 @@ impl DeviceTrait for Device {
Ok(stream)
}

fn build_output_stream<D, E>(
fn build_output_stream_raw<D, E>(
&self,
format: &Format,
data_callback: D,
Expand Down
8 changes: 4 additions & 4 deletions src/host/asio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl DeviceTrait for Device {
Device::default_output_format(self)
}

fn build_input_stream<D, E>(
fn build_input_stream_raw<D, E>(
&self,
format: &Format,
data_callback: D,
Expand All @@ -91,10 +91,10 @@ impl DeviceTrait for Device {
D: FnMut(&Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
Device::build_input_stream(self, format, data_callback, error_callback)
Device::build_input_stream_raw(self, format, data_callback, error_callback)
}

fn build_output_stream<D, E>(
fn build_output_stream_raw<D, E>(
&self,
format: &Format,
data_callback: D,
Expand All @@ -104,7 +104,7 @@ impl DeviceTrait for Device {
D: FnMut(&mut Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
Device::build_output_stream(self, format, data_callback, error_callback)
Device::build_output_stream_raw(self, format, data_callback, error_callback)
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/host/asio/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl Stream {
}

impl Device {
pub fn build_input_stream<D, E>(
pub fn build_input_stream_raw<D, E>(
&self,
format: &Format,
mut data_callback: D,
Expand Down Expand Up @@ -202,7 +202,7 @@ impl Device {
}

unsupported_format_pair => unreachable!(
"`build_input_stream` should have returned with unsupported \
"`build_input_stream_raw` should have returned with unsupported \
format {:?}",
unsupported_format_pair
),
Expand All @@ -223,7 +223,7 @@ impl Device {
})
}

pub fn build_output_stream<D, E>(
pub fn build_output_stream_raw<D, E>(
&self,
format: &Format,
mut data_callback: D,
Expand Down Expand Up @@ -410,7 +410,7 @@ impl Device {
}

unsupported_format_pair => unreachable!(
"`build_output_stream` should have returned with unsupported \
"`build_output_stream_raw` should have returned with unsupported \
format {:?}",
unsupported_format_pair
),
Expand Down
12 changes: 6 additions & 6 deletions src/host/coreaudio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl DeviceTrait for Device {
Device::default_output_format(self)
}

fn build_input_stream<D, E>(
fn build_input_stream_raw<D, E>(
&self,
format: &Format,
data_callback: D,
Expand All @@ -112,10 +112,10 @@ impl DeviceTrait for Device {
D: FnMut(&Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
Device::build_input_stream(self, format, data_callback, error_callback)
Device::build_input_stream_raw(self, format, data_callback, error_callback)
}

fn build_output_stream<D, E>(
fn build_output_stream_raw<D, E>(
&self,
format: &Format,
data_callback: D,
Expand All @@ -125,7 +125,7 @@ impl DeviceTrait for Device {
D: FnMut(&mut Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
Device::build_output_stream(self, format, data_callback, error_callback)
Device::build_output_stream_raw(self, format, data_callback, error_callback)
}
}

Expand Down Expand Up @@ -467,7 +467,7 @@ fn audio_unit_from_device(device: &Device, input: bool) -> Result<AudioUnit, cor
}

impl Device {
fn build_input_stream<D, E>(
fn build_input_stream_raw<D, E>(
&self,
format: &Format,
mut data_callback: D,
Expand Down Expand Up @@ -655,7 +655,7 @@ impl Device {
}))
}

fn build_output_stream<D, E>(
fn build_output_stream_raw<D, E>(
&self,
format: &Format,
mut data_callback: D,
Expand Down
4 changes: 2 additions & 2 deletions src/host/emscripten/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ impl DeviceTrait for Device {
Device::default_output_format(self)
}

fn build_input_stream<D, E>(
fn build_input_stream_raw<D, E>(
&self,
_format: &Format,
_data_callback: D,
Expand All @@ -161,7 +161,7 @@ impl DeviceTrait for Device {
unimplemented!()
}

fn build_output_stream<D, E>(
fn build_output_stream_raw<D, E>(
&self,
format: &Format,
data_callback: D,
Expand Down
4 changes: 2 additions & 2 deletions src/host/null/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl DeviceTrait for Device {
unimplemented!()
}

fn build_input_stream<D, E>(
fn build_input_stream_raw<D, E>(
&self,
_format: &Format,
_data_callback: D,
Expand All @@ -75,7 +75,7 @@ impl DeviceTrait for Device {
}

/// Create an output stream.
fn build_output_stream<D, E>(
fn build_output_stream_raw<D, E>(
&self,
_format: &Format,
_data_callback: D,
Expand Down
12 changes: 6 additions & 6 deletions src/host/wasapi/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl DeviceTrait for Device {
Device::default_output_format(self)
}

fn build_input_stream<D, E>(
fn build_input_stream_raw<D, E>(
&self,
format: &Format,
data_callback: D,
Expand All @@ -105,15 +105,15 @@ impl DeviceTrait for Device {
D: FnMut(&Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
let stream_inner = self.build_input_stream_inner(format)?;
let stream_inner = self.build_input_stream_raw_inner(format)?;
Ok(Stream::new_input(
stream_inner,
data_callback,
error_callback,
))
}

fn build_output_stream<D, E>(
fn build_output_stream_raw<D, E>(
&self,
format: &Format,
data_callback: D,
Expand All @@ -123,7 +123,7 @@ impl DeviceTrait for Device {
D: FnMut(&mut Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
let stream_inner = self.build_output_stream_inner(format)?;
let stream_inner = self.build_output_stream_raw_inner(format)?;
Ok(Stream::new_output(
stream_inner,
data_callback,
Expand Down Expand Up @@ -610,7 +610,7 @@ impl Device {
}
}

pub(crate) fn build_input_stream_inner(
pub(crate) fn build_input_stream_raw_inner(
&self,
format: &Format,
) -> Result<StreamInner, BuildStreamError> {
Expand Down Expand Up @@ -754,7 +754,7 @@ impl Device {
}
}

pub(crate) fn build_output_stream_inner(
pub(crate) fn build_output_stream_raw_inner(
&self,
format: &Format,
) -> Result<StreamInner, BuildStreamError> {
Expand Down
Loading

0 comments on commit ae910e3

Please sign in to comment.