Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: third_party/WebKit/Source/platform/audio/Biquad.cpp

Issue 2862373002: Compute tail time from Biquad coefficients (Closed)
Patch Set: Initialize tail_time_ in constructor Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/platform/audio/Biquad.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2010 Google Inc. All rights reserved. 2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 573 matching lines...) Expand 10 before | Expand all | Expand 10 after
584 std::complex<double> denominator = 584 std::complex<double> denominator =
585 std::complex<double>(1, 0) + (a1 + a2 * z) * z; 585 std::complex<double>(1, 0) + (a1 + a2 * z) * z;
586 std::complex<double> response = numerator / denominator; 586 std::complex<double> response = numerator / denominator;
587 mag_response[k] = static_cast<float>(abs(response)); 587 mag_response[k] = static_cast<float>(abs(response));
588 phase_response[k] = 588 phase_response[k] =
589 static_cast<float>(atan2(imag(response), real(response))); 589 static_cast<float>(atan2(imag(response), real(response)));
590 } 590 }
591 } 591 }
592 } 592 }
593 593
594 static double RepeatedRootResponse(double n,
595 double c1,
596 double c2,
597 double r,
598 double log_eps) {
599 // The response is h(n) = r^(n-2)*[c1*(n+1)*r^2+c2]. We're looking
600 // for n such that |h(n)| = eps. Equivalently, we want a root
601 // of the equation log(|h(n)|) - log(eps) = 0 or
602 //
603 // (n-2)*log(r) + log(|c1*(n+1)*r^2+c2|) - log(eps)
604 //
605 // This helps with finding a nuemrical solution because this
606 // approximately linearizes the response for large n.
607
608 return (n - 2) * log(r) + log(fabs(c1 * (n + 1) * r * r + c2)) - log_eps;
609 }
610
611 // Regula Falsi root finder, Illinois variant
612 // (https://en.wikipedia.org/wiki/False_position_method#The_Illinois_algorithm).
613 //
614 // This finds a root of the repeated root response where the root is
615 // assumed to lie between |low| and |high|. The response is given by
616 // |c1|, |c2|, and |r| as determined by |RepeatedRootResponse|.
617 // |log_eps| is the log the the maximum allowed amplitude in the
618 // response.
619 static double RootFinder(double low,
620 double high,
621 double log_eps,
622 double c1,
623 double c2,
624 double r) {
625 // Desired accuray of the root (in frames). This doesn't need to be
626 // super-accurate, so half frame is good enough, and should be less
627 // than 1 because the algorithm may prematurely terminate.
628 const double kAccuracyThreshold = 0.5;
629 // Max number of iterations to do. If we haven't converged by now,
630 // just return whatever we've found.
631 const int kMaxIterations = 10;
632
633 int side = 0;
634 double root = 0;
635 double f_low = RepeatedRootResponse(low, c1, c2, r, log_eps);
636 double f_high = RepeatedRootResponse(high, c1, c2, r, log_eps);
637
638 // The function values must be finite and have opposite signs!
639 DCHECK(std::isfinite(f_low));
640 DCHECK(std::isfinite(f_high));
641 DCHECK_LE(f_low * f_high, 0);
642
643 int iteration;
644 for (iteration = 0; iteration < kMaxIterations; ++iteration) {
645 root = (f_low * high - f_high * low) / (f_low - f_high);
646 if (fabs(high - low) < kAccuracyThreshold * fabs(high + low))
647 break;
648 double fr = RepeatedRootResponse(root, c1, c2, r, log_eps);
649
650 DCHECK(std::isfinite(fr));
651
652 if (fr * f_high > 0) {
653 // fr and f_high have same sign. Copy root to f_high
654 high = root;
655 f_high = fr;
656 side = -1;
657 } else if (f_low * fr > 0) {
658 // fr and f_low have same sign. Copy root to f_low
659 low = root;
660 f_low = fr;
661 if (side == 1)
662 f_high /= 2;
663 side = 1;
664 } else {
665 // f_low * fr looks like zero, so assume we've converged.
666 break;
667 }
668 }
669
670 // Want to know if the max number of iterations is ever exceeded so
671 // we can understand why that happened.
672 DCHECK_LT(iteration, kMaxIterations);
673
674 return root;
675 }
676
677 double Biquad::TailFrame(int coef_index, double max_frame) {
678 // The Biquad filter is given by
679 //
680 // H(z) = (b0 + b1/z + b2/z^2)/(1 + a1/z + a2/z^2).
681 //
682 // To compute the tail time, compute the impulse response, h(n), of
683 // H(z), which we can do analytically. From this impulse response,
684 // find the value n0 where |h(n)| <= eps for n >= n0.
685 //
686 // Assume first that the two poles of H(z) are not repeated, say r1
687 // and r2. Then, we can compute a partial fraction expansion of
688 // H(z):
689 //
690 // H(z) = (b0+b1/z+b2/z^2)/[(1-r1/z)*(1-r2/z)]
691 // = b0 + C2/(z-r2) - C1/(z-r1)
692 //
693 // where
694 // C2 = (b0*r2^2+b1*r2+b2)/(r2-r1)
695 // C1 = (b0*r1^2+b1*r1+b2)/(r2-r1)
696 //
697 // Expand H(z) then this in powers of 1/z gives:
698 //
699 // H(z) = b0 -(C2/r2+C1/r1) + sum(C2*r2^(i-1)/z^i + C1*r1^(i-1)/z^i)
700 //
701 // Thus, for n > 1 (we don't care about small n),
702 //
703 // h(n) = C2*r2^(n-1) + C1*r1^(n-1)
704 //
705 // We need to find n0 such that |h(n)| < eps for n > n0.
706 //
707 // Case 1: r1 and r2 are real and distinct, with |r1|>=|r2|.
708 //
709 // Then
710 //
711 // h(n) = C1*r1^(n-1)*(1 + C2/C1*(r2/r1)^(n-1))
712 //
713 // so
714 //
715 // |h(n)| = |C1|*|r|^(n-1)*|1+C2/C1*(r2/r1)^(n-1)|
716 // <= |C1|*|r|^(n-1)*[1 + |C2/C1|*|r2/r1|^(n-1)]
717 // <= |C1|*|r|^(n-1)*[1 + |C2/C1|]
718 //
719 // by using the triangle inequality and the fact that |r2|<=|r1|.
720 // And we want |h(n)|<=eps which is true if
721 //
722 // |C1|*|r|^(n-1)*[1 + |C2/C1|] <= eps
723 //
724 // or
725 //
726 // n >= 1 + log(eps/C)/log(|r1|)
727 //
728 // where C = |C1|*[1+|C2/C1|] = |C1| + |C2|.
729 //
730 // Case 2: r1 and r2 are complex
731 //
732 // Thne we can write r1=r*exp(i*p) and r2=r*exp(-i*p). So,
733 //
734 // |h(n)| = |C2*r^(n-1)*exp(-i*p*(n-1)) + C1*r^(n-1)*exp(i*p*(n-1))|
735 // = |C1|*r^(n-1)*|1 + C2/C1*exp(-i*p*(n-1))/exp(i*n*(n-1))|
736 // <= |C1|*r^(n-1)*[1 + |C2/C1|]
737 //
738 // Again, this is easily solved to give
739 //
740 // n >= 1 + log(eps/C)/log(r)
741 //
742 // where C = |C1|*[1+|C2/C1|] = |C1| + |C2|.
743 //
744 // Case 3: Repeated roots, r1=r2=r.
745 //
746 // In this case,
747 //
748 // H(z) = (b0+b1/z+b2/z^2)/[(1-r/z)^2
749 //
750 // Expanding this in powers of 1/z gives:
751 //
752 // H(z) = C1*sum((i+1)*r^i/z^i) - C2 * sum(r^(i-2)/z^i) + b2/r^2
753 // = b2/r^2 + sum([C1*(i+1)*r^i + C2*r^(i-2)]/z^i)
754 // where
755 // C1 = (b0*r^2+b1*r+b2)/r^2
756 // C2 = b1*r+2*b2
757 //
758 // Thus, the impulse response is
759 //
760 // h(n) = C1*(n+1)*r^n + C2*r^(n-2)
761 // = r^(n-2)*[C1*(n+1)*r^2+C2]
762 //
763 // So
764 //
765 // |h(n)| = |r|^(n-2)*|C1*(n+1)*r^2+C2|
766 //
767 // To find n such that |h(n)| < eps, we need a numerical method in
768 // general, so there's no real reason to simplify this or use other
769 // approximations. Just solve |h(n)|=eps directly.
770 //
771 // Thus, for an set of filter coefficients, we can compute the tail
772 // time.
773 //
774
775 // If the maximum amplitude of the impulse response is less than
776 // this, we assume that we've reached the tail of the response.
777 // Currently, this means that the impulse is less than 1 bit of a
778 // 16-bit PCM value.
779 const double kMaxTailAmplitude = 1 / 32768.0;
780
781 // Find the roots of 1+a1/z+a2/z^2 = 0. Or equivalently,
782 // z^2+a1*z+a2 = 0. From the quadratic formula the roots are
783 // (-a1+/-sqrt(a1^2-4*a2))/2.
784
785 double a1 = a1_[coef_index];
786 double a2 = a2_[coef_index];
787 double b0 = b0_[coef_index];
788 double b1 = b1_[coef_index];
789 double b2 = b2_[coef_index];
790
791 double tail_frame = 0;
792 double discrim = a1 * a1 - 4 * a2;
793
794 if (discrim > 0) {
795 // Compute the real roots so that r1 has the largest magnitude.
796 double r1;
797 double r2;
798 if (a1 < 0) {
799 r1 = (-a1 + sqrt(discrim)) / 2;
800 } else {
801 r1 = (-a1 - sqrt(discrim)) / 2;
802 }
803 r2 = a2 / r1;
804
805 double c1 = (b0 * r1 * r1 + b1 * r1 + b2) / (r2 - r1);
806 double c2 = (b0 * r2 * r2 + b1 * r2 + b2) / (r2 - r1);
807
808 DCHECK(std::isfinite(r1));
809 DCHECK(std::isfinite(r2));
810 DCHECK(std::isfinite(c1));
811 DCHECK(std::isfinite(c2));
812
813 // It's possible for kMaxTailAmplitude to be greater than c1 + c2.
814 // This may produce a negative tail frame. Just clamp the tail
815 // frame to 0.
816 tail_frame = clampTo(
817 1 + log(kMaxTailAmplitude / (fabs(c1) + fabs(c2))) / log(r1), 0);
818
819 DCHECK(std::isfinite(tail_frame));
820 } else if (discrim < 0) {
821 // Two complex roots.
822 // One root is -a1/2 + i*sqrt(-discrim)/2.
823 double x = -a1 / 2;
824 double y = sqrt(-discrim) / 2;
825 std::complex<double> r1(x, y);
826 std::complex<double> r2(x, -y);
827 double r = hypot(x, y);
828
829 DCHECK(std::isfinite(r));
830
831 // It's possible for r to be 1. (LPF with Q very large can cause this.)
832 if (r == 1) {
833 tail_frame = max_frame;
834 } else {
835 double c1 = abs((b0 * r1 * r1 + b1 * r1 + b2) / (r2 - r1));
836 double c2 = abs((b0 * r2 * r2 + b1 * r2 + b2) / (r2 - r1));
837
838 DCHECK(std::isfinite(c1));
839 DCHECK(std::isfinite(c2));
840
841 tail_frame = 1 + log(kMaxTailAmplitude / (c1 + c2)) / log(r);
842 DCHECK(std::isfinite(tail_frame));
843 }
844 } else {
845 // Repeated roots. This should be pretty rare because all the
846 // coefficients need to be just the right values to get a
847 // discriminant of exactly zero.
848 double r = -a1 / 2;
849
850 if (r == 0) {
851 // Double pole at 0. This just delays the signal by 2 frames,
852 // so set the tail frame to 2.
853 tail_frame = 2;
854 } else {
855 double c1 = (b0 * r * r + b1 * r + b2) / (r * r);
856 double c2 = b1 * r + 2 * b2;
857
858 DCHECK(std::isfinite(c1));
859 DCHECK(std::isfinite(c2));
860
861 // It can happen that c1=c2=0. This basically means that H(z) =
862 // constant, which is the limiting case for several of the
863 // biquad filters.
864 if (c1 == 0 && c2 == 0) {
865 tail_frame = 0;
866 } else {
867 // The function c*(n+1)*r^n is not monotonic, but it's easy to
868 // find the max point since the derivative is
869 // c*r^n*(1+(n+1)*log(r)). This has a root at
870 // -(1+log(r))/log(r). so we can start our search from that
871 // point to max_frames.
872
873 double low = clampTo(-(1 + log(r)) / log(r), 1.0,
874 static_cast<double>(max_frame - 1));
875 double high = max_frame;
876
877 DCHECK(std::isfinite(low));
878 DCHECK(std::isfinite(high));
879
880 tail_frame = RootFinder(low, high, log(kMaxTailAmplitude), c1, c2, r);
881 }
882 }
883 }
884
885 return tail_frame;
886 }
887
594 } // namespace blink 888 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/platform/audio/Biquad.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698