output dsp (not done yet)
This commit is contained in:
parent
1ecdbeb75f
commit
bc7a8860fd
7 changed files with 196 additions and 57 deletions
|
@ -11,8 +11,8 @@ use crate::task_msg::PcmFrameMessage;
|
|||
|
||||
pub fn audio_receiver_main(
|
||||
tx_for_demod: Sender<PcmFrameMessage>,
|
||||
cpal_input: cpal::Device,
|
||||
) -> Result<()> {
|
||||
cpal_input: &cpal::Device,
|
||||
) -> Result<cpal::Stream> {
|
||||
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<T>(pcm: &[T], channel: &Sender<PcmFrameMessage>) where T: Sample + std::fmt::Debug, i64: FromSample<T> {
|
||||
|
|
|
@ -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<PcmSampleMessage>,
|
||||
cpal_output: cpal::Device,
|
||||
) -> Result<()> {
|
||||
cpal_output: &cpal::Device,
|
||||
) -> Result<cpal::Stream> {
|
||||
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::<u8>(pcm, &mut rx_for_wire, &mut i),
|
||||
move |pcm, _: &_| give_output_pcm::<u8>(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::<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,
|
||||
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::<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,
|
||||
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::<i32>(pcm, &mut rx_for_wire, &mut i),
|
||||
move |pcm, _: &_| give_output_pcm::<i32>(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::<f32>(pcm, &mut rx_for_wire, &mut i),
|
||||
move |pcm, _: &_| give_output_pcm::<f32>(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::<f64>(pcm, &mut rx_for_wire, &mut i),
|
||||
move |pcm, _: &_| give_output_pcm::<f64>(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::<u64>(pcm, &mut rx_for_wire, &mut i),
|
||||
move |pcm, _: &_| give_output_pcm::<u64>(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::<i64>(pcm, &mut rx_for_wire, &mut i),
|
||||
move |pcm, _: &_| give_output_pcm::<i64>(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<T>(pcm: &mut [T], channel: &mut Receiver<PcmSampleMessage>, i: &mut f64)
|
||||
fn give_output_pcm<T>(pcm: &mut [T], channel: &mut Receiver<PcmSampleMessage>)
|
||||
where
|
||||
T: Sample + std::fmt::Debug + FromSample<i64> + FromSample<f64>,
|
||||
{
|
||||
|
@ -136,14 +147,12 @@ where
|
|||
for outgoing in pcm.iter_mut() {
|
||||
*outgoing = match channel.try_recv() {
|
||||
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(_) => {
|
||||
signal.next().to_sample::<T>()
|
||||
}*/
|
||||
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;
|
||||
}
|
||||
|
|
75
src/dsp_common/carrier.rs
Normal file
75
src/dsp_common/carrier.rs
Normal 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
1
src/dsp_common/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod carrier;
|
49
src/dsp_outb/mod.rs
Normal file
49
src/dsp_outb/mod.rs
Normal 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()
|
||||
}
|
||||
}
|
25
src/main.rs
25
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::<PcmSampleMessage>(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 {
|
||||
|
|
|
@ -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::*;
|
||||
|
|
Loading…
Reference in a new issue