-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
dab2d40
commit 5d0e7b9
Showing
7 changed files
with
318 additions
and
133 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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()) { | ||
|
@@ -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()) { | ||
|
@@ -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)] | ||
|
@@ -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), | ||
} | ||
} | ||
} | ||
|
@@ -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 { | ||
|
@@ -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 | ||
}, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.