All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Latency()onSimpleResamplerandSimpleResamplerFloat32, returning the startup deficit in output samples so a caller can prime a real-time FIFO before the first output. (#51)- Streaming documentation (latency, the
Flushcontract, per-channel instance requirements) and a real-time FIFO example atexamples/streaming. (#51)
- Polyphase phase-boundary coefficient interpolation used a wrapped neighbor, degrading THD+N at ratios with active sub-phase interpolation. The committed measurement shows an 86.26 dB improvement (wrapped -54.46 dB versus flat -140.72 dB) at 44100 to 64000, with similar magnitude at other active-interpolation ratios measured during the investigation but not committed as tests; exact-rational ratios such as 44100 to 48000 were unaffected. (#51)
- Severe non-integer downsampling (beyond roughly 1:16) corrupted output with repeated stale samples and grew internal history without bound. (#51)
Flushover-padded each filter stage by one zero, emitting about 2 phantom samples;ProcessplusFlushnow totals within[floor(n*ratio), ceil(n*ratio)+1]. (#51)- At unity ratio (
inputRate == outputRate),Processreturned the caller's own input slice; it now returns an owned buffer. (#51) - Cubic (
QualityQuick) resampling computed its first output segments from a fictional zero history and never emitted the final segments; output is now aligned to real data, with the first output after 2 input samples. ItsProcessalso returned an aliased empty slice during priming; it now returns an owned buffer. (#51) - NaN sample rates are now rejected by all constructors, covering both the
NewEngine/NewEngineFloat32engine path and theNew(config)pipeline path (New,NewMultiChannel,NewStereo,NewSimple, and the preset helpers). (#51) - Half-band stage construction errors now propagate instead of silently substituting a nearest-neighbor stub. (#51)
GetLatencynow accounts for decimation and cubic stages. (#51)GetLatencyon theNew(config)path now reports the measured startup deficit in output samples; it previously mixed rate domains across pipeline stages and mis-reported multi-stage ratios (672 reported vs 703 measured at 44100 to 96000 QualityHigh; now within 2 samples). (#52)
Flushis now terminal: a secondFlushreturns an empty slice, and aProcesscall afterFlushstarts a fresh stream instead of convolving against leftover padding. (#51)QualityQuickthroughNewEngineandNewEngineFloat32now uses cubic interpolation (matchingNew()and the documented contract) instead of a full FIR pipeline; latency drops accordingly. (#51)
- The internal duplicate polyphase filter design path
(
internal/filter/polyphase.go) and thecmd/analyze-filterdiagnostic that consumed it; the engine's design code ininternal/engineis the single polyphase implementation. (#55) - The production-dead
LinearStagefrominternal/engine; only its own tests referenced it. (#55)
1.4.0 - 2026-05-29
- Zero-allocation float32 streaming.
SimpleResamplerFloat32(fromNewEngineFloat32) now hasProcessInto(input, output []float32) (int, error)andEstimateOutput(inputLen int) int. The engine is float32-native, so this path has no float64 round-trip and reports 0 allocs/op once warm. TheNew(config)path gains the float32 counterpartProcessFloat32Into, which reuses grow-only scratch buffers for the conversion. Both produce output bit-identical toProcess/ProcessFloat32and returnErrBufferTooSmallbefore advancing state, so a too-small call can be retried safely. (#31, fixes #28) FlushMulti() ([][]float64, error)on a new optionalMultiFlusherinterface, draining every channel's pipeline independently afterProcessMulti. Exposed as an optional interface (matching the existinginfoProviderpattern) so it does not break external implementors ofResampler. (#41, #39)
- Multi-stage pipelines now flush inter-stage tails correctly. Each stage's pending input, including the previous stage's flushed tail, is processed through the stage before its delay line is drained, so the tail propagates all the way to the final output. Polyphase over-padding was also removed. (#40, #37, #30)
Flush()previously drained only channel 0, silently dropping the delay-line tails of channels 1..N-1 afterProcessMulti. UseFlushMultifor multi-channel streams. (#41, #39)
- Removed the
gonum.org/v1/gonumdependency. The DFT pre-stage is FIR-polyphase based and no longer uses an external FFT, sogithub.com/tphakala/simdis now the core library's only runtime dependency. (#29) - Stereo processing reuses a single engine and reads all available samples in the per-channel path; a dead mutex was removed. (#38, #32, #33, #34)
- Engine internals: dead-code cleanup, warm-path zero-allocation, hot-loop bounds-check elimination, and a split of the oversized polyphase source. No public API change. (#29)
- Bumped
github.com/tphakala/simdto v1.1.0. (#20)
1.3.0 - 2026-05-04
- Zero-allocation float64 streaming via caller-owned output buffers:
SimpleResampler.ProcessIntoandEstimateOutput.
1.2.0 - 2026-03-15
- Security, fuzzing, and CI hardening: fuzz tests, Kaiser window overflow fix for extreme parameters, OpenSSF Scorecard compliance, and Dependabot auto-merge.
1.1.0 - 2025-11-26
- Float32-native API:
SimpleResamplerFloat32,ResampleMonoFloat32, andResampleStereoFloat32for consistent float32 workflows.
1.0.1 - 2025-11-25
- Bug fixes.
1.0.0 - 2025-11-24
- Initial release. Pure Go, multi-stage polyphase FIR resampling with Kaiser window design, quality presets, multi-channel and streaming support, validated against libsoxr.