What's wrong
RingBuffer<T>.Resample (Containers/RingBuffer.cs, in the resample loop) computes the source index like this:
double oldIndex = i * (oldCount - 1) / (double)Math.Max(length - 1, 1);
int index = (int)Math.Round(oldIndex);
index = Math.Min(index, oldCount - 1);
i * (oldCount - 1) is evaluated in int before the double division. Once (length - 1) * (oldCount - 1) passes int.MaxValue, the product wraps negative, so index comes out negative. Math.Min only clamps the upper end, and oldData[negative] throws.
By then AllocateBuffer(length) has already reset the buffer, so the exception also leaves it half-refilled. The original contents are lost.
Why it matters
The doc comment presents Resample as a tool for time-series and sample-rate changes. One second of 48 kHz audio is 48,000 samples, which is well past the threshold.
Repro:
foreach (int n in new[] { 46340, 46342, 48000 })
{
var rb = new RingBuffer<int>(Enumerable.Range(0, n), n);
try { rb.Resample(n); Console.WriteLine($"n={n}: ok"); }
catch (Exception e) { Console.WriteLine($"n={n}: {e.GetType().Name}; Count={rb.Count} (was {n})"); }
}
// also: new RingBuffer<int>(Enumerable.Range(0, 1000), 1000).Resample(3_000_000) -> IndexOutOfRangeException
Output:
n=46340: ok
n=46342: IndexOutOfRangeException; Count=46341 (was 46342)
n=48000: IndexOutOfRangeException; Count=44741 (was 48000)
Expected: every size succeeds, ending with Count == length and the last element equal to the old last element. The only documented exception is ArgumentOutOfRangeException for length < 1.
Suggested fix
double oldIndex = (double)i * (oldCount - 1) / Math.Max(length - 1, 1);
int index = Math.Clamp((int)Math.Round(oldIndex), 0, oldCount - 1);
Acceptance criteria
- Resampling a 50,000-element buffer to the same length succeeds, and
rb[^1] == 49999.
- Upsampling 1,000 elements to 3,000,000 succeeds.
What's wrong
RingBuffer<T>.Resample(Containers/RingBuffer.cs, in the resample loop) computes the source index like this:i * (oldCount - 1)is evaluated inintbefore thedoubledivision. Once(length - 1) * (oldCount - 1)passesint.MaxValue, the product wraps negative, soindexcomes out negative.Math.Minonly clamps the upper end, andoldData[negative]throws.By then
AllocateBuffer(length)has already reset the buffer, so the exception also leaves it half-refilled. The original contents are lost.Why it matters
The doc comment presents
Resampleas a tool for time-series and sample-rate changes. One second of 48 kHz audio is 48,000 samples, which is well past the threshold.Repro:
Output:
Expected: every size succeeds, ending with
Count == lengthand the last element equal to the old last element. The only documented exception isArgumentOutOfRangeExceptionforlength < 1.Suggested fix
Acceptance criteria
rb[^1] == 49999.