mirror of
https://github.com/RustAudio/rodio
synced 2024-11-10 06:04:16 +00:00
Initial commit
This commit is contained in:
commit
824b4f0041
8 changed files with 149 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
target
|
||||||
|
Cargo.lock
|
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "rodio"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Pierre Krieger <pierre.krieger1708@gmail.com>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cpal = "0.1.1"
|
||||||
|
hound = "1.0.0"
|
||||||
|
lazy_static = "0.1.12"
|
9
examples/basic.rs
Normal file
9
examples/basic.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
extern crate rodio;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let file = std::fs::File::open("examples/beep.wav").unwrap();
|
||||||
|
|
||||||
|
rodio::play_once(file);
|
||||||
|
|
||||||
|
std::thread::sleep_ms(10000);
|
||||||
|
}
|
BIN
examples/beep.wav
Normal file
BIN
examples/beep.wav
Normal file
Binary file not shown.
16
src/decoder/mod.rs
Normal file
16
src/decoder/mod.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use std::io::Read;
|
||||||
|
use cpal::Voice;
|
||||||
|
|
||||||
|
mod wav;
|
||||||
|
|
||||||
|
pub trait Decoder {
|
||||||
|
fn write(&mut self, &mut Voice);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode<R>(data: R) -> Box<Decoder + Send> where R: Read + Send + 'static {
|
||||||
|
if let Ok(decoder) = wav::WavDecoder::new(data) {
|
||||||
|
return Box::new(decoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("Invalid format");
|
||||||
|
}
|
49
src/decoder/wav.rs
Normal file
49
src/decoder/wav.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
use std::io::Read;
|
||||||
|
use super::Decoder;
|
||||||
|
|
||||||
|
use cpal::{self, Voice};
|
||||||
|
use hound::WavReader;
|
||||||
|
use hound::WavSpec;
|
||||||
|
|
||||||
|
pub struct WavDecoder<R> where R: Read {
|
||||||
|
reader: WavReader<R>,
|
||||||
|
spec: WavSpec,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> WavDecoder<R> where R: Read {
|
||||||
|
pub fn new(data: R) -> Result<WavDecoder<R>, ()> {
|
||||||
|
let reader = match WavReader::new(data) {
|
||||||
|
Err(_) => return Err(()),
|
||||||
|
Ok(r) => r
|
||||||
|
};
|
||||||
|
|
||||||
|
let spec = reader.spec();
|
||||||
|
|
||||||
|
Ok(WavDecoder {
|
||||||
|
reader: reader,
|
||||||
|
spec: spec,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R> Decoder for WavDecoder<R> where R: Read {
|
||||||
|
fn write(&mut self, voice: &mut Voice) {
|
||||||
|
let mut samples = self.reader.samples::<i16>();
|
||||||
|
let samples_left = samples.len();
|
||||||
|
if samples_left == 0 { return; }
|
||||||
|
|
||||||
|
// TODO: hack because of a bug in cpal
|
||||||
|
let samples_left = if samples_left > 512 { 512 } else { samples_left };
|
||||||
|
|
||||||
|
let mut buffer: cpal::Buffer<u16> =
|
||||||
|
voice.append_data(self.spec.channels,
|
||||||
|
cpal::SamplesRate(self.spec.sample_rate),
|
||||||
|
samples_left);
|
||||||
|
|
||||||
|
for (dest, src) in buffer.iter_mut().zip(&mut samples) {
|
||||||
|
// TODO: There is a bug in cpal that handles signed samples in the
|
||||||
|
// wrong manner, so we cast it to `u16` for now.
|
||||||
|
*dest = src.unwrap() as u16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
src/engine.rs
Normal file
45
src/engine.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use std::thread;
|
||||||
|
use std::sync::mpsc::{self, Sender, Receiver};
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
use cpal::Voice;
|
||||||
|
use decoder::Decoder;
|
||||||
|
|
||||||
|
pub enum Command {
|
||||||
|
Play(Box<Decoder + Send>)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Engine {
|
||||||
|
commands: Mutex<Sender<Command>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Engine {
|
||||||
|
pub fn new() -> Engine {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
thread::spawn(move || background(rx));
|
||||||
|
Engine { commands: Mutex::new(tx) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play_once(&self, decoder: Box<Decoder + Send>) {
|
||||||
|
let commands = self.commands.lock().unwrap();
|
||||||
|
commands.send(Command::Play(decoder)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn background(rx: Receiver<Command>) {
|
||||||
|
let mut sounds = Vec::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// polling for new sounds
|
||||||
|
if let Ok(command) = rx.try_recv() {
|
||||||
|
match command {
|
||||||
|
Command::Play(decoder) => sounds.push((Voice::new(), decoder)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for &mut (ref mut voice, ref mut decoder) in sounds.iter_mut() {
|
||||||
|
decoder.write(voice);
|
||||||
|
voice.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
src/lib.rs
Normal file
19
src/lib.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
extern crate cpal;
|
||||||
|
extern crate hound;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
mod decoder;
|
||||||
|
mod engine;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref ENGINE: engine::Engine = engine::Engine::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Plays a sound once. There's no way to stop the sound except by exiting the program.
|
||||||
|
pub fn play_once<R>(input: R) where R: Read + Send + 'static {
|
||||||
|
let decoder = decoder::decode(input);
|
||||||
|
ENGINE.play_once(decoder);
|
||||||
|
}
|
Loading…
Reference in a new issue