use std::mem;
use crate::anyhow::Result;
use crate::runtime::Block;
use crate::runtime::BlockMeta;
use crate::runtime::BlockMetaBuilder;
use crate::runtime::Kernel;
use crate::runtime::MessageIo;
use crate::runtime::MessageIoBuilder;
use crate::runtime::StreamIo;
use crate::runtime::StreamIoBuilder;
use crate::runtime::WorkIo;
use futuredsp::fir::*;
use futuredsp::firdes;
use futuredsp::{TapsAccessor, UnaryKernel};
use num_integer;
pub struct Fir<InputType, OutputType, TapType, Core>
where
InputType: 'static + Send,
OutputType: 'static + Send,
TapType: 'static,
Core: 'static + UnaryKernel<InputType, OutputType>,
{
core: Core,
_input_type: std::marker::PhantomData<InputType>,
_output_type: std::marker::PhantomData<OutputType>,
_tap_type: std::marker::PhantomData<TapType>,
}
unsafe impl<InputType, OutputType, TapType, Core> Send for Fir<InputType, OutputType, TapType, Core>
where
InputType: 'static + Send,
OutputType: 'static + Send,
TapType: 'static,
Core: 'static + UnaryKernel<InputType, OutputType>,
{
}
impl<InputType, OutputType, TapType, Core> Fir<InputType, OutputType, TapType, Core>
where
InputType: 'static + Send,
OutputType: 'static + Send,
TapType: 'static,
Core: 'static + UnaryKernel<InputType, OutputType>,
{
pub fn new(core: Core) -> Block {
Block::new(
BlockMetaBuilder::new("Fir").build(),
StreamIoBuilder::new()
.add_input("in", mem::size_of::<InputType>())
.add_output("out", mem::size_of::<OutputType>())
.build(),
MessageIoBuilder::<Fir<InputType, OutputType, TapType, Core>>::new().build(),
Fir {
core,
_input_type: std::marker::PhantomData,
_output_type: std::marker::PhantomData,
_tap_type: std::marker::PhantomData,
},
)
}
}
#[doc(hidden)]
#[async_trait]
impl<InputType, OutputType, TapType, Core> Kernel for Fir<InputType, OutputType, TapType, Core>
where
InputType: 'static + Send,
OutputType: 'static + Send,
TapType: 'static,
Core: 'static + UnaryKernel<InputType, OutputType>,
{
async fn work(
&mut self,
io: &mut WorkIo,
sio: &mut StreamIo,
_mio: &mut MessageIo<Self>,
_meta: &mut BlockMeta,
) -> Result<()> {
let i = sio.input(0).slice::<InputType>();
let o = sio.output(0).slice::<OutputType>();
let (consumed, produced, status) = self.core.work(i, o);
sio.input(0).consume(consumed);
sio.output(0).produce(produced);
if sio.input(0).finished() && status.produced_all_samples() {
io.finished = true;
}
Ok(())
}
}
pub struct FirBuilder {
}
impl FirBuilder {
pub fn new<InputType, OutputType, TapType, Taps>(taps: Taps) -> Block
where
InputType: 'static + Send,
OutputType: 'static + Send,
TapType: 'static,
Taps: 'static + TapsAccessor<TapType = TapType>,
NonResamplingFirKernel<InputType, OutputType, Taps, TapType>:
UnaryKernel<InputType, OutputType>,
{
Fir::<
InputType,
OutputType,
TapType,
NonResamplingFirKernel<InputType, OutputType, Taps, TapType>,
>::new(NonResamplingFirKernel::new(taps))
}
pub fn new_resampling<InputType, OutputType>(interp: usize, decim: usize) -> Block
where
InputType: 'static + Send,
OutputType: 'static + Send,
PolyphaseResamplingFirKernel<InputType, OutputType, Vec<f32>, f32>:
UnaryKernel<InputType, OutputType>,
{
let gcd = num_integer::gcd(interp, decim);
let interp = interp / gcd;
let decim = decim / gcd;
let taps = firdes::kaiser::multirate::<f32>(interp, decim, 12, 0.0001);
FirBuilder::new_resampling_with_taps::<InputType, OutputType, f32, _>(interp, decim, taps)
}
pub fn new_resampling_with_taps<InputType, OutputType, TapType, Taps>(
interp: usize,
decim: usize,
taps: Taps,
) -> Block
where
InputType: 'static + Send,
OutputType: 'static + Send,
TapType: 'static,
Taps: 'static + TapsAccessor<TapType = TapType>,
PolyphaseResamplingFirKernel<InputType, OutputType, Taps, TapType>:
UnaryKernel<InputType, OutputType>,
{
Fir::<
InputType,
OutputType,
TapType,
PolyphaseResamplingFirKernel<InputType, OutputType, Taps, TapType>,
>::new(PolyphaseResamplingFirKernel::new(interp, decim, taps))
}
}