Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   package com.sun.media.sound;
   26   
   27   /**
   28    * Infinite impulse response (IIR) filter class.
   29    *
   30    * The filters where implemented and adapted using algorithms from musicdsp.org
   31    * archive: 1-RC and C filter, Simple 2-pole LP LP and HP filter, biquad,
   32    * tweaked butterworth RBJ Audio-EQ-Cookbook, EQ filter kookbook
   33    *
   34    * @author Karl Helgason
   35    */
   36   public class SoftFilter {
   37   
   38       public final static int FILTERTYPE_LP6 = 0x00;
   39       public final static int FILTERTYPE_LP12 = 0x01;
   40       public final static int FILTERTYPE_HP12 = 0x11;
   41       public final static int FILTERTYPE_BP12 = 0x21;
   42       public final static int FILTERTYPE_NP12 = 0x31;
   43       public final static int FILTERTYPE_LP24 = 0x03;
   44       public final static int FILTERTYPE_HP24 = 0x13;
   45   
   46       //
   47       // 0x0 = 1st-order, 6 dB/oct
   48       // 0x1 = 2nd-order, 12 dB/oct
   49       // 0x2 = 3rd-order, 18 dB/oct
   50       // 0x3 = 4th-order, 24 db/oct
   51       //
   52       // 0x00 = LP, Low Pass Filter
   53       // 0x10 = HP, High Pass Filter
   54       // 0x20 = BP, Band Pass Filter
   55       // 0x30 = NP, Notch or Band Elimination Filter
   56       //
   57       private int filtertype = FILTERTYPE_LP6;
   58       private float samplerate;
   59       private float x1;
   60       private float x2;
   61       private float y1;
   62       private float y2;
   63       private float xx1;
   64       private float xx2;
   65       private float yy1;
   66       private float yy2;
   67       private float a0;
   68       private float a1;
   69       private float a2;
   70       private float b1;
   71       private float b2;
   72       private float q;
   73       private float gain = 1;
   74       private float wet = 0;
   75       private float last_wet = 0;
   76       private float last_a0;
   77       private float last_a1;
   78       private float last_a2;
   79       private float last_b1;
   80       private float last_b2;
   81       private float last_q;
   82       private float last_gain;
   83       private boolean last_set = false;
   84       private double cutoff = 44100;
   85       private double resonancedB = 0;
   86       private boolean dirty = true;
   87   
   88       public SoftFilter(float samplerate) {
   89           this.samplerate = samplerate;
   90           dirty = true;
   91       }
   92   
   93       public void setFrequency(double cent) {
   94           if (cutoff == cent)
   95               return;
   96           cutoff = cent;
   97           dirty = true;
   98       }
   99   
  100       public void setResonance(double db) {
  101           if (resonancedB == db)
  102               return;
  103           resonancedB = db;
  104           dirty = true;
  105       }
  106   
  107       public void reset() {
  108           dirty = true;
  109           last_set = false;
  110           x1 = 0;
  111           x2 = 0;
  112           y1 = 0;
  113           y2 = 0;
  114           xx1 = 0;
  115           xx2 = 0;
  116           yy1 = 0;
  117           yy2 = 0;
  118           wet = 0.0f;
  119           gain = 1.0f;
  120           a0 = 0;
  121           a1 = 0;
  122           a2 = 0;
  123           b1 = 0;
  124           b2 = 0;
  125       }
  126   
  127       public void setFilterType(int filtertype) {
  128           this.filtertype = filtertype;
  129       }
  130   
  131       public void processAudio(SoftAudioBuffer sbuffer) {
  132           if (filtertype == FILTERTYPE_LP6)
  133               filter1(sbuffer);
  134           if (filtertype == FILTERTYPE_LP12)
  135               filter2(sbuffer);
  136           if (filtertype == FILTERTYPE_HP12)
  137               filter2(sbuffer);
  138           if (filtertype == FILTERTYPE_BP12)
  139               filter2(sbuffer);
  140           if (filtertype == FILTERTYPE_NP12)
  141               filter2(sbuffer);
  142           if (filtertype == FILTERTYPE_LP24)
  143               filter4(sbuffer);
  144           if (filtertype == FILTERTYPE_HP24)
  145               filter4(sbuffer);
  146       }
  147   
  148       public void filter4(SoftAudioBuffer sbuffer) {
  149   
  150           float[] buffer = sbuffer.array();
  151   
  152           if (dirty) {
  153               filter2calc();
  154               dirty = false;
  155           }
  156           if (!last_set) {
  157               last_a0 = a0;
  158               last_a1 = a1;
  159               last_a2 = a2;
  160               last_b1 = b1;
  161               last_b2 = b2;
  162               last_gain = gain;
  163               last_wet = wet;
  164               last_set = true;
  165           }
  166   
  167           if (wet > 0 || last_wet > 0) {
  168   
  169               int len = buffer.length;
  170               float a0 = this.last_a0;
  171               float a1 = this.last_a1;
  172               float a2 = this.last_a2;
  173               float b1 = this.last_b1;
  174               float b2 = this.last_b2;
  175               float gain = this.last_gain;
  176               float wet = this.last_wet;
  177               float a0_delta = (this.a0 - this.last_a0) / len;
  178               float a1_delta = (this.a1 - this.last_a1) / len;
  179               float a2_delta = (this.a2 - this.last_a2) / len;
  180               float b1_delta = (this.b1 - this.last_b1) / len;
  181               float b2_delta = (this.b2 - this.last_b2) / len;
  182               float gain_delta = (this.gain - this.last_gain) / len;
  183               float wet_delta = (this.wet - this.last_wet) / len;
  184               float x1 = this.x1;
  185               float x2 = this.x2;
  186               float y1 = this.y1;
  187               float y2 = this.y2;
  188               float xx1 = this.xx1;
  189               float xx2 = this.xx2;
  190               float yy1 = this.yy1;
  191               float yy2 = this.yy2;
  192   
  193               if (wet_delta != 0) {
  194                   for (int i = 0; i < len; i++) {
  195                       a0 += a0_delta;
  196                       a1 += a1_delta;
  197                       a2 += a2_delta;
  198                       b1 += b1_delta;
  199                       b2 += b2_delta;
  200                       gain += gain_delta;
  201                       wet += wet_delta;
  202                       float x = buffer[i];
  203                       float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
  204                       float xx = (y * gain) * wet + (x) * (1 - wet);
  205                       x2 = x1;
  206                       x1 = x;
  207                       y2 = y1;
  208                       y1 = y;
  209                       float yy = (a0*xx + a1*xx1 + a2*xx2 - b1*yy1 - b2*yy2);
  210                       buffer[i] = (yy * gain) * wet + (xx) * (1 - wet);
  211                       xx2 = xx1;
  212                       xx1 = xx;
  213                       yy2 = yy1;
  214                       yy1 = yy;
  215                   }
  216               } else if (a0_delta == 0 && a1_delta == 0 && a2_delta == 0
  217                       && b1_delta == 0 && b2_delta == 0) {
  218                   for (int i = 0; i < len; i++) {
  219                       float x = buffer[i];
  220                       float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
  221                       float xx = (y * gain) * wet + (x) * (1 - wet);
  222                       x2 = x1;
  223                       x1 = x;
  224                       y2 = y1;
  225                       y1 = y;
  226                       float yy = (a0*xx + a1*xx1 + a2*xx2 - b1*yy1 - b2*yy2);
  227                       buffer[i] = (yy * gain) * wet + (xx) * (1 - wet);
  228                       xx2 = xx1;
  229                       xx1 = xx;
  230                       yy2 = yy1;
  231                       yy1 = yy;
  232                   }
  233               } else {
  234                   for (int i = 0; i < len; i++) {
  235                       a0 += a0_delta;
  236                       a1 += a1_delta;
  237                       a2 += a2_delta;
  238                       b1 += b1_delta;
  239                       b2 += b2_delta;
  240                       gain += gain_delta;
  241                       float x = buffer[i];
  242                       float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
  243                       float xx = (y * gain) * wet + (x) * (1 - wet);
  244                       x2 = x1;
  245                       x1 = x;
  246                       y2 = y1;
  247                       y1 = y;
  248                       float yy = (a0*xx + a1*xx1 + a2*xx2 - b1*yy1 - b2*yy2);
  249                       buffer[i] = (yy * gain) * wet + (xx) * (1 - wet);
  250                       xx2 = xx1;
  251                       xx1 = xx;
  252                       yy2 = yy1;
  253                       yy1 = yy;
  254                   }
  255               }
  256   
  257               if (Math.abs(x1) < 1.0E-8)
  258                   x1 = 0;
  259               if (Math.abs(x2) < 1.0E-8)
  260                   x2 = 0;
  261               if (Math.abs(y1) < 1.0E-8)
  262                   y1 = 0;
  263               if (Math.abs(y2) < 1.0E-8)
  264                   y2 = 0;
  265               this.x1 = x1;
  266               this.x2 = x2;
  267               this.y1 = y1;
  268               this.y2 = y2;
  269               this.xx1 = xx1;
  270               this.xx2 = xx2;
  271               this.yy1 = yy1;
  272               this.yy2 = yy2;
  273           }
  274   
  275           this.last_a0 = this.a0;
  276           this.last_a1 = this.a1;
  277           this.last_a2 = this.a2;
  278           this.last_b1 = this.b1;
  279           this.last_b2 = this.b2;
  280           this.last_gain = this.gain;
  281           this.last_wet = this.wet;
  282   
  283       }
  284   
  285       private double sinh(double x) {
  286           return (Math.exp(x) - Math.exp(-x)) * 0.5;
  287       }
  288   
  289       public void filter2calc() {
  290   
  291           double resonancedB = this.resonancedB;
  292           if (resonancedB < 0)
  293               resonancedB = 0;    // Negative dB are illegal.
  294           if (resonancedB > 30)
  295               resonancedB = 30;   // At least 22.5 dB is needed.
  296           if (filtertype == FILTERTYPE_LP24 || filtertype == FILTERTYPE_HP24)
  297               resonancedB *= 0.6;
  298   
  299           if (filtertype == FILTERTYPE_BP12) {
  300               wet = 1;
  301               double r = (cutoff / samplerate);
  302               if (r > 0.45)
  303                   r = 0.45;
  304   
  305               double bandwidth = Math.PI * Math.pow(10.0, -(resonancedB / 20));
  306   
  307               double omega = 2 * Math.PI * r;
  308               double cs = Math.cos(omega);
  309               double sn = Math.sin(omega);
  310               double alpha = sn * sinh((Math.log(2)*bandwidth*omega) / (sn * 2));
  311   
  312               double b0 = alpha;
  313               double b1 = 0;
  314               double b2 = -alpha;
  315               double a0 = 1 + alpha;
  316               double a1 = -2 * cs;
  317               double a2 = 1 - alpha;
  318   
  319               double cf = 1.0 / a0;
  320               this.b1 = (float) (a1 * cf);
  321               this.b2 = (float) (a2 * cf);
  322               this.a0 = (float) (b0 * cf);
  323               this.a1 = (float) (b1 * cf);
  324               this.a2 = (float) (b2 * cf);
  325           }
  326   
  327           if (filtertype == FILTERTYPE_NP12) {
  328               wet = 1;
  329               double r = (cutoff / samplerate);
  330               if (r > 0.45)
  331                   r = 0.45;
  332   
  333               double bandwidth = Math.PI * Math.pow(10.0, -(resonancedB / 20));
  334   
  335               double omega = 2 * Math.PI * r;
  336               double cs = Math.cos(omega);
  337               double sn = Math.sin(omega);
  338               double alpha = sn * sinh((Math.log(2)*bandwidth*omega) / (sn*2));
  339   
  340               double b0 = 1;
  341               double b1 = -2 * cs;
  342               double b2 = 1;
  343               double a0 = 1 + alpha;
  344               double a1 = -2 * cs;
  345               double a2 = 1 - alpha;
  346   
  347               double cf = 1.0 / a0;
  348               this.b1 = (float)(a1 * cf);
  349               this.b2 = (float)(a2 * cf);
  350               this.a0 = (float)(b0 * cf);
  351               this.a1 = (float)(b1 * cf);
  352               this.a2 = (float)(b2 * cf);
  353           }
  354   
  355           if (filtertype == FILTERTYPE_LP12 || filtertype == FILTERTYPE_LP24) {
  356               double r = (cutoff / samplerate);
  357               if (r > 0.45) {
  358                   if (wet == 0) {
  359                       if (resonancedB < 0.00001)
  360                           wet = 0.0f;
  361                       else
  362                           wet = 1.0f;
  363                   }
  364                   r = 0.45;
  365               } else
  366                   wet = 1.0f;
  367   
  368               double c = 1.0 / (Math.tan(Math.PI * r));
  369               double csq = c * c;
  370               double resonance = Math.pow(10.0, -(resonancedB / 20));
  371               double q = Math.sqrt(2.0f) * resonance;
  372               double a0 = 1.0 / (1.0 + (q * c) + (csq));
  373               double a1 = 2.0 * a0;
  374               double a2 = a0;
  375               double b1 = (2.0 * a0) * (1.0 - csq);
  376               double b2 = a0 * (1.0 - (q * c) + csq);
  377   
  378               this.a0 = (float)a0;
  379               this.a1 = (float)a1;
  380               this.a2 = (float)a2;
  381               this.b1 = (float)b1;
  382               this.b2 = (float)b2;
  383   
  384           }
  385   
  386           if (filtertype == FILTERTYPE_HP12 || filtertype == FILTERTYPE_HP24) {
  387               double r = (cutoff / samplerate);
  388               if (r > 0.45)
  389                   r = 0.45;
  390               if (r < 0.0001)
  391                   r = 0.0001;
  392               wet = 1.0f;
  393               double c = (Math.tan(Math.PI * (r)));
  394               double csq = c * c;
  395               double resonance = Math.pow(10.0, -(resonancedB / 20));
  396               double q = Math.sqrt(2.0f) * resonance;
  397               double a0 = 1.0 / (1.0 + (q * c) + (csq));
  398               double a1 = -2.0 * a0;
  399               double a2 = a0;
  400               double b1 = (2.0 * a0) * (csq - 1.0);
  401               double b2 = a0 * (1.0 - (q * c) + csq);
  402   
  403               this.a0 = (float)a0;
  404               this.a1 = (float)a1;
  405               this.a2 = (float)a2;
  406               this.b1 = (float)b1;
  407               this.b2 = (float)b2;
  408   
  409           }
  410   
  411       }
  412   
  413       public void filter2(SoftAudioBuffer sbuffer) {
  414   
  415           float[] buffer = sbuffer.array();
  416   
  417           if (dirty) {
  418               filter2calc();
  419               dirty = false;
  420           }
  421           if (!last_set) {
  422               last_a0 = a0;
  423               last_a1 = a1;
  424               last_a2 = a2;
  425               last_b1 = b1;
  426               last_b2 = b2;
  427               last_q = q;
  428               last_gain = gain;
  429               last_wet = wet;
  430               last_set = true;
  431           }
  432   
  433           if (wet > 0 || last_wet > 0) {
  434   
  435               int len = buffer.length;
  436               float a0 = this.last_a0;
  437               float a1 = this.last_a1;
  438               float a2 = this.last_a2;
  439               float b1 = this.last_b1;
  440               float b2 = this.last_b2;
  441               float gain = this.last_gain;
  442               float wet = this.last_wet;
  443               float a0_delta = (this.a0 - this.last_a0) / len;
  444               float a1_delta = (this.a1 - this.last_a1) / len;
  445               float a2_delta = (this.a2 - this.last_a2) / len;
  446               float b1_delta = (this.b1 - this.last_b1) / len;
  447               float b2_delta = (this.b2 - this.last_b2) / len;
  448               float gain_delta = (this.gain - this.last_gain) / len;
  449               float wet_delta = (this.wet - this.last_wet) / len;
  450               float x1 = this.x1;
  451               float x2 = this.x2;
  452               float y1 = this.y1;
  453               float y2 = this.y2;
  454   
  455               if (wet_delta != 0) {
  456                   for (int i = 0; i < len; i++) {
  457                       a0 += a0_delta;
  458                       a1 += a1_delta;
  459                       a2 += a2_delta;
  460                       b1 += b1_delta;
  461                       b2 += b2_delta;
  462                       gain += gain_delta;
  463                       wet += wet_delta;
  464                       float x = buffer[i];
  465                       float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
  466                       buffer[i] = (y * gain) * wet + (x) * (1 - wet);
  467                       x2 = x1;
  468                       x1 = x;
  469                       y2 = y1;
  470                       y1 = y;
  471                   }
  472               } else if (a0_delta == 0 && a1_delta == 0 && a2_delta == 0
  473                       && b1_delta == 0 && b2_delta == 0) {
  474                   for (int i = 0; i < len; i++) {
  475                       float x = buffer[i];
  476                       float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
  477                       buffer[i] = y * gain;
  478                       x2 = x1;
  479                       x1 = x;
  480                       y2 = y1;
  481                       y1 = y;
  482                   }
  483               } else {
  484                   for (int i = 0; i < len; i++) {
  485                       a0 += a0_delta;
  486                       a1 += a1_delta;
  487                       a2 += a2_delta;
  488                       b1 += b1_delta;
  489                       b2 += b2_delta;
  490                       gain += gain_delta;
  491                       float x = buffer[i];
  492                       float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2);
  493                       buffer[i] = y * gain;
  494                       x2 = x1;
  495                       x1 = x;
  496                       y2 = y1;
  497                       y1 = y;
  498                   }
  499               }
  500   
  501               if (Math.abs(x1) < 1.0E-8)
  502                   x1 = 0;
  503               if (Math.abs(x2) < 1.0E-8)
  504                   x2 = 0;
  505               if (Math.abs(y1) < 1.0E-8)
  506                   y1 = 0;
  507               if (Math.abs(y2) < 1.0E-8)
  508                   y2 = 0;
  509               this.x1 = x1;
  510               this.x2 = x2;
  511               this.y1 = y1;
  512               this.y2 = y2;
  513           }
  514   
  515           this.last_a0 = this.a0;
  516           this.last_a1 = this.a1;
  517           this.last_a2 = this.a2;
  518           this.last_b1 = this.b1;
  519           this.last_b2 = this.b2;
  520           this.last_q = this.q;
  521           this.last_gain = this.gain;
  522           this.last_wet = this.wet;
  523   
  524       }
  525   
  526       public void filter1calc() {
  527           if (cutoff < 120)
  528               cutoff = 120;
  529           double c = (7.0 / 6.0) * Math.PI * 2 * cutoff / samplerate;
  530           if (c > 1)
  531               c = 1;
  532           a0 = (float)(Math.sqrt(1 - Math.cos(c)) * Math.sqrt(0.5 * Math.PI));
  533           if (resonancedB < 0)
  534               resonancedB = 0;
  535           if (resonancedB > 20)
  536               resonancedB = 20;
  537           q = (float)(Math.sqrt(0.5) * Math.pow(10.0, -(resonancedB / 20)));
  538           gain = (float)Math.pow(10, -((resonancedB)) / 40.0);
  539           if (wet == 0.0f)
  540               if (resonancedB > 0.00001 || c < 0.9999999)
  541                   wet = 1.0f;
  542       }
  543   
  544       public void filter1(SoftAudioBuffer sbuffer) {
  545   
  546           if (dirty) {
  547               filter1calc();
  548               dirty = false;
  549           }
  550           if (!last_set) {
  551               last_a0 = a0;
  552               last_q = q;
  553               last_gain = gain;
  554               last_wet = wet;
  555               last_set = true;
  556           }
  557   
  558           if (wet > 0 || last_wet > 0) {
  559   
  560               float[] buffer = sbuffer.array();
  561               int len = buffer.length;
  562               float a0 = this.last_a0;
  563               float q = this.last_q;
  564               float gain = this.last_gain;
  565               float wet = this.last_wet;
  566               float a0_delta = (this.a0 - this.last_a0) / len;
  567               float q_delta = (this.q - this.last_q) / len;
  568               float gain_delta = (this.gain - this.last_gain) / len;
  569               float wet_delta = (this.wet - this.last_wet) / len;
  570               float y2 = this.y2;
  571               float y1 = this.y1;
  572   
  573               if (wet_delta != 0) {
  574                   for (int i = 0; i < len; i++) {
  575                       a0 += a0_delta;
  576                       q += q_delta;
  577                       gain += gain_delta;
  578                       wet += wet_delta;
  579                       float ga0 = (1 - q * a0);
  580                       y1 = ga0 * y1 + (a0) * (buffer[i] - y2);
  581                       y2 = ga0 * y2 + (a0) * y1;
  582                       buffer[i] = y2 * gain * wet + buffer[i] * (1 - wet);
  583                   }
  584               } else if (a0_delta == 0 && q_delta == 0) {
  585                   float ga0 = (1 - q * a0);
  586                   for (int i = 0; i < len; i++) {
  587                       y1 = ga0 * y1 + (a0) * (buffer[i] - y2);
  588                       y2 = ga0 * y2 + (a0) * y1;
  589                       buffer[i] = y2 * gain;
  590                   }
  591               } else {
  592                   for (int i = 0; i < len; i++) {
  593                       a0 += a0_delta;
  594                       q += q_delta;
  595                       gain += gain_delta;
  596                       float ga0 = (1 - q * a0);
  597                       y1 = ga0 * y1 + (a0) * (buffer[i] - y2);
  598                       y2 = ga0 * y2 + (a0) * y1;
  599                       buffer[i] = y2 * gain;
  600                   }
  601               }
  602   
  603               if (Math.abs(y2) < 1.0E-8)
  604                   y2 = 0;
  605               if (Math.abs(y1) < 1.0E-8)
  606                   y1 = 0;
  607               this.y2 = y2;
  608               this.y1 = y1;
  609           }
  610   
  611           this.last_a0 = this.a0;
  612           this.last_q = this.q;
  613           this.last_gain = this.gain;
  614           this.last_wet = this.wet;
  615       }
  616   }

Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]