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