1 // Copyright 2013 Olivier Gillet. 2 // 3 // Author: Olivier Gillet (ol.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 // Tidal generator. 28 29 #ifndef TIDES_GENERATOR_H_ 30 #define TIDES_GENERATOR_H_ 31 32 #include "stmlib/stmlib.h" 33 34 #include "stmlib/algorithms/pattern_predictor.h" 35 #include "stmlib/utils/ring_buffer.h" 36 37 // #define WAVETABLE_HACK 38 39 namespace tides { 40 41 enum GeneratorRange { 42 GENERATOR_RANGE_HIGH, 43 GENERATOR_RANGE_MEDIUM, 44 GENERATOR_RANGE_LOW 45 }; 46 47 enum GeneratorMode { 48 GENERATOR_MODE_AD, 49 GENERATOR_MODE_LOOPING, 50 GENERATOR_MODE_AR, 51 }; 52 53 enum ControlBitMask { 54 CONTROL_FREEZE = 1, 55 CONTROL_GATE = 2, 56 CONTROL_CLOCK = 4, 57 CONTROL_CLOCK_RISING = 8, 58 CONTROL_GATE_RISING = 16, 59 CONTROL_GATE_FALLING = 32 60 }; 61 62 enum FlagBitMask { 63 FLAG_END_OF_ATTACK = 1, 64 FLAG_END_OF_RELEASE = 2 65 }; 66 67 struct GeneratorSample { 68 uint16_t unipolar; 69 int16_t bipolar; 70 uint8_t flags; 71 }; 72 73 const uint16_t kBlockSize = 16; 74 75 struct FrequencyRatio { 76 uint32_t p; 77 uint32_t q; 78 }; 79 80 class Generator { 81 public: Generator()82 Generator() { } ~Generator()83 ~Generator() { } 84 85 void Init(); 86 set_range(GeneratorRange range)87 void set_range(GeneratorRange range) { 88 ClearFilterState(); 89 range_ = range; 90 clock_divider_ = 91 /* harmonic oscillator is sampled at 24kHz */ 92 feature_mode_ == FEAT_MODE_HARMONIC ? 2 : 93 range_ == GENERATOR_RANGE_LOW ? 4 : 1; 94 } 95 set_mode(GeneratorMode mode)96 void set_mode(GeneratorMode mode) { 97 mode_ = mode; 98 if (mode_ == GENERATOR_MODE_LOOPING) { 99 running_ = true; 100 } 101 } 102 set_pitch_high_range(int16_t pitch,int16_t fm)103 void set_pitch_high_range(int16_t pitch, int16_t fm) { 104 if (sync_) { 105 ComputeFrequencyRatio(pitch); 106 } 107 pitch_ = pitch + (12 << 7) + fm; 108 } 109 set_pitch(int16_t pitch,int16_t fm)110 void set_pitch(int16_t pitch, int16_t fm) { 111 if (sync_) { 112 ComputeFrequencyRatio(pitch); 113 } 114 115 pitch += (12 << 7) - (60 << 7) * static_cast<int16_t>(range_); 116 if (range_ == GENERATOR_RANGE_LOW) { 117 pitch -= (12 << 7); // One extra octave of super LF stuff! 118 } 119 pitch_ = pitch + fm; 120 } 121 set_shape(int16_t shape)122 void set_shape(int16_t shape) { 123 shape_ = shape; 124 } 125 set_slope(int16_t slope)126 void set_slope(int16_t slope) { 127 #ifndef WAVETABLE_HACK 128 if (range_ == GENERATOR_RANGE_HIGH && 129 feature_mode_ != FEAT_MODE_HARMONIC) { 130 CONSTRAIN(slope, -32512, 32512); 131 } 132 #endif // WAVETABLE_HACK 133 slope_ = slope; 134 } 135 set_smoothness(int16_t smoothness)136 void set_smoothness(int16_t smoothness) { 137 smoothness_ = smoothness; 138 } 139 set_frequency_ratio(FrequencyRatio ratio)140 void set_frequency_ratio(FrequencyRatio ratio) { 141 frequency_ratio_ = ratio; 142 } 143 set_waveshaper_antialiasing(bool antialiasing)144 void set_waveshaper_antialiasing(bool antialiasing) { 145 antialiasing_ = antialiasing; 146 } 147 set_sync(bool sync)148 void set_sync(bool sync) { 149 if (!sync_ && sync) { 150 pattern_predictor_.Init(); 151 } 152 sync_ = sync; 153 sync_edges_counter_ = 0; 154 } 155 set_pulse_width(uint16_t pw)156 void set_pulse_width(uint16_t pw) { 157 pulse_width_ = pw; 158 } 159 mode()160 inline GeneratorMode mode() const { return mode_; } range()161 inline GeneratorRange range() const { return range_; } sync()162 inline bool sync() const { return sync_; } 163 Process(uint8_t control)164 inline GeneratorSample Process(uint8_t control) { 165 input_buffer_.Overwrite(control); 166 return output_buffer_.ImmediateRead(); 167 } 168 writable_block()169 inline bool writable_block() const { 170 return output_buffer_.writable() >= kBlockSize; 171 } 172 FillBufferSafe()173 inline bool FillBufferSafe() { 174 if (!writable_block()) { 175 return false; 176 } else { 177 FillBuffer(); 178 return true; 179 } 180 } 181 182 void FillBuffer(); 183 clock_divider()184 uint32_t clock_divider() const { 185 return clock_divider_; 186 } 187 188 enum FeatureMode { 189 FEAT_MODE_FUNCTION, 190 FEAT_MODE_HARMONIC, 191 FEAT_MODE_RANDOM, 192 }; 193 194 FeatureMode feature_mode_; 195 196 private: 197 // There are two versions of the rendering code, one optimized for audio, with 198 // band-limiting. 199 void FillBufferAudioRate(); 200 void FillBufferControlRate(); 201 void FillBufferWavetable(); 202 template<GeneratorMode mode> void FillBufferHarmonic(); 203 void FillBufferRandom(); 204 int32_t ComputeAntialiasAttenuation( 205 int16_t pitch, 206 int16_t slope, 207 int16_t shape, 208 int16_t smoothness); 209 ClearFilterState()210 inline void ClearFilterState() { 211 uni_lp_state_[0] = uni_lp_state_[1] = 0; 212 bi_lp_state_[0] = bi_lp_state_[1] = 0; 213 } 214 215 int32_t ComputePhaseIncrement(int16_t pitch); 216 int16_t ComputePitch(int32_t phase_increment); 217 int32_t ComputeCutoffFrequency(int16_t pitch, int16_t smoothness); 218 void ComputeFrequencyRatio(int16_t pitch); 219 220 stmlib::RingBuffer<uint8_t, kBlockSize * 2> input_buffer_; 221 stmlib::RingBuffer<GeneratorSample, kBlockSize * 2> output_buffer_; 222 223 GeneratorMode mode_; 224 GeneratorRange range_; 225 GeneratorSample previous_sample_; 226 227 uint32_t clock_divider_; 228 229 int16_t pitch_; 230 int16_t previous_pitch_; 231 int16_t shape_; 232 int16_t slope_; 233 int32_t smoothed_slope_; 234 int16_t smoothness_; 235 bool antialiasing_; 236 uint16_t final_gain_; 237 238 uint32_t phase_; 239 int32_t phase_increment_; 240 uint32_t sub_phase_; 241 uint16_t x_; 242 uint16_t y_; 243 uint16_t z_; 244 bool wrap_; 245 246 uint16_t pulse_width_; 247 uint32_t divided_phase_; 248 uint32_t divider_; 249 uint32_t divider_counter_; 250 uint32_t delayed_phase_; 251 int32_t delayed_phase_increment_; 252 uint32_t delay_; 253 uint32_t delay_counter_; 254 int16_t previous_slope_; 255 uint32_t delayed_threshold_; 256 257 uint16_t current_value_[2]; 258 uint16_t next_value_[2]; 259 bool walk_direction_[2]; 260 uint16_t value_[2]; 261 262 int16_t old_slope_; 263 int16_t old_pitch_; 264 265 bool sync_; 266 FrequencyRatio frequency_ratio_; 267 268 // Time measurement and clock divider for PLL mode. 269 uint32_t sync_counter_; 270 uint32_t sync_edges_counter_; 271 uint32_t local_osc_phase_; 272 int32_t local_osc_phase_increment_; 273 int32_t target_phase_increment_; 274 uint32_t eor_counter_; 275 276 stmlib::PatternPredictor<32, 8> pattern_predictor_; 277 278 int64_t uni_lp_state_[2]; 279 int64_t bi_lp_state_[2]; 280 281 bool running_; 282 bool previous_freeze_; 283 bool previous_clock_; 284 285 static const FrequencyRatio frequency_ratios_[]; 286 static const int16_t num_frequency_ratios_; 287 288 static const uint8_t kNumHarmonics = 16; 289 static const uint8_t kNumHarmonicsPowers = 12; 290 291 uint16_t envelope_[kNumHarmonics]; 292 uint16_t envelope_increment_[kNumHarmonics]; 293 uint8_t harm_permut_[kNumHarmonics]; 294 295 void RandomizeDelay(); 296 void RandomizeDivider(); 297 void RandomizeHarmonicPhase(); 298 void RandomizeHarmonicDistribution(); 299 300 DISALLOW_COPY_AND_ASSIGN(Generator); 301 }; 302 303 } // namespace tides 304 305 #endif // TIDES_GENERATOR_H_ 306