123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- //$ nobt
- //$ nocpp
- /**
- * @file CDSPHBDownsampler.h
- *
- * @brief Half-band downsampling convolver class.
- *
- * This file includes half-band downsampling convolver class.
- *
- * r8brain-free-src Copyright (c) 2013-2022 Aleksey Vaneev
- * See the "LICENSE" file for license.
- */
- #ifndef R8B_CDSPHBDOWNSAMPLER_INCLUDED
- #define R8B_CDSPHBDOWNSAMPLER_INCLUDED
- #include "CDSPHBUpsampler.h"
- namespace r8b {
- /**
- * @brief Half-band downsampler class.
- *
- * Class implements brute-force half-band 2X downsampling that uses small
- * sparse symmetric FIR filters. The output has 2.0 gain.
- */
- class CDSPHBDownsampler : public CDSPProcessor
- {
- public:
- /**
- * Constructor initalizes the half-band downsampler.
- *
- * @param ReqAtten Required half-band filter attentuation.
- * @param SteepIndex Steepness index - 0=steepest. Corresponds to general
- * downsampling ratio, e.g. at 4x downsampling 0 is used, at 8x
- * downsampling 1 is used, etc.
- * @param IsThird "True" if 1/3 resampling is performed.
- * @param PrevLatency Latency, in samples (any value >=0), which was left
- * in the output signal by a previous process. Whole-number latency will
- * be consumed by *this object while remaining fractional latency can be
- * obtained via the getLatencyFrac() function.
- */
- CDSPHBDownsampler( const double ReqAtten, const int SteepIndex,
- const bool IsThird, const double PrevLatency )
- {
- static const CConvolveFn FltConvFn[ 14 ] = {
- &CDSPHBDownsampler :: convolve1, &CDSPHBDownsampler :: convolve2,
- &CDSPHBDownsampler :: convolve3, &CDSPHBDownsampler :: convolve4,
- &CDSPHBDownsampler :: convolve5, &CDSPHBDownsampler :: convolve6,
- &CDSPHBDownsampler :: convolve7, &CDSPHBDownsampler :: convolve8,
- &CDSPHBDownsampler :: convolve9, &CDSPHBDownsampler :: convolve10,
- &CDSPHBDownsampler :: convolve11, &CDSPHBDownsampler :: convolve12,
- &CDSPHBDownsampler :: convolve13,
- &CDSPHBDownsampler :: convolve14 };
- int fltt;
- double att;
- if( IsThird )
- {
- CDSPHBUpsampler :: getHBFilterThird( ReqAtten, SteepIndex, fltp,
- fltt, att );
- }
- else
- {
- CDSPHBUpsampler :: getHBFilter( ReqAtten, SteepIndex, fltp, fltt,
- att );
- }
- convfn = FltConvFn[ fltt - 1 ];
- fll = fltt * 2 - 1;
- fl2 = fll;
- flo = fll + fl2;
- flb = BufLen - fll;
- BufRP = Buf + fll;
- LatencyFrac = PrevLatency * 0.5;
- Latency = (int) LatencyFrac;
- LatencyFrac -= Latency;
- R8BASSERT( Latency >= 0 );
- R8BCONSOLE( "CDSPHBDownsampler: taps=%i third=%i att=%.1f io=1/2\n",
- fltt, (int) IsThird, att );
- clear();
- }
- virtual int getLatency() const
- {
- return( 0 );
- }
- virtual double getLatencyFrac() const
- {
- return( LatencyFrac );
- }
- virtual int getMaxOutLen( const int MaxInLen ) const
- {
- R8BASSERT( MaxInLen >= 0 );
- return(( MaxInLen + 1 ) >> 1 );
- }
- virtual void clear()
- {
- LatencyLeft = Latency;
- BufLeft = 0;
- WritePos = 0;
- ReadPos = flb; // Set "read" position to account for filter's latency.
- memset( &Buf[ ReadPos ], 0, ( BufLen - flb ) * sizeof( Buf[ 0 ]));
- }
- virtual int process( double* ip, int l, double*& op0 )
- {
- R8BASSERT( l >= 0 );
- double* op = op0;
- while( l > 0 )
- {
- // Add new input samples to both halves of the ring buffer.
- const int b = min( min( l, BufLen - WritePos ), flb - BufLeft );
- double* const wp1 = Buf + WritePos;
- memcpy( wp1, ip, b * sizeof( wp1[ 0 ]));
- if( WritePos < flo )
- {
- const int c = min( b, flo - WritePos );
- memcpy( wp1 + BufLen, wp1, c * sizeof( wp1[ 0 ]));
- }
- ip += b;
- WritePos = ( WritePos + b ) & BufLenMask;
- l -= b;
- BufLeft += b;
- // Produce output.
- if( BufLeft > fl2 )
- {
- const int c = ( BufLeft - fl2 + 1 ) >> 1;
- double* const opend = op + c;
- ( *convfn )( op, opend, fltp, BufRP, ReadPos );
- op = opend;
- const int c2 = c + c;
- ReadPos = ( ReadPos + c2 ) & BufLenMask;
- BufLeft -= c2;
- }
- }
- int ol = (int) ( op - op0 );
- if( LatencyLeft != 0 )
- {
- if( LatencyLeft >= ol )
- {
- LatencyLeft -= ol;
- return( 0 );
- }
- ol -= LatencyLeft;
- op0 += LatencyLeft;
- LatencyLeft = 0;
- }
- return( ol );
- }
- private:
- static const int BufLenBits = 10; ///< The length of the ring buffer,
- ///< expressed as Nth power of 2. This value can be reduced if it is
- ///< known that only short input buffers will be passed to the
- ///< interpolator. The minimum value of this parameter is 5, and
- ///< 1 << BufLenBits should be at least 3 times larger than the
- ///< FilterLen.
- ///<
- static const int BufLen = 1 << BufLenBits; ///< The length of the ring
- ///< buffer. The actual length is twice as long to allow "beyond max
- ///< position" positioning.
- ///<
- static const int BufLenMask = BufLen - 1; ///< Mask used for quick buffer
- ///< position wrapping.
- ///<
- double Buf[ BufLen + 54 ]; ///< The ring buffer, including overrun
- ///< protection for the largest filter.
- ///<
- const double* fltp; ///< Half-band filter taps.
- ///<
- int fll; ///< Input latency.
- ///<
- int fl2; ///< Right-side filter length.
- ///<
- int flo; ///< Overrun length.
- ///<
- int flb; ///< Initial read position and maximal buffer write length.
- ///<
- const double* BufRP; ///< Offseted Buf pointer at ReadPos=0.
- ///<
- int Latency; ///< Initial latency that should be removed from the output.
- ///<
- double LatencyFrac; ///< Fractional latency left on the output.
- ///<
- int BufLeft; ///< The number of samples left in the buffer to process.
- ///< When this value is below FilterLenD2Plus1, the interpolation
- ///< cycle ends.
- ///<
- int WritePos; ///< The current buffer write position. Incremented together
- ///< with the BufLeft variable.
- ///<
- int ReadPos; ///< The current buffer read position.
- ///<
- int LatencyLeft; ///< Latency left to remove.
- ///<
- typedef void( *CConvolveFn )( double* op, double* const opend,
- const double* const flt, const double* const rp0, int rpos ); ///<
- ///< Convolution function type.
- ///<
- CConvolveFn convfn; ///< Convolution function in use.
- ///<
- #define R8BHBC1( fn ) \
- static void fn( double* op, double* const opend, const double* const flt, \
- const double* const rp0, int rpos ) \
- { \
- while( op != opend ) \
- { \
- const double* const rp = rp0 + rpos; \
- *op = rp[ 0 ] +
- #define R8BHBC2 \
- rpos = ( rpos + 2 ) & BufLenMask; \
- op++; \
- } \
- }
- R8BHBC1( convolve1 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]);
- R8BHBC2
- R8BHBC1( convolve2 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]);
- R8BHBC2
- R8BHBC1( convolve3 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]);
- R8BHBC2
- R8BHBC1( convolve4 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]) +
- flt[ 3 ] * ( rp[ 7 ] + rp[ -7 ]);
- R8BHBC2
- R8BHBC1( convolve5 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]) +
- flt[ 3 ] * ( rp[ 7 ] + rp[ -7 ]) +
- flt[ 4 ] * ( rp[ 9 ] + rp[ -9 ]);
- R8BHBC2
- R8BHBC1( convolve6 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]) +
- flt[ 3 ] * ( rp[ 7 ] + rp[ -7 ]) +
- flt[ 4 ] * ( rp[ 9 ] + rp[ -9 ]) +
- flt[ 5 ] * ( rp[ 11 ] + rp[ -11 ]);
- R8BHBC2
- R8BHBC1( convolve7 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]) +
- flt[ 3 ] * ( rp[ 7 ] + rp[ -7 ]) +
- flt[ 4 ] * ( rp[ 9 ] + rp[ -9 ]) +
- flt[ 5 ] * ( rp[ 11 ] + rp[ -11 ]) +
- flt[ 6 ] * ( rp[ 13 ] + rp[ -13 ]);
- R8BHBC2
- R8BHBC1( convolve8 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]) +
- flt[ 3 ] * ( rp[ 7 ] + rp[ -7 ]) +
- flt[ 4 ] * ( rp[ 9 ] + rp[ -9 ]) +
- flt[ 5 ] * ( rp[ 11 ] + rp[ -11 ]) +
- flt[ 6 ] * ( rp[ 13 ] + rp[ -13 ]) +
- flt[ 7 ] * ( rp[ 15 ] + rp[ -15 ]);
- R8BHBC2
- R8BHBC1( convolve9 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]) +
- flt[ 3 ] * ( rp[ 7 ] + rp[ -7 ]) +
- flt[ 4 ] * ( rp[ 9 ] + rp[ -9 ]) +
- flt[ 5 ] * ( rp[ 11 ] + rp[ -11 ]) +
- flt[ 6 ] * ( rp[ 13 ] + rp[ -13 ]) +
- flt[ 7 ] * ( rp[ 15 ] + rp[ -15 ]) +
- flt[ 8 ] * ( rp[ 17 ] + rp[ -17 ]);
- R8BHBC2
- R8BHBC1( convolve10 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]) +
- flt[ 3 ] * ( rp[ 7 ] + rp[ -7 ]) +
- flt[ 4 ] * ( rp[ 9 ] + rp[ -9 ]) +
- flt[ 5 ] * ( rp[ 11 ] + rp[ -11 ]) +
- flt[ 6 ] * ( rp[ 13 ] + rp[ -13 ]) +
- flt[ 7 ] * ( rp[ 15 ] + rp[ -15 ]) +
- flt[ 8 ] * ( rp[ 17 ] + rp[ -17 ]) +
- flt[ 9 ] * ( rp[ 19 ] + rp[ -19 ]);
- R8BHBC2
- R8BHBC1( convolve11 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]) +
- flt[ 3 ] * ( rp[ 7 ] + rp[ -7 ]) +
- flt[ 4 ] * ( rp[ 9 ] + rp[ -9 ]) +
- flt[ 5 ] * ( rp[ 11 ] + rp[ -11 ]) +
- flt[ 6 ] * ( rp[ 13 ] + rp[ -13 ]) +
- flt[ 7 ] * ( rp[ 15 ] + rp[ -15 ]) +
- flt[ 8 ] * ( rp[ 17 ] + rp[ -17 ]) +
- flt[ 9 ] * ( rp[ 19 ] + rp[ -19 ]) +
- flt[ 10 ] * ( rp[ 21 ] + rp[ -21 ]);
- R8BHBC2
- R8BHBC1( convolve12 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]) +
- flt[ 3 ] * ( rp[ 7 ] + rp[ -7 ]) +
- flt[ 4 ] * ( rp[ 9 ] + rp[ -9 ]) +
- flt[ 5 ] * ( rp[ 11 ] + rp[ -11 ]) +
- flt[ 6 ] * ( rp[ 13 ] + rp[ -13 ]) +
- flt[ 7 ] * ( rp[ 15 ] + rp[ -15 ]) +
- flt[ 8 ] * ( rp[ 17 ] + rp[ -17 ]) +
- flt[ 9 ] * ( rp[ 19 ] + rp[ -19 ]) +
- flt[ 10 ] * ( rp[ 21 ] + rp[ -21 ]) +
- flt[ 11 ] * ( rp[ 23 ] + rp[ -23 ]);
- R8BHBC2
- R8BHBC1( convolve13 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]) +
- flt[ 3 ] * ( rp[ 7 ] + rp[ -7 ]) +
- flt[ 4 ] * ( rp[ 9 ] + rp[ -9 ]) +
- flt[ 5 ] * ( rp[ 11 ] + rp[ -11 ]) +
- flt[ 6 ] * ( rp[ 13 ] + rp[ -13 ]) +
- flt[ 7 ] * ( rp[ 15 ] + rp[ -15 ]) +
- flt[ 8 ] * ( rp[ 17 ] + rp[ -17 ]) +
- flt[ 9 ] * ( rp[ 19 ] + rp[ -19 ]) +
- flt[ 10 ] * ( rp[ 21 ] + rp[ -21 ]) +
- flt[ 11 ] * ( rp[ 23 ] + rp[ -23 ]) +
- flt[ 12 ] * ( rp[ 25 ] + rp[ -25 ]);
- R8BHBC2
- R8BHBC1( convolve14 )
- flt[ 0 ] * ( rp[ 1 ] + rp[ -1 ]) +
- flt[ 1 ] * ( rp[ 3 ] + rp[ -3 ]) +
- flt[ 2 ] * ( rp[ 5 ] + rp[ -5 ]) +
- flt[ 3 ] * ( rp[ 7 ] + rp[ -7 ]) +
- flt[ 4 ] * ( rp[ 9 ] + rp[ -9 ]) +
- flt[ 5 ] * ( rp[ 11 ] + rp[ -11 ]) +
- flt[ 6 ] * ( rp[ 13 ] + rp[ -13 ]) +
- flt[ 7 ] * ( rp[ 15 ] + rp[ -15 ]) +
- flt[ 8 ] * ( rp[ 17 ] + rp[ -17 ]) +
- flt[ 9 ] * ( rp[ 19 ] + rp[ -19 ]) +
- flt[ 10 ] * ( rp[ 21 ] + rp[ -21 ]) +
- flt[ 11 ] * ( rp[ 23 ] + rp[ -23 ]) +
- flt[ 12 ] * ( rp[ 25 ] + rp[ -25 ]) +
- flt[ 13 ] * ( rp[ 27 ] + rp[ -27 ]);
- R8BHBC2
- #undef R8BHBC1
- #undef R8BHBC2
- };
- // ---------------------------------------------------------------------------
- } // namespace r8b
- #endif // R8B_CDSPHBDOWNSAMPLER_INCLUDED
|