//$ nobt
//$ nocpp

/**
 * @file CDSPResampler.h
 *
 * @brief The master sample rate converter (resampler) class.
 *
 * This file includes the master sample rate converter (resampler) class that
 * combines all elements of this library into a single front-end class.
 *
 * r8brain-free-src Copyright (c) 2013-2025 Aleksey Vaneev
 *
 * See the "LICENSE" file for license.
 */

#ifndef R8B_CDSPRESAMPLER_INCLUDED
#define R8B_CDSPRESAMPLER_INCLUDED

#include "CDSPHBDownsampler.h"
#include "CDSPHBUpsampler.h"
#include "CDSPBlockConvolver.h"
#include "CDSPFracInterpolator.h"

namespace r8b {

/**
 * @brief The master sample rate converter (resampler) class.
 *
 * This class can be considered the "master" sample rate converter (resampler)
 * class since it combines all functionality of this library into a single
 * front-end class that performs sample rate conversion to/from any sample
 * rate, including non-integer sample rates.
 *
 * Note that objects of this class can be constructed on the stack as it has a
 * small member data size. The default template parameters of this class are
 * suited for 27-bit fixed point resampling.
 *
 * Use the CDSPResampler16 class for 16-bit resampling.
 *
 * Use the CDSPResampler16IR class for 16-bit impulse response resampling.
 *
 * Use the CDSPResampler24 class for 24-bit resampling (including 32-bit
 * floating point resampling).
 */

class CDSPResampler : public CDSPProcessor
{
public:
	/**
	 * @brief Initalizes the resampler object.
	 *
	 * Note that increasing the transition band and decreasing attenuation
	 * reduces the filter length, this in turn reduces the "input before
	 * output" delay. However, the filter length has only a minor influence on
	 * the overall resampling speed.
	 *
	 * It should be noted that the `ReqAtten` specifies the minimal difference
	 * between the loudest input signal component and the produced aliasing
	 * artifacts during resampling. For example, if `ReqAtten=100` was
	 * specified when performing 2x upsampling, the analysis of the resulting
	 * signal may display high-frequency components which are quieter than
	 * the loudest part of the input signal by only 100 decibel meaning
	 * the high-frequency part did not become "magically" completely silent
	 * after resampling. You have to specify a higher `ReqAtten` value if you
	 * need a totally clean high-frequency content. On the other hand, it may
	 * not be reasonable to have a high-frequency content cleaner than
	 * the input signal itself: if the input signal is 16-bit, setting
	 * `ReqAtten` to 180 will make its high-frequency content 24-bit, but
	 * the original part of the signal will remain 16-bit.
	 *
	 * @param SrcSampleRate Source signal's sample rate. Both sample rates can
	 * be specified as a ratio: e.g., `SrcSampleRate = 1.0`,
	 * `DstSampleRate = 2.0`.
	 * @param DstSampleRate Destination signal's sample rate. The "power of 2"
	 * ratios between the source and destination sample rates force resampler
	 * to use several fast "power of 2" resampling steps, without using
	 * fractional interpolation at all.
	 * @param aMaxInLen The maximal planned length of the input buffer (in
	 * samples) that will be passed to the resampler. The resampler relies on
	 * this value as it allocates intermediate buffers. Input buffers longer
	 * than this value should never be supplied to the resampler. Note that
	 * upsampling produces more samples than was provided on input, so at
	 * higher upsampling ratios it is advisable to use smaller `aMaxInLen`
	 * values to reduce memory footprint. When downsampling, a larger
	 * `aMaxInLen` is suggested in order to increase downsampling performance.
	 * @param ReqTransBand Required transition band, in percent of the
	 * spectral space of the input signal (or the output signal if
	 * downsampling is performed) between filter's -3 dB point and the Nyquist
	 * frequency. The range is from CDSPFIRFilter::getLPMinTransBand() to
	 * CDSPFIRFilter::getLPMaxTransBand(), inclusive. When upsampling 88200 or
	 * 96000 audio to higher sample rates the ReqTransBand can be considerably
	 * increased, up to 30. The selection of ReqTransBand depends on the level
	 * of desire to preserve the high-frequency content. While values 0.5 to 2
	 * are extremely "greedy" settings, not necessary in most cases, values 2
	 * to 3 can be used in most cases. Values 3 to 4 are relaxed settings, but
	 * they still offer a flat frequency response up to 21kHz with 44.1k
	 * source or destination sample rate.
	 * @param ReqAtten Required stop-band attenuation in decibel, in the
	 * range CDSPFIRFilter::getLPMinAtten() to CDSPFIRFilter::getLPMaxAtten(),
	 * inclusive. The actual attenuation may be 0.40-4.46 dB higher. The
	 * general formula for selecting the `ReqAtten` is `6.02 * Bits + 40`,
	 * where `Bits` is the bit resolution (e.g., 16, 24), 40 is an added
	 * resolution for dynamic signals; this value can be decreased to 20 to
	 * 10, if the signal being resampled is non-dynamic (e.g., an impulse
	 * response or filter, with a non-steep frequency response).
	 * @param ReqPhase Required filter's phase response. Note that this
	 * setting does not affect interpolator's phase response which is always
	 * linear-phase. Also note that if the "power of 2" resampling was engaged
	 * by the resampler together with the minimum-phase response, the audio
	 * stream may become fractionally delayed, depending on the minimum-phase
	 * filter's actual fractional delay. Linear-phase filters do not have
	 * fractional delay.
	 * @see EDSPFilterPhaseResponse
	 */

	CDSPResampler( const double SrcSampleRate, const double DstSampleRate,
		const int aMaxInLen, const double ReqTransBand = 2.0,
		const double ReqAtten = 206.91,
		const EDSPFilterPhaseResponse ReqPhase = fprLinearPhase )
		: StepCapacity( 0 )
		, StepCount( 0 )
		, MaxInLen( aMaxInLen )
		, CurMaxOutLen( aMaxInLen )
		, LatencyFrac( 0.0 )
	{
		R8BASSERT( SrcSampleRate > 0.0 );
		R8BASSERT( DstSampleRate > 0.0 );
		R8BASSERT( MaxInLen > 0 );

		R8BCONSOLE( "* CDSPResampler: src=%.1f dst=%.1f len=%i tb=%.1f "
			"att=%.2f ph=%i\n", SrcSampleRate, DstSampleRate, aMaxInLen,
			ReqTransBand, ReqAtten, (int) ReqPhase );

		if( SrcSampleRate == DstSampleRate )
		{
			return;
		}

		TmpBufCapacities[ 0 ] = 0;
		TmpBufCapacities[ 1 ] = 0;
		CurTmpBuf = 0;

		// Try some common efficient ratios requiring only a single step.

		const int CommonRatioCount = 5;
		const int CommonRatios[ CommonRatioCount ][ 2 ] = {
			{ 1, 2 },
			{ 1, 3 },
			{ 2, 3 },
			{ 3, 2 },
			{ 3, 4 }
		};

		int i;

		for( i = 0; i < CommonRatioCount; i++ )
		{
			const int num = CommonRatios[ i ][ 0 ];
			const int den = CommonRatios[ i ][ 1 ];

			if( SrcSampleRate * num == DstSampleRate * den )
			{
				addProcessor( new CDSPBlockConvolver(
					CDSPFIRFilterCache :: getLPFilter(
					1.0 / ( num > den ? num : den ), ReqTransBand,
					ReqAtten, ReqPhase, num ), num, den, LatencyFrac ));

				createTmpBuffers();
				return;
			}
		}

		// Try whole-number power-of-2 or 3*power-of-2 upsampling.

		for( i = 2; i <= 3; i++ )
		{
			bool WasFound = false;
			int c = 0;

			while( true )
			{
				const double NewSR = SrcSampleRate * ( i << c );

				if( NewSR == DstSampleRate )
				{
					WasFound = true;
					break;
				}

				if( NewSR > DstSampleRate )
				{
					break;
				}

				c++;
			}

			if( WasFound )
			{
				addProcessor( new CDSPBlockConvolver(
					CDSPFIRFilterCache :: getLPFilter( 1.0 / i, ReqTransBand,
					ReqAtten, ReqPhase, i ), i, 1, LatencyFrac ));

				const bool IsThird = ( i == 3 );

				for( i = 0; i < c; i++ )
				{
					addProcessor( new CDSPHBUpsampler( ReqAtten, i, IsThird,
						LatencyFrac ));
				}

				createTmpBuffers();
				return;
			}
		}

		if( DstSampleRate * 2.0 > SrcSampleRate )
		{
			// Upsampling or fractional downsampling down to 2X.

			const double NormFreq = ( DstSampleRate > SrcSampleRate ? 0.5 :
				0.5 * DstSampleRate / SrcSampleRate );

			addProcessor( new CDSPBlockConvolver(
				CDSPFIRFilterCache :: getLPFilter( NormFreq, ReqTransBand,
				ReqAtten, ReqPhase, 2.0 ), 2, 1, LatencyFrac ));

			// Try intermediate interpolated resampling with subsequent 2X
			// or 3X upsampling.

			const double tbw = 0.0175; // Intermediate filter's transition
				// band extension coefficient.
			const double ThreshSampleRate = SrcSampleRate /
				( 1.0 - tbw * ReqTransBand ); // Make sure intermediate
				// filter's transition band is not steeper than ReqTransBand
				// (this keeps the latency under control).

			int c = 0;
			int div = 1;

			while( true )
			{
				const int ndiv = div * 2;

				if( DstSampleRate < ThreshSampleRate * ndiv )
				{
					break;
				}

				div = ndiv;
				c++;
			}

			int c2 = 0;
			int div2 = 1;

			while( true )
			{
				const int ndiv = div * ( c2 == 0 ? 3 : 2 );

				if( DstSampleRate < ThreshSampleRate * ndiv )
				{
					break;
				}

				div2 = ndiv;
				c2++;
			}

			const double SrcSampleRate2 = SrcSampleRate * 2.0;
			int tmp1;
			int tmp2;

			if( c == 1 && getWholeStepping( SrcSampleRate2, DstSampleRate,
				tmp1, tmp2 ))
			{
				// Do not use intermediate interpolation if whole stepping is
				// available as it performs very fast.

				c = 0;
			}

			if( c > 0 )
			{
				// Add steps using intermediate interpolation.

				int num;

				if( c2 > 0 && div2 > div )
				{
					div = div2;
					c = c2;
					num = 3;
				}
				else
				{
					num = 2;
				}

				addProcessor( new CDSPFracInterpolator( SrcSampleRate2 * div,
					DstSampleRate, ReqAtten, false, LatencyFrac ));

				double tb = ( 1.0 - SrcSampleRate * div / DstSampleRate ) /
					tbw; // Divide TransBand by a constant that assures a
					// linear response in the pass-band.

				if( tb > CDSPFIRFilter :: getLPMaxTransBand() )
				{
					tb = CDSPFIRFilter :: getLPMaxTransBand();
				}

				addProcessor( new CDSPBlockConvolver(
					CDSPFIRFilterCache :: getLPFilter( 1.0 / num, tb,
					ReqAtten, ReqPhase, num ), num, 1, LatencyFrac ));

				const bool IsThird = ( num == 3 );

				for( i = 1; i < c; i++ )
				{
					addProcessor( new CDSPHBUpsampler( ReqAtten, i - 1,
						IsThird, LatencyFrac ));
				}
			}
			else
			{
				addProcessor( new CDSPFracInterpolator( SrcSampleRate2,
					DstSampleRate, ReqAtten, false, LatencyFrac ));
			}

			createTmpBuffers();
			return;
		}

		// Use downsampling steps, including power-of-2 downsampling.

		double CheckSR = DstSampleRate * 4.0;
		int c = 0;
		double FinGain = 1.0;

		while( CheckSR <= SrcSampleRate )
		{
			c++;
			CheckSR *= 2.0;
			FinGain *= 0.5;
		}

		const int SrcSRDiv = ( 1 << c );
		int downf;
		double NormFreq = 0.5;
		bool UseInterp = true;
		bool IsThird = false;

		for( downf = 2; downf <= 3; downf++ )
		{
			if( DstSampleRate * SrcSRDiv * downf == SrcSampleRate )
			{
				NormFreq = 1.0 / downf;
				UseInterp = false;
				IsThird = ( downf == 3 );
				break;
			}
		}

		if( UseInterp )
		{
			downf = 1;
			NormFreq = DstSampleRate * SrcSRDiv / SrcSampleRate;
			IsThird = ( NormFreq * 3.0 <= 1.0 );
		}

		for( i = 0; i < c; i++ )
		{
			// Use fixed, very relaxed 2X downsampling filters, that at the
			// final stage only guarantee stop-band between 0.75 and pi.
			// 0.5-0.75 range will be aliased to 0.25-0.5 range which will
			// then be filtered out by the final filter.

			addProcessor( new CDSPHBDownsampler( ReqAtten, c - 1 - i, IsThird,
				LatencyFrac ));
		}

		addProcessor( new CDSPBlockConvolver(
			CDSPFIRFilterCache :: getLPFilter( NormFreq, ReqTransBand,
			ReqAtten, ReqPhase, FinGain ), 1, downf, LatencyFrac ));

		if( UseInterp )
		{
			addProcessor( new CDSPFracInterpolator( SrcSampleRate,
				DstSampleRate * SrcSRDiv, ReqAtten, IsThird, LatencyFrac ));
		}

		createTmpBuffers();
	}

	virtual ~CDSPResampler()
	{
		int i;

		for( i = 0; i < StepCount; i++ )
		{
			delete Steps[ i ];
		}
	}

	virtual int getInLenBeforeOutPos( const int ReqOutPos ) const
	{
		R8BASSERT( ReqOutPos >= 0 );

		int ReqInSamples = ReqOutPos;
		int c = StepCount;

		while( --c >= 0 )
		{
			ReqInSamples = Steps[ c ] -> getInLenBeforeOutPos( ReqInSamples );
		}

		return( ReqInSamples );
	}

	/**
	 * @brief Returns the number of input samples required to advance to
	 * the specified output sample position (so that the next process() call
	 * passes this output position), starting at the cleared or
	 * after-construction state of *this* object.
	 *
	 * This function works by iteratively passing 1 sample at a time until the
	 * overall output length passes the specified value. This is a relatively
	 * CPU-consuming operation. This function should be called after the
	 * clear() function call or after object's construction. The function
	 * itself calls the clear() function before return.
	 *
	 * Note that this function can be considered a legacy function, and is now
	 * used for testing purposes. It is advised to use "instant" (much faster)
	 * getInLenBeforeOutPos() and getInputRequiredForOutput() functions
	 * instead.
	 *
	 * @param ReqOutPos The required output position. Must be a non-negative
	 * value.
	 * @return The number of input samples required.
	 */

	int getInLenBeforeOutStart( const int ReqOutPos = 0 )
	{
		R8BASSERT( ReqOutPos >= 0 );

		int inc = 0;
		int outc = 0;

		while( true )
		{
			double ins = 0.0;
			double* op;
			outc += process( &ins, 1, op );

			if( outc > ReqOutPos )
			{
				clear();
				return( inc );
			}

			inc++;
		}
	}

	/**
	 * @brief Returns the number of input samples required to produce at
	 * least the specified number of output samples, starting at the cleared
	 * or after-construction state of *this* object.
	 *
	 * @param ReqOutSamples The number of output samples required. If a
	 * non-positive value was specified, the function returns 0.
	 * @return The number of input samples required.
	 */

	int getInputRequiredForOutput( const int ReqOutSamples ) const
	{
		if( ReqOutSamples < 1 )
		{
			return( 0 );
		}

		return( getInLenBeforeOutPos( ReqOutSamples - 1 ) + 1 );
	}

	virtual int getLatency() const
	{
		return( 0 );
	}

	virtual double getLatencyFrac() const
	{
		return( LatencyFrac );
	}

	/**
	 * @brief This implementation ignores the supplied parameter and returns
	 * the maximal output buffer length that depends on the `MaxInLen`
	 * supplied to the constructor.
	 */

	virtual int getMaxOutLen( const int/* MaxInLen */) const
	{
		return( CurMaxOutLen );
	}

	/**
	 * @brief Clears (resets) the state of *this* object and returns it to
	 * the state after construction.
	 *
	 * All input data accumulated in the internal buffer so far will be
	 * discarded.
	 *
	 * This function makes it possible to use *this* object for converting
	 * separate streams from the same source sample rate to the same
	 * destination sample rate without reconstructing the object. It is more
	 * efficient to clear the state of the resampler object than to destroy it
	 * and create a new object.
	 */

	virtual void clear()
	{
		int i;

		for( i = 0; i < StepCount; i++ )
		{
			Steps[ i ] -> clear();
		}
	}

	/**
	 * @brief Performs sample rate conversion.
	 *
	 * If the source and destination sample rates are equal, the resampler
	 * will do nothing and will simply return the input buffer unchanged.
	 *
	 * You do not need to allocate an intermediate output buffer for use with
	 * this function. If required, the resampler will allocate a suitable
	 * intermediate output buffer itself.
	 *
	 * @param ip0 Input buffer. This buffer is never used as output buffer by
	 * this function. This pointer may be returned in `op0` if no resampling
	 * is happening (source sample rate equals destination sample rate).
	 * @param l The number of samples available in the input buffer. Should
	 * not exceed the `MaxInLen` supplied in the constructor.
	 * @param[out] op0 This variable receives the pointer to the resampled
	 * data. On function's return, this pointer points to *this* object's
	 * internal buffer. In real-time applications it is suggested to pass this
	 * pointer to the next output audio block and consume any data left from
	 * the previous output audio block first before calling the process()
	 * function again. The buffer pointed to by the `op0` on return is owned
	 * by the resampler, so it should not be freed by the caller.
	 * @return The number of samples available in the `op0` output buffer. If
	 * the data from the output buffer `op0` is going to be written to a
	 * bigger output buffer, it is suggested to check the returned number of
	 * samples so that no overflow of the bigger output buffer happens.
	 */

	virtual int process( double* ip0, int l, double*& op0 )
	{
		R8BASSERT( l >= 0 );

		double* ip = ip0;
		int i;

		for( i = 0; i < StepCount; i++ )
		{
			double* op = TmpBufs[ i & 1 ];
			l = Steps[ i ] -> process( ip, l, op );
			ip = op;
		}

		op0 = ip;
		return( l );
	}

	/**
	 * @brief Performs resampling of an input sample buffer of the specified
	 * length in the "one-shot" mode.
	 *
	 * This function can be useful when impulse response or time-series
	 * resampling is required.
	 *
	 * @param ip Input buffer pointer.
	 * @param iplen Length of the input buffer in samples.
	 * @param[out] op Output buffer pointer.
	 * @param oplen Length of the output buffer in samples.
	 * @tparam Tin Input buffer's element type.
	 * @tparam Tout Output buffer's element type.
	 */

	template< typename Tin, typename Tout >
	void oneshot( const Tin* ip, int iplen, Tout* op, int oplen )
	{
		CFixedBuffer< double > Buf( MaxInLen );
		bool IsZero = false;

		while( oplen > 0 )
		{
			int rc;
			double* p;
			int i;

			if( iplen == 0 )
			{
				rc = MaxInLen;
				p = &Buf[ 0 ];

				if( !IsZero )
				{
					IsZero = true;
					memset( p, 0, MaxInLen * sizeof( p[ 0 ]));
				}
			}
			else
			{
				rc = min( iplen, MaxInLen );

				if( sizeof( Tin ) == sizeof( double ))
				{
					p = (double*) ip;
				}
				else
				{
					p = &Buf[ 0 ];

					for( i = 0; i < rc; i++ )
					{
						p[ i ] = ip[ i ];
					}
				}

				ip += rc;
				iplen -= rc;
			}

			double* op0;
			int wc = process( p, rc, op0 );
			wc = min( oplen, wc );

			for( i = 0; i < wc; i++ )
			{
				op[ i ] = (Tout) op0[ i ];
			}

			op += wc;
			oplen -= wc;
		}

		clear();
	}

private:
	CFixedBuffer< CDSPProcessor* > Steps; ///< Array of processing steps.
	int StepCapacity; ///< The capacity of the `Steps` array.
	int StepCount; ///< The number of created processing steps.
	int MaxInLen; ///< Maximal input length.
	CFixedBuffer< double > TmpBufAll; ///< Buffer containing both temporary
		///< buffers.
	double* TmpBufs[ 2 ]; ///< Temporary output buffers.
	int TmpBufCapacities[ 2 ]; ///< Capacities of temporary buffers, updated
		///< during processing steps building.
	int CurTmpBuf; ///< Current temporary buffer.
	int CurMaxOutLen; ///< Current maximal output length.
	double LatencyFrac; ///< Current fractional latency. After object's
		///< construction, equals to the remaining fractional latency in the
		///< output.

	/**
	 * @brief Adds processor, updates `MaxOutLen` variable and adjusts length
	 * of temporary internal buffers.
	 *
	 * @param Proc Processor to add. This pointer is inherited and will be
	 * destroyed on *this* object's destruction.
	 */

	void addProcessor( CDSPProcessor* const Proc )
	{
		if( StepCount == StepCapacity )
		{
			// Reallocate and increase Steps array's capacity.

			const int NewCapacity = StepCapacity + 8;
			Steps.realloc( StepCapacity, NewCapacity );
			StepCapacity = NewCapacity;
		}

		LatencyFrac = Proc -> getLatencyFrac();
		CurMaxOutLen = Proc -> getMaxOutLen( CurMaxOutLen );

		if( CurMaxOutLen > TmpBufCapacities[ CurTmpBuf ])
		{
			TmpBufCapacities[ CurTmpBuf ] = CurMaxOutLen;
		}

		CurTmpBuf ^= 1;

		Steps[ StepCount ] = Proc;
		StepCount++;
	}

	/**
	 * @brief Creates temporary buffers.
	 */

	void createTmpBuffers()
	{
		const int ol = TmpBufCapacities[ 0 ] + TmpBufCapacities[ 1 ];

		if( ol > 0 )
		{
			TmpBufAll.alloc( ol );
			TmpBufs[ 0 ] = &TmpBufAll[ 0 ];
			TmpBufs[ 1 ] = &TmpBufAll[ TmpBufCapacities[ 0 ]];
		}

		R8BCONSOLE( "* CDSPResampler: init done\n" );
	}
};

/**
 * @brief The resampler class for 16-bit resampling.
 *
 * This class defines resampling parameters suitable for 16-bit resampling,
 * using linear-phase low-pass filter. See the r8b::CDSPResampler class for
 * details.
 */

class CDSPResampler16 : public CDSPResampler
{
public:
	/**
	 * @brief Initializes the 16-bit resampler. See the r8b::CDSPResampler
	 * class for details.
	 *
	 * @param SrcSampleRate Source signal's sample rate.
	 * @param DstSampleRate Destination signal's sample rate.
	 * @param aMaxInLen The maximal planned length of the input buffer (in
	 * samples) that will be passed to the resampler.
	 * @param ReqTransBand Required transition band, in percent.
	 */

	CDSPResampler16( const double SrcSampleRate, const double DstSampleRate,
		const int aMaxInLen, const double ReqTransBand = 2.0 )
		: CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
			136.45, fprLinearPhase )
	{
	}
};

/**
 * @brief The resampler class for 16-bit impulse response resampling.
 *
 * This class defines resampling parameters suitable for 16-bit impulse
 * response resampling, using linear-phase low-pass filter. Impulse responses
 * are non-dynamic signals, and thus need resampler with a lesser SNR. See the
 * r8b::CDSPResampler class for details.
 */

class CDSPResampler16IR : public CDSPResampler
{
public:
	/**
	 * @brief Initializes the 16-bit impulse response resampler. See the
	 * r8b::CDSPResampler class for details.
	 *
	 * @param SrcSampleRate Source signal's sample rate.
	 * @param DstSampleRate Destination signal's sample rate.
	 * @param aMaxInLen The maximal planned length of the input buffer (in
	 * samples) that will be passed to the resampler.
	 * @param ReqTransBand Required transition band, in percent.
	 */

	CDSPResampler16IR( const double SrcSampleRate, const double DstSampleRate,
		const int aMaxInLen, const double ReqTransBand = 2.0 )
		: CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
			109.56, fprLinearPhase )
	{
	}
};

/**
 * @brief The resampler class for 24-bit resampling.
 *
 * This class defines resampling parameters suitable for 24-bit resampling
 * (including 32-bit floating point resampling), using linear-phase low-pass
 * filter. See the r8b::CDSPResampler class for details.
 */

class CDSPResampler24 : public CDSPResampler
{
public:
	/**
	 * @brief Initializes the 24-bit resampler (including 32-bit floating
	 * point). See the r8b::CDSPResampler class for details.
	 *
	 * @param SrcSampleRate Source signal's sample rate.
	 * @param DstSampleRate Destination signal's sample rate.
	 * @param aMaxInLen The maximal planned length of the input buffer (in
	 * samples) that will be passed to the resampler.
	 * @param ReqTransBand Required transition band, in percent.
	 */

	CDSPResampler24( const double SrcSampleRate, const double DstSampleRate,
		const int aMaxInLen, const double ReqTransBand = 2.0 )
		: CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
			180.15, fprLinearPhase )
	{
	}
};

} // namespace r8b

#endif // R8B_CDSPRESAMPLER_INCLUDED
