diff --git a/src/audio_receiver/foreign_signal.rs b/src/audio_receiver/foreign_signal.rs new file mode 100644 index 0000000..0f52049 --- /dev/null +++ b/src/audio_receiver/foreign_signal.rs @@ -0,0 +1,6 @@ +pub struct ForeignTwoStateCarrier { + pub acquired: bool, + pub clock_hz: f64, + pub freq_low: Option, + pub freq_high: Option, +} diff --git a/src/audio_receiver/input_dsp.rs b/src/audio_receiver/input_dsp.rs index e6e6c18..f0a7232 100644 --- a/src/audio_receiver/input_dsp.rs +++ b/src/audio_receiver/input_dsp.rs @@ -1,40 +1,59 @@ -use std::io::Write; use std::collections::VecDeque; +use std::io::Write; use cpal::{FromSample, Sample, SampleRate}; -use rustfft::{FftPlanner, num_complex::Complex}; +use ringbuf::{traits::*, LocalRb}; + +use rustfft::{num_complex::Complex, FftPlanner}; + +use super::ForeignTwoStateCarrier; pub fn take_input_pcm( pcm: &[T], sample_rate: SampleRate, channel: &tokio::sync::mpsc::Sender>, pcm_buffer: &mut VecDeque>, -) where + carrier: &mut ForeignTwoStateCarrier, +) where T: ToString + Sample + FromSample + std::fmt::Debug, - f64: FromSample + f64: FromSample, { - // TODO: Obtain this information during the handshake - let fft_size = 320 + let fft_size = (sample_rate / carrier.symbol_rate).round() as u32; - pcm_buffer.extend( - pcm - .iter() - .map(|s| Complex { re: s.to_sample::(), im: 0.0f64 }) - ); + pcm_buffer.extend(pcm.iter().map(|s| Complex { + re: s.to_sample::(), + im: 0.0f64, + })); let mut fft_planner = FftPlanner::::new(); - let fft_machine = fft_planner.plan_fft_forward(FFT_SIZE); // TODO: cfgable + let fft_machine = fft_planner.plan_fft_forward(fft_size); // TODO: cfgable + let mut fft_frame = pcm_buffer[..fft_size]; - while pcm_buffer.len() >= FFT_SIZE { - let mut fft_frame = - pcm_buffer.drain(..FFT_SIZE).collect::>>(); + // Zero-pad for a better freq resolution. 8192 fft should be fast enough + if fft_size < 8192 { + fft_frame.extend([0.0_f64].repeat(8192 - fft_size)); + } + + let mut window_offset = 0; + + while !carrier.acquired + && pcm_buffer.len() >= fft_size + && window_offset < fft_size + { fft_machine.process(&mut fft_frame); - + let frame_index = fft_size * carrier.clock_hz / sample_rate.0 as usize; + if let Some(bin) = fft_frame.get(frame_index) { + // yay + } + } + + while carrier.acquired && pcm_buffer.len() >= fft_size { + fft_machine.process(&mut fft_frame); /*for (i, s) in fft_frame.iter().enumerate() { - let freq = sample_rate.0 as usize * i / FFT_SIZE; + let freq = sample_rate.0 as usize * i / fft_size; let ampl = s.norm(); let confidence = ampl; if ampl > 50.0 { @@ -45,3 +64,10 @@ pub fn take_input_pcm( }*/ } } + +fn ampl_between_bins_quadratic( + fft_res: VecDeque>, + freq: f64, +) -> f64 { + todo!(); +} diff --git a/src/audio_receiver/mod.rs b/src/audio_receiver/mod.rs index 9d10fa0..1b18802 100644 --- a/src/audio_receiver/mod.rs +++ b/src/audio_receiver/mod.rs @@ -7,6 +7,9 @@ use tracing::{info, trace, warn}; use std::collections::VecDeque; +pub mod foreign_signal; +use foreign_signal::ForeignTwoStateCarrier; + mod input_dsp; use self::input_dsp::take_input_pcm; @@ -50,12 +53,19 @@ pub fn audio_receiver_main( let mut pcm_buf: VecDeque> = vec![].into(); + // TODO: determine freqs from handshake + let mut foreign_carrier = ForeignTwoStateCarrier { + acquired: false, + symbol_rate: 1200.0, + freq_low: Some(2400.0), + freq_high: Some(3600.0), + }; let input_stream = match cpal_input_config.sample_format() { cpal::SampleFormat::U8 => cpal_input.build_input_stream( &cpal_input_config.into(), move |pcm, _: &_| { - take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf) + take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf, &mut foreign_carrier) }, failed_pcm_take, None, @@ -63,7 +73,7 @@ pub fn audio_receiver_main( cpal::SampleFormat::I8 => cpal_input.build_input_stream( &cpal_input_config.into(), move |pcm, _: &_| { - take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf) + take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf, &mut foreign_carrier) }, failed_pcm_take, None, @@ -71,7 +81,7 @@ pub fn audio_receiver_main( cpal::SampleFormat::I16 => cpal_input.build_input_stream( &cpal_input_config.into(), move |pcm, _: &_| { - take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf) + take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf, &mut foreign_carrier) }, failed_pcm_take, None, @@ -79,7 +89,7 @@ pub fn audio_receiver_main( cpal::SampleFormat::I32 => cpal_input.build_input_stream( &cpal_input_config.into(), move |pcm, _: &_| { - take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf) + take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf, &mut foreign_carrier) }, failed_pcm_take, None, @@ -87,7 +97,7 @@ pub fn audio_receiver_main( cpal::SampleFormat::F32 => cpal_input.build_input_stream( &cpal_input_config.into(), move |pcm, _: &_| { - take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf) + take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf, &mut foreign_carrier) }, failed_pcm_take, None, @@ -95,7 +105,7 @@ pub fn audio_receiver_main( cpal::SampleFormat::F64 => cpal_input.build_input_stream( &cpal_input_config.into(), move |pcm, _: &_| { - take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf) + take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf, &mut foreign_carrier) }, failed_pcm_take, None, @@ -103,7 +113,7 @@ pub fn audio_receiver_main( cpal::SampleFormat::U64 => cpal_input.build_input_stream( &cpal_input_config.into(), move |pcm, _: &_| { - take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf) + take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf, &mut foreign_carrier) }, failed_pcm_take, None, @@ -111,7 +121,7 @@ pub fn audio_receiver_main( cpal::SampleFormat::I64 => cpal_input.build_input_stream( &cpal_input_config.into(), move |pcm, _: &_| { - take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf) + take_input_pcm::(pcm, sample_rate, &tx_for_demod, &mut pcm_buf, &mut foreign_carrier) }, failed_pcm_take, None,