use biquad::{Biquad, Coefficients, DirectForm1, ToHertz, Type};
use image::{ColorType, DynamicImage, GenericImage, GenericImageView, Pixel, imageops::FilterType};
use crate::{
SAMPLE_RATE,
common::{DSPOut, DecodeResult, SSTVMode, Signal},
dsp,
};
pub struct MartinM1 {
decoded_image: DynamicImage,
samples: Vec<f32>,
in_partial_decode: bool,
pos: usize,
row: u32,
}
impl SSTVMode for MartinM1 {
fn new() -> Self {
MartinM1 {
decoded_image: DynamicImage::new(320, 256, ColorType::Rgb16),
samples: Vec::new(),
in_partial_decode: false,
row: 0,
pos: 0,
}
}
fn encode(&mut self, image: image::DynamicImage) -> Signal {
let resize = image.resize_exact(320, 256, FilterType::Nearest);
let mut out = Signal::new();
out.push(1000, 200_000.);
out.push(1900, 300_000.);
out.push(1200, 10_000.);
out.push(1900, 300_000.);
out.push(1200, 30_000.);
out.push(1100, 30_000.);
out.push(1300, 30_000.);
out.push(1300, 30_000.);
out.push(1100, 30_000.);
out.push(1100, 30_000.);
out.push(1300, 30_000.);
out.push(1100, 30_000.);
out.push(1200, 30_000.);
for i in 0..256 {
sync(&mut out);
colour_sep(&mut out);
for colour in [1, 2, 0] {
for j in 0..320 {
let pixel = resize.get_pixel(j, i);
let rgb = pixel.to_rgb();
let channels = rgb.channels();
let value = channels[colour] as f64 / u8::MAX as f64;
let range = 2300. - 1500.;
let freq = value * range;
out.push(freq as usize + 1500, 457.6);
}
colour_sep(&mut out);
}
}
out.push(0, 100_000.);
out
}
fn decode(&mut self, audio: &[f32]) -> DecodeResult {
self.samples.append(&mut audio.to_vec());
let fl = 1.khz();
let fh = 3.khz();
let fs = SAMPLE_RATE.hz();
let coeffs_lp = Coefficients::<f64>::from_params(Type::LowPass, fs, fh, 1.).unwrap();
let coeffs_hp = Coefficients::<f64>::from_params(Type::HighPass, fs, fl, 1.).unwrap();
let mut biquad_lp = DirectForm1::<f64>::new(coeffs_lp);
let mut biquad_hp = DirectForm1::<f64>::new(coeffs_hp);
let mut filtered = Vec::with_capacity(audio.len());
for elem in &self.samples {
filtered.push(biquad_lp.run(*elem as f64));
}
for elem in filtered.iter_mut() {
*elem = biquad_hp.run(*elem);
}
let res = dsp::quadrature_demod(&filtered);
let mut filtered_dsp = Vec::with_capacity(res.len());
let coeffs_lpd = Coefficients::<f64>::from_params(Type::LowPass, fs, 400.hz(), 1.).unwrap();
let mut biquad_dsp_out = DirectForm1::<f64>::new(coeffs_lpd);
for elem in res {
filtered_dsp.push(biquad_dsp_out.run(elem));
}
let mut out = DSPOut::new(&filtered_dsp);
out.set_to(self.pos);
if !self.in_partial_decode {
if let None = self.get_calibration_header(&mut out) {
return DecodeResult::NoneFound;
}
println!("found header");
}
for i in self.row..256 {
let start_pos = out.get_pos();
if let None = out
.take_till_frq(1200.)
.and_then(|_| out.take_while_frq(1200.))
.and_then(|_| out.take_us(572.))
{
self.pos = start_pos;
self.in_partial_decode = true;
self.row = i;
return DecodeResult::Partial(self.decoded_image.clone());
}
for colour in [1, 2, 0] {
for j in 0..320 {
if let Some(val) = out.take_us(457.6) {
let brightness = (val - 1500.) / (2300. - 1500.);
let mut rgb = self.decoded_image.get_pixel(j, i);
rgb.channels_mut()[colour] = (brightness * 255.) as u8;
self.decoded_image.put_pixel(j, i, rgb);
} else {
self.pos = start_pos;
self.row = i;
self.in_partial_decode = true;
return DecodeResult::Partial(self.decoded_image.clone());
}
}
if let None = out.take_us(572.) {
self.pos = start_pos;
self.row = i;
self.in_partial_decode = true;
return DecodeResult::Partial(self.decoded_image.clone());
}
}
}
DecodeResult::Finished(self.decoded_image.clone())
}
fn get_image(&self) -> image::DynamicImage {
self.decoded_image.clone()
}
}
impl MartinM1 {
fn get_calibration_header(&mut self, sig: &mut DSPOut) -> Option<u8> {
sig.take_till_frq(1900.)?;
sig.take_while_frq_within(1900., 400.)?;
sig.take_till_frq(1200.)?;
let avg = sig.take_us(300_000.)?;
if (avg-1900.).abs() > 200. {
return None;
}
let vis = [
sig.take_us(30_000.)? < 1200.,
sig.take_us(30_000.)? < 1200.,
sig.take_us(30_000.)? < 1200.,
sig.take_us(30_000.)? < 1200.,
sig.take_us(30_000.)? < 1200.,
sig.take_us(30_000.)? < 1200.,
];
let _parity = sig.take_us(30_000.)? < 1200.;
sig.take_while_frq(1200.)?;
let mut total = 0;
for (pos, elem) in vis.iter().enumerate() {
total += 2_u8.pow((6 - pos) as u32) * (*elem as u8);
}
Some(total)
}
}
fn sync(out: &mut Signal) {
out.push(1200, 4862.);
}
fn colour_sep(out: &mut Signal) {
out.push(1500, 572.);
}