1 /*
2  *  mdaLeslieProcessor.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 "mdaLeslieProcessor.h"
18 #include "mdaLeslieController.h"
19 
20 #include <math.h>
21 
22 namespace Steinberg {
23 namespace Vst {
24 namespace mda {
25 
26 //-----------------------------------------------------------------------------
27 FUID LeslieProcessor::uid (0xFBD3AD80, 0x9E2847E0, 0xB87CDEC3, 0x5C0469B1);
28 
29 //-----------------------------------------------------------------------------
30 LeslieProcessor::LeslieProcessor ()
31 {
32 	setControllerClass (LeslieController::uid);
33 	allocParameters (9);
34 }
35 
36 //-----------------------------------------------------------------------------
37 LeslieProcessor::~LeslieProcessor ()
38 {
39 }
40 
41 //-----------------------------------------------------------------------------
42 tresult PLUGIN_API LeslieProcessor::initialize (FUnknown* context)
43 {
44 	tresult res = BaseProcessor::initialize (context);
45 	if (res == kResultTrue)
46 	{
47 		addAudioInput (USTRING("Stereo In"), SpeakerArr::kStereo);
48 		addAudioOutput (USTRING("Stereo Out"), SpeakerArr::kStereo);
49 
50 		params[LeslieController::kParam0] = 0.66f;
51 		params[LeslieController::kParam7] = 0.50f;
52 		params[LeslieController::kParam6] = 0.48f;
53 		params[LeslieController::kParam3] = 0.70f;
54 		params[LeslieController::kParam4] = 0.60f;
55 		params[LeslieController::kParam5] = 0.70f;
56 		params[LeslieController::kParam2] = 0.50f;
57 		params[LeslieController::kParam1] = 0.50f;
58 		params[LeslieController::kParam8] = 0.60f;
59 
60 		size = 256; hpos = 0;
61 		hbuf = new float[size];
62 		fbuf1 = fbuf2 = 0.0f;
63 		twopi = 6.2831853f;
64 		chp = dchp = clp = dclp = shp = dshp = slp = dslp = 0.0f;
65 
66 		lspd = 0.0f; hspd = 0.0f;
67 		lphi = 0.0f; hphi = 1.6f;
68 
69 		recalculate ();
70 	}
71 	return res;
72 }
73 
74 //-----------------------------------------------------------------------------
75 tresult PLUGIN_API LeslieProcessor::terminate ()
76 {
77 	if (hbuf) delete [] hbuf;
78 	hbuf = 0;
79 	return BaseProcessor::terminate ();
80 }
81 
82 //-----------------------------------------------------------------------------
83 tresult PLUGIN_API LeslieProcessor::setActive (TBool state)
84 {
85 	if (state)
86 		memset (hbuf, 0, size * sizeof (float));
87 	return BaseProcessor::setActive (state);
88 }
89 
90 //-----------------------------------------------------------------------------
91 void LeslieProcessor::doProcessing (ProcessData& data)
92 {
93 	int32 sampleFrames = data.numSamples;
94 
95 	float* in1 = data.inputs[0].channelBuffers32[0];
96 	float* in2 = data.inputs[0].channelBuffers32[1];
97 	float* out1 = data.outputs[0].channelBuffers32[0];
98 	float* out2 = data.outputs[0].channelBuffers32[1];
99 
100 	float a, c, d, g=gain, h, l;
101 	float fo=filo, fb1=fbuf1, fb2=fbuf2;
102 	float hl=hlev, hs=hspd, ht, hm=hmom, hp=hphi, hw=hwid, hd=hdep;
103 	float ll=llev, ls=lspd, lt, lm=lmom, lp=lphi, lw=lwid;
104 	float hint, k0=0.03125f, k1=32.f; //k0 = 1/k1
105 	int32  hdd, hdd2, k=0, hps=hpos;
106 
107 	ht=hset*(1.f-hm); //target speeds
108 	lt=lset*(1.f-lm);
109 
110 	chp = (float)cos(hp); chp *= chp * chp; //set LFO values
111 	clp = (float)cos(lp);
112 	shp = (float)sin(hp);
113 	slp = (float)sin(lp);
114 
115 	--in1;
116 	--in2;
117 	--out1;
118 	--out2;
119 	while (--sampleFrames >= 0)
120 	{
121 		a = *++in1 + *++in2; //mono input
122 
123 		if (k) k--; else //linear piecewise approx to LFO waveforms
124 		{
125 			ls = (lm * ls) + lt; //tend to required speed
126 			hs = (hm * hs) + ht;
127 			lp += k1 * ls;
128 			hp += k1 * hs;
129 
130 			dchp = (float)cos(hp + k1*hs);
131 			dchp = k0 * (dchp * dchp * dchp - chp); //sin^3 level mod
132 			dclp = k0 * ((float)cos(lp + k1*ls) - clp);
133 			dshp = k0 * ((float)sin(hp + k1*hs) - shp);
134 			dslp = k0 * ((float)sin(lp + k1*ls) - slp);
135 
136 			k= (int32)k1;
137 		}
138 
139 		fb1 = fo * (fb1 - a) + a; //crossover
140 		fb2 = fo * (fb2 - fb1) + fb1;
141 		h = (g - hl * chp) * (a - fb2); //volume
142 		l = (g - ll * clp) * fb2;
143 
144 		if (hps>0) hps--; else hps=200;  //delay input pos
145 		hint = hps + hd * (1.0f + chp); //delay output pos
146 		hdd = (int)hint;
147 		hint = hint - hdd; //linear intrpolation
148 		hdd2 = hdd + 1;
149 		if (hdd>199) { if (hdd>200) hdd -= 201; hdd2 -= 201; }
150 
151 		*(hbuf + hps) = h; //delay input
152 		a = *(hbuf + hdd);
153 		h += a + hint * ( *(hbuf + hdd2) - a); //delay output
154 
155 		c = l + h;
156 		d = l + h;
157 		h *= hw * shp;
158 		l *= lw * slp;
159 		d += l - h;
160 		c += h - l;
161 
162 		*++out1 = c; //output
163 		*++out2 = d;
164 
165 		chp += dchp;
166 		clp += dclp;
167 		shp += dshp;
168 		slp += dslp;
169 	}
170 	lspd = ls;
171 	hspd = hs;
172 	hpos = hps;
173 	lphi = (float)fmod(lp+(k1 -k)*ls,twopi);
174 	hphi = (float)fmod(hp+(k1 -k)*hs,twopi);
175 	if (fabs (fb1)>1.0e-10) fbuf1=fb1; else fbuf1=0.0f; //catch denormals
176 	if (fabs (fb2)>1.0e-10) fbuf2=fb2; else fbuf2=0.0f;
177 }
178 
179 //-----------------------------------------------------------------------------
180 void LeslieProcessor::recalculate ()
181 {
182 	float ifs = 1.0f / (float)getSampleRate ();
183 	float spd = twopi * ifs * 2.0f * params[LeslieController::kParam8];
184 
185 	filo = 1.f - (float)pow (10.0f, (float)(params[LeslieController::kParam6] * (2.27f - 0.54f * params[LeslieController::kParam6]) - 1.92f));
186 
187 	switch ((int)(params[LeslieController::kParam0]*2.))
188 	{
189 		case 0:
190 		{
191 			lset = 0.00f; hset = 0.00f;
192 			lmom = 0.12f; hmom = 0.10f;
193 			break;
194 		}
195 		case 1:
196 		{
197 			lset = 0.49f; hset = 0.66f;
198 			lmom = 0.27f; hmom = 0.18f;
199 			break;
200 		}
201 		case 2:
202 		{
203 			lset = 5.31f; hset = 6.40f;
204 			lmom = 0.14f; hmom = 0.09f;
205 			break;
206 		}
207 	}
208 
209 	hmom = (float)pow (10.0f, -ifs / hmom);
210 	lmom = (float)pow (10.0f, -ifs / lmom);
211 	hset *= spd;
212 	lset *= spd;
213 
214 	gain = 0.4f * (float)pow (10.0f, (float)(2.0f * params[LeslieController::kParam7] - 1.0f));
215 	lwid = params[LeslieController::kParam1] * params[LeslieController::kParam1];
216 	llev = gain * 0.9f * params[LeslieController::kParam2] * params[LeslieController::kParam2];
217 	hwid = params[LeslieController::kParam3] * params[LeslieController::kParam3];
218 	hdep = params[LeslieController::kParam4] * params[LeslieController::kParam4] * getSampleRate () / 760.0f;
219 	hlev = gain * 0.9f * params[LeslieController::kParam5] * params[LeslieController::kParam5];
220 }
221 
222 }}} // namespaces
223 
224