1 // Copyright 2017 Emilie Gillet. 2 // 3 // Author: Emilie Gillet (emilie.o.gillet@gmail.com) 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to enable, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 // 23 // See http://creativecommons.org/licenses/MIT/ for more information. 24 // 25 // ----------------------------------------------------------------------------- 26 // 27 // Convert the phase counters generated by RampGenerator into actual variable 28 // slope waveforms (or variants, like EOA/EOR pulses). 29 30 #ifndef TIDES_RAMP_SHAPER_H_ 31 #define TIDES_RAMP_SHAPER_H_ 32 33 #include "stmlib/dsp/dsp.h" 34 #include "stmlib/dsp/parameter_interpolator.h" 35 #include "stmlib/dsp/polyblep.h" 36 37 #include "tides2/ramp_generator.h" 38 39 namespace tides { 40 41 class RampShaper { 42 public: RampShaper()43 RampShaper() { } ~RampShaper()44 ~RampShaper() { } 45 Init()46 void Init() { 47 next_sample_ = 0.0f; 48 previous_phase_shift_ = 0.0f; 49 going_up_ = true; 50 } 51 BandLimitedPulse(float phase,float frequency,float pw)52 inline float BandLimitedPulse(float phase, float frequency, float pw) { 53 CONSTRAIN(pw, frequency * 2.0f, 1.0f - 2.0f * frequency); 54 float this_sample = next_sample_; 55 float next_sample = 0.0f; 56 57 float wrap_point = pw; 58 if (phase < pw * 0.5f) { 59 wrap_point = 0.0f; 60 } else if (phase > 0.5f + pw * 0.5f) { 61 wrap_point = 1.0f; 62 } 63 64 if (going_up_ ^ (phase < pw)) { 65 float t = (phase - wrap_point) / frequency; 66 float discontinuity = 1.0f; 67 if (wrap_point != pw) { 68 discontinuity = -discontinuity; 69 } 70 if (frequency < 0.0f) { 71 discontinuity = -discontinuity; 72 } 73 this_sample += stmlib::ThisBlepSample(t) * discontinuity; 74 next_sample += stmlib::NextBlepSample(t) * discontinuity; 75 going_up_ = phase < pw; 76 } 77 next_sample += phase < pw ? 0.0f : 1.0f; 78 next_sample_ = next_sample; 79 return this_sample; 80 } 81 82 template<RampMode ramp_mode, Range range> Slope(float phase,float phase_shift,float frequency,float pw)83 inline float Slope( 84 float phase, float phase_shift, float frequency, float pw) { 85 if (ramp_mode == RAMP_MODE_AD) { 86 return SkewedRamp(phase, 0.0f, frequency, pw); 87 } else if (ramp_mode == RAMP_MODE_AR) { 88 return phase; 89 } else { 90 if (range == RANGE_CONTROL) { 91 return SkewedRamp(phase, phase_shift, frequency, pw); 92 } else { 93 return BandLimitedSlope(phase, phase_shift, frequency, pw); 94 } 95 } 96 } 97 98 template<RampMode ramp_mode> EOA(float phase,float frequency,float pw)99 inline float EOA(float phase, float frequency, float pw) { 100 if (ramp_mode == RAMP_MODE_LOOPING) { 101 return BandLimitedPulse(phase, frequency, pw); 102 } else if (ramp_mode == RAMP_MODE_AR) { 103 return phase >= 0.5f ? 1.0f : 0.0f; 104 } else { 105 return phase >= pw ? 1.0f : 0.0f; 106 } 107 } 108 109 template<RampMode ramp_mode> EOR(float phase,float frequency,float pw)110 inline float EOR(float phase, float frequency, float pw) { 111 if (ramp_mode == RAMP_MODE_LOOPING) { 112 return 1.0f - BandLimitedPulse( 113 phase, frequency, std::min(0.5f, 96.0f * frequency)); 114 } else { 115 return phase >= 1.0f; 116 } 117 } 118 119 private: BandLimitedSlope(float phase,float phase_shift,float frequency,float pw)120 inline float BandLimitedSlope( 121 float phase, float phase_shift, float frequency, float pw) { 122 if (phase_shift) { 123 phase += phase_shift; 124 frequency += phase_shift - previous_phase_shift_; 125 previous_phase_shift_ = phase_shift; 126 127 if (phase >= 1.0f) { 128 phase -= 1.0f; 129 } else if (phase < 0.0f) { 130 phase += 1.0f; 131 } 132 } 133 134 CONSTRAIN(pw, fabsf(frequency) * 2.0f, 1.0f - 2.0f * fabsf(frequency)); 135 float this_sample = next_sample_; 136 float next_sample = 0.0f; 137 138 float wrap_point = pw; 139 if (phase < pw * 0.5f) { 140 wrap_point = 0.0f; 141 } else if (phase > 0.5f + pw * 0.5f) { 142 wrap_point = 1.0f; 143 } 144 145 const float slope_up = 1.0f / pw; 146 const float slope_down = 1.0f / (1.0f - pw); 147 if (going_up_ ^ (phase < pw)) { 148 float t = (phase - wrap_point) / frequency; 149 float discontinuity = -(slope_up + slope_down) * frequency; 150 if (wrap_point != pw) { 151 discontinuity = -discontinuity; 152 } 153 if (frequency < 0.0f) { 154 discontinuity = -discontinuity; 155 } 156 this_sample += stmlib::ThisIntegratedBlepSample(t) * discontinuity; 157 next_sample += stmlib::NextIntegratedBlepSample(t) * discontinuity; 158 going_up_ = phase < pw; 159 } 160 next_sample += going_up_ 161 ? phase * slope_up 162 : 1.0f - (phase - pw) * slope_down; 163 next_sample_ = next_sample; 164 return this_sample; 165 } 166 SkewedRamp(float phase,float phase_shift,float frequency,float pw)167 inline float SkewedRamp( 168 float phase, float phase_shift, float frequency, float pw) { 169 if (phase_shift) { 170 phase += phase_shift; 171 frequency += phase_shift - previous_phase_shift_; 172 previous_phase_shift_ = phase_shift; 173 174 if (phase >= 1.0f) { 175 phase -= 1.0f; 176 } else if (phase < 0.0f) { 177 phase += 1.0f; 178 } 179 } 180 181 CONSTRAIN(pw, fabsf(frequency) * 2.0f, 1.0f - 2.0f * fabsf(frequency)); 182 const float slope_up = 0.5f / pw; 183 const float slope_down = 0.5f / (1.0f - pw); 184 return phase < pw ? phase * slope_up : (phase - pw) * slope_down + 0.5f; 185 } 186 187 float next_sample_; 188 float previous_phase_shift_; 189 bool going_up_; 190 191 DISALLOW_COPY_AND_ASSIGN(RampShaper); 192 }; 193 194 class RampWaveshaper { 195 public: RampWaveshaper()196 RampWaveshaper() { } ~RampWaveshaper()197 ~RampWaveshaper() { } 198 Init()199 void Init() { 200 previous_input_ = 0.0f; 201 previous_output_ = 0.0f; 202 breakpoint_ = 0.0f; 203 } 204 205 template<RampMode ramp_mode> Shape(float input,const int16_t * shape,float shape_fractional)206 inline float Shape( 207 float input, 208 const int16_t* shape, 209 float shape_fractional) { 210 float ws_index = 1024.0f * input; 211 MAKE_INTEGRAL_FRACTIONAL(ws_index) 212 ws_index_integral &= 1023; 213 float x0 = static_cast<float>(shape[ws_index_integral]) / 32768.0f; 214 float x1 = static_cast<float>(shape[ws_index_integral + 1]) / 32768.0f; 215 float y0 = static_cast<float>(shape[ws_index_integral + 1025]) / 32768.0f; 216 float y1 = static_cast<float>(shape[ws_index_integral + 1026]) / 32768.0f; 217 float x = x0 + (x1 - x0) * ws_index_fractional; 218 float y = y0 + (y1 - y0) * ws_index_fractional; 219 float output = x + (y - x) * shape_fractional; 220 221 if (ramp_mode != RAMP_MODE_AR) { 222 return output; 223 } else { 224 if (previous_input_ <= 0.5f && input > 0.5f) { 225 breakpoint_ = previous_output_; 226 } else if (previous_input_ > 0.5f && input < 0.5f) { 227 breakpoint_ = previous_output_; 228 } else if (input == 1.0f) { 229 breakpoint_ = 1.0f; 230 } else if (input == 0.5f) { 231 breakpoint_ = 0.0f; 232 } 233 if (input <= 0.5f) { 234 output = breakpoint_ + (1.0f - breakpoint_) * output; 235 } else { 236 output = breakpoint_ * output; 237 } 238 previous_input_ = input; 239 previous_output_ = output; 240 return output; 241 } 242 } 243 244 private: 245 float previous_input_; 246 float previous_output_; 247 float breakpoint_; 248 249 DISALLOW_COPY_AND_ASSIGN(RampWaveshaper); 250 }; 251 252 } // namespace tides 253 254 #endif // TIDES_RAMP_SHAPER_H_ 255