Compare commits
3 Commits
8efb9c031e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 497cc3b61c | |||
| 7b3bd7e2e5 | |||
| 3d42a7b61b |
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,3 +1,6 @@
|
|||||||
/target
|
/target
|
||||||
test.iq
|
# test.iq
|
||||||
test.py
|
test.py
|
||||||
|
/frames
|
||||||
|
*.png
|
||||||
|
*.mp4
|
||||||
|
|||||||
214
Cargo.lock
generated
214
Cargo.lock
generated
@ -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"
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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)),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|||||||
201
src/main.rs
201
src/main.rs
@ -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),
|
||||||
|
),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user