From 0079c28d3cf6c4faf2a03ded895acec2713c94c0 Mon Sep 17 00:00:00 2001 From: Andy Nowacki Date: Mon, 11 Mar 2024 09:20:32 +0000 Subject: [PATCH] Fix bounds errors when resampling with some arbitrary ratios (#539) In some cases when `filt(::FIRFilter{FIRArbitrary}, x)` is called with certain values of `x`, `filt!(buffer, ::FIRFilter{FIRArbitrary}, x)` tries to write one sample too many to the buffer and a `BoundsError` is thrown. Add one extra sample to the buffer to catch these exceptional cases. (This code is really a hack and simply works around the deeper problem of calculating the correct output buffer length; this should instead be addressed properly in a future change.) Closes #317. (cherry picked from commit 73d3214a4aceb8f11f82623e22f66101ff498c92) --- src/Filters/stream_filt.jl | 13 +++++++++++++ test/resample.jl | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Filters/stream_filt.jl b/src/Filters/stream_filt.jl index 4f5429582..17cc16660 100644 --- a/src/Filters/stream_filt.jl +++ b/src/Filters/stream_filt.jl @@ -630,6 +630,19 @@ end function filt(self::FIRFilter{Tk}, x::AbstractVector{Tx}) where {Th,Tx,Tk<:FIRKernel{Th}} bufLen = outputlength(self, length(x)) + # In some cases when `filt(::FIRFilter{FIRArbitrary}, x)` is called + # with certain values of `x`, `filt!(buffer, ::FIRFilter{FIRArbitrary}, x)` + # tries to write one sample too many to the buffer and a `BoundsError` + # is thrown. Add one extra sample to catch these exceptional cases. + # + # See https://github.com/JuliaDSP/DSP.jl/issues/317 + # + # FIXME: Remove this if and when the code in + # `filt!(buffer, ::FIRFilter{FIRArbitrary}, x)` + # is updated to properly account for pathological arbitrary rates. + if Tk <: FIRArbitrary + bufLen += 1 + end buffer = Vector{promote_type(Th,Tx)}(undef, bufLen) samplesWritten = filt!(buffer, self, x) diff --git a/test/resample.jl b/test/resample.jl index 7a437db21..78b174f4e 100644 --- a/test/resample.jl +++ b/test/resample.jl @@ -97,6 +97,16 @@ end @test all(map(delta -> abs(delta) < 0.005, yDelta)) end +@testset "arbitrary ratio" begin + # https://github.com/JuliaDSP/DSP.jl/issues/317 + @testset "Buffer length calculation" begin + @test length(resample(sin.(1:1:35546), 1/55.55)) == 641 + @test length(resample(randn(1822), 0.9802414928649835)) == 1787 + @test length(resample(1:16_367_000*2, 10_000_000/16_367_000)) == 20_000_001 + @test resample(zeros(1000), 0.012) == zeros(13) + end +end + @testset "resample_filter" begin @testset "decimation" begin ratio = 1//2