Simple 2FSK
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
use std::ops::Add;
|
||||
use std::ops::{Add, Mul};
|
||||
|
||||
use oxydsp_flowgraph::{
|
||||
BlockIO,
|
||||
@ -59,3 +59,57 @@ where
|
||||
BlockResult::Ok
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(BlockIO)]
|
||||
pub struct Multiplier<Ia, Ib, O>
|
||||
where
|
||||
Ia: Mul<Ib, Output = O> + 'static,
|
||||
Ib: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
#[input]
|
||||
input_a: In<Ia>,
|
||||
|
||||
#[input]
|
||||
input_b: In<Ib>,
|
||||
|
||||
#[output]
|
||||
output: Out<O>,
|
||||
}
|
||||
|
||||
impl<Ia, Ib, O> Multiplier<Ia, Ib, O>
|
||||
where
|
||||
Ia: Mul<Ib, Output = O> + 'static,
|
||||
Ib: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
pub fn new(input_a: In<Ia>, input_b: In<Ib>) -> (Self, In<O>)
|
||||
{
|
||||
let (output, added) = stream();
|
||||
(
|
||||
Self {
|
||||
input_a,
|
||||
input_b,
|
||||
output,
|
||||
},
|
||||
added,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ia, Ib, O> Block for Multiplier<Ia, Ib, O>
|
||||
where
|
||||
Ia: Mul<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 * b),
|
||||
);
|
||||
BlockResult::Ok
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +50,15 @@ pub struct Nco<T: Float + From<f32> + 'static>
|
||||
|
||||
impl<T: Float + From<f32> + 'static> Nco<T>
|
||||
{
|
||||
pub fn new(
|
||||
pub fn new(input: In<DigitalFrequency>) -> (Self, In<Complex<T>>)
|
||||
{
|
||||
Self::with(
|
||||
input,
|
||||
crate::synthesis::oscillator::Nco::<T>::new(DigitalFrequency(0)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn with(
|
||||
input: In<DigitalFrequency>,
|
||||
nco: crate::synthesis::oscillator::Nco<T>,
|
||||
) -> (Self, In<Complex<T>>)
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
pub mod adapters;
|
||||
pub mod channels;
|
||||
pub mod iter;
|
||||
|
||||
@ -1 +1,97 @@
|
||||
use oxydsp_flowgraph::{
|
||||
BlockIO,
|
||||
block::{Block, BlockResult},
|
||||
edge::{In, Out, PopIterable, stream},
|
||||
};
|
||||
|
||||
#[derive(BlockIO)]
|
||||
pub struct Map<I: 'static, O: 'static, F>
|
||||
{
|
||||
#[input]
|
||||
input: In<I>,
|
||||
|
||||
#[output]
|
||||
output: Out<O>,
|
||||
|
||||
map: F,
|
||||
}
|
||||
|
||||
impl<I: 'static, O: 'static, F> Map<I, O, F>
|
||||
where
|
||||
F: Fn(I) -> O,
|
||||
{
|
||||
pub fn new(input: In<I>, map: F) -> (Self, In<O>)
|
||||
{
|
||||
let (output, mapped) = stream();
|
||||
(Self { input, output, map }, mapped)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: 'static, O: 'static, F> Block for Map<I, O, F>
|
||||
where
|
||||
F: Fn(I) -> O,
|
||||
{
|
||||
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
|
||||
{
|
||||
self.output.push_iter(self.input.pop_iter().map(&self.map));
|
||||
BlockResult::Ok
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(BlockIO)]
|
||||
pub struct Repeat<T: 'static>
|
||||
{
|
||||
#[input]
|
||||
input: In<T>,
|
||||
|
||||
repetitions: usize,
|
||||
remaining: usize,
|
||||
current: Option<T>,
|
||||
|
||||
#[output]
|
||||
output: Out<T>,
|
||||
}
|
||||
|
||||
impl<T: 'static> Repeat<T>
|
||||
{
|
||||
pub fn new(input: In<T>, repetitions: usize) -> (Self, In<T>)
|
||||
{
|
||||
let (output, repeated) = stream();
|
||||
(
|
||||
Self {
|
||||
input,
|
||||
repetitions,
|
||||
remaining: repetitions,
|
||||
current: None,
|
||||
output,
|
||||
},
|
||||
repeated,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + 'static> Block for Repeat<T>
|
||||
{
|
||||
fn work(&mut self) -> BlockResult
|
||||
{
|
||||
let writer = self.output.write();
|
||||
let reader = self.input.read();
|
||||
let len = writer.len().min(reader.len() / self.repetitions + 1);
|
||||
|
||||
for _ in 0..len
|
||||
{
|
||||
if self.remaining == 0 || self.current.is_none()
|
||||
{
|
||||
self.current = Some(reader.pop().unwrap());
|
||||
self.remaining = self.repetitions;
|
||||
}
|
||||
|
||||
writer
|
||||
.push(self.current.clone().unwrap())
|
||||
.unwrap_or_else(|_| panic!());
|
||||
self.remaining -= 1;
|
||||
}
|
||||
|
||||
BlockResult::Ok
|
||||
}
|
||||
}
|
||||
|
||||
95
oxydsp-dsp/src/blocks/utilities/channels.rs
Normal file
95
oxydsp-dsp/src/blocks/utilities/channels.rs
Normal file
@ -0,0 +1,95 @@
|
||||
use std::sync::mpsc::{Receiver, Sender, SyncSender};
|
||||
|
||||
use oxydsp_flowgraph::{
|
||||
BlockIO,
|
||||
block::{Block, BlockResult},
|
||||
edge::{In, Out, PopIterable, stream},
|
||||
};
|
||||
|
||||
#[derive(BlockIO)]
|
||||
pub struct RxSource<Rx, I: 'static>
|
||||
{
|
||||
input: Rx,
|
||||
|
||||
#[output]
|
||||
output: Out<I>,
|
||||
}
|
||||
|
||||
#[derive(BlockIO)]
|
||||
pub struct TxSink<Tx, I: 'static>
|
||||
{
|
||||
#[input]
|
||||
input: In<I>,
|
||||
|
||||
output: Tx,
|
||||
}
|
||||
|
||||
impl<Rx, I: 'static> RxSource<Rx, I>
|
||||
{
|
||||
pub fn new(input: Rx) -> (Self, In<I>)
|
||||
{
|
||||
let (output, source) = stream();
|
||||
(Self { input, output }, source)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tx, I: 'static> TxSink<Tx, I>
|
||||
{
|
||||
pub fn new(input: In<I>, output: Tx) -> Self
|
||||
{
|
||||
Self { input, output }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: 'static> Block for RxSource<Receiver<I>, I>
|
||||
{
|
||||
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
|
||||
{
|
||||
if self.output.push_iter(self.input.iter())
|
||||
{
|
||||
BlockResult::Ok
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockResult::Terminated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: 'static> Block for TxSink<Sender<I>, I>
|
||||
{
|
||||
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
|
||||
{
|
||||
if self
|
||||
.input
|
||||
.pop_iter()
|
||||
.map(|x| self.output.send(x))
|
||||
.any(|res| res.is_err())
|
||||
{
|
||||
BlockResult::Terminated
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockResult::Ok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: 'static> Block for TxSink<SyncSender<I>, I>
|
||||
{
|
||||
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
|
||||
{
|
||||
if self
|
||||
.input
|
||||
.pop_iter()
|
||||
.map(|x| self.output.send(x))
|
||||
.any(|res| res.is_err())
|
||||
{
|
||||
BlockResult::Terminated
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockResult::Ok
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -51,7 +51,8 @@ impl<T> Nco<T>
|
||||
|
||||
pub fn step(&mut self)
|
||||
{
|
||||
let _ = self.phase.overflowing_add(self.d_phase);
|
||||
let (new, _) = self.phase.overflowing_add(self.d_phase);
|
||||
self.phase = new;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::f64::consts::PI;
|
||||
use std::{f64::consts::PI, ops::Neg};
|
||||
|
||||
use crate::map;
|
||||
|
||||
@ -15,7 +15,7 @@ impl DigitalFrequency
|
||||
{
|
||||
// Frequnecy wraps arround : Going at 2 pi radians per second
|
||||
// Is like not oscillating at all
|
||||
let f = radians_per_sample.rem_euclid(radians_per_sample);
|
||||
let f = radians_per_sample.rem_euclid(2. * PI);
|
||||
|
||||
// Then we map the [0, 2*PI] range into the 0 to usize range
|
||||
DigitalFrequency(map(f, 0., 2. * PI, 0., usize::MAX as f64).floor() as usize)
|
||||
@ -36,3 +36,13 @@ impl DigitalFrequency
|
||||
map(self.0 as f64, 0., usize::MAX as f64, 0., sample_rate)
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for DigitalFrequency
|
||||
{
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self::Output
|
||||
{
|
||||
DigitalFrequency(usize::MAX - self.0)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user