use alloc::vec::Vec;
use crate::engine::equalize::EqMode;
use crate::engine::pipeline::{DecodeDepth, DecodeStrictness, FftCache, LlrEffort};
use crate::engine::protocol::Protocol;
use super::ap::{ApHint, WsjtApCompatible};
pub trait FrameDecodable: Protocol {
type DecodeResult;
#[doc(hidden)]
fn __single_pass(req: &DecodeRequest<'_, Self>) -> DecodeOutcome<Self>
where
Self: Sized;
#[doc(hidden)]
fn __sniper(req: &SniperRequest<'_, Self>) -> DecodeOutcome<Self>
where
Self: Sized;
}
pub trait SupportsSicRounds: FrameDecodable {
#[doc(hidden)]
fn __flat_sic(req: &DecodeRequest<'_, Self>) -> DecodeOutcome<Self>
where
Self: Sized;
}
pub trait SupportsSicEarly: FrameDecodable {
#[doc(hidden)]
fn __staged_sic(req: &DecodeRequest<'_, Self>) -> DecodeOutcome<Self>
where
Self: Sized;
}
pub trait SupportsWideBandAp: FrameDecodable {}
pub struct DecodeOutcome<P: FrameDecodable> {
pub results: Vec<P::DecodeResult>,
pub fft_cache: FftCache,
}
pub struct DecodeRequest<'a, P: FrameDecodable> {
pub(crate) audio: &'a [i16],
pub(crate) freq_min: f32,
pub(crate) freq_max: f32,
pub(crate) sync_min: f32,
pub(crate) freq_hint: Option<f32>,
pub(crate) depth: DecodeDepth,
pub(crate) max_cand: usize,
pub(crate) strictness: DecodeStrictness,
pub(crate) eq_mode: EqMode,
pub(crate) ap_hint: Option<&'a ApHint>,
pub(crate) known: &'a [P::DecodeResult],
pub(crate) fft_cache: Option<FftCache>,
pub(crate) sic_rounds: usize,
strategy: fn(&DecodeRequest<'a, P>) -> DecodeOutcome<P>,
}
impl<'a, P: FrameDecodable> DecodeRequest<'a, P> {
pub fn new(
audio: &'a [i16],
freq_min: f32,
freq_max: f32,
sync_min: f32,
max_cand: usize,
) -> Self {
Self {
audio,
freq_min,
freq_max,
sync_min,
freq_hint: None,
depth: DecodeDepth::FULL,
max_cand,
strictness: DecodeStrictness::Normal,
eq_mode: EqMode::Off,
ap_hint: None,
known: &[],
fft_cache: None,
sic_rounds: 3,
strategy: P::__single_pass,
}
}
pub fn sniper(audio: &'a [i16], target_freq: f32, max_cand: usize) -> SniperRequest<'a, P> {
SniperRequest::new(audio, target_freq, max_cand)
}
pub fn freq_hint(mut self, f: f32) -> Self {
self.freq_hint = Some(f);
self
}
pub fn osd(mut self, on: bool) -> Self {
self.depth = DecodeDepth {
llr_effort: LlrEffort::Full,
osd: on,
};
self
}
pub fn strictness(mut self, s: DecodeStrictness) -> Self {
self.strictness = s;
self
}
pub fn eq_mode(mut self, e: EqMode) -> Self {
self.eq_mode = e;
self
}
pub fn known(mut self, k: &'a [P::DecodeResult]) -> Self {
self.known = k;
self
}
pub fn fft_cache(mut self, c: FftCache) -> Self {
self.fft_cache = Some(c);
self
}
pub fn decode(&self) -> DecodeOutcome<P> {
(self.strategy)(self)
}
}
impl<'a, P: SupportsWideBandAp> DecodeRequest<'a, P> {
pub fn ap_hint(mut self, ap: &'a ApHint) -> Self {
self.ap_hint = Some(ap);
self
}
}
impl<'a, P: SupportsSicRounds> DecodeRequest<'a, P> {
pub fn sic_rounds(mut self, n: usize) -> Self {
self.strategy = P::__flat_sic;
self.sic_rounds = n.clamp(1, 3);
self
}
}
impl<'a, P: SupportsSicEarly> DecodeRequest<'a, P> {
pub fn sic_early(mut self) -> Self {
self.strategy = P::__staged_sic;
self
}
}
pub struct SniperRequest<'a, P: FrameDecodable> {
pub(crate) audio: &'a [i16],
pub(crate) target_freq: f32,
pub(crate) sync_min: f32,
pub(crate) depth: DecodeDepth,
pub(crate) max_cand: usize,
pub(crate) strictness: DecodeStrictness,
pub(crate) eq_mode: EqMode,
pub(crate) ap_hint: Option<&'a ApHint>,
_protocol: core::marker::PhantomData<P>,
}
impl<'a, P: FrameDecodable> SniperRequest<'a, P> {
pub fn new(audio: &'a [i16], target_freq: f32, max_cand: usize) -> Self {
Self {
audio,
target_freq,
sync_min: 0.8,
depth: DecodeDepth::FULL,
max_cand,
strictness: DecodeStrictness::Normal,
eq_mode: EqMode::Off,
ap_hint: None,
_protocol: core::marker::PhantomData,
}
}
pub fn sync_min(mut self, v: f32) -> Self {
self.sync_min = v;
self
}
pub fn osd(mut self, on: bool) -> Self {
self.depth = DecodeDepth {
llr_effort: LlrEffort::Full,
osd: on,
};
self
}
pub fn strictness(mut self, s: DecodeStrictness) -> Self {
self.strictness = s;
self
}
pub fn eq_mode(mut self, e: EqMode) -> Self {
self.eq_mode = e;
self
}
pub fn decode(&self) -> DecodeOutcome<P> {
P::__sniper(self)
}
}
impl<'a, P: FrameDecodable> SniperRequest<'a, P>
where
P::Msg: WsjtApCompatible,
{
pub fn ap_hint(mut self, ap: &'a ApHint) -> Self {
self.ap_hint = Some(ap);
self
}
}