#![cfg(feature = "distributed")]
use audio_core_bsd::{AudioFrame, AudioNode, PortDescriptor, PortDirection, ProcessContext, SampleFormat};
use audio_graph_bsd::{Graph, GraphConfig, GraphPartition, RingSink, RingSource};
struct Gain {
g: f32,
inp: [PortDescriptor; 1],
out: [PortDescriptor; 1],
}
impl Gain {
fn new(g: f32) -> Self {
Self {
g,
inp: [PortDescriptor::new(PortDirection::Input, 1, SampleFormat::F32)],
out: [PortDescriptor::new(PortDirection::Output, 1, SampleFormat::F32)],
}
}
}
impl AudioNode for Gain {
fn inputs(&self) -> &[PortDescriptor] {
&self.inp
}
fn outputs(&self) -> &[PortDescriptor] {
&self.out
}
fn process(&mut self, _: &mut ProcessContext, i: &[AudioFrame], o: &mut [AudioFrame]) {
let (Some(inp), Some(out)) = (i.first(), o.get_mut(0)) else {
return;
};
let n = inp.samples.len().min(out.samples.len());
for k in 0..n {
out.samples[k] = inp.samples[k] * self.g;
}
}
}
#[test]
fn two_partitions_run_independently_without_panic() {
const N: usize = 64;
let (mut prod_a, cons_a) = rtrb::RingBuffer::<AudioFrame>::new(4);
let (prod_out_a, _cons_out_a) = rtrb::RingBuffer::<AudioFrame>::new(4);
let mut ga = Graph::new();
let sa = ga.add_node(Box::new(RingSource::new(cons_a, 1, 48_000, N)));
let na = ga.add_node(Box::new(Gain::new(0.5)));
let ka = ga.add_node(Box::new(RingSink::new(prod_out_a, 1, 48_000, N)));
ga.link((sa, 0), (na, 0)).unwrap();
ga.link((na, 0), (ka, 0)).unwrap();
let mut pa = GraphPartition::new(ga, vec![]);
pa.compile(GraphConfig::new(N, 48_000, 1)).unwrap();
let (mut prod_b, cons_b) = rtrb::RingBuffer::<AudioFrame>::new(4);
let (prod_out_b, _cons_out_b) = rtrb::RingBuffer::<AudioFrame>::new(4);
let mut gb = Graph::new();
let sb = gb.add_node(Box::new(RingSource::new(cons_b, 1, 48_000, N)));
let nb = gb.add_node(Box::new(Gain::new(2.0)));
let kb = gb.add_node(Box::new(RingSink::new(prod_out_b, 1, 48_000, N)));
gb.link((sb, 0), (nb, 0)).unwrap();
gb.link((nb, 0), (kb, 0)).unwrap();
let mut pb = GraphPartition::new(gb, vec![]);
pb.compile(GraphConfig::new(N, 48_000, 1)).unwrap();
for _ in 0..4 {
let _ = prod_a.push(AudioFrame::from_planar(1, 48_000, vec![0.5; N]));
let _ = prod_b.push(AudioFrame::from_planar(1, 48_000, vec![0.25; N]));
}
let mut ctx = ProcessContext::new(N, 0, 48_000);
for _ in 0..1000 {
pa.process_cycle(&mut ctx).unwrap();
pb.process_cycle(&mut ctx).unwrap();
}
let stash_a = pa.graph().read_input(ka, 0).unwrap();
assert!(stash_a.samples.iter().all(|s| s.is_finite()));
}
#[test]
fn partition_compile_then_process_is_isolated() {
const N: usize = 32;
let (_prod, cons) = rtrb::RingBuffer::<AudioFrame>::new(2);
let mut g = Graph::new();
let s = g.add_node(Box::new(RingSource::new(cons, 1, 48_000, N)));
let n = g.add_node(Box::new(Gain::new(1.0)));
g.link((s, 0), (n, 0)).unwrap();
let mut p = GraphPartition::new(g, vec![]);
p.compile(GraphConfig::new(N, 48_000, 1)).unwrap();
assert_eq!(p.boundary().len(), 0);
let mut ctx = ProcessContext::new(N, 0, 48_000);
p.process_cycle(&mut ctx).unwrap();
assert_eq!(p.graph().node_count(), 2);
}