Compare commits

...

2 Commits

Author SHA1 Message Date
7b3bd7e2e5 sync 2026-06-20 10:29:07 +02:00
3d42a7b61b sync 2026-06-18 20:48:54 +02:00
15 changed files with 243 additions and 241 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
/target /target
test.iq test.iq
test.py test.py
/frames
*.png
*.mp4

214
Cargo.lock generated
View File

@ -635,9 +635,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.11.1" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593"
[[package]] [[package]]
name = "calloop" name = "calloop"
@ -1421,15 +1421,13 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.4.2" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"r-efi 6.0.0", "r-efi 6.0.0",
"wasip2",
"wasip3",
] ]
[[package]] [[package]]
@ -1603,12 +1601,6 @@ version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.5.2" version = "0.5.2"
@ -1709,12 +1701,6 @@ dependencies = [
"zerovec", "zerovec",
] ]
[[package]]
name = "id-arena"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]] [[package]]
name = "idna" name = "idna"
version = "1.1.0" version = "1.1.0"
@ -1772,9 +1758,9 @@ dependencies = [
[[package]] [[package]]
name = "imgref" name = "imgref"
version = "1.12.1" version = "1.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40fac9d56ed6437b198fddba683305e8e2d651aa42647f00f5ae542e7f5c94a2" checksum = "89194689a993ab15268672e99e7b0e19da2da3268ac682e8f02d29d4d1434cd7"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
@ -1784,8 +1770,6 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.17.1", "hashbrown 0.17.1",
"serde",
"serde_core",
] ]
[[package]] [[package]]
@ -1821,12 +1805,6 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]] [[package]]
name = "jni" name = "jni"
version = "0.22.4" version = "0.22.4"
@ -1935,12 +1913,6 @@ dependencies = [
"smallvec", "smallvec",
] ]
[[package]]
name = "leb128fmt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]] [[package]]
name = "lebe" name = "lebe"
version = "0.5.3" version = "0.5.3"
@ -2859,16 +2831,6 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa"
[[package]]
name = "prettyplease"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn",
]
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "3.5.0" version = "3.5.0"
@ -3259,19 +3221,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "serde_json"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]] [[package]]
name = "serde_repr" name = "serde_repr"
version = "0.1.20" version = "0.1.20"
@ -3468,9 +3417,9 @@ checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.117" version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3495,7 +3444,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [ dependencies = [
"fastrand", "fastrand",
"getrandom 0.4.2", "getrandom 0.4.3",
"once_cell", "once_cell",
"rustix 1.1.4", "rustix 1.1.4",
"windows-sys 0.61.2", "windows-sys 0.61.2",
@ -3705,12 +3654,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]] [[package]]
name = "unit-prefix" name = "unit-prefix"
version = "0.5.2" version = "0.5.2"
@ -3805,16 +3748,7 @@ version = "1.0.4+wasi-0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
dependencies = [ dependencies = [
"wit-bindgen 0.57.1", "wit-bindgen",
]
[[package]]
name = "wasip3"
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
dependencies = [
"wit-bindgen 0.51.0",
] ]
[[package]] [[package]]
@ -3872,40 +3806,6 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "wasm-encoder"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
dependencies = [
"leb128fmt",
"wasmparser",
]
[[package]]
name = "wasm-metadata"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
dependencies = [
"anyhow",
"indexmap",
"wasm-encoder",
"wasmparser",
]
[[package]]
name = "wasmparser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
dependencies = [
"bitflags 2.13.0",
"hashbrown 0.15.5",
"indexmap",
"semver",
]
[[package]] [[package]]
name = "wayland-backend" name = "wayland-backend"
version = "0.3.15" version = "0.3.15"
@ -4606,100 +4506,12 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "wit-bindgen"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
dependencies = [
"wit-bindgen-rust-macro",
]
[[package]] [[package]]
name = "wit-bindgen" name = "wit-bindgen"
version = "0.57.1" version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]]
name = "wit-bindgen-core"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
dependencies = [
"anyhow",
"heck",
"wit-parser",
]
[[package]]
name = "wit-bindgen-rust"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
dependencies = [
"anyhow",
"heck",
"indexmap",
"prettyplease",
"syn",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
]
[[package]]
name = "wit-bindgen-rust-macro"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
dependencies = [
"anyhow",
"prettyplease",
"proc-macro2",
"quote",
"syn",
"wit-bindgen-core",
"wit-bindgen-rust",
]
[[package]]
name = "wit-component"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
dependencies = [
"anyhow",
"bitflags 2.13.0",
"indexmap",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
dependencies = [
"anyhow",
"id-arena",
"indexmap",
"log",
"semver",
"serde",
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser",
]
[[package]] [[package]]
name = "writeable" name = "writeable"
version = "0.6.3" version = "0.6.3"
@ -4969,12 +4781,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
[[package]] [[package]]
name = "zune-core" name = "zune-core"
version = "0.5.1" version = "0.5.1"

BIN
frames/frame_0000.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 KiB

BIN
frames/frame_0001.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

BIN
frames/frame_0002.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

BIN
frames/frame_0003.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

BIN
frames/frame_0004.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

BIN
frames/frame_0005.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

BIN
frames/frame_0006.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 KiB

BIN
frames/output.mp4 Normal file

Binary file not shown.

1
frames/vid.sh Executable file
View File

@ -0,0 +1 @@
ffmpeg -framerate 30 -i frame_%04d.png -c:v libx264 -vf "format=yuv420p" output.mp4

View File

@ -4,9 +4,9 @@ use std::path::Path;
use crate::line_assembler::VideoFrame; use crate::line_assembler::VideoFrame;
// PAL // PAL: 1280 samples per line
const WIDTH: u32 = 1280; const WIDTH: u32 = 1280;
const HEIGHT: u32 = 288; const HEIGHT: u32 = 480; // NTSC (576 for PAL)
pub fn save_frames(frames: &[VideoFrame], output_dir: &str, sig_min: f32, sig_max: f32) { pub fn save_frames(frames: &[VideoFrame], output_dir: &str, sig_min: f32, sig_max: f32) {
fs::create_dir_all(output_dir).expect("Could not create output directory"); fs::create_dir_all(output_dir).expect("Could not create output directory");
@ -22,7 +22,6 @@ pub fn save_frames(frames: &[VideoFrame], output_dir: &str, sig_min: f32, sig_ma
let mut img = GrayImage::new(WIDTH, HEIGHT); let mut img = GrayImage::new(WIDTH, HEIGHT);
for y in 0..HEIGHT as usize { for y in 0..HEIGHT as usize {
// If the frame has fewer lines than HEIGHT, fill the rest with black
let line = frame.lines.get(y); let line = frame.lines.get(y);
for x in 0..WIDTH as usize { for x in 0..WIDTH as usize {

View File

@ -8,6 +8,8 @@ pub struct VideoFrame {
pub lines: Vec<VideoLine>, pub lines: Vec<VideoLine>,
} }
const LINES_PER_FRAME: usize = 480; // NTSC (576 for PAL)
pub struct LineAssembler<I> { pub struct LineAssembler<I> {
pub inner: I, pub inner: I,
pub current_line: Vec<Sample>, pub current_line: Vec<Sample>,
@ -37,22 +39,57 @@ where
self.current_line.push(s); self.current_line.push(s);
} }
Ok(SyncEvent::HSync) => { Ok(SyncEvent::HSync) => {
// Save the finished line
let line = VideoLine { let line = VideoLine {
samples: std::mem::take(&mut self.current_line), samples: std::mem::take(&mut self.current_line),
}; };
self.current_frame.push(line); self.current_frame.push(line);
}
Ok(SyncEvent::VSync) => { if self.current_frame.len() >= LINES_PER_FRAME {
// Frame finished
let frame = VideoFrame { let frame = VideoFrame {
lines: std::mem::take(&mut self.current_frame), lines: std::mem::take(&mut self.current_frame),
}; };
return Some(Ok(frame)); return Some(Ok(frame));
} }
}
Ok(SyncEvent::VSync) => {
// test without vsync
}
Err(e) => return Some(Err(e)), Err(e) => return Some(Err(e)),
} }
} }
} }
} }
// impl<I, E> Iterator for LineAssembler<I>
// where
// I: Iterator<Item = Result<SyncEvent, E>>,
// {
// type Item = Result<VideoFrame, E>;
//
// fn next(&mut self) -> Option<Self::Item> {
// loop {
// match self.inner.next()? {
// Ok(SyncEvent::VideoSample(s)) => {
// self.current_line.push(s);
// }
// Ok(SyncEvent::HSync) => {
// // Save the finished line
// let line = VideoLine {
// samples: std::mem::take(&mut self.current_line),
// };
//
// self.current_frame.push(line);
// }
// Ok(SyncEvent::VSync) => {
// // Frame finished
// let frame = VideoFrame {
// lines: std::mem::take(&mut self.current_frame),
// };
// self.current_line.clear();
// return Some(Ok(frame));
// }
// Err(e) => return Some(Err(e)),
// }
// }
// }
// }

View File

@ -1,7 +1,7 @@
use crate::fm_demod::Sample; use crate::fm_demod::Sample;
use crate::iq_reader::FileSource; use crate::iq_reader::FileSource;
use crate::pipeline::{AfterDemodPiplineExt, DspPipelineExt, SyncPipelineExt}; use crate::pipeline::{AfterDemodPiplineExt, DspPipelineExt, SyncPipelineExt};
use egui_plot::{Line, Plot}; use egui_plot::{HLine, Line, Plot, VLine};
use indicatif::ProgressIterator; use indicatif::ProgressIterator;
mod agc; mod agc;
@ -17,16 +17,84 @@ mod sync;
mod utils; mod utils;
const SAMPLE_RATE: f32 = 20_000_000.0; const SAMPLE_RATE: f32 = 20_000_000.0;
const SYNC_THRESHOLD: f32 = -0.3; const SYNC_THRESHOLD: f32 = -0.4;
const LOWPASS_ALPHA: f32 = 0.6; const LOWPASS_ALPHA: f32 = 0.7;
// fn main() -> eframe::Result {
fn main() { fn main() {
// fn main() {
let taps: [f32; 64] = [
-0.00015813,
-0.00047836,
-0.00080166,
-0.00110309,
-0.00132172,
-0.00136203,
-0.00111203,
-0.00047680,
0.00057973,
0.00199526,
0.00358456,
0.00504093,
0.00597041,
0.00595859,
0.00466189,
0.00190795,
-0.00221520,
-0.00730261,
-0.01262639,
-0.01719077,
-0.01984753,
-0.01945971,
-0.01509023,
-0.00618502,
0.00728221,
0.02473253,
0.04499119,
0.06638976,
0.08695132,
0.10463402,
0.11759778,
0.12445312,
0.12445312,
0.11759778,
0.10463402,
0.08695132,
0.06638976,
0.04499119,
0.02473253,
0.00728221,
-0.00618502,
-0.01509023,
-0.01945971,
-0.01984753,
-0.01719077,
-0.01262639,
-0.00730261,
-0.00221520,
0.00190795,
0.00466189,
0.00595859,
0.00597041,
0.00504093,
0.00358456,
0.00199526,
0.00057973,
-0.00047680,
-0.00111203,
-0.00136203,
-0.00132172,
-0.00110309,
-0.00080166,
-0.00047836,
-0.00015813,
];
let source = FileSource::new("test.iq", 32769).unwrap(); let source = FileSource::new("test.iq", 32769).unwrap();
let samples: Vec<f32> = source let samples: Vec<f32> = source
.skip(10_000) .skip(10_000)
.take(100_000) .take(10_000)
.agc(SAMPLE_RATE, 1.0, 0.001, 100.0) .agc(SAMPLE_RATE, 1.0, 0.001, 100.0)
// .fir(taps, 1)
.demodulate() .demodulate()
.dc_block(0.997) .dc_block(0.997)
.lowpass(LOWPASS_ALPHA) .lowpass(LOWPASS_ALPHA)
@ -41,12 +109,12 @@ fn main() {
let source = FileSource::new("test.iq", 32769).unwrap(); let source = FileSource::new("test.iq", 32769).unwrap();
// let taps = [0.5; 64];
let frames: Vec<_> = source let frames: Vec<_> = source
.take(50_000_000) .skip(10_000)
.take(5_000_000)
.progress() .progress()
.agc(SAMPLE_RATE, 1.0, 0.001, 100.0) .agc(SAMPLE_RATE, 1.0, 0.001, 100.0)
// .fir(taps, 1)
.demodulate() .demodulate()
.dc_block(0.997) .dc_block(0.997)
.lowpass(LOWPASS_ALPHA) .lowpass(LOWPASS_ALPHA)
@ -59,21 +127,63 @@ fn main() {
frame::save_frames(&frames, "frames", min, max); frame::save_frames(&frames, "frames", min, max);
// let source2 = FileSource::new("test.iq", 32769).unwrap(); let source = FileSource::new("test.iq", 32769).unwrap();
// let samples: Vec<Sample> = source
// let samples: Vec<Sample> = source2 .skip(40_000)
// .skip(10_000) .take(1_000_000)
// .take(10_000) .progress()
// .progress() .agc(20_000_000.0, 1.0, 0.001, 100.0)
// .agc(20_000_000.0, 1.0, 0.001, 100.0) // .fir::<64>(taps, 1)
// // .fir::<64>(taps, 4) .demodulate()
// .demodulate() .dc_block(0.997)
// .dc_block(0.997) .lowpass(0.75)
// .lowpass(0.75) .filter_map(|r| r.ok())
// .filter_map(|r| r.ok()) .collect();
// .collect();
// let source = FileSource::new("test.iq", 32769).unwrap();
// eframe::run_ui_native("DSP", Default::default(), move |ui, _frame| { let sync_events: Vec<(usize, &str)> = {
use crate::sync::SyncEvent;
let mut events = Vec::new();
let source = FileSource::new("test.iq", 32769).unwrap();
let mut separator = source
.progress()
.skip(40_000)
.take(1_000_000)
.agc(SAMPLE_RATE, 1.0, 0.001, 100.0)
.demodulate()
.dc_block(0.997)
.lowpass(LOWPASS_ALPHA)
.sync_separate(SAMPLE_RATE, SYNC_THRESHOLD);
while let Some(r) = separator.next() {
if let Ok(evt) = r {
let pos = separator.samples_consumed;
match evt {
SyncEvent::HSync => events.push((pos, "h")),
SyncEvent::VSync => {
events.push((pos, "v"));
println!("vsync\n")
}
SyncEvent::VideoSample(_) => {}
}
}
}
events
};
let _ = eframe::run_native(
"DSP debug",
Default::default(),
Box::new(move |_cc| {
Ok(Box::new(DebugApp {
samples,
sync_events,
}))
}),
);
// let _ = eframe::run_ui_native("DSP", Default::default(), move |ui, _frame| {
// egui::CentralPanel::default().show(ui, |ui| { // egui::CentralPanel::default().show(ui, |ui| {
// Plot::new("plot").show(ui, |plot_ui| { // Plot::new("plot").show(ui, |plot_ui| {
// plot_ui.line(Line::new( // plot_ui.line(Line::new(
@ -87,5 +197,48 @@ fn main() {
// )) // ))
// }) // })
// }); // });
// }) // });
}
struct DebugApp {
samples: Vec<Sample>,
sync_events: Vec<(usize, &'static str)>,
}
impl eframe::App for DebugApp {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
Plot::new("plot").show(ui, |plot_ui| {
plot_ui.line(Line::new(
"Signal",
self.samples
.iter()
.enumerate()
.map(|(i, x)| [i as f64, *x as f64])
.collect::<Vec<_>>(),
));
plot_ui.hline(
HLine::new("Threshold", SYNC_THRESHOLD as f64)
.color(egui::Color32::YELLOW)
.width(4.0),
);
for (pos, kind) in &self.sync_events {
let x = *pos as f64;
match *kind {
"h" => plot_ui.vline(
VLine::new("HSync", x)
.color(egui::Color32::from_rgb(80, 160, 255))
.width(4.0),
),
"v" => plot_ui.vline(
VLine::new("VSync", x)
.color(egui::Color32::BROWN)
.width(10.0),
),
_ => {}
}
}
});
}
} }

View File

@ -19,6 +19,7 @@ pub struct SyncSeparator<I> {
pub hsync_min: usize, pub hsync_min: usize,
pub hsync_max: usize, pub hsync_max: usize,
pub vsync_min: usize, pub vsync_min: usize,
pub samples_consumed: usize,
} }
impl<I> SyncSeparator<I> { impl<I> SyncSeparator<I> {
@ -30,13 +31,15 @@ impl<I> SyncSeparator<I> {
inner, inner,
state: SyncState::Active, state: SyncState::Active,
sync_threshold, sync_threshold,
hsync_min: us(3.5), hsync_min: us(2.0),
hsync_max: us(6.0), hsync_max: us(10.0),
vsync_min: us(25.0), vsync_min: us(25.0),
samples_consumed: 0,
} }
} }
pub fn process_sample(&mut self, sample: Sample) -> Option<SyncEvent> { pub fn process_sample(&mut self, sample: Sample) -> Option<SyncEvent> {
self.samples_consumed += 1;
match self.state { match self.state {
SyncState::Active => { SyncState::Active => {
if sample < self.sync_threshold { if sample < self.sync_threshold {
@ -58,7 +61,7 @@ impl<I> SyncSeparator<I> {
} else if pulse_len >= self.hsync_min && pulse_len <= self.hsync_max { } else if pulse_len >= self.hsync_min && pulse_len <= self.hsync_max {
Some(SyncEvent::HSync) Some(SyncEvent::HSync)
} else { } else {
None Some(SyncEvent::VideoSample(sample))
} }
} }
} }