diff --git a/src/audio/eq_iir/tune/sof_ucm2_eq_example.txt b/src/audio/eq_iir/tune/sof_ucm2_eq_example.txt new file mode 100644 index 000000000000..1b47705f08bd --- /dev/null +++ b/src/audio/eq_iir/tune/sof_ucm2_eq_example.txt @@ -0,0 +1,1024 @@ + 100.000, -32.508, -34.491 + 100.519, -32.455, -34.372 + 101.041, -32.402, -34.252 + 101.566, -32.349, -34.130 + 102.093, -32.296, -34.008 + 102.623, -32.242, -33.885 + 103.156, -32.189, -33.761 + 103.692, -32.135, -33.636 + 104.230, -32.080, -33.512 + 104.772, -32.026, -33.387 + 105.316, -31.971, -33.261 + 105.863, -31.916, -33.136 + 106.412, -31.861, -33.011 + 106.965, -31.806, -32.885 + 107.520, -31.750, -32.760 + 108.079, -31.694, -32.635 + 108.640, -31.638, -32.510 + 109.204, -31.581, -32.386 + 109.771, -31.525, -32.262 + 110.341, -31.468, -32.138 + 110.914, -31.411, -32.015 + 111.490, -31.353, -31.893 + 112.069, -31.295, -31.771 + 112.651, -31.237, -31.649 + 113.236, -31.179, -31.528 + 113.824, -31.120, -31.407 + 114.415, -31.061, -31.288 + 115.009, -31.001, -31.168 + 115.606, -30.941, -31.050 + 116.206, -30.881, -30.932 + 116.810, -30.820, -30.814 + 117.416, -30.759, -30.698 + 118.026, -30.698, -30.582 + 118.639, -30.636, -30.466 + 119.255, -30.573, -30.351 + 119.874, -30.510, -30.237 + 120.497, -30.447, -30.124 + 121.122, -30.383, -30.011 + 121.751, -30.318, -29.899 + 122.383, -30.253, -29.787 + 123.019, -30.188, -29.676 + 123.658, -30.121, -29.565 + 124.300, -30.055, -29.456 + 124.945, -29.987, -29.346 + 125.594, -29.919, -29.238 + 126.246, -29.850, -29.129 + 126.902, -29.781, -29.022 + 127.561, -29.711, -28.915 + 128.223, -29.640, -28.808 + 128.889, -29.568, -28.702 + 129.558, -29.496, -28.596 + 130.231, -29.423, -28.491 + 130.907, -29.349, -28.387 + 131.587, -29.274, -28.283 + 132.270, -29.198, -28.179 + 132.957, -29.122, -28.076 + 133.647, -29.045, -27.973 + 134.341, -28.967, -27.870 + 135.039, -28.888, -27.768 + 135.740, -28.808, -27.666 + 136.445, -28.727, -27.565 + 137.154, -28.646, -27.464 + 137.866, -28.563, -27.363 + 138.582, -28.480, -27.263 + 139.301, -28.395, -27.163 + 140.025, -28.310, -27.063 + 140.752, -28.224, -26.963 + 141.483, -28.137, -26.864 + 142.217, -28.048, -26.765 + 142.956, -27.959, -26.666 + 143.698, -27.869, -26.567 + 144.444, -27.778, -26.468 + 145.194, -27.686, -26.370 + 145.948, -27.593, -26.272 + 146.706, -27.499, -26.174 + 147.468, -27.404, -26.076 + 148.234, -27.308, -25.978 + 149.003, -27.211, -25.880 + 149.777, -27.114, -25.782 + 150.555, -27.015, -25.685 + 151.337, -26.915, -25.587 + 152.122, -26.815, -25.489 + 152.912, -26.713, -25.392 + 153.706, -26.611, -25.294 + 154.504, -26.508, -25.196 + 155.307, -26.403, -25.099 + 156.113, -26.298, -25.001 + 156.924, -26.193, -24.903 + 157.739, -26.086, -24.805 + 158.558, -25.978, -24.707 + 159.381, -25.870, -24.609 + 160.209, -25.761, -24.511 + 161.041, -25.651, -24.412 + 161.877, -25.540, -24.314 + 162.717, -25.429, -24.215 + 163.562, -25.317, -24.116 + 164.412, -25.204, -24.017 + 165.265, -25.091, -23.918 + 166.123, -24.977, -23.818 + 166.986, -24.862, -23.718 + 167.853, -24.747, -23.618 + 168.725, -24.631, -23.518 + 169.601, -24.515, -23.417 + 170.482, -24.398, -23.316 + 171.367, -24.281, -23.215 + 172.257, -24.163, -23.113 + 173.151, -24.045, -23.012 + 174.050, -23.926, -22.909 + 174.954, -23.807, -22.807 + 175.863, -23.687, -22.704 + 176.776, -23.568, -22.601 + 177.694, -23.448, -22.497 + 178.616, -23.327, -22.393 + 179.544, -23.206, -22.289 + 180.476, -23.086, -22.184 + 181.413, -22.964, -22.079 + 182.355, -22.843, -21.973 + 183.302, -22.722, -21.867 + 184.254, -22.600, -21.761 + 185.211, -22.478, -21.654 + 186.173, -22.356, -21.547 + 187.139, -22.234, -21.439 + 188.111, -22.112, -21.331 + 189.088, -21.990, -21.223 + 190.070, -21.868, -21.114 + 191.057, -21.746, -21.005 + 192.049, -21.624, -20.895 + 193.046, -21.502, -20.785 + 194.048, -21.381, -20.675 + 195.056, -21.259, -20.565 + 196.069, -21.137, -20.453 + 197.087, -21.016, -20.342 + 198.110, -20.895, -20.230 + 199.139, -20.773, -20.118 + 200.173, -20.652, -20.006 + 201.213, -20.532, -19.893 + 202.257, -20.411, -19.780 + 203.308, -20.291, -19.667 + 204.363, -20.171, -19.554 + 205.424, -20.051, -19.440 + 206.491, -19.932, -19.326 + 207.563, -19.812, -19.212 + 208.641, -19.693, -19.097 + 209.725, -19.575, -18.983 + 210.814, -19.457, -18.868 + 211.908, -19.339, -18.753 + 213.009, -19.221, -18.638 + 214.115, -19.104, -18.523 + 215.227, -18.987, -18.408 + 216.344, -18.870, -18.293 + 217.468, -18.754, -18.178 + 218.597, -18.639, -18.063 + 219.732, -18.523, -17.947 + 220.873, -18.408, -17.832 + 222.020, -18.294, -17.717 + 223.173, -18.180, -17.603 + 224.331, -18.066, -17.488 + 225.496, -17.953, -17.373 + 226.667, -17.840, -17.259 + 227.844, -17.727, -17.145 + 229.027, -17.616, -17.031 + 230.217, -17.504, -16.918 + 231.412, -17.393, -16.804 + 232.614, -17.283, -16.691 + 233.822, -17.172, -16.579 + 235.036, -17.063, -16.467 + 236.256, -16.954, -16.355 + 237.483, -16.845, -16.244 + 238.716, -16.737, -16.133 + 239.956, -16.630, -16.023 + 241.202, -16.523, -15.914 + 242.454, -16.416, -15.805 + 243.713, -16.310, -15.696 + 244.979, -16.205, -15.588 + 246.251, -16.100, -15.481 + 247.529, -15.996, -15.375 + 248.815, -15.892, -15.269 + 250.107, -15.790, -15.164 + 251.405, -15.687, -15.060 + 252.711, -15.585, -14.957 + 254.023, -15.484, -14.854 + 255.342, -15.384, -14.753 + 256.668, -15.284, -14.652 + 258.001, -15.185, -14.552 + 259.341, -15.086, -14.453 + 260.687, -14.989, -14.355 + 262.041, -14.891, -14.258 + 263.402, -14.795, -14.162 + 264.769, -14.699, -14.067 + 266.144, -14.604, -13.973 + 267.526, -14.510, -13.880 + 268.915, -14.416, -13.788 + 270.312, -14.324, -13.697 + 271.715, -14.232, -13.607 + 273.126, -14.140, -13.518 + 274.545, -14.049, -13.430 + 275.970, -13.959, -13.344 + 277.403, -13.870, -13.258 + 278.844, -13.781, -13.174 + 280.292, -13.693, -13.090 + 281.747, -13.606, -13.008 + 283.210, -13.519, -12.926 + 284.681, -13.433, -12.846 + 286.159, -13.348, -12.767 + 287.645, -13.263, -12.688 + 289.138, -13.178, -12.611 + 290.640, -13.094, -12.535 + 292.149, -13.011, -12.459 + 293.666, -12.927, -12.385 + 295.191, -12.844, -12.311 + 296.724, -12.762, -12.238 + 298.264, -12.679, -12.166 + 299.813, -12.597, -12.095 + 301.370, -12.514, -12.024 + 302.935, -12.432, -11.955 + 304.508, -12.350, -11.885 + 306.089, -12.267, -11.817 + 307.679, -12.184, -11.748 + 309.276, -12.101, -11.681 + 310.882, -12.018, -11.613 + 312.497, -11.934, -11.546 + 314.119, -11.849, -11.479 + 315.750, -11.764, -11.412 + 317.390, -11.678, -11.346 + 319.038, -11.591, -11.279 + 320.695, -11.503, -11.212 + 322.360, -11.414, -11.145 + 324.034, -11.324, -11.078 + 325.716, -11.232, -11.010 + 327.408, -11.139, -10.942 + 329.108, -11.045, -10.874 + 330.817, -10.950, -10.805 + 332.535, -10.852, -10.735 + 334.261, -10.753, -10.664 + 335.997, -10.653, -10.592 + 337.742, -10.550, -10.519 + 339.495, -10.446, -10.446 + 341.258, -10.340, -10.370 + 343.030, -10.232, -10.294 + 344.812, -10.122, -10.216 + 346.602, -10.010, -10.137 + 348.402, -9.896, -10.057 + 350.211, -9.781, -9.974 + 352.029, -9.663, -9.890 + 353.857, -9.543, -9.804 + 355.695, -9.422, -9.717 + 357.542, -9.298, -9.627 + 359.398, -9.173, -9.535 + 361.265, -9.047, -9.442 + 363.141, -8.918, -9.346 + 365.026, -8.788, -9.249 + 366.922, -8.657, -9.149 + 368.827, -8.524, -9.048 + 370.742, -8.391, -8.944 + 372.667, -8.256, -8.838 + 374.602, -8.120, -8.730 + 376.548, -7.983, -8.620 + 378.503, -7.845, -8.508 + 380.468, -7.707, -8.394 + 382.444, -7.569, -8.278 + 384.430, -7.430, -8.160 + 386.426, -7.291, -8.040 + 388.433, -7.152, -7.918 + 390.450, -7.013, -7.794 + 392.477, -6.874, -7.669 + 394.515, -6.736, -7.543 + 396.564, -6.599, -7.414 + 398.623, -6.462, -7.284 + 400.693, -6.326, -7.153 + 402.773, -6.191, -7.021 + 404.865, -6.057, -6.887 + 406.967, -5.924, -6.752 + 409.080, -5.792, -6.616 + 411.204, -5.662, -6.478 + 413.340, -5.533, -6.340 + 415.486, -5.406, -6.201 + 417.644, -5.281, -6.062 + 419.812, -5.157, -5.921 + 421.992, -5.035, -5.780 + 424.183, -4.915, -5.638 + 426.386, -4.797, -5.495 + 428.600, -4.680, -5.352 + 430.826, -4.566, -5.209 + 433.063, -4.454, -5.065 + 435.311, -4.343, -4.921 + 437.572, -4.235, -4.776 + 439.844, -4.128, -4.631 + 442.128, -4.024, -4.486 + 444.424, -3.921, -4.341 + 446.732, -3.821, -4.195 + 449.051, -3.722, -4.049 + 451.383, -3.626, -3.904 + 453.727, -3.531, -3.758 + 456.083, -3.439, -3.612 + 458.451, -3.348, -3.466 + 460.832, -3.259, -3.321 + 463.225, -3.173, -3.176 + 465.630, -3.088, -3.031 + 468.048, -3.005, -2.886 + 470.478, -2.923, -2.742 + 472.921, -2.844, -2.599 + 475.377, -2.767, -2.456 + 477.845, -2.691, -2.314 + 480.327, -2.618, -2.174 + 482.821, -2.546, -2.034 + 485.328, -2.477, -1.896 + 487.848, -2.410, -1.759 + 490.381, -2.344, -1.623 + 492.928, -2.281, -1.489 + 495.487, -2.220, -1.358 + 498.060, -2.161, -1.228 + 500.646, -2.105, -1.101 + 503.246, -2.050, -0.976 + 505.859, -1.999, -0.854 + 508.486, -1.949, -0.734 + 511.126, -1.902, -0.618 + 513.780, -1.858, -0.505 + 516.448, -1.816, -0.395 + 519.130, -1.777, -0.288 + 521.826, -1.741, -0.186 + 524.535, -1.707, -0.087 + 527.259, -1.676, 0.008 + 529.997, -1.647, 0.099 + 532.749, -1.621, 0.185 + 535.515, -1.598, 0.267 + 538.296, -1.577, 0.345 + 541.091, -1.559, 0.418 + 543.901, -1.543, 0.486 + 546.725, -1.530, 0.550 + 549.564, -1.519, 0.608 + 552.418, -1.510, 0.662 + 555.286, -1.503, 0.711 + 558.170, -1.498, 0.755 + 561.068, -1.495, 0.795 + 563.982, -1.493, 0.829 + 566.910, -1.493, 0.858 + 569.854, -1.494, 0.882 + 572.813, -1.496, 0.901 + 575.787, -1.499, 0.915 + 578.777, -1.503, 0.924 + 581.783, -1.508, 0.927 + 584.804, -1.513, 0.926 + 587.840, -1.518, 0.920 + 590.893, -1.524, 0.908 + 593.961, -1.529, 0.891 + 597.045, -1.534, 0.869 + 600.145, -1.539, 0.842 + 603.262, -1.543, 0.809 + 606.394, -1.547, 0.771 + 609.543, -1.550, 0.727 + 612.708, -1.553, 0.679 + 615.890, -1.555, 0.624 + 619.088, -1.556, 0.565 + 622.303, -1.556, 0.500 + 625.534, -1.556, 0.429 + 628.782, -1.556, 0.353 + 632.047, -1.555, 0.272 + 635.329, -1.554, 0.185 + 638.628, -1.552, 0.093 + 641.944, -1.550, -0.004 + 645.278, -1.549, -0.106 + 648.628, -1.548, -0.212 + 651.996, -1.547, -0.324 + 655.382, -1.548, -0.439 + 658.785, -1.549, -0.559 + 662.206, -1.551, -0.682 + 665.645, -1.555, -0.809 + 669.101, -1.560, -0.938 + 672.575, -1.568, -1.071 + 676.068, -1.577, -1.205 + 679.578, -1.589, -1.342 + 683.107, -1.604, -1.480 + 686.654, -1.622, -1.619 + 690.220, -1.642, -1.759 + 693.804, -1.666, -1.900 + 697.407, -1.693, -2.041 + 701.028, -1.724, -2.181 + 704.668, -1.758, -2.321 + 708.327, -1.797, -2.460 + 712.005, -1.839, -2.599 + 715.703, -1.886, -2.736 + 719.419, -1.937, -2.872 + 723.155, -1.993, -3.006 + 726.910, -2.053, -3.139 + 730.684, -2.118, -3.270 + 734.478, -2.188, -3.399 + 738.292, -2.262, -3.526 + 742.126, -2.342, -3.651 + 745.980, -2.427, -3.772 + 749.853, -2.517, -3.890 + 753.747, -2.613, -4.004 + 757.661, -2.714, -4.113 + 761.595, -2.820, -4.217 + 765.550, -2.932, -4.313 + 769.525, -3.048, -4.402 + 773.521, -3.169, -4.482 + 777.537, -3.295, -4.551 + 781.575, -3.424, -4.609 + 785.633, -3.556, -4.654 + 789.713, -3.690, -4.685 + 793.813, -3.824, -4.702 + 797.935, -3.959, -4.704 + 802.079, -4.091, -4.690 + 806.244, -4.221, -4.662 + 810.430, -4.345, -4.619 + 814.639, -4.463, -4.563 + 818.869, -4.574, -4.495 + 823.121, -4.675, -4.417 + 827.395, -4.765, -4.331 + 831.691, -4.844, -4.239 + 836.010, -4.912, -4.143 + 840.351, -4.967, -4.044 + 844.715, -5.010, -3.945 + 849.101, -5.041, -3.846 + 853.510, -5.062, -3.751 + 857.942, -5.073, -3.659 + 862.397, -5.075, -3.571 + 866.875, -5.069, -3.488 + 871.376, -5.057, -3.409 + 875.901, -5.040, -3.336 + 880.449, -5.018, -3.266 + 885.021, -4.994, -3.200 + 889.617, -4.966, -3.135 + 894.236, -4.937, -3.071 + 898.880, -4.907, -3.006 + 903.547, -4.875, -2.938 + 908.239, -4.842, -2.866 + 912.955, -4.807, -2.787 + 917.696, -4.770, -2.699 + 922.461, -4.731, -2.602 + 927.251, -4.689, -2.494 + 932.066, -4.644, -2.374 + 936.906, -4.596, -2.243 + 941.771, -4.544, -2.100 + 946.661, -4.488, -1.947 + 951.577, -4.428, -1.785 + 956.518, -4.364, -1.615 + 961.485, -4.296, -1.440 + 966.477, -4.225, -1.262 + 971.496, -4.151, -1.083 + 976.541, -4.076, -0.905 + 981.611, -3.999, -0.731 + 986.709, -3.923, -0.563 + 991.832, -3.846, -0.402 + 996.982, -3.772, -0.249 + 1002.159, -3.699, -0.106 + 1007.363, -3.630, 0.026 + 1012.594, -3.564, 0.147 + 1017.852, -3.502, 0.257 + 1023.137, -3.444, 0.355 + 1028.450, -3.391, 0.442 + 1033.791, -3.343, 0.518 + 1039.159, -3.300, 0.582 + 1044.555, -3.260, 0.636 + 1049.979, -3.224, 0.680 + 1055.431, -3.192, 0.715 + 1060.911, -3.161, 0.740 + 1066.420, -3.130, 0.758 + 1071.958, -3.100, 0.768 + 1077.524, -3.067, 0.770 + 1083.119, -3.031, 0.766 + 1088.743, -2.990, 0.757 + 1094.397, -2.943, 0.742 + 1100.080, -2.888, 0.724 + 1105.792, -2.826, 0.702 + 1111.534, -2.755, 0.679 + 1117.306, -2.675, 0.656 + 1123.107, -2.587, 0.635 + 1128.939, -2.492, 0.617 + 1134.802, -2.391, 0.605 + 1140.694, -2.285, 0.601 + 1146.617, -2.176, 0.607 + 1152.571, -2.067, 0.624 + 1158.556, -1.958, 0.656 + 1164.572, -1.853, 0.702 + 1170.619, -1.753, 0.765 + 1176.698, -1.659, 0.844 + 1182.808, -1.572, 0.939 + 1188.950, -1.493, 1.048 + 1195.124, -1.424, 1.170 + 1201.330, -1.363, 1.303 + 1207.568, -1.310, 1.445 + 1213.838, -1.265, 1.591 + 1220.141, -1.226, 1.739 + 1226.477, -1.192, 1.885 + 1232.845, -1.162, 2.028 + 1239.247, -1.133, 2.163 + 1245.682, -1.103, 2.288 + 1252.151, -1.070, 2.401 + 1258.652, -1.033, 2.500 + 1265.188, -0.989, 2.584 + 1271.758, -0.938, 2.651 + 1278.362, -0.879, 2.701 + 1285.000, -0.812, 2.734 + 1291.672, -0.738, 2.750 + 1298.379, -0.657, 2.751 + 1305.121, -0.570, 2.737 + 1311.898, -0.480, 2.709 + 1318.711, -0.386, 2.669 + 1325.558, -0.291, 2.619 + 1332.441, -0.195, 2.561 + 1339.360, -0.097, 2.495 + 1346.315, 0.001, 2.423 + 1353.306, 0.102, 2.347 + 1360.333, 0.207, 2.268 + 1367.397, 0.317, 2.186 + 1374.497, 0.436, 2.104 + 1381.634, 0.566, 2.022 + 1388.809, 0.710, 1.942 + 1396.020, 0.869, 1.864 + 1403.269, 1.046, 1.791 + 1410.556, 1.241, 1.725 + 1417.881, 1.454, 1.668 + 1425.243, 1.684, 1.621 + 1432.644, 1.927, 1.587 + 1440.083, 2.182, 1.566 + 1447.561, 2.443, 1.560 + 1455.078, 2.706, 1.568 + 1462.633, 2.966, 1.588 + 1470.228, 3.219, 1.618 + 1477.862, 3.458, 1.655 + 1485.536, 3.682, 1.696 + 1493.250, 3.884, 1.737 + 1501.004, 4.064, 1.773 + 1508.798, 4.218, 1.802 + 1516.633, 4.345, 1.820 + 1524.508, 4.445, 1.825 + 1532.425, 4.519, 1.816 + 1540.382, 4.569, 1.793 + 1548.380, 4.598, 1.755 + 1556.421, 4.611, 1.706 + 1564.503, 4.611, 1.647 + 1572.626, 4.603, 1.582 + 1580.792, 4.593, 1.515 + 1589.001, 4.585, 1.449 + 1597.252, 4.580, 1.389 + 1605.546, 4.580, 1.336 + 1613.883, 4.585, 1.292 + 1622.263, 4.593, 1.256 + 1630.687, 4.600, 1.226 + 1639.155, 4.603, 1.199 + 1647.666, 4.597, 1.169 + 1656.222, 4.578, 1.131 + 1664.822, 4.542, 1.077 + 1673.467, 4.486, 1.003 + 1682.157, 4.410, 0.901 + 1690.891, 4.312, 0.770 + 1699.672, 4.194, 0.605 + 1708.497, 4.057, 0.408 + 1717.369, 3.904, 0.183 + 1726.287, 3.737, -0.062 + 1735.251, 3.559, -0.316 + 1744.261, 3.371, -0.561 + 1753.318, 3.175, -0.774 + 1762.423, 2.973, -0.933 + 1771.574, 2.765, -1.015 + 1780.773, 2.554, -1.007 + 1790.020, 2.341, -0.906 + 1799.315, 2.130, -0.722 + 1808.658, 1.925, -0.474 + 1818.050, 1.730, -0.186 + 1827.491, 1.548, 0.120 + 1836.980, 1.383, 0.423 + 1846.519, 1.233, 0.711 + 1856.107, 1.096, 0.976 + 1865.745, 0.962, 1.212 + 1875.433, 0.822, 1.420 + 1885.172, 0.662, 1.601 + 1894.961, 0.468, 1.757 + 1904.801, 0.228, 1.889 + 1914.692, -0.067, 1.999 + 1924.634, -0.418, 2.085 + 1934.628, -0.816, 2.147 + 1944.674, -1.236, 2.180 + 1954.772, -1.636, 2.182 + 1964.922, -1.951, 2.148 + 1975.125, -2.109, 2.078 + 1985.381, -2.054, 1.972 + 1995.691, -1.772, 1.834 + 2006.053, -1.300, 1.675 + 2016.470, -0.706, 1.511 + 2026.941, -0.065, 1.362 + 2037.466, 0.565, 1.252 + 2048.046, 1.144, 1.200 + 2058.681, 1.649, 1.220 + 2069.371, 2.069, 1.310 + 2080.116, 2.402, 1.461 + 2090.917, 2.651, 1.655 + 2101.775, 2.827, 1.875 + 2112.688, 2.942, 2.110 + 2123.659, 3.013, 2.356 + 2134.686, 3.057, 2.617 + 2145.771, 3.088, 2.903 + 2156.913, 3.121, 3.224 + 2168.113, 3.163, 3.585 + 2179.371, 3.221, 3.983 + 2190.688, 3.293, 4.409 + 2202.063, 3.376, 4.845 + 2213.498, 3.467, 5.275 + 2224.992, 3.560, 5.683 + 2236.545, 3.651, 6.058 + 2248.159, 3.739, 6.392 + 2259.833, 3.823, 6.681 + 2271.567, 3.904, 6.924 + 2283.363, 3.983, 7.120 + 2295.219, 4.061, 7.269 + 2307.138, 4.140, 7.373 + 2319.118, 4.222, 7.432 + 2331.160, 4.309, 7.448 + 2343.265, 4.401, 7.420 + 2355.433, 4.501, 7.351 + 2367.663, 4.609, 7.241 + 2379.958, 4.726, 7.095 + 2392.316, 4.854, 6.919 + 2404.739, 4.994, 6.727 + 2417.225, 5.150, 6.537 + 2429.777, 5.322, 6.372 + 2442.394, 5.514, 6.255 + 2455.077, 5.725, 6.205 + 2467.825, 5.950, 6.231 + 2480.639, 6.182, 6.326 + 2493.520, 6.411, 6.475 + 2506.468, 6.624, 6.656 + 2519.484, 6.811, 6.850 + 2532.566, 6.961, 7.043 + 2545.717, 7.071, 7.227 + 2558.936, 7.140, 7.399 + 2572.224, 7.171, 7.557 + 2585.580, 7.168, 7.696 + 2599.006, 7.140, 7.810 + 2612.502, 7.093, 7.891 + 2626.068, 7.036, 7.930 + 2639.704, 6.970, 7.920 + 2653.411, 6.897, 7.856 + 2667.189, 6.809, 7.741 + 2681.039, 6.695, 7.578 + 2694.960, 6.543, 7.374 + 2708.954, 6.342, 7.137 + 2723.021, 6.083, 6.875 + 2737.160, 5.768, 6.592 + 2751.374, 5.405, 6.291 + 2765.660, 5.012, 5.976 + 2780.021, 4.611, 5.644 + 2794.457, 4.228, 5.297 + 2808.968, 3.882, 4.934 + 2823.554, 3.579, 4.561 + 2838.215, 3.316, 4.189 + 2852.953, 3.080, 3.837 + 2867.767, 2.858, 3.527 + 2882.659, 2.639, 3.279 + 2897.627, 2.422, 3.105 + 2912.674, 2.209, 3.001 + 2927.798, 2.008, 2.948 + 2943.001, 1.829, 2.925 + 2958.283, 1.683, 2.904 + 2973.644, 1.577, 2.866 + 2989.085, 1.515, 2.798 + 3004.606, 1.486, 2.694 + 3020.208, 1.469, 2.558 + 3035.891, 1.435, 2.404 + 3051.655, 1.355, 2.251 + 3067.501, 1.208, 2.118 + 3083.430, 0.990, 2.019 + 3099.441, 0.726, 1.951 + 3115.535, 0.467, 1.889 + 3131.713, 0.280, 1.797 + 3147.975, 0.218, 1.632 + 3164.321, 0.288, 1.355 + 3180.752, 0.457, 0.938 + 3197.269, 0.677, 0.372 + 3213.871, 0.918, -0.336 + 3230.559, 1.170, -1.138 + 3247.335, 1.432, -1.928 + 3264.197, 1.698, -2.527 + 3281.147, 1.947, -2.742 + 3298.184, 2.146, -2.510 + 3315.311, 2.264, -1.959 + 3332.526, 2.285, -1.292 + 3349.830, 2.216, -0.668 + 3367.225, 2.081, -0.171 + 3384.710, 1.917, 0.171 + 3402.285, 1.757, 0.372 + 3419.952, 1.612, 0.464 + 3437.710, 1.465, 0.495 + 3455.561, 1.285, 0.502 + 3473.505, 1.051, 0.513 + 3491.541, 0.764, 0.543 + 3509.672, 0.452, 0.604 + 3527.896, 0.148, 0.703 + 3546.215, -0.134, 0.833 + 3564.629, -0.419, 0.961 + 3583.139, -0.749, 1.033 + 3601.745, -1.158, 0.988 + 3620.448, -1.629, 0.786 + 3639.247, -2.095, 0.420 + 3658.144, -2.470, -0.075 + 3677.140, -2.699, -0.628 + 3696.234, -2.803, -1.164 + 3715.427, -2.843, -1.626 + 3734.720, -2.847, -1.983 + 3754.113, -2.776, -2.195 + 3773.607, -2.564, -2.204 + 3793.202, -2.200, -1.968 + 3812.898, -1.779, -1.529 + 3832.697, -1.441, -1.010 + 3852.599, -1.297, -0.548 + 3872.604, -1.386, -0.256 + 3892.713, -1.676, -0.200 + 3912.927, -2.088, -0.391 + 3933.245, -2.529, -0.764 + 3953.669, -2.942, -1.180 + 3974.199, -3.338, -1.481 + 3994.835, -3.787, -1.589 + 4015.579, -4.352, -1.567 + 4036.430, -5.023, -1.565 + 4057.390, -5.679, -1.724 + 4078.459, -6.101, -2.132 + 4099.637, -6.069, -2.834 + 4120.925, -5.561, -3.859 + 4142.323, -4.789, -5.264 + 4163.833, -4.018, -7.179 + 4185.454, -3.441, -9.843 + 4207.187, -3.175, -13.476 + 4229.034, -3.291, -16.662 + 4250.993, -3.819, -15.263 + 4273.067, -4.728, -12.543 + 4295.256, -5.939, -10.774 + 4317.559, -7.337, -9.828 + 4339.979, -8.753, -9.406 + 4362.515, -9.868, -9.261 + 4385.168, -10.286, -9.180 + 4407.938, -10.048, -8.976 + 4430.827, -9.665, -8.512 + 4453.835, -9.483, -7.790 + 4476.962, -9.421, -6.959 + 4500.209, -9.119, -6.188 + 4523.577, -8.363, -5.571 + 4547.066, -7.338, -5.118 + 4570.678, -6.360, -4.781 + 4594.411, -5.614, -4.477 + 4618.268, -5.155, -4.149 + 4642.249, -4.983, -3.808 + 4666.355, -5.087, -3.525 + 4690.586, -5.407, -3.363 + 4714.942, -5.739, -3.307 + 4739.425, -5.714, -3.227 + 4764.035, -5.084, -2.947 + 4788.773, -4.053, -2.415 + 4813.639, -3.021, -1.776 + 4838.635, -2.223, -1.244 + 4863.760, -1.716, -0.947 + 4889.016, -1.472, -0.887 + 4914.403, -1.419, -0.968 + 4939.921, -1.466, -1.066 + 4965.572, -1.541, -1.123 + 4991.357, -1.614, -1.183 + 5017.275, -1.708, -1.327 + 5043.328, -1.870, -1.594 + 5069.516, -2.127, -1.955 + 5095.840, -2.441, -2.362 + 5122.301, -2.678, -2.771 + 5148.899, -2.625, -3.098 + 5175.636, -2.168, -3.156 + 5202.511, -1.448, -2.786 + 5229.525, -0.746, -2.056 + 5256.680, -0.276, -1.223 + 5283.976, -0.114, -0.509 + 5311.414, -0.222, -0.004 + 5338.994, -0.511, 0.313 + 5366.718, -0.897, 0.503 + 5394.585, -1.306, 0.622 + 5422.597, -1.659, 0.675 + 5450.755, -1.905, 0.629 + 5479.059, -2.070, 0.477 + 5507.509, -2.242, 0.247 + 5536.108, -2.518, -0.078 + 5564.855, -2.954, -0.599 + 5593.751, -3.515, -1.372 + 5622.797, -4.057, -2.256 + 5651.994, -4.428, -2.984 + 5681.343, -4.666, -3.456 + 5710.844, -4.998, -3.835 + 5740.499, -5.593, -4.217 + 5770.307, -6.404, -4.443 + 5800.270, -7.202, -4.380 + 5830.389, -7.699, -4.204 + 5860.664, -7.679, -4.240 + 5891.096, -7.167, -4.652 + 5921.686, -6.465, -5.360 + 5952.435, -6.012, -6.068 + 5983.344, -6.175, -6.427 + 6014.413, -7.093, -6.494 + 6045.644, -8.490, -6.699 + 6077.037, -9.407, -7.254 + 6108.593, -9.036, -7.923 + 6140.312, -8.078, -8.234 + 6172.197, -7.434, -8.040 + 6204.247, -7.359, -7.681 + 6236.463, -7.728, -7.472 + 6268.847, -8.259, -7.460 + 6301.399, -8.740, -7.533 + 6334.119, -9.255, -7.542 + 6367.010, -10.077, -7.421 + 6400.072, -11.221, -7.290 + 6433.305, -12.171, -7.449 + 6466.711, -12.438, -8.167 + 6500.290, -12.441, -9.431 + 6534.043, -12.716, -10.924 + 6567.972, -13.375, -12.318 + 6602.077, -14.522, -13.594 + 6636.360, -16.291, -14.726 + 6670.820, -18.101, -15.238 + 6705.459, -18.039, -15.202 + 6740.278, -16.402, -15.660 + 6775.278, -15.051, -17.365 + 6810.459, -14.271, -20.048 + 6845.823, -13.987, -21.818 + 6881.371, -14.444, -21.562 + 6917.104, -16.046, -20.989 + 6953.022, -18.976, -20.814 + 6989.126, -21.513, -20.848 + 7025.418, -19.935, -20.559 + 7061.898, -17.556, -19.332 + 7098.568, -16.478, -17.667 + 7135.428, -16.342, -16.496 + 7172.480, -16.694, -16.255 + 7209.724, -17.631, -16.975 + 7247.162, -19.119, -18.228 + 7284.793, -20.456, -19.398 + 7322.621, -20.687, -20.406 + 7360.644, -19.696, -21.304 + 7398.865, -18.155, -20.938 + 7437.285, -16.363, -18.936 + 7475.904, -15.019, -16.690 + 7514.724, -14.858, -15.023 + 7553.745, -15.810, -14.036 + 7592.969, -17.228, -13.553 + 7632.396, -17.894, -13.531 + 7672.028, -17.607, -13.920 + 7711.866, -17.483, -14.575 + 7751.911, -17.746, -15.310 + 7792.164, -17.784, -15.947 + 7832.626, -17.193, -16.403 + 7873.298, -16.241, -16.281 + 7914.181, -15.411, -15.424 + 7955.276, -15.321, -14.933 + 7996.585, -16.266, -15.499 + 8038.109, -17.631, -16.236 + 8079.847, -18.283, -16.140 + 8121.803, -18.228, -15.764 + 8163.977, -18.534, -15.990 + 8206.369, -19.440, -16.806 + 8248.982, -20.279, -17.370 + 8291.816, -21.029, -17.339 + 8334.872, -21.487, -16.961 + 8378.152, -20.743, -15.922 + 8421.657, -20.368, -15.269 + 8465.387, -22.097, -16.216 + 8509.345, -24.351, -17.655 + 8553.531, -25.517, -18.692 + 8597.946, -27.087, -20.607 + 8642.592, -27.679, -22.159 + 8687.470, -27.150, -21.397 + 8732.581, -28.437, -20.818 + 8777.926, -31.018, -21.232 + 8823.506, -33.644, -22.472 + 8869.323, -34.609, -24.474 + 8915.379, -33.982, -25.161 + 8961.673, -33.633, -25.372 + 9008.208, -33.089, -26.322 + 9054.984, -35.767, -28.407 + 9102.003, -41.735, -32.372 + 9149.266, -34.312, -33.912 + 9196.775, -32.116, -31.573 + 9244.531, -32.322, -29.695 + 9292.534, -35.271, -27.913 + 9340.787, -40.656, -27.612 + 9389.290, -43.153, -29.349 + 9438.045, -39.375, -30.869 + 9487.053, -32.993, -29.169 + 9536.316, -28.298, -30.903 + 9585.835, -25.244, -35.381 + 9635.610, -25.701, -35.362 + 9685.645, -26.142, -32.926 + 9735.939, -25.770, -30.588 + 9786.494, -27.603, -29.455 + 9837.311, -28.201, -30.668 + 9888.393, -26.653, -32.910 + 9939.740, -25.131, -34.270 + 9991.353, -24.468, -35.300 + 10043.235, -23.680, -30.777 + 10095.385, -24.079, -28.870 + 10147.807, -24.705, -27.825 + 10200.501, -21.853, -24.193 + 10253.468, -19.870, -20.828 + 10306.711, -20.054, -19.489 + 10360.230, -18.561, -19.124 + 10414.026, -16.977, -19.539 + 10468.103, -18.750, -22.053 + 10522.460, -19.384, -22.842 + 10577.099, -16.125, -20.135 + 10632.022, -14.385, -19.305 + 10687.230, -13.973, -19.471 + 10742.725, -13.647, -18.969 + 10798.508, -14.294, -19.198 + 10854.581, -14.520, -19.317 + 10910.944, -13.225, -18.710 + 10967.601, -12.438, -18.775 + 11024.552, -12.464, -19.154 + 11081.798, -12.716, -18.998 + 11139.342, -13.167, -18.335 + 11197.184, -13.560, -17.458 + 11255.327, -11.920, -15.783 + 11313.772, -10.510, -14.429 + 11372.520, -10.493, -13.845 + 11431.573, -10.929, -13.800 + 11490.933, -10.800, -13.789 + 11550.601, -11.014, -14.439 + 11610.579, -11.331, -14.387 + 11670.869, -11.260, -14.252 + 11731.471, -10.606, -13.932 + 11792.389, -10.766, -13.623 + 11853.622, -12.072, -13.561 + 11915.174, -13.699, -14.575 + 11977.045, -13.911, -14.760 + 12039.237, -13.612, -13.833 + 12101.752, -14.254, -15.248 + 12164.592, -14.255, -16.082 + 12227.759, -15.246, -15.230 + 12291.253, -17.082, -15.578 + 12355.077, -17.119, -16.278 + 12419.232, -18.754, -17.374 + 12483.721, -20.074, -18.117 + 12548.544, -19.721, -17.465 + 12613.704, -22.686, -17.832 + 12679.202, -21.220, -19.830 + 12745.041, -19.104, -21.238 + 12811.221, -19.327, -23.423 + 12877.745, -18.651, -29.805 + 12944.614, -17.624, -25.798 + 13011.831, -18.196, -21.551 + 13079.397, -18.380, -19.626 + 13147.313, -17.632, -19.430 + 13215.582, -17.013, -20.859 + 13284.206, -15.295, -20.423 + 13353.186, -14.005, -18.827 + 13422.524, -13.332, -18.428 + 13492.222, -14.533, -18.642 + 13562.282, -14.689, -17.755 + 13632.706, -13.633, -17.931 + 13703.496, -13.694, -17.529 + 13774.653, -14.440, -17.448 + 13846.180, -15.071, -18.632 + 13918.078, -15.652, -19.169 + 13990.349, -15.433, -18.595 + 14062.996, -15.518, -17.754 + 14136.020, -15.975, -16.881 + 14209.423, -15.197, -15.931 + 14283.207, -15.387, -16.473 + 14357.375, -16.436, -17.261 + 14431.927, -17.499, -17.709 + 14506.867, -17.735, -17.362 + 14582.196, -18.070, -17.592 + 14657.916, -17.755, -17.638 + 14734.029, -18.716, -17.712 + 14810.537, -18.667, -18.692 + 14887.443, -18.899, -21.009 + 14964.748, -19.456, -21.171 + 15042.454, -20.952, -21.413 + 15120.564, -21.670, -21.334 + 15199.080, -21.980, -22.066 + 15278.003, -25.323, -23.947 + 15357.336, -26.823, -24.928 + 15437.081, -25.991, -27.074 + 15517.240, -27.629, -30.389 + 15597.815, -30.773, -32.039 + 15678.809, -35.757, -31.495 + 15760.223, -29.072, -31.792 + 15842.060, -28.077, -35.229 + 15924.322, -27.585, -42.646 + 16007.012, -25.155, -34.823 + 16090.130, -25.171, -32.693 + 16173.680, -25.795, -32.305 + 16257.664, -25.643, -31.496 + 16342.084, -25.355, -32.089 + 16426.943, -25.736, -31.500 + 16512.242, -26.246, -30.598 + 16597.984, -25.192, -29.239 + 16684.171, -27.304, -30.238 + 16770.806, -28.107, -31.071 + 16857.890, -27.198, -30.781 + 16945.427, -27.967, -33.128 + 17033.418, -29.094, -33.147 + 17121.867, -30.431, -33.102 + 17210.774, -32.619, -34.209 + 17300.143, -34.268, -35.872 + 17389.977, -34.497, -36.592 + 17480.276, -31.588, -34.715 + 17571.045, -37.675, -40.715 + 17662.285, -37.569, -39.255 + 17753.999, -42.735, -42.000 + 17846.189, -49.213, -49.727 + 17938.857, -47.611, -50.239 + 18032.007, -45.206, -42.393 + 18125.641, -51.820, -50.161 + 18219.761, -55.094, -53.106 + 18314.369, -52.647, -50.265 + 18409.469, -53.595, -49.285 + 18505.062, -49.637, -61.368 + 18601.152, -52.866, -55.880 + 18697.741, -44.759, -50.507 + 18794.832, -43.593, -55.002 + 18892.426, -42.729, -53.713 + 18990.528, -42.671, -50.713 + 19089.139, -40.584, -49.937 + 19188.261, -34.787, -43.509 + 19287.899, -41.757, -48.445 + 19388.054, -32.058, -42.623 + 19488.729, -31.664, -39.266 + 19589.927, -31.893, -36.969 + 19691.650, -30.779, -35.801 + 19793.901, -31.022, -36.402 + 19896.684, -32.701, -36.436 + 20000.000, -36.437, -39.544 diff --git a/src/audio/eq_iir/tune/sof_ucm2_eq_example.xlsx b/src/audio/eq_iir/tune/sof_ucm2_eq_example.xlsx new file mode 100644 index 000000000000..6e8ece702ff7 Binary files /dev/null and b/src/audio/eq_iir/tune/sof_ucm2_eq_example.xlsx differ diff --git a/src/audio/eq_iir/tune/sof_ucm2_eq_generate.m b/src/audio/eq_iir/tune/sof_ucm2_eq_generate.m new file mode 100644 index 000000000000..131ca99ed99e --- /dev/null +++ b/src/audio/eq_iir/tune/sof_ucm2_eq_generate.m @@ -0,0 +1,510 @@ +function sof_ucm2_eq_generate(sys_vendor, product_name, endpoint, meas_file) + +% SOF_UCM2_EQ_GENERATE Fit IIR + FIR endpoint EQ from a measurement. +% +% sof_ucm2_eq_generate(SYS_VENDOR, PRODUCT_NAME, ENDPOINT, MEAS_FILE) +% +% SYS_VENDOR DMI /sys/devices/virtual/dmi/id/sys_vendor value, e.g. +% 'Acme Ltd.'. Kept verbatim (with spaces and case) for the +% product_configs directory name. +% PRODUCT_NAME DMI product_name value, e.g. 'Model 100'. Kept +% verbatim for the .conf file name. +% ENDPOINT Endpoint being tuned, e.g. 'speaker' or 'headphone'. Used +% lower case in blob file names and capitalized in the +% Define.PostMixerPlayback... UCM keys. +% MEAS_FILE Path to a comma separated numbers text file whose first +% column is the measurement frequency in Hz and whose +% remaining columns are one or more measured magnitude +% traces in dB. Multiple traces are averaged. +% Such a file can be produced with sof_mls_freq_resp.m. +% Excel workbooks (.xls, .xlsx, .xlsm) and OpenDocument +% spreadsheets (.ods) are also accepted; the format is +% detected from the file extension and imported via +% xlsread from the Octave 'io' package. The workbook +% is expected to contain the same [freq, resp...] numeric +% layout with no header row, matching +% sof_ucm2_eq_example.xlsx. +% +% The binary IIR and FIR blobs consumed by UCM are written to +% ./ucm2_blobs_sof/ipc4/eq_iir/___iir.bin +% ./ucm2_blobs_sof/ipc4/eq_fir/___fir.bin +% +% The matching sof-ctl text dumps for manual testing are written under +% the SOF source tree (independent of the caller's current directory): +% /tools/ctl/ipc4/eq_iir/___iir.txt +% /tools/ctl/ipc4/eq_fir/___fir.txt +% +% and a UCM include file that will be picked up automatically by UCM is +% written to +% ./ucm2_blobs_sof/product_configs//.conf +% +% Run this to see a design example and produced configuration for ALSA UCMv2 +% sof_ucm2_eq_generate('example', 'example', 'speaker', 'sof_ucm2_eq_example.txt'); +% or +% sof_ucm2_eq_generate('example', 'example', 'speaker', 'sof_ucm2_eq_example.xlsx'); + +% SPDX-License-Identifier: BSD-3-Clause +% +% Copyright (c) 2026, Intel Corporation. + +if nargin < 4 + help sof_ucm2_eq_generate + printf('\n'); + error('Usage: sof_ucm2_eq_generate(sys_vendor, product_name, endpoint, meas_file)'); +end + +%% Validate DMI and endpoint inputs before they are used to build any +%% path or UCM key. sys_vendor and product_name are kept verbatim as +%% directory / file name components under product_configs/, so they must +%% not contain path separators or traversal segments. endpoint is +%% capitalized and dropped into Define.PostMixerPlayback... +%% keys, so it has to be a plain letter identifier. +validate_dmi_field('sys_vendor', sys_vendor); +validate_dmi_field('product_name', product_name); +validate_endpoint(endpoint); + +%% Load the signal package up front so the script fails cleanly on a +%% system missing it, before any output directories are created. The io +%% package is only pulled in when the measurement file is a spreadsheet +%% (see load_measurement below), so text-only users do not need it. +pkg load signal; + +%% Derive blob base name and output paths from the DMI info + endpoint. +%% The binary blobs go into a UCM-shaped staging tree (ucm2_blobs_sof/) +%% that mirrors the alsa-ucm-conf layout. The sof-ctl text dumps go into +%% the regular tools/ctl/ipc4/eq_{iir,fir}/ locations so they can be used +%% for manual testing with sof-ctl the same way as the other tune scripts; +%% UCM itself does not consume these .txt files. The tools/ctl path is +%% derived from the location of this script so it works regardless of the +%% caller's current directory. +endpoint_lc = lower(endpoint); +base = sprintf('%s_%s_%s', endpoint_lc, ... + sanitize_name('sys_vendor', sys_vendor), ... + sanitize_name('product_name', product_name)); +out_root = 'ucm2_blobs_sof'; +cpath4 = fullfile(out_root, 'ipc4'); +iir_bin = fullfile('eq_iir', [base '_iir.bin']); +fir_bin = fullfile('eq_fir', [base '_fir.bin']); +conf_dir = fullfile(out_root, 'product_configs', sys_vendor); +conf_file = fullfile(conf_dir, [product_name '.conf']); +ensure_dir(fullfile(cpath4, 'eq_iir')); +ensure_dir(fullfile(cpath4, 'eq_fir')); +ensure_dir(conf_dir); + +script_dir = fileparts(mfilename('fullpath')); +ctl_root = fullfile(script_dir, '..', '..', '..', '..', 'tools', 'ctl', 'ipc4'); +ctl_iir_dir = fullfile(ctl_root, 'eq_iir'); +ctl_fir_dir = fullfile(ctl_root, 'eq_fir'); +ensure_dir(ctl_iir_dir); +ensure_dir(ctl_fir_dir); +iir_txt = fullfile(ctl_iir_dir, [base '_iir.txt']); +fir_txt = fullfile(ctl_fir_dir, [base '_fir.txt']); + +enable_common_paths(script_dir, true); + +%% Base equalizer setup +eq = sof_eq_defaults(); +eq.fs = 48e3; +eq.logsmooth_plot = 1.0; +eq.logsmooth_eq = 1.0; +eq.enable_iir = 1; +eq.enable_fir = 1; +eq.iir_norm_type = 'loudness'; +eq.iir_norm_offs_db = -1; +eq.fir_norm_type = 'loudness'; +eq.fir_norm_offs_db = -1; +eq.p_fmin = 20; +eq.p_fmax = 20e3; + +%% Parametric target: keep the corrected response band-limited so the fit +%% does not chase noise below 80 Hz (below the speaker's useful range) or +%% brighten the top octave. HP2 80 Hz rolls off sub-bass in the target, +%% LP2 10 kHz tames the highs. Both the IIR stage fit (stage_rms) and the +%% FIR design in sof_eq_compute honor eq.t_db that this generates. +eq.parametric_target_response = [ ... + eq.PEQ_HP2 80 0 0; ... + eq.PEQ_LP2 10000 0 0; ... +]; + +%% Load measurement, fit IIR + FIR, compute the final response and export +eq = load_measurement(eq, meas_file); +eq = design_iir_stages(eq); +eq = configure_fir(eq); +eq = sof_eq_compute(eq); +sof_eq_plot(eq, 1); +export_blobs(eq, cpath4, iir_txt, iir_bin, fir_txt, fir_bin); +write_product_conf(conf_file, sys_vendor, product_name, endpoint, base, eq); + +enable_common_paths(script_dir, false); + +printf('\n'); +printf('To install these blobs into alsa-ucm-conf, copy the contents of\n'); +printf('%s/ recursively into alsa-ucm-conf/ucm2/blobs/sof:\n', out_root); +printf(' cp -r %s/* /ucm2/blobs/sof/\n', out_root); +printf('sof-ctl text dumps written under tools/ctl/ipc4/eq_{iir,fir}/.\n'); + +end + +%% ----------------------------------------------------------------------- +%% Measurement loading +%% ----------------------------------------------------------------------- +function eq = load_measurement(eq, meas_file) +if ~exist(meas_file, 'file') + error('Measurement file not found: %s', meas_file); +end +[~, ~, ext] = fileparts(meas_file); +switch lower(ext) +case {'.xls', '.xlsx', '.xlsm', '.ods'} + pkg load io; + meas = xlsread(meas_file); +otherwise + %% dlmread with no explicit delimiter auto-detects whitespace or + %% comma separation, which covers both the sof_mls_freq_resp.m + %% output and legacy whitespace-delimited measurement files. + meas = dlmread(meas_file); +end +if size(meas, 2) < 2 + error('%s must have at least a frequency column and one response column', ... + meas_file); +end +eq.raw_f = meas(:,1); +if size(meas, 2) == 2 + eq.raw_m_db = meas(:,2); +else + %% Average of the response columns + eq.raw_m_db = mean(meas(:, 2:end), 2); + fprintf('Averaged %d response columns from %s\n', size(meas, 2) - 1, meas_file); +end +end + +%% ----------------------------------------------------------------------- +%% Multi-stage IIR fit +%% ----------------------------------------------------------------------- +function eq = design_iir_stages(eq) + +%% Cap on the combined response shaping between the mid PN2 (stage 1) and +% the bass LS2 (stage 2). If stage 1 pulls the mids down by A dB, the +% LS2 upper bound is reduced so that bass_boost + |mid_atten| does not +% exceed this limit. This keeps the bass-to-mid tilt from becoming +% excessive (e.g. 26 dB total is already an aggressive shape). +max_bass_plus_mid_atten_db = 26; + +%% Filter budget (4 biquads max): +% 1) HP2 at 80 Hz to protect the speaker +% 2) PN2 mid shaper -> fc [2000, 4000], gain [-12, +6], Q [0.5, 1.0] +% 3) LS2 bass boost -> fc [120, 1000], gain [0, +12] +% 4) PN2 fine correction (low band) -> fc [200, 4000], gain [-6, +12], Q [0.5, 1.0] +% Fitting order matters: the mid PN2 is fit first so the subsequent low +% shelf can settle on top of an already-flattened midrange instead of +% chasing a mid bump with bass gain. The remaining high-band correction +% is left to the mid-band FIR that runs after the IIR, which keeps the +% IIR order low and avoids the audible ringing seen with a larger IIR +% budget. +hp_fc = 80; + +opts = optimset('Display', 'notify', 'MaxIter', 300, 'MaxFunEvals', 2000, ... + 'TolX', 1e-3, 'TolFun', 1e-3); + +peq_fixed = [eq.PEQ_HP2, hp_fc, 0, 0]; + +%% Stage 1: fit a mid PN2 peak/notch first, on top of the HP2. Doing this +% before the low shelf keeps the shelf from over-compensating for a +% broad midrange bump. The gain upper bound is kept low (+6 dB) so this +% stage stays a mid *attenuator* rather than a boost. +% Params: [fc, gain, Q]. fc [2000, 4000] Hz, gain [-12, +6] dB, Q [0.5, 1.0]. +fmin_fit = 400; +fmax_fit = 7000; +p1_0 = [2500, -6, 0.6]; +p1_bounds = [2000, 4000; -12, +6; 0.5, 1.0]; +p1 = fminsearch(@(p) stage_rms(peq_fixed, pn_row(p, p1_bounds, eq), eq, fmin_fit, fmax_fit), ... + p1_0, opts); +peq_fixed = [peq_fixed; pn_row(p1, p1_bounds, eq)]; +fprintf('Stage 1 (mid PN2): fc=%.1f Hz g=%.2f dB Q=%.2f\n', ... + clamp(p1(1), p1_bounds(1,1), p1_bounds(1,2)), ... + clamp(p1(2), p1_bounds(2,1), p1_bounds(2,2)), ... + clamp(p1(3), p1_bounds(3,1), p1_bounds(3,2))); + +%% Stage 2: fit the low shelf on top of the flattened midrange. +% Params: [ls_fc, ls_g]. fc [120, 1000] Hz, gain [0, +12] dB. +% The upper bass gain bound is shrunk when stage 1 attenuated the mids, +% so the total bass-to-mid shaping stays within max_bass_plus_mid_atten_db. +fmin_fit = 200; +fmax_fit = 2000; +ls0 = [200, 8]; +ls_bounds = [120, 1000; 0, 12]; +mid_atten_db = min(0, clamp(p1(2), p1_bounds(2,1), p1_bounds(2,2))); +ls_bounds(2,2) = min(ls_bounds(2,2), max(0, max_bass_plus_mid_atten_db - abs(mid_atten_db))); +if ls_bounds(2,2) < ls0(2) + ls0(2) = ls_bounds(2,2); +end +fprintf('Stage 2 bass gain upper bound = %.2f dB (mid atten %.2f dB, cap %.1f dB)\n', ... + ls_bounds(2,2), mid_atten_db, max_bass_plus_mid_atten_db); +ls = fminsearch(@(p) stage_rms(peq_fixed, shelf_row(eq.PEQ_LS2, p, ls_bounds), ... + eq, fmin_fit, fmax_fit), ls0, opts); +peq_fixed = [peq_fixed; shelf_row(eq.PEQ_LS2, ls, ls_bounds)]; +fprintf('Stage 2 (LS2): fc=%.1f Hz g=%.2f dB\n', clamp(ls(1), ls_bounds(1,1), ls_bounds(1,2)), ... + clamp(ls(2), ls_bounds(2,1), ls_bounds(2,2))); + +%% Widen the fit band for the fine correction stage: below 400 Hz the LS2 +% already dominates and above the mid we still want to shape the response +% out to 7 kHz. +fmin_fit = 400; +fmax_fit = 7000; + +%% Stage 3: single fine correction across the low/mid band. The higher +% frequencies are left to the mid-band FIR, so this biquad can focus on +% whatever residual the shelf + mid PN2 left behind. +% Params: [fc, gain, Q]. fc [200, 4000] Hz, gain [-6, +12] dB, Q [0.5, 1.0]. +p2_0 = [800, -3, 1.0]; +p2_bounds = [200, 4000; -6, 12; 0.5, 1.0]; +p2 = fminsearch(@(p) stage_rms(peq_fixed, pn_row(p, p2_bounds, eq), eq, fmin_fit, fmax_fit), ... + p2_0, opts); +peq_fixed = [peq_fixed; pn_row(p2, p2_bounds, eq)]; +fprintf('Stage 3 (fine PN2): fc=%.1f Hz g=%.2f dB Q=%.2f\n', ... + clamp(p2(1), p2_bounds(1,1), p2_bounds(1,2)), ... + clamp(p2(2), p2_bounds(2,1), p2_bounds(2,2)), ... + clamp(p2(3), p2_bounds(3,1), p2_bounds(3,2))); + +eq.peq = peq_fixed; +end + +%% ----------------------------------------------------------------------- +%% FIR configuration for mid-band residual correction +%% ----------------------------------------------------------------------- +function eq = configure_fir(eq) +%% The IIR takes care of the coarse bass shelf plus two low/mid PN2 +% shapers. Whatever residual vs. the target is left after the IIR +% (fir_compensate_iir = 1 in the defaults) is picked up here by a short +% minimum-phase FIR limited to [fmin_fir, fmax_fir], so it does not +% spend taps on the LF/HF regions the IIR already handles or where the +% measurement is unreliable. +eq.fir_length = 63; +eq.fir_beta = 10; +eq.fir_minph = 1; +eq.fir_autoband = 0; +eq.fmin_fir = 400; +eq.fmax_fir = 7000; +fprintf('FIR: length=%d taps, mid band [%d, %d] Hz\n', ... + eq.fir_length, eq.fmin_fir, eq.fmax_fir); +end + +%% ----------------------------------------------------------------------- +%% IIR + FIR blob packing and export +%% ----------------------------------------------------------------------- +function export_blobs(eq, cpath, iir_txt, iir_bin, fir_txt, fir_bin) +%% Two-channel blob with a single shared response. Both channels are +%% assigned to response 0, which suits identical L/R drivers on a +%% single endpoint. For endpoints with distinct per-channel tuning, +%% pass num_responses > 1 and adjust assign_response accordingly. +%% +%% iir_bin / fir_bin are relative to `cpath` (the UCM staging tree), +%% iir_txt / fir_txt are full paths to the sof-ctl text dumps under +%% tools/ctl/ipc4/eq_{iir,fir}/ and are written as-is. +channels_in_config = 2; +num_responses = 1; +assign_response = [0 0]; + +%% IIR blob +bq_iir = sof_eq_iir_blob_quant(eq.p_z, eq.p_p, eq.p_k); +bm_iir = sof_eq_iir_blob_merge(channels_in_config, num_responses, ... + assign_response, bq_iir); +bp_iir = sof_eq_iir_blob_pack(bm_iir, 4); % IPC4 +sof_alsactl_write(iir_txt, bp_iir); +sof_ucm_blob_write(fullfile(cpath, iir_bin), bp_iir); + +%% FIR blob +bq_fir = sof_eq_fir_blob_quant(eq.b_fir); +bm_fir = sof_eq_fir_blob_merge(channels_in_config, num_responses, ... + assign_response, bq_fir); +bp_fir = sof_eq_fir_blob_pack(bm_fir, 4); % IPC4 +sof_alsactl_write(fir_txt, bp_fir); +sof_ucm_blob_write(fullfile(cpath, fir_bin), bp_fir); +end + +%% ----------------------------------------------------------------------- +%% Small helpers used by the IIR stages +%% ----------------------------------------------------------------------- +function peq = shelf_row(type, p, b) +peq = [type, clamp(p(1), b(1,1), b(1,2)), clamp(p(2), b(2,1), b(2,2)), 0]; +end + +function peq = pn_row(p, b, eq) +peq = [eq.PEQ_PN2, clamp(p(1), b(1,1), b(1,2)), ... + clamp(p(2), b(2,1), b(2,2)), ... + clamp(p(3), b(3,1), b(3,2))]; +end + +function e = stage_rms(peq_fixed, new_row, eq, fmin_fit, fmax_fit) +eq.peq = [peq_fixed; new_row]; +%% Skip the FIR design pass on every fminsearch evaluation. The stage +%% objective below only looks at eq.err_db_s and eq.iir_eq_db, which +%% sof_eq_compute produces before the FIR stage, so designing the FIR +%% here would just be wasted work inside the optimization loop. +eq.enable_fir = 0; +try + eq2 = sof_eq_compute(eq); +catch + e = 1e6; + return; +end +idx = eq2.f >= fmin_fit & eq2.f <= fmax_fit; +%% eq.err_db_s is the eq-smoothed (logsmooth_eq) target-minus-measurement +%% error the FIR will pick up. What remains for the FIR after the IIR is +%% err_db_s - iir_eq_db, so minimizing its shape here fits the IIR against +%% the same signal the FIR design consumes and applies logsmooth_eq (not +%% the plot-only logsmooth_plot). +residual = eq2.err_db_s(idx) - eq2.iir_eq_db(idx); +residual = residual - mean(residual); +e = sqrt(mean(residual .^ 2)); +end + +function y = clamp(x, lo, hi) +y = min(hi, max(lo, x)); +end + +%% ----------------------------------------------------------------------- +%% UCM product .conf generation and misc string / filesystem helpers +%% ----------------------------------------------------------------------- +function write_product_conf(conf_file, sys_vendor, product_name, endpoint, base, eq) +ep_cap = capitalize(endpoint); +iir_key = sprintf('Define.PostMixer%sPlaybackIirBlob', ep_cap); +fir_key = sprintf('Define.PostMixer%sPlaybackFirBlob', ep_cap); +iir_path = sprintf('/usr/share/alsa/ucm2/blobs/sof/ipc4/eq_iir/%s_iir.bin', base); +fir_path = sprintf('/usr/share/alsa/ucm2/blobs/sof/ipc4/eq_fir/%s_fir.bin', base); + +fid = fopen(conf_file, 'w'); +if fid < 0 + error('Could not open %s for writing', conf_file); +end +fprintf(fid, '# Add bespoke %s equalizer for %s %s\n', endpoint, sys_vendor, product_name); +fprintf(fid, '#\n'); +fprintf(fid, '# This file was generated with %s.m\n', mfilename()); +fprintf(fid, '#\n'); +fprintf(fid, '# IIR is defined as parametric equalizer and FIR carries the mid-band residual\n'); +fprintf(fid, '# correction, see:\n'); +fprintf(fid, '# https://github.com/thesofproject/sof/tree/main/src/audio/eq_iir/tune\n'); +fprintf(fid, '#\n'); +fprintf(fid, '# IIR biquad stages:\n'); +fprintf(fid, '# type fc [Hz] gain [dB] Q\n'); +for i = 1:size(eq.peq, 1) + fprintf(fid, '# %-4s %8.1f %+6.2f %5.2f\n', ... + peq_short_name(eq, eq.peq(i, 1)), ... + eq.peq(i, 2), eq.peq(i, 3), eq.peq(i, 4)); +end +fprintf(fid, '#\n'); +fprintf(fid, '# FIR parameters:\n'); +fprintf(fid, '# length = %d taps\n', eq.fir_length); +fprintf(fid, '# kaiser beta = %g\n', eq.fir_beta); +fprintf(fid, '# minph = %d\n', eq.fir_minph); +fprintf(fid, '# band = [%g, %g] Hz\n', eq.fmin_fir, eq.fmax_fir); +fprintf(fid, '\n'); +fprintf(fid, '%s "%s"\n', iir_key, iir_path); +fprintf(fid, '%s "%s"\n', fir_key, fir_path); +fclose(fid); +fprintf('Wrote %s\n', conf_file); +end + +function s = sanitize_name(field_name, s) +% Lower case, replace any non-alphanumeric run with a single underscore, and +% trim leading/trailing underscores. e.g. 'Acme Ltd.' -> 'acme_ltd', +% 'Model 100' -> 'model_100'. +% +% Error out if the result is empty (input had no ASCII letters or digits, +% e.g. a non-ASCII-only DMI value). Otherwise the blob base name would +% collapse to something like 'speaker__' and every product with such a +% DMI value would land on the same blob path. +raw = s; +s = lower(s); +s = regexprep(s, '[^a-z0-9]+', '_'); +s = regexprep(s, '^_+|_+$', ''); +if isempty(s) + error(['%s "%s" has no ASCII letters or digits and would produce ' ... + 'an empty blob name component; please pass a value that ' ... + 'contains at least one [a-z0-9] character.'], field_name, raw); +end +end + +function validate_dmi_field(field_name, s) +% Reject DMI values that would escape the output tree or otherwise produce +% a bad directory / file name when used verbatim. Path separators and the +% special names '.' and '..' are refused; any other printable UTF-8 string +% is accepted because DMI content is noisy in the wild. +if ~ischar(s) || isempty(s) + error('%s must be a non-empty string', field_name); +end +if any(s == '/') || any(s == '\') + error('%s must not contain path separators: "%s"', field_name, s); +end +if strcmp(s, '.') || strcmp(s, '..') + error('%s must not be "." or "..": "%s"', field_name, s); +end +if any(s < 32) + error('%s must not contain control characters', field_name); +end +end + +function validate_endpoint(s) +% endpoint becomes part of the UCM key Define.PostMixerPlayback... +% and a component of blob file names, so restrict it to a plain letters-only +% identifier. Extend the pattern here if a new endpoint naming scheme is +% needed. +if ~ischar(s) || isempty(s) + error('endpoint must be a non-empty string'); +end +if isempty(regexp(s, '^[A-Za-z]+$', 'once')) + error('endpoint must be letters only (e.g. speaker, headphone): "%s"', s); +end +end + +function s = capitalize(s) +if isempty(s) + return; +end +s = [upper(s(1)), lower(s(2:end))]; +end + +function ensure_dir(d) +if ~exist(d, 'dir') + [ok, msg] = mkdir(d); + if ~ok + error('mkdir %s failed: %s', d, msg); + end +end +end + +function enable_common_paths(script_dir, enable) +% sof_eq_paths() addpath/rmpaths a relative '../../../../tools/tune/common' +% that is resolved against the current working directory, so it only works +% when called from src/audio/eq_iir/tune/. Do a scoped cd to script_dir so +% the (dis)enable resolves correctly regardless of the caller's CWD. +% onCleanup restores the original directory even if sof_eq_paths errors. +orig_dir = pwd(); +cleanup = onCleanup(@() cd(orig_dir)); %#ok +cd(script_dir); +sof_eq_paths(enable); +end + +function name = peq_type_name(eq, type_num) +% Look up the PEQ_* field name whose value matches type_num, using the +% constants that sof_eq_defaults() already stored on the eq struct. This +% keeps the mapping in sync with sof_eq_define_parametric_eq.m without +% duplicating the enum here. +fns = fieldnames(eq); +for k = 1:numel(fns) + if strncmp(fns{k}, 'PEQ_', 4) && isnumeric(eq.(fns{k})) && ... + isscalar(eq.(fns{k})) && eq.(fns{k}) == type_num + name = fns{k}; + return; + end +end +name = sprintf('PEQ_%d', type_num); +end + +function name = peq_short_name(eq, type_num) +% Same lookup as peq_type_name but with the 'PEQ_' prefix stripped, e.g. +% 'HP2' or 'LS2', for compact human-readable summaries in the .conf header. +name = peq_type_name(eq, type_num); +if strncmp(name, 'PEQ_', 4) + name = name(5:end); +end +end