Skip to content

Instantly share code, notes, and snippets.

@andrewcsmith
Created October 6, 2017 19:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andrewcsmith/68f30935084c38a66275f376aa7c8496 to your computer and use it in GitHub Desktop.
Save andrewcsmith/68f30935084c38a66275f376aa7c8496 to your computer and use it in GitHub Desktop.
Splits a signal into two parts
use std::sync::Arc;
use std::cell::RefCell;
use bounded_spsc_queue::{Producer, Consumer, make};
use sample::Signal;
const SPLIT_BUFFER_SIZE: usize = 512;
#[allow(dead_code)]
pub struct Joint<S>
where
S: Signal + Sized,
{
sig: S,
pipes: [Producer<<S as Signal>::Frame>; 2],
}
#[allow(dead_code)]
pub struct Split<S>
where
S: Signal + Sized,
{
sig: Arc<RefCell<Joint<S>>>,
pipe: Consumer<<S as Signal>::Frame>,
}
impl<S> Joint<S>
where
S: Signal + Sized,
{
/// Adds a value to all pipes
pub fn produce(&mut self) {
let val = self.sig.next();
for pipe in self.pipes.iter_mut() {
pipe.try_push(val);
}
}
}
#[allow(unused_must_use)]
impl<S> Signal for Split<S>
where
S: Signal + Sized,
{
type Frame = S::Frame;
fn next(&mut self) -> Self::Frame {
match self.pipe.try_pop() {
Some(v) => v,
None => {
// Reasonably, we can assume that if this is borrowed then it's the other Split
// that's borrowing it. In that case, we can spin on pop() for as long as is
// necessary to get the value. Not ideal though.
self.sig.try_borrow_mut().and_then(|mut s| Ok(s.produce()));
self.pipe.pop()
}
}
}
}
#[allow(dead_code)]
pub fn split<S: Signal>(s: S) -> (Split<S>, Split<S>) {
let (p1, c1) = make(SPLIT_BUFFER_SIZE);
let (p2, c2) = make(SPLIT_BUFFER_SIZE);
let joint = Joint {
sig: s,
pipes: [p1, p2],
};
let ref_joint = Arc::new(RefCell::new(joint));
let s1 = Split {
sig: ref_joint.clone(),
pipe: c1,
};
let s2 = Split {
sig: ref_joint.clone(),
pipe: c2,
};
(s1, s2)
}
#[cfg(test)]
mod tests {
use super::*;
use sample::{Signal, signal};
#[test]
fn test_split_signal() {
let sig = signal::gen(|| [0.]);
let (mut one, _) = split(sig);
assert_eq!(one.next(), [0.]);
}
#[test]
fn test_split_and_overwrite() {
let mut val = 0.;
let ramp = signal::gen_mut(move || {
val = val + 0.25;
[val]
});
let (mut one, mut two) = split(ramp);
assert_eq!(one.next(), [0.25]);
assert_eq!(one.next(), [0.5]);
assert_eq!(two.next(), [0.25]);
assert_eq!(two.next(), [0.5]);
assert_eq!(two.next(), [0.75]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment