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 // Multi-stage envelope. 28 29 #ifndef STAGES_SEGMENT_GENERATOR_H_ 30 #define STAGES_SEGMENT_GENERATOR_H_ 31 32 #include "stmlib/dsp/delay_line.h" 33 #include "stmlib/dsp/hysteresis_quantizer.h" 34 #include "stmlib/utils/gate_flags.h" 35 36 #include "stages/delay_line_16_bits.h" 37 38 #include "stages/ramp_extractor.h" 39 40 namespace stages { 41 42 const float kSampleRate = 31250.0f; 43 44 // Each segment generator can handle up to 36 segments. That's a bit of a waste 45 // of RAM because the 6 generators running on a module will never have to deal 46 // with 36 segments each. But it was a bit too much to have a shared pool of 47 // pre-allocated Segments shared by all SegmentGenerators! 48 const int kMaxNumSegments = 36; 49 50 const size_t kMaxDelay = 768; 51 52 #define DECLARE_PROCESS_FN(X) void Process ## X \ 53 (const stmlib::GateFlags* gate_flags, Output* out, size_t size); 54 55 namespace segment { 56 57 // High level descriptions / parameters. 58 enum Type { 59 TYPE_RAMP = 0, 60 TYPE_STEP = 1, 61 TYPE_HOLD = 2, 62 }; 63 64 struct Configuration { 65 Type type; 66 bool loop; 67 }; 68 69 struct Parameters { 70 // Segment type | Main | Secondary 71 // 72 // RAMP | Time | Shape (or level if followed by RAMP) 73 // HOLD | Level | Time 74 // STEP | Level | Shape (portamento) 75 float primary; 76 float secondary; 77 }; 78 79 } // namespace segment 80 81 class SegmentGenerator { 82 public: SegmentGenerator()83 SegmentGenerator() { } ~SegmentGenerator()84 ~SegmentGenerator() { } 85 86 struct Output { 87 float value; 88 float phase; 89 int32_t segment; 90 }; 91 92 struct Segment { 93 // Low level state. 94 95 float* start; // NULL if we should start from the current value. 96 float* time; // NULL if the segment has infinite duration. 97 float* curve; 98 float* portamento; 99 float* end; 100 float* phase; 101 102 int8_t if_rising; 103 int8_t if_falling; 104 int8_t if_complete; 105 }; 106 107 void Init(); 108 109 typedef void (SegmentGenerator::*ProcessFn)( 110 const stmlib::GateFlags* gate_flags, Output* out, size_t size); 111 Process(const stmlib::GateFlags * gate_flags,Output * out,size_t size)112 bool Process( 113 const stmlib::GateFlags* gate_flags, Output* out, size_t size) { 114 (this->*process_fn_)(gate_flags, out, size); 115 return active_segment_ == 0; 116 } 117 118 void Configure( 119 bool has_trigger, 120 const segment::Configuration* segment_configuration, 121 int num_segments); 122 ConfigureSingleSegment(bool has_trigger,segment::Configuration segment_configuration)123 inline void ConfigureSingleSegment( 124 bool has_trigger, 125 segment::Configuration segment_configuration) { 126 int i = has_trigger ? 2 : 0; 127 i += segment_configuration.loop ? 1 : 0; 128 i += int(segment_configuration.type) * 4; 129 process_fn_ = process_fn_table_[i]; 130 num_segments_ = 1; 131 } 132 ConfigureSlave(int i)133 inline void ConfigureSlave(int i) { 134 monitored_segment_ = i; 135 process_fn_ = &SegmentGenerator::ProcessSlave; 136 num_segments_ = 0; 137 } 138 set_segment_parameters(int index,float primary,float secondary)139 void set_segment_parameters(int index, float primary, float secondary) { 140 // assert (primary >= -1.0f && primary <= 2.0f) 141 // assert (secondary >= 0.0f && secondary <= 1.0f) 142 parameters_[index].primary = primary; 143 parameters_[index].secondary = secondary; 144 } 145 num_segments()146 inline int num_segments() { 147 return num_segments_; 148 } 149 150 private: 151 // Process function for the general case. 152 DECLARE_PROCESS_FN(MultiSegment); 153 DECLARE_PROCESS_FN(DecayEnvelope); 154 DECLARE_PROCESS_FN(TimedPulseGenerator); 155 DECLARE_PROCESS_FN(GateGenerator); 156 DECLARE_PROCESS_FN(SampleAndHold); 157 DECLARE_PROCESS_FN(TapLFO); 158 DECLARE_PROCESS_FN(FreeRunningLFO); 159 DECLARE_PROCESS_FN(Delay); 160 DECLARE_PROCESS_FN(Portamento); 161 DECLARE_PROCESS_FN(Zero); 162 DECLARE_PROCESS_FN(ClockedSampleAndHold); 163 DECLARE_PROCESS_FN(Slave); 164 165 void ShapeLFO(float shape, Output* in_out, size_t size); 166 float WarpPhase(float t, float curve) const; 167 float RateToFrequency(float rate) const; 168 float PortamentoRateToLPCoefficient(float rate) const; 169 170 float phase_; 171 float aux_; 172 float previous_delay_sample_; 173 174 float start_; 175 float value_; 176 float lp_; 177 float primary_; 178 179 float zero_; 180 float half_; 181 float one_; 182 183 int active_segment_; 184 int monitored_segment_; 185 int retrig_delay_; 186 187 int num_segments_; 188 189 ProcessFn process_fn_; 190 191 RampExtractor ramp_extractor_; 192 stmlib::HysteresisQuantizer ramp_division_quantizer_; 193 194 Segment segments_[kMaxNumSegments + 1]; // There's a sentinel! 195 segment::Parameters parameters_[kMaxNumSegments]; 196 197 DelayLine16Bits<kMaxDelay> delay_line_; 198 stmlib::DelayLine<stmlib::GateFlags, 128> gate_delay_; 199 200 static ProcessFn process_fn_table_[12]; 201 202 DISALLOW_COPY_AND_ASSIGN(SegmentGenerator); 203 }; 204 205 } // namespace stages 206 207 #endif // STAGES_SEGMENT_GENERATOR_H_ 208