1 /* 2 * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any 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 SoftFilter(float samplerate)88 public SoftFilter(float samplerate) { 89 this.samplerate = samplerate; 90 dirty = true; 91 } 92 setFrequency(double cent)93 public void setFrequency(double cent) { 94 if (cutoff == cent) 95 return; 96 cutoff = cent; 97 dirty = true; 98 } 99 setResonance(double db)100 public void setResonance(double db) { 101 if (resonancedB == db) 102 return; 103 resonancedB = db; 104 dirty = true; 105 } 106 reset()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 setFilterType(int filtertype)127 public void setFilterType(int filtertype) { 128 this.filtertype = filtertype; 129 } 130 processAudio(SoftAudioBuffer sbuffer)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 filter4(SoftAudioBuffer sbuffer)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 sinh(double x)285 private double sinh(double x) { 286 return (Math.exp(x) - Math.exp(-x)) * 0.5; 287 } 288 filter2calc()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 filter2(SoftAudioBuffer sbuffer)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 filter1calc()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 filter1(SoftAudioBuffer sbuffer)544 public void filter1(SoftAudioBuffer sbuffer) { 545 546 float[] buffer = sbuffer.array(); 547 548 if (dirty) { 549 filter1calc(); 550 dirty = false; 551 } 552 if (!last_set) { 553 last_a0 = a0; 554 last_q = q; 555 last_gain = gain; 556 last_wet = wet; 557 last_set = true; 558 } 559 560 if (wet > 0 || last_wet > 0) { 561 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 y1 = (1 - q * a0) * y1 - (a0) * y2 + (a0) * buffer[i]; 581 y2 = (1 - q * a0) * y2 + (a0) * y1; 582 buffer[i] = y2 * gain * wet + buffer[i] * (1 - wet); 583 } 584 } else if (a0_delta == 0 && q_delta == 0) { 585 for (int i = 0; i < len; i++) { 586 y1 = (1 - q * a0) * y1 - (a0) * y2 + (a0) * buffer[i]; 587 y2 = (1 - q * a0) * y2 + (a0) * y1; 588 buffer[i] = y2 * gain; 589 } 590 } else { 591 for (int i = 0; i < len; i++) { 592 a0 += a0_delta; 593 q += q_delta; 594 gain += gain_delta; 595 y1 = (1 - q * a0) * y1 - (a0) * y2 + (a0) * buffer[i]; 596 y2 = (1 - q * a0) * y2 + (a0) * y1; 597 buffer[i] = y2 * gain; 598 } 599 } 600 601 if (Math.abs(y2) < 1.0E-8) 602 y2 = 0; 603 if (Math.abs(y1) < 1.0E-8) 604 y1 = 0; 605 this.y2 = y2; 606 this.y1 = y1; 607 } 608 609 this.last_a0 = this.a0; 610 this.last_q = this.q; 611 this.last_gain = this.gain; 612 this.last_wet = this.wet; 613 } 614 } 615