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