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