From 37ac9b6abebc8051e325af8fe15b1f63c61131f9 Mon Sep 17 00:00:00 2001 From: Skyler Lehmkuhl Date: Fri, 6 Mar 2026 06:37:25 -0500 Subject: [PATCH] Fix NAM runtime errors on linux --- nam-ffi/build.rs | 15 +++- nam-ffi/capi-override/NeuralAudioCApi.cpp | 83 +++++++++++++++++++++++ nam-ffi/capi-override/NeuralAudioCApi.h | 50 ++++++++++++++ 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 nam-ffi/capi-override/NeuralAudioCApi.cpp create mode 100644 nam-ffi/capi-override/NeuralAudioCApi.h diff --git a/nam-ffi/build.rs b/nam-ffi/build.rs index 778ca6a..a3703b1 100644 --- a/nam-ffi/build.rs +++ b/nam-ffi/build.rs @@ -13,6 +13,19 @@ fn main() { let wrapper_dir = Path::new(&manifest_dir).join("cmake"); let neural_audio_dir = Path::new(&manifest_dir).join("../vendor/NeuralAudio"); + // Copy our patched CAPI files over the submodule versions before building. + // The upstream submodule uses `wchar_t*` on all platforms; our patch makes + // Linux/macOS use `const char*` instead, matching what the Rust FFI sends. + let capi_dir = neural_audio_dir.join("NeuralAudioCAPI"); + let override_dir = Path::new(&manifest_dir).join("capi-override"); + for filename in &["NeuralAudioCApi.h", "NeuralAudioCApi.cpp"] { + let src = override_dir.join(filename); + let dst = capi_dir.join(filename); + std::fs::copy(&src, &dst) + .unwrap_or_else(|e| panic!("Failed to copy {} override: {}", filename, e)); + println!("cargo:rerun-if-changed=capi-override/{}", filename); + } + let mut cfg = cmake::Config::new(&wrapper_dir); // Force single-config generator on Unix to avoid libraries landing in Release/ subdirs if !cfg!(target_os = "windows") { @@ -50,6 +63,4 @@ fn main() { _ => {} } - println!("cargo:rerun-if-changed=../vendor/NeuralAudio/NeuralAudioCAPI/NeuralAudioCApi.h"); - println!("cargo:rerun-if-changed=../vendor/NeuralAudio/NeuralAudioCAPI/NeuralAudioCApi.cpp"); } diff --git a/nam-ffi/capi-override/NeuralAudioCApi.cpp b/nam-ffi/capi-override/NeuralAudioCApi.cpp new file mode 100644 index 0000000..c385586 --- /dev/null +++ b/nam-ffi/capi-override/NeuralAudioCApi.cpp @@ -0,0 +1,83 @@ +#include "NeuralAudioCApi.h" +#include "NeuralModel.h" + +struct NeuralModel +{ + NeuralAudio::NeuralModel* model; +}; + +#ifdef _WIN32 +NeuralModel* CreateModelFromFile(const wchar_t* modelPath) +#else +NeuralModel* CreateModelFromFile(const char* modelPath) +#endif +{ + NeuralModel* model = new NeuralModel(); + + model->model = NeuralAudio::NeuralModel::CreateFromFile(modelPath); + + return model; +} + +void DeleteModel(NeuralModel* model) +{ + delete model->model; + delete model; +} + +void SetLSTMLoadMode(int loadMode) +{ + NeuralAudio::NeuralModel::SetLSTMLoadMode((NeuralAudio::EModelLoadMode)loadMode); +} + +void SetWaveNetLoadMode(int loadMode) +{ + NeuralAudio::NeuralModel::SetWaveNetLoadMode((NeuralAudio::EModelLoadMode)loadMode); +} + +void SetAudioInputLevelDBu(float audioDBu) +{ + NeuralAudio::NeuralModel::SetAudioInputLevelDBu(audioDBu); +} + +void SetDefaultMaxAudioBufferSize(int maxSize) +{ + NeuralAudio::NeuralModel::SetDefaultMaxAudioBufferSize(maxSize); +} + +int GetLoadMode(NeuralModel* model) +{ + return model->model->GetLoadMode(); +} + +bool IsStatic(NeuralModel* model) +{ + return model->model->IsStatic(); +} + +void SetMaxAudioBufferSize(NeuralModel* model, int maxSize) +{ + model->model->SetMaxAudioBufferSize(maxSize); +} + +float GetRecommendedInputDBAdjustment(NeuralModel* model) +{ + return model->model->GetRecommendedInputDBAdjustment(); +} + +float GetRecommendedOutputDBAdjustment(NeuralModel* model) +{ + return model->model->GetRecommendedOutputDBAdjustment(); +} + +float GetSampleRate(NeuralModel* model) +{ + return model->model->GetSampleRate(); +} + +void Process(NeuralModel* model, float* input, float* output, size_t numSamples) +{ + model->model->Process(input, output, numSamples); +} + + diff --git a/nam-ffi/capi-override/NeuralAudioCApi.h b/nam-ffi/capi-override/NeuralAudioCApi.h new file mode 100644 index 0000000..4e62f08 --- /dev/null +++ b/nam-ffi/capi-override/NeuralAudioCApi.h @@ -0,0 +1,50 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#define NA_EXTERN extern __declspec(dllexport) +#else +#define NA_EXTERN extern +#endif + +struct NeuralModel; + + +#ifdef _WIN32 +NA_EXTERN NeuralModel* CreateModelFromFile(const wchar_t* modelPath); +#else +NA_EXTERN NeuralModel* CreateModelFromFile(const char* modelPath); +#endif + +NA_EXTERN void DeleteModel(NeuralModel* model); + +NA_EXTERN void SetLSTMLoadMode(int loadMode); + +NA_EXTERN void SetWaveNetLoadMode(int loadMode); + +NA_EXTERN void SetAudioInputLevelDBu(float audioDBu); + +NA_EXTERN void SetDefaultMaxAudioBufferSize(int maxSize); + +NA_EXTERN int GetLoadMode(NeuralModel* model); + +NA_EXTERN bool IsStatic(NeuralModel* model); + +NA_EXTERN void SetMaxAudioBufferSize(NeuralModel* model, int maxSize); + +NA_EXTERN float GetRecommendedInputDBAdjustment(NeuralModel* model); + +NA_EXTERN float GetRecommendedOutputDBAdjustment(NeuralModel* model); + +NA_EXTERN float GetSampleRate(NeuralModel* model); + +NA_EXTERN void Process(NeuralModel* model, float* input, float* output, size_t numSamples); + +#ifdef __cplusplus +} +#endif \ No newline at end of file