@@ -625,6 +625,172 @@ int FilterDesigner<CoeffType>::designLinkwitzRiley (
625625 return static_cast <int > (lowCoeffs.size ());
626626}
627627
628+ // ==============================================================================
629+ // FIR Filter Design Implementations
630+ // ==============================================================================
631+
632+ template <typename CoeffType>
633+ std::vector<CoeffType> FilterDesigner<CoeffType>::designFIRLowpass (
634+ int numCoefficients,
635+ CoeffType cutoffFreq,
636+ double sampleRate,
637+ WindowType windowType) noexcept
638+ {
639+ jassert (numCoefficients > 0 );
640+ jassert (cutoffFreq > static_cast <CoeffType> (0.0 ));
641+ jassert (sampleRate > 0.0 );
642+ jassert (cutoffFreq < static_cast <CoeffType> (sampleRate / 2.0 ));
643+
644+ numCoefficients = nextOdd (numCoefficients);
645+ std::vector<CoeffType> coefficients (numCoefficients);
646+
647+ const auto normalizedCutoff = static_cast <CoeffType> (2.0 ) * cutoffFreq / static_cast <CoeffType> (sampleRate);
648+ const int center = (numCoefficients - 1 ) / 2 ;
649+
650+ // Generate ideal lowpass sinc function
651+ for (int i = 0 ; i < numCoefficients; ++i)
652+ {
653+ if (i == center)
654+ {
655+ coefficients[i] = normalizedCutoff;
656+ }
657+ else
658+ {
659+ const auto x = MathConstants<CoeffType>::pi * normalizedCutoff * static_cast <CoeffType> (i - center);
660+ coefficients[i] = std::sin (x) / (MathConstants<CoeffType>::pi * static_cast <CoeffType> (i - center));
661+ }
662+ }
663+
664+ // Apply window function
665+ for (int i = 0 ; i < numCoefficients; ++i)
666+ {
667+ const auto windowValue = WindowFunctions<CoeffType>::getValue (windowType, i, numCoefficients);
668+ coefficients[i] *= windowValue;
669+ }
670+
671+ // Normalization
672+ const auto sum = std::accumulate (coefficients.begin (), coefficients.end (), static_cast <CoeffType> (0.0 ));
673+ if (sum != static_cast <CoeffType> (0.0 ))
674+ for (auto & c : coefficients)
675+ c /= sum;
676+
677+ return coefficients;
678+ }
679+
680+ template <typename CoeffType>
681+ std::vector<CoeffType> FilterDesigner<CoeffType>::designFIRHighpass (
682+ int numCoefficients,
683+ CoeffType cutoffFreq,
684+ double sampleRate,
685+ WindowType windowType) noexcept
686+ {
687+ jassert (numCoefficients > 0 );
688+ jassert (cutoffFreq > static_cast <CoeffType> (0.0 ));
689+ jassert (sampleRate > 0.0 );
690+ jassert (cutoffFreq < static_cast <CoeffType> (sampleRate / 2.0 ));
691+
692+ // Generate lowpass first
693+ numCoefficients = nextOdd (numCoefficients);
694+ auto coefficients = designFIRLowpass (numCoefficients, cutoffFreq, sampleRate, windowType);
695+
696+ // Convert to highpass using spectral inversion
697+ const int center = (numCoefficients - 1 ) / 2 ;
698+ for (int i = 0 ; i < numCoefficients; ++i)
699+ coefficients[i] = -coefficients[i];
700+
701+ // Add unit impulse at center
702+ coefficients[center] += static_cast <CoeffType> (1.0 );
703+
704+ // Normalization
705+ CoeffType hpi (0.0 );
706+ for (int n = 0 ; n < numCoefficients; ++n)
707+ hpi += coefficients[n] * ((n & 1 ) ? static_cast <CoeffType> (-1.0 ) : static_cast <CoeffType> (1.0 ));
708+
709+ if (hpi != static_cast <CoeffType> (0.0 ))
710+ for (auto & c : coefficients)
711+ c /= hpi;
712+
713+ return coefficients;
714+ }
715+
716+ template <typename CoeffType>
717+ std::vector<CoeffType> FilterDesigner<CoeffType>::designFIRBandpass (
718+ int numCoefficients,
719+ CoeffType lowCutoffFreq,
720+ CoeffType highCutoffFreq,
721+ double sampleRate,
722+ WindowType windowType) noexcept
723+ {
724+ jassert (numCoefficients > 0 );
725+ jassert (lowCutoffFreq > static_cast <CoeffType> (0.0 ));
726+ jassert (highCutoffFreq > lowCutoffFreq);
727+ jassert (sampleRate > 0.0 );
728+ jassert (highCutoffFreq < static_cast <CoeffType> (sampleRate / 2.0 ));
729+
730+ numCoefficients = nextOdd (numCoefficients);
731+ std::vector<CoeffType> coefficients (numCoefficients);
732+
733+ const auto normalizedLow = static_cast <CoeffType> (2.0 ) * lowCutoffFreq / static_cast <CoeffType> (sampleRate);
734+ const auto normalizedHigh = static_cast <CoeffType> (2.0 ) * highCutoffFreq / static_cast <CoeffType> (sampleRate);
735+ const int center = (numCoefficients - 1 ) / 2 ;
736+
737+ // Generate ideal bandpass as difference of two sinc functions
738+ for (int i = 0 ; i < numCoefficients; ++i)
739+ {
740+ if (i == center)
741+ {
742+ coefficients[i] = normalizedHigh - normalizedLow;
743+ }
744+ else
745+ {
746+ const auto n = static_cast <CoeffType> (i - center);
747+ const auto xHigh = MathConstants<CoeffType>::pi * normalizedHigh * n;
748+ const auto xLow = MathConstants<CoeffType>::pi * normalizedLow * n;
749+
750+ coefficients[i] = (std::sin (xHigh) - std::sin (xLow)) / (MathConstants<CoeffType>::pi * n);
751+ }
752+ }
753+
754+ // Apply window function
755+ for (int i = 0 ; i < numCoefficients; ++i)
756+ {
757+ const auto windowValue = WindowFunctions<CoeffType>::getValue (windowType, i, numCoefficients);
758+ coefficients[i] *= windowValue;
759+ }
760+
761+ return coefficients;
762+ }
763+
764+ template <typename CoeffType>
765+ std::vector<CoeffType> FilterDesigner<CoeffType>::designFIRBandstop (
766+ int numCoefficients,
767+ CoeffType lowCutoffFreq,
768+ CoeffType highCutoffFreq,
769+ double sampleRate,
770+ WindowType windowType) noexcept
771+ {
772+ jassert (numCoefficients > 0 );
773+ jassert (lowCutoffFreq > static_cast <CoeffType> (0.0 ));
774+ jassert (highCutoffFreq > lowCutoffFreq);
775+ jassert (sampleRate > 0.0 );
776+ jassert (highCutoffFreq < static_cast <CoeffType> (sampleRate / 2.0 ));
777+
778+ // Generate bandpass first
779+ numCoefficients = nextOdd (numCoefficients);
780+ auto coefficients = designFIRBandpass (numCoefficients, lowCutoffFreq, highCutoffFreq, sampleRate, windowType);
781+
782+ // Convert to bandstop using spectral inversion
783+ const int center = (numCoefficients - 1 ) / 2 ;
784+
785+ for (int i = 0 ; i < numCoefficients; ++i)
786+ coefficients[i] = -coefficients[i];
787+
788+ // Add unit impulse at center
789+ coefficients[center] += static_cast <CoeffType> (1.0 );
790+
791+ return coefficients;
792+ }
793+
628794// ==============================================================================
629795
630796template class FilterDesigner <float >;
0 commit comments