FilterStageIIR.cc

Go to the documentation of this file.
00001 
00002 //
00003 //  $Id: FilterStageIIR.cc 538 2010-07-17 23:59:03Z weegreenblobbie $
00004 //
00005 //  Copyright (c) 2008 Nick Hilton
00006 //
00007 //  weegreenblobbie_yahoo_com (replace '_' with '@' and '.')
00008 //
00010 
00012 //
00013 //  This program is free software; you can redistribute it and/or modify
00014 //  it under the terms of the GNU General Public License as published by
00015 //  the Free Software Foundation; either version 2 of the License, or
00016 //  (at your option) any later version.
00017 //
00018 //  This program is distributed in the hope that it will be useful,
00019 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021 //  GNU Library General Public License for more details.
00022 //
00023 //  You should have received a copy of the GNU General Public License
00024 //  along with this program; if not, write to the Free Software
00025 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00026 //
00028 
00029 #include <Nsound/AudioStream.h>
00030 #include <Nsound/Buffer.h>
00031 #include <Nsound/FilterStageIIR.h>
00032 
00033 #include <cmath>
00034 #include <string.h>
00035 #include <iostream>
00036 
00037 using namespace Nsound;
00038 
00039 using std::cout;
00040 using std::endl;
00041 
00043 FilterStageIIR::
00044 FilterStageIIR(
00045     Type type,
00046     const float64 & sample_rate,
00047     uint32 n_poles,
00048     const float64 & frequency,
00049     const float64 & percent_ripple)
00050     :
00051     Filter(sample_rate),
00052     type_(type),
00053     n_poles_(n_poles),
00054     frequency_(frequency),
00055     percent_ripple_(percent_ripple),
00056     a_(NULL),
00057     b_(NULL),
00058     x_history_(NULL),
00059     x_ptr_(NULL),
00060     x_end_ptr_(NULL),
00061     y_history_(NULL),
00062     y_ptr_(NULL),
00063     y_end_ptr_(NULL),
00064     kernel_cache_()
00065 {
00066     if(n_poles_ > 20)
00067     {
00068         n_poles_ = 20;
00069     }
00070     else if(n_poles_ < 2)
00071     {
00072         n_poles_ = 2;
00073     }
00074 
00075     if(n_poles_ % 2 != 0)
00076     {
00077         ++n_poles_;
00078     }
00079 
00080     x_history_ = new float64 [n_poles_ + 1];
00081     x_ptr_     = x_history_;
00082     x_end_ptr_ = x_history_ + n_poles_ + 1;
00083 
00084     y_history_ = new float64 [n_poles_ + 1];
00085     y_ptr_     = y_history_;
00086     y_end_ptr_ = y_history_ + n_poles_ + 1;
00087 
00088     reset();
00089 }
00090 
00092 FilterStageIIR::
00093 FilterStageIIR(const FilterStageIIR & copy)
00094     :
00095     Filter(copy.sample_rate_),
00096     type_(copy.type_),
00097     n_poles_(copy.n_poles_),
00098     frequency_(copy.frequency_),
00099     percent_ripple_(copy.percent_ripple_),
00100     a_(NULL),
00101     b_(NULL),
00102     x_history_(NULL),
00103     x_ptr_(NULL),
00104     x_end_ptr_(NULL),
00105     y_history_(NULL),
00106     y_ptr_(NULL),
00107     y_end_ptr_(NULL),
00108     kernel_cache_()
00109 {
00110     *this = copy;
00111 }
00112 
00114 FilterStageIIR::
00115 ~FilterStageIIR()
00116 {
00117     delete [] x_history_;
00118     delete [] y_history_;
00119 
00120     FilterStageIIR::KernelCache::iterator itor = kernel_cache_.begin();
00121     FilterStageIIR::KernelCache::iterator end = kernel_cache_.end();
00122 
00123     while(itor != end)
00124     {
00125         delete [] itor->b_;
00126         delete [] itor->a_;
00127         ++itor;
00128     }
00129 }
00130 
00132 AudioStream
00133 FilterStageIIR::
00134 filter(const AudioStream & x)
00135 {
00136     return Filter::filter(x);
00137 };
00138 
00139 
00141 AudioStream
00142 FilterStageIIR::
00143 filter(const AudioStream & x, const float64 & f)
00144 {
00145     return Filter::filter(x, f);
00146 }
00147 
00149 AudioStream
00150 FilterStageIIR::
00151 filter(const AudioStream & x, const Buffer & frequencies)
00152 {
00153     return Filter::filter(x, frequencies);
00154 }
00155 
00157 Buffer
00158 FilterStageIIR::
00159 filter(const Buffer & x)
00160 {
00161     return Filter::filter(x);
00162 }
00163 
00165 Buffer
00166 FilterStageIIR::
00167 filter(const Buffer & x, const float64 & f)
00168 {
00169     // Instead of calling Filter::filter(x,f), we implement this function here
00170     // to avoid calling makeKernel(f) for each sample.
00171 
00172 //~    cout << "f = " << f << endl;
00173 
00174     FilterStageIIR::reset();
00175     FilterStageIIR::makeKernel(f);
00176 
00177     Buffer::const_iterator itor = x.begin();
00178     Buffer::const_iterator end = x.end();
00179 
00180     Buffer y(x.getLength());
00181     while(itor != end)
00182     {
00183         y << FilterStageIIR::filter(*itor);
00184         ++itor;
00185     }
00186 
00187     return y;
00188 }
00189 
00191 Buffer
00192 FilterStageIIR::
00193 filter(const Buffer & x, const Buffer & frequencies)
00194 {
00195     return Filter::filter(x, frequencies);
00196 }
00197 
00199 FilterStageIIR &
00200 FilterStageIIR::
00201 operator=(const FilterStageIIR & rhs)
00202 {
00203     if(this == &rhs) return *this;
00204 
00205     uint32 n_poles_orig = n_poles_;
00206 
00207     type_           = rhs.type_;
00208     n_poles_        = rhs.n_poles_;
00209     frequency_      = rhs.frequency_;
00210     percent_ripple_ = rhs.percent_ripple_;
00211 
00212     // Clear the kernal cache.
00213     KernelCache::iterator itor = kernel_cache_.begin();
00214 
00215     while(itor != kernel_cache_.end())
00216     {
00217         delete [] itor->b_;
00218         delete [] itor->a_;
00219         ++itor;
00220     }
00221 
00222     kernel_cache_.clear();
00223 
00224     // Copy kernal cache.
00225     itor = rhs.kernel_cache_.begin();
00226     while(itor != rhs.kernel_cache_.end())
00227     {
00228         Kernel new_kernel(static_cast<uint32>(itor->frequency_));
00229 
00230         // Allocate new kernel memory.
00231         new_kernel.b_ = new float64 [n_poles_ + 1];
00232         new_kernel.a_ = new float64 [n_poles_ + 1];
00233 
00234         // Copy values.
00235         memcpy(new_kernel.b_, itor->b_, sizeof(float64) * (n_poles_ + 1));
00236         memcpy(new_kernel.a_, itor->a_, sizeof(float64) * (n_poles_ + 1));
00237 
00238         // Insert into cache.
00239         kernel_cache_.insert(new_kernel);
00240     }
00241 
00242     // Setup history memory.
00243     if(n_poles_orig != rhs.n_poles_)
00244     {
00245         delete [] x_history_;
00246         delete [] y_history_;
00247 
00248         x_history_ = new float64 [n_poles_ + 1];
00249         x_ptr_     = x_history_;
00250         x_end_ptr_ = x_history_ + n_poles_ + 1;
00251 
00252         y_history_ = new float64 [n_poles_ + 1];
00253         y_ptr_     = y_history_;
00254         y_end_ptr_ = y_history_ + n_poles_ + 1;
00255     }
00256 
00257     reset();
00258 
00259     return *this;
00260 }
00261 
00263 void
00264 FilterStageIIR::
00265 reset()
00266 {
00267     memset(x_history_, 0, sizeof(float64) * (n_poles_ + 1));
00268     memset(y_history_, 0, sizeof(float64) * (n_poles_ + 1));
00269 
00270     x_ptr_ = x_history_;
00271     y_ptr_ = y_history_;
00272 
00273     makeKernel(frequency_);
00274 }
00275 
00277 float64
00278 FilterStageIIR::
00279 filter(const float64 & x)
00280 {
00281     // Write x to history
00282     *x_ptr_ = x;
00283 
00284     // Increment history pointer
00285     ++x_ptr_;
00286 
00287     // Bounds check
00288     if(x_ptr_ >= x_end_ptr_)
00289     {
00290         x_ptr_ = x_history_;
00291     }
00292 
00293     float64 y = 0.0;
00294     float64 * x_hist = x_ptr_;
00295     for(float64 * b = b_; b != b_ + n_poles_ + 1; ++b)
00296     {
00297         // When we enter this loop, x_hist is pointing at x[n + 1]
00298         --x_hist;
00299 
00300         // Bounds check
00301         if(x_hist < x_history_)
00302         {
00303             x_hist = x_end_ptr_ - 1;
00304         }
00305 
00306         y += *b * *x_hist;
00307     }
00308 
00309     float64 * y_hist = y_ptr_;
00310     for(float64 * a = a_ + 1; a != a_ + n_poles_ + 1; ++a)
00311     {
00312         // When we enter this loop, y_hist is pointing at y[n + 1]
00313         --y_hist;
00314 
00315         // Bounds check
00316         if(y_hist < y_history_)
00317         {
00318             y_hist = y_end_ptr_ - 1;
00319         }
00320 
00321         y += *a * *y_hist;
00322 
00323     }
00324 
00325     // insert output into history buffer
00326     *y_ptr_ = y;
00327 
00328     // Increment history pointer
00329     ++y_ptr_;
00330 
00331     // Bounds check
00332     if(y_ptr_ >= y_end_ptr_)
00333     {
00334         y_ptr_ = y_history_;
00335     }
00336 
00337     return y;
00338 }
00339 
00341 float64
00342 FilterStageIIR::
00343 filter(const float64 & x, const float64 & frequency)
00344 {
00345     makeKernel(frequency);
00346     return FilterStageIIR::filter(x);
00347 }
00348 
00350 void
00351 FilterStageIIR::
00352 makeKernel(const float64 & frequency)
00353 {
00354     FilterStageIIR::
00355     Kernel new_kernel(static_cast<uint32>(frequency));
00356 
00357     // See if the kernel is in the cache.
00358 
00359     FilterStageIIR::
00360     KernelCache::const_iterator itor = kernel_cache_.find(new_kernel);
00361 
00362     if(itor != kernel_cache_.end())
00363     {
00364         b_ = itor->b_;
00365         a_ = itor->a_;
00366 
00367         return;
00368     }
00369 
00370     // Allocate new kernel.
00371     new_kernel.b_ = new float64 [n_poles_ + 1];
00372     new_kernel.a_ = new float64 [n_poles_ + 1];
00373 
00374     b_ = new_kernel.b_;
00375     a_ = new_kernel.a_;
00376 
00377     // No kernel in cache, must make it.
00378 
00379     if(type_ == LOW_PASS && frequency < 1.0)
00380     {
00381         // create no pass filter
00382         memset(new_kernel.b_, 0, sizeof(float64) * (n_poles_ + 1));
00383         memset(new_kernel.a_, 0, sizeof(float64) * (n_poles_ + 1));
00384     }
00385 
00386     else if(type_ == LOW_PASS && frequency >= (sample_rate_ / 2.0))
00387     {
00388         // create all pass
00389         memset(new_kernel.b_, 0, sizeof(float64) * (n_poles_ + 1));
00390         memset(new_kernel.a_, 0, sizeof(float64) * (n_poles_ + 1));
00391 
00392         b_[0] = 1.0;
00393     }
00394 
00395     else if(type_ == HIGH_PASS && frequency < 1.0)
00396     {
00397         // create all pass
00398         memset(new_kernel.b_, 0, sizeof(float64) * (n_poles_ + 1));
00399         memset(new_kernel.a_, 0, sizeof(float64) * (n_poles_ + 1));
00400 
00401         b_[0] = 1.0;
00402     }
00403 
00404     else if(type_ == HIGH_PASS && frequency >= (sample_rate_ / 2.0))
00405     {
00406         // create no pass filter
00407         memset(new_kernel.b_, 0, sizeof(float64) * (n_poles_ + 1));
00408         memset(new_kernel.a_, 0, sizeof(float64) * (n_poles_ + 1));
00409     }
00410 
00411     else
00412     {
00413 
00414         float64 B[23];
00415         float64 A[23];
00416 
00417         float64 TB[23];
00418         float64 TA[23];
00419 
00420         memset(B,0,sizeof(float64) * 23);
00421         memset(A,0,sizeof(float64) * 23);
00422         memset(TB,0,sizeof(float64) * 23);
00423         memset(TA,0,sizeof(float64) * 23);
00424 
00425         B[2] = A[2] = 1.0;
00426 
00427         for(uint32 p = 1; p <= n_poles_ / 2; ++p)
00428         {
00429             float64 b[3];
00430             float64 a[3];
00431 
00432             makeIIRKernelHelper(frequency, b, a, p);
00433 
00434             memcpy(TB,B, sizeof(float64) * 23);
00435             memcpy(TA,A, sizeof(float64) * 23);
00436 
00437             for(uint32 i = 2; i <= 22; ++i)
00438             {
00439                 B[i] = b[0] * TB[i] + b[1] * TB[i - 1] + b[2] * TB[i - 2];
00440                 A[i] =        TA[i] - a[1] * TA[i - 1] - a[2] * TA[i - 2];
00441             }
00442         }
00443 
00444         A[2] = 0.0;
00445         for(uint32 i = 0; i <= 20; ++i)
00446         {
00447             B[i] =        B[i + 2];
00448             A[i] = -1.0 * A[i + 2];
00449         }
00450 
00451         float64 sumB = 0.0;
00452         float64 sumA = 0.0;
00453 
00454         for(int32 i = 0; i <= 22; ++i)
00455         {
00456             if(type_ == LOW_PASS)
00457             {
00458                 sumB += B[i];
00459                 sumA += A[i];
00460             }
00461             else if(type_ == HIGH_PASS)
00462             {
00463                 sumB += B[i] * pow(-1.0,i);
00464                 sumA += A[i] * pow(-1.0,i);
00465             }
00466         }
00467         float64 gain = sumB / (1.0 - sumA);
00468 
00469         for(uint32 i = 0; i <= 22; ++i)
00470         {
00471             B[i] /= gain;
00472         }
00473 
00474         memcpy(b_, B, sizeof(float64) * (n_poles_ + 1));
00475         memcpy(a_, A, sizeof(float64) * (n_poles_ + 1));
00476     }
00477 
00478     // Add the new kernel to the cache.
00479     kernel_cache_.insert(new_kernel);
00480 }
00481 
00483 void
00484 FilterStageIIR::
00485 makeIIRKernelHelper(
00486     const float64 & frequency,
00487     float64 * b,
00488     float64 * a,
00489     uint32 p)
00490 {
00491     float64 n_poles = static_cast<float64>(n_poles_);
00492 
00493     float64 RP = -1.0 * cos(M_PI / (n_poles * 2.0) + (p - 1) * (M_PI / n_poles));
00494     float64 IP = sin(M_PI / (n_poles * 2.0) + (p - 1) * (M_PI / n_poles));
00495 
00496     float64 ES = 0.0;
00497     float64 VX = 0.0;
00498     float64 KX = 0.0;
00499 
00500     if(percent_ripple_ != 0.0)
00501     {
00502         float64 temp = (1.0 / (1.0 - percent_ripple_));
00503 
00504         ES = sqrt(temp * temp - 1.0);
00505 
00506         VX = (1.0 / n_poles) * log((1.0 / ES) + sqrt((1.0 /(ES * ES)) + 1.0));
00507         KX = (1.0 / n_poles) * log((1.0 / ES) + sqrt((1.0 /(ES * ES)) - 1.0));
00508         KX = (exp(KX) + exp(-KX)) / 2.0;
00509         RP = RP * ( (exp(VX) - exp(-1.0 * VX) ) / 2.0) / KX;
00510         IP = IP * ( (exp(VX) + exp(-1.0 * VX) ) / 2.0) / KX;
00511     }
00512 
00513     /* DEBUG
00514     if(p == 1)
00515     {
00516         std::cout << endl
00517                   << "RP = " << RP << endl
00518                   << "IP = " << IP << endl
00519                   << "ES = " << ES << endl
00520                   << "VX = " << VX << endl
00521                   << "KX = " << KX << endl << endl;
00522     }
00523     */
00524 
00525 
00526     float64 T = 2.0 * tan(0.5);
00527     float64 W = 2.0 * M_PI * (frequency / static_cast<float64>(sample_rate_));
00528     float64 M = RP * RP + IP * IP;
00529     float64 D = 4.0 - (4.0 * RP * T) + (M * T * T);
00530     float64 X0 = T * T / D;
00531     float64 X1 = 2.0 * X0;
00532     float64 X2 = X0;
00533     float64 Y1 = (8.0 - 2.0 * M * T * T) / D;
00534     float64 Y2 = (-4.0 - (4.0 * RP * T) - M * T * T) / D;
00535 
00536     /* DEBUG
00537     if(p == 1)
00538     {
00539         std::cout << "T  = " << T << endl
00540                   << "W  = " << W << endl
00541                   << "M  = " << M << endl
00542                   << "D  = " << D << endl
00543                   << "X0 = " << X0 << endl
00544                   << "X1 = " << X1 << endl
00545                   << "X2 = " << X2 << endl
00546                   << "Y1 = " << Y1 << endl
00547                   << "Y2 = " << Y2 << endl << endl;
00548     }
00549     */
00550 
00551 
00552     // Low Pass
00553     float64 K = 0.0;
00554 
00555     if(type_ == LOW_PASS)
00556     {
00557         K = sin(0.5 - W / 2.0) / sin(0.5 + W / 2.0);
00558     }
00559 
00560     // High Pass
00561     else if(type_ == HIGH_PASS)
00562     {
00563         K = -1.0 * cos(W / 2.0 + 0.5) / cos(W / 2.0 - 0.5);
00564     }
00565 
00566     D = 1.0 + Y1 * K - Y2 * K * K;
00567     b[0] = (X0 - X1 * K + X2 * K * K) / D;
00568     b[1] = (-2.0 * X0 *K + X1 + X1 * K * K - 2.0 * X2 * K) / D;
00569     b[2] = (X0 * K * K - X1 * K + X2) / D;
00570     a[1] = (2.0 * K + Y1 + Y1 * K * K - 2.0 * Y2 * K) / D;
00571     a[2] = (-1.0 * K * K - Y1 * K + Y2) / D;
00572 
00573     /* DEBUG
00574     if(p == 1)
00575     {
00576         std::cout << "W  = " << W    << endl
00577                   << "K  = " << K    << endl
00578                   << "D  = " << D    << endl
00579                   << "A0 = " << a[0] << endl
00580                   << "A1 = " << a[1] << endl
00581                   << "A2 = " << a[2] << endl
00582                   << "B1 = " << b[1] << endl
00583                   << "B2 = " << b[2] << endl << endl;
00584     }
00585     */
00586 
00587     if(type_ == HIGH_PASS)
00588     {
00589         b[1] = -b[1];
00590         a[1] = -a[1];
00591     }
00592 
00593     /* DEBUG
00594     if(p == 1)
00595     {
00596         std::cout << "A0 = " << a[0] << endl
00597                   << "A1 = " << a[1] << endl
00598                   << "A2 = " << a[2] << endl
00599                   << "B1 = " << b[1] << endl
00600                   << "B2 = " << b[2] << endl << endl;
00601     }
00602     */
00603 }
00604 
00606 FilterStageIIR::
00607 Kernel::
00608 Kernel(const uint32 & frequency)
00609     :
00610     b_(NULL),
00611     a_(NULL),
00612     frequency_(frequency)
00613 {
00614 }
00615 
00617 bool
00618 FilterStageIIR::
00619 Kernel::
00620 operator<(const Kernel & rhs) const
00621 {
00622     return frequency_ <  rhs.frequency_;
00623 }
00624 
Generated on Sun Apr 15 20:10:05 2012 for nsound by  doxygen 1.6.3