output dsp (not done yet)

This commit is contained in:
TerraMaster85 2024-12-16 21:06:39 -05:00
parent 1ecdbeb75f
commit bc7a8860fd
7 changed files with 196 additions and 57 deletions

View file

@ -11,8 +11,8 @@ use crate::task_msg::PcmFrameMessage;
pub fn audio_receiver_main( pub fn audio_receiver_main(
tx_for_demod: Sender<PcmFrameMessage>, tx_for_demod: Sender<PcmFrameMessage>,
cpal_input: cpal::Device, cpal_input: &cpal::Device,
) -> Result<()> { ) -> Result<cpal::Stream> {
trace!("audio_receiver started"); trace!("audio_receiver started");
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.")?
@ -102,7 +102,7 @@ pub fn audio_receiver_main(
input_stream.play().context("failed to start intake audio stream")?; input_stream.play().context("failed to start intake audio stream")?;
Ok(()) Ok(input_stream)
} }
fn take_input_pcm<T>(pcm: &[T], channel: &Sender<PcmFrameMessage>) where T: Sample + std::fmt::Debug, i64: FromSample<T> { fn take_input_pcm<T>(pcm: &[T], channel: &Sender<PcmFrameMessage>) where T: Sample + std::fmt::Debug, i64: FromSample<T> {

View file

@ -3,8 +3,6 @@ use anyhow::{Context, Result};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use cpal::{FromSample, Sample, SampleFormat}; use cpal::{FromSample, Sample, SampleFormat};
use dasp_signal::Signal;
use tracing::{error, info, trace, warn}; use tracing::{error, info, trace, warn};
use tokio::sync::mpsc::Receiver; use tokio::sync::mpsc::Receiver;
@ -13,13 +11,13 @@ use crate::task_msg::{PcmFrameMessage, PcmSampleMessage};
pub fn audio_transmitter_main( pub fn audio_transmitter_main(
mut rx_for_wire: Receiver<PcmSampleMessage>, mut rx_for_wire: Receiver<PcmSampleMessage>,
cpal_output: cpal::Device, cpal_output: &cpal::Device,
) -> Result<()> { ) -> Result<cpal::Stream> {
trace!("audio_transmitter started"); trace!("audio_transmitter started");
let cpal_output_config = cpal_output.supported_output_configs() 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.")? .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| { .max_by_key(|cfg| {
println!("AVAIL RATE: {:?}, {:?}, {:?}", cfg.sample_format(), cfg.min_sample_rate(), cfg.max_sample_rate()); if cfg.channels() > 1 { return -999; }
match cfg.sample_format() { match cfg.sample_format() {
SampleFormat::U8 => 10, SampleFormat::U8 => 10,
SampleFormat::I8 => 11, SampleFormat::I8 => 11,
@ -34,25 +32,24 @@ pub fn audio_transmitter_main(
x => { warn!("Backend offered unknown sample format {x}",); -999 } x => { warn!("Backend offered unknown sample format {x}",); -999 }
} }
}).expect("output device has no supported configurations available") }).expect("output device has no supported configurations available")
.with_sample_rate(cpal::SampleRate(384000));//max_sample_rate(); .with_max_sample_rate();
info!( info!(
"output samples are {} @ {}hz", "output samples are {} @ {}hz on {} channels",
&cpal_output_config.sample_format(), &cpal_output_config.sample_format(),
&cpal_output_config.sample_rate().0, &cpal_output_config.sample_rate().0,
&cpal_output_config.channels(),
); );
let failed_pcm_give = move |e| { let failed_pcm_give = move |e| {
warn!("dropped some PCM data on output stream?! {}", e); warn!("dropped some PCM data on output stream?! {}", e);
}; };
let mut i = 0f64;
let output_stream = match cpal_output_config.sample_format() { let output_stream = match cpal_output_config.sample_format() {
cpal::SampleFormat::U8 => cpal_output cpal::SampleFormat::U8 => cpal_output
.build_output_stream( .build_output_stream(
&cpal_output_config.into(), &cpal_output_config.into(),
move |pcm, _: &_| give_output_pcm::<u8>(pcm, &mut rx_for_wire, &mut i), move |pcm, _: &_| give_output_pcm::<u8>(pcm, &mut rx_for_wire),
failed_pcm_give, failed_pcm_give,
None, None,
) )
@ -60,7 +57,15 @@ pub fn audio_transmitter_main(
cpal::SampleFormat::I8 => cpal_output cpal::SampleFormat::I8 => cpal_output
.build_output_stream( .build_output_stream(
&cpal_output_config.into(), &cpal_output_config.into(),
move |pcm, _: &_| give_output_pcm::<i8>(pcm, &mut rx_for_wire, &mut i), move |pcm, _: &_| give_output_pcm::<i8>(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::<u16>(pcm, &mut rx_for_wire),
failed_pcm_give, failed_pcm_give,
None, None,
) )
@ -68,7 +73,15 @@ pub fn audio_transmitter_main(
cpal::SampleFormat::I16 => cpal_output cpal::SampleFormat::I16 => cpal_output
.build_output_stream( .build_output_stream(
&cpal_output_config.into(), &cpal_output_config.into(),
move |pcm, _: &_| give_output_pcm::<i16>(pcm, &mut rx_for_wire, &mut i), move |pcm, _: &_| give_output_pcm::<i16>(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::<u32>(pcm, &mut rx_for_wire),
failed_pcm_give, failed_pcm_give,
None, None,
) )
@ -76,7 +89,7 @@ pub fn audio_transmitter_main(
cpal::SampleFormat::I32 => cpal_output cpal::SampleFormat::I32 => cpal_output
.build_output_stream( .build_output_stream(
&cpal_output_config.into(), &cpal_output_config.into(),
move |pcm, _: &_| give_output_pcm::<i32>(pcm, &mut rx_for_wire, &mut i), move |pcm, _: &_| give_output_pcm::<i32>(pcm, &mut rx_for_wire),
failed_pcm_give, failed_pcm_give,
None, None,
) )
@ -84,7 +97,7 @@ pub fn audio_transmitter_main(
cpal::SampleFormat::F32 => cpal_output cpal::SampleFormat::F32 => cpal_output
.build_output_stream( .build_output_stream(
&cpal_output_config.into(), &cpal_output_config.into(),
move |pcm, _: &_| give_output_pcm::<f32>(pcm, &mut rx_for_wire, &mut i), move |pcm, _: &_| give_output_pcm::<f32>(pcm, &mut rx_for_wire),
failed_pcm_give, failed_pcm_give,
None, None,
) )
@ -92,7 +105,7 @@ pub fn audio_transmitter_main(
cpal::SampleFormat::F64 => cpal_output cpal::SampleFormat::F64 => cpal_output
.build_output_stream( .build_output_stream(
&cpal_output_config.into(), &cpal_output_config.into(),
move |pcm, _: &_| give_output_pcm::<f64>(pcm, &mut rx_for_wire, &mut i), move |pcm, _: &_| give_output_pcm::<f64>(pcm, &mut rx_for_wire),
failed_pcm_give, failed_pcm_give,
None, None,
) )
@ -100,7 +113,7 @@ pub fn audio_transmitter_main(
cpal::SampleFormat::U64 => cpal_output cpal::SampleFormat::U64 => cpal_output
.build_output_stream( .build_output_stream(
&cpal_output_config.into(), &cpal_output_config.into(),
move |pcm, _: &_| give_output_pcm::<u64>(pcm, &mut rx_for_wire, &mut i), move |pcm, _: &_| give_output_pcm::<u64>(pcm, &mut rx_for_wire),
failed_pcm_give, failed_pcm_give,
None, None,
) )
@ -108,7 +121,7 @@ pub fn audio_transmitter_main(
cpal::SampleFormat::I64 => cpal_output cpal::SampleFormat::I64 => cpal_output
.build_output_stream( .build_output_stream(
&cpal_output_config.into(), &cpal_output_config.into(),
move |pcm, _: &_| give_output_pcm::<i64>(pcm, &mut rx_for_wire, &mut i), move |pcm, _: &_| give_output_pcm::<i64>(pcm, &mut rx_for_wire),
failed_pcm_give, failed_pcm_give,
None, None,
) )
@ -121,14 +134,12 @@ pub fn audio_transmitter_main(
output_stream output_stream
.play() .play()
.context("failed to start ingive audio stream")?; .context("failed to start output audio stream")?;
loop{} Ok(output_stream)
Ok(())
} }
fn give_output_pcm<T>(pcm: &mut [T], channel: &mut Receiver<PcmSampleMessage>, i: &mut f64) fn give_output_pcm<T>(pcm: &mut [T], channel: &mut Receiver<PcmSampleMessage>)
where where
T: Sample + std::fmt::Debug + FromSample<i64> + FromSample<f64>, T: Sample + std::fmt::Debug + FromSample<i64> + FromSample<f64>,
{ {
@ -136,14 +147,12 @@ where
for outgoing in pcm.iter_mut() { for outgoing in pcm.iter_mut() {
*outgoing = match channel.try_recv() { *outgoing = match channel.try_recv() {
Ok(sample) => sample.to_sample::<T>(), Ok(sample) => sample.to_sample::<T>(),
Err(_) => (std::f64::consts::PI * 2.0*(*i)/(384000.0/100.0)).sin().to_sample::<T>(), //T::EQUILIBRIUM, Err(_) => {
/*Err(_) => { //warn!("rx_for_wire has no samples for us! carrier dead!");
signal.next().to_sample::<T>() //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"); println!("gave them");
//let mut ctr = 0usize;
} }

75
src/dsp_common/carrier.rs Normal file
View file

@ -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<PcmSample>;
}
impl Carrier for TwoStateCarrier {
fn byte_into_fsk_samples(&mut self, byte: &u8) -> Vec<PcmSample> {
let mut bits: Vec<u8> = Vec::new();
let mut out: Vec<i64> = 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::<i64>());
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::<i64>());
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;
}
}

1
src/dsp_common/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod carrier;

49
src/dsp_outb/mod.rs Normal file
View file

@ -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<PcmSampleMessage>,
mut rx_for_mod: Receiver<RawEthFrameMessage>,
) -> 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()
}
}

View file

@ -20,9 +20,14 @@ use crate::audio_receiver::audio_receiver_main;
mod audio_transmitter; mod audio_transmitter;
use crate::audio_transmitter::audio_transmitter_main; use crate::audio_transmitter::audio_transmitter_main;
mod dsp_common;
mod dsp_inb; mod dsp_inb;
use crate::dsp_inb::dsp_inb_main; use crate::dsp_inb::dsp_inb_main;
mod dsp_outb;
use crate::dsp_outb::dsp_outb_main;
mod tap_junction; mod tap_junction;
use crate::tap_junction::tap_junction_main; use crate::tap_junction::tap_junction_main;
@ -55,25 +60,25 @@ async fn main() -> Result<()> {
let (tx_for_wire, rx_for_wire) = channel::<PcmSampleMessage>(1); let (tx_for_wire, rx_for_wire) = channel::<PcmSampleMessage>(1);
trace!("starting listener for audio on wire"); 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")?; .context("listener for audio on wire has failed to start")?;
let mut tasks = tokio::task::JoinSet::new(); let mut tasks = tokio::task::JoinSet::new();
let task_dsp_inb = tasks.spawn(async move { //let task_dsp_inb = tasks.spawn(async move {
trace!("starting inbound audio demodulator"); // trace!("starting inbound audio demodulator");
dsp_inb_main(tx_for_eth_inb, rx_for_demod).await // dsp_inb_main(tx_for_eth_inb, rx_for_demod).await
}); //});
let task_tap_junction = tasks.spawn(async move { let task_tap_junction = tasks.spawn(async move {
trace!("Starting tap manager"); trace!("Starting tap manager");
tap_junction_main(tx_for_mod, rx_for_eth_inb).await tap_junction_main(tx_for_mod, rx_for_eth_inb).await
}); });
//let task_dsp_outb = tasks.spawn(async move { let task_dsp_outb = tasks.spawn(async move {
// trace!("Starting outbound audio modulator"); trace!("Starting outbound audio modulator");
// dsp_outb_main(tx_for_wire, rx_for_mod).await dsp_outb_main(tx_for_wire, rx_for_mod).await
//}); });
trace!("Starting audio sender"); 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")?; .context("transmitter for audio on wire has failed to start")?;
while let Some(task_result) = tasks.join_next().await { while let Some(task_result) = tasks.join_next().await {

View file

@ -1,5 +1,5 @@
mod cap; mod cap;
pub use cap::*; pub use self::cap::*;
mod wire_msg; mod wire_msg;
pub use wire_msg::*; pub use self::wire_msg::*;