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 use, 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 // Generates several ramps, in lockstep or with various frequency/slope ratios. 28 29 #ifndef TIDES_RAMP_GENERATOR_H_ 30 #define TIDES_RAMP_GENERATOR_H_ 31 32 #include "stmlib/dsp/dsp.h" 33 #include "stmlib/dsp/parameter_interpolator.h" 34 #include "stmlib/dsp/polyblep.h" 35 #include "stmlib/utils/gate_flags.h" 36 37 #include <algorithm> 38 39 #include "tides2/ratio.h" 40 41 namespace tides { 42 43 enum RampMode { 44 RAMP_MODE_AD, 45 RAMP_MODE_LOOPING, 46 RAMP_MODE_AR, 47 RAMP_MODE_LAST 48 }; 49 50 enum OutputMode { 51 OUTPUT_MODE_GATES, 52 OUTPUT_MODE_AMPLITUDE, 53 OUTPUT_MODE_SLOPE_PHASE, 54 OUTPUT_MODE_FREQUENCY, 55 OUTPUT_MODE_LAST, 56 }; 57 58 enum Range { 59 RANGE_CONTROL, 60 RANGE_AUDIO, 61 RANGE_LAST 62 }; 63 64 template<size_t num_channels=4> 65 class RampGenerator { 66 public: RampGenerator()67 RampGenerator() { } ~RampGenerator()68 ~RampGenerator() { } 69 phase(size_t index)70 inline float phase(size_t index) const { 71 return phase_[index]; 72 } 73 frequency(size_t index)74 inline float frequency(size_t index) const { 75 return frequency_[index]; 76 } 77 Init()78 inline void Init() { 79 master_phase_ = 0.0f; 80 std::fill(&phase_[0], &phase_[num_channels], 0.0f); 81 std::fill(&frequency_[0], &frequency_[num_channels], 0.0f); 82 std::fill(&wrap_counter_[0], &wrap_counter_[num_channels], 0); 83 84 Ratio r; 85 r.ratio = 1.0f; 86 r.q = 1; 87 std::fill(&ratio_[0], &ratio_[num_channels], r); 88 next_ratio_ = &ratio_[0]; 89 } 90 set_next_ratio(const Ratio * next_ratio)91 inline void set_next_ratio(const Ratio* next_ratio) { 92 next_ratio_ = next_ratio; 93 } 94 95 template< 96 RampMode ramp_mode, 97 OutputMode output_mode, 98 Range range, 99 bool use_ramp> Step(const float f0,const float * pw,stmlib::GateFlags gate_flags,float ramp)100 inline void Step( 101 const float f0, 102 const float* pw, 103 stmlib::GateFlags gate_flags, 104 float ramp) { 105 106 const size_t n = output_mode == OUTPUT_MODE_FREQUENCY || 107 (output_mode == OUTPUT_MODE_SLOPE_PHASE && ramp_mode == RAMP_MODE_AR) 108 ? num_channels : 1; 109 110 if (ramp_mode == RAMP_MODE_AD) { 111 if (gate_flags & stmlib::GATE_FLAG_RISING) { 112 std::fill(&phase_[0], &phase_[n], 0.0f); 113 } 114 115 for (size_t i = 0; i < n; ++i) { 116 frequency_[i] = std::min(f0 * next_ratio_[i].ratio, 0.25f); 117 if (use_ramp) { 118 phase_[i] = ramp * next_ratio_[i].ratio; 119 } else { 120 phase_[i] += frequency_[i]; 121 } 122 phase_[i] = std::min(phase_[i], 1.0f); 123 } 124 } 125 126 if (ramp_mode == RAMP_MODE_AR) { 127 if (output_mode == OUTPUT_MODE_SLOPE_PHASE) { 128 std::fill(&frequency_[0], &frequency_[n], f0); 129 } else { 130 for (size_t i = 0; i < n; ++i) { 131 frequency_[i] = std::min(f0 * next_ratio_[i].ratio, 0.25f); 132 } 133 } 134 135 const bool should_ramp_up = use_ramp 136 ? ramp < 0.5f : gate_flags & stmlib::GATE_FLAG_HIGH; 137 138 float clip_at = should_ramp_up ? 0.5f : 1.0f; 139 for (size_t i = 0; i < n; ++i) { 140 if (phase_[i] < 0.5f && !should_ramp_up) { 141 phase_[i] = 0.5f; 142 } else if (phase_[i] > 0.5f && should_ramp_up) { 143 phase_[i] = 0.0f; 144 } 145 float this_pw = output_mode == OUTPUT_MODE_FREQUENCY ? pw[0] : pw[i]; 146 float slope = phase_[i] < 0.5f 147 ? 0.5f / (1.0e-6f + this_pw) 148 : 0.5f / (1.0f + 1.0e-6f - this_pw); 149 phase_[i] += frequency_[i] * slope; 150 phase_[i] = std::min(phase_[i], clip_at); 151 } 152 } 153 154 if (ramp_mode == RAMP_MODE_LOOPING) { 155 if (range == RANGE_AUDIO && output_mode == OUTPUT_MODE_FREQUENCY) { 156 // Do not attempt to lock the phase of all outputs. This allows 157 // smooth frequency changes. 158 bool reset = false; 159 if (gate_flags & stmlib::GATE_FLAG_RISING) { 160 std::fill(&phase_[0], &phase_[n], 0.0f); 161 reset = true; 162 } 163 for (size_t i = 0; i < n; ++i) { 164 frequency_[i] = std::min(f0 * next_ratio_[i].ratio, 0.25f); 165 } 166 if (!reset) { 167 for (size_t i = 0; i < n; ++i) { 168 phase_[i] += frequency_[i]; 169 if (phase_[i] >= 1.0f) { 170 phase_[i] -= 1.0f; 171 } 172 } 173 } 174 } else { 175 if (use_ramp) { 176 for (size_t i = 0; i < n; ++i) { 177 frequency_[i] = std::min(f0 * ratio_[i].ratio, 0.25f); 178 } 179 if (ramp < master_phase_) { 180 for (size_t i = 0; i < n; ++i) { 181 ++wrap_counter_[i]; 182 if (wrap_counter_[i] >= ratio_[i].q) { 183 ratio_[i] = next_ratio_[i]; 184 wrap_counter_[i] = 0; 185 } 186 } 187 } 188 master_phase_ = ramp; 189 } else { 190 bool reset = false; 191 if (gate_flags & stmlib::GATE_FLAG_RISING) { 192 master_phase_ = 0.0f; 193 std::copy(&next_ratio_[0], &next_ratio_[n], &ratio_[0]); 194 std::fill(&wrap_counter_[0], &wrap_counter_[n], 0); 195 reset = true; 196 } 197 for (size_t i = 0; i < n; ++i) { 198 frequency_[i] = std::min(f0 * ratio_[i].ratio, 0.25f); 199 } 200 if (!reset) { 201 master_phase_ += f0; 202 } 203 if (master_phase_ >= 1.0f) { 204 master_phase_ -= 1.0f; 205 for (size_t i = 0; i < n; ++i) { 206 ++wrap_counter_[i]; 207 if (wrap_counter_[i] >= ratio_[i].q) { 208 ratio_[i] = next_ratio_[i]; 209 wrap_counter_[i] = 0; 210 } 211 } 212 } 213 } 214 for (size_t i = 0; i < n; ++i) { 215 float mult_phase = master_phase_ + float(wrap_counter_[i]); 216 mult_phase *= ratio_[i].ratio; 217 MAKE_INTEGRAL_FRACTIONAL(mult_phase); 218 phase_[i] = mult_phase_fractional; 219 } 220 } 221 } 222 } 223 224 private: 225 const Ratio* next_ratio_; 226 227 float master_phase_; 228 int wrap_counter_[num_channels]; 229 230 float phase_[num_channels]; 231 float frequency_[num_channels]; 232 Ratio ratio_[num_channels]; 233 234 DISALLOW_COPY_AND_ASSIGN(RampGenerator); 235 }; 236 237 } // namespace tides 238 239 #endif // TIDES_RAMP_GENERATOR_H_ 240