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