|
55 | 55 | //! -TransientFilter[] must be 3 elements in size. Initialize with 0. |
56 | 56 | //! Internal layout is: |
57 | 57 | //! { |
58 | | -//! float EnvGainHP; //! Gain envelope tap for HP filter |
59 | | -//! float EnvGainBP; //! Gain envelope tap for BP filter |
60 | | -//! float EnvPost; //! Post-echo-compensated gain tap |
| 58 | +//! float EnvPostMaskHP; |
| 59 | +//! float EnvPostMaskBP; |
| 60 | +//! float EnvBlockMask; |
61 | 61 | //! } |
62 | 62 | //! -TmpBuffer[] must be BlockSize*2 elements in size. |
63 | 63 | #pragma GCC push_options |
@@ -102,43 +102,69 @@ static inline void Block_Transform_GetWindowCtrl_TransientFiltering( |
102 | 102 | } |
103 | 103 |
|
104 | 104 | //! Model the energy curve and integrate it over each segment |
| 105 | + //! NOTE: All rates were determined experimentally, based on what |
| 106 | + //! resulted in the best sensitivity without excessive glitching. |
105 | 107 | { |
106 | 108 | int i, BinSize = BlockSize / ULC_MAX_BLOCK_DECIMATION_FACTOR; |
107 | | - float EnvGainHP = TransientFilter[0], GainHPRate = expf(-0x1.5A92D6p2f / RateHz); //! -0.047dB/ms (1000 * Log[2^-(1/128)]) |
108 | | - float EnvGainBP = TransientFilter[1], GainBPRate = expf(-0x1.5A92D6p2f / RateHz); //! -0.047dB/ms (1000 * Log[2^-(1/128)]) |
109 | | - float EnvPost = TransientFilter[2], PostRate = expf(-0x1.5A92D6p6f / RateHz); //! -0.753dB/ms (1000 * Log[2^-(1/8)]) |
110 | 109 | struct ULC_TransientData_t *Dst = TransientBuffer + ULC_MAX_BLOCK_DECIMATION_FACTOR; //! Align to new block |
111 | | - const float *Src = BufEnergy; |
112 | 110 | i = ULC_MAX_BLOCK_DECIMATION_FACTOR; do { |
113 | 111 | //! Swap out the old "new" data, and clear the new "new" data |
114 | 112 | Dst[-ULC_MAX_BLOCK_DECIMATION_FACTOR] = *Dst; |
115 | 113 | *Dst = (struct ULC_TransientData_t){.Sum = 0.0f, .SumW = 0.0f}; |
116 | | - n = BinSize; do { |
117 | | - //! Accumulate and subtract 'drift' from the HP and BP |
118 | | - //! signals to "unbias" the data for the next steps. |
119 | | - //! This essentially 'enhances' energy differences. |
| 114 | + |
| 115 | + //! Smear the energy forwards in time to account for post-masking |
| 116 | + //! Dev note: Closer to 0dB = Less sensitive |
| 117 | + float EnvPostMaskHP = TransientFilter[0]; |
| 118 | + float EnvPostMaskBP = TransientFilter[1]; |
| 119 | + float EnvPostMaskHP_Rate = expf(-0x1.CC845Cp6f / RateHz); //! -1.0dB/ms (1000 * Log[10^(-0.2/20))]) |
| 120 | + float EnvPostMaskBP_Rate = expf(-0x1.9E771Ep6f / RateHz); //! -0.9dB/ms (1000 * Log[10^(-0.5/20))]) |
| 121 | + for(n=0;n<BinSize;n++) { |
120 | 122 | //! NOTE: This calculation must be done in the amplitude |
121 | 123 | //! domain, as the power domain behaves too erratically. |
122 | | - float vHP = sqrtf(Src[0]) - EnvGainHP; |
123 | | - float vBP = sqrtf(Src[1]) - EnvGainBP; |
124 | | - EnvGainHP += vHP * (1.0f-GainHPRate); |
125 | | - EnvGainBP += vBP * (1.0f-GainBPRate); |
126 | | - Src += 2; |
127 | | - |
128 | | - //! Update the post-echo-compensating energy curve, and |
129 | | - //! store the updated sum for this segment. |
130 | | - //! NOTE: Delta HP and delta BP are cross-multiplied by |
131 | | - //! their respective gains to sort of 'normalize' with |
132 | | - //! respect to one another. This balances out their |
133 | | - //! weaknesses somewhat. |
134 | | - float vPost = SQR(vHP*EnvGainBP) + SQR(vBP*EnvGainHP) - EnvPost; |
135 | | - EnvPost += vPost * (1.0f-PostRate); |
136 | | - Dst->Sum += EnvPost, Dst->SumW += (SQR(EnvGainBP) + SQR(EnvGainHP)); |
137 | | - } while(--n); |
| 124 | + float vHP = sqrtf(BufEnergy[n*2+0]), dHP = vHP - EnvPostMaskHP; |
| 125 | + float vBP = sqrtf(BufEnergy[n*2+1]), dBP = vBP - EnvPostMaskBP; |
| 126 | + EnvPostMaskHP += dHP * (1.0f-EnvPostMaskHP_Rate); |
| 127 | + EnvPostMaskBP += dBP * (1.0f-EnvPostMaskBP_Rate); |
| 128 | + BufEnergy[n*2+0] = EnvPostMaskHP; |
| 129 | + BufEnergy[n*2+1] = EnvPostMaskBP; |
| 130 | + |
| 131 | + } |
| 132 | + TransientFilter[0] = EnvPostMaskHP; |
| 133 | + TransientFilter[1] = EnvPostMaskBP; |
| 134 | + |
| 135 | + //! Now smear backwards to account for pre-masking, but take the |
| 136 | + //! difference between post- and pre-masking to form the 'error' |
| 137 | + //! Dev note: Closer to 0dB = More sensitive |
| 138 | + float EnvPreMaskHP = EnvPostMaskHP; |
| 139 | + float EnvPreMaskBP = EnvPostMaskBP; |
| 140 | + float EnvPreMaskHP_Rate = expf(-0x1.CC845Cp7f / RateHz); //! -2.0dB/ms (1000 * Log[10^(-1.0/20)]) |
| 141 | + float EnvPreMaskBP_Rate = expf(-0x1.144F6Ap5f / RateHz); //! -0.3dB/ms (1000 * Log[10^(-1.0/20)]) |
| 142 | + for(n=BinSize-1;n>=0;n--) { |
| 143 | + //! NOTE: Cross-multiply HP with BP energy and vice-versa |
| 144 | + //! to normalize the levels with respect to one another |
| 145 | + float vHP = BufEnergy[n*2+0], dHP = vHP - EnvPreMaskHP; |
| 146 | + float vBP = BufEnergy[n*2+1], dBP = vBP - EnvPreMaskBP; |
| 147 | + EnvPreMaskHP += dHP * (1.0f-EnvPreMaskHP_Rate); |
| 148 | + EnvPreMaskBP += dBP * (1.0f-EnvPreMaskBP_Rate); |
| 149 | + BufEnergy[n*2+0] = SQR(dHP*EnvPreMaskBP) + SQR(dBP*EnvPreMaskHP); |
| 150 | + } |
| 151 | + |
| 152 | + //! Finally, smooth the signal to account for the block size. |
| 153 | + //! Larger blocks get less smoothing to capture changes more |
| 154 | + //! easily, smaller blocks get more smoothing because they |
| 155 | + //! don't need to capture smooth-ish changes. |
| 156 | + float EnvBlockMask = TransientFilter[2]; |
| 157 | + float EnvBlockMask_Rate = expf(-0x1.1AF110p-6f * BlockSize / RateHz); //! -0.00015dB/ms*BlockSize (1000 * Log[10^(-0.00015/20)]) |
| 158 | + for(n=0;n<BinSize;n++) { |
| 159 | + float vEnergy = BufEnergy[n*2+0], dEnergy = vEnergy - EnvBlockMask; |
| 160 | + EnvBlockMask += dEnergy * (1.0f-EnvBlockMask_Rate); |
| 161 | + Dst->Sum += SQR(EnvBlockMask), Dst->SumW += EnvBlockMask; |
| 162 | + } |
| 163 | + TransientFilter[2] = EnvBlockMask; |
| 164 | + |
| 165 | + //! Move to next segment |
| 166 | + BufEnergy += BinSize*2; |
138 | 167 | } while(Dst++, --i); |
139 | | - TransientFilter[0] = EnvGainHP; |
140 | | - TransientFilter[1] = EnvGainBP; |
141 | | - TransientFilter[2] = EnvPost; |
142 | 168 | } |
143 | 169 | } |
144 | 170 | #pragma GCC pop_options |
|
0 commit comments