ffdshow_decoder.cpp (8905B)
1 /* 2 * Copyright (c) 2004-2006 Milan Cutka 3 * based on mplayer HRTF plugin by ylai 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 #include "ffdshow_decoder.hpp" 21 22 #include "firfilter.hpp" 23 24 #include <cmath> 25 #include <cstring> 26 27 float FfdshowDecoder::passive_lock(float x) 28 { 29 static const float MATAGCLOCK = 0.2f; /* AGC range (around 1) where the matrix behaves passively */ 30 const float x1 = x - 1; 31 const float ax1s = fabs(x - 1) * (1.0f / MATAGCLOCK); 32 return x1 - x1 / (1 + ax1s * ax1s) + 1; 33 } 34 35 void FfdshowDecoder::matrix_decode(const float *in, const int k, const int il, 36 const int ir, bool decode_rear, 37 const int dlbuflen, 38 float l_fwr, float r_fwr, 39 float lpr_fwr, float lmr_fwr, 40 float *adapt_l_gain, float *adapt_r_gain, 41 float *adapt_lpr_gain, float *adapt_lmr_gain, 42 float *lf, float *rf, float *lr, 43 float *rr, float *cf) const 44 { 45 static const float M9_03DB = 0.3535533906f; 46 static const float MATAGCTRIG = 8.0f; /* (Fuzzy) AGC trigger */ 47 static const float MATAGCDECAY = 1.0f; /* AGC baseline decay rate (1/samp.) */ 48 static const float MATCOMPGAIN = 0.37f; /* Cross talk compensation gain, 0.50 - 0.55 is full cancellation. */ 49 50 const int kr = k % dlbuflen; 51 float l_gain = (l_fwr + r_fwr) / (1 + l_fwr + l_fwr); 52 float r_gain = (l_fwr + r_fwr) / (1 + r_fwr + r_fwr); 53 /* The 2nd axis has strong gain fluctuations, and therefore require 54 limits. The factor corresponds to the 1 / amplification of (Lt 55 - Rt) when (Lt, Rt) is strongly correlated. (e.g. during 56 dialogues). It should be bigger than -12 dB to prevent 57 distortion. */ 58 float lmr_lim_fwr = lmr_fwr > M9_03DB * lpr_fwr ? lmr_fwr : M9_03DB * lpr_fwr; 59 float lpr_gain = (lpr_fwr + lmr_lim_fwr) / (1 + lpr_fwr + lpr_fwr); 60 float lmr_gain = (lpr_fwr + lmr_lim_fwr) / (1 + lmr_lim_fwr + lmr_lim_fwr); 61 float lmr_unlim_gain = (lpr_fwr + lmr_fwr) / (1 + lmr_fwr + lmr_fwr); 62 float lpr, lmr; 63 float l_agc, r_agc, lpr_agc, lmr_agc; 64 float f, d_gain, c_gain, c_agc_cfk; 65 66 /*** AXIS NO. 1: (Lt, Rt) -> (C, Ls, Rs) ***/ 67 /* AGC adaption */ 68 d_gain = (fabs(l_gain - *adapt_l_gain) + fabs(r_gain - *adapt_r_gain)) * 0.5f; 69 f = d_gain * (1.0f / MATAGCTRIG); 70 f = MATAGCDECAY - MATAGCDECAY / (1 + f * f); 71 *adapt_l_gain = (1 - f) * *adapt_l_gain + f * l_gain; 72 *adapt_r_gain = (1 - f) * *adapt_r_gain + f * r_gain; 73 /* Matrix */ 74 l_agc = in[il] * passive_lock(*adapt_l_gain); 75 r_agc = in[ir] * passive_lock(*adapt_r_gain); 76 cf[k] = (l_agc + r_agc) * (float)M_SQRT1_2; 77 if (decode_rear) { 78 lr[kr] = rr[kr] = (l_agc - r_agc) * (float)M_SQRT1_2; 79 /* Stereo rear channel is steered with the same AGC steering as 80 the decoding matrix. Note this requires a fast updating AGC 81 at the order of 20 ms (which is the case here). */ 82 lr[kr] *= (l_fwr + l_fwr) / (1 + l_fwr + r_fwr); 83 rr[kr] *= (r_fwr + r_fwr) / (1 + l_fwr + r_fwr); 84 } 85 86 /*** AXIS NO. 2: (Lt + Rt, Lt - Rt) -> (L, R) ***/ 87 lpr = (in[il] + in[ir]) * (float)M_SQRT1_2; 88 lmr = (in[il] - in[ir]) * (float)M_SQRT1_2; 89 /* AGC adaption */ 90 d_gain = fabs(lmr_unlim_gain - *adapt_lmr_gain); 91 f = d_gain * (1.0f / MATAGCTRIG); 92 f = MATAGCDECAY - MATAGCDECAY / (1 + f * f); 93 *adapt_lpr_gain = (1 - f) * *adapt_lpr_gain + f * lpr_gain; 94 *adapt_lmr_gain = (1 - f) * *adapt_lmr_gain + f * lmr_gain; 95 /* Matrix */ 96 lpr_agc = lpr * passive_lock(*adapt_lpr_gain); 97 lmr_agc = lmr * passive_lock(*adapt_lmr_gain); 98 lf[k] = (lpr_agc + lmr_agc) * (float)M_SQRT1_2; 99 rf[k] = (lpr_agc - lmr_agc) * (float)M_SQRT1_2; 100 101 /*** CENTER FRONT CANCELLATION ***/ 102 /* A heuristic approach exploits that Lt + Rt gain contains the 103 information about Lt, Rt correlation. This effectively reshapes 104 the front and rear "cones" to concentrate Lt + Rt to C and 105 introduce Lt - Rt in L, R. */ 106 /* 0.67677 is the empirical lower bound for lpr_gain. */ 107 c_gain = 8 * (*adapt_lpr_gain - 0.67677f); 108 c_gain = c_gain > 0 ? c_gain : 0; 109 /* c_gain should not be too high, not even reaching full 110 cancellation (~ 0.50 - 0.55 at current AGC implementation), or 111 the center will sound too narrow. */ 112 c_gain = MATCOMPGAIN / (1 + c_gain * c_gain); 113 c_agc_cfk = c_gain * cf[k]; 114 lf[k] -= c_agc_cfk; 115 rf[k] -= c_agc_cfk; 116 cf[k] += c_agc_cfk + c_agc_cfk; 117 } 118 119 std::unique_ptr<float[]> FfdshowDecoder::calc_coefficients_125Hz_lowpass() 120 { 121 len125 = 256; 122 float f = rate * (125.0f / 2); 123 std::unique_ptr<float[]> coeffs{TfirFilter::design_fir( 124 &len125, &f, TfirFilter::Type::LOWPASS, TfirFilter::Window::HAMMING, 0)}; 125 static const float M3_01DB = 0.7071067812f; 126 for (unsigned int i = 0; i < len125; i++) { 127 coeffs[i] *= M3_01DB; 128 } 129 return coeffs; 130 } 131 132 static const unsigned int FWRDURATION = 240; /* FWR average duration (samples) */ 133 134 std::span<const float> FfdshowDecoder::Decode(std::span<const float> input) 135 { 136 constexpr unsigned out_channels = 6; 137 138 const float* in = input.data(); // Input audio data 139 const float* end = in + input.size(); // Loop end 140 out_buf.resize(out_channels * (input.size() / 2)); 141 float* out = out_buf.data(); 142 while (in < end) { 143 const int k = cyc_pos; 144 145 const int fwr_pos = (k + FWRDURATION) % dlbuflen; 146 /* Update the full wave rectified total amplitude */ 147 /* Input matrix decoder */ 148 l_fwr += fabs(in[0]) - fabs(fwrbuf_l[fwr_pos]); 149 r_fwr += fabs(in[1]) - fabs(fwrbuf_r[fwr_pos]); 150 lpr_fwr += fabs(in[0] + in[1]) - fabs(fwrbuf_l[fwr_pos] + fwrbuf_r[fwr_pos]); 151 lmr_fwr += fabs(in[0] - in[1]) - fabs(fwrbuf_l[fwr_pos] - fwrbuf_r[fwr_pos]); 152 153 /* Matrix encoded 2 channel sources */ 154 fwrbuf_l[k] = in[0]; 155 fwrbuf_r[k] = in[1]; 156 matrix_decode(in, k, 0, 1, true, dlbuflen, 157 l_fwr, r_fwr, 158 lpr_fwr, lmr_fwr, 159 &adapt_l_gain, &adapt_r_gain, 160 &adapt_lpr_gain, &adapt_lmr_gain, 161 &lf[0], &rf[0], &lr[0], &rr[0], &cf[0]); 162 163 out[0] = lf[k]; 164 out[1] = rf[k]; 165 out[2] = center_gain * cf[k]; 166 if (enable_lfe) 167 { 168 LFE_buf[lfe_pos] = (out[0] + out[1]) / 2; 169 out[3] = TfirFilter::firfilter( 170 LFE_buf, lfe_pos, len125, len125, filter_coefs_lfe.get()); 171 lfe_pos++; 172 if (lfe_pos == len125) lfe_pos = 0; 173 } 174 else out[3] = 0; 175 out[4] = lr[k]; 176 out[5] = rr[k]; 177 // Next sample... 178 in += 2; 179 out += out_channels; 180 cyc_pos--; 181 if (cyc_pos < 0) { 182 cyc_pos += dlbuflen; 183 } 184 } 185 186 return out_buf; 187 } 188 189 void FfdshowDecoder::Init(float rate) 190 { 191 if (rate < 0) return; 192 l_fwr = r_fwr = lpr_fwr = lmr_fwr = 0; 193 std::fill(fwrbuf_l.begin(), fwrbuf_l.end(), 0.0f); 194 std::fill(fwrbuf_r.begin(), fwrbuf_r.end(), 0.0f); 195 adapt_l_gain = adapt_r_gain = adapt_lpr_gain = adapt_lmr_gain = 0; 196 std::fill(lf.begin(), lf.end(), 0.0f); 197 std::fill(rf.begin(), rf.end(), 0.0f); 198 std::fill(lr.begin(), lr.end(), 0.0f); 199 std::fill(rr.begin(), rr.end(), 0.0f); 200 std::fill(cf.begin(), cf.end(), 0.0f); 201 std::fill(cr.begin(), cr.end(), 0.0f); 202 lfe_pos = 0; 203 memset(LFE_buf, 0, sizeof(LFE_buf)); 204 filter_coefs_lfe.reset(); 205 206 this->rate = rate; 207 //dlbuflen = std::max(FWRDURATION, (cfg_delay / rate / 1000)); //+(len7000-1); 208 dlbuflen = FWRDURATION; // TODO delay is always 0 209 cyc_pos = dlbuflen - 1; 210 fwrbuf_l.resize(dlbuflen); 211 fwrbuf_r.resize(dlbuflen); 212 lf.resize(dlbuflen); 213 rf.resize(dlbuflen); 214 lr.resize(dlbuflen); 215 rr.resize(dlbuflen); 216 cf.resize(dlbuflen); 217 cr.resize(dlbuflen); 218 filter_coefs_lfe = calc_coefficients_125Hz_lowpass(); 219 } 220 221 std::vector<Option> FfdshowDecoder::GetOptions() 222 { 223 return { 224 { 225 "enable_lfe", "BOOL", "Enable LFE output (default: true)", 226 [this](std::string_view sv) { enable_lfe = FromString<bool>(sv); }, 227 }, 228 { 229 "center_gain", "FLOAT", "Center gain (default: 1)", 230 [this](std::string_view sv) { center_gain = FromString<float>(sv); }, 231 }, 232 }; 233 } 234 235 std::vector<Channel::E> FfdshowDecoder::GetChannels() 236 { 237 return {Channel::FRONT_LEFT, Channel::FRONT_RIGHT, Channel::FRONT_CENTER, 238 Channel::LFE, Channel::REAR_LEFT, Channel::REAR_RIGHT}; 239 }