Context
PR #3205 strips DeepFilterNet3_onnx.tar.gz from Store-bound MSIX packages to clear WACK's "Archive files usage" rule. The runtime is unchanged, so Store-installed AetherSDR currently has DFNR effectively broken — df_create() fails at startup because the model archive is absent.
This issue tracks restoring DFNR for Store builds.
Why the "obvious" fix doesn't work
The upstream C API header at third_party/deepfilter/include/deep_filter.h:24 documents:
path: File path to a DeepFilterNet tar.gz onnx model (NULL for embedded default)
That comment is wrong / hand-added. The actual upstream Rust at our pinned commit d375b2d8 (libDF/src/capi.rs#L88) unconditionally dereferences path:
pub unsafe extern "C" fn df_create(
path: *const c_char,
atten_lim: f32,
log_level: *const c_char,
) -> *mut DFState {
let c_str = CStr::from_ptr(path); // segfaults on NULL
let path = c_str.to_str().unwrap(); // no NULL handling
...
let df_params = DfParams::new(PathBuf::from(model_path))
.expect("Could not load model from path");
Same code on upstream main today — not a "bump the pin" fix.
The good news
capi already transitively enables the default-model Cargo feature (libDF/Cargo.toml#L55):
capi = ["tract", "default-model", "dep:ndarray", "logging"]
…which compiles the model bytes directly into the static lib via include_bytes!:
DfParams::from_bytes(include_bytes!("../../models/DeepFilterNet3_onnx.tar.gz"))
The embedded model exists in our libdeepfilter.a today (~52 MB lib, of which ~8 MB is the embedded tarball). It's just unreachable from the public C API.
Proposed fix
Small fork patch to libDF/src/capi.rs — add a NULL-path branch to df_create that constructs DfParams::default() (uses the include_bytes!-embedded model) instead of DfParams::new(path):
let df = if path.is_null() {
DFState::new_default(1, atten_lim, log_level)
} else {
let path_str = CStr::from_ptr(path).to_str().unwrap();
DFState::new(path_str, 1, atten_lim, log_level)
};
Plus a DFState::new_default() helper that calls DfParams::default() for the embedded path.
Estimated work:
- ~20-line patch to upstream DeepFilterNet
- Modify
scripts/setup/setup-deepfilter.{sh,ps1} to apply the patch after git checkout $DfnrCommit
- Update DeepFilterFilter::DeepFilterFilter() to pass
nullptr when findModelPath() returns empty, instead of bailing out
- Rebuild prebuilt libs on the
dfnr-libs GitHub Release tag for all platforms (Win/Linux/macOS)
- Drop
-ExcludeDfnrModel from the Windows MSIX workflow (or keep it as opt-in for size reasons — embedded vs sidecar tarball is roughly the same byte cost)
Upstream path
Worth opening as a PR against Rikorose/DeepFilterNet — anyone shipping to Microsoft Store or app sandbox environments hits the same wall. If declined, we maintain a one-file patch in our setup scripts (we already pin a commit, so patch-on-checkout is straightforward).
Cleanup
While we're in here:
References
73, Jeremy KK7GWY & Claude (AI dev partner)
Context
PR #3205 strips
DeepFilterNet3_onnx.tar.gzfrom Store-bound MSIX packages to clear WACK's "Archive files usage" rule. The runtime is unchanged, so Store-installed AetherSDR currently has DFNR effectively broken —df_create()fails at startup because the model archive is absent.This issue tracks restoring DFNR for Store builds.
Why the "obvious" fix doesn't work
The upstream C API header at third_party/deepfilter/include/deep_filter.h:24 documents:
That comment is wrong / hand-added. The actual upstream Rust at our pinned commit
d375b2d8(libDF/src/capi.rs#L88) unconditionally dereferencespath:Same code on upstream
maintoday — not a "bump the pin" fix.The good news
capialready transitively enables thedefault-modelCargo feature (libDF/Cargo.toml#L55):…which compiles the model bytes directly into the static lib via
include_bytes!:The embedded model exists in our
libdeepfilter.atoday (~52 MB lib, of which ~8 MB is the embedded tarball). It's just unreachable from the public C API.Proposed fix
Small fork patch to
libDF/src/capi.rs— add a NULL-path branch todf_createthat constructsDfParams::default()(uses theinclude_bytes!-embedded model) instead ofDfParams::new(path):Plus a
DFState::new_default()helper that callsDfParams::default()for the embedded path.Estimated work:
scripts/setup/setup-deepfilter.{sh,ps1}to apply the patch aftergit checkout $DfnrCommitnullptrwhenfindModelPath()returns empty, instead of bailing outdfnr-libsGitHub Release tag for all platforms (Win/Linux/macOS)-ExcludeDfnrModelfrom the Windows MSIX workflow (or keep it as opt-in for size reasons — embedded vs sidecar tarball is roughly the same byte cost)Upstream path
Worth opening as a PR against Rikorose/DeepFilterNet — anyone shipping to Microsoft Store or app sandbox environments hits the same wall. If declined, we maintain a one-file patch in our setup scripts (we already pin a commit, so patch-on-checkout is straightforward).
Cleanup
While we're in here:
References
73, Jeremy KK7GWY & Claude (AI dev partner)