Skip to content

Commit

Permalink
feat: BstreamController
Browse files Browse the repository at this point in the history
  • Loading branch information
mbillingr committed Jul 19, 2018
1 parent f2e5f63 commit 2848c6f
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 30 deletions.
24 changes: 16 additions & 8 deletions src/bmixer.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::time::Duration;

use rodio::{Sample, Source};

use bformat::{Bformat, Bweights};
use bstream::Bstream;
use bstream::{self, Bstream, BstreamController};

pub fn bmixer(sample_rate: u32) -> (BstreamMixer, Arc<BmixerController>) {
let controller = Arc::new(BmixerController {
Expand Down Expand Up @@ -54,7 +54,10 @@ impl Iterator for BstreamMixer {

fn next(&mut self) -> Option<Self::Item> {
if self.controller.has_pending.load(Ordering::SeqCst) {
let mut pending = self.controller.pending_streams.lock().expect("Cannot lock pending streams");
let mut pending = self.controller
.pending_streams
.lock()
.expect("Cannot lock pending streams");
self.active_streams.extend(pending.drain(..));
self.controller.has_pending.store(false, Ordering::SeqCst);
}
Expand Down Expand Up @@ -85,15 +88,20 @@ pub struct BmixerController {
}

impl BmixerController {
pub fn play<I>(&self, input: I, pos: [f32; 3])
pub fn play<I>(&self, input: I, pos: [f32; 3]) -> Arc<BstreamController>
where
I: Source<Item = f32> + Send + 'static
I: Source<Item = f32> + Send + 'static,
{
assert_eq!(input.channels(), 1);

let bstream = Bstream::new(input, pos);
let (bstream, sound_ctl) = bstream::bstream(input, pos);

self.pending_streams.lock().expect("Cannot lock pending streams").push(bstream);
self.pending_streams
.lock()
.expect("Cannot lock pending streams")
.push(bstream);
self.has_pending.store(true, Ordering::SeqCst);

sound_ctl
}
}
}
86 changes: 74 additions & 12 deletions src/bstream.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::time::Duration;

use rodio::Source;

use bformat::{Bformat, Bweights};

pub fn bstream<I: Source<Item = f32> + Send + 'static>(
source: I,
pos: [f32; 3],
) -> (Bstream, Arc<BstreamController>) {
let controller = Arc::new(BstreamController {
commands: Mutex::new(Vec::new()),
pending_commands: AtomicBool::new(false),
stopped: AtomicBool::new(false),
});

let stream = Bstream {
input: Box::new(source),
bweights: Bweights::from_position(pos),
controller: controller.clone(),
};

(stream, controller)
}

pub struct Bstream {
input: Box<Source<Item = f32> + Send>,
bweights: Bweights,
}

impl Bstream {
pub fn new<I: Source<Item = f32> + Send + 'static>(source: I, pos: [f32; 3]) -> Self {
Bstream {
input: Box::new(source),
bweights: Bweights::from_position(pos),
}
}
controller: Arc<BstreamController>,
}

impl Source for Bstream {
Expand Down Expand Up @@ -46,7 +58,57 @@ impl Iterator for Bstream {
type Item = Bformat;

fn next(&mut self) -> Option<Self::Item> {
let x = self.input.next()?;
Some(self.bweights.scale(x))
if self.controller.pending_commands.load(Ordering::SeqCst) {
let mut commands = self.controller.commands.lock().unwrap();
let mut new_pos = None;

for cmd in commands.drain(..) {
match cmd {
Command::SetPos(p) => new_pos = Some(p),
Command::Stop => {
self.controller.stopped.store(true, Ordering::SeqCst);
return None;
}
}
}

if let Some(pos) = new_pos {
self.bweights = Bweights::from_position(pos);
}

self.controller
.pending_commands
.store(false, Ordering::SeqCst);
}
match self.input.next() {
Some(x) => Some(self.bweights.scale(x)),
None => {
self.controller.stopped.store(true, Ordering::SeqCst);
None
}
}
}
}

enum Command {
SetPos([f32; 3]),
Stop,
}

pub struct BstreamController {
commands: Mutex<Vec<Command>>,
pending_commands: AtomicBool,
stopped: AtomicBool,
}

impl BstreamController {
pub fn set_position(&self, pos: [f32; 3]) {
self.commands.lock().unwrap().push(Command::SetPos(pos));
self.pending_commands.store(true, Ordering::SeqCst);
}

pub fn stop(&self) {
self.commands.lock().unwrap().push(Command::Stop);
self.pending_commands.store(true, Ordering::SeqCst);
}
}
22 changes: 12 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ extern crate cpal;
pub extern crate rodio;

mod bformat;
mod bstream;
mod bmixer;
mod bstream;
mod renderer;

use std::sync::Arc;
Expand Down Expand Up @@ -37,7 +37,7 @@ impl AmbisonicBuilder {
}
}

pub fn build(self) -> Engine {
pub fn build(self) -> Ambisonic {
let device = self.device
.unwrap_or_else(|| rodio::default_output_device().unwrap());
let sink = rodio::Sink::new(&device);
Expand All @@ -47,14 +47,11 @@ impl AmbisonicBuilder {

sink.append(output);

Engine {
sink,
controller,
}
Ambisonic { sink, controller }
}
}

pub struct Engine {
pub struct Ambisonic {
sink: rodio::Sink,
controller: Arc<BmixerController>,
}
Expand All @@ -70,13 +67,18 @@ mod tests {
let engine = AmbisonicBuilder::new().build();

let source = rodio::source::SineWave::new(440);
engine.controller.play(source, [1.0, 0.0, 0.0]);
let first = engine.controller.play(source, [1.0, 0.0, 0.0]);

sleep(Duration::from_millis(1000));

let source = rodio::source::SineWave::new(330);
engine.controller.play(source, [-1.0, 0.0, 0.0]);
let second = engine.controller.play(source, [-1.0, 0.0, 0.0]);

sleep(Duration::from_millis(2000));
sleep(Duration::from_millis(1000));

first.stop();
second.set_position([0.0, 1.0, 0.0]);

sleep(Duration::from_millis(1000));
}
}

0 comments on commit 2848c6f

Please sign in to comment.