Skip to content

Restore DFNR in Windows Store MSIX builds via DeepFilter fork patch #3217

Description

@ten9876

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)

Metadata

Metadata

Assignees

Labels

WindowsWindows-specific issueaudioAudio engine and streamingbugSomething isn't workingenhancementImprovement to existing featuremaintainer-reviewRequires maintainer review before any action is takenpriority: highHigh priority

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions