From bc7a8860fdda6b9767766e19aabf3d7c24b3fc68 Mon Sep 17 00:00:00 2001 From: TerraMaster85 Date: Mon, 16 Dec 2024 21:06:39 -0500 Subject: [PATCH] output dsp (not done yet) --- src/audio_receiver/mod.rs | 6 +-- src/audio_transmitter/mod.rs | 93 ++++++++++++++++++++---------------- src/dsp_common/carrier.rs | 75 +++++++++++++++++++++++++++++ src/dsp_common/mod.rs | 1 + src/dsp_outb/mod.rs | 49 +++++++++++++++++++ src/main.rs | 25 ++++++---- src/wire_fmt/mod.rs | 4 +- 7 files changed, 196 insertions(+), 57 deletions(-) create mode 100644 src/dsp_common/carrier.rs create mode 100644 src/dsp_common/mod.rs create mode 100644 src/dsp_outb/mod.rs diff --git a/src/audio_receiver/mod.rs b/src/audio_receiver/mod.rs index efeab11..256fea0 100644 --- a/src/audio_receiver/mod.rs +++ b/src/audio_receiver/mod.rs @@ -11,8 +11,8 @@ use crate::task_msg::PcmFrameMessage; pub fn audio_receiver_main( tx_for_demod: Sender, - cpal_input: cpal::Device, -) -> Result<()> { + cpal_input: &cpal::Device, +) -> Result { trace!("audio_receiver started"); 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.")? @@ -102,7 +102,7 @@ pub fn audio_receiver_main( input_stream.play().context("failed to start intake audio stream")?; - Ok(()) + Ok(input_stream) } fn take_input_pcm(pcm: &[T], channel: &Sender) where T: Sample + std::fmt::Debug, i64: FromSample { diff --git a/src/audio_transmitter/mod.rs b/src/audio_transmitter/mod.rs index 8169418..43482e1 100644 --- a/src/audio_transmitter/mod.rs +++ b/src/audio_transmitter/mod.rs @@ -3,8 +3,6 @@ use anyhow::{Context, Result}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use cpal::{FromSample, Sample, SampleFormat}; -use dasp_signal::Signal; - use tracing::{error, info, trace, warn}; use tokio::sync::mpsc::Receiver; @@ -13,46 +11,45 @@ use crate::task_msg::{PcmFrameMessage, PcmSampleMessage}; pub fn audio_transmitter_main( mut rx_for_wire: Receiver, - cpal_output: cpal::Device, -) -> Result<()> { + cpal_output: &cpal::Device, +) -> Result { trace!("audio_transmitter started"); let cpal_output_config = cpal_output.supported_output_configs() .context("could not find a suitable audio output 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| { - println!("AVAIL RATE: {:?}, {:?}, {:?}", cfg.sample_format(), cfg.min_sample_rate(), cfg.max_sample_rate()); - match cfg.sample_format() { - SampleFormat::U8 => 10, - SampleFormat::I8 => 11, - SampleFormat::U16 => 20, - SampleFormat::I16 => 21, - SampleFormat::U32 => 30, - SampleFormat::I32 => 31, - SampleFormat::F32 => 40, - SampleFormat::F64 => 50, - SampleFormat::U64 => 60, - SampleFormat::I64 => 61, - x => { warn!("Backend offered unknown sample format {x}",); -999 } - } + if cfg.channels() > 1 { return -999; } + match cfg.sample_format() { + SampleFormat::U8 => 10, + SampleFormat::I8 => 11, + SampleFormat::U16 => 20, + SampleFormat::I16 => 21, + SampleFormat::U32 => 30, + SampleFormat::I32 => 31, + SampleFormat::F32 => 40, + SampleFormat::F64 => 50, + SampleFormat::U64 => 60, + SampleFormat::I64 => 61, + x => { warn!("Backend offered unknown sample format {x}",); -999 } + } }).expect("output device has no supported configurations available") - .with_sample_rate(cpal::SampleRate(384000));//max_sample_rate(); + .with_max_sample_rate(); info!( - "output samples are {} @ {}hz", + "output samples are {} @ {}hz on {} channels", &cpal_output_config.sample_format(), &cpal_output_config.sample_rate().0, + &cpal_output_config.channels(), ); let failed_pcm_give = move |e| { warn!("dropped some PCM data on output stream?! {}", e); }; - let mut i = 0f64; - let output_stream = match cpal_output_config.sample_format() { cpal::SampleFormat::U8 => cpal_output .build_output_stream( &cpal_output_config.into(), - move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire, &mut i), + move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire), failed_pcm_give, None, ) @@ -60,7 +57,15 @@ pub fn audio_transmitter_main( cpal::SampleFormat::I8 => cpal_output .build_output_stream( &cpal_output_config.into(), - move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire, &mut i), + move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire), + failed_pcm_give, + None, + ) + .context("failed to build output stream")?, + cpal::SampleFormat::U16 => cpal_output + .build_output_stream( + &cpal_output_config.into(), + move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire), failed_pcm_give, None, ) @@ -68,7 +73,15 @@ pub fn audio_transmitter_main( cpal::SampleFormat::I16 => cpal_output .build_output_stream( &cpal_output_config.into(), - move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire, &mut i), + move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire), + failed_pcm_give, + None, + ) + .context("failed to build output stream")?, + cpal::SampleFormat::U32 => cpal_output + .build_output_stream( + &cpal_output_config.into(), + move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire), failed_pcm_give, None, ) @@ -76,7 +89,7 @@ pub fn audio_transmitter_main( cpal::SampleFormat::I32 => cpal_output .build_output_stream( &cpal_output_config.into(), - move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire, &mut i), + move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire), failed_pcm_give, None, ) @@ -84,7 +97,7 @@ pub fn audio_transmitter_main( cpal::SampleFormat::F32 => cpal_output .build_output_stream( &cpal_output_config.into(), - move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire, &mut i), + move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire), failed_pcm_give, None, ) @@ -92,7 +105,7 @@ pub fn audio_transmitter_main( cpal::SampleFormat::F64 => cpal_output .build_output_stream( &cpal_output_config.into(), - move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire, &mut i), + move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire), failed_pcm_give, None, ) @@ -100,7 +113,7 @@ pub fn audio_transmitter_main( cpal::SampleFormat::U64 => cpal_output .build_output_stream( &cpal_output_config.into(), - move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire, &mut i), + move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire), failed_pcm_give, None, ) @@ -108,7 +121,7 @@ pub fn audio_transmitter_main( cpal::SampleFormat::I64 => cpal_output .build_output_stream( &cpal_output_config.into(), - move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire, &mut i), + move |pcm, _: &_| give_output_pcm::(pcm, &mut rx_for_wire), failed_pcm_give, None, ) @@ -121,14 +134,12 @@ pub fn audio_transmitter_main( output_stream .play() - .context("failed to start ingive audio stream")?; + .context("failed to start output audio stream")?; - loop{} - - Ok(()) + Ok(output_stream) } -fn give_output_pcm(pcm: &mut [T], channel: &mut Receiver, i: &mut f64) +fn give_output_pcm(pcm: &mut [T], channel: &mut Receiver) where T: Sample + std::fmt::Debug + FromSample + FromSample, { @@ -136,14 +147,12 @@ where for outgoing in pcm.iter_mut() { *outgoing = match channel.try_recv() { Ok(sample) => sample.to_sample::(), - Err(_) => (std::f64::consts::PI * 2.0*(*i)/(384000.0/100.0)).sin().to_sample::(), //T::EQUILIBRIUM, - /*Err(_) => { - signal.next().to_sample::() - }*/ + Err(_) => { + //warn!("rx_for_wire has no samples for us! carrier dead!"); + //warn!("are we able to produce samples quickly enough? CPU OK?"); + T::EQUILIBRIUM + } }; - *i = *i % 384000.0 + 1.0; - //if *i > 200000.0 { break; } } println!("gave them"); - //let mut ctr = 0usize; } diff --git a/src/dsp_common/carrier.rs b/src/dsp_common/carrier.rs new file mode 100644 index 0000000..a9bbaf8 --- /dev/null +++ b/src/dsp_common/carrier.rs @@ -0,0 +1,75 @@ +use cpal::Sample; + +const TAU: f64 = 2.0 * std::f64::consts::PI; + +pub struct TwoStateCarrier { + pub sample_rate: u32, + pub freq_low: u32, + pub freq_high: u32, + phase_low: u32, + phase_high: u32, +} + +type PcmSample = i64; + +pub trait Carrier { + fn byte_into_fsk_samples(&mut self, byte: &u8) -> Vec; +} + +impl Carrier for TwoStateCarrier { + fn byte_into_fsk_samples(&mut self, byte: &u8) -> Vec { + let mut bits: Vec = Vec::new(); + let mut out: Vec = Vec::new(); + + // MSb first + bits.push((byte ) & 0b0000_0001); + bits.push((byte >> 1) & 0b0000_0010); + bits.push((byte >> 2) & 0b0000_0100); + bits.push((byte >> 3) & 0b0000_1000); + bits.push((byte >> 4) & 0b0001_0000); + bits.push((byte >> 5) & 0b0010_0000); + bits.push((byte >> 6) & 0b0100_0000); + bits.push((byte >> 7) & 0b1000_0000); + + for bit in bits { + if bit == 0 { + while self.phase_low < self.sample_rate / self.freq_low { + out.push((self.phase_low as f64 * TAU * self.freq_low as f64 / self.sample_rate as f64).sin().to_sample::()); + self.phase_low += 1; + } + self.phase_low = self.phase_low % self.sample_rate; + } else if bit == 1 { + while self.phase_high < self.sample_rate / self.freq_high { + out.push((self.phase_high as f64 * TAU * self.freq_low as f64 / self.sample_rate as f64).sin().to_sample::()); + self.phase_high += 1; + } + self.phase_high = self.phase_high % self.sample_rate; + } + } + out + } +} + +impl TwoStateCarrier { + pub fn new(freq_low: u32, freq_high: u32, sample_rate: u32) -> Self { + TwoStateCarrier { + freq_low: freq_low, + freq_high: freq_high, + sample_rate: sample_rate, + phase_low: 0, + phase_high: 0, + } + } + fn freq_low(mut self, freq_low: u32) { + self.freq_low = freq_low; + } + fn freq_high(mut self, freq_high: u32) { + self.freq_high = freq_high; + } + fn phase_low(mut self, phase_low: u32) { + self.phase_low = phase_low; + } + fn phase_high(mut self, phase_high: u32) { + self.phase_high = phase_high; + } +} diff --git a/src/dsp_common/mod.rs b/src/dsp_common/mod.rs new file mode 100644 index 0000000..8fe1f10 --- /dev/null +++ b/src/dsp_common/mod.rs @@ -0,0 +1 @@ +pub mod carrier; diff --git a/src/dsp_outb/mod.rs b/src/dsp_outb/mod.rs new file mode 100644 index 0000000..09cb1fb --- /dev/null +++ b/src/dsp_outb/mod.rs @@ -0,0 +1,49 @@ +use anyhow::{Context, Result}; + +use cpal::Sample; + +use tracing::{error, info, trace, warn}; + +use tokio::sync::mpsc::{Receiver, Sender}; +use tokio::sync::mpsc::error::TryRecvError; + +use crate::task_msg::{RawEthFrameMessage, PcmSampleMessage}; +use crate::dsp_common::carrier::{Carrier, TwoStateCarrier}; + +pub async fn dsp_outb_main( + tx_for_wire: Sender, + mut rx_for_mod: Receiver, +) -> Result<()> { + trace!("pcm_outb task started"); + + let carrier_phase = 0_f64; + let carrier_low = 2400; + let carrier_high = 2500; + + let mut carrier = TwoStateCarrier::new(carrier_low, carrier_high, 384000); + + loop { + let eth_frame = match rx_for_mod.try_recv() { + Ok(x) => x, + Err(TryRecvError::Empty) => { + tx_for_wire.send(i64::EQUILIBRIUM).await?; + continue; + } + Err(TryRecvError::Disconnected) => { + Err(anyhow::Error::msg( + format!("rx_for_mod closed?! the tap task likely crashed"), + ))? + } + }; + + for byte in eth_frame { + for samp in carrier.byte_into_fsk_samples(&byte).iter() { + tx_for_wire.send(*samp).await?; + } + } + println!("done with that"); + + // TODO: fetch real sample rate + //(*carrier_phase * TAU * freq / sample_rate).sin() + } +} diff --git a/src/main.rs b/src/main.rs index 389876d..2d7889a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,9 +20,14 @@ use crate::audio_receiver::audio_receiver_main; mod audio_transmitter; use crate::audio_transmitter::audio_transmitter_main; +mod dsp_common; + mod dsp_inb; use crate::dsp_inb::dsp_inb_main; +mod dsp_outb; +use crate::dsp_outb::dsp_outb_main; + mod tap_junction; use crate::tap_junction::tap_junction_main; @@ -55,25 +60,25 @@ async fn main() -> Result<()> { let (tx_for_wire, rx_for_wire) = channel::(1); trace!("starting listener for audio on wire"); - audio_receiver_main(tx_for_demod, cpal_input) + let audio_in_stream = audio_receiver_main(tx_for_demod, &cpal_input) .context("listener for audio on wire has failed to start")?; let mut tasks = tokio::task::JoinSet::new(); - let task_dsp_inb = tasks.spawn(async move { - trace!("starting inbound audio demodulator"); - dsp_inb_main(tx_for_eth_inb, rx_for_demod).await - }); + //let task_dsp_inb = tasks.spawn(async move { + // trace!("starting inbound audio demodulator"); + // dsp_inb_main(tx_for_eth_inb, rx_for_demod).await + //}); let task_tap_junction = tasks.spawn(async move { trace!("Starting tap manager"); tap_junction_main(tx_for_mod, rx_for_eth_inb).await }); - //let task_dsp_outb = tasks.spawn(async move { - // trace!("Starting outbound audio modulator"); - // dsp_outb_main(tx_for_wire, rx_for_mod).await - //}); + let task_dsp_outb = tasks.spawn(async move { + trace!("Starting outbound audio modulator"); + dsp_outb_main(tx_for_wire, rx_for_mod).await + }); trace!("Starting audio sender"); - audio_transmitter_main(rx_for_wire, cpal_output) + let audio_out_stream = audio_transmitter_main(rx_for_wire, &cpal_output) .context("transmitter for audio on wire has failed to start")?; while let Some(task_result) = tasks.join_next().await { diff --git a/src/wire_fmt/mod.rs b/src/wire_fmt/mod.rs index 6142e05..9c4a9a4 100644 --- a/src/wire_fmt/mod.rs +++ b/src/wire_fmt/mod.rs @@ -1,5 +1,5 @@ mod cap; -pub use cap::*; +pub use self::cap::*; mod wire_msg; -pub use wire_msg::*; +pub use self::wire_msg::*;