1 /*
2 ** Surge Synthesizer is Free and Open Source Software
3 **
4 ** Surge is made available under the Gnu General Public License, v3.0
5 ** https://www.gnu.org/licenses/gpl-3.0.en.html
6 **
7 ** Copyright 2004-2020 by various individuals as described by the Git transaction log
8 **
9 ** All source at: https://github.com/surge-synthesizer/surge.git
10 **
11 ** Surge was a commercial product from 2004-2018, with Copyright and ownership
12 ** in that period held by Claes Johanson at Vember Audio. Claes made Surge
13 ** open source in September 2018.
14 */
15 
16 #include "FM3Oscillator.h"
17 #include <cmath>
18 #include <algorithm>
19 
20 using namespace std;
21 
FM3Oscillator(SurgeStorage * storage,OscillatorStorage * oscdata,pdata * localcopy)22 FM3Oscillator::FM3Oscillator(SurgeStorage *storage, OscillatorStorage *oscdata, pdata *localcopy)
23     : Oscillator(storage, oscdata, localcopy)
24 {
25 }
26 
init(float pitch,bool is_display,bool nonzero_init_drift)27 void FM3Oscillator::init(float pitch, bool is_display, bool nonzero_init_drift)
28 {
29     phase =
30         (is_display || oscdata->retrigger.val.b) ? 0.f : (2.0 * M_PI * storage->rand_01() - M_PI);
31     lastoutput = 0.f;
32     driftLFO.init(nonzero_init_drift);
33     fb_val = 0.f;
34     AM.set_phase(phase);
35     RM1.set_phase(phase);
36     RM2.set_phase(phase);
37 }
38 
~FM3Oscillator()39 FM3Oscillator::~FM3Oscillator() {}
40 
process_block(float pitch,float drift,bool stereo,bool FM,float fmdepth)41 void FM3Oscillator::process_block(float pitch, float drift, bool stereo, bool FM, float fmdepth)
42 {
43     auto driftlfo = driftLFO.next() * drift;
44     fb_val = oscdata->p[fm3_feedback].get_extended(
45         localcopy[oscdata->p[fm3_feedback].param_id_in_scene].f);
46 
47     double omega = min(M_PI, (double)pitch_to_omega(pitch + driftlfo));
48 
49     auto m1 = oscdata->p[fm3_m1ratio].get_extended(
50         localcopy[oscdata->p[fm3_m1ratio].param_id_in_scene].f);
51 
52     if (m1 < 0)
53     {
54         m1 = -1.0 / m1;
55     }
56 
57     if (oscdata->p[fm3_m1ratio].absolute)
58     {
59         float f = localcopy[oscdata->p[fm3_m1ratio].param_id_in_scene].f;
60         float bpv = (f - 16.0) / 16.0;
61         auto note = 69 + 69 * bpv;
62         RM1.set_rate(min(M_PI, (double)pitch_to_omega(note)));
63     }
64     else
65     {
66         RM1.set_rate(min(M_PI, (double)pitch_to_omega(pitch + driftlfo) * m1));
67     }
68 
69     auto m2 = oscdata->p[fm3_m2ratio].get_extended(
70         localcopy[oscdata->p[fm3_m2ratio].param_id_in_scene].f);
71 
72     if (m2 < 0)
73     {
74         m2 = -1.0 / m2;
75     }
76 
77     if (oscdata->p[fm3_m2ratio].absolute)
78     {
79         float f = localcopy[oscdata->p[fm3_m2ratio].param_id_in_scene].f;
80         float bpv = (f - 16.0) / 16.0;
81         auto note = 69 + 69 * bpv;
82         RM2.set_rate(min(M_PI, (double)pitch_to_omega(note)));
83     }
84     else
85     {
86         RM2.set_rate(min(M_PI, (double)pitch_to_omega(pitch + driftlfo) * m2));
87     }
88 
89     AM.set_rate(min(M_PI, (double)pitch_to_omega(
90                               60.0 + localcopy[oscdata->p[fm3_m3freq].param_id_in_scene].f)));
91 
92     double d1 = localcopy[oscdata->p[fm3_m1amount].param_id_in_scene].f;
93     double d2 = localcopy[oscdata->p[fm3_m2amount].param_id_in_scene].f;
94     double d3 = localcopy[oscdata->p[fm3_m3amount].param_id_in_scene].f;
95 
96     RelModDepth1.newValue(32.0 * M_PI * d1 * d1 * d1);
97     RelModDepth2.newValue(32.0 * M_PI * d2 * d2 * d2);
98     AbsModDepth.newValue(32.0 * M_PI * d3 * d3 * d3);
99 
100     if (FM)
101     {
102         FMdepth.newValue(32.0 * M_PI * fmdepth * fmdepth * fmdepth);
103     }
104 
105     FeedbackDepth.newValue(abs(fb_val));
106 
107     for (int k = 0; k < BLOCK_SIZE_OS; k++)
108     {
109         RM1.process();
110         RM2.process();
111         AM.process();
112 
113         output[k] = phase + RelModDepth1.v * RM1.r + RelModDepth2.v * RM2.r + AbsModDepth.v * AM.r +
114                     lastoutput;
115 
116         if (FM)
117         {
118             output[k] += FMdepth.v * master_osc[k];
119         }
120 
121         output[k] = sin(output[k]);
122         lastoutput =
123             (fb_val < 0) ? output[k] * output[k] * FeedbackDepth.v : output[k] * FeedbackDepth.v;
124 
125         phase += omega;
126         if (phase > 2.0 * M_PI)
127         {
128             phase -= 2.0 * M_PI;
129         }
130 
131         RelModDepth1.process();
132         RelModDepth2.process();
133         AbsModDepth.process();
134 
135         if (FM)
136         {
137             FMdepth.process();
138         }
139 
140         FeedbackDepth.process();
141     }
142     if (stereo)
143     {
144         memcpy(outputR, output, sizeof(float) * BLOCK_SIZE_OS);
145     }
146 }
147 
init_ctrltypes()148 void FM3Oscillator::init_ctrltypes()
149 {
150     oscdata->p[fm3_m1amount].set_name("M1 Amount");
151     oscdata->p[fm3_m1amount].set_type(ct_percent);
152     if (oscdata->p[fm3_m1ratio].absolute)
153     {
154         oscdata->p[fm3_m1ratio].set_name("M1 Frequency");
155     }
156     else
157     {
158         oscdata->p[fm3_m1ratio].set_name("M1 Ratio");
159     }
160     oscdata->p[fm3_m1ratio].set_type(ct_fmratio);
161 
162     oscdata->p[fm3_m2amount].set_name("M2 Amount");
163     oscdata->p[fm3_m2amount].set_type(ct_percent);
164     if (oscdata->p[fm3_m2ratio].absolute)
165     {
166         oscdata->p[fm3_m2ratio].set_name("M2 Frequency");
167     }
168     else
169     {
170         oscdata->p[fm3_m2ratio].set_name("M2 Ratio");
171     }
172     oscdata->p[fm3_m2ratio].set_type(ct_fmratio);
173 
174     oscdata->p[fm3_m3amount].set_name("M3 Amount");
175     oscdata->p[fm3_m3amount].set_type(ct_percent);
176     oscdata->p[fm3_m3freq].set_name("M3 Frequency");
177     oscdata->p[fm3_m3freq].set_type(ct_freq_audible);
178 
179     oscdata->p[fm3_feedback].set_name("Feedback");
180     oscdata->p[fm3_feedback].set_type(ct_osc_feedback_negative);
181 }
init_default_values()182 void FM3Oscillator::init_default_values()
183 {
184     oscdata->p[fm3_m1amount].val.f = 0.f;
185     if (oscdata->p[fm3_m1ratio].absolute || oscdata->p[fm3_m1ratio].extend_range)
186     {
187         oscdata->p[fm3_m1ratio].val_default.f = 16.f;
188     }
189     else
190     {
191         oscdata->p[fm3_m1ratio].val.f = 1.f;
192     }
193     oscdata->p[fm3_m2amount].val.f = 0.f;
194     if (oscdata->p[fm3_m1ratio].absolute || oscdata->p[fm3_m1ratio].extend_range)
195     {
196         oscdata->p[fm3_m2ratio].val.f = 16.f;
197     }
198     else
199     {
200         oscdata->p[fm3_m2ratio].val.f = 1.f;
201     }
202     oscdata->p[fm3_m3amount].val.f = 0.f;
203     oscdata->p[fm3_m3freq].val.f = 0.f;
204     oscdata->p[fm3_feedback].val.f = 0.f;
205 }
206 
handleStreamingMismatches(int streamingRevision,int currentSynthStreamingRevision)207 void FM3Oscillator::handleStreamingMismatches(int streamingRevision,
208                                               int currentSynthStreamingRevision)
209 {
210     if (streamingRevision <= 12)
211     {
212         oscdata->p[fm3_feedback].set_type(ct_osc_feedback);
213     }
214 
215     if (streamingRevision <= 13)
216     {
217         oscdata->p[fm3_m1ratio].absolute = false;
218         oscdata->p[fm3_m2ratio].absolute = false;
219     }
220 
221     if (streamingRevision <= 15)
222     {
223         oscdata->retrigger.val.b = true;
224     }
225 }
226