Changeset 106621 in webkit
- Timestamp:
- Feb 2, 2012 8:08:50 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 17 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r106619 r106621 1 2012-02-02 Raymond Toy <rtoy@chromium.org> 2 3 Check parameters to biquad filters 4 https://bugs.webkit.org/show_bug.cgi?id=71413 5 6 Reviewed by Kenneth Russell. 7 8 * webaudio/biquad-allpass-expected.txt: Added 9 * webaudio/biquad-allpass.html: Added 10 * webaudio/biquad-bandpass-expected.txt: Added 11 * webaudio/biquad-bandpass.html: Added 12 * webaudio/biquad-highpass-expected.txt: Added 13 * webaudio/biquad-highpass.html: Added 14 * webaudio/biquad-highshelf-expected.txt: Added 15 * webaudio/biquad-highshelf.html: Added 16 * webaudio/biquad-lowpass-expected.txt: Added 17 * webaudio/biquad-lowpass.html: Added 18 * webaudio/biquad-lowshelf-expected.txt: Added 19 * webaudio/biquad-lowshelf.html: Added 20 * webaudio/biquad-notch-expected.txt: Added 21 * webaudio/biquad-notch.html: Added 22 * webaudio/biquad-peaking-expected.txt: Added 23 * webaudio/biquad-peaking.html: Added 24 * webaudio/resources/biquad-testing.js: Added 25 1 26 2012-02-02 Shinya Kawanaka <shinyak@google.com> 2 27 -
trunk/Source/WebCore/ChangeLog
r106620 r106621 1 2012-02-02 Raymond Toy <rtoy@google.com> 2 3 Check parameters to biquad filters 4 https://bugs.webkit.org/show_bug.cgi?id=71413 5 6 Reviewed by Kenneth Russell. 7 8 Tests added for each filter type and for the limiting cases for 9 each filter type. 10 11 * platform/audio/Biquad.cpp: 12 (WebCore::Biquad::setLowpassParams): 13 (WebCore::Biquad::setHighpassParams): 14 (WebCore::Biquad::setLowShelfParams): 15 (WebCore::Biquad::setHighShelfParams): 16 (WebCore::Biquad::setPeakingParams): 17 (WebCore::Biquad::setAllpassParams): 18 (WebCore::Biquad::setNotchParams): 19 (WebCore::Biquad::setBandpassParams): 20 Check for invalid parameters and clip them to something sensible. 21 Also check for the limiting cases and try to use the limiting form 22 of the z-transform for the biquad. Some issues cannot be 23 consistently handled because the z-transform is not continuous as 24 the parameters approach the limit. 25 1 26 2012-02-02 No'am Rosenthal <noam.rosenthal@nokia.com> 2 27 -
trunk/Source/WebCore/platform/audio/Biquad.cpp
r99337 r106621 189 189 { 190 190 resonance = std::max(0.0, resonance); // can't go negative 191 191 // Limit cutoff to 0 to 1. 192 cutoff = std::max(0.0, std::min(cutoff, 1.0)); 193 192 194 double g = pow(10.0, 0.05 * resonance); 193 195 double d = sqrt((4 - sqrt(16 - 16 / (g * g))) / 2); 194 196 195 // Compute biquad coefficients for lopass filter 196 double theta = piDouble * cutoff; 197 double sn = 0.5 * d * sin(theta); 198 double beta = 0.5 * (1 - sn) / (1 + sn); 199 double gamma = (0.5 + beta) * cos(theta); 200 double alpha = 0.25 * (0.5 + beta - gamma); 201 202 m_b0 = 2 * alpha; 203 m_b1 = 2 * 2 * alpha; 204 m_b2 = 2 * alpha; 205 m_a1 = 2 * -gamma; 206 m_a2 = 2 * beta; 197 if (cutoff == 1) { 198 // When cutoff is 1, the z-transform is 1. 199 m_b0 = 1; 200 m_b1 = 0; 201 m_b2 = 0; 202 m_a1 = 0; 203 m_a2 = 0; 204 } else if (cutoff > 0) { 205 // Compute biquad coefficients for lowpass filter 206 double theta = piDouble * cutoff; 207 double sn = 0.5 * d * sin(theta); 208 double beta = 0.5 * (1 - sn) / (1 + sn); 209 double gamma = (0.5 + beta) * cos(theta); 210 double alpha = 0.25 * (0.5 + beta - gamma); 211 212 m_b0 = 2 * alpha; 213 m_b1 = 2 * 2 * alpha; 214 m_b2 = 2 * alpha; 215 m_a1 = 2 * -gamma; 216 m_a2 = 2 * beta; 217 } else { 218 // When cutoff is zero, nothing gets through the filter, so set 219 // coefficients up correctly. 220 m_b0 = 0; 221 m_b1 = 0; 222 m_b2 = 0; 223 m_a1 = 0; 224 m_a2 = 0; 225 } 207 226 } 208 227 … … 210 229 { 211 230 resonance = std::max(0.0, resonance); // can't go negative 231 232 // Limit cutoff to 0 to 1. 233 cutoff = std::max(0.0, std::min(cutoff, 1.0)); 212 234 213 235 double g = pow(10.0, 0.05 * resonance); 214 236 double d = sqrt((4 - sqrt(16 - 16 / (g * g))) / 2); 215 237 216 // Compute biquad coefficients for highpass filter 217 double theta = piDouble * cutoff; 218 double sn = 0.5 * d * sin(theta); 219 double beta = 0.5 * (1 - sn) / (1 + sn); 220 double gamma = (0.5 + beta) * cos(theta); 221 double alpha = 0.25 * (0.5 + beta + gamma); 222 223 m_b0 = 2 * alpha; 224 m_b1 = 2 * -2 * alpha; 225 m_b2 = 2 * alpha; 226 m_a1 = 2 * -gamma; 227 m_a2 = 2 * beta; 238 if (cutoff == 1) { 239 // The z-transform is 0. 240 m_b0 = 0; 241 m_b1 = 0; 242 m_b2 = 0; 243 m_a1 = 0; 244 m_a2 = 0; 245 } else if (cutoff > 0) { 246 // Compute biquad coefficients for highpass filter 247 double theta = piDouble * cutoff; 248 double sn = 0.5 * d * sin(theta); 249 double beta = 0.5 * (1 - sn) / (1 + sn); 250 double gamma = (0.5 + beta) * cos(theta); 251 double alpha = 0.25 * (0.5 + beta + gamma); 252 253 m_b0 = 2 * alpha; 254 m_b1 = 2 * -2 * alpha; 255 m_b2 = 2 * alpha; 256 m_a1 = 2 * -gamma; 257 m_a2 = 2 * beta; 258 } else { 259 // When cutoff is zero, we need to be careful because the above 260 // gives a quadratic divided by the same quadratic, with poles 261 // and zeros on the unit circle in the same place. When cutoff 262 // is zero, the z-transform is 1. 263 m_b0 = 1; 264 m_b1 = 0; 265 m_b2 = 0; 266 m_a1 = 0; 267 m_a2 = 0; 268 } 228 269 } 229 270 … … 241 282 void Biquad::setLowShelfParams(double frequency, double dbGain) 242 283 { 243 double w0 = piDouble * frequency; 244 284 // Clip frequencies to between 0 and 1, inclusive. 285 frequency = std::max(0.0, std::min(frequency, 1.0)); 286 245 287 double A = pow(10.0, dbGain / 40); 246 double S = 1; // filter slope (1 is max value) 247 double alpha = 0.5 * sin(w0) * sqrt((A + 1 / A) * (1 / S - 1) + 2); 248 249 double k = cos(w0); 250 double k2 = 2 * sqrt(A) * alpha; 251 252 double aPlusOne = A + 1; 253 double aMinusOne = A - 1; 288 289 if (frequency == 1) { 290 // The z-transform is a constant gain. 291 setNormalizedCoefficients(A * A, 0, 0, 292 1, 0, 0); 293 } else if (frequency > 0) { 294 double w0 = piDouble * frequency; 295 double S = 1; // filter slope (1 is max value) 296 double alpha = 0.5 * sin(w0) * sqrt((A + 1 / A) * (1 / S - 1) + 2); 297 double k = cos(w0); 298 double k2 = 2 * sqrt(A) * alpha; 299 double aPlusOne = A + 1; 300 double aMinusOne = A - 1; 301 302 double b0 = A * (aPlusOne - aMinusOne * k + k2); 303 double b1 = 2 * A * (aMinusOne - aPlusOne * k); 304 double b2 = A * (aPlusOne - aMinusOne * k - k2); 305 double a0 = aPlusOne + aMinusOne * k + k2; 306 double a1 = -2 * (aMinusOne + aPlusOne * k); 307 double a2 = aPlusOne + aMinusOne * k - k2; 308 309 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 310 } else { 311 // When frequency is 0, the z-transform is 1. 312 setNormalizedCoefficients(1, 0, 0, 313 1, 0, 0); 314 } 315 } 316 317 void Biquad::setHighShelfParams(double frequency, double dbGain) 318 { 319 // Clip frequencies to between 0 and 1, inclusive. 320 frequency = std::max(0.0, std::min(frequency, 1.0)); 321 322 double A = pow(10.0, dbGain / 40); 323 324 if (frequency == 1) { 325 // The z-transform is 1. 326 setNormalizedCoefficients(1, 0, 0, 327 1, 0, 0); 328 } else if (frequency > 0) { 329 double w0 = piDouble * frequency; 330 double S = 1; // filter slope (1 is max value) 331 double alpha = 0.5 * sin(w0) * sqrt((A + 1 / A) * (1 / S - 1) + 2); 332 double k = cos(w0); 333 double k2 = 2 * sqrt(A) * alpha; 334 double aPlusOne = A + 1; 335 double aMinusOne = A - 1; 336 337 double b0 = A * (aPlusOne + aMinusOne * k + k2); 338 double b1 = -2 * A * (aMinusOne + aPlusOne * k); 339 double b2 = A * (aPlusOne + aMinusOne * k - k2); 340 double a0 = aPlusOne - aMinusOne * k + k2; 341 double a1 = 2 * (aMinusOne - aPlusOne * k); 342 double a2 = aPlusOne - aMinusOne * k - k2; 343 344 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 345 } else { 346 // When frequency = 0, the filter is just a gain, A^2. 347 setNormalizedCoefficients(A * A, 0, 0, 348 1, 0, 0); 349 } 350 } 351 352 void Biquad::setPeakingParams(double frequency, double Q, double dbGain) 353 { 354 // Clip frequencies to between 0 and 1, inclusive. 355 frequency = std::max(0.0, std::min(frequency, 1.0)); 356 357 // Don't let Q go negative, which causes an unstable filter. 358 Q = std::max(0.0, Q); 359 360 double A = pow(10.0, dbGain / 40); 361 362 if (frequency > 0 && frequency < 1) { 363 if (Q > 0) { 364 double w0 = piDouble * frequency; 365 double alpha = sin(w0) / (2 * Q); 366 double k = cos(w0); 367 368 double b0 = 1 + alpha * A; 369 double b1 = -2 * k; 370 double b2 = 1 - alpha * A; 371 double a0 = 1 + alpha / A; 372 double a1 = -2 * k; 373 double a2 = 1 - alpha / A; 374 375 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 376 } else { 377 // When Q = 0, the above formulas have problems. If we look at 378 // the z-transform, we can see that the limit as Q->0 is A^2, so 379 // set the filter that way. 380 setNormalizedCoefficients(A * A, 0, 0, 381 1, 0, 0); 382 } 383 } else { 384 // When frequency is 0 or 1, the z-transform is 1. 385 setNormalizedCoefficients(1, 0, 0, 386 1, 0, 0); 387 } 388 } 389 390 void Biquad::setAllpassParams(double frequency, double Q) 391 { 392 // Clip frequencies to between 0 and 1, inclusive. 393 frequency = std::max(0.0, std::min(frequency, 1.0)); 394 395 // Don't let Q go negative, which causes an unstable filter. 396 Q = std::max(0.0, Q); 397 398 if (frequency > 0 && frequency < 1) { 399 if (Q > 0) { 400 double w0 = piDouble * frequency; 401 double alpha = sin(w0) / (2 * Q); 402 double k = cos(w0); 403 404 double b0 = 1 - alpha; 405 double b1 = -2 * k; 406 double b2 = 1 + alpha; 407 double a0 = 1 + alpha; 408 double a1 = -2 * k; 409 double a2 = 1 - alpha; 410 411 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 412 } else { 413 // When Q = 0, the above formulas have problems. If we look at 414 // the z-transform, we can see that the limit as Q->0 is -1, so 415 // set the filter that way. 416 setNormalizedCoefficients(-1, 0, 0, 417 1, 0, 0); 418 } 419 } else { 420 // When frequency is 0 or 1, the z-transform is 1. 421 setNormalizedCoefficients(1, 0, 0, 422 1, 0, 0); 423 } 424 } 425 426 void Biquad::setNotchParams(double frequency, double Q) 427 { 428 // Clip frequencies to between 0 and 1, inclusive. 429 frequency = std::max(0.0, std::min(frequency, 1.0)); 430 431 // Don't let Q go negative, which causes an unstable filter. 432 Q = std::max(0.0, Q); 433 434 if (frequency > 0 && frequency < 1) { 435 if (Q > 0) { 436 double w0 = piDouble * frequency; 437 double alpha = sin(w0) / (2 * Q); 438 double k = cos(w0); 439 440 double b0 = 1; 441 double b1 = -2 * k; 442 double b2 = 1; 443 double a0 = 1 + alpha; 444 double a1 = -2 * k; 445 double a2 = 1 - alpha; 446 447 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 448 } else { 449 // When Q = 0, the above formulas have problems. If we look at 450 // the z-transform, we can see that the limit as Q->0 is 0, so 451 // set the filter that way. 452 setNormalizedCoefficients(0, 0, 0, 453 1, 0, 0); 454 } 455 } else { 456 // When frequency is 0 or 1, the z-transform is 1. 457 setNormalizedCoefficients(1, 0, 0, 458 1, 0, 0); 459 } 460 } 461 462 void Biquad::setBandpassParams(double frequency, double Q) 463 { 464 // No negative frequencies allowed. 465 frequency = std::max(0.0, frequency); 466 467 // Don't let Q go negative, which causes an unstable filter. 468 Q = std::max(0.0, Q); 469 470 if (frequency > 0 && frequency < 1) { 471 double w0 = piDouble * frequency; 472 if (Q > 0) { 473 double alpha = sin(w0) / (2 * Q); 474 double k = cos(w0); 254 475 255 double b0 = A * (aPlusOne - aMinusOne * k + k2); 256 double b1 = 2 * A * (aMinusOne - aPlusOne * k); 257 double b2 = A * (aPlusOne - aMinusOne * k - k2); 258 double a0 = aPlusOne + aMinusOne * k + k2; 259 double a1 = -2 * (aMinusOne + aPlusOne * k); 260 double a2 = aPlusOne + aMinusOne * k - k2; 261 262 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 263 } 264 265 void Biquad::setHighShelfParams(double frequency, double dbGain) 266 { 267 double w0 = piDouble * frequency; 268 269 double A = pow(10.0, dbGain / 40); 270 double S = 1; // filter slope (1 is max value) 271 double alpha = 0.5 * sin(w0) * sqrt((A + 1 / A) * (1 / S - 1) + 2); 272 273 double k = cos(w0); 274 double k2 = 2 * sqrt(A) * alpha; 275 276 double aPlusOne = A + 1; 277 double aMinusOne = A - 1; 278 279 double b0 = A * (aPlusOne + aMinusOne * k + k2); 280 double b1 = -2 * A * (aMinusOne + aPlusOne * k); 281 double b2 = A * (aPlusOne + aMinusOne * k - k2); 282 double a0 = aPlusOne - aMinusOne * k + k2; 283 double a1 = 2 * (aMinusOne - aPlusOne * k); 284 double a2 = aPlusOne - aMinusOne * k - k2; 285 286 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 287 } 288 289 void Biquad::setPeakingParams(double frequency, double Q, double dbGain) 290 { 291 double w0 = piDouble * frequency; 292 double alpha = sin(w0) / (2 * Q); 293 double A = pow(10.0, dbGain / 40); 294 295 double k = cos(w0); 296 297 double b0 = 1 + alpha * A; 298 double b1 = -2 * k; 299 double b2 = 1 - alpha * A; 300 double a0 = 1 + alpha / A; 301 double a1 = -2 * k; 302 double a2 = 1 - alpha / A; 303 304 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 305 } 306 307 void Biquad::setAllpassParams(double frequency, double Q) 308 { 309 double w0 = piDouble * frequency; 310 double alpha = sin(w0) / (2 * Q); 311 312 double k = cos(w0); 313 314 double b0 = 1 - alpha; 315 double b1 = -2 * k; 316 double b2 = 1 + alpha; 317 double a0 = 1 + alpha; 318 double a1 = -2 * k; 319 double a2 = 1 - alpha; 320 321 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 322 } 323 324 void Biquad::setNotchParams(double frequency, double Q) 325 { 326 double w0 = piDouble * frequency; 327 double alpha = sin(w0) / (2 * Q); 328 329 double k = cos(w0); 330 331 double b0 = 1; 332 double b1 = -2 * k; 333 double b2 = 1; 334 double a0 = 1 + alpha; 335 double a1 = -2 * k; 336 double a2 = 1 - alpha; 337 338 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 339 } 340 341 void Biquad::setBandpassParams(double frequency, double Q) 342 { 343 double w0 = piDouble * frequency; 344 double alpha = sin(w0) / (2 * Q); 345 346 double k = cos(w0); 347 348 double b0 = alpha; 349 double b1 = 0; 350 double b2 = -alpha; 351 double a0 = 1 + alpha; 352 double a1 = -2 * k; 353 double a2 = 1 - alpha; 354 355 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 476 double b0 = alpha; 477 double b1 = 0; 478 double b2 = -alpha; 479 double a0 = 1 + alpha; 480 double a1 = -2 * k; 481 double a2 = 1 - alpha; 482 483 setNormalizedCoefficients(b0, b1, b2, a0, a1, a2); 484 } else { 485 // When Q = 0, the above formulas have problems. If we look at 486 // the z-transform, we can see that the limit as Q->0 is 1, so 487 // set the filter that way. 488 setNormalizedCoefficients(1, 0, 0, 489 1, 0, 0); 490 } 491 } else { 492 // When the cutoff is zero, the z-transform approaches 0, if Q 493 // > 0. When both Q and cutoff are zero, the z-transform is 494 // pretty much undefined. What should we do in this case? 495 // For now, just make the filter 0. When the cutoff is 1, the 496 // z-transform also approaches 0. 497 setNormalizedCoefficients(0, 0, 0, 498 1, 0, 0); 499 } 356 500 } 357 501
Note: See TracChangeset
for help on using the changeset viewer.