1 // Copyright 2013 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 // LFO.
28 
29 #include "peaks/modulations/lfo.h"
30 
31 #include <cstdio>
32 
33 #include "stmlib/utils/dsp.h"
34 #include "stmlib/utils/random.h"
35 
36 #include "peaks/resources.h"
37 
38 namespace peaks {
39 
40 const uint16_t kSlopeBits = 12;
41 const uint32_t kSyncCounterMaxTime = 8 * 48000;
42 
43 using namespace stmlib;
44 
Init()45 void Lfo::Init() {
46   rate_ = 0;
47   shape_ = LFO_SHAPE_SQUARE;
48   parameter_ = 0;
49   reset_phase_ = 0;
50   sync_ = false;
51   previous_parameter_ = 32767;
52   sync_counter_ = kSyncCounterMaxTime;
53   level_ = 32767;
54   pattern_predictor_.Init();
55 }
56 
57 const int16_t presets[7][2] = {
58   { LFO_SHAPE_SINE, 0 },
59   { LFO_SHAPE_TRIANGLE, 0 },
60   { LFO_SHAPE_TRIANGLE, 32767 },
61   { LFO_SHAPE_SQUARE, 0 },
62   { LFO_SHAPE_STEPS, 0 },
63   { LFO_SHAPE_NOISE, -32767 },
64   { LFO_SHAPE_NOISE, 32767 },
65 };
66 
set_shape_parameter_preset(uint16_t value)67 void Lfo::set_shape_parameter_preset(uint16_t value) {
68   value = (value >> 8) * 7 >> 8;
69   set_shape(static_cast<LfoShape>(presets[value][0]));
70   set_parameter(presets[value][1]);
71 }
72 
Process(const GateFlags * gate_flags,int16_t * out,size_t size)73 void Lfo::Process(const GateFlags* gate_flags, int16_t* out, size_t size) {
74   if (!sync_) {
75     int32_t a = lut_lfo_increments[rate_ >> 8];
76     int32_t b = lut_lfo_increments[(rate_ >> 8) + 1];
77     phase_increment_ = a + (((b - a) >> 1) * (rate_ & 0xff) >> 7);
78   }
79   while (size--) {
80     ++sync_counter_;
81     GateFlags gate_flag = *gate_flags++;
82     if (gate_flag & GATE_FLAG_RISING) {
83       bool reset_phase = true;
84       if (sync_) {
85         if (sync_counter_ < kSyncCounterMaxTime) {
86           uint32_t period = 0;
87           if (gate_flag & GATE_FLAG_FROM_BUTTON) {
88             period = sync_counter_;
89           } else if (sync_counter_ < 1920) {
90             period = (3 * period_ + sync_counter_) >> 2;
91             reset_phase = false;
92           } else {
93             period = pattern_predictor_.Predict(sync_counter_);
94           }
95           if (period != period_) {
96             period_ = period;
97             phase_increment_ = 0xffffffff / period_;
98           }
99         }
100         sync_counter_ = 0;
101       }
102       if (reset_phase) {
103         phase_ = reset_phase_;
104       }
105     }
106     phase_ += phase_increment_;
107     int32_t sample = (this->*compute_sample_fn_table_[shape_])();
108     *out++ = sample * level_ >> 15;
109   }
110 }
111 
ComputeSampleSine()112 int16_t Lfo::ComputeSampleSine() {
113   uint32_t phase = phase_;
114   int16_t sine = Interpolate1022(wav_sine, phase);
115   int16_t sample;
116   if (parameter_ > 0) {
117     int32_t wf_balance = parameter_;
118     int32_t wf_gain = 2048 + \
119         (static_cast<int32_t>(parameter_) * (65535 - 2048) >> 15);
120     int32_t original = sine;
121     int32_t folded = Interpolate1022(
122         wav_fold_sine, original * wf_gain + (1UL << 31));
123     sample = original + ((folded - original) * wf_balance >> 15);
124   } else {
125     int32_t wf_balance = -parameter_;
126     int32_t original = sine;
127     phase += 1UL << 30;
128     int32_t tri = phase < (1UL << 31) ? phase << 1 : ~(phase << 1);
129     int32_t folded = Interpolate1022(wav_fold_power, tri);
130     sample = original + ((folded - original) * wf_balance >> 15);
131   }
132   return sample;
133 }
134 
ComputeSampleTriangle()135 int16_t Lfo::ComputeSampleTriangle() {
136   if (parameter_ != previous_parameter_) {
137     uint16_t slope_offset = parameter_ + 32768;
138     if (slope_offset <= 1) {
139       decay_factor_ = 32768 << kSlopeBits;
140       attack_factor_ = 1 << (kSlopeBits - 1);
141     } else {
142       decay_factor_ = (32768 << kSlopeBits) / slope_offset;
143       attack_factor_ = (32768 << kSlopeBits) / (65536 - slope_offset);
144     }
145     end_of_attack_ = (static_cast<uint32_t>(slope_offset) << 16);
146     previous_parameter_ = parameter_;
147   }
148 
149   uint32_t phase = phase_;
150   uint32_t skewed_phase = phase;
151   if (phase < end_of_attack_) {
152     skewed_phase = (phase >> kSlopeBits) * decay_factor_;
153   } else {
154     skewed_phase = ((phase - end_of_attack_) >> kSlopeBits) * attack_factor_;
155     skewed_phase += 1L << 31;
156   }
157   return skewed_phase < 1UL << 31
158       ? -32768 + (skewed_phase >> 15)
159       :  32767 - (skewed_phase >> 15);
160 }
161 
ComputeSampleSquare()162 int16_t Lfo::ComputeSampleSquare() {
163   uint32_t threshold = static_cast<uint32_t>(parameter_ + 32768) << 16;
164   if (threshold < (phase_increment_ << 1)) {
165     threshold = phase_increment_ << 1;
166   } else if (~threshold < (phase_increment_ << 1)) {
167     threshold = ~(phase_increment_ << 1);
168   }
169   return phase_ < threshold ? 32767 : -32767;
170 }
171 
ComputeSampleSteps()172 int16_t Lfo::ComputeSampleSteps() {
173   uint16_t quantization_levels = 2 + (((parameter_ + 32768) * 15) >> 16);
174   uint16_t scale = 65535 / (quantization_levels - 1);
175   uint32_t phase = phase_;
176   uint32_t tri_phase = phase;
177   uint32_t tri = tri_phase < (1UL << 31) ? tri_phase << 1 : ~(tri_phase << 1);
178   return ((tri >> 16) * quantization_levels >> 16) * scale - 32768;
179 }
180 
ComputeSampleNoise()181 int16_t Lfo::ComputeSampleNoise() {
182   uint32_t phase = phase_;
183   if (phase < phase_increment_) {
184     value_ = next_value_;
185     next_value_ = Random::GetSample();
186   }
187   int16_t sample;
188   int32_t linear_interpolation = value_ + \
189       ((next_value_ - value_) * static_cast<int32_t>(phase >> 17) >> 15);
190   if (parameter_ < 0) {
191     int32_t balance = parameter_ + 32767;
192     sample = value_ + ((linear_interpolation - value_) * balance >> 15);
193   } else {
194     int16_t raised_cosine = Interpolate824(lut_raised_cosine, phase) >> 1;
195     int32_t smooth_interpolation = value_ + \
196         ((next_value_ - value_) * raised_cosine >> 15);
197     sample = linear_interpolation + \
198         ((smooth_interpolation - linear_interpolation) * parameter_ >> 15);
199   }
200   return sample;
201 }
202 
203 /* static */
204 Lfo::ComputeSampleFn Lfo::compute_sample_fn_table_[] = {
205   &Lfo::ComputeSampleSine,
206   &Lfo::ComputeSampleTriangle,
207   &Lfo::ComputeSampleSquare,
208   &Lfo::ComputeSampleSteps,
209   &Lfo::ComputeSampleNoise
210 };
211 
212 }  // namespace peaks
213