begin correcting fft stuff. need to find a way to sync to signal
This commit is contained in:
parent
f050cec085
commit
3639b4ddfa
5 changed files with 98 additions and 34 deletions
7
run.sh
Executable file
7
run.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
ROOT="$(git rev-parse --show-toplevel)"
|
||||||
|
ROOT="${ROOT:-.}"
|
||||||
|
cargo build --release --bin sang
|
||||||
|
sudo setcap CAP_NET_ADMIN+ep "$ROOT/target/release/sang"
|
||||||
|
"$ROOT/target/release/sang"
|
|
@ -1,13 +1,47 @@
|
||||||
use cpal::{FromSample, Sample};
|
use std::io::Write;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use cpal::{FromSample, Sample, SampleRate};
|
||||||
|
|
||||||
use rustfft::{FftPlanner, num_complex::Complex};
|
use rustfft::{FftPlanner, num_complex::Complex};
|
||||||
|
|
||||||
pub fn take_input_pcm<T>(pcm: &[T], channel: &tokio::sync::mpsc::Sender<Vec<f64>>) where T: Sample + FromSample<f64> + std::fmt::Debug, f64: FromSample<T> {
|
pub fn take_input_pcm<T>(
|
||||||
let mut pcm_complex = pcm.iter().map(|s| Complex { re: s.to_sample::<f64>(), im: 0.0f64 }).collect::<Vec<Complex<_>>>();
|
pcm: &[T],
|
||||||
|
sample_rate: SampleRate,
|
||||||
|
channel: &tokio::sync::mpsc::Sender<Vec<f64>>,
|
||||||
|
pcm_buffer: &mut VecDeque<Complex<f64>>,
|
||||||
|
) where
|
||||||
|
T: ToString + Sample + FromSample<f64> + std::fmt::Debug,
|
||||||
|
f64: FromSample<T>
|
||||||
|
{
|
||||||
|
// TODO: Obtain this information during the handshake
|
||||||
|
let fft_size = 320
|
||||||
|
|
||||||
|
pcm_buffer.extend(
|
||||||
|
pcm
|
||||||
|
.iter()
|
||||||
|
.map(|s| Complex { re: s.to_sample::<f64>(), im: 0.0f64 })
|
||||||
|
);
|
||||||
|
|
||||||
let mut fft_planner = FftPlanner::<f64>::new();
|
let mut fft_planner = FftPlanner::<f64>::new();
|
||||||
let fft_machine = fft_planner.plan_fft_forward(pcm.len());
|
let fft_machine = fft_planner.plan_fft_forward(FFT_SIZE); // TODO: cfgable
|
||||||
fft_machine.process(&mut pcm_complex);
|
|
||||||
let fft_out = pcm_complex.iter().map(|n| n.norm()).collect::<Vec<_>>();
|
while pcm_buffer.len() >= FFT_SIZE {
|
||||||
println!("{:?}",fft_out);
|
let mut fft_frame =
|
||||||
|
pcm_buffer.drain(..FFT_SIZE).collect::<Vec<Complex<f64>>>();
|
||||||
|
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 ampl = s.norm();
|
||||||
|
let confidence = ampl;
|
||||||
|
if ampl > 50.0 {
|
||||||
|
println!("{:?}: {:?}", freq, ampl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// soon: confidence = ampl / |freq_target - freq_observed|
|
||||||
|
}*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ use cpal::{FromSample, Sample, SampleFormat};
|
||||||
|
|
||||||
use tracing::{info, trace, warn};
|
use tracing::{info, trace, warn};
|
||||||
|
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
mod input_dsp;
|
mod input_dsp;
|
||||||
use self::input_dsp::take_input_pcm;
|
use self::input_dsp::take_input_pcm;
|
||||||
|
|
||||||
|
@ -16,78 +18,101 @@ pub fn audio_receiver_main(
|
||||||
let cpal_input_config = cpal_input.supported_input_configs()
|
let cpal_input_config = cpal_input.supported_input_configs()
|
||||||
.context("could not find a suitable audio input configuration. are you root, trying to use a normal user's audio stack? try setting the capability CAP_NET_ADMIN=ep on this binary, and running as the user who is running the audio stack.")?
|
.context("could not find a suitable audio input configuration. are you root, trying to use a normal user's audio stack? try setting the capability CAP_NET_ADMIN=ep on this binary, and running as the user who is running the audio stack.")?
|
||||||
.max_by_key(|cfg| {
|
.max_by_key(|cfg| {
|
||||||
match cfg.sample_format() {
|
if cfg.channels() > 1 { return -999; }
|
||||||
SampleFormat::U8 => 10,
|
match cfg.sample_format() {
|
||||||
SampleFormat::I8 => 11,
|
SampleFormat::U8 => 10,
|
||||||
SampleFormat::U16 => 20,
|
SampleFormat::I8 => 11,
|
||||||
SampleFormat::I16 => 21,
|
SampleFormat::U16 => 20,
|
||||||
SampleFormat::U32 => 30,
|
SampleFormat::I16 => 21,
|
||||||
SampleFormat::I32 => 31,
|
SampleFormat::U32 => 30,
|
||||||
SampleFormat::F32 => 40,
|
SampleFormat::I32 => 31,
|
||||||
SampleFormat::F64 => 50,
|
SampleFormat::F32 => 40,
|
||||||
SampleFormat::U64 => 60,
|
SampleFormat::F64 => 50,
|
||||||
SampleFormat::I64 => 61,
|
SampleFormat::U64 => 60,
|
||||||
x => { warn!("Backend offered unknown sample format {x}",); -999 }
|
SampleFormat::I64 => 61,
|
||||||
}
|
x => { warn!("Backend offered unknown sample format {x}",); -999 }
|
||||||
|
}
|
||||||
}).expect("input device has no supported configurations available")
|
}).expect("input device has no supported configurations available")
|
||||||
.with_max_sample_rate();
|
.with_max_sample_rate();
|
||||||
|
//.with_sample_rate(cpal::SampleRate(8000));
|
||||||
|
|
||||||
|
let sample_rate = cpal_input_config.sample_rate();
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"input samples are {} @ {}hz",
|
"input samples are {} @ {}hz",
|
||||||
&cpal_input_config.sample_format(),
|
&cpal_input_config.sample_format(),
|
||||||
&cpal_input_config.sample_rate().0,
|
sample_rate.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
let failed_pcm_take = move |e| {
|
let failed_pcm_take = move |e| {
|
||||||
warn!("dropped some PCM data on input stream?! {}", e);
|
warn!("dropped some PCM data on input stream?! {}", e);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut pcm_buf: VecDeque<rustfft::num_complex::Complex<f64>> =
|
||||||
|
vec![].into();
|
||||||
|
|
||||||
let input_stream = match cpal_input_config.sample_format() {
|
let input_stream = match cpal_input_config.sample_format() {
|
||||||
cpal::SampleFormat::U8 => cpal_input.build_input_stream(
|
cpal::SampleFormat::U8 => cpal_input.build_input_stream(
|
||||||
&cpal_input_config.into(),
|
&cpal_input_config.into(),
|
||||||
move |pcm, _: &_| take_input_pcm::<u8>(pcm, &tx_for_demod),
|
move |pcm, _: &_| {
|
||||||
|
take_input_pcm::<u8>(pcm, sample_rate, &tx_for_demod, &mut pcm_buf)
|
||||||
|
},
|
||||||
failed_pcm_take,
|
failed_pcm_take,
|
||||||
None,
|
None,
|
||||||
).context("failed to build input stream")?,
|
).context("failed to build input stream")?,
|
||||||
cpal::SampleFormat::I8 => cpal_input.build_input_stream(
|
cpal::SampleFormat::I8 => cpal_input.build_input_stream(
|
||||||
&cpal_input_config.into(),
|
&cpal_input_config.into(),
|
||||||
move |pcm, _: &_| take_input_pcm::<i8>(pcm, &tx_for_demod),
|
move |pcm, _: &_| {
|
||||||
|
take_input_pcm::<i8>(pcm, sample_rate, &tx_for_demod, &mut pcm_buf)
|
||||||
|
},
|
||||||
failed_pcm_take,
|
failed_pcm_take,
|
||||||
None,
|
None,
|
||||||
).context("failed to build input stream")?,
|
).context("failed to build input stream")?,
|
||||||
cpal::SampleFormat::I16 => cpal_input.build_input_stream(
|
cpal::SampleFormat::I16 => cpal_input.build_input_stream(
|
||||||
&cpal_input_config.into(),
|
&cpal_input_config.into(),
|
||||||
move |pcm, _: &_| take_input_pcm::<i16>(pcm, &tx_for_demod),
|
move |pcm, _: &_| {
|
||||||
|
take_input_pcm::<i16>(pcm, sample_rate, &tx_for_demod, &mut pcm_buf)
|
||||||
|
},
|
||||||
failed_pcm_take,
|
failed_pcm_take,
|
||||||
None,
|
None,
|
||||||
).context("failed to build input stream")?,
|
).context("failed to build input stream")?,
|
||||||
cpal::SampleFormat::I32 => cpal_input.build_input_stream(
|
cpal::SampleFormat::I32 => cpal_input.build_input_stream(
|
||||||
&cpal_input_config.into(),
|
&cpal_input_config.into(),
|
||||||
move |pcm, _: &_| take_input_pcm::<i32>(pcm, &tx_for_demod),
|
move |pcm, _: &_| {
|
||||||
|
take_input_pcm::<i32>(pcm, sample_rate, &tx_for_demod, &mut pcm_buf)
|
||||||
|
},
|
||||||
failed_pcm_take,
|
failed_pcm_take,
|
||||||
None,
|
None,
|
||||||
).context("failed to build input stream")?,
|
).context("failed to build input stream")?,
|
||||||
cpal::SampleFormat::F32 => cpal_input.build_input_stream(
|
cpal::SampleFormat::F32 => cpal_input.build_input_stream(
|
||||||
&cpal_input_config.into(),
|
&cpal_input_config.into(),
|
||||||
move |pcm, _: &_| take_input_pcm::<f32>(pcm, &tx_for_demod),
|
move |pcm, _: &_| {
|
||||||
|
take_input_pcm::<f32>(pcm, sample_rate, &tx_for_demod, &mut pcm_buf)
|
||||||
|
},
|
||||||
failed_pcm_take,
|
failed_pcm_take,
|
||||||
None,
|
None,
|
||||||
).context("failed to build input stream")?,
|
).context("failed to build input stream")?,
|
||||||
cpal::SampleFormat::F64 => cpal_input.build_input_stream(
|
cpal::SampleFormat::F64 => cpal_input.build_input_stream(
|
||||||
&cpal_input_config.into(),
|
&cpal_input_config.into(),
|
||||||
move |pcm, _: &_| take_input_pcm::<f64>(pcm, &tx_for_demod),
|
move |pcm, _: &_| {
|
||||||
|
take_input_pcm::<f64>(pcm, sample_rate, &tx_for_demod, &mut pcm_buf)
|
||||||
|
},
|
||||||
failed_pcm_take,
|
failed_pcm_take,
|
||||||
None,
|
None,
|
||||||
).context("failed to build input stream")?,
|
).context("failed to build input stream")?,
|
||||||
cpal::SampleFormat::U64 => cpal_input.build_input_stream(
|
cpal::SampleFormat::U64 => cpal_input.build_input_stream(
|
||||||
&cpal_input_config.into(),
|
&cpal_input_config.into(),
|
||||||
move |pcm, _: &_| take_input_pcm::<u64>(pcm, &tx_for_demod),
|
move |pcm, _: &_| {
|
||||||
|
take_input_pcm::<u64>(pcm, sample_rate, &tx_for_demod, &mut pcm_buf)
|
||||||
|
},
|
||||||
failed_pcm_take,
|
failed_pcm_take,
|
||||||
None,
|
None,
|
||||||
).context("failed to build input stream")?,
|
).context("failed to build input stream")?,
|
||||||
cpal::SampleFormat::I64 => cpal_input.build_input_stream(
|
cpal::SampleFormat::I64 => cpal_input.build_input_stream(
|
||||||
&cpal_input_config.into(),
|
&cpal_input_config.into(),
|
||||||
move |pcm, _: &_| take_input_pcm::<i64>(pcm, &tx_for_demod),
|
move |pcm, _: &_| {
|
||||||
|
take_input_pcm::<i64>(pcm, sample_rate, &tx_for_demod, &mut pcm_buf)
|
||||||
|
},
|
||||||
failed_pcm_take,
|
failed_pcm_take,
|
||||||
None,
|
None,
|
||||||
).context("failed to build input stream")?,
|
).context("failed to build input stream")?,
|
||||||
|
|
|
@ -49,10 +49,12 @@ pub fn audio_transmitter_main(
|
||||||
warn!("dropped some PCM data on output stream?! {}", e);
|
warn!("dropped some PCM data on output stream?! {}", e);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// These are mathematically chosen to make things easier for now.
|
||||||
|
//
|
||||||
// TODO: from cli
|
// TODO: from cli
|
||||||
let mut carrier = crate::dsp_common::carrier::TwoStateCarrier::new(
|
let mut carrier = crate::dsp_common::carrier::TwoStateCarrier::new(
|
||||||
2400, // freq_low
|
2400, // freq_low
|
||||||
2800, // freq_high
|
3200, // freq_high
|
||||||
cpal_output_config.sample_rate().0, // sample_rate
|
cpal_output_config.sample_rate().0, // sample_rate
|
||||||
1200, // symbol_rate
|
1200, // symbol_rate
|
||||||
);
|
);
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue