This commit is contained in:
2026-04-11 10:03:22 +02:00
parent 81cac2f239
commit 87921968b4
23 changed files with 1115 additions and 663 deletions

View File

@ -2,11 +2,8 @@ use num::Zero;
use oxydsp_flowgraph::BlockIO;
use oxydsp_flowgraph::block::Block;
use oxydsp_flowgraph::block::BlockResult;
use oxydsp_flowgraph::block::SyncBlock;
use oxydsp_flowgraph::io::In;
use oxydsp_flowgraph::io::Out;
use oxydsp_flowgraph::io::PopIterable;
use oxydsp_flowgraph::sync_block;
use std::iter::Sum;
use std::ops::Add;
use std::ops::Mul;
@ -57,7 +54,7 @@ where
{
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
self.output.push_iter(self.input.pop_iter().map(|x| (self.filter.next(x.0), x.1).into()));
self.output.push_iter(self.input.iter().map(|x| (self.filter.next(x.0), x.1).into()));
BlockResult::Ok
}
}

View File

@ -47,14 +47,14 @@ impl<T: 'static + std::ops::Mul<Output = T> + std::iter::Sum + std::clone::Clone
{
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
let reader = self.input.read();
let writer = self.output.write();
let mut reader = self.input.iter();
let mut writer = self.output.write_push();
for _ in 0..writer.len()
{
if self.remaining == 0
{
if let Some(input) = reader.pop()
if let Some(input) = reader.next()
{
let (data, tag) = input.into();
let _ = writer.push((self.pulse_shaper.next(data), tag).into());

View File

@ -1,12 +1,11 @@
use std::fmt::Debug;
use num::Complex;
use num::Float;
use oxydsp_flowgraph::BlockIO;
use oxydsp_flowgraph::block::Block;
use oxydsp_flowgraph::block::SyncBlock;
use oxydsp_flowgraph::io::In;
use oxydsp_flowgraph::io::Out;
use oxydsp_flowgraph::io::PopIterable;
use oxydsp_flowgraph::sync_block;
use rustfft::FftNum;
use crate::filtering::fir::Fir;
@ -62,7 +61,7 @@ where
{
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
self.output.push_iter(self.input.pop_iter().map(|input| {
self.output.push_iter(self.input.iter().map(|input| {
let (data, tag) = input.into();
// Mix
let lo_sample = self.local_oscillator.next().unwrap();

View File

@ -4,15 +4,11 @@ use std::ops::Mul;
use oxydsp_flowgraph::BlockIO;
use oxydsp_flowgraph::block::Block;
use oxydsp_flowgraph::block::BlockResult;
use oxydsp_flowgraph::block::SyncBlock;
use oxydsp_flowgraph::io::In;
use oxydsp_flowgraph::io::Out;
use oxydsp_flowgraph::io::PopIterable;
use oxydsp_flowgraph::sync_block;
use oxydsp_flowgraph::tag::TagMergable;
use oxydsp_flowgraph::tag::Tag;
#[derive(BlockIO)]
#[sync_block]
pub struct Adder<Ia, Ib, O>
where
Ia: Add<Ib, Output = O> + 'static,
@ -49,35 +45,26 @@ where
}
}
impl<'view, Ia, Ib, O> SyncBlock<'view> for Adder<Ia, Ib, O>
impl<Ia, Ib, O> Block for Adder<Ia, Ib, O>
where
Ia: Add<Ib, Output = O> + 'static,
Ib: 'static,
O: 'static,
{
fn sync_work(_state: Self::StateView, input: Self::Input) -> Option<Self::Output>
fn work(&mut self) -> BlockResult
{
Some(input.0 + input.1)
self.output.push_iter(
self.input_a
.iter()
.zip(self.input_b.iter())
.map(|(x, y)| {
(x.0 + y.0, Tag::from_tag_opts(&[&x.1, &y.1])).into()
})
);
BlockResult::Ok
}
}
// impl<Ia, Ib, O> Block for Adder<Ia, Ib, O>
// where
// Ia: Add<Ib, Output = O> + 'static,
// Ib: 'static,
// O: 'static,
// {
// fn work(&mut self) -> BlockResult
// {
// self.output.push_iter(
// (&mut self.input_a, &mut self.input_b)
// .pop_iter()
// .map(|(a, b)| (a.0 + b.0, a.1.merge(&b.1))),
// );
// BlockResult::Ok
// }
// }
#[derive(BlockIO)]
pub struct Multiplier<Ia, Ib, O>
where
@ -124,9 +111,12 @@ where
fn work(&mut self) -> BlockResult
{
self.output.push_iter(
(&mut self.input_a, &mut self.input_b)
.pop_iter()
.map(|(a, b)| (a.0 * b.0, a.1.merge(&b.1)).into()),
self.input_a
.iter()
.zip(self.input_b.iter())
.map(|(x, y)| {
(x.0 * y.0, Tag::from_tag_opts(&[&x.1, &y.1])).into()
})
);
BlockResult::Ok
}

View File

@ -6,7 +6,6 @@ use oxydsp_flowgraph::block::Block;
use oxydsp_flowgraph::block::BlockResult;
use oxydsp_flowgraph::io::In;
use oxydsp_flowgraph::io::Out;
use oxydsp_flowgraph::io::PopIterable;
use oxydsp_flowgraph::io::stream;
#[derive(BlockIO)]
@ -81,7 +80,7 @@ impl<T: Float + From<f32> + 'static> Block for Nco<T>
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
self.output
.push_iter(&mut self.frequency.pop_iter().map(|f| {
.push_iter(&mut self.frequency.iter().map(|f| {
self.nco.set_frequency(f.0);
(self.nco.next().unwrap(), f.1).into()
}));

View File

@ -1,21 +1,19 @@
use std::collections::VecDeque;
use std::iter::Sum;
use num::Float;
use num::NumCast;
use oxydsp_flowgraph::BlockIO;
use oxydsp_flowgraph::block::SyncBlock;
use oxydsp_flowgraph::block::Block;
use oxydsp_flowgraph::io::In;
use oxydsp_flowgraph::io::Out;
use oxydsp_flowgraph::sync_block;
use oxydsp_flowgraph::tag::Tag;
use oxydsp_flowgraph::tag::TagKey;
use crate::filtering::fir::Fir;
use crate::filtering::fir::FirFilter;
use crate::filtering::history_buf::HistoryBuf;
#[derive(BlockIO)]
#[sync_block(tagged)]
pub struct EarlyLateGate<T: Float + Send + Sync + Sum + Clone + NumCast + 'static>
{
#[input]
@ -27,7 +25,7 @@ pub struct EarlyLateGate<T: Float + Send + Sync + Sum + Clone + NumCast + 'stati
symbol_length: usize,
// Window looking at symbol_length samples at a time
window: VecDeque<T>,
window: HistoryBuf<T>,
// The current location of the window, in relation to the last sample
window_location: usize,
@ -44,7 +42,7 @@ pub struct EarlyLateGate<T: Float + Send + Sync + Sum + Clone + NumCast + 'stati
impl<T> EarlyLateGate<T>
where
T: Float + Sum + Clone + 'static + Send + Sync + NumCast,
T: Float + Sum + Clone + 'static + Send + Sync + NumCast + Default,
{
pub fn new(
input: In<T>,
@ -58,7 +56,7 @@ where
Self {
input,
output,
window: VecDeque::with_capacity(symbol_length),
window: HistoryBuf::new(Default::default(), symbol_length),
symbol_length,
window_location: 0,
window_center: symbol_length / 2,
@ -72,48 +70,44 @@ where
}
}
impl<'view, T> SyncBlock<'view> for EarlyLateGate<T>
impl<'view, T> Block for EarlyLateGate<T>
where
T: Float + Sum + Clone + 'static + Send + Sync + NumCast,
{
fn sync_work(state: Self::StateView, input: Self::Input) -> Option<Self::Output>
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
if state.window.len() < *state.symbol_length
{
state.window.push_back(input.0);
*state.window_location += 1;
return Some(input.0.into());
}
self.output.push_iter(self.input.iter().map(|input| {
// Bring new sample in
self.window.push(input.0);
self.window_location += 1;
// Bring new sample in
state.window.pop_front();
state.window.push_back(input.0);
*state.window_location += 1;
let sample = self.window.as_slice()[self.window_center];
let mut tag = None;
if self.window_location >= self.next_sample as usize
{
let early_index = self.window_center - (0.25 * self.symbol_length as f32) as usize;
let late_index = self.window_center + (0.25 * self.symbol_length as f32) as usize;
let sample = state.window[*state.window_center];
let mut tag = None;
if *state.window_location >= *state.next_sample as usize
{
let early_index = *state.window_center - (0.25 * *state.symbol_length as f32) as usize;
let late_index = *state.window_center + (0.25 * *state.symbol_length as f32) as usize;
let early_sample = self.window.as_slice()[early_index];
let late_sample = self.window.as_slice()[late_index];
let early_sample = state.window[early_index];
let late_sample = state.window[late_index];
let error = (late_sample - early_sample) * sample;
let correction = self.loop_filter.next(error);
let error = (late_sample - early_sample) * sample;
let correction = state.loop_filter.next(error);
// Figure out next sample location
self.next_sample +=
(self.symbol_length as f32 + correction.to_f32().unwrap()).max(0.);
// Figure out next sample location
*state.next_sample +=
(*state.symbol_length as f32 + correction.to_f32().unwrap()).max(0.);
// Turn everything back relative to current sample
self.next_sample -= self.window_location as f32;
self.window_location = 0;
// Turn everything back relative to current sample
*state.next_sample -= *state.window_location as f32;
*state.window_location = 0;
tag = Some(Tag::with_entry(self.symbol_tag_key.clone(), error));
}
tag = Some(Tag::with_entry(state.symbol_tag_key.clone(), error));
}
(sample, tag).into()
}));
Some((sample, tag).into())
oxydsp_flowgraph::block::BlockResult::Ok
}
}

View File

@ -2,3 +2,4 @@ pub mod adapters;
pub mod channels;
pub mod iter;
pub mod squelch;
pub mod graph_control;

View File

@ -3,12 +3,9 @@ use std::iter::FusedIterator;
use oxydsp_flowgraph::BlockIO;
use oxydsp_flowgraph::block::Block;
use oxydsp_flowgraph::block::BlockResult;
use oxydsp_flowgraph::block::SyncBlock;
use oxydsp_flowgraph::io::In;
use oxydsp_flowgraph::io::Out;
use oxydsp_flowgraph::io::PopIterable;
use oxydsp_flowgraph::io::stream;
use oxydsp_flowgraph::sync_block;
use oxydsp_flowgraph::tag::Tag;
use oxydsp_flowgraph::tag::TagMergable;
use oxydsp_flowgraph::tag::Tagged;
@ -44,7 +41,7 @@ where
{
self.output.push_iter(
self.input
.pop_iter()
.iter()
.map(|x| ((&self.map)(x.0), x.1).into()),
);
BlockResult::Ok
@ -80,12 +77,12 @@ where
{
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
let writer = self.output.write();
let reader = self.input.read();
let mut writer = self.output.write_push();
let mut reader = self.input.iter();
for _ in 0..(writer.len().min(reader.len()))
{
let (input, tag_opt) = reader.pop().unwrap().into();
let (input, tag_opt) = reader.next().unwrap().into();
let (output, result) = (self.map)(input);
let _ = writer.push((output, tag_opt).into());
match result
@ -131,12 +128,12 @@ where
{
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
let writer = self.output.write();
let reader = self.input.read();
let mut writer = self.output.write_push();
let mut reader = self.input.iter();
for _ in 0..(writer.len().min(reader.len()))
{
let (input, tag_opt) = reader.pop().unwrap().into();
let (input, tag_opt) = reader.next().unwrap().into();
let (tagged_out, result) = (self.map)((input, tag_opt.clone()).into());
let (output, tag_out) = tagged_out.into();
@ -196,15 +193,18 @@ where
O: 'static,
F: Fn(&mut S, I) -> O,
{
fn work(&mut self) -> BlockResult {
self.output.push_iter(self.input.pop_iter()
.map(|x| ((self.map)(&mut self.state, x.0), x.1).into()));
fn work(&mut self) -> BlockResult
{
self.output.push_iter(
self.input
.iter()
.map(|x| ((self.map)(&mut self.state, x.0), x.1).into()),
);
BlockResult::Ok
}
}
#[derive(BlockIO)]
#[sync_block(tagged)]
pub struct ScanTagged<I: 'static, O: 'static, S, F>
where
F: Fn(&mut S, Tagged<I>) -> Tagged<O>,
@ -239,16 +239,20 @@ where
}
}
impl<'view, I, O, S, F> SyncBlock<'view> for ScanTagged<I, O, S, F>
impl<I, O, S, F> Block for ScanTagged<I, O, S, F>
where
I: 'static,
O: 'static,
S: 'view,
F: Fn(&mut S, Tagged<I>) -> Tagged<O> + 'view,
F: Fn(&mut S, Tagged<I>) -> Tagged<O>,
{
fn sync_work(state: Self::StateView, input: Self::Input) -> Option<Self::Output>
fn work(&mut self) -> BlockResult
{
Some((*state.map)(state.state, input))
self.output.push_iter(self.input.iter().map(|tagged| {
let cloned_tag = tagged.1.clone();
let (output, tag) = (self.map)(&mut self.state, (tagged.0, cloned_tag).into()).into();
(output, Tag::from_tag_opts(&[&tagged.1, &tag])).into()
}));
BlockResult::Ok
}
}
@ -288,15 +292,15 @@ impl<T: Clone + 'static> Block for Repeat<T>
{
fn work(&mut self) -> BlockResult
{
let writer = self.output.write();
let reader = self.input.read();
let mut writer = self.output.write_push();
let mut reader = self.input.iter();
let len = writer.len().min(reader.len() / self.repetitions + 1);
for _ in 0..len
{
if self.remaining == 0 || self.current.is_none()
{
if let Some(x) = reader.pop()
if let Some(x) = reader.next()
{
self.current = Some(x.into());
self.remaining = self.repetitions;
@ -324,7 +328,6 @@ impl<T: Clone + 'static> Block for Repeat<T>
}
#[derive(BlockIO)]
#[sync_block]
pub struct NullSink<T: 'static>
{
#[input]
@ -339,12 +342,12 @@ impl<T: 'static> NullSink<T>
}
}
impl<'view, I: 'static> SyncBlock<'view> for NullSink<I>
impl<I: 'static> Block for NullSink<I>
{
fn sync_work(_: Self::StateView, _: Self::Input) -> Option<Self::Output>
fn work(&mut self) -> BlockResult
{
// Don't do shit !
Some(())
self.input.iter().for_each(|_| ());
BlockResult::Ok
}
}
@ -383,12 +386,9 @@ impl<T: 'static + Clone> Block for Tee<T>
{
fn work(&mut self) -> BlockResult
{
let writer_a = self.output_a.write();
let writer_b = self.output_b.write();
for x in self
.input
.pop_iter()
.take(writer_a.len().min(writer_b.len()))
let mut writer_a = self.output_a.write_push();
let mut writer_b = self.output_b.write_push();
for x in self.input.iter().take(writer_a.len().min(writer_b.len()))
{
let _ = writer_a.push(x.clone());
let _ = writer_b.push(x);
@ -446,8 +446,8 @@ where
{
fn work(&mut self) -> BlockResult
{
let writer = self.output.write();
let reader = self.input.read();
let mut writer = self.output.write_push();
let mut reader = self.input.iter();
let max_write = writer.len();
let mut written = 0;
@ -472,7 +472,7 @@ where
if self.current_iter.is_none()
{
// Get input
if let Some(input) = reader.pop()
if let Some(input) = reader.next()
{
let mut new_iter = (self.map)(input.0).into_iter();
if let Some(first_elt) = new_iter.next()

View File

@ -7,7 +7,6 @@ use oxydsp_flowgraph::block::Block;
use oxydsp_flowgraph::block::BlockResult;
use oxydsp_flowgraph::io::In;
use oxydsp_flowgraph::io::Out;
use oxydsp_flowgraph::io::PopIterable;
use oxydsp_flowgraph::io::stream;
#[derive(BlockIO)]
@ -49,16 +48,10 @@ impl<I: 'static> Block for RxSource<Receiver<I>, I>
{
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
if self
self
.output
.push_iter(self.input.try_iter().map(|x| (x, None).into()))
{
BlockResult::Ok
}
else
{
BlockResult::Terminated
}
.push_iter(self.input.try_iter().map(|x| (x, None).into()));
BlockResult::Ok
}
}
@ -68,7 +61,7 @@ impl<I: 'static> Block for TxSink<Sender<I>, I>
{
if self
.input
.pop_iter()
.iter()
.map(|x| self.output.send(x.0))
.any(|res| res.is_err())
{
@ -87,7 +80,7 @@ impl<I: 'static> Block for TxSink<SyncSender<I>, I>
{
if self
.input
.pop_iter()
.iter()
.map(|x| self.output.send(x.0))
.any(|res| res.is_err())
{

View File

@ -0,0 +1,53 @@
use oxydsp_flowgraph::{BlockIO, block::Block, io::{In, Out}, tag::TagKey};
#[derive(BlockIO)]
pub struct GraphKiller<T: 'static, K: Send>
{
#[input]
input: In<T>,
#[output]
output: Out<T>,
kill_tag: TagKey<K>
}
impl<T: 'static, K: Send + Send + 'static> GraphKiller<T, K>
{
pub fn new(input: In<T>, kill_on: TagKey<K>) -> (Self, In<T>)
{
let (output, port) = oxydsp_flowgraph::io::stream();
(
GraphKiller
{
input,
output,
kill_tag: kill_on,
},
port
)
}
}
impl<T: 'static, K: Send + Sync + 'static> Block for GraphKiller<T, K>
{
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
let mut reader = self.input.iter();
let mut writer = self.output.write_push();
for _ in 0..reader.len().min(writer.len())
{
let (data, tag) = reader.next().unwrap().into();
if tag.as_ref().is_some_and(|t| t.retrieve(&self.kill_tag).is_some())
{
return oxydsp_flowgraph::block::BlockResult::Exit;
}
let _ = writer.push((data, tag).into());
}
oxydsp_flowgraph::block::BlockResult::Ok
}
}

View File

@ -52,7 +52,7 @@ where
{
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
let writer = self.output.write();
let mut writer = self.output.write_push();
for _ in 0..writer.len()
{

View File

@ -11,7 +11,6 @@ use oxydsp_flowgraph::block::Block;
use oxydsp_flowgraph::block::BlockResult;
use oxydsp_flowgraph::io::In;
use oxydsp_flowgraph::io::Out;
use oxydsp_flowgraph::io::PopIterable;
#[derive(BlockIO)]
pub struct Squelch<T>
@ -61,8 +60,8 @@ where
{
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
let writer = self.output.write();
for x in self.input.pop_iter().take(writer.len())
let mut writer = self.output.write_push();
for x in self.input.iter().take(writer.len())
{
let (element, tag) = x.into();

View File

@ -6,8 +6,6 @@ use num::Zero;
use num::complex::ComplexFloat;
use rustfft::FftNum;
use rustfft::FftPlanner;
use std::array;
use std::collections::VecDeque;
use std::f64::consts::PI;
use std::iter::Sum;
use std::ops::Add;