Files
oxydsp/example/src/main.rs
2026-03-17 17:34:42 +01:00

167 lines
4.3 KiB
Rust

use std::collections::VecDeque;
use std::fmt::Display;
use std::fs::File;
use std::io::Write;
use std::sync::mpmc::sync_channel;
use std::sync::mpsc;
use eframe::NativeOptions;
use egui_plot::Line;
use egui_plot::PlotPoints;
use num::Complex;
use oxydsp_dsp::blocks::math::basic::Multiplier;
use oxydsp_dsp::blocks::synthesis::Nco;
use oxydsp_dsp::blocks::synthesis::OscillatorSource;
use oxydsp_dsp::blocks::utilities::adapters::Map;
use oxydsp_dsp::blocks::utilities::adapters::Repeat;
use oxydsp_dsp::blocks::utilities::channels::TxSink;
use oxydsp_dsp::blocks::utilities::iter::IterSource;
use oxydsp_dsp::units::DigitalFrequency;
use oxydsp_flowgraph::BlockIO;
use oxydsp_flowgraph::block::Block;
use oxydsp_flowgraph::block::BlockResult;
use oxydsp_flowgraph::edge::In;
use oxydsp_flowgraph::edge::PopIterable;
use oxydsp_flowgraph::flowgraph;
use oxydsp_flowgraph::graph::FlowGraph;
#[derive(BlockIO)]
pub struct Printer<T: 'static>
{
#[input]
input: In<T>,
n: usize,
}
impl<T: 'static> Printer<T>
{
pub fn new(input: In<T>) -> Self
{
Self { input, n: 0 }
}
}
impl<T: 'static> Block for Printer<T>
where
T: Display,
{
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
for x in self.input.pop_iter()
{
if self.n.is_multiple_of(2usize.pow(20))
{
println!("{}", x);
self.n = 0;
}
self.n += 1;
}
BlockResult::Ok
}
}
fn main()
{
let sample_rate = 48_000;
let sample_per_symbol = 96;
let deviation = DigitalFrequency::from_time_frequency(500., sample_rate as f64);
let carrier = DigitalFrequency::from_time_frequency(1000., sample_rate as f64);
let data = (0..255u8).flat_map(to_bits).collect::<Vec<_>>();
let (bit_stream, bits) = IterSource::new(data.into_iter());
let (to_freq, freq) = Map::new(bits, move |x| [-deviation, deviation][x as usize]);
let (repeat, freq) = Repeat::new(freq, sample_per_symbol);
let (base_oscillator, baseband) = Nco::<f32>::new(freq);
let (local_oscillator, lo) = OscillatorSource::<f32>::new(carrier.into());
let (frontend, passband) = Multiplier::new(baseband, lo);
let (tx, rx) = mpsc::channel::<Complex<f32>>();
let sink = TxSink::new(passband, tx);
let graph = flowgraph![
bit_stream,
to_freq,
repeat,
base_oscillator,
local_oscillator,
frontend,
sink,
];
File::create("out.dot")
.unwrap()
.write_all(graph.get_dot().as_bytes())
.unwrap();
let j = graph.run();
let mut output = vec![];
while let Ok(x) = rx.recv()
{
output.push(x);
}
let _ = j.join();
// Write signal
let spec = hound::WavSpec {
channels: 1,
sample_rate,
bits_per_sample: 16,
sample_format: hound::SampleFormat::Int,
};
let mut writer = hound::WavWriter::create("mod.wav", spec).unwrap();
for x in output.iter()
{
let amplitude = i16::MAX as f32;
writer.write_sample((x.re * amplitude) as i16).unwrap();
}
writer.finalize().unwrap();
//
eframe::run_simple_native("Plot", NativeOptions::default(), move |ctx, _frame| {
egui::CentralPanel::default().show(ctx, |ui| {
egui_plot::Plot::new("hello").show(ui, |plot_ui| {
plot_ui.line(Line::new(
"samples",
output
.iter()
.enumerate()
.map(|(i, s)| [i as f64, s.re as f64])
.collect::<PlotPoints>(),
));
});
ctx.request_repaint();
});
})
.unwrap();
}
pub fn to_bits(n: u8) -> [bool; 8]
{
[
(n & 1) == 1,
(n >> 1) & 1 == 1,
(n >> 2) & 1 == 1,
(n >> 3) & 1 == 1,
(n >> 4) & 1 == 1,
(n >> 5) & 1 == 1,
(n >> 6) & 1 == 1,
(n >> 7) & 1 == 1,
]
}
pub fn from_bits(n: [bool; 8]) -> u8
{
(n[0] as u8)
| ((n[1] as u8) << 1)
| ((n[2] as u8) << 2)
| ((n[3] as u8) << 3)
| ((n[4] as u8) << 4)
| ((n[5] as u8) << 5)
| ((n[6] as u8) << 6)
| ((n[7] as u8) << 7)
}
pub fn gaussian(sigma: f32, t: f32) -> f32
{
let sq = (t - 0.5) / sigma;
(-sq * sq).exp()
}