|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- /*
- ==============================================================================
-
- This file is part of the JUCE 6 technical preview.
- Copyright (c) 2020 - Raw Material Software Limited
-
- You may use this code under the terms of the GPL v3
- (see www.gnu.org/licenses).
-
- For this technical preview, this file is not subject to commercial licensing.
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- class Interpolators
- {
- private:
- struct WindowedSincTraits
- {
- static constexpr float algorithmicLatency = 100.0f;
-
- static forcedinline float windowedSinc (float firstFrac, int index) noexcept
- {
- auto index2 = index + 1;
- auto frac = firstFrac;
-
- auto value1 = lookupTable[index];
- auto value2 = lookupTable[index2];
-
- return value1 + (frac * (value2 - value1));
- }
-
- static forcedinline float valueAtOffset (const float* const inputs, const float offset, int indexBuffer) noexcept
- {
- int numCrossings = 100;
- float result = 0.0f;
-
- auto samplePosition = indexBuffer;
- float firstFrac = 0.0f;
- float lastSincPosition = -1.0f;
- int index = 0, sign = -1;
-
- for (int i = -numCrossings; i <= numCrossings; ++i)
- {
- auto sincPosition = (1.0f - offset) + (float) i;
-
- if (i == -numCrossings || (sincPosition >= 0 && lastSincPosition < 0))
- {
- auto indexFloat = (sincPosition >= 0.f ? sincPosition : -sincPosition) * 100.0f;
- index = (int) std::floor (indexFloat);
- firstFrac = indexFloat - index;
- sign = (sincPosition < 0 ? -1 : 1);
- }
-
- if (sincPosition == 0.0f)
- result += inputs[samplePosition];
- else if (sincPosition < numCrossings && sincPosition > -numCrossings)
- result += inputs[samplePosition] * windowedSinc (firstFrac, index);
-
- if (++samplePosition == numCrossings * 2)
- samplePosition = 0;
-
- lastSincPosition = sincPosition;
- index += 100 * sign;
- }
-
- return result;
- }
-
- static const float lookupTable[10001];
- };
-
- struct LagrangeTraits
- {
- static constexpr float algorithmicLatency = 2.0f;
-
- static float valueAtOffset (const float*, float, int) noexcept;
- };
-
- struct CatmullRomTraits
- {
- //==============================================================================
- static constexpr float algorithmicLatency = 2.0f;
-
- static forcedinline float valueAtOffset (const float* const inputs, const float offset, int index) noexcept
- {
- auto y0 = inputs[index]; if (++index == 4) index = 0;
- auto y1 = inputs[index]; if (++index == 4) index = 0;
- auto y2 = inputs[index]; if (++index == 4) index = 0;
- auto y3 = inputs[index];
-
- auto halfY0 = 0.5f * y0;
- auto halfY3 = 0.5f * y3;
-
- return y1 + offset * ((0.5f * y2 - halfY0)
- + (offset * (((y0 + 2.0f * y2) - (halfY3 + 2.5f * y1))
- + (offset * ((halfY3 + 1.5f * y1) - (halfY0 + 1.5f * y2))))));
- }
- };
-
- struct LinearTraits
- {
- static constexpr float algorithmicLatency = 1.0f;
-
- static forcedinline float valueAtOffset (const float* const inputs, const float offset, int index) noexcept
- {
- auto y0 = inputs[index];
- auto y1 = inputs[index == 0 ? 1 : 0];
-
- return y1 * offset + y0 * (1.0f - offset);
- }
- };
-
- struct ZeroOrderHoldTraits
- {
- static constexpr float algorithmicLatency = 0.0f;
-
- static forcedinline float valueAtOffset (const float* const inputs, const float, int) noexcept
- {
- return inputs[0];
- }
- };
-
- public:
- using WindowedSinc = GenericInterpolator<WindowedSincTraits, 200>;
- using Lagrange = GenericInterpolator<LagrangeTraits, 5>;
- using CatmullRom = GenericInterpolator<CatmullRomTraits, 4>;
- using Linear = GenericInterpolator<LinearTraits, 2>;
- using ZeroOrderHold = GenericInterpolator<ZeroOrderHoldTraits, 1>;
- };
-
- //==============================================================================
- /**
- An interpolator for resampling a stream of floats using high order windowed
- (hann) sinc interpolation, recommended for high quality resampling.
-
- Note that the resampler is stateful, so when there's a break in the continuity
- of the input stream you're feeding it, you should call reset() before feeding
- it any new data. And like with any other stateful filter, if you're resampling
- multiple channels, make sure each one uses its own LinearInterpolator object.
-
- @see GenericInterpolator
-
- @see LagrangeInterpolator, CatmullRomInterpolator, LinearInterpolator,
- ZeroOrderHoldInterpolator
-
- @tags{Audio}
- */
- using WindowedSincInterpolator = Interpolators::WindowedSinc;
-
- /**
- An interpolator for resampling a stream of floats using 4-point lagrange interpolation.
-
- Note that the resampler is stateful, so when there's a break in the continuity
- of the input stream you're feeding it, you should call reset() before feeding
- it any new data. And like with any other stateful filter, if you're resampling
- multiple channels, make sure each one uses its own LagrangeInterpolator object.
-
- @see GenericInterpolator
-
- @see CatmullRomInterpolator, WindowedSincInterpolator, LinearInterpolator,
- ZeroOrderHoldInterpolator
-
- @tags{Audio}
- */
- using LagrangeInterpolator = Interpolators::Lagrange;
-
- /**
- An interpolator for resampling a stream of floats using Catmull-Rom interpolation.
-
- Note that the resampler is stateful, so when there's a break in the continuity
- of the input stream you're feeding it, you should call reset() before feeding
- it any new data. And like with any other stateful filter, if you're resampling
- multiple channels, make sure each one uses its own CatmullRomInterpolator object.
-
- @see GenericInterpolator
-
- @see LagrangeInterpolator, WindowedSincInterpolator, LinearInterpolator,
- ZeroOrderHoldInterpolator
-
- @tags{Audio}
- */
- using CatmullRomInterpolator = Interpolators::CatmullRom;
-
- /**
- An interpolator for resampling a stream of floats using linear interpolation.
-
- Note that the resampler is stateful, so when there's a break in the continuity
- of the input stream you're feeding it, you should call reset() before feeding
- it any new data. And like with any other stateful filter, if you're resampling
- multiple channels, make sure each one uses its own LinearInterpolator object.
-
- @see GenericInterpolator
-
- @see LagrangeInterpolator, CatmullRomInterpolator, WindowedSincInterpolator,
- ZeroOrderHoldInterpolator
-
- @tags{Audio}
- */
- using LinearInterpolator = Interpolators::Linear;
-
- /**
- An interpolator for resampling a stream of floats using zero order hold
- interpolation.
-
- Note that the resampler is stateful, so when there's a break in the continuity
- of the input stream you're feeding it, you should call reset() before feeding
- it any new data. And like with any other stateful filter, if you're resampling
- multiple channels, make sure each one uses its own ZeroOrderHoldInterpolator
- object.
-
- @see GenericInterpolator
-
- @see LagrangeInterpolator, CatmullRomInterpolator, WindowedSincInterpolator,
- LinearInterpolator
-
- @tags{Audio}
- */
- using ZeroOrderHoldInterpolator = Interpolators::ZeroOrderHold;
-
- } // namespace juce
|