Skip to content

Commit

Permalink
Refactor to remove channels
Browse files Browse the repository at this point in the history
  • Loading branch information
bennetthardwick committed Apr 28, 2020
1 parent dab2d40 commit 5d0e7b9
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 133 deletions.
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ keywords = [ "audio", "dsp", "graph" ]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

# [profile.release]
# debug = true

[dependencies]
sample = "0.10.0"
bufferpool = "0.1.6"
Expand All @@ -25,3 +28,7 @@ crossbeam = "0.7"

[badges]
travis-ci = { repository = "https://github.com/bennetthardwick/audio-graph" }

[[example]]
name = "counting-node-bench"
path = "benches/counting-node.rs"
136 changes: 136 additions & 0 deletions benches/counting-node.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#[macro_use]
extern crate lazy_static;

use std::cell::RefCell;
use std::rc::Rc;

use audiograph;

const BUFFER_SIZE: usize = 1024 * 1024;

lazy_static! {
static ref TEST_DATA: Vec<f32> = {
let mut test: Vec<f32> = vec![0.; BUFFER_SIZE];
for (index, value) in test.iter_mut().enumerate() {
*value = index as f32;
}
test
};
}

fn main() {
#[derive(Debug)]
struct CountingRoute {
current: usize,
}

impl audiograph::Route<f32> for CountingRoute {
fn process(
&mut self,
_input: &[audiograph::BufferPoolReference<f32>],
output: &mut [audiograph::BufferPoolReference<f32>],
_frames: usize,
) {
let current = self.current;
for (index, sample) in output[0].as_mut().iter_mut().enumerate() {
*sample = (current + index) as f32;
}

self.current += output[0].as_ref().len();
}
}

#[derive(Debug)]
struct OutputRoute {
buffer: Rc<RefCell<Vec<f32>>>,
offset: usize,
}

impl audiograph::Route<f32> for OutputRoute {
fn process(
&mut self,
input: &[audiograph::BufferPoolReference<f32>],
_output: &mut [audiograph::BufferPoolReference<f32>],
_frames: usize,
) {
let mut buffer = self.buffer.borrow_mut();
for (input, output) in input[0]
.as_ref()
.iter()
.zip(buffer[self.offset..].iter_mut())
{
*output = *input;
}

self.offset += input[0].as_ref().len();
}
}

enum Routes {
Counting(CountingRoute),
Output(OutputRoute),
}

impl audiograph::Route<f32> for Routes {
fn process(
&mut self,
input: &[audiograph::BufferPoolReference<f32>],
output: &mut [audiograph::BufferPoolReference<f32>],
frames: usize,
) {
match self {
Routes::Counting(route) => route.process(input, output, frames),
Routes::Output(route) => route.process(input, output, frames),
}
}
}

#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
struct Id(u32);

impl audiograph::NodeId for Id {
fn generate_node_id() -> Self {
Id(0)
}
}

let test: Vec<f32> = TEST_DATA.iter().cloned().collect();

let iters = 10000;

for _ in 0..iters {
let buffer: Vec<f32> = vec![0.; BUFFER_SIZE];
let buffer = Rc::new(RefCell::new(buffer));

let output_id = Id(1);

let buffer_size = 1024;
let count = BUFFER_SIZE / buffer_size;

let mut graph = audiograph::RouteGraph::with_nodes(
vec![
audiograph::Node::new(
1,
Routes::Counting(CountingRoute { current: 0 }),
vec![audiograph::Connection::new(output_id, 1.)],
),
audiograph::Node::with_id(
output_id,
1,
Routes::Output(OutputRoute {
buffer: Rc::clone(&buffer),
offset: 0,
}),
vec![],
),
],
buffer_size as usize,
);

for _ in 0..count {
graph.process(buffer_size as usize);
}

assert_eq!(*buffer.borrow(), test);
}
}
97 changes: 60 additions & 37 deletions examples/pass-through.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,24 @@ struct InputRoute {
returner: Sender<Vec<&'static [Sample]>>,
}

struct Context<'a> {
pub(crate) in_l_port: &'a jack::Port<jack::AudioIn>,
pub(crate) in_r_port: &'a jack::Port<jack::AudioIn>,

pub(crate) out_l_port: &'a mut jack::Port<jack::AudioOut>,
pub(crate) out_r_port: &'a mut jack::Port<jack::AudioOut>,

pub(crate) ps: &'a jack::ProcessScope,
}

// Implement route for the InputRoute
impl Route<Sample> for InputRoute {
impl Route<Sample, Context<'_>> for InputRoute {
fn process(
&mut self,
_input: &[BufferPoolReference<Sample>],
output: &mut [BufferPoolReference<Sample>],
frames: usize,
context: &mut Context,
) {
if let Some(data) = self.input.try_iter().last() {
for (output_stream, input_stream) in output.iter_mut().zip(data.iter()) {
Expand Down Expand Up @@ -62,12 +73,13 @@ struct OutputRoute {
returner: Sender<Vec<&'static mut [Sample]>>,
}

impl Route<Sample> for OutputRoute {
impl Route<Sample, Context<'_>> for OutputRoute {
fn process(
&mut self,
input: &[BufferPoolReference<Sample>],
_output: &mut [BufferPoolReference<Sample>],
frames: usize,
context: &mut Context,
) {
if let Some(mut data) = self.output.try_iter().last() {
for (output_stream, input_stream) in data.iter_mut().zip(input.iter()) {
Expand All @@ -88,7 +100,7 @@ impl Route<Sample> for OutputRoute {
}
}

// RouteGraph also requires that each node have a unique id.
// RouteGraph also requires that each node have a unique id.[email protected]:bennetthardwick/audio-graph.git
// What Id you use is completely up to you, in this example I usea
// a library called uuid.
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
Expand All @@ -110,16 +122,17 @@ enum Routes {
}

// Likewise, implement Route<Sample> for the Routes enum.
impl Route<Sample> for Routes {
impl<'a> Route<Sample, Context<'a>> for Routes {
fn process(
&mut self,
input: &[BufferPoolReference<Sample>],
output: &mut [BufferPoolReference<Sample>],
frames: usize,
context: &mut Context,
) {
match self {
Routes::Input(route) => route.process(input, output, frames),
Routes::Output(route) => route.process(input, output, frames),
Routes::Input(route) => route.process(input, output, frames, context),
Routes::Output(route) => route.process(input, output, frames, context),
}
}
}
Expand Down Expand Up @@ -151,7 +164,7 @@ fn main() {
// Create the Node to host the route. Nodes have a little bit of extra information
// that is used with the routing of the graph, such as the number of channels it has
// and the other nodes that it's connected to.
let output_node: Node<Id, Sample, Routes> = Node::with_id(
let output_node: Node<Id, Sample, Routes, _> = Node::with_id(
output_id,
channels,
Routes::Output(OutputRoute {
Expand Down Expand Up @@ -196,38 +209,48 @@ fn main() {
// Create the Jack callback. This function is called for every buffer that is requested from
// Jack. It's responsibility is to send the slices to the input and output routes and then
// process the graph.
//

let process = jack::ClosureProcessHandler::new(
move |_: &jack::Client, ps: &jack::ProcessScope| -> jack::Control {
let in_l = in_l_port.as_slice(ps);
let in_r = in_r_port.as_slice(ps);

let out_l = out_l_port.as_mut_slice(ps);
let out_r = out_r_port.as_mut_slice(ps);

unsafe {
if let Some(mut in_vec) = return_input_recv.try_iter().last() {
in_vec.clear();
in_vec.push(std::slice::from_raw_parts(in_l.as_ptr(), in_l.len()));
in_vec.push(std::slice::from_raw_parts(in_r.as_ptr(), in_r.len()));
input_send.try_send(in_vec).unwrap();
}

if let Some(mut out_vec) = return_output_recv.try_iter().last() {
out_vec.clear();
out_vec.push(std::slice::from_raw_parts_mut(
out_l.as_mut_ptr(),
out_l.len(),
));
out_vec.push(std::slice::from_raw_parts_mut(
out_r.as_mut_ptr(),
out_r.len(),
));
output_send.try_send(out_vec).unwrap();
}
}

// Process the graph
graph.process(in_l.len().min(out_l.len()));
let frames = ps.n_frames();

let mut context = Context {
out_r_port: &mut out_r_port,
out_l_port: &mut out_l_port,
in_l_port: &in_l_port,
in_r_port: &in_r_port,
ps,
};

graph.process(frames as usize, &mut context);

// drop(context);

// unsafe {
// if let Some(mut in_vec) = return_input_recv.try_iter().last() {
// in_vec.clear();
// in_vec.push(std::slice::from_raw_parts(in_l.as_ptr(), in_l.len()));
// in_vec.push(std::slice::from_raw_parts(in_r.as_ptr(), in_r.len()));
// input_send.try_send(in_vec).unwrap();
// }

// if let Some(mut out_vec) = return_output_recv.try_iter().last() {
// out_vec.clear();
// out_vec.push(std::slice::from_raw_parts_mut(
// out_l.as_mut_ptr(),
// out_l.len(),
// ));
// out_vec.push(std::slice::from_raw_parts_mut(
// out_r.as_mut_ptr(),
// out_r.len(),
// ));
// output_send.try_send(out_vec).unwrap();
// }
// }

// // Process the graph
// graph.process(in_l.len().min(out_l.len()), &mut context);

jack::Control::Continue
},
Expand Down
26 changes: 14 additions & 12 deletions src/graph/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,32 @@ use super::{Node, NodeId, Route, RouteGraph};
use sample::Sample;
use std::hash::Hash;

pub struct RouteGraphBuilder<Id, S, R>
pub struct RouteGraphBuilder<Id, S, R, C>
where
Id: NodeId + Eq,
S: Sample + Default,
R: Route<S>,
R: Route<S, C>,
{
nodes: Vec<Node<Id, S, R>>,
nodes: Vec<Node<Id, S, R, C>>,
buffer_size: usize,
__context: std::marker::PhantomData<*const C>,
}

impl<Id, S, R> RouteGraphBuilder<Id, S, R>
impl<Id, S, R, C> RouteGraphBuilder<Id, S, R, C>
where
Id: Eq + Hash + Copy + NodeId,
S: Sample + Default,
R: Route<S>,
R: Route<S, C>,
{
pub fn new() -> RouteGraphBuilder<Id, S, R> {
pub fn new() -> RouteGraphBuilder<Id, S, R, C> {
RouteGraphBuilder {
nodes: vec![],
buffer_size: 1024,
__context: std::marker::PhantomData::default(),
}
}

pub fn with_node(mut self, node: Node<Id, S, R>) -> Self {
pub fn with_node(mut self, node: Node<Id, S, R, C>) -> Self {
self.nodes.push(node);
self
}
Expand All @@ -35,23 +37,23 @@ where
self
}

pub fn with_nodes(mut self, mut nodes: Vec<Node<Id, S, R>>) -> Self {
pub fn with_nodes(mut self, mut nodes: Vec<Node<Id, S, R, C>>) -> Self {
self.nodes.extend(nodes.drain(..));
self
}

pub fn build(self) -> RouteGraph<Id, S, R> {
pub fn build(self) -> RouteGraph<Id, S, R, C> {
RouteGraph::with_nodes(self.nodes, self.buffer_size)
}
}

impl<Id, S, R> Default for RouteGraphBuilder<Id, S, R>
impl<Id, S, R, C> Default for RouteGraphBuilder<Id, S, R, C>
where
Id: Eq + Hash + Copy + NodeId,
S: Sample + Default,
R: Route<S>,
R: Route<S, C>,
{
fn default() -> RouteGraphBuilder<Id, S, R> {
fn default() -> RouteGraphBuilder<Id, S, R, C> {
RouteGraphBuilder::new()
}
}
Loading

0 comments on commit 5d0e7b9

Please sign in to comment.