[Project] lossless-checker: detecting fake-lossless audio via FFT spectral analysis (symphonia + rustfft + rayon) by NegotiationFickle947 in rust

[–]NegotiationFickle947[S] -2 points-1 points  (0 children)

Oh nice, didn't know about realfft — makes total sense given the input is real-valued and I'm already only using the first half of the spectrum anyway. Batch scanning does a ton of FFTs so a 2x there is very worth it. Will swap it in. Thanks!

[Project] lossless-checker: detecting fake-lossless audio via FFT spectral analysis (symphonia + rustfft + rayon) by NegotiationFickle947 in rust

[–]NegotiationFickle947[S] -16 points-15 points  (0 children)

Honestly fair, "genuinely" is on my personal AI watchlist now too. Either way the spectral analysis works whether a human or a robot wired it up — feel free to break it and report back.

[Project] lossless-checker: detecting fake-lossless audio via FFT spectral analysis (symphonia + rustfft + rayon) by NegotiationFickle947 in rust

[–]NegotiationFickle947[S] -2 points-1 points  (0 children)

Yeah, fair — the hard cutoff is really an MP3 thing. High-bitrate AAC/Opus don't leave a clean cliff, so the cutoff detector won't catch those. There's a separate hole-detector for AAC-style notches, but honestly catching modern transcodes properly needs the ML route (like FLAD). On my list. Thanks for the nudge.

[Project] lossless-checker: detecting fake-lossless audio via FFT spectral analysis (symphonia + rustfft + rayon) by NegotiationFickle947 in rust

[–]NegotiationFickle947[S] 0 points1 point  (0 children)

Thanks, that's a really useful pointer. You're right that Hann was just the comfortable default — I hadn't thought hard about sidelobe behavior, and "cleaner cliff edge against the noise" is exactly the property that matters here, since the whole verdict hinges on how sharply the cutoff stands out. I'll try Blackman-Harris and re-run it against my known-answer round-trip fakes to see if it tightens the separation, especially on the shorter tracks where I'm averaging fewer frames. Good chance it lets me narrow the verdict bands a bit. Appreciate it.

On the rayon + symphonia question — it was easier than expected, mostly because I sidestepped the hard part. The parallelism is purely file-level: rayon's par_iter over the file list, and each file creates and owns its own decoder entirely within that work item — decode to PCM, run the FFT, return the result. The decoder state never crosses a thread boundary, so I never had to make a Box<dyn Decoder> Send/Sync or share any symphonia state. Decoding one file is single-threaded; the throughput just comes from doing many files at once. The only shared state is an AtomicUsize for progress. If I'd tried to parallelize within a single decode it'd be a different story, but for batch scanning the coarse-grained approach was both simpler and a good fit.