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 { #[input] input: In, n: usize, } impl Printer { pub fn new(input: In) -> Self { Self { input, n: 0 } } } impl Block for Printer 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::>(); 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::::new(freq); let (local_oscillator, lo) = OscillatorSource::::new(carrier.into()); let (frontend, passband) = Multiplier::new(baseband, lo); let (tx, rx) = mpsc::channel::>(); 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::(), )); }); 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() }