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