2014-12-17 08:45:14 +00:00
|
|
|
/*!
|
|
|
|
# How to use cpal
|
|
|
|
|
|
|
|
In order to play a sound, first you need to create a `Voice`.
|
|
|
|
|
|
|
|
```no_run
|
|
|
|
let mut voice = cpal::Voice::new();
|
|
|
|
```
|
|
|
|
|
|
|
|
Then you must send raw samples to it by calling `append_data`.
|
|
|
|
This function takes three parameters: the number of channels, the number of samples
|
|
|
|
that must be played per second, and the number of samples that you have available.
|
|
|
|
|
|
|
|
You can then fill the buffer with the data.
|
|
|
|
|
|
|
|
```no_run
|
|
|
|
# let mut voice = cpal::Voice::new();
|
|
|
|
let mut buffer: cpal::Buffer<f32> = voice.append_data(2, cpal::SamplesRate(44100), 1024);
|
|
|
|
|
|
|
|
// filling the buffer with 0s
|
|
|
|
for e in buffer.iter_mut() {
|
|
|
|
*e = 0.0f32;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
**Important**: the `append_data` function can return a buffer shorter than what you requested.
|
|
|
|
This is the case if the device doesn't have enough space available. **It happens very often**,
|
|
|
|
this is not some obscure situation that can be ignored.
|
|
|
|
|
2014-12-22 13:16:47 +00:00
|
|
|
After you have submitted data for the first time, call `play`:
|
|
|
|
|
|
|
|
```no_run
|
|
|
|
# let mut voice = cpal::Voice::new();
|
|
|
|
voice.play();
|
|
|
|
```
|
|
|
|
|
2014-12-17 08:45:14 +00:00
|
|
|
The audio device of the user will read the buffer that you sent, and play it. If the audio device
|
2014-12-22 13:16:47 +00:00
|
|
|
reaches the end of the data, it will stop playing. You must continuously fill the buffer by
|
2014-12-17 08:45:14 +00:00
|
|
|
calling `append_data` repeatedly if you don't want the audio to stop playing.
|
|
|
|
|
|
|
|
# Native format
|
|
|
|
|
|
|
|
Each `Voice` is bound to a specific number of channels, samples rate, and samples format.
|
|
|
|
If you call `append_data` with values different than these, then cpal will automatically perform
|
|
|
|
a conversion on your data.
|
|
|
|
|
|
|
|
If you have the possibility, you should try to match the format of the voice.
|
|
|
|
|
|
|
|
*/
|
2015-02-27 19:05:24 +00:00
|
|
|
#![feature(box_syntax, core, unsafe_destructor)]
|
2014-12-17 08:13:58 +00:00
|
|
|
#![unstable]
|
2014-12-11 13:22:55 +00:00
|
|
|
|
2014-12-17 07:47:19 +00:00
|
|
|
pub use samples_formats::{SampleFormat, Sample};
|
|
|
|
|
2015-01-05 09:52:59 +00:00
|
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
|
2014-12-15 10:45:38 +00:00
|
|
|
mod conversions;
|
2014-12-17 07:47:19 +00:00
|
|
|
mod samples_formats;
|
2014-12-15 10:45:38 +00:00
|
|
|
|
2015-02-22 13:50:06 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2014-12-16 15:45:45 +00:00
|
|
|
#[path="alsa/mod.rs"]
|
2014-12-17 08:13:58 +00:00
|
|
|
mod cpal_impl;
|
2015-02-22 13:50:06 +00:00
|
|
|
|
2014-12-11 13:22:55 +00:00
|
|
|
#[cfg(windows)]
|
|
|
|
#[path="wasapi/mod.rs"]
|
2014-12-17 08:13:58 +00:00
|
|
|
mod cpal_impl;
|
2014-12-11 16:23:33 +00:00
|
|
|
|
2015-02-22 13:50:06 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
2015-02-28 18:50:29 +00:00
|
|
|
#[path="coreaudio/mod.rs"]
|
2015-02-22 13:50:06 +00:00
|
|
|
mod cpal_impl;
|
|
|
|
|
2015-01-09 15:06:24 +00:00
|
|
|
#[cfg(all(not(windows), not(unix)))]
|
|
|
|
#[path="null/mod.rs"]
|
|
|
|
mod cpal_impl;
|
|
|
|
|
2014-12-17 08:45:14 +00:00
|
|
|
/// Controls a sound output. A typical application has one `Voice` for each sound
|
|
|
|
/// it wants to output.
|
2014-12-17 08:13:58 +00:00
|
|
|
///
|
2014-12-17 08:16:26 +00:00
|
|
|
/// A voice must be periodically filled with new data by calling `append_data`, or the sound
|
2014-12-17 08:13:58 +00:00
|
|
|
/// will stop playing.
|
2014-12-17 08:45:14 +00:00
|
|
|
///
|
|
|
|
/// Each `Voice` is bound to a specific number of channels, samples rate, and samples format,
|
|
|
|
/// which can be retreived by calling `get_channels`, `get_samples_rate` and `get_samples_format`.
|
|
|
|
/// If you call `append_data` with values different than these, then cpal will automatically
|
|
|
|
/// perform a conversion on your data.
|
|
|
|
///
|
|
|
|
/// If you have the possibility, you should try to match the format of the voice.
|
2014-12-17 08:16:26 +00:00
|
|
|
pub struct Voice(cpal_impl::Voice);
|
2014-12-11 16:23:33 +00:00
|
|
|
|
2014-12-11 18:02:04 +00:00
|
|
|
/// Number of channels.
|
|
|
|
pub type ChannelsCount = u16;
|
|
|
|
|
2014-12-15 10:45:38 +00:00
|
|
|
///
|
2015-02-22 13:50:06 +00:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
2014-12-15 10:58:52 +00:00
|
|
|
pub struct SamplesRate(pub u32);
|
2014-12-15 10:45:38 +00:00
|
|
|
|
2014-12-11 17:09:48 +00:00
|
|
|
/// Represents a buffer that must be filled with audio data.
|
|
|
|
///
|
2014-12-17 08:45:14 +00:00
|
|
|
/// You should destroy this object as soon as possible. Data is only committed when it
|
|
|
|
/// is destroyed.
|
2014-12-26 09:39:19 +00:00
|
|
|
#[must_use]
|
2015-02-22 09:31:25 +00:00
|
|
|
pub struct Buffer<'a, T: 'a> {
|
2014-12-15 14:29:59 +00:00
|
|
|
// also contains something, taken by `Drop`
|
|
|
|
target: Option<cpal_impl::Buffer<'a, T>>,
|
2014-12-17 08:45:14 +00:00
|
|
|
|
2014-12-15 14:29:59 +00:00
|
|
|
// if this is non-none, then the data will be written to `conversion.intermediate_buffer`
|
|
|
|
// instead of `target`, and the conversion will be done in buffer's destructor
|
|
|
|
conversion: Option<RequiredConversion<T>>,
|
|
|
|
}
|
|
|
|
|
2014-12-15 10:45:38 +00:00
|
|
|
struct RequiredConversion<T> {
|
|
|
|
intermediate_buffer: Vec<T>,
|
|
|
|
from_sample_rate: SamplesRate,
|
|
|
|
to_sample_rate: SamplesRate,
|
|
|
|
to_format: SampleFormat,
|
|
|
|
from_channels: ChannelsCount,
|
|
|
|
to_channels: ChannelsCount,
|
|
|
|
}
|
2014-12-11 16:23:33 +00:00
|
|
|
|
2014-12-17 08:16:26 +00:00
|
|
|
impl Voice {
|
2014-12-17 08:13:58 +00:00
|
|
|
/// Builds a new channel.
|
2014-12-17 08:16:26 +00:00
|
|
|
pub fn new() -> Voice {
|
|
|
|
let channel = cpal_impl::Voice::new();
|
|
|
|
Voice(channel)
|
2014-12-11 16:23:33 +00:00
|
|
|
}
|
|
|
|
|
2014-12-11 17:09:48 +00:00
|
|
|
/// Returns the number of channels.
|
|
|
|
///
|
2014-12-17 08:45:14 +00:00
|
|
|
/// You can add data with any number of channels, but matching the voice's native format
|
|
|
|
/// will lead to better performances.
|
2014-12-11 18:02:04 +00:00
|
|
|
pub fn get_channels(&self) -> ChannelsCount {
|
2014-12-11 16:23:33 +00:00
|
|
|
self.0.get_channels()
|
|
|
|
}
|
|
|
|
|
2014-12-11 18:07:58 +00:00
|
|
|
/// Returns the number of samples that are played per second.
|
|
|
|
///
|
2014-12-17 08:45:14 +00:00
|
|
|
/// You can add data with any samples rate, but matching the voice's native format
|
|
|
|
/// will lead to better performances.
|
2014-12-15 10:45:38 +00:00
|
|
|
pub fn get_samples_rate(&self) -> SamplesRate {
|
|
|
|
self.0.get_samples_rate()
|
2014-12-11 18:07:58 +00:00
|
|
|
}
|
|
|
|
|
2014-12-17 08:45:14 +00:00
|
|
|
/// Returns the format of the samples that are accepted by the backend.
|
2014-12-11 18:07:58 +00:00
|
|
|
///
|
2014-12-17 08:45:14 +00:00
|
|
|
/// You can add data of any format, but matching the voice's native format
|
|
|
|
/// will lead to better performances.
|
2014-12-11 18:07:58 +00:00
|
|
|
pub fn get_samples_format(&self) -> SampleFormat {
|
|
|
|
self.0.get_samples_format()
|
|
|
|
}
|
|
|
|
|
2014-12-17 08:45:14 +00:00
|
|
|
/// Adds some PCM data to the voice's buffer.
|
2014-12-11 17:09:48 +00:00
|
|
|
///
|
|
|
|
/// This function returns a `Buffer` object that must be filled with the audio data.
|
2014-12-17 08:45:14 +00:00
|
|
|
/// The size of the buffer being returned depends on the current state of the backend
|
|
|
|
/// and can't be known in advance. However it is never greater than `max_elements`.
|
|
|
|
///
|
|
|
|
/// You must fill the buffer *entirely*, so do not set `max_elements` to a value greater
|
|
|
|
/// than the amount of data available to you.
|
|
|
|
///
|
|
|
|
/// Channels are interleaved. For example if you have two channels, you must write
|
|
|
|
/// the first sample of the first channel, then the first sample of the second channel,
|
|
|
|
/// then the second sample of the first channel, then the second sample of the second
|
|
|
|
/// channel, etc.
|
|
|
|
///
|
|
|
|
/// ## Parameters
|
|
|
|
///
|
|
|
|
/// * `channels`: number of channels (1 for mono, 2 for stereo, etc.)
|
|
|
|
/// * `samples_rate`: number of samples that must be played by second for each channel
|
|
|
|
/// * `max_elements`: maximum size of the returned buffer
|
2014-12-15 15:26:55 +00:00
|
|
|
///
|
|
|
|
/// ## Panic
|
|
|
|
///
|
|
|
|
/// Panics if `max_elements` is 0 or is not a multiple of `channels`.
|
|
|
|
///
|
2014-12-15 10:45:38 +00:00
|
|
|
pub fn append_data<'a, T>(&'a mut self, channels: ChannelsCount,
|
2015-01-09 20:25:51 +00:00
|
|
|
samples_rate: SamplesRate, max_elements: usize)
|
2014-12-15 10:45:38 +00:00
|
|
|
-> Buffer<'a, T> where T: Sample + Clone
|
|
|
|
{
|
2014-12-15 15:26:55 +00:00
|
|
|
assert!(max_elements != 0);
|
2015-01-09 20:25:51 +00:00
|
|
|
assert!(max_elements % channels as usize == 0);
|
2014-12-15 15:26:55 +00:00
|
|
|
|
2014-12-15 10:45:38 +00:00
|
|
|
let target_samples_rate = self.0.get_samples_rate();
|
|
|
|
let target_channels = self.0.get_channels();
|
|
|
|
|
|
|
|
let source_samples_format = Sample::get_format(None::<T>);
|
|
|
|
let target_samples_format = self.0.get_samples_format();
|
|
|
|
|
|
|
|
// if we need to convert the incoming data
|
|
|
|
if samples_rate != target_samples_rate || channels != target_channels ||
|
|
|
|
source_samples_format != target_samples_format
|
|
|
|
{
|
2015-01-09 20:25:51 +00:00
|
|
|
let max_elements = max_elements * target_channels as usize / channels as usize;
|
|
|
|
let max_elements = max_elements * target_samples_rate.0 as usize /
|
|
|
|
samples_rate.0 as usize;
|
2014-12-15 15:40:55 +00:00
|
|
|
|
2014-12-15 15:26:55 +00:00
|
|
|
let mut target_buffer = self.0.append_data(max_elements);
|
2014-12-15 10:45:38 +00:00
|
|
|
|
|
|
|
// computing the length of the intermediary buffer
|
|
|
|
let intermediate_buffer_length = target_buffer.get_buffer().len();
|
2015-01-09 20:25:51 +00:00
|
|
|
let intermediate_buffer_length = intermediate_buffer_length * channels as usize /
|
|
|
|
target_channels as usize;
|
|
|
|
let intermediate_buffer_length = intermediate_buffer_length * samples_rate.0 as usize /
|
|
|
|
target_samples_rate.0 as usize;
|
2015-01-05 09:52:59 +00:00
|
|
|
let intermediate_buffer = std::iter::repeat(unsafe { std::mem::uninitialized() })
|
|
|
|
.take(intermediate_buffer_length).collect();
|
2014-12-15 10:45:38 +00:00
|
|
|
|
2014-12-15 14:29:59 +00:00
|
|
|
Buffer {
|
|
|
|
target: Some(target_buffer),
|
|
|
|
conversion: Some(RequiredConversion {
|
2014-12-15 10:45:38 +00:00
|
|
|
intermediate_buffer: intermediate_buffer,
|
|
|
|
from_sample_rate: samples_rate,
|
|
|
|
to_sample_rate: target_samples_rate,
|
|
|
|
to_format: target_samples_format,
|
|
|
|
from_channels: channels,
|
|
|
|
to_channels: target_channels,
|
2014-12-15 14:29:59 +00:00
|
|
|
}),
|
|
|
|
}
|
2014-12-15 10:45:38 +00:00
|
|
|
|
|
|
|
} else {
|
2014-12-15 14:29:59 +00:00
|
|
|
Buffer {
|
2014-12-15 15:26:55 +00:00
|
|
|
target: Some(self.0.append_data(max_elements)),
|
2014-12-15 14:29:59 +00:00
|
|
|
conversion: None,
|
|
|
|
}
|
2014-12-15 10:45:38 +00:00
|
|
|
}
|
2014-12-11 16:23:33 +00:00
|
|
|
}
|
2014-12-22 13:16:47 +00:00
|
|
|
|
|
|
|
/// Sends a command to the audio device that it should start playing.
|
|
|
|
///
|
|
|
|
/// Has no effect is the voice was already playing.
|
|
|
|
///
|
|
|
|
/// Only call this after you have submitted some data, otherwise you may hear
|
|
|
|
/// some glitches.
|
|
|
|
pub fn play(&mut self) {
|
|
|
|
self.0.play()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends a command to the audio device that it should stop playing.
|
|
|
|
///
|
|
|
|
/// Has no effect is the voice was already paused.
|
|
|
|
///
|
|
|
|
/// If you call `play` afterwards, the playback will resume exactly where it was.
|
|
|
|
pub fn pause(&mut self) {
|
|
|
|
self.0.pause()
|
|
|
|
}
|
2014-12-11 16:23:33 +00:00
|
|
|
}
|
|
|
|
|
2015-01-05 09:52:59 +00:00
|
|
|
impl<'a, T> Deref for Buffer<'a, T> {
|
|
|
|
type Target = [T];
|
|
|
|
|
2014-12-15 15:32:13 +00:00
|
|
|
fn deref(&self) -> &[T] {
|
|
|
|
panic!("It is forbidden to read from the audio buffer");
|
2014-12-11 16:23:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-05 09:52:59 +00:00
|
|
|
impl<'a, T> DerefMut for Buffer<'a, T> {
|
2014-12-15 15:32:13 +00:00
|
|
|
fn deref_mut(&mut self) -> &mut [T] {
|
2014-12-15 15:40:55 +00:00
|
|
|
if let Some(ref mut conversion) = self.conversion {
|
|
|
|
conversion.intermediate_buffer.as_mut_slice()
|
|
|
|
} else {
|
|
|
|
self.target.as_mut().unwrap().get_buffer()
|
|
|
|
}
|
2014-12-15 10:45:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[unsafe_destructor]
|
|
|
|
impl<'a, T> Drop for Buffer<'a, T> where T: Sample {
|
|
|
|
fn drop(&mut self) {
|
2014-12-15 14:29:59 +00:00
|
|
|
if let Some(conversion) = self.conversion.take() {
|
2014-12-15 10:45:38 +00:00
|
|
|
let buffer = conversion.intermediate_buffer;
|
|
|
|
|
|
|
|
let buffer = if conversion.from_channels != conversion.to_channels {
|
|
|
|
conversions::convert_channels(buffer.as_slice(), conversion.from_channels,
|
|
|
|
conversion.to_channels)
|
|
|
|
} else {
|
|
|
|
buffer
|
|
|
|
};
|
|
|
|
|
|
|
|
let buffer = if conversion.from_sample_rate != conversion.to_sample_rate {
|
|
|
|
conversions::convert_samples_rate(buffer.as_slice(), conversion.from_sample_rate,
|
2014-12-22 15:31:37 +00:00
|
|
|
conversion.to_sample_rate,
|
|
|
|
conversion.to_channels)
|
2014-12-15 10:45:38 +00:00
|
|
|
} else {
|
|
|
|
buffer
|
|
|
|
};
|
|
|
|
|
2014-12-15 14:29:59 +00:00
|
|
|
let output = self.target.as_mut().unwrap().get_buffer();
|
2014-12-15 10:45:38 +00:00
|
|
|
assert!(buffer.len() == output.len(), "Buffers length mismatch: {} vs {}", buffer.len(), output.len());
|
2014-12-17 07:39:00 +00:00
|
|
|
|
|
|
|
macro_rules! write_to_buf(
|
|
|
|
($buf:expr, $output:expr, $ty:ty) => ({
|
2014-12-17 07:53:09 +00:00
|
|
|
use std::borrow::Cow;
|
|
|
|
|
2014-12-17 07:39:00 +00:00
|
|
|
let output: &mut [$ty] = unsafe { std::mem::transmute($output) };
|
2014-12-17 07:53:09 +00:00
|
|
|
|
|
|
|
match $buf {
|
|
|
|
Cow::Borrowed(buf) => {
|
|
|
|
for (i, o) in buf.iter().zip(output.iter_mut()) {
|
|
|
|
*o = *i;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Cow::Owned(buf) => {
|
|
|
|
for (i, o) in buf.into_iter().zip(output.iter_mut()) {
|
|
|
|
*o = i;
|
|
|
|
}
|
|
|
|
}
|
2014-12-17 07:39:00 +00:00
|
|
|
}
|
|
|
|
})
|
2014-12-20 17:55:44 +00:00
|
|
|
);
|
2014-12-17 07:39:00 +00:00
|
|
|
|
|
|
|
match conversion.to_format {
|
|
|
|
SampleFormat::I16 => {
|
2014-12-17 07:47:19 +00:00
|
|
|
let buffer = Sample::to_vec_i16(buffer.as_slice());
|
|
|
|
write_to_buf!(buffer, output, i16);
|
2014-12-17 07:39:00 +00:00
|
|
|
},
|
|
|
|
SampleFormat::U16 => {
|
|
|
|
let buffer = Sample::to_vec_u16(buffer.as_slice());
|
|
|
|
write_to_buf!(buffer, output, u16);
|
|
|
|
},
|
2014-12-17 07:47:19 +00:00
|
|
|
SampleFormat::F32 => {
|
|
|
|
let buffer = Sample::to_vec_f32(buffer.as_slice());
|
|
|
|
write_to_buf!(buffer, output, f32);
|
|
|
|
},
|
2014-12-15 10:45:38 +00:00
|
|
|
}
|
|
|
|
}
|
2014-12-15 14:29:59 +00:00
|
|
|
|
2014-12-15 15:32:13 +00:00
|
|
|
self.target.take().unwrap().finish();
|
2014-12-11 16:23:33 +00:00
|
|
|
}
|
|
|
|
}
|