1 /*
2 * mdaDX10Processor.cpp
3 * mda-vst3
4 *
5 * Created by Arne Scheffler on 6/14/08.
6 *
7 * mda VST Plug-ins
8 *
9 * Copyright (c) 2008 Paul Kellett
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14 *
15 */
16
17 #include "mdaDX10Processor.h"
18 #include "mdaDX10Controller.h"
19
20 #include <cmath>
21
22 namespace Steinberg {
23 namespace Vst {
24 namespace mda {
25
26 #define NOUTS 2 //number of outputs
27 #define SILENCE 0.0003f //voice choking
28
29 float DX10Processor::programParams[][NPARAMS] = {
30 {0.000f, 0.650f, 0.441f, 0.842f, 0.329f, 0.230f, 0.800f, 0.050f, 0.800f, 0.900f, 0.000f, 0.500f, 0.500f, 0.447f, 0.000f, 0.414f },
31 {0.000f, 0.500f, 0.100f, 0.671f, 0.000f, 0.441f, 0.336f, 0.243f, 0.800f, 0.500f, 0.000f, 0.500f, 0.500f, 0.178f, 0.000f, 0.500f },
32 {0.000f, 0.700f, 0.400f, 0.230f, 0.184f, 0.270f, 0.474f, 0.224f, 0.800f, 0.974f, 0.250f, 0.500f, 0.500f, 0.428f, 0.836f, 0.500f },
33 {0.000f, 0.700f, 0.400f, 0.320f, 0.217f, 0.599f, 0.670f, 0.309f, 0.800f, 0.500f, 0.263f, 0.507f, 0.500f, 0.276f, 0.638f, 0.526f },
34 {0.400f, 0.600f, 0.650f, 0.760f, 0.000f, 0.390f, 0.250f, 0.160f, 0.900f, 0.500f, 0.362f, 0.500f, 0.500f, 0.401f, 0.296f, 0.493f },
35 {0.000f, 0.342f, 0.000f, 0.280f, 0.000f, 0.880f, 0.100f, 0.408f, 0.740f, 0.000f, 0.000f, 0.600f, 0.500f, 0.842f, 0.651f, 0.500f },
36 {0.000f, 0.400f, 0.100f, 0.360f, 0.000f, 0.875f, 0.160f, 0.592f, 0.800f, 0.500f, 0.000f, 0.500f, 0.500f, 0.303f, 0.868f, 0.500f },
37 {0.000f, 0.500f, 0.704f, 0.230f, 0.000f, 0.151f, 0.750f, 0.493f, 0.770f, 0.500f, 0.000f, 0.400f, 0.500f, 0.421f, 0.632f, 0.500f },
38 {0.600f, 0.990f, 0.400f, 0.320f, 0.283f, 0.570f, 0.300f, 0.050f, 0.240f, 0.500f, 0.138f, 0.500f, 0.500f, 0.283f, 0.822f, 0.500f },
39 {0.000f, 0.500f, 0.650f, 0.368f, 0.651f, 0.395f, 0.550f, 0.257f, 0.900f, 0.500f, 0.300f, 0.800f, 0.500f, 0.000f, 0.414f, 0.500f },
40 {0.000f, 0.700f, 0.520f, 0.230f, 0.197f, 0.520f, 0.720f, 0.280f, 0.730f, 0.500f, 0.250f, 0.500f, 0.500f, 0.336f, 0.428f, 0.500f },
41 {0.000f, 0.240f, 0.000f, 0.390f, 0.000f, 0.880f, 0.100f, 0.600f, 0.740f, 0.500f, 0.000f, 0.500f, 0.500f, 0.526f, 0.480f, 0.500f },
42 {0.000f, 0.500f, 0.700f, 0.160f, 0.000f, 0.158f, 0.349f, 0.000f, 0.280f, 0.900f, 0.000f, 0.618f, 0.500f, 0.401f, 0.000f, 0.500f },
43 {0.000f, 0.500f, 0.100f, 0.390f, 0.000f, 0.490f, 0.250f, 0.250f, 0.800f, 0.500f, 0.000f, 0.500f, 0.500f, 0.263f, 0.145f, 0.500f },
44 {0.000f, 0.300f, 0.507f, 0.480f, 0.730f, 0.000f, 0.100f, 0.303f, 0.730f, 1.000f, 0.000f, 0.600f, 0.500f, 0.579f, 0.000f, 0.500f },
45 {0.000f, 0.300f, 0.500f, 0.320f, 0.000f, 0.467f, 0.079f, 0.158f, 0.500f, 0.500f, 0.000f, 0.400f, 0.500f, 0.151f, 0.020f, 0.500f },
46 {0.000f, 0.990f, 0.100f, 0.230f, 0.000f, 0.000f, 0.200f, 0.450f, 0.800f, 0.000f, 0.112f, 0.600f, 0.500f, 0.711f, 0.000f, 0.401f },
47 {0.280f, 0.990f, 0.280f, 0.230f, 0.000f, 0.180f, 0.400f, 0.300f, 0.800f, 0.500f, 0.000f, 0.400f, 0.500f, 0.217f, 0.480f, 0.500f },
48 {0.220f, 0.990f, 0.250f, 0.170f, 0.000f, 0.240f, 0.310f, 0.257f, 0.900f, 0.757f, 0.000f, 0.500f, 0.500f, 0.697f, 0.803f, 0.500f },
49 {0.220f, 0.990f, 0.250f, 0.450f, 0.070f, 0.240f, 0.310f, 0.360f, 0.900f, 0.500f, 0.211f, 0.500f, 0.500f, 0.184f, 0.000f, 0.414f },
50 {0.697f, 0.990f, 0.421f, 0.230f, 0.138f, 0.750f, 0.390f, 0.513f, 0.800f, 0.316f, 0.467f, 0.678f, 0.500f, 0.743f, 0.757f, 0.487f },
51 {0.000f, 0.400f, 0.000f, 0.280f, 0.125f, 0.474f, 0.250f, 0.100f, 0.500f, 0.500f, 0.000f, 0.400f, 0.500f, 0.579f, 0.592f, 0.500f },
52 {0.230f, 0.500f, 0.100f, 0.395f, 0.000f, 0.388f, 0.092f, 0.250f, 0.150f, 0.500f, 0.200f, 0.200f, 0.500f, 0.178f, 0.822f, 0.500f },
53 {0.000f, 0.600f, 0.400f, 0.230f, 0.000f, 0.450f, 0.320f, 0.050f, 0.900f, 0.500f, 0.000f, 0.200f, 0.500f, 0.520f, 0.105f, 0.500f },
54 {0.000f, 0.600f, 0.400f, 0.170f, 0.145f, 0.290f, 0.350f, 0.100f, 0.900f, 0.500f, 0.000f, 0.400f, 0.500f, 0.441f, 0.309f, 0.500f },
55 {0.000f, 0.600f, 0.490f, 0.170f, 0.151f, 0.099f, 0.400f, 0.000f, 0.900f, 0.500f, 0.000f, 0.400f, 0.500f, 0.118f, 0.013f, 0.500f },
56 {0.000f, 0.600f, 0.100f, 0.320f, 0.000f, 0.350f, 0.670f, 0.100f, 0.150f, 0.500f, 0.000f, 0.200f, 0.500f, 0.303f, 0.730f, 0.500f },
57 {0.300f, 0.500f, 0.400f, 0.280f, 0.000f, 0.180f, 0.540f, 0.000f, 0.700f, 0.500f, 0.000f, 0.400f, 0.500f, 0.296f, 0.033f, 0.500f },
58 {0.300f, 0.500f, 0.400f, 0.360f, 0.000f, 0.461f, 0.070f, 0.070f, 0.700f, 0.500f, 0.000f, 0.400f, 0.500f, 0.546f, 0.467f, 0.500f },
59 {0.000f, 0.500f, 0.500f, 0.280f, 0.000f, 0.330f, 0.200f, 0.000f, 0.700f, 0.500f, 0.000f, 0.500f, 0.500f, 0.151f, 0.079f, 0.500f },
60 {0.000f, 0.500f, 0.000f, 0.000f, 0.240f, 0.580f, 0.630f, 0.000f, 0.000f, 0.500f, 0.000f, 0.600f, 0.500f, 0.816f, 0.243f, 0.500f },
61 {0.000f, 0.355f, 0.350f, 0.000f, 0.105f, 0.000f, 0.000f, 0.200f, 0.500f, 0.500f, 0.000f, 0.645f, 0.500f, 1.000f, 0.296f, 0.500f }
62 };
63
64 //-----------------------------------------------------------------------------
65 #ifdef SMTG_MDA_VST2_COMPATIBILITY
66 FUID DX10Processor::uid (0x5653544D, 0x4441786D, 0x64612064, 0x78313000);
67 #else
68 FUID DX10Processor::uid (0xF8713648, 0xE2444174, 0x8AAA3B62, 0xA77F9E2D);
69 #endif
70
71 //-----------------------------------------------------------------------------
DX10Processor()72 DX10Processor::DX10Processor ()
73 : currentProgram (0)
74 {
75 setControllerClass (DX10Controller::uid);
76 allocParameters (NPARAMS);
77 }
78
79 //-----------------------------------------------------------------------------
~DX10Processor()80 DX10Processor::~DX10Processor ()
81 {
82 }
83
84 //-----------------------------------------------------------------------------
initialize(FUnknown * context)85 tresult PLUGIN_API DX10Processor::initialize (FUnknown* context)
86 {
87 tresult res = BaseProcessor::initialize (context);
88 if (res == kResultTrue)
89 {
90 addEventInput (USTRING("MIDI in"), 1);
91 addAudioOutput (USTRING("Stereo Out"), SpeakerArr::kStereo);
92
93 const float initParams[] = { 0.000f, 0.650f, 0.441f, 0.842f, 0.329f, 0.230f, 0.800f, 0.050f, 0.800f, 0.900f, 0.000f, 0.500f, 0.500f, 0.447f, 0.000f, 0.414f};
94 for (int32 i = 0; i < NPARAMS; i++)
95 params[i] = initParams[i];
96
97 //initialise...
98 for(int32 i = 0; i<NVOICES; i++)
99 {
100 memset (&voice[i], 0, sizeof (VOICE));
101 voice[i].env = 0.0f;
102 voice[i].car = voice[i].dcar = 0.0f;
103 voice[i].mod0 = voice[i].mod1 = voice[i].dmod = 0.0f;
104 voice[i].cdec = 0.99f; //all notes off
105 }
106 notes[0] = EVENTS_DONE;
107 lfo0 = dlfo = modwhl = 0.0f;
108 lfo1 = pbend = 1.0f;
109 volume = 0.0035f;
110 sustain = activevoices = 0;
111 K = 0;
112
113 recalculate ();
114 }
115 return res;
116 }
117
118 //-----------------------------------------------------------------------------
terminate()119 tresult PLUGIN_API DX10Processor::terminate ()
120 {
121 return BaseProcessor::terminate ();
122 }
123
124 //-----------------------------------------------------------------------------
setActive(TBool state)125 tresult PLUGIN_API DX10Processor::setActive (TBool state)
126 {
127 if (state)
128 {
129 lfo0 = 0.0f;
130 lfo1 = 1.0f; //reset LFO phase
131 }
132 return BaseProcessor::setActive (state);
133 }
134
135 //-----------------------------------------------------------------------------
setParameter(ParamID index,ParamValue newValue,int32 sampleOffset)136 void DX10Processor::setParameter (ParamID index, ParamValue newValue, int32 sampleOffset)
137 {
138 if (index < NPARAMS)
139 BaseProcessor::setParameter (index, newValue, sampleOffset);
140 else if (index == BaseController::kPresetParam) // program change
141 {
142 currentProgram = std::min<int32> (kNumPrograms - 1, (int32)(newValue * kNumPrograms));
143 const float* newParams = programParams[currentProgram];
144 if (newParams)
145 {
146 for (int32 i = 0; i < NPARAMS; i++)
147 params[i] = newParams[i];
148 }
149 }
150 else if (index == BaseController::kModWheelParam) // mod wheel
151 {
152 newValue *= 127.;
153 modwhl = 0.00000005f * (float)(newValue * newValue);
154 }
155 else if (index == BaseController::kPitchBendParam) // pitch bend
156 {
157 if (newValue <= 1)
158 pbend = (newValue - 0.5) * 0x2000;
159 else
160 pbend = newValue;
161 if (pbend>0.0f) pbend = 1.0f + 0.000014951f * pbend;
162 else pbend = 1.0f + 0.000013318f * pbend;
163 }
164 }
165
166 //-----------------------------------------------------------------------------
setCurrentProgram(Steinberg::uint32 val)167 void DX10Processor::setCurrentProgram (Steinberg::uint32 val)
168 {
169 currentProgram = val;
170 }
171
172 //-----------------------------------------------------------------------------
setCurrentProgramNormalized(ParamValue val)173 void DX10Processor::setCurrentProgramNormalized (ParamValue val)
174 {
175 setCurrentProgram (std::min<int32> (kNumPrograms - 1, (int32)(val * kNumPrograms)));
176 }
177
178 //-----------------------------------------------------------------------------
doProcessing(ProcessData & data)179 void DX10Processor::doProcessing (ProcessData& data)
180 {
181 int32 sampleFrames = data.numSamples;
182
183 float* out1 = data.outputs[0].channelBuffers32[0];
184 float* out2 = data.outputs[0].channelBuffers32[1];
185
186 int32 event=0, frame=0, frames, v;
187 float o, x, e, mw=MW, w=rich, m = modmix;
188 int32 k=K;
189
190 if (activevoices>0 || notes[event]<sampleFrames) //detect & bypass completely empty blocks
191 {
192 while (frame<sampleFrames)
193 {
194 frames = notes[event++];
195 if (frames>sampleFrames) frames = sampleFrames;
196 frames -= frame;
197 frame += frames;
198
199 while (--frames>=0) //would be faster with voice loop outside frame loop!
200 { //but then each voice would need it's own LFO...
201 VOICE *V = voice;
202 o = 0.0f;
203
204 if (--k<0)
205 {
206 lfo0 += dlfo * lfo1; //sine LFO
207 lfo1 -= dlfo * lfo0;
208 mw = lfo1 * (modwhl + vibrato);
209 k=100;
210 }
211
212 for(v=0; v<NVOICES; v++) //for each voice
213 {
214 e = V->env;
215 if (e > SILENCE) //**** this is the synth ****
216 {
217 V->env = e * V->cdec; //decay & release
218 V->cenv += V->catt * (e - V->cenv); //attack
219
220 x = V->dmod * V->mod0 - V->mod1; //could add more modulator blocks like
221 V->mod1 = V->mod0; //this for a wider range of FM sounds
222 V->mod0 = x;
223 V->menv += V->mdec * (V->mlev - V->menv);
224
225 x = V->car + V->dcar + x * V->menv + mw; //carrier phase
226 while (x > 1.0f) x -= 2.0f; //wrap phase
227 while (x < -1.0f) x += 2.0f;
228 V->car = x;
229 o += V->cenv * (m * V->mod1 + (x + x * x * x * (w * x * x - 1.0f - w)));
230 } //amp env //mod thru-mix //5th-order sine approximation
231
232 /// xx = x * x;
233 /// x + x + x * xx * (xx - 3.0f);
234
235 V++;
236 }
237 *out1++ = o;
238 *out2++ = o;
239 }
240
241 if (frame<sampleFrames) //next note on/off
242 {
243 int32 note = notes[event++];
244 int32 vel = notes[event++];
245 noteOn(note, vel);
246 }
247 }
248
249 activevoices = NVOICES;
250 for(v=0; v<NVOICES; v++)
251 {
252 if (voice[v].env < SILENCE) //choke voices that have finished
253 {
254 voice[v].env = voice[v].cenv = 0.0f;
255 activevoices--;
256 }
257 if (voice[v].menv < SILENCE) voice[v].menv = voice[v].mlev = 0.0f;
258 }
259 }
260 else //completely empty block
261 {
262 while (--sampleFrames >= 0)
263 {
264 *out1++ = 0.0f;
265 *out2++ = 0.0f;
266 }
267 data.outputs[0].silenceFlags = 3;
268 }
269 K=k; MW=mw; //remember these so vibrato speed not buffer size dependant!
270 notes[0] = EVENTS_DONE;
271 }
272
273 //-----------------------------------------------------------------------------
processEvents(IEventList * events)274 void DX10Processor::processEvents (IEventList* events)
275 {
276 if (events)
277 {
278 int32 npos=0;
279 int32 count = events->getEventCount ();
280 for (int32 i = 0; i < count; i++)
281 {
282 Event e;
283 events->getEvent (i, e);
284 switch (e.type)
285 {
286 case Event::kNoteOnEvent:
287 {
288 notes[npos++] = e.sampleOffset;
289 notes[npos++] = e.noteOn.pitch;
290 notes[npos++] = e.noteOn.velocity * 127;
291 break;
292 }
293 case Event::kNoteOffEvent:
294 {
295 notes[npos++] = e.sampleOffset;
296 notes[npos++] = e.noteOff.pitch;
297 notes[npos++] = 0;
298 break;
299 }
300 default:
301 continue;
302 }
303 if (npos > EVENTBUFFER) npos -= 3; //discard events if buffer full!!
304 }
305 notes[npos] = EVENTS_DONE;
306 }
307 }
308
309 //-----------------------------------------------------------------------------
noteOn(int32 note,int32 velocity)310 void DX10Processor::noteOn(int32 note, int32 velocity)
311 {
312 float l = 1.0f;
313 int32 v, vl=0;
314
315 if (velocity>0)
316 {
317 for(v=0; v<NVOICES; v++) //find quietest voice
318 {
319 if (voice[v].env<l) { l=voice[v].env; vl=v; }
320 }
321
322 l = (float)exp (0.05776226505f * ((float)note + params[12] + params[12] - 1.0f));
323 voice[vl].note = note; //fine tuning
324 voice[vl].car = 0.0f;
325 voice[vl].dcar = tune * pbend * l; //pitch bend not updated during note as a bit tricky...
326
327 if (l>50.0f) l = 50.0f; //key tracking
328 l *= (64.0f + velsens * (velocity - 64)); //vel sens
329 voice[vl].menv = depth * l;
330 voice[vl].mlev = dept2 * l;
331 voice[vl].mdec = mdec;
332
333 voice[vl].dmod = ratio * voice[vl].dcar; //sine oscillator
334 voice[vl].mod0 = 0.0f;
335 voice[vl].mod1 = (float)sin(voice[vl].dmod);
336 voice[vl].dmod = 2.0f * (float)cos(voice[vl].dmod);
337 //scale volume with richness
338 voice[vl].env = (1.5f - params[13]) * volume * (velocity + 10);
339 voice[vl].catt = catt;
340 voice[vl].cenv = 0.0f;
341 voice[vl].cdec = cdec;
342 }
343 else //note off
344 {
345 for(v=0; v<NVOICES; v++) if (voice[v].note==note) //any voices playing that note?
346 {
347 if (sustain==0)
348 {
349 voice[v].cdec = crel; //release phase
350 voice[v].env = voice[v].cenv;
351 voice[v].catt = 1.0f;
352 voice[v].mlev = 0.0f;
353 voice[v].mdec = mrel;
354 }
355 else voice[v].note = SUSTAIN;
356 }
357 }
358 }
359
360 //-----------------------------------------------------------------------------
recalculate()361 void DX10Processor::recalculate ()
362 {
363 float ifs = 1.0f / (float)getSampleRate ();
364
365 tune = (float)(8.175798915644 * ifs * pow (2.0, floor(params[11] * 6.9) - 2.0));
366
367 rati = params[3];
368 rati = (float)floor(40.1f * rati * rati);
369 if (params[4]<0.5f)
370 ratf = 0.2f * params[4] * params[4];
371 else
372 switch ((int32)(8.9f * params[4]))
373 {
374 case 4: ratf = 0.25f; break;
375 case 5: ratf = 0.33333333f; break;
376 case 6: ratf = 0.50f; break;
377 case 7: ratf = 0.66666667f; break;
378 default: ratf = 0.75f;
379 }
380 ratio = 1.570796326795f * (rati + ratf);
381
382 depth = 0.0002f * params[5] * params[5];
383 dept2 = 0.0002f * params[7] * params[7];
384
385 velsens = params[9];
386 vibrato = 0.001f * params[10] * params[10];
387
388 catt = 1.0f - (float)exp (-ifs * exp (8.0 - 8.0 * params[0]));
389 if (params[1]>0.98f) cdec = 1.0f; else
390 cdec = (float)exp (-ifs * exp (5.0 - 8.0 * params[1]));
391 crel = (float)exp (-ifs * exp (5.0 - 5.0 * params[2]));
392 mdec = 1.0f - (float)exp (-ifs * exp (6.0 - 7.0 * params[6]));
393 mrel = 1.0f - (float)exp (-ifs * exp (5.0 - 8.0 * params[8]));
394
395 rich = 0.50f - 3.0f * params[13] * params[13];
396 //rich = -1.0f + 2 * params[13];
397 modmix = 0.25f * params[14] * params[14];
398 dlfo = 628.3f * ifs * 25.0f * params[15] * params[15]; //these params not in original DX10
399 }
400
401 }}} // namespaces
402
403