123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642 |
- #ifndef R8B_CDSPBLOCKCONVOLVER_INCLUDED
- #define R8B_CDSPBLOCKCONVOLVER_INCLUDED
- #include "CDSPFIRFilter.h"
- #include "CDSPProcessor.h"
- namespace r8b {
- class CDSPBlockConvolver : public CDSPProcessor
- {
- public:
-
- CDSPBlockConvolver( CDSPFIRFilter& aFilter, const int aUpFactor,
- const int aDownFactor, const double PrevLatency = 0.0,
- const bool aDoConsumeLatency = true )
- : Filter( &aFilter )
- , UpFactor( aUpFactor )
- , DownFactor( aDownFactor )
- , DoConsumeLatency( aDoConsumeLatency )
- , BlockLen2( 2 << Filter -> getBlockLenBits() )
- {
- R8BASSERT( UpFactor > 0 );
- R8BASSERT( DownFactor > 0 );
- R8BASSERT( PrevLatency >= 0.0 );
- int fftinBits;
- UpShift = getBitOccupancy( UpFactor ) - 1;
- if(( 1 << UpShift ) == UpFactor )
- {
- fftinBits = Filter -> getBlockLenBits() + 1 - UpShift;
- PrevInputLen = ( Filter -> getKernelLen() - 1 + UpFactor - 1 ) /
- UpFactor;
- InputLen = BlockLen2 - PrevInputLen * UpFactor;
- }
- else
- {
- UpShift = -1;
- fftinBits = Filter -> getBlockLenBits() + 1;
- PrevInputLen = Filter -> getKernelLen() - 1;
- InputLen = BlockLen2 - PrevInputLen;
- }
- OutOffset = ( Filter -> isZeroPhase() ? Filter -> getLatency() : 0 );
- LatencyFrac = Filter -> getLatencyFrac() + PrevLatency * UpFactor;
- Latency = (int) LatencyFrac;
- const int InLatency = Latency + Filter -> getLatency() - OutOffset;
- LatencyFrac -= Latency;
- LatencyFrac /= DownFactor;
- Latency += InputLen + Filter -> getLatency();
- int fftoutBits;
- InputDelay = 0;
- DownSkipInit = 0;
- DownShift = getBitOccupancy( DownFactor ) - 1;
- if(( 1 << DownShift ) == DownFactor )
- {
- fftoutBits = Filter -> getBlockLenBits() + 1 - DownShift;
- if( DownFactor > 1 )
- {
- if( UpShift > 0 )
- {
-
-
-
- R8BASSERT( UpShift == 0 );
- }
- else
- {
-
- const int ilc = InputLen & ( DownFactor - 1 );
- PrevInputLen += ilc;
- InputLen -= ilc;
- Latency -= ilc;
-
- const int lc = InLatency & ( DownFactor - 1 );
- if( lc > 0 )
- {
- InputDelay = DownFactor - lc;
- }
- if( !DoConsumeLatency )
- {
- Latency /= DownFactor;
- }
- }
- }
- }
- else
- {
- fftoutBits = Filter -> getBlockLenBits() + 1;
- DownShift = -1;
- if( !DoConsumeLatency && DownFactor > 1 )
- {
- DownSkipInit = Latency % DownFactor;
- Latency /= DownFactor;
- }
- }
- R8BASSERT( Latency >= 0 );
- fftin = new CDSPRealFFTKeeper( fftinBits );
- if( fftoutBits == fftinBits )
- {
- fftout = fftin;
- }
- else
- {
- ffto2 = new CDSPRealFFTKeeper( fftoutBits );
- fftout = ffto2;
- }
- WorkBlocks.alloc( BlockLen2 * 2 + PrevInputLen );
- CurInput = &WorkBlocks[ 0 ];
- CurOutput = &WorkBlocks[ BlockLen2 ];
-
- PrevInput = &WorkBlocks[ BlockLen2 * 2 ];
- clear();
- R8BCONSOLE( "CDSPBlockConvolver: flt_len=%i in_len=%i io=%i/%i "
- "fft=%i/%i latency=%i\n", Filter -> getKernelLen(), InputLen,
- UpFactor, DownFactor, (*fftin) -> getLen(), (*fftout) -> getLen(),
- getLatency() );
- }
- virtual ~CDSPBlockConvolver()
- {
- Filter -> unref();
- }
- virtual int getLatency() const
- {
- return( DoConsumeLatency ? 0 : Latency );
- }
- virtual double getLatencyFrac() const
- {
- return( LatencyFrac );
- }
- virtual int getMaxOutLen( const int MaxInLen ) const
- {
- R8BASSERT( MaxInLen >= 0 );
- return(( MaxInLen * UpFactor + DownFactor - 1 ) / DownFactor );
- }
- virtual void clear()
- {
- memset( &PrevInput[ 0 ], 0, PrevInputLen * sizeof( PrevInput[ 0 ]));
- if( DoConsumeLatency )
- {
- LatencyLeft = Latency;
- }
- else
- {
- LatencyLeft = 0;
- if( DownShift > 0 )
- {
- memset( &CurOutput[ 0 ], 0, ( BlockLen2 >> DownShift ) *
- sizeof( CurOutput[ 0 ]));
- }
- else
- {
- memset( &CurOutput[ BlockLen2 - OutOffset ], 0, OutOffset *
- sizeof( CurOutput[ 0 ]));
- memset( &CurOutput[ 0 ], 0, ( InputLen - OutOffset ) *
- sizeof( CurOutput[ 0 ]));
- }
- }
- memset( CurInput, 0, InputDelay * sizeof( CurInput[ 0 ]));
- InDataLeft = InputLen - InputDelay;
- UpSkip = 0;
- DownSkip = DownSkipInit;
- }
- virtual int process( double* ip, int l0, double*& op0 )
- {
- R8BASSERT( l0 >= 0 );
- R8BASSERT( UpFactor / DownFactor <= 1 || ip != op0 || l0 == 0 );
- double* op = op0;
- int l = l0 * UpFactor;
- l0 = 0;
- while( l > 0 )
- {
- const int Offs = InputLen - InDataLeft;
- if( l < InDataLeft )
- {
- InDataLeft -= l;
- if( UpShift >= 0 )
- {
- memcpy( &CurInput[ Offs >> UpShift ], ip,
- ( l >> UpShift ) * sizeof( CurInput[ 0 ]));
- }
- else
- {
- copyUpsample( ip, &CurInput[ Offs ], l );
- }
- copyToOutput( Offs - OutOffset, op, l, l0 );
- break;
- }
- const int b = InDataLeft;
- l -= b;
- InDataLeft = InputLen;
- int ilu;
- if( UpShift >= 0 )
- {
- const int bu = b >> UpShift;
- memcpy( &CurInput[ Offs >> UpShift ], ip,
- bu * sizeof( CurInput[ 0 ]));
- ip += bu;
- ilu = InputLen >> UpShift;
- }
- else
- {
- copyUpsample( ip, &CurInput[ Offs ], b );
- ilu = InputLen;
- }
- const size_t pil = PrevInputLen * sizeof( CurInput[ 0 ]);
- memcpy( &CurInput[ ilu ], PrevInput, pil );
- memcpy( PrevInput, &CurInput[ ilu - PrevInputLen ], pil );
- (*fftin) -> forward( CurInput );
- if( UpShift > 0 )
- {
- #if R8B_FLOATFFT
- mirrorInputSpectrum( (float*) CurInput );
- #else
- mirrorInputSpectrum( CurInput );
- #endif
- }
- if( Filter -> isZeroPhase() )
- {
- (*fftout) -> multiplyBlocksZP( Filter -> getKernelBlock(),
- CurInput );
- }
- else
- {
- (*fftout) -> multiplyBlocks( Filter -> getKernelBlock(),
- CurInput );
- }
- if( DownShift > 0 )
- {
- const int z = BlockLen2 >> DownShift;
- #if R8B_FLOATFFT
- float* const kb = (float*) Filter -> getKernelBlock();
- float* const p = (float*) CurInput;
- #else
- const double* const kb = Filter -> getKernelBlock();
- double* const p = CurInput;
- #endif
- p[ 1 ] = kb[ z ] * p[ z ] - kb[ z + 1 ] * p[ z + 1 ];
- }
- (*fftout) -> inverse( CurInput );
- copyToOutput( Offs - OutOffset, op, b, l0 );
- double* const tmp = CurInput;
- CurInput = CurOutput;
- CurOutput = tmp;
- }
- return( l0 );
- }
- private:
- CDSPFIRFilter* Filter;
-
- CPtrKeeper< CDSPRealFFTKeeper* > fftin;
-
-
- CPtrKeeper< CDSPRealFFTKeeper* > ffto2;
-
- CDSPRealFFTKeeper* fftout;
-
-
-
- int UpFactor;
-
- int DownFactor;
-
- bool DoConsumeLatency;
-
-
-
- int BlockLen2;
-
- int OutOffset;
-
- int PrevInputLen;
-
-
- int InputLen;
-
-
- int Latency;
-
- double LatencyFrac;
-
-
- int UpShift;
-
-
- int DownShift;
-
-
-
- int InputDelay;
-
-
-
- CFixedBuffer< double > WorkBlocks;
-
-
-
- double* PrevInput;
-
- double* CurInput;
-
- double* CurOutput;
-
- int InDataLeft;
-
-
- int LatencyLeft;
-
- int UpSkip;
-
-
- int DownSkip;
-
-
- int DownSkipInit;
-
-
- void copyUpsample( double*& ip0, double* op, int l0 )
- {
- int b = min( UpSkip, l0 );
- if( b != 0 )
- {
- UpSkip -= b;
- l0 -= b;
- *op = 0.0;
- op++;
- while( --b != 0 )
- {
- *op = 0.0;
- op++;
- }
- }
- double* ip = ip0;
- const int upf = UpFactor;
- int l = l0 / upf;
- int lz = l0 - l * upf;
- if( upf == 3 )
- {
- while( l != 0 )
- {
- op[ 0 ] = *ip;
- op[ 1 ] = 0.0;
- op[ 2 ] = 0.0;
- ip++;
- op += upf;
- l--;
- }
- }
- else
- if( upf == 5 )
- {
- while( l != 0 )
- {
- op[ 0 ] = *ip;
- op[ 1 ] = 0.0;
- op[ 2 ] = 0.0;
- op[ 3 ] = 0.0;
- op[ 4 ] = 0.0;
- ip++;
- op += upf;
- l--;
- }
- }
- else
- {
- const size_t zc = ( upf - 1 ) * sizeof( op[ 0 ]);
- while( l != 0 )
- {
- *op = *ip;
- ip++;
- memset( op + 1, 0, zc );
- op += upf;
- l--;
- }
- }
- if( lz != 0 )
- {
- *op = *ip;
- ip++;
- op++;
- UpSkip = upf - lz;
- while( --lz != 0 )
- {
- *op = 0.0;
- op++;
- }
- }
- ip0 = ip;
- }
-
- void copyToOutput( int Offs, double*& op0, int b, int& l0 )
- {
- if( Offs < 0 )
- {
- if( Offs + b <= 0 )
- {
- Offs += BlockLen2;
- }
- else
- {
- copyToOutput( Offs + BlockLen2, op0, -Offs, l0 );
- b += Offs;
- Offs = 0;
- }
- }
- if( LatencyLeft != 0 )
- {
- if( LatencyLeft >= b )
- {
- LatencyLeft -= b;
- return;
- }
- Offs += LatencyLeft;
- b -= LatencyLeft;
- LatencyLeft = 0;
- }
- const int df = DownFactor;
- if( DownShift > 0 )
- {
- int Skip = Offs & ( df - 1 );
- if( Skip > 0 )
- {
- Skip = df - Skip;
- b -= Skip;
- Offs += Skip;
- }
- if( b > 0 )
- {
- b = ( b + df - 1 ) >> DownShift;
- memcpy( op0, &CurOutput[ Offs >> DownShift ],
- b * sizeof( op0[ 0 ]));
- op0 += b;
- l0 += b;
- }
- }
- else
- {
- if( df > 1 )
- {
- const double* ip = &CurOutput[ Offs + DownSkip ];
- int l = ( b + df - 1 - DownSkip ) / df;
- DownSkip += l * df - b;
- double* op = op0;
- l0 += l;
- op0 += l;
- while( l > 0 )
- {
- *op = *ip;
- ip += df;
- op++;
- l--;
- }
- }
- else
- {
- memcpy( op0, &CurOutput[ Offs ], b * sizeof( op0[ 0 ]));
- op0 += b;
- l0 += b;
- }
- }
- }
-
- template< typename T >
- void mirrorInputSpectrum( T* const p )
- {
- const int bl1 = BlockLen2 >> UpShift;
- const int bl2 = bl1 + bl1;
- int i;
- for( i = bl1 + 2; i < bl2; i += 2 )
- {
- p[ i ] = p[ bl2 - i ];
- p[ i + 1 ] = -p[ bl2 - i + 1 ];
- }
- p[ bl1 ] = p[ 1 ];
- p[ bl1 + 1 ] = 0.0;
- p[ 1 ] = p[ 0 ];
- for( i = 1; i < UpShift; i++ )
- {
- const int z = bl1 << i;
- memcpy( &p[ z ], p, z * sizeof( p[ 0 ]));
- p[ z + 1 ] = 0.0;
- }
- }
- };
- }
- #endif
|