1 /* 2 ** Surge Synthesizer is Free and Open Source Software 3 ** 4 ** Surge is made available under the Gnu General Public License, v3.0 5 ** https://www.gnu.org/licenses/gpl-3.0.en.html 6 ** 7 ** Copyright 2004-2021 by various individuals as described by the Git transaction log 8 ** 9 ** All source at: https://github.com/surge-synthesizer/surge.git 10 ** 11 ** Surge was a commercial product from 2004-2018, with Copyright and ownership 12 ** in that period held by Claes Johanson at Vember Audio. Claes made Surge 13 ** open source in September 2018. 14 */ 15 16 #include "TreemonsterEffect.h" 17 #include "DebugHelpers.h" 18 19 TreemonsterEffect::TreemonsterEffect(SurgeStorage *storage, FxStorage *fxdata, pdata *pd) 20 : Effect(storage, fxdata, pd), lp(storage), hp(storage) 21 { 22 rm.set_blocksize(BLOCK_SIZE); 23 width.set_blocksize(BLOCK_SIZE); 24 mix.set_blocksize(BLOCK_SIZE); 25 } 26 27 TreemonsterEffect::~TreemonsterEffect() {} 28 29 void TreemonsterEffect::init() 30 { 31 setvars(true); 32 bi = 0; 33 } get_effectname()34 35 void TreemonsterEffect::setvars(bool init) 36 { 37 if (init) 38 { 39 lp.suspend(); 40 hp.suspend(); 41 42 hp.coeff_HP(hp.calc_omega(*f[tm_hp] / 12.0), 0.707); 43 hp.coeff_instantize(); 44 45 lp.coeff_LP2B(lp.calc_omega(*f[tm_lp] / 12.0), 0.707); 46 lp.coeff_instantize(); 47 48 oscL.set_rate(0.f); 49 oscR.set_rate(0.f); 50 51 rm.set_target(1.f); 52 width.set_target(0.f); 53 mix.set_target(1.f); 54 55 rm.instantize(); 56 width.instantize(); 57 mix.instantize(); 58 59 // envelope follower times: 5 ms attack, 500 ms release 60 envA = pow(0.01, 1.0 / (5 * dsamplerate * 0.001)); 61 envR = pow(0.01, 1.0 / (500 * dsamplerate * 0.001)); 62 envV[0] = 0.f; 63 envV[1] = 0.f; 64 65 length[0] = 100; 66 length[1] = 100; 67 length_target[0] = 100; 68 length_target[1] = 100; 69 length_smooth[0] = 100; 70 length_smooth[1] = 100; 71 first_thresh[0] = true; 72 first_thresh[1] = true; 73 oscL.set_phase(0); 74 oscR.set_phase(M_PI / 2.0); 75 } 76 } 77 78 void TreemonsterEffect::process(float *dataL, float *dataR) 79 { 80 float tbuf alignas(16)[2][BLOCK_SIZE]; 81 float envscaledSineWave alignas(16)[2][BLOCK_SIZE]; 82 83 auto thres = db_to_linear(limit_range(*f[tm_threshold], fxdata->p[tm_threshold].val_min.f, 84 fxdata->p[tm_threshold].val_max.f)); 85 86 // copy dry signal (dataL, dataR) to wet signal (L, R) 87 copy_block(dataL, L, BLOCK_SIZE_QUAD); 88 copy_block(dataR, R, BLOCK_SIZE_QUAD); 89 90 // copy it to pitch detection buffer (tbuf) as well 91 // in case filters are not activated 92 copy_block(dataL, tbuf[0], BLOCK_SIZE_QUAD); 93 copy_block(dataR, tbuf[1], BLOCK_SIZE_QUAD); 94 95 // apply filters to the pitch detection buffer 96 if (!fxdata->p[tm_hp].deactivated) 97 { 98 hp.coeff_HP(hp.calc_omega(*f[tm_hp] / 12.0), 0.707); 99 hp.process_block(tbuf[0], tbuf[1]); 100 } 101 102 if (!fxdata->p[tm_lp].deactivated) 103 { 104 lp.coeff_LP2B(lp.calc_omega(*f[tm_lp] / 12.0), 0.707); 105 lp.process_block(tbuf[0], tbuf[1]); 106 } 107 108 /* 109 * We assume wavelengths below this are just noisy detection errors. This is used to 110 * clamp when we have a pitch detect basically. 111 */ 112 constexpr float smallest_wavelength = 16.0; 113 114 float qs = clamp01(*f[tm_speed]); 115 qs *= qs * qs * qs; 116 float speed = 0.9999 - qs * 0.0999 / 128; 117 float numberOfSteps = 32 * 48000 * samplerate_inv; 118 for (int i = 0; i < numberOfSteps; ++i) 119 { 120 length_smooth[0] = speed * length_smooth[0] + (1 - speed) * length_target[0]; 121 length_smooth[1] = speed * length_smooth[1] + (1 - speed) * length_target[1]; 122 } 123 124 oscL.set_rate((2.0 * M_PI / std::max(2.f, length_smooth[0])) * 125 powf(2.0, *f[tm_pitch] * (1 / 12.f))); 126 oscR.set_rate((2.0 * M_PI / std::max(2.f, length_smooth[1])) * 127 powf(2.0, *f[tm_pitch] * (1 / 12.f))); 128 129 for (int k = 0; k < BLOCK_SIZE; k++) 130 { 131 // envelope detection 132 for (int c = 0; c < 2; ++c) 133 { 134 auto v = (c == 0 ? dataL[k] : dataR[k]); 135 auto e = envV[c]; 136 137 if (v > e) 138 { 139 e = envA * (e - v) + v; 140 } 141 else 142 { 143 e = envR * (e - v) + v; 144 } 145 146 envV[c] = e; 147 } 148 149 // pitch detection 150 if ((lastval[0] < 0.f) && (tbuf[0][k] >= 0.f)) 151 { 152 if (tbuf[0][k] > thres && length[0] > smallest_wavelength) 153 { 154 length_target[0] = 155 (length[0] > length_smooth[0] * 10 ? length_smooth[0] : length[0]); 156 if (first_thresh[0]) 157 length_smooth[0] = length[0]; 158 first_thresh[0] = false; 159 } 160 161 length[0] = 0.0; // (0.0-lastval[0]) / ( tbuf[0][k] - lastval[0]); 162 } 163 164 if ((lastval[1] < 0.f) && (tbuf[1][k] >= 0.f)) 165 { 166 if (tbuf[1][k] > thres && length[1] > smallest_wavelength) 167 { 168 length_target[1] = 169 (length[1] > length_smooth[1] * 10 ? length_smooth[1] : length[1]); 170 if (first_thresh[1]) 171 length_smooth[1] = length[1]; 172 first_thresh[1] = false; 173 } 174 175 length[1] = 0.0; // (0.0-lastval[1]) / ( tbuf[1][k] - lastval[1]); 176 } 177 178 oscL.process(); 179 oscR.process(); 180 181 // do not apply followed envelope to sine oscillator - we need full freight sine for RM 182 L[k] = oscL.r; 183 R[k] = oscR.r; 184 185 // but we need to store the scaled for mix 186 envscaledSineWave[0][k] = oscL.r * envV[0]; 187 envscaledSineWave[1][k] = oscR.r * envV[0]; 188 189 // track positive zero crossings 190 length[0] += 1.0f; 191 length[1] += 1.0f; 192 193 lastval[0] = tbuf[0][k]; 194 lastval[1] = tbuf[1][k]; 195 } 196 197 // do dry signal * pitch tracked signal ringmod 198 // store to pitch detection buffer 199 mul_block(L, dataL, tbuf[0], BLOCK_SIZE_QUAD); 200 mul_block(R, dataR, tbuf[1], BLOCK_SIZE_QUAD); 201 202 // mix pure pitch tracked sine with ring modulated signal 203 rm.set_target_smoothed(clamp01(*f[tm_ring_mix])); 204 rm.fade_2_blocks_to(envscaledSineWave[0], tbuf[0], envscaledSineWave[1], tbuf[1], L, R, 205 BLOCK_SIZE_QUAD); 206 207 // scale width 208 width.set_target_smoothed(clamp1bp(*f[tm_width])); 209 float M alignas(16)[BLOCK_SIZE], S alignas(16)[BLOCK_SIZE]; 210 encodeMS(L, R, M, S, BLOCK_SIZE_QUAD); 211 width.multiply_block(S, BLOCK_SIZE_QUAD); 212 decodeMS(M, S, L, R, BLOCK_SIZE_QUAD); 213 214 // main dry-wet mix 215 mix.set_target_smoothed(clamp01(*f[tm_mix])); 216 mix.fade_2_blocks_to(dataL, L, dataR, R, dataL, dataR, BLOCK_SIZE_QUAD); 217 } 218 219 void TreemonsterEffect::suspend() { init(); } 220 221 const char *TreemonsterEffect::group_label(int id) 222 { 223 switch (id) 224 { 225 case 0: 226 return "Pitch Detection"; 227 case 1: 228 return "Oscillator"; 229 case 2: 230 return "Output"; 231 } 232 return 0; 233 } 234 int TreemonsterEffect::group_label_ypos(int id) 235 { 236 switch (id) 237 { 238 case 0: 239 return 1; 240 case 1: 241 return 11; 242 case 2: 243 return 17; 244 } 245 return 0; 246 } 247 248 void TreemonsterEffect::init_ctrltypes() 249 { 250 Effect::init_ctrltypes(); 251 252 fxdata->p[tm_threshold].set_name("Threshold"); 253 fxdata->p[tm_threshold].set_type(ct_decibel_attenuation_large); 254 fxdata->p[tm_threshold].val_default.f = -24.f; 255 fxdata->p[tm_threshold].posy_offset = 1; 256 fxdata->p[tm_speed].set_name("Speed"); 257 fxdata->p[tm_speed].set_type(ct_percent); 258 fxdata->p[tm_speed].val_default.f = 0.5f; 259 fxdata->p[tm_speed].posy_offset = 1; 260 fxdata->p[tm_hp].set_name("Low Cut"); 261 fxdata->p[tm_hp].set_type(ct_freq_audible_deactivatable); 262 fxdata->p[tm_hp].posy_offset = 1; 263 fxdata->p[tm_lp].set_name("High Cut"); 264 fxdata->p[tm_lp].set_type(ct_freq_audible_deactivatable); 265 fxdata->p[tm_lp].posy_offset = 1; 266 267 fxdata->p[tm_pitch].set_name("Pitch"); 268 fxdata->p[tm_pitch].set_type(ct_pitch); 269 fxdata->p[tm_pitch].posy_offset = 3; 270 fxdata->p[tm_ring_mix].set_name("Ring Modulation"); 271 fxdata->p[tm_ring_mix].set_type(ct_percent); 272 fxdata->p[tm_ring_mix].val_default.f = 0.5f; 273 fxdata->p[tm_ring_mix].posy_offset = 3; 274 275 fxdata->p[tm_width].set_name("Width"); 276 fxdata->p[tm_width].set_type(ct_percent_bipolar); 277 fxdata->p[tm_width].posy_offset = 5; 278 fxdata->p[tm_mix].set_name("Mix"); 279 fxdata->p[tm_mix].set_type(ct_percent); 280 fxdata->p[tm_mix].posy_offset = 5; 281 fxdata->p[tm_mix].val_default.f = 1.f; 282 } 283 284 void TreemonsterEffect::init_default_values() 285 { 286 fxdata->p[tm_threshold].val.f = -24.f; 287 fxdata->p[tm_speed].val.f = 0.5f; 288 289 fxdata->p[tm_hp].val.f = fxdata->p[tm_hp].val_min.f; 290 fxdata->p[tm_hp].deactivated = false; 291 fxdata->p[tm_lp].val.f = fxdata->p[tm_lp].val_max.f; 292 fxdata->p[tm_lp].deactivated = false; 293 294 fxdata->p[tm_pitch].val.f = 0; 295 fxdata->p[tm_ring_mix].val.f = 0.5f; 296 297 fxdata->p[tm_width].val.f = 1.f; 298 fxdata->p[tm_mix].val.f = 1.f; 299 } 300