123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557 |
- //$ nocpp
-
- /**
- * @file CDSPFIRFilter.h
- *
- * @brief FIR filter generator and filter cache classes.
- *
- * This file includes low-pass FIR filter generator and filter cache.
- *
- * r8brain-free-src Copyright (c) 2013-2014 Aleksey Vaneev
- * See the "License.txt" file for license.
- */
-
- #ifndef R8B_CDSPFIRFILTER_INCLUDED
- #define R8B_CDSPFIRFILTER_INCLUDED
-
- #include "CDSPSincFilterGen.h"
- #include "CDSPRealFFT.h"
-
- namespace r8b
- {
-
- /**
- * Enumeration of filter's phase responses.
- */
-
- enum EDSPFilterPhaseResponse
- {
- fprLinearPhase = 0 ///< Linear-phase response. Features a linear-phase
- ///< high-latency response, with the latency expressed as integer
- ///< value.
- // fprMinPhase ///< Minimum-phase response. Features a minimal latency
- ///< response, but the response's phase is non-linear. The latency is
- ///< usually expressed as non-integer value, and usually is small, but
- ///< is never equal to zero. The minimum-phase filter is transformed
- ///< from the linear-phase filter. The transformation has precision
- ///< limits which may skew both the -3 dB point and attenuation of the
- ///< filter being transformed: as it was measured, the skew happens
- ///< purely at random, and in most cases it is within tolerable range.
- ///< In a small (1%) random subset of cases the skew is bigger and
- ///< cannot be predicted.
- };
-
- /**
- * @brief Calculation and storage class for FIR filters.
- *
- * Class that implements calculation and storing of a FIR filter (currently
- * contains low-pass filter calculation routine designed for sample rate
- * conversion). Objects of this class cannot be created directly, but can be
- * obtained via the CDSPFilterCache::getLPFilter() static function.
- */
-
- class CDSPFIRFilter : public R8B_BASECLASS
- {
- R8BNOCTOR(CDSPFIRFilter)
-
- friend class CDSPFIRFilterCache;
-
- public:
- ~CDSPFIRFilter()
- {
- R8BASSERT(RefCount == 0);
-
- delete Next;
- }
-
- /**
- * @return The minimal allowed low-pass filter's transition band, in percent.
- */
- static double getLPMinTransBand() { return (0.5); }
-
- /**
- * @return The maximal allowed low-pass filter's transition band, in percent.
- */
- static double getLPMaxTransBand() { return (45.0); }
-
- /**
- * @return The minimal allowed low-pass filter's stop-band attenuation, in decibel.
- */
- static double getLPMinAtten() { return (49.0); }
-
- /**
- * @return The maximal allowed low-pass filter's stop-band attenuation, in decibel.
- */
- static double getLPMaxAtten() { return (218.0); }
-
- /**
- * @return "True" if kernel block of *this filter has zero-phase response.
- */
- bool isZeroPhase() const { return (IsZeroPhase); }
-
- /**
- * @return Filter's latency, in samples (integer part).
- */
- int getLatency() const { return (Latency); }
-
- /**
- * @return Filter's latency, in samples (fractional part). Always zero for linear-phase filters.
- */
- double getLatencyFrac() const { return (LatencyFrac); }
-
- /**
- * @return Filter kernel length, in samples. Not to be confused with the block length.
- */
- int getKernelLen() const { return (KernelLen); }
-
- /**
- * @return Filter's block length, espressed as Nth power of 2. The actual length is twice as large due to zero-padding.
- */
- int getBlockLenBits() const { return (BlockLenBits); }
-
- /**
- * @return Filter's kernel block, in complex-numbered form obtained via
- * the CDSPRealFFT::forward() function call, zero-padded, gain-adjusted
- * with the CDSPRealFFT::getInvMulConst() * ReqGain constant, immediately
- * suitable for convolution. Kernel block may have "zero-phase" response,
- * depending on the isZeroPhase() function's result.
- */
- const double* getKernelBlock() const { return (KernelBlock); }
-
- /**
- * This function should be called when the filter obtained via the
- * filter cache is no longer needed.
- */
-
- void unref();
-
- private:
- double ReqNormFreq = 0; ///< Required normalized frequency, 0 to 1 inclusive.
- double ReqTransBand = 0; ///< Required transition band in percent, as passed by the user.
- double ReqAtten = 0; ///< Required stop-band attenuation in decibel, as passed by the user (positive value).
- EDSPFilterPhaseResponse ReqPhase = fprLinearPhase; ///< Required filter's phase response.
- double ReqGain = 0; ///< Required overall filter's gain.
- CDSPFIRFilter* Next = nullptr; ///< Next FIR filter in cache's list.
- int RefCount = 1; ///< The number of references made to *this FIR filter.
- bool IsZeroPhase = false; ///< "True" if kernel block of *this filter has zero-phase response.
- int Latency = 0; ///< Filter's latency in samples (integer part).
- double LatencyFrac = 0; ///< Filter's latency in samples (fractional part).
- int KernelLen = 0; ///< Filter kernel length, in samples.
- int BlockLenBits =
- 0; ///< Block length used to store *this FIR filter, expressed as Nth power of 2. This value is used directly by the convolver.
- CFixedBuffer<double>
- KernelBlock; ///< FIR filter buffer, capacity equals to 1 << ( BlockLenBits + 1 ). Second part of the buffer contains zero-padding to allow alias-free convolution.
-
- CDSPFIRFilter() { }
-
- /**
- * Function builds filter kernel based on the "Req" parameters.
- *
- * @param ExtAttenCorrs External attentuation correction table, for
- * internal use.
- */
-
- void buildLPFilter(const double* const ExtAttenCorrs)
- {
- const double tb = ReqTransBand * 0.01;
- double fo1;
- double hl;
- double atten = -ReqAtten;
-
- if (tb >= 0.25)
- {
- if (ReqAtten >= 117.0) { atten -= 1.60; }
- else if (ReqAtten >= 60.0) { atten -= 1.91; }
- else { atten -= 2.25; }
- }
- else if (tb >= 0.10)
- {
- if (ReqAtten >= 117.0) { atten -= 0.69; }
- else if (ReqAtten >= 60.0) { atten -= 0.73; }
- else { atten -= 1.13; }
- }
- else
- {
- if (ReqAtten >= 117.0) { atten -= 0.21; }
- else if (ReqAtten >= 60.0) { atten -= 0.25; }
- else { atten -= 0.36; }
- }
-
- static const int AttenCorrCount = 264;
- static const double AttenCorrMin = 49.0;
- static const double AttenCorrDiff = 176.25;
- int AttenCorr = (int)floor((-atten - AttenCorrMin) * AttenCorrCount / AttenCorrDiff + 0.5);
-
- AttenCorr = min(AttenCorrCount, max(0, AttenCorr));
-
- if (ExtAttenCorrs != nullptr) { atten -= ExtAttenCorrs[AttenCorr]; }
- else if (tb >= 0.25)
- {
- static const double AttenCorrScale = 101.0;
- static const signed char AttenCorrs[] = {
- -127, -127, -125, -125, -122, -119, -115, -110, -104, -97,
- -91, -82, -75, -24, -16, -6, 4, 14, 24, 29, 30, 32, 37, 44,
- 51, 57, 63, 67, 65, 50, 53, 56, 58, 60, 63, 64, 66, 68, 74,
- 77, 78, 78, 78, 79, 79, 60, 60, 60, 61, 59, 52, 47, 41, 36,
- 30, 24, 17, 9, 0, -8, -10, -11, -14, -13, -18, -25, -31, -38,
- -44, -50, -57, -63, -68, -74, -81, -89, -96, -101, -104, -107,
- -109, -110, -86, -84, -85, -82, -80, -77, -73, -67, -62, -55,
- -48, -42, -35, -30, -20, -11, -2, 5, 6, 6, 7, 11, 16, 21, 26,
- 34, 41, 46, 49, 52, 55, 56, 48, 49, 51, 51, 52, 52, 52, 52,
- 52, 51, 51, 50, 47, 47, 50, 48, 46, 42, 38, 35, 31, 27, 24,
- 20, 16, 12, 11, 12, 10, 8, 4, -1, -6, -11, -16, -19, -17, -21,
- -24, -27, -32, -34, -37, -38, -40, -41, -40, -40, -42, -41,
- -44, -45, -43, -41, -34, -31, -28, -24, -21, -18, -14, -10,
- -5, -1, 2, 5, 8, 7, 4, 3, 2, 2, 4, 6, 8, 9, 9, 10, 10, 10, 10,
- 9, 8, 9, 11, 14, 13, 12, 11, 10, 8, 7, 6, 5, 3, 2, 2, -1, -1,
- -3, -3, -4, -4, -5, -4, -6, -7, -9, -5, -1, -1, 0, 1, 0, -2,
- -3, -4, -5, -5, -8, -13, -13, -13, -12, -13, -12, -11, -11,
- -9, -8, -7, -5, -3, -1, 2, 4, 6, 9, 10, 11, 14, 18, 21, 24,
- 27, 30, 34, 37, 37, 39, 40
- };
-
- atten -= AttenCorrs[AttenCorr] / AttenCorrScale;
- }
- else if (tb >= 0.10)
- {
- static const double AttenCorrScale = 210.0;
- static const signed char AttenCorrs[] = {
- -113, -118, -122, -125, -126, -97, -95, -92, -92, -89, -82,
- -75, -69, -48, -42, -36, -30, -22, -14, -5, -2, 1, 6, 13, 22,
- 28, 35, 41, 48, 55, 56, 56, 61, 65, 71, 77, 81, 83, 85, 85,
- 74, 74, 73, 72, 71, 70, 68, 64, 59, 56, 49, 52, 46, 42, 36,
- 32, 26, 20, 13, 7, -2, -6, -10, -15, -20, -27, -33, -38, -44,
- -43, -48, -53, -57, -63, -69, -73, -75, -79, -81, -74, -76,
- -77, -77, -78, -81, -80, -80, -78, -76, -65, -62, -59, -56,
- -51, -48, -44, -38, -33, -25, -19, -13, -5, -1, 2, 7, 13, 17,
- 21, 25, 30, 35, 40, 45, 50, 53, 56, 57, 55, 58, 59, 62, 64,
- 67, 67, 68, 68, 62, 61, 61, 59, 59, 57, 57, 55, 52, 48, 42,
- 38, 35, 31, 26, 20, 15, 13, 10, 7, 3, -2, -8, -13, -17, -23,
- -28, -34, -37, -40, -41, -45, -48, -50, -53, -57, -59, -62,
- -63, -63, -57, -57, -56, -56, -54, -54, -53, -49, -48, -41,
- -38, -33, -31, -26, -23, -18, -12, -9, -7, -7, -3, 0, 5, 9,
- 14, 16, 20, 22, 21, 23, 25, 27, 28, 29, 34, 33, 35, 33, 31,
- 30, 29, 29, 26, 26, 25, 24, 20, 19, 15, 10, 8, 4, 1, -2, -6,
- -10, -16, -19, -23, -26, -27, -30, -34, -39, -43, -47, -51,
- -52, -54, -56, -58, -59, -62, -63, -66, -65, -65, -64, -59,
- -57, -54, -52, -48, -44, -42, -37, -32, -22, -17, -10, -3, 5,
- 13, 22, 30, 40, 50, 60, 72
- };
-
- atten -= AttenCorrs[AttenCorr] / AttenCorrScale;
- }
- else
- {
- static const double AttenCorrScale = 196.0;
- static const signed char AttenCorrs[] = {
- -15, -17, -20, -20, -20, -21, -20, -16, -17, -18, -17, -13,
- -12, -11, -9, -7, -5, -4, -1, 1, 3, 4, 5, 6, 7, 9, 9, 10, 10,
- 10, 11, 11, 11, 12, 12, 12, 10, 11, 10, 10, 8, 10, 11, 10, 11,
- 11, 13, 14, 15, 19, 27, 26, 23, 18, 14, 8, 4, -2, -6, -12,
- -17, -23, -28, -33, -37, -42, -46, -49, -53, -57, -60, -61,
- -64, -65, -67, -66, -66, -66, -65, -64, -61, -59, -56, -52,
- -48, -42, -38, -31, -27, -19, -13, -7, -1, 8, 14, 22, 29, 37,
- 45, 52, 59, 66, 73, 80, 86, 91, 96, 100, 104, 108, 111, 114,
- 115, 117, 118, 120, 120, 118, 117, 114, 113, 111, 107, 103,
- 99, 95, 89, 84, 78, 72, 66, 60, 52, 44, 37, 30, 21, 14, 6, -3,
- -11, -18, -26, -34, -43, -51, -58, -65, -73, -78, -85, -90,
- -97, -102, -107, -113, -115, -118, -121, -125, -125, -126,
- -126, -126, -125, -124, -121, -119, -115, -111, -109, -101,
- -102, -95, -88, -81, -73, -67, -63, -54, -47, -40, -33, -26,
- -18, -11, -5, 2, 8, 14, 19, 25, 31, 36, 37, 43, 47, 49, 51,
- 52, 57, 57, 56, 57, 58, 58, 58, 57, 56, 52, 52, 50, 48, 44,
- 41, 39, 37, 33, 31, 26, 24, 21, 18, 14, 11, 8, 4, 2, -2, -5,
- -7, -9, -11, -13, -15, -16, -18, -19, -20, -23, -24, -24, -25,
- -27, -26, -27, -29, -30, -31, -32, -35, -36, -39, -40, -44,
- -46, -51, -54, -59, -63, -69, -76, -83, -91, -98
- };
-
- atten -= AttenCorrs[AttenCorr] / AttenCorrScale;
- }
-
- double pwr = 7.43932822146293e-8 * sqr(atten) + 0.000102747434588003 * cos(0.00785021930010397 * atten) * cos(
- 0.633854318781239 + 0.103208573657699 * atten)
- - 0.00798132247867036 - 0.000903555213543865 * atten - 0.0969365532127236 * exp(0.0779275237937911 * atten) - 1.37304948662012e-5 *
- atten * cos(0.00785021930010397 * atten);
-
- if (pwr <= 0.067665322581)
- {
- if (tb >= 0.25)
- {
- hl = 2.6778150875894 / tb + 300.547590563091 * atan(atan(2.68959772209918 * pwr)) / (5.5099277187035 * tb - tb * tanh(cos(asinh(atten))));
- fo1 = 0.987205355829873 * tb + 1.00011788929851 * atan2(-0.321432067051302 - 6.19131357321578 * sqrt(pwr),
- hl + -1.14861472207245 / (hl - 14.1821147585957) + pow(0.9521145021664,
- pow(
- atan2(
- 1.12018764830637,
- tb),
- 2.10988901686912 * hl -
- 20.9691278378345)));
- }
- else if (tb >= 0.10)
- {
- hl = (1.56688617018066 + 142.064321294568 * pwr + 0.00419441117131136 * cos(243.633511747297 * pwr) - 0.022953443903576 * atten -
- 0.026629568860284 * cos(127.715550622571 * pwr)) / tb;
- fo1 = 0.982299356642411 * tb + 0.999441744774215 * asinh((-0.361783054039583 - 5.80540593623676 * sqrt(pwr)) / hl);
- }
- else
- {
- hl = (2.45739657014937 + 269.183679500541 * pwr * cos(
- 5.73225668178813 + atan2(cosh(0.988861169868941 - 17.2201556280744 * pwr), 1.08340138240431 * pwr))) / tb;
- fo1 = 2.291956939 * tb + 0.01942450693 * sqr(tb) * hl - 4.67538973161837 * pwr * tb - 1.668433124 * tb * pow(pwr, pwr);
- }
- }
- else
- {
- if (tb >= 0.25)
- {
- hl = (1.50258368698213 + 158.556968859477 * asinh(pwr) * tanh(57.9466246871383 * tanh(pwr)) - 0.0105440479814834 * atten) / tb;
- fo1 = 0.994024401639321 * tb + (-0.236282717577215 - 6.8724924545387 * sqrt(sin(pwr))) / hl;
- }
- else if (tb >= 0.10)
- {
- hl = (1.50277377248945 + 158.222625721046 * asinh(pwr) * tanh(1.02875299001715 + 42.072277322604 * pwr) - 0.0108380943845632 * atten) / tb;
- fo1 = 0.992539376734551 * tb + (-0.251747813037178 - 6.74159892452584 * sqrt(tanh(tanh(tan(pwr))))) / hl;
- }
- else
- {
- hl = (1.15990238966306 * pwr - 5.02124037125213 * sqr(pwr) - 0.158676856669827 * atten * cos(
- 1.1609073390614 * pwr - 6.33932586197475 * pwr * sqr(pwr))) / tb;
- fo1 = 0.867344453126885 * tb + 0.052693817907757 * tb * log(pwr) + 0.0895511178735932 * tb * atan(59.7538527741309 * pwr) -
- 0.0745653568081453 * pwr * tb;
- }
- }
-
- double WinParams[ 2 ];
- WinParams[0] = 125.0;
- WinParams[1] = pwr;
-
- CDSPSincFilterGen sinc;
- sinc.Len2 = 0.25 * hl / ReqNormFreq;
- sinc.Freq1 = 0.0;
- sinc.Freq2 = M_PI * (1.0 - fo1) * ReqNormFreq;
- sinc.initBand(CDSPSincFilterGen::wftKaiser, WinParams, true);
-
- KernelLen = sinc.KernelLen;
- BlockLenBits = getBitOccupancy(KernelLen - 1);
- const int BlockLen = 1 << BlockLenBits;
-
- KernelBlock.alloc(BlockLen * 2);
- sinc.generateBand(&KernelBlock[0],
- &CDSPSincFilterGen::calcWindowKaiser);
-
- /* if( ReqPhase == fprLinearPhase )
- {*/
- IsZeroPhase = true;
- Latency = sinc.fl2;
- LatencyFrac = 0.0;
- /* }
- else
- {
- IsZeroPhase = false;
- double DCGroupDelay;
-
- calcMinPhaseTransform( &KernelBlock[ 0 ], KernelLen, 3, false, &DCGroupDelay );
-
- Latency = (int) DCGroupDelay;
- LatencyFrac = DCGroupDelay - Latency;
- }*/
-
- CDSPRealFFTKeeper ffto(BlockLenBits + 1);
-
- if (IsZeroPhase)
- {
- // Calculate DC gain.
-
- double s = 0.0;
- int i;
-
- for (i = 0; i < KernelLen; ++i) { s += KernelBlock[i]; }
-
- s = ffto->getInvMulConst() * ReqGain / s;
-
- // Time-shift the filter so that zero-phase response is produced.
- // Simultaneously multiply by "s".
-
- for (i = 0; i <= sinc.fl2; ++i) { KernelBlock[i] = KernelBlock[sinc.fl2 + i] * s; }
- for (i = 1; i <= sinc.fl2; ++i) { KernelBlock[BlockLen * 2 - i] = KernelBlock[i]; }
-
- memset(&KernelBlock[sinc.fl2 + 1], 0, (BlockLen * 2 - KernelLen) * sizeof(double));
- }
- else
- {
- normalizeFIRFilter(&KernelBlock[0], KernelLen, ffto->getInvMulConst() * ReqGain);
- memset(&KernelBlock[KernelLen], 0, (BlockLen * 2 - KernelLen) * sizeof(double));
- }
-
- ffto->forward(KernelBlock);
-
- R8BCONSOLE("CDSPFIRFilter: flt_len=%i latency=%i nfreq=%.4f tb=%.1f att=%.1f gain=%.3f\n", KernelLen, Latency, ReqNormFreq, ReqTransBand, ReqAtten,
- ReqGain);
- }
- };
-
- /**
- * @brief FIR filter cache class.
- *
- * Class that implements cache for calculated FIR filters. The required FIR
- * filter should be obtained via the getLPFilter() static function.
- */
-
- class CDSPFIRFilterCache : public R8B_BASECLASS
- {
- friend class CDSPFIRFilter;
-
- public:
- /**
- * @return The number of filters present in the cache now. This value can
- * be monitored for debugging "forgotten" filters.
- */
-
- static int getObjCount()
- {
- R8BSYNC(StateSync);
-
- return (ObjCount);
- }
-
- /**
- * Function calculates or returns reference to a previously calculated
- * (cached) low-pass FIR filter. Note that the real transition band and
- * attenuation achieved by the filter varies with the magnitude of the
- * required attenuation, and are never 100% exact.
- *
- * @param ReqNormFreq Required normalized frequency, in the range 0 to 1,
- * inclusive. This is the point after which the stop-band spans.
- * @param ReqTransBand Required transition band, in percent of the
- * 0 to ReqNormFreq spectral bandwidth, in the range
- * CDSPFIRFilter::getLPMinTransBand() to
- * CDSPFIRFilter::getLPMaxTransBand(), inclusive. The transition band
- * specifies the part of the spectrum between the -3 dB and ReqNormFreq
- * points. The real resulting -3 dB point varies in the range from -3.00
- * to -3.05 dB, but is generally very close to -3 dB.
- * @param ReqAtten Required stop-band attenuation in decibel, in the range
- * CDSPFIRFilter::getLPMinAtten() to CDSPFIRFilter::getLPMaxAtten(),
- * inclusive. Note that the actual stop-band attenuation of the resulting
- * filter may be 0.40-4.46 dB higher.
- * @param ReqPhase Required filter's phase response.
- * @param ReqGain Required overall filter's gain (1.0 for unity gain).
- * @param AttenCorrs Attentuation correction table, to pass to the filter
- * generation function. For internal use.
- * @return A reference to a new or a previously calculated low-pass FIR
- * filter object with the required characteristics. A reference count is
- * incremented in the returned filter object which should be released
- * after use via the CDSPFIRFilter::unref() function.
- */
-
- static CDSPFIRFilter& getLPFilter(const double ReqNormFreq, const double ReqTransBand, const double ReqAtten,
- const EDSPFilterPhaseResponse ReqPhase, const double ReqGain, const double* const AttenCorrs = nullptr)
- {
- R8BASSERT(ReqNormFreq > 0.0 && ReqNormFreq <= 1.0);
- R8BASSERT(ReqTransBand >= CDSPFIRFilter :: getLPMinTransBand());
- R8BASSERT(ReqTransBand <= CDSPFIRFilter :: getLPMaxTransBand());
- R8BASSERT(ReqAtten >= CDSPFIRFilter :: getLPMinAtten());
- R8BASSERT(ReqAtten <= CDSPFIRFilter :: getLPMaxAtten());
- R8BASSERT(ReqGain > 0.0);
-
- R8BSYNC(StateSync);
-
- CDSPFIRFilter* PrevObj = nullptr;
- CDSPFIRFilter* CurObj = Objects;
-
- while (CurObj != nullptr)
- {
- if (CurObj->ReqNormFreq == ReqNormFreq &&
- CurObj->ReqTransBand == ReqTransBand &&
- CurObj->ReqAtten == ReqAtten &&
- CurObj->ReqPhase == ReqPhase &&
- CurObj->ReqGain == ReqGain) { break; }
-
- if (CurObj->Next == nullptr && ObjCount >= R8B_FILTER_CACHE_MAX)
- {
- if (CurObj->RefCount == 0)
- {
- // Delete the last filter which is not used.
-
- PrevObj->Next = nullptr;
- delete CurObj;
- ObjCount--;
- }
- else
- {
- // Move the last filter to the top of the list since it
- // seems to be in use for a long time.
-
- PrevObj->Next = nullptr;
- CurObj->Next = Objects.unkeep();
- Objects = CurObj;
- }
-
- CurObj = nullptr;
- break;
- }
-
- PrevObj = CurObj;
- CurObj = CurObj->Next;
- }
-
- if (CurObj != nullptr)
- {
- CurObj->RefCount++;
-
- if (PrevObj == nullptr) { return (*CurObj); }
-
- // Remove the filter from the list temporarily.
-
- PrevObj->Next = CurObj->Next;
- }
- else
- {
- // Create a new filter object (with RefCount == 1) and build the
- // filter kernel.
-
- CurObj = new CDSPFIRFilter();
- CurObj->ReqNormFreq = ReqNormFreq;
- CurObj->ReqTransBand = ReqTransBand;
- CurObj->ReqAtten = ReqAtten;
- CurObj->ReqPhase = ReqPhase;
- CurObj->ReqGain = ReqGain;
- ObjCount++;
-
- CurObj->buildLPFilter(AttenCorrs);
- }
-
- // Insert the filter at the start of the list.
-
- CurObj->Next = Objects.unkeep();
- Objects = CurObj;
-
- return (*CurObj);
- }
-
- private:
- static CSyncObject StateSync; ///< Cache state synchronizer.
- ///<
- static CPtrKeeper<CDSPFIRFilter*> Objects; ///< The chain of cached
- ///< objects.
- ///<
- static int ObjCount; ///< The number of objects currently preset in the
- ///< cache.
- ///<
- };
-
- // ---------------------------------------------------------------------------
- // CDSPFIRFilter PUBLIC
- // ---------------------------------------------------------------------------
-
- inline void CDSPFIRFilter::unref()
- {
- R8BSYNC(CDSPFIRFilterCache :: StateSync);
-
- RefCount--;
- }
-
- // ---------------------------------------------------------------------------
- } // namespace r8b
-
- #endif // R8B_CDSPFIRFILTER_INCLUDED
|