Skip to content

[FEATURE] Support models variable sample rate - #333

Merged
sdatkinson merged 5 commits into
mainfrom
332-feature-support-models-variable-sample-rate
Sep 18, 2026
Merged

sdatkinson merged 5 commits into
mainfrom
332-feature-support-models-variable-sample-rate

Conversation

@sdatkinson

Copy link
Copy Markdown
Owner

Resolves #332

Summary

Adds an explicit capability check for models that support arbitrary processing sample rates and implements that support for Linear models.

For example, a linear model trained at 48 kHz can now be reset to another processing rate, such as 44.1 or 96 kHz. Its impulse response is resampled during Reset(), and subsequent calls to process() use the adapted coefficients. The model continues to report 48 kHz as its training rate.

Public API

Adds the following virtual method to DSP:

virtual bool SupportsArbitrarySampleRate() { return false; }

Linear overrides it to return true. Other model architectures retain the default behavior.

Hosts can query this capability when deciding whether a model can process at the host’s sample rate or requires external sample-rate conversion. Supporting models are configured through the existing Reset(sampleRate, maxBufferSize) interface.

The documentation for GetExpectedSampleRate() now identifies it as the model’s training sample rate, which is not necessarily its only supported processing rate. Resetting a model does not change this metadata. This might be cleaned up in a later breaking version bump.

Linear model sample-rate adaptation

Linear retains a separate copy of its original trained impulse response. Every reset derives the active coefficients from that original response, preventing interpolation errors from accumulating across successive rate changes.

When the processing rate differs from the known training rate:

  • The impulse response is resampled using cubic interpolation adapted from AudioDSPTools.
  • Samples outside the original response are treated as zero.
  • Output sample positions are calculated directly from their indices, avoiding accumulated timing error.
  • The response length scales with the sample-rate ratio, rounding up and retaining at least one tap.
  • Coefficients are multiplied by the training rate divided by the processing rate to compensate for the changed tap density.
  • The bias remains unchanged.

Resetting to the training rate restores the original coefficients without interpolation.

Both direct and FFT convolution use the adapted response. Automatic implementation selection is reevaluated using the resampled response length, allowing a rate change to switch the selected convolution engine.

Reset and processing behavior

Reset rebuilds the convolution state and clears input history and pending FFT work, including when resetting to the same processing rate. This prevents audio buffered before the reset from appearing afterward.

Input and output buffers are prepared during reset so processing within the advertised maximum buffer size does not allocate, including the first processing call when prewarming is disabled. Resampling and FFT preparation happen outside process(); callers must perform reset outside the audio callback.

Invalid processing rates, including nonpositive and nonfinite values, are rejected. Oversized resampled responses and input buffers are also checked.

Compatibility and limitations

Models whose training rate is unknown (-1.0) retain their original coefficients because a conversion ratio cannot be determined. Linear is conservative and does not advertise the architecture’s arbitrary-rate capability in this case.

Other architectures retain their existing processing behavior.

Cubic interpolation approximates the original impulse response and is not a band-limited resampler. Accuracy can degrade near Nyquist and when downsampling; this limitation is documented.

Tests and verification

Added regression coverage for:

  • The default DSP capability and Linear’s override through the base interface.
  • Exact expected coefficients for upsampling and downsampling a delayed impulse.
  • Bias preservation and unchanged training-rate metadata.
  • Repeated rate changes and restoration of the original coefficients.
  • Fractional conversion, including 48 kHz to 44.1 kHz.
  • Direct/FFT agreement with irregular processing block sizes.
  • Automatic convolution-engine selection after the response length changes.
  • Single-tap responses and unknown training rates.
  • Invalid and excessively large processing rates.
  • Multichannel processing and zeroing of extra output channels.
  • Allocation-free processing immediately after reset.
  • Clearing buffered input and pending FFT work on reset.

Verification completed:

  • The existing full test suite passed before implementation.
  • The new rate-conversion regression failed against the original implementation.
  • The full Debug build and final test suite passed.
  • Focused sample-rate tests passed under AddressSanitizer and UndefinedBehaviorSanitizer.
  • Focused tests passed with NAM_SAMPLE_FLOAT.
  • Formatting and whitespace checks passed.

@sdatkinson
sdatkinson merged commit e771d99 into main Sep 18, 2026
4 checks passed
@sdatkinson
sdatkinson deleted the 332-feature-support-models-variable-sample-rate branch September 18, 2026 19:56
dfernandes83 added a commit to dfernandes83/NeuralAmpModelerCore that referenced this pull request Sep 21, 2026
Brings in NAM Core 0.6.0 from sdatkinson/NeuralAmpModelerCore:
- models with variable sample rate (sdatkinson#333): Linear reports
  SupportsArbitrarySampleRate() and resamples in Reset()
- 1-to-n and n-to-1 channel configurations in Linear models (sdatkinson#335, breaking:
  a Linear model now needs one kernel per output/input path)
- Linear models instantiated from .wav files through get_dsp() (sdatkinson#337)
- version bump to 0.6.0 (sdatkinson#336)

Conflicts:
- NAM/get_dsp.cpp: kept all three includes (<algorithm> and <cctype> from
  upstream, <cmath> from our validation code).
- NAM/linear.cpp: took upstream's rewritten direct-convolution loop. Our side
  only had a static_cast to silence an MSVC conversion warning in the code
  that upstream replaced.

Consumers now have to compile NAM/wav.cpp too: get_dsp.cpp calls
nam::detail::load_wav_ir().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Support models with variable sample rate

1 participant