|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497 |
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2022 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- The code included in this file is provided under the terms of the ISC license
- http://www.isc.org/downloads/software-support-policy/isc-license. Permission
- To use, copy, modify, and/or distribute this software for any purpose with or
- without fee is hereby granted provided that the above copyright notice and
- this permission notice appear in all copies.
-
- 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
- {
-
- /**
- An interpolator base class for resampling streams of floats.
-
- Note that the resamplers are 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 interpolator object.
-
- @see LagrangeInterpolator, CatmullRomInterpolator, WindowedSincInterpolator,
- LinearInterpolator, ZeroOrderHoldInterpolator
-
- @tags{Audio}
- */
- template <class InterpolatorTraits, int memorySize>
- class JUCE_API GenericInterpolator
- {
- public:
- GenericInterpolator() noexcept { reset(); }
-
- GenericInterpolator (GenericInterpolator&&) noexcept = default;
- GenericInterpolator& operator= (GenericInterpolator&&) noexcept = default;
-
- /** Returns the latency of the interpolation algorithm in isolation.
-
- In the context of resampling the total latency of a process using
- the interpolator is the base latency divided by the speed ratio.
- */
- static constexpr float getBaseLatency() noexcept
- {
- return InterpolatorTraits::algorithmicLatency;
- }
-
- /** Resets the state of the interpolator.
-
- Call this when there's a break in the continuity of the input data stream.
- */
- void reset() noexcept
- {
- indexBuffer = 0;
- subSamplePos = 1.0;
- std::fill (std::begin (lastInputSamples), std::end (lastInputSamples), 0.0f);
- }
-
- /** Resamples a stream of samples.
-
- @param speedRatio the number of input samples to use for each output sample
- @param inputSamples the source data to read from. This must contain at
- least (speedRatio * numOutputSamplesToProduce) samples.
- @param outputSamples the buffer to write the results into
- @param numOutputSamplesToProduce the number of output samples that should be created
-
- @returns the actual number of input samples that were used
- */
- int process (double speedRatio,
- const float* inputSamples,
- float* outputSamples,
- int numOutputSamplesToProduce) noexcept
- {
- return interpolate (speedRatio, inputSamples, outputSamples, numOutputSamplesToProduce);
- }
-
- /** Resamples a stream of samples.
-
- @param speedRatio the number of input samples to use for each output sample
- @param inputSamples the source data to read from. This must contain at
- least (speedRatio * numOutputSamplesToProduce) samples.
- @param outputSamples the buffer to write the results into
- @param numOutputSamplesToProduce the number of output samples that should be created
- @param numInputSamplesAvailable the number of available input samples. If it needs more samples
- than available, it either wraps back for wrapAround samples, or
- it feeds zeroes
- @param wrapAround if the stream exceeds available samples, it wraps back for
- wrapAround samples. If wrapAround is set to 0, it will feed zeroes.
-
- @returns the actual number of input samples that were used
- */
- int process (double speedRatio,
- const float* inputSamples,
- float* outputSamples,
- int numOutputSamplesToProduce,
- int numInputSamplesAvailable,
- int wrapAround) noexcept
- {
- return interpolate (speedRatio, inputSamples, outputSamples,
- numOutputSamplesToProduce, numInputSamplesAvailable, wrapAround);
- }
-
- /** Resamples a stream of samples, adding the results to the output data
- with a gain.
-
- @param speedRatio the number of input samples to use for each output sample
- @param inputSamples the source data to read from. This must contain at
- least (speedRatio * numOutputSamplesToProduce) samples.
- @param outputSamples the buffer to write the results to - the result values will be added
- to any pre-existing data in this buffer after being multiplied by
- the gain factor
- @param numOutputSamplesToProduce the number of output samples that should be created
- @param gain a gain factor to multiply the resulting samples by before
- adding them to the destination buffer
-
- @returns the actual number of input samples that were used
- */
- int processAdding (double speedRatio,
- const float* inputSamples,
- float* outputSamples,
- int numOutputSamplesToProduce,
- float gain) noexcept
- {
- return interpolateAdding (speedRatio, inputSamples, outputSamples, numOutputSamplesToProduce, gain);
- }
-
- /** Resamples a stream of samples, adding the results to the output data
- with a gain.
-
- @param speedRatio the number of input samples to use for each output sample
- @param inputSamples the source data to read from. This must contain at
- least (speedRatio * numOutputSamplesToProduce) samples.
- @param outputSamples the buffer to write the results to - the result values will be added
- to any pre-existing data in this buffer after being multiplied by
- the gain factor
- @param numOutputSamplesToProduce the number of output samples that should be created
- @param numInputSamplesAvailable the number of available input samples. If it needs more samples
- than available, it either wraps back for wrapAround samples, or
- it feeds zeroes
- @param wrapAround if the stream exceeds available samples, it wraps back for
- wrapAround samples. If wrapAround is set to 0, it will feed zeroes.
- @param gain a gain factor to multiply the resulting samples by before
- adding them to the destination buffer
-
- @returns the actual number of input samples that were used
- */
- int processAdding (double speedRatio,
- const float* inputSamples,
- float* outputSamples,
- int numOutputSamplesToProduce,
- int numInputSamplesAvailable,
- int wrapAround,
- float gain) noexcept
- {
- return interpolateAdding (speedRatio, inputSamples, outputSamples,
- numOutputSamplesToProduce, numInputSamplesAvailable, wrapAround, gain);
- }
-
- private:
- //==============================================================================
- forcedinline void pushInterpolationSample (float newValue) noexcept
- {
- lastInputSamples[indexBuffer] = newValue;
-
- if (++indexBuffer == memorySize)
- indexBuffer = 0;
- }
-
- forcedinline void pushInterpolationSamples (const float* input,
- int numOutputSamplesToProduce) noexcept
- {
- if (numOutputSamplesToProduce >= memorySize)
- {
- const auto* const offsetInput = input + (numOutputSamplesToProduce - memorySize);
-
- for (int i = 0; i < memorySize; ++i)
- pushInterpolationSample (offsetInput[i]);
- }
- else
- {
- for (int i = 0; i < numOutputSamplesToProduce; ++i)
- pushInterpolationSample (input[i]);
- }
- }
-
- forcedinline void pushInterpolationSamples (const float* input,
- int numOutputSamplesToProduce,
- int numInputSamplesAvailable,
- int wrapAround) noexcept
- {
- if (numOutputSamplesToProduce >= memorySize)
- {
- if (numInputSamplesAvailable >= memorySize)
- {
- pushInterpolationSamples (input,
- numOutputSamplesToProduce);
- }
- else
- {
- pushInterpolationSamples (input + ((numOutputSamplesToProduce - numInputSamplesAvailable) - 1),
- numInputSamplesAvailable);
-
- if (wrapAround > 0)
- {
- numOutputSamplesToProduce -= wrapAround;
-
- pushInterpolationSamples (input + ((numOutputSamplesToProduce - (memorySize - numInputSamplesAvailable)) - 1),
- memorySize - numInputSamplesAvailable);
- }
- else
- {
- for (int i = numInputSamplesAvailable; i < memorySize; ++i)
- pushInterpolationSample (0.0f);
- }
- }
- }
- else
- {
- if (numOutputSamplesToProduce > numInputSamplesAvailable)
- {
- for (int i = 0; i < numInputSamplesAvailable; ++i)
- pushInterpolationSample (input[i]);
-
- const auto extraSamples = numOutputSamplesToProduce - numInputSamplesAvailable;
-
- if (wrapAround > 0)
- {
- const auto* const offsetInput = input + (numInputSamplesAvailable - wrapAround);
-
- for (int i = 0; i < extraSamples; ++i)
- pushInterpolationSample (offsetInput[i]);
- }
- else
- {
- for (int i = 0; i < extraSamples; ++i)
- pushInterpolationSample (0.0f);
- }
- }
- else
- {
- for (int i = 0; i < numOutputSamplesToProduce; ++i)
- pushInterpolationSample (input[i]);
- }
- }
- }
-
- //==============================================================================
- int interpolate (double speedRatio,
- const float* input,
- float* output,
- int numOutputSamplesToProduce) noexcept
- {
- auto pos = subSamplePos;
- int numUsed = 0;
-
- while (numOutputSamplesToProduce > 0)
- {
- while (pos >= 1.0)
- {
- pushInterpolationSample (input[numUsed++]);
- pos -= 1.0;
- }
-
- *output++ = InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer);
- pos += speedRatio;
- --numOutputSamplesToProduce;
- }
-
- subSamplePos = pos;
- return numUsed;
- }
-
- int interpolate (double speedRatio,
- const float* input, float* output,
- int numOutputSamplesToProduce,
- int numInputSamplesAvailable,
- int wrap) noexcept
- {
- auto originalIn = input;
- auto pos = subSamplePos;
- bool exceeded = false;
-
- if (speedRatio < 1.0)
- {
- for (int i = numOutputSamplesToProduce; --i >= 0;)
- {
- if (pos >= 1.0)
- {
- if (exceeded)
- {
- pushInterpolationSample (0.0f);
- }
- else
- {
- pushInterpolationSample (*input++);
-
- if (--numInputSamplesAvailable <= 0)
- {
- if (wrap > 0)
- {
- input -= wrap;
- numInputSamplesAvailable += wrap;
- }
- else
- {
- exceeded = true;
- }
- }
- }
-
- pos -= 1.0;
- }
-
- *output++ = InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer);
- pos += speedRatio;
- }
- }
- else
- {
- for (int i = numOutputSamplesToProduce; --i >= 0;)
- {
- while (pos < speedRatio)
- {
- if (exceeded)
- {
- pushInterpolationSample (0);
- }
- else
- {
- pushInterpolationSample (*input++);
-
- if (--numInputSamplesAvailable <= 0)
- {
- if (wrap > 0)
- {
- input -= wrap;
- numInputSamplesAvailable += wrap;
- }
- else
- {
- exceeded = true;
- }
- }
- }
-
- pos += 1.0;
- }
-
- pos -= speedRatio;
- *output++ = InterpolatorTraits::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos), indexBuffer);
- }
- }
-
- subSamplePos = pos;
-
- if (wrap == 0)
- return (int) (input - originalIn);
-
- return ((int) (input - originalIn) + wrap) % wrap;
- }
-
- int interpolateAdding (double speedRatio,
- const float* input,
- float* output,
- int numOutputSamplesToProduce,
- int numInputSamplesAvailable,
- int wrap,
- float gain) noexcept
- {
- auto originalIn = input;
- auto pos = subSamplePos;
- bool exceeded = false;
-
- if (speedRatio < 1.0)
- {
- for (int i = numOutputSamplesToProduce; --i >= 0;)
- {
- if (pos >= 1.0)
- {
- if (exceeded)
- {
- pushInterpolationSample (0.0);
- }
- else
- {
- pushInterpolationSample (*input++);
-
- if (--numInputSamplesAvailable <= 0)
- {
- if (wrap > 0)
- {
- input -= wrap;
- numInputSamplesAvailable += wrap;
- }
- else
- {
- numInputSamplesAvailable = true;
- }
- }
- }
-
- pos -= 1.0;
- }
-
- *output++ += gain * InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer);
- pos += speedRatio;
- }
- }
- else
- {
- for (int i = numOutputSamplesToProduce; --i >= 0;)
- {
- while (pos < speedRatio)
- {
- if (exceeded)
- {
- pushInterpolationSample (0.0);
- }
- else
- {
- pushInterpolationSample (*input++);
-
- if (--numInputSamplesAvailable <= 0)
- {
- if (wrap > 0)
- {
- input -= wrap;
- numInputSamplesAvailable += wrap;
- }
- else
- {
- exceeded = true;
- }
- }
- }
-
- pos += 1.0;
- }
-
- pos -= speedRatio;
- *output++ += gain * InterpolatorTraits::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos), indexBuffer);
- }
- }
-
- subSamplePos = pos;
-
- if (wrap == 0)
- return (int) (input - originalIn);
-
- return ((int) (input - originalIn) + wrap) % wrap;
- }
-
- int interpolateAdding (double speedRatio,
- const float* input,
- float* output,
- int numOutputSamplesToProduce,
- float gain) noexcept
- {
- auto pos = subSamplePos;
- int numUsed = 0;
-
- while (numOutputSamplesToProduce > 0)
- {
- while (pos >= 1.0)
- {
- pushInterpolationSample (input[numUsed++]);
- pos -= 1.0;
- }
-
- *output++ += gain * InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer);
- pos += speedRatio;
- --numOutputSamplesToProduce;
- }
-
- subSamplePos = pos;
- return numUsed;
- }
-
- //==============================================================================
- float lastInputSamples[(size_t) memorySize];
- double subSamplePos = 1.0;
- int indexBuffer = 0;
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GenericInterpolator)
- };
-
- } // namespace juce
|