1 module pixelperfectengine.audio.modules.qm816;
2 
3 import pixelperfectengine.audio.base.modulebase;
4 import pixelperfectengine.audio.base.envgen;
5 import pixelperfectengine.audio.base.func;
6 
7 import midi2.types.structs;
8 import midi2.types.enums;
9 
10 import inteli.emmintrin;
11 
12 import std.math;
13 
14 /**
15 QM816 - implements a Quadrature-Amplitude synthesizer. This technique was used in early 
16 digital FM synths, since it allowed allowed a cheap implementation of the same thing as
17 long as the modulator was a sinusoidal waveform.
18 
19 It has 16 2 operator channels that can be individually paired-up for 4 operator channels,
20 for more complex sounds. Also all operators have the option for feedback, including 
21 carriers. 2 operator channels have 2, 4 operator channels have 3*4 algorithms.
22 
23 Before use, the synth needs to be supplied with a wavetable file, in 16 bit wav format.
24 */
25 public class QM816 : AudioModule {
26 	/** 
27 	Contains a table to calculate Attack, Decay, and Release values.
28 
29 	All values are seconds with factions. Actual values are live-calculated depending on sustain-level and sampling
30 	frequency.
31 	*/
32 	public static immutable float[128] ADSR_TIME_TABLE = [
33 	//	0     |1     |2     |3     |4     |5     |6     |7     |8     |9     |A     |B     |C     |D     |E     |F
34 		0.000, 0.0005,0.001, 0.0015,0.002, 0.0025,0.003, 0.0035,0.004, 0.0045,0.005, 0.006, 0.007, 0.008, 0.009, 0.010,//0
35 		0.011, 0.012, 0.013, 0.014, 0.015, 0.017, 0.019, 0.021, 0.023, 0.025, 0.028, 0.031, 0.034, 0.038, 0.042, 0.047,//1
36 		0.052, 0.057, 0.062, 0.067, 0.073, 0.079, 0.085, 0.092, 0.099, 0.107, 0.116, 0.126, 0.137, 0.149, 0.162, 0.176,//2
37 		0.191, 0.207, 0.224, 0.242, 0.261, 0.281, 0.302, 0.324, 0.347, 0.371, 0.396, 0.422, 0.449, 0.477, 0.506, 0.536,//3
38 		0.567, 0.599, 0.632, 0.666, 0.701, 0.737, 0.774, 0.812, 0.851, 0.891, 0.932, 0.974, 1.017, 1.061, 1.106, 1.152,//4
39 		1.199, 1.247, 1.296, 1.346, 1.397, 1.499, 1.502, 1.556, 1.611, 1.667, 1.724, 1.782, 1.841, 1.901, 1.962, 2.024,//5
40 		2.087, 2.151, 2.216, 2.282, 2.349, 2.417, 2.486, 2.556, 2.627, 2.699, 2.772, 2.846, 2.921, 2.997, 3.074, 3.152,//6
41 		3.231, 3.331, 3.392, 3.474, 3.557, 3.621, 3.726, 3.812, 3.899, 3.987, 4.076, 4.166, 4.257, 4.349, 4.442, 4.535,//7
42 		
43 	];
44 	/**
45 	Contains a table to calculate Sustain control values.
46 
47 	All values are seconds with fractions. Actual values are live-calculated depending on sustain level and sampling
48 	frequency. Please note that with certain levels of sustain, the actual max time might be altered.
49 	*/
50 	public static immutable float[63] SUSTAIN_CONTROL_TIME_TABLE = [
51 	//	0     |1     |2     |3     |4     |5     |6     |7     |8     |9     |A     |B     |C     |D     |E     |F
52 		70.00, 60.00, 55.00, 50.00, 45.00, 42.50, 40.00, 38.50, 35.00, 32.50, 30.00, 27.50, 25.00, 24.00, 23.00, 22.00,//0
53 		21.00, 20.00, 19.00, 18.00, 17.50, 17.00, 16.50, 16.00, 15.50, 15.00, 14.50, 14.00, 13.50, 13.00, 12.50, 12.25,//1
54 		12.00, 11.75, 11.50, 11.25, 11.00, 10.75, 10.50, 10.25, 10.00, 9.750, 9.500, 9.250, 9.000, 8.750, 8.500, 8.250,//2
55 		8.000, 7.750, 7.500, 7.250, 7.000, 6.750, 6.500, 6.250, 6.000, 5.750, 5.500, 5.250, 5.000, 4.750, 4.500        //3
56 	];
57 	/**
58 	Defines operator parameter numbers, within the unregistered namespace.
59 	*/
60 	public enum OperatorParamNums {
61 		//Unregistered
62 		Level		=	0,
63 		Attack		=	1,
64 		Decay		=	2,
65 		SusLevel	=	3,
66 		SusCtrl		=	4,
67 		Release		=	5,
68 		Waveform	=	6,
69 		Feedback	=	7,
70 		TuneCor		=	8,
71 		TuneFine	=	9,
72 		ShpA		=	10,
73 		ShpR		=	11,
74 		VelToLevel	=	12,
75 		MWToLevel	=	13,
76 		LFOToLevel	=	14,
77 		OpCtrl		=	15,
78 		VelToFB		=	16,
79 		MWToFB		=	17,
80 		LFOToFB		=	18,
81 		EEGToFB		=	19,
82 		VelToShpA	=	20,
83 		VelToShpR	=	21,
84 	}
85 	/**
86 	Defines channel parameter numbers, within the unregistered namespace.
87 	*/
88 	public enum ChannelParamNums {
89 		MasterVol	=	0,
90 		Bal			=	1,
91 		AuxSLA		=	2,
92 		AuxSLB		=	3,
93 		EEGDetune	=	4,
94 		PLFO		=	5,
95 		Attack		=	6,
96 		Decay		=	7,
97 		SusLevel	=	8,
98 		SusCtrl		=	9,
99 		Release		=	10,
100 		ShpA		=	11,
101 		ShpR		=	12,
102 		ChCtrl		=	16,
103 		RingMod		=	17,
104 		EEGToLeft	=	18,
105 		EEGToRight	=	19,
106 		EEGToAuxA	=	20,
107 		EEGToAuxB	=	21,
108 		LFOToLeft	=	22,
109 		LFOToRight	=	23,
110 		LFOToAuxA	=	24,
111 		LFOToAuxB	=	25,
112 	}
113 	/**
114 	Defines channel parameters within the registered namespace
115 	*/
116 	public enum ChannelRegParams {
117 		PitchBendSens,
118 		TuneCor,
119 		TuneFine,
120 	}
121 	/**
122 	Defines global parameter nummbers, within the unregistered namespace
123 	*/
124 	public enum GlobalParamNums {
125 		PLFORate	=	0,
126 		PLFOWF		=	1,
127 		ALFORate	=	2,
128 		ALFOWF		=	3,
129 		FilterLCFreq=	4,
130 		FilterLCQ	=	5,
131 		FilterRCFreq=	6,
132 		FilterRCQ	=	7,
133 		FilterACFreq=	8,
134 		FilterACQ	=	9,
135 		FilterBCFreq=	10,
136 		FilterBCQ	=	11,
137 	}
138 	/**
139 	Implements a single operator.
140 	
141 	Contains an oscillator, an ADSR envelop generator, and locals.
142 	*/
143 	public struct Operator {
144 		///The envelop generator of the operator.
145 		ADSREnvelopGenerator	eg;
146 		///The current position of the oscillator, including fractions.
147 		uint			pos;	
148 		///The amount the oscillator must be stepped forward each cycle, including fractions.
149 		uint			step;
150 		///Operator tuning
151 		///Bit 31-25: Coarse detuning (-24 to +103 seminotes)
152 		///Bit 24-0: Fine detuning (-100 to 100 cents), 0x1_00_00_00 is center
153 		///If fixed mode is being used, then top 7 bits are the note, the rest are fine tuning.
154 		uint			tune	=	0x31_00_00_00;
155 		enum TuneCtrlFlags : uint {
156 			FineTuneMidPoint	=	0x1_00_00_00,
157 			CorTuneMidPoint		=	0x30_00_00_00,
158 			FineTuneTest		=	0x1_FF_FF_FF,
159 			CorTuneTest			=	0xFE_00_00_00,
160 		}
161 		///Input register.
162 		///The amount which the oscillator will be offsetted.
163 		int				input;
164 		///Feedback register. Either out_0[n-1] or out[n-1] multiplied by feedback amount.
165 		///The amount which the oscillator will be offsetted.
166 		///Negative if inverted.
167 		int				feedback;
168 		///Output register.
169 		///Not affected by either level or EG
170 		int				output;
171 		///Output level (between 0.0 and 1.0)
172 		float			outL	=	1.0;
173 		///Feedback level (between 0.0 and 1.0)
174 		float			fbL		=	0.0;
175 		///Output level controller assignment
176 		///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: unused
177 		__m128			outLCtrl=	__m128(0.0);
178 		///Feedback level controller assignment
179 		///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: Extra envelop generator
180 		__m128			fbLCtrl	=	__m128(0.0);
181 		///Live calculated out of shpA
182 		float			shpA0	=	0.0;
183 		///Live calculated out of shpR
184 		float			shpR0	=	0.0;
185 		///Output affected by EEG and level.
186 		///Either used for audible output, or to modulate other operators
187 		int				output_0;
188 		///Control flags and Wavetable selector
189 		uint			opCtrl;
190 		///Defines control values
191 		enum OpCtrlFlags {
192 			WavetableSelect	=	127,		///Wavetable select flags
193 			FBMode			=	1 << 7,		///Feedback mode (L: After Envelop Generator, H: Before Envelop Generator)
194 			FBNeg			=	1 << 8,		///Feedback mode (L: Positive, H: Negative)
195 			MWNeg			=	1 << 9,		///Invert modulation wheel control
196 			VelNeg			=	1 << 10,	///Invert velocity control
197 			EGRelAdaptive	=	1 << 11,	///Adaptive release time based on current output level
198 			FixedPitch		=	1 << 12,	///Enables fixed pitch mode
199 		}
200 		///Attack time control (between 0 and 127)
201 		ubyte			atk;
202 		///Decay time control (between 0 and 127)
203 		ubyte			dec;
204 		///Release time control (between 0 and 127)
205 		ubyte			rel;
206 		///Sustain curve control (between 0 and 127)
207 		///0: Percussive mode
208 		///1 - 63: Descending over time
209 		///64: Constant
210 		///65 - 127: Ascending over time
211 		ubyte			susCC;
212 		///ADSR shaping parameter (for the attack phase)
213 		float			shpA	=	0.5;
214 		///ADSR shaping parameter (for the decay/release phase)
215 		float			shpR	=	0.5;
216 		///Assigns velocity to shpA
217 		float			shpAVel	=	0.0;
218 		///Assigns velocity to shpR
219 		float			shpRVel =	0.0;
220 
221 		///Sets the frequency of the operator
222 		void setFrequency(int slmpFreq, ubyte note, double pitchBend, double tuning) @nogc @safe pure nothrow {
223 			/+const double actualNote = (opCtrl & OpCtrlFlags.FixedPitch) ? 
224 					(tune>>25) + ((cast(double)(tune & TuneCtrlFlags.FineTuneTest) - TuneCtrlFlags.FineTuneMidPoint) / 
225 					TuneCtrlFlags.FineTuneTest) : pitchBend + note ;+/
226 			double actualNote;
227 			if (opCtrl & OpCtrlFlags.FixedPitch) {
228 				actualNote = (tune>>25) + ((cast(double)(tune & TuneCtrlFlags.FineTuneTest) - TuneCtrlFlags.FineTuneMidPoint) / 
229 						TuneCtrlFlags.FineTuneTest);
230 			} else {
231 				actualNote = pitchBend + note + cast(int)((tune>>25) - TuneCtrlFlags.CorTuneMidPoint) + ((cast(double)(tune & 
232 						TuneCtrlFlags.FineTuneTest) - TuneCtrlFlags.FineTuneMidPoint) / TuneCtrlFlags.FineTuneTest);
233 			}
234 			const double oscFreq = noteToFreq(actualNote, tuning);
235 			const double cycLen = oscFreq / (slmpFreq / 1024.0);
236 			step = cast(uint)(cast(double)(1<<20) / cycLen);
237 		}
238 		///Resets the Envelop generator
239 		void resetEG(int sampleRate) @nogc @safe pure nothrow {
240 			//Set attack phase
241 			if (atk) {
242 				eg.attackRate = calculateRate(ADSR_TIME_TABLE[atk], sampleRate);
243 			} else {
244 				eg.attackRate = 1.0;
245 			}
246 			//Set decay phase
247 			if (dec) {
248 				eg.decayRate = calculateRate(ADSR_TIME_TABLE[dec] * 2, sampleRate, ADSREnvelopGenerator.maxOutput, eg.sustainLevel);
249 			} else {
250 				eg.decayRate = 1.0;
251 			}
252 			//Set sustain phase
253 			if (susCC) {
254 				eg.isPercussive = false;
255 				if (susCC == 64) {
256 					eg.sustainControl = 0.0;
257 				} else if (susCC < 64) {
258 					eg.sustainControl = -1.0 * 
259 							calculateRate(SUSTAIN_CONTROL_TIME_TABLE[susCC - 1], sampleRate);
260 				} else {
261 					eg.sustainControl = 
262 							calculateRate(SUSTAIN_CONTROL_TIME_TABLE[susCC - 64], sampleRate);
263 				}
264 			} else {
265 				eg.isPercussive = true;
266 				eg.sustainControl = 0.0;
267 			}
268 			//Set release phase
269 			if (rel) {
270 				eg.releaseRate = calculateRate(ADSR_TIME_TABLE[rel] * 2, sampleRate, eg.sustainLevel);
271 			} else {
272 				eg.releaseRate = 1.0;
273 			}
274 		}
275 		auto opAssign(Preset.Op value) @nogc @safe pure nothrow {
276 			eg.sustainLevel = value.susLevel;
277 			tune = value.tune;
278 			outL = value.outL;
279 			fbL = value.fbL;
280 			for (int i ; i < 4 ; i++)
281 				outLCtrl[i] = value.outLCtrl[i];
282 			for (int i ; i < 4 ; i++)
283 				fbLCtrl[i] = value.fbLCtrl[i];
284 			opCtrl = value.opCtrl;
285 			atk = value.atk;
286 			dec = value.dec;
287 			susCC = value.susCC;
288 			rel = value.rel;
289 			return this;
290 		}
291 	}
292 	/**
293 	Defines channel common parameters.
294 	*/
295 	public struct Channel {
296 		///Extra envelop generator that can be assigned for multiple purpose.
297 		ADSREnvelopGenerator	eeg;
298 		///ADSR shaping parameter (for the attack phase)
299 		float			shpAX;
300 		///ADSR shaping parameter (for the decay/release phase)
301 		float			shpRX;
302 		///Pitch amount for EEG
303 		///Bit 31-25: Coarse (-64 to +63 seminotes)
304 		///Bit 24-0: Fine (0 to 100 cents)
305 		uint			eegDetuneAm;
306 		///Pitch bend sensitivity
307 		///Bit 31-25: Coarse (0 to 127 seminotes)
308 		///Bit 24-0: Fine (0 to 100 cents)
309 		uint			pitchBendSens;
310 		///A-4 channel tuning in hertz.
311 		float			chnlTun = 440.0;
312 		///Stores channel control flags.
313 		uint			chCtrl;
314 		///Defines channel control flags.
315 		enum ChCtrlFlags {
316 			///Channel combination turned off, the channel pair is independent
317 			ComboModeOff	=	0b0000,	
318 			///Channel combination mode 1: Secondary channel's output is fed into primary operator 0.
319 			ComboMode1		=	0b0001,
320 			///Channel combination mode 2: Secondary channel's output is fed into primary operator 1 if primary 
321 			///is in serial mode, or into both if primary is in parallel mode.
322 			ComboMode2		=	0b0010,
323 			///Channel combination mode 3: Secondary channel's output is fed into main output, except if primary 
324 			///channel set to parallel and secondary set to serial, then S1, P0, and P1 are connected to output, while
325 			///S0 is modulating all of them.
326 			ComboMode3		=	0b0011,
327 			///Used for testing combo mode.
328 			ComboModeTest	=	ComboMode3,
329 			Algorithm		=	1<<2,	///Channel algorithm (H: Parallel, L: Series)
330 			IndivOutChLev	=	1<<3,	///Enables the setting of individual output channel levels
331 			LFOPan			=	1<<4,	///Enables LFO Panning
332 			EEGPan			=	1<<5,	///Enables EEG Panning
333 			MWToTrem		=	1<<6,	///Assigns modwheel to amplitude LFO
334 			MWToVibr		=	1<<7,	///Assigns modwheel to pitch LFO
335 			MWToAux			=	1<<8,	///Assigns modwheel to aux levels
336 		}
337 		///Master volume (0.0 to 1.0)
338 		float			masterVol;
339 		///Master balance (0.0 to 1.0)
340 		float			masterBal;
341 		///Calculated output level controls + aux send levels
342 		///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B
343 		__m128			outLevels;
344 		///EEG assign levels
345 		///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B
346 		__m128			eegLevels;
347 		///Amplitude LFO assign levels
348 		///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B
349 		__m128			aLFOlevels;
350 		///Ring modulation amount
351 		///Only available on select algorithms
352 		int				rmAmount;
353 		///Pitch LFO level
354 		float			pLFOlevel;
355 		///Amplitude LFO to 
356 		///Attack time control (between 0 and 127)
357 		ubyte			atkX;
358 		///Decay time control (between 0 and 127)
359 		ubyte			decX;
360 		///Release time control (between 0 and 127)
361 		ubyte			relX;
362 		///Sustain curve control (between 0 and 127)
363 		///0: Percussive mode
364 		///1 - 63: Descending over time
365 		///64: Constant
366 		///65 - 127: Ascending over time
367 		ubyte			susCCX;
368 		///Resets the Extra Envelop generator
369 		void resetEEG(int sampleRate) @nogc @safe pure nothrow {
370 			//Set attack phase
371 			if (atkX) {
372 				eeg.attackRate = calculateRate(ADSR_TIME_TABLE[atkX], sampleRate);
373 			} else {
374 				eeg.attackRate = 1.0;
375 			}
376 			//Set decay phase
377 			if (decX) {
378 				eeg.decayRate = calculateRate(ADSR_TIME_TABLE[decX] * 2, sampleRate, ADSREnvelopGenerator.maxOutput, eeg.sustainLevel);
379 			} else {
380 				eeg.decayRate = 1.0;
381 			}
382 			//Set sustain phase
383 			if (susCCX) {
384 				eeg.isPercussive = false;
385 				if (susCCX == 64) {
386 					eeg.sustainControl = 0.0;
387 				} else if (susCCX < 64) {
388 					eeg.sustainControl = -1.0 * calculateRate(SUSTAIN_CONTROL_TIME_TABLE[susCCX - 1], sampleRate);
389 				} else {
390 					eeg.sustainControl = calculateRate(SUSTAIN_CONTROL_TIME_TABLE[susCCX - 64], sampleRate);
391 				}
392 			} else {
393 				eeg.isPercussive = true;
394 				eeg.sustainControl = 0.0;
395 			}
396 			//Set release phase
397 			if (relX) {
398 				eeg.releaseRate = calculateRate(ADSR_TIME_TABLE[relX] * 2, sampleRate, eeg.sustainLevel);
399 			} else {
400 				eeg.releaseRate = 1.0;
401 			}
402 		}
403 		auto opAssign(Preset.Ch value) @nogc @safe pure nothrow {
404 			eeg.sustainLevel = value.susLevel;
405 			shpAX = value.shpAX;
406 			shpRX = value.shpRX;
407 			eegDetuneAm = value.eegDetuneAm;
408 			pitchBendSens = value.pitchBendSens;
409 			chnlTun = value.chnlTun;
410 			chCtrl = value.chCtrl;
411 			masterVol = value.masterVol;
412 			masterBal = value.masterBal;
413 			outLevels[2] = value.auxSendA;
414 			outLevels[3] = value.auxSendB;
415 			for (int i ; i < 4 ; i++)
416 				eegLevels[i] = value.eegLevels[i];
417 			for (int i ; i < 4 ; i++)
418 				aLFOlevels[i] = value.aLFOlevels[i];
419 			rmAmount = value.rmAmount;
420 			pLFOlevel = value.pLFOlevel;
421 			atkX = value.atkX;
422 			decX = value.decX;
423 			relX = value.relX;
424 			susCCX = value.susCCX;
425 			if (chCtrl & ChCtrlFlags.IndivOutChLev) {
426 				outLevels[1] = masterBal * masterBal;
427 			} else {
428 				outLevels[0] = masterVol - masterBal;
429 				outLevels[1] = masterVol - (1.0 - masterBal);
430 			}
431 			return this;
432 		}
433 	}
434 	/**
435 	Stores channel controller values (modwheel, velocity, etc.)
436 	*/
437 	public struct ChControllers {
438 		///Modulation wheel parameter, normalized between 0.0 and 1.0
439 		float			modwheel;
440 		///Velocity parameter, normalized between 0.0 and 1.0
441 		float			velocity;
442 		///Pitch bend parameter, with the amount of pitch shifting in semitones + fractions
443 		float			pitchBend;
444 		///The note that is currently being played
445 		ubyte			note;
446 	}
447 	/**
448 	Defines a preset.
449 	*/
450 	public struct Preset {
451 		///Defines parameters of a single operator
452 		public struct Op {
453 			///Operator tuning
454 			///Bit 31-25: Coarse detuning (-24 to +103 seminotes)
455 			///Bit 24-0: Fine detuning (-100 to 100 cents), 0x1_00_00_00 is center
456 			///If fixed mode is being used, then top 7 bits are the note, the rest are fine tuning.
457 			uint			tune	=	0x31_00_00_00;
458 			///Output level (between 0.0 and 1.0)
459 			float			outL;
460 			///Feedback level (between 0.0 and 1.0)
461 			float			fbL;
462 			///Output level controller assignment
463 			///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: unused
464 			float[4]		outLCtrl;
465 			///Feedback level controller assignment
466 			///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: Extra envelop generator
467 			float[4]		fbLCtrl;
468 			///Control flags and Wavetable selector
469 			uint			opCtrl;
470 			///Attack time control (between 0 and 127)
471 			ubyte			atk;
472 			///Decay time control (between 0 and 127)
473 			ubyte			dec;
474 			///Release time control (between 0 and 127)
475 			ubyte			rel;
476 			///Sustain curve control (between 0 and 127)
477 			///0: Percussive mode
478 			///1 - 63: Descending over time
479 			///64: Constant
480 			///65 - 127: Ascending over time
481 			ubyte			susCC;
482 			///Sustain level for the EG
483 			float			susLevel;
484 			///ADSR shaping parameter (for the attack phase)
485 			float			shpA	=	0.5;
486 			///ADSR shaping parameter (for the decay/release phase)
487 			float			shpR	=	0.5;
488 			///Assigns velocity to shpA
489 			float			shpAVel	=	0.0;
490 			///Assigns velocity to shpR
491 			float			shpRVel =	0.0;
492 		}
493 		///Defines parameters of a single channel.
494 		public struct Ch {
495 			///ADSR shaping parameter (for the attack phase)
496 			float			shpAX;
497 			///ADSR shaping parameter (for the decay/release phase)
498 			float			shpRX;
499 			///Pitch amount for EEG
500 			///Bit 31-25: Coarse (-64 to +63 seminotes)
501 			///Bit 24-0: Fine (0 to 100 cents)
502 			uint			eegDetuneAm;
503 			///Pitch bend sensitivity
504 			///Bit 31-25: Coarse (0 to 127 seminotes)
505 			///Bit 24-0: Fine (0 to 100 cents)
506 			uint			pitchBendSens;
507 			///A-4 channel tuning in hertz.
508 			float			chnlTun = 440.0;
509 			///Stores channel control flags.
510 			uint			chCtrl;
511 			///Master volume (0.0 to 1.0)
512 			float			masterVol;
513 			///Master balance (0.0 to 1.0)
514 			float			masterBal;
515 			///Aux send A
516 			float			auxSendA;
517 			///Aux send B
518 			float			auxSendB;
519 			///EEG assign levels
520 			///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B
521 			float[4]		eegLevels;
522 			///Amplitude LFO assign levels
523 			///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B
524 			float[4]		aLFOlevels;
525 			///Ring modulation amount
526 			///Only available on select algorithms
527 			int				rmAmount;
528 			///Pitch LFO level
529 			float			pLFOlevel;
530 			///Amplitude LFO to 
531 			///Attack time control (between 0 and 127)
532 			ubyte			atkX;
533 			///Decay time control (between 0 and 127)
534 			ubyte			decX;
535 			///Release time control (between 0 and 127)
536 			ubyte			relX;
537 			///Sustain curve control (between 0 and 127)
538 			///0: Percussive mode
539 			///1 - 63: Descending over time
540 			///64: Constant
541 			///65 - 127: Ascending over time
542 			ubyte			susCCX;
543 			///Sustain level
544 			float			susLevel;
545 		}
546 		Op[2]			operators;		///The operators belonging to this channel
547 		Ch				channel;		///Channel common values
548 	}
549 	///Contains the wavetables for the operators and LFOs.
550 	///Value might be divided to limit the values between 2047 and -2048 via bitshifting,
551 	///otherwise the full range can be used for audio output, etc.
552 	///Loaded from a 16 bit wave file.
553 	protected short[1024][128]	wavetables;
554 	///Stores presets.
555 	///8 banks of 128 presets are available for a total of 1024.
556 	///If a channel combination is being used, then bank pairs (0-1, 2-3, etc) will store their primary and secondary
557 	///halves, and calling either will load both halves.
558 	protected Preset[128][8]	soundBank;
559 	///Operator data.
560 	///See rendering function on updating.
561 	protected Operator[32]		operators;
562 	///Channel data.
563 	///See rendering function on updating.
564 	protected Channel[16]		channels;
565 	///Channel control data.
566 	protected ChControllers[16]	chCtrls;
567 	///Preset numbers per channels.
568 	protected ubyte[16]			presetNum;
569 	///Bank numbers per channels.
570 	protected ubyte[16]			bankNum;
571 	///Keeps the registered/unregistered parameter positions (LSB = 0).
572 	protected ubyte[2]			paramNum;
573 	///Stores LFO waveform selection. 1: Amplitude; 0: Pitch
574 	protected ubyte[2]			lfoWaveform;
575 	///Stores temporary parameter values
576 	protected ubyte[4]			paramTemp;
577 	///Stores ALFO position
578 	protected uint				aLFOPos;
579 	///Stores ALFO rate
580 	protected uint				aLFORate;
581 	///Stores output filter values.
582 	///0: a0; 1: a1; 2: a2; 3: b0; 4: b1; 5: b2; 6: x[n-1]; 7: x[n-2]; 8: y[n-1] 9: y[n-2]
583 	protected __m128[10]		filterVals;
584 	///Stores control values of the output values.
585 	///Layout: [LF, LQ, RF, RQ, AF, AQ, BF, BQ]
586 	protected float[8]			filterCtrl;
587 	///Initial mixing buffers
588 	///Output is directed there before filtering
589 	///Layout is: LRAB
590 	protected float[]			initBuffers;
591 	///Dummy buffer
592 	///Only used if one or more outputs haven't been defined
593 	protected float[]			dummyBuf;
594 	///Amplitude LFO buffer. Values are between 0.0 and 1.0
595 	protected float[]			aLFOBuf;
596 	///Pitch LFO output. Values are between -1.0 and 1.0
597 	protected float				pLFOOut;
598 	///Stores PLFO position
599 	protected uint				pLFOPos;
600 	///Stores PLFO rate
601 	protected uint				pLFORate;
602 	///Mixdown value.
603 	///Used for final mixing.
604 	protected float				mixdownVal = 1.0 / (ushort.max);
605 	alias ChFun = void delegate(int chNum, size_t length) @nogc pure nothrow;
606 	///Channel update delegates
607 	protected ChFun[16]			chDeleg;
608 	/**
609 	Creates an instance of QM816
610 	*/
611 	public this(ModuleManager handler) @safe nothrow {
612 		this.handler = handler;
613 		info.nOfAudioInput = 0;
614 		info.nOfAudioOutput = 4;
615 		info.outputChNames = ["mainL", "mainR", "auxSendA", "auxSendB"];
616 		info.isInstrument = true;
617 		info.hasMidiIn = true;
618 		info.hasMidiOut = true;
619 		info.midiSendback = true;
620 	}
621 	/**
622 	 * Receives waveform data that has been loaded from disk for reading. Returns zero if successful, or a specific 
623 	 * errorcode.
624 	 *
625 	 * id: The ID of the waveform.
626 	 * rawData: The data itself, in unprocessed form.
627 	 * format: The format of the wave data, including the data type, bit depth, base sampling rate
628 	 *
629 	 * Note: This function needs the audio system to be unlocked.
630 	 */
631 	public override int waveformDataReceive(uint id, ubyte[] rawData, WaveFormat format) nothrow {
632 		int errorcode;
633 		if (format.channels != 1) errorcode |= SampleLoadErrorCode.ChNumNotSupported;
634 		if (format.bitsPerSample != 16) errorcode |= SampleLoadErrorCode.BitdepthNotSupported;
635 		if (format.format != AudioFormat.PCM) errorcode |= SampleLoadErrorCode.FormatNotSupported;
636 		if (rawData.length != 128 * 1024 * 2) errorcode |= SampleLoadErrorCode.SampleLenghtNotSupported;
637 		if (errorcode) {
638 			return errorcode;
639 		} else {
640 			import core.stdc.string : memcpy;
641 			memcpy (wavetables.ptr, rawData.ptr, 128 * 1024 * 2);
642 			return 0;
643 		}
644 	}
645 	/**
646 	 * MIDI 2.0 data received here.
647 	 *
648 	 * data: up to 128 bits of MIDI 2.0 commands. Any packets that are shorter should be padded with zeros.
649 	 * offset: time offset of the command. This can reduce jitter caused by the asynchronous operation of the 
650 	 * sequencer and the audio plugin system.
651 	 */
652 	public override void midiReceive(uint[4] data, uint offset) @nogc nothrow {
653 		UMP firstPacket;
654 		firstPacket.base = data[0];
655 		switch (firstPacket.msgType) {
656 			case MessageType.SysCommMsg:	//Process system common message
657 				break;
658 			case MessageType.MIDI1:			//Process MIDI 1.0 messages
659 				switch (firstPacket.status) {
660 					case MIDI1_0Cmd.CtrlCh:	//Process MIDI 1.0 control change messages
661 						switch (firstPacket.note) {
662 							case 0, 32:			//Bank select
663 								bankNum[firstPacket.channel] = firstPacket.value;
664 								break;
665 							case 1:				//Modulation wheel
666 								chCtrls[firstPacket.channel].modwheel = cast(double)(firstPacket.value) / byte.max;
667 								break;
668 							case 6:			//Data Entry MSB
669 								paramNum[1] = firstPacket.value;
670 								break;
671 							case 38:		//Data Entry LSB
672 								paramNum[0] = firstPacket.value;
673 								break;
674 							case 98:		//Non Registered Parameter Number LSB
675 								setUnregisteredParam(firstPacket.value, paramNum, 0, firstPacket.channel);
676 								break;
677 							case 99:		//Non Registered Parameter Number LSB
678 								setUnregisteredParam(firstPacket.value, paramNum, 0, firstPacket.channel);
679 								break;
680 							default:
681 								break;
682 						}
683 						break;
684 					case MIDI1_0Cmd.NoteOn:	//Note on command
685 						const uint ch = firstPacket.channel;
686 						if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch > 7) return;
687 						chCtrls[ch].note = firstPacket.note;
688 						chCtrls[ch].velocity = cast(double)firstPacket.velocity / cast(double)byte.max;
689 						channels[ch].eeg.keyOn();
690 						operators[ch].eg.keyOn();
691 						operators[ch].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun);
692 						operators[ch + 1].eg.keyOn();
693 						operators[ch + 1].setFrequency(sampleRate, firstPacket.note, chCtrls[ch + 1].pitchBend, channels[ch].chnlTun);
694 						if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch <= 7) {
695 							channels[ch + 8].eeg.keyOn();
696 							operators[ch + 16].eg.keyOn();
697 							operators[ch + 16].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun);
698 							operators[ch + 17].eg.keyOn();
699 							operators[ch + 17].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun);
700 						}
701 						break;
702 					case MIDI1_0Cmd.NoteOff://Note off command
703 						const uint ch = firstPacket.channel;
704 						if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch > 7) return;
705 						chCtrls[ch].velocity = cast(double)firstPacket.velocity / cast(double)byte.max;
706 						channels[ch].eeg.keyOff();
707 						operators[ch].eg.keyOff();
708 						if (operators[ch].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) {
709 							if (operators[ch].rel) {
710 								operators[ch].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch].rel] * 2, sampleRate, 
711 										operators[ch].eg.sustainLevel);
712 							} else {
713 								operators[ch].eg.releaseRate = 1.0;
714 							}
715 						}
716 						operators[ch + 1].eg.keyOff();
717 						if (operators[ch + 1].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) {
718 							if (operators[ch + 1].rel) {
719 								operators[ch + 1].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 1].rel] * 2, sampleRate, 
720 										operators[ch + 1].eg.sustainLevel);
721 							} else {
722 								operators[ch + 1].eg.releaseRate = 1.0;
723 							}
724 						}
725 						if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch <= 7) {
726 							channels[ch + 8].eeg.keyOff();
727 							operators[ch + 16].eg.keyOff();
728 							if (operators[ch + 16].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) {
729 								if (operators[ch + 16].rel) {
730 									operators[ch + 16].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 16].rel] * 2, sampleRate, 
731 											operators[ch + 16].eg.sustainLevel);
732 								} else {
733 									operators[ch + 16].eg.releaseRate = 1.0;
734 								}
735 							}
736 							operators[ch + 17].eg.keyOff();
737 							if (operators[ch + 17].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) {
738 								if (operators[ch + 17].rel) {
739 									operators[ch + 17].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 17].rel] * 2, sampleRate, 
740 											operators[ch + 17].eg.sustainLevel);
741 								} else {
742 									operators[ch + 17].eg.releaseRate = 1.0;
743 								}
744 							}
745 						}
746 						break;
747 					case MIDI1_0Cmd.ChAftrTch:
748 						chCtrls[firstPacket.channel].velocity = cast(double)firstPacket.note / cast(double)byte.max;
749 						break;
750 					case MIDI1_0Cmd.PolyAftrTch:
751 						chCtrls[firstPacket.channel].velocity = cast(double)firstPacket.velocity / cast(double)byte.max;
752 						break;
753 					case MIDI1_0Cmd.PrgCh:	//Program change
754 						const uint chOffset = firstPacket.channel;
755 						const uint chCtrl = soundBank[bankNum[chOffset] & 7][presetNum[chOffset]].channel.chCtrl;
756 						if (chCtrl & Channel.ChCtrlFlags.ComboModeTest) {
757 							const uint chX = chOffset & 7, bankX = bankNum[chOffset] & 7 & ~1;
758 							prgRecall(chX, presetNum[chX], bankX);
759 							prgRecall(chX + 8, presetNum[chX], bankX + 1);
760 						} else {
761 							prgRecall(chOffset, presetNum[chOffset], bankNum[chOffset]);
762 						}
763 						break;
764 					case MIDI1_0Cmd.PitchBend:
765 						const uint ch = firstPacket.channel;
766 						const double pitchBendSens = (channels[ch].pitchBendSens>>25) + 
767 								(cast(double)(channels[ch].pitchBendSens & 0x01_FF_FF_FF) / 0x01_FF_FF_FF);
768 						chCtrls[ch].pitchBend = pitchBendSens * ((cast(double)firstPacket.bend - 0x20_00) / 0x3F_FF);
769 						break;
770 					default:
771 						break;
772 				}
773 				break;
774 			case MessageType.MIDI2:
775 				switch (firstPacket.status) {
776 					case MIDI2_0Cmd.CtrlCh:	//Control change
777 						setUnregisteredParam(data[1], [firstPacket.index, firstPacket.value], 0, firstPacket.channel);
778 						break;
779 					case MIDI2_0Cmd.CtrlChR://Registered control change
780 						setRegisteredParam(data[1], [firstPacket.index, firstPacket.value], 0, firstPacket.channel);
781 						break;
782 					case MIDI2_0Cmd.PrgCh:	//Program change
783 						const uint chOffset = firstPacket.channel;
784 						//const uint prg = data[1]>>24, bank = data[1] & 7;
785 						presetNum[chOffset] = cast(ubyte)(data[1]>>24);
786 						if (firstPacket.value & 1) bankNum[chOffset] = cast(ubyte)(data[1] & 7);
787 						const uint chCtrl = soundBank[bankNum[chOffset] & 7][presetNum[chOffset]].channel.chCtrl;
788 						if (chCtrl & Channel.ChCtrlFlags.ComboModeTest) {
789 							const uint chX = chOffset & 7, bankX = bankNum[chOffset] & 7 & ~1;
790 							prgRecall(chX, presetNum[chX], bankX);
791 							prgRecall(chX + 8, presetNum[chX], bankX + 1);
792 						} else {
793 							prgRecall(chOffset, presetNum[chOffset], bankNum[chOffset]);
794 						}
795 						break;
796 					case MIDI2_0Cmd.NoteOn:
797 						NoteVals v = *cast(NoteVals*)(&data[1]);
798 						const uint ch = firstPacket.channel;
799 						if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch > 7) return;
800 						chCtrls[ch].note = firstPacket.note;
801 						chCtrls[ch].velocity = v.velocity / cast(double)ushort.max;
802 						channels[ch].eeg.keyOn();
803 						operators[ch].eg.keyOn();
804 						operators[ch].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun);
805 						operators[ch + 1].eg.keyOn();
806 						operators[ch + 1].setFrequency(sampleRate, firstPacket.note, chCtrls[ch + 1].pitchBend, channels[ch].chnlTun);
807 						if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch <= 7) {
808 							channels[ch + 8].eeg.keyOn();
809 							operators[ch + 16].eg.keyOn();
810 							operators[ch + 16].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun);
811 							operators[ch + 17].eg.keyOn();
812 							operators[ch + 17].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun);
813 						}
814 						break;
815 					case MIDI2_0Cmd.NoteOff:
816 						NoteVals v = *cast(NoteVals*)(&data[1]);
817 						const uint ch = firstPacket.channel;
818 						if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch > 7) return;
819 						//chCtrls[ch].note = firstPacket.note;
820 						chCtrls[ch].velocity = v.velocity / cast(double)ushort.max;
821 						channels[ch].eeg.keyOff();
822 						operators[ch].eg.keyOff();
823 						if (operators[ch].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) {
824 							if (operators[ch].rel) {
825 								operators[ch].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch].rel] * 2, sampleRate, 
826 										operators[ch].eg.sustainLevel);
827 							} else {
828 								operators[ch].eg.releaseRate = 1.0;
829 							}
830 						}
831 						operators[ch + 1].eg.keyOff();
832 						if (operators[ch + 1].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) {
833 							if (operators[ch + 1].rel) {
834 								operators[ch + 1].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 1].rel] * 2, sampleRate, 
835 										operators[ch + 1].eg.sustainLevel);
836 							} else {
837 								operators[ch + 1].eg.releaseRate = 1.0;
838 							}
839 						}
840 						if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch <= 7) {
841 							channels[ch + 8].eeg.keyOff();
842 							operators[ch + 16].eg.keyOff();
843 							if (operators[ch + 16].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) {
844 								if (operators[ch + 16].rel) {
845 									operators[ch + 16].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 16].rel] * 2, sampleRate, 
846 											operators[ch + 16].eg.sustainLevel);
847 								} else {
848 									operators[ch + 16].eg.releaseRate = 1.0;
849 								}
850 							}
851 							operators[ch + 17].eg.keyOff();
852 							if (operators[ch + 17].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) {
853 								if (operators[ch + 17].rel) {
854 									operators[ch + 17].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 17].rel] * 2, sampleRate, 
855 											operators[ch + 17].eg.sustainLevel);
856 								} else {
857 									operators[ch + 17].eg.releaseRate = 1.0;
858 								}
859 							}
860 						}
861 						break;
862 					case MIDI2_0Cmd.PitchBend:
863 						const uint ch = firstPacket.channel;
864 						const double pitchBendSens = (channels[ch].pitchBendSens>>25) + 
865 								(cast(double)(channels[ch].pitchBendSens & 0x01_FF_FF_FF) / 0x01_FF_FF_FF);
866 						chCtrls[ch].pitchBend = pitchBendSens * (cast(double)(firstPacket.bend - (uint.max / 2)) / (uint.max / 2));
867 						break;
868 					default:
869 						break;
870 				}
871 				break;
872 			default:
873 				break;
874 		}
875 	}
876 	/**
877 	Sets the channel delegates
878 	*/
879 	protected void setChDeleg(uint chCtrl, uint chNum, uint chCtrl0 = 0) @nogc @safe pure nothrow {
880 		if (chCtrl & Channel.ChCtrlFlags.ComboModeTest) {	//Test if channel is combined or not
881 			if (chNum < 8) {
882 				const uint algID = chCtrl & (Channel.ChCtrlFlags.ComboModeTest | Channel.ChCtrlFlags.Algorithm) | 
883 						((chCtrl0 | Channel.ChCtrlFlags.Algorithm)<<1);
884 				enum priChAlg = Channel.ChCtrlFlags.Algorithm;
885 				enum secChAlg = Channel.ChCtrlFlags.Algorithm<<1;
886 				switch (algID) {
887 					case Channel.ChCtrlFlags.ComboMode1:
888 						chDeleg[chNum] = &updateChannelM100;
889 						break;
890 					case Channel.ChCtrlFlags.ComboMode1 | secChAlg:
891 						chDeleg[chNum] = &updateChannelM110;
892 						break;
893 					case Channel.ChCtrlFlags.ComboMode1 | priChAlg:
894 						chDeleg[chNum] = &updateChannelM101;
895 						break;
896 					case Channel.ChCtrlFlags.ComboMode1 | secChAlg | priChAlg:
897 						chDeleg[chNum] = &updateChannelM111;
898 						break;
899 					case Channel.ChCtrlFlags.ComboMode2:
900 						chDeleg[chNum] = &updateChannelM200;
901 						break;
902 					case Channel.ChCtrlFlags.ComboMode2 | secChAlg:
903 						chDeleg[chNum] = &updateChannelM210;
904 						break;
905 					case Channel.ChCtrlFlags.ComboMode2 | priChAlg:
906 						chDeleg[chNum] = &updateChannelM201;
907 						break;
908 					case Channel.ChCtrlFlags.ComboMode2 | secChAlg | priChAlg:
909 						chDeleg[chNum] = &updateChannelM211;
910 						break;
911 					case Channel.ChCtrlFlags.ComboMode3:
912 						chDeleg[chNum] = &updateChannelM300;
913 						break;
914 					case Channel.ChCtrlFlags.ComboMode3 | secChAlg:
915 						chDeleg[chNum] = &updateChannelM310;
916 						break;
917 					case Channel.ChCtrlFlags.ComboMode3 | priChAlg:
918 						chDeleg[chNum] = &updateChannelM301;
919 						break;
920 					case Channel.ChCtrlFlags.ComboMode3 | secChAlg | priChAlg:
921 						chDeleg[chNum] = &updateChannelM311;
922 						break;
923 					default:
924 						chDeleg[chNum] = &updateChannelMD;
925 						break;
926 				}
927 			} else {
928 				chDeleg[chNum] = &updateChannelMD;
929 			}
930 		} else {
931 			if (chCtrl & Channel.ChCtrlFlags.Algorithm) 
932 				chDeleg[chNum] = &updateChannelM01;
933 			else
934 				chDeleg[chNum] = &updateChannelM00;
935 		}
936 	}
937 	/**
938 	Recalls a program
939 	*/
940 	protected void prgRecall(ubyte ch, ubyte prg, ubyte bank) @nogc @safe pure nothrow {
941 		Preset p = soundBank[bank & 7][prg];
942 		operators[ch] = p.operators[0];
943 		operators[ch].resetEG(sampleRate);
944 		operators[ch + 1] = p.operators[1];
945 		operators[ch + 1].resetEG(sampleRate);
946 		channels[ch] = p.channel;
947 		channels[ch].resetEEG(sampleRate);
948 	}
949 	/**
950 	Sets a registered parameter
951 
952 	If type is not zero, then the MSB is being set, otherwise the LSB will be used
953 	*/
954 	protected void setRegisteredParam(T)(T val, ubyte[2] paramNum, ubyte type, ubyte chNum) @nogc @safe pure nothrow {
955 		switch (paramNum[0]) {
956 			case ChannelRegParams.PitchBendSens:
957 				static if (is(T == uint)) {
958 					channels[chNum].pitchBendSens = val;
959 				} else static if (is(T == ubyte)) {
960 					if (type) {
961 						channels[chNum].pitchBendSens &= ~(byte.max<<25);
962 						channels[chNum].pitchBendSens |= val<<25;
963 					} else {
964 						channels[chNum].pitchBendSens &= ~(byte.max<<18);
965 						channels[chNum].pitchBendSens |= val<<18;
966 					}
967 				}
968 				break;
969 			case ChannelRegParams.TuneFine:			//Channel master tuning (fine)
970 				break;
971 			case ChannelRegParams.TuneCor:			//Channel master tuning (coarse)
972 				break;
973 			default: break;
974 		}
975 	}
976 	/**
977 	Sets an unregistered parameter
978 
979 	If type is not zero, then the MSB is being set, otherwise the LSB will be used
980 	*/
981 	protected void setUnregisteredParam(T)(T val, ubyte[2] paramNum, ubyte type, ubyte chNum) @nogc @safe pure nothrow {
982 		void setOpParam(int chNum) {
983 			switch (paramNum[0]) {
984 				case OperatorParamNums.Attack:
985 					static if (is(T == uint)) {
986 						operators[chNum].atk = cast(ubyte)(val >> 25);
987 					} else static if (is(T == ubyte)) {
988 						operators[chNum].atk = val;
989 					}
990 					if (operators[chNum].atk) {
991 						operators[chNum].eg.attackRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].atk], sampleRate);
992 					} else {
993 						operators[chNum].eg.attackRate = 1.0;
994 					}
995 					break;
996 				case OperatorParamNums.Decay:
997 					static if (is(T == uint)) {
998 						operators[chNum].dec = cast(ubyte)(val >> 25);
999 					} else static if (is(T == ubyte)) {
1000 						operators[chNum].dec = val;
1001 					}
1002 					if (operators[chNum].dec) {
1003 						operators[chNum].eg.decayRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].dec] * 2, sampleRate, 
1004 								ADSREnvelopGenerator.maxOutput, operators[chNum].eg.sustainLevel);
1005 					} else {
1006 						operators[chNum].eg.decayRate = 1.0;
1007 					}
1008 					break;
1009 				case OperatorParamNums.Feedback:
1010 					static if (is(T == uint)) {
1011 						const double valF = cast(double)val / uint.max;
1012 						operators[chNum].fbL = valF * valF;
1013 					} else static if (is(T == ubyte)) {
1014 						if (type)
1015 							paramTemp[2] = val;
1016 						else
1017 							paramTemp[3] = val;
1018 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1019 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1020 							const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1021 							operators[chNum].fbL = valF * valF;
1022 						} else {		//Set temp for next command (assume MSB-LSB order)
1023 							paramNum[0] = paramTemp[0];
1024 							paramNum[1] = paramTemp[1];
1025 						}
1026 					}
1027 					break;
1028 				case OperatorParamNums.Level:
1029 					static if (is(T == uint)) {
1030 						const double valF = cast(double)val / uint.max;
1031 						operators[chNum].outL = valF * valF;
1032 					} else static if (is(T == ubyte)) {
1033 						if (type)
1034 							paramTemp[2] = val;
1035 						else
1036 							paramTemp[3] = val;
1037 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1038 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1039 							const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1040 							operators[chNum].outL = valF * valF;
1041 						} else {		//Set temp for next command (assume MSB-LSB order)
1042 							paramNum[0] = paramTemp[0];
1043 							paramNum[1] = paramTemp[1];
1044 						}
1045 					}
1046 					break;
1047 				case OperatorParamNums.OpCtrl:
1048 					static if (is(T == uint)) {
1049 						operators[chNum].opCtrl = val;
1050 					} else static if (is(T == ubyte)) {
1051 						operators[chNum].opCtrl &= ~(byte.max<<7);
1052 						operators[chNum].opCtrl |= val<<7;
1053 					}
1054 					break;
1055 				case OperatorParamNums.Release:
1056 					static if (is(T == uint)) {
1057 						operators[chNum].rel = cast(ubyte)(val >> 25);
1058 					} else static if (is(T == ubyte)) {
1059 						operators[chNum].rel = val;
1060 					}
1061 					if (operators[chNum].rel) {
1062 						operators[chNum].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].rel] * 2, sampleRate, 
1063 								operators[chNum].eg.sustainLevel);
1064 					} else {
1065 						operators[chNum].eg.releaseRate = 1.0;
1066 					}
1067 					break;
1068 				case OperatorParamNums.ShpA:
1069 					static if (is(T == uint)) {
1070 						operators[chNum].shpA = cast(double)val / uint.max;
1071 					} else static if (is(T == ubyte)) {
1072 						if (type)
1073 							paramTemp[2] = val;
1074 						else
1075 							paramTemp[3] = val;
1076 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1077 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1078 							operators[chNum].shpA = cast(double)(val32) / cast(double)(ushort.max>>2);
1079 						} else {		//Set temp for next command (assume MSB-LSB order)
1080 							paramNum[0] = paramTemp[0];
1081 							paramNum[1] = paramTemp[1];
1082 						}
1083 					}
1084 					break;
1085 				case OperatorParamNums.ShpR:
1086 					static if (is(T == uint)) {
1087 						operators[chNum].shpR = cast(double)val / uint.max;
1088 					} else static if (is(T == ubyte)) {
1089 						if (type)
1090 							paramTemp[2] = val;
1091 						else
1092 							paramTemp[3] = val;
1093 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1094 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1095 							operators[chNum].shpR = cast(double)(val32) / cast(double)(ushort.max>>2);
1096 						} else {		//Set temp for next command (assume MSB-LSB order)
1097 							paramNum[0] = paramTemp[0];
1098 							paramNum[1] = paramTemp[1];
1099 						}
1100 					}
1101 					break;
1102 				case OperatorParamNums.SusCtrl:
1103 					static if (is(T == uint)) {
1104 						operators[chNum].susCC = cast(ubyte)(val >> 25);
1105 					} else static if (is(T == ubyte)) {
1106 						operators[chNum].susCC = val;
1107 					}
1108 					if (operators[chNum].susCC) {
1109 						operators[chNum].eg.isPercussive = false;
1110 						if (operators[chNum].susCC == 64) {
1111 							operators[chNum].eg.sustainControl = 0.0;
1112 						} else if (operators[chNum].susCC < 64) {
1113 							operators[chNum].eg.sustainControl = -1.0 * 
1114 									calculateRate(SUSTAIN_CONTROL_TIME_TABLE[operators[chNum].susCC - 1], sampleRate);
1115 						} else {
1116 							operators[chNum].eg.sustainControl = 
1117 									calculateRate(SUSTAIN_CONTROL_TIME_TABLE[operators[chNum].susCC - 64], sampleRate);
1118 						}
1119 					} else {
1120 						operators[chNum].eg.isPercussive = true;
1121 						operators[chNum].eg.sustainControl = 0.0;
1122 					}
1123 					break;
1124 				case OperatorParamNums.SusLevel:
1125 					static if (is(T == uint)) {
1126 						operators[chNum].eg.sustainLevel = cast(double)val / uint.max;
1127 					} else static if (is(T == ubyte)) {
1128 						if (type)
1129 							paramTemp[2] = val;
1130 						else
1131 							paramTemp[3] = val;
1132 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1133 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1134 							operators[chNum].eg.sustainLevel = cast(double)(val32) / cast(double)(ushort.max>>2);
1135 						} else {		//Set temp for next command (assume MSB-LSB order)
1136 							paramNum[0] = paramTemp[0];
1137 							paramNum[1] = paramTemp[1];
1138 						}
1139 						
1140 					}
1141 					//Recalculate decay and release rates to new sustain levels
1142 					if (operators[chNum].dec) {
1143 						operators[chNum].eg.decayRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].dec] * 2, sampleRate, 
1144 								ADSREnvelopGenerator.maxOutput, operators[chNum].eg.sustainLevel);
1145 					} else {
1146 						operators[chNum].eg.decayRate = 1.0;
1147 					}
1148 					if (operators[chNum].rel) {
1149 						operators[chNum].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].rel] * 2, sampleRate, 
1150 								operators[chNum].eg.sustainLevel);
1151 					} else {
1152 						operators[chNum].eg.releaseRate = 1.0;
1153 					}
1154 					break;
1155 				case OperatorParamNums.TuneCor:
1156 					static if (is(T == uint)) {
1157 						operators[chNum].tune = val;
1158 					} else static if (is(T == ubyte)) {
1159 						if (type)
1160 							paramTemp[2] = val;
1161 						else
1162 							paramTemp[3] = val;
1163 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1164 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1165 							//operators[chNum].velAm = val32 / ushort.max>>2;
1166 							operators[chNum].tune &= ~(uint.max<<18);
1167 							operators[chNum].tune |= val32<<18;
1168 						} else {		//Set temp for next command (assume MSB-LSB order)
1169 							paramNum[0] = paramTemp[0];
1170 							paramNum[1] = paramTemp[1];
1171 						}
1172 					}
1173 					break;
1174 				case OperatorParamNums.TuneFine:
1175 					operators[chNum].tune &= uint.max>>7;
1176 					static if (is(T == uint)) {
1177 						operators[chNum].tune |= val>>7;
1178 					} else static if (is(T == ubyte)) {
1179 						if (type)
1180 							paramTemp[2] = val;
1181 						else
1182 							paramTemp[3] = val;
1183 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1184 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1185 							operators[chNum].tune |= val32<<10 | val32>>5;
1186 						} else {		//Set temp for next command (assume MSB-LSB order)
1187 							paramNum[0] = paramTemp[0];
1188 							paramNum[1] = paramTemp[1];
1189 						}
1190 					}
1191 					break;
1192 				case OperatorParamNums.VelToLevel:
1193 					static if (is(T == uint)) {
1194 						operators[chNum].outLCtrl[0] = cast(double)val / uint.max;
1195 					} else static if (is(T == ubyte)) {
1196 						if (type)
1197 							paramTemp[2] = val;
1198 						else
1199 							paramTemp[3] = val;
1200 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1201 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1202 							operators[chNum].outLCtrl[0] = cast(double)(val32) / cast(double)(ushort.max>>2);
1203 						} else {		//Set temp for next command (assume MSB-LSB order)
1204 							paramNum[0] = paramTemp[0];
1205 							paramNum[1] = paramTemp[1];
1206 						}
1207 					}
1208 					break;
1209 				case OperatorParamNums.MWToLevel:
1210 					static if (is(T == uint)) {
1211 						operators[chNum].outLCtrl[1] = cast(double)val / uint.max;
1212 					} else static if (is(T == ubyte)) {
1213 						if (type)
1214 							paramTemp[2] = val;
1215 						else
1216 							paramTemp[3] = val;
1217 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1218 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1219 							operators[chNum].outLCtrl[1] = cast(double)(val32) / cast(double)(ushort.max>>2);
1220 						} else {		//Set temp for next command (assume MSB-LSB order)
1221 							paramNum[0] = paramTemp[0];
1222 							paramNum[1] = paramTemp[1];
1223 						}
1224 					}
1225 					break;
1226 				case OperatorParamNums.LFOToLevel:
1227 					static if (is(T == uint)) {
1228 						operators[chNum].outLCtrl[2] = cast(double)val / uint.max;
1229 					} else static if (is(T == ubyte)) {
1230 						if (type)
1231 							paramTemp[2] = val;
1232 						else
1233 							paramTemp[3] = val;
1234 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1235 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1236 							operators[chNum].outLCtrl[2] = cast(double)(val32) / cast(double)(ushort.max>>2);
1237 						} else {		//Set temp for next command (assume MSB-LSB order)
1238 							paramNum[0] = paramTemp[0];
1239 							paramNum[1] = paramTemp[1];
1240 						}
1241 					}
1242 					break;
1243 				case OperatorParamNums.VelToFB:
1244 					static if (is(T == uint)) {
1245 						operators[chNum].fbLCtrl[0] = cast(double)val / uint.max;
1246 					} else static if (is(T == ubyte)) {
1247 						if (type)
1248 							paramTemp[2] = val;
1249 						else
1250 							paramTemp[3] = val;
1251 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1252 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1253 							operators[chNum].fbLCtrl[0] = cast(double)(val32) / cast(double)(ushort.max>>2);
1254 						} else {		//Set temp for next command (assume MSB-LSB order)
1255 							paramNum[0] = paramTemp[0];
1256 							paramNum[1] = paramTemp[1];
1257 						}
1258 					}
1259 					break;
1260 				case OperatorParamNums.MWToFB:
1261 					static if (is(T == uint)) {
1262 						operators[chNum].fbLCtrl[1] = cast(double)val / uint.max;
1263 					} else static if (is(T == ubyte)) {
1264 						if (type)
1265 							paramTemp[2] = val;
1266 						else
1267 							paramTemp[3] = val;
1268 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1269 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1270 							operators[chNum].fbLCtrl[1] = cast(double)(val32) / cast(double)(ushort.max>>2);
1271 						} else {		//Set temp for next command (assume MSB-LSB order)
1272 							paramNum[0] = paramTemp[0];
1273 							paramNum[1] = paramTemp[1];
1274 						}
1275 					}
1276 					break;
1277 				case OperatorParamNums.LFOToFB:
1278 					static if (is(T == uint)) {
1279 						operators[chNum].fbLCtrl[2] = cast(double)val / uint.max;
1280 					} else static if (is(T == ubyte)) {
1281 						if (type)
1282 							paramTemp[2] = val;
1283 						else
1284 							paramTemp[3] = val;
1285 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1286 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1287 							operators[chNum].fbLCtrl[2] = cast(double)(val32) / cast(double)(ushort.max>>2);
1288 						} else {		//Set temp for next command (assume MSB-LSB order)
1289 							paramNum[0] = paramTemp[0];
1290 							paramNum[1] = paramTemp[1];
1291 						}
1292 					}
1293 					break;
1294 				case OperatorParamNums.EEGToFB:
1295 					static if (is(T == uint)) {
1296 						operators[chNum].fbLCtrl[3] = cast(double)val / uint.max;
1297 					} else static if (is(T == ubyte)) {
1298 						if (type)
1299 							paramTemp[2] = val;
1300 						else
1301 							paramTemp[3] = val;
1302 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1303 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1304 							operators[chNum].fbLCtrl[3] = cast(double)(val32) / cast(double)(ushort.max>>2);
1305 						} else {		//Set temp for next command (assume MSB-LSB order)
1306 							paramNum[0] = paramTemp[0];
1307 							paramNum[1] = paramTemp[1];
1308 						}
1309 					}
1310 					break;
1311 				case OperatorParamNums.VelToShpA:
1312 					static if (is(T == uint)) {
1313 						operators[chNum].shpAVel = cast(double)val / uint.max;
1314 					} else static if (is(T == ubyte)) {
1315 						if (type)
1316 							paramTemp[2] = val;
1317 						else
1318 							paramTemp[3] = val;
1319 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1320 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1321 							operators[chNum].shpAVel = cast(double)(val32) / cast(double)(ushort.max>>2);
1322 						} else {		//Set temp for next command (assume MSB-LSB order)
1323 							paramNum[0] = paramTemp[0];
1324 							paramNum[1] = paramTemp[1];
1325 						}
1326 					}
1327 					break;
1328 				case OperatorParamNums.VelToShpR:
1329 					static if (is(T == uint)) {
1330 						operators[chNum].shpRVel = cast(double)val / uint.max;
1331 					} else static if (is(T == ubyte)) {
1332 						if (type)
1333 							paramTemp[2] = val;
1334 						else
1335 							paramTemp[3] = val;
1336 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1337 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1338 							operators[chNum].shpRVel = cast(double)(val32) / cast(double)(ushort.max>>2);
1339 						} else {		//Set temp for next command (assume MSB-LSB order)
1340 							paramNum[0] = paramTemp[0];
1341 							paramNum[1] = paramTemp[1];
1342 						}
1343 					}
1344 					break;
1345 				case OperatorParamNums.Waveform:
1346 					operators[chNum].opCtrl &= ~Operator.OpCtrlFlags.WavetableSelect;
1347 					static if (is(T == uint)) {
1348 						operators[chNum].opCtrl |= cast(ubyte)(val >> 25);
1349 					} else static if (is(T == ubyte)) {
1350 						operators[chNum].opCtrl |= val;
1351 					}
1352 					break;
1353 				default: break;
1354 			}
1355 		}
1356 		switch (paramNum[1]) {
1357 			case 0:			//Channel operator 0
1358 				chNum *= 2;
1359 				setOpParam(chNum);
1360 				break;
1361 			case 1:			//Channel operator 1
1362 				chNum *= 2;
1363 				setOpParam(chNum + 1);
1364 				break;
1365 			case 2:			//Channel common values
1366 				switch (paramNum[0]) { 
1367 					//case ChannelParamNums.ALFO: break;
1368 					case ChannelParamNums.Attack:
1369 						static if (is(T == uint)) {
1370 							channels[chNum].atkX = cast(ubyte)(val >> 25);
1371 						} else static if (is(T == ubyte)) {
1372 							channels[chNum].atkX = val;
1373 						}
1374 						if (channels[chNum].atkX) {
1375 							channels[chNum].eeg.attackRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].atkX], sampleRate);
1376 						} else {
1377 							channels[chNum].eeg.attackRate = 1.0;
1378 						}
1379 						break;
1380 					case ChannelParamNums.AuxSLA:
1381 						static if (is(T == uint)) {
1382 							const double valF = cast(double)val / uint.max;
1383 							channels[chNum].outLevels[2] = valF * valF;
1384 						} else static if (is(T == ubyte)) {
1385 							if (type)
1386 								paramTemp[2] = val;
1387 							else
1388 								paramTemp[3] = val;
1389 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1390 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1391 								const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1392 								channels[chNum].outLevels[2] = valF * valF;
1393 							} else {		//Set temp for next command (assume MSB-LSB order)
1394 								paramNum[0] = paramTemp[0];
1395 								paramNum[1] = paramTemp[1];
1396 							}
1397 						}
1398 						break;
1399 					case ChannelParamNums.AuxSLB: 
1400 						static if (is(T == uint)) {
1401 							const double valF = cast(double)val / uint.max;
1402 							channels[chNum].outLevels[2] = valF * valF;
1403 						} else static if (is(T == ubyte)) {
1404 							if (type)
1405 								paramTemp[2] = val;
1406 							else
1407 								paramTemp[3] = val;
1408 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1409 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1410 								const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1411 								channels[chNum].outLevels[2] = valF * valF;
1412 							} else {		//Set temp for next command (assume MSB-LSB order)
1413 								paramNum[0] = paramTemp[0];
1414 								paramNum[1] = paramTemp[1];
1415 							}
1416 						}
1417 						break;
1418 					case ChannelParamNums.Bal: 
1419 						static if (is(T == uint)) {
1420 							channels[chNum].masterBal = cast(double)val / uint.max;
1421 						} else static if (is(T == ubyte)) {
1422 							if (type)
1423 								paramTemp[2] = val;
1424 							else
1425 								paramTemp[3] = val;
1426 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1427 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1428 								channels[chNum].masterBal = cast(double)(val32) / cast(double)(ushort.max>>2);
1429 							} else {		//Set temp for next command (assume MSB-LSB order)
1430 								paramNum[0] = paramTemp[0];
1431 								paramNum[1] = paramTemp[1];
1432 								return;
1433 							}
1434 						}
1435 						if (channels[chNum].chCtrl & Channel.ChCtrlFlags.IndivOutChLev) {
1436 							channels[chNum].outLevels[1] = channels[chNum].masterBal * channels[chNum].masterBal;
1437 						} else {
1438 							channels[chNum].outLevels[0] = channels[chNum].masterVol - channels[chNum].masterBal;
1439 							channels[chNum].outLevels[1] = channels[chNum].masterVol - (1.0 - channels[chNum].masterBal);
1440 						}
1441 						break;
1442 					case ChannelParamNums.ChCtrl:
1443 						static if (is(T == uint)) {
1444 							channels[chNum].chCtrl = val;
1445 						} else static if (is(T == ubyte)) {
1446 							if (type) {
1447 								channels[chNum].chCtrl &= ~(byte.max<<7);
1448 								channels[chNum].chCtrl |= val<<7;
1449 							} else {
1450 								channels[chNum].chCtrl &= ~(cast(uint)byte.max);
1451 								channels[chNum].chCtrl |= val;
1452 							}
1453 						}
1454 						//mirror operator configuration parameters between paired channels
1455 						if (chNum < 8) {
1456 							channels[chNum + 8].chCtrl &= ~Channel.ChCtrlFlags.ComboModeTest;
1457 							channels[chNum + 8].chCtrl |= Channel.ChCtrlFlags.ComboModeTest & channels[chNum].chCtrl;
1458 						} else {
1459 							channels[chNum - 8].chCtrl &= ~Channel.ChCtrlFlags.ComboModeTest;
1460 							channels[chNum - 8].chCtrl |= Channel.ChCtrlFlags.ComboModeTest & channels[chNum].chCtrl;
1461 						}
1462 						break;
1463 					//case ChannelParamNums.ChCtrlL: break;
1464 					case ChannelParamNums.Decay:
1465 						static if (is(T == uint)) {
1466 							channels[chNum].decX = cast(ubyte)(val >> 25);
1467 						} else static if (is(T == ubyte)) {
1468 							channels[chNum].decX = val;
1469 						}
1470 						if (channels[chNum].decX) {
1471 							channels[chNum].eeg.decayRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].decX] * 2, sampleRate);
1472 						} else {
1473 							channels[chNum].eeg.decayRate = 1.0;
1474 						}
1475 						break;
1476 					case ChannelParamNums.EEGDetune:
1477 						static if (is(T == uint)) {
1478 							channels[chNum].eegDetuneAm = val;
1479 						} else static if (is(T == ubyte)) {
1480 							if (type)
1481 								paramTemp[2] = val;
1482 							else
1483 								paramTemp[3] = val;
1484 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1485 								channels[chNum].eegDetuneAm = paramTemp[3] | paramTemp[2]<<7;
1486 							} else {		//Set temp for next command (assume MSB-LSB order)
1487 								paramNum[0] = paramTemp[0];
1488 								paramNum[1] = paramTemp[1];
1489 							}
1490 						}
1491 						break;
1492 					case ChannelParamNums.MasterVol: 
1493 						static if (is(T == uint)) {
1494 							const double valF = cast(double)val / uint.max;
1495 							channels[chNum].outLevels[2] = valF * valF;
1496 						} else static if (is(T == ubyte)) {
1497 							if (type)
1498 								paramTemp[2] = val;
1499 							else
1500 								paramTemp[3] = val;
1501 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1502 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1503 								const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1504 								channels[chNum].outLevels[2] = valF * valF;
1505 							} else {		//Set temp for next command (assume MSB-LSB order)
1506 								paramNum[0] = paramTemp[0];
1507 								paramNum[1] = paramTemp[1];
1508 							}
1509 						}
1510 						if (channels[chNum].chCtrl & Channel.ChCtrlFlags.IndivOutChLev) {
1511 							channels[chNum].outLevels[1] = channels[chNum].masterBal * channels[chNum].masterBal;
1512 						} else {
1513 							channels[chNum].outLevels[0] = channels[chNum].masterVol - channels[chNum].masterBal;
1514 							channels[chNum].outLevels[1] = channels[chNum].masterVol - (1.0 - channels[chNum].masterBal);
1515 						}
1516 						break;
1517 					case ChannelParamNums.PLFO: 
1518 						static if (is(T == uint)) {
1519 							channels[chNum].pLFOlevel = cast(double)val / uint.max;
1520 						} else static if (is(T == ubyte)) {
1521 							if (type)
1522 								paramTemp[2] = val;
1523 							else
1524 								paramTemp[3] = val;
1525 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1526 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1527 								channels[chNum].pLFOlevel = cast(double)(val32) / cast(double)(ushort.max>>2);
1528 							} else {		//Set temp for next command (assume MSB-LSB order)
1529 								paramNum[0] = paramTemp[0];
1530 								paramNum[1] = paramTemp[1];
1531 							}
1532 						}
1533 						break;
1534 					case ChannelParamNums.Release: 
1535 						static if (is(T == uint)) {
1536 							channels[chNum].relX = cast(ubyte)(val >> 25);
1537 						} else static if (is(T == ubyte)) {
1538 							channels[chNum].relX = val;
1539 						}
1540 						if (channels[chNum].relX) {
1541 							channels[chNum].eeg.releaseRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].relX] * 2, sampleRate);
1542 						} else {
1543 							channels[chNum].eeg.releaseRate = 1.0;
1544 						}
1545 						break;
1546 					case ChannelParamNums.ShpA:
1547 						static if (is(T == uint)) {
1548 							channels[chNum].shpAX = cast(double)val / uint.max;
1549 						} else static if (is(T == ubyte)) {
1550 							if (type)
1551 								paramTemp[2] = val;
1552 							else
1553 								paramTemp[3] = val;
1554 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1555 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1556 								channels[chNum].shpAX = cast(double)(val32) / cast(double)(ushort.max>>2);
1557 							} else {		//Set temp for next command (assume MSB-LSB order)
1558 								paramNum[0] = paramTemp[0];
1559 								paramNum[1] = paramTemp[1];
1560 							}
1561 						}
1562 						break;
1563 					case ChannelParamNums.ShpR:
1564 						static if (is(T == uint)) {
1565 							channels[chNum].shpRX = cast(double)val / uint.max;
1566 						} else static if (is(T == ubyte)) {
1567 							if (type)
1568 								paramTemp[2] = val;
1569 							else
1570 								paramTemp[3] = val;
1571 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1572 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1573 								channels[chNum].shpRX = cast(double)(val32) / cast(double)(ushort.max>>2);
1574 							} else {		//Set temp for next command (assume MSB-LSB order)
1575 								paramNum[0] = paramTemp[0];
1576 								paramNum[1] = paramTemp[1];
1577 							}
1578 						}
1579 						break;
1580 					case ChannelParamNums.SusCtrl: 
1581 						static if (is(T == uint)) {
1582 							channels[chNum].susCCX = cast(ubyte)(val >> 25);
1583 						} else static if (is(T == ubyte)) {
1584 							channels[chNum].susCCX = val;
1585 						}
1586 						if (channels[chNum].susCCX) {
1587 							channels[chNum].eeg.isPercussive = false;
1588 							if (channels[chNum].susCCX == 64) {
1589 								channels[chNum].eeg.sustainControl = 0.0;
1590 							} else if (channels[chNum].susCCX < 64) {
1591 								channels[chNum].eeg.sustainControl = -1.0 * 
1592 										calculateRate(SUSTAIN_CONTROL_TIME_TABLE[channels[chNum].susCCX - 1], sampleRate);
1593 							} else {
1594 								channels[chNum].eeg.sustainControl = 
1595 										calculateRate(SUSTAIN_CONTROL_TIME_TABLE[channels[chNum].susCCX - 64], sampleRate);
1596 							}
1597 						} else {
1598 							channels[chNum].eeg.isPercussive = true;
1599 							channels[chNum].eeg.sustainControl = 0.0;
1600 						}
1601 						break;
1602 					case ChannelParamNums.SusLevel: 
1603 						static if (is(T == uint)) {
1604 							channels[chNum].eeg.sustainLevel = cast(double)val / uint.max;
1605 						} else static if (is(T == ubyte)) {
1606 							if (type)
1607 								paramTemp[2] = val;
1608 							else
1609 								paramTemp[3] = val;
1610 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1611 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1612 								channels[chNum].eeg.sustainLevel = cast(double)(val32) / cast(double)(ushort.max>>2);
1613 							} else {		//Set temp for next command (assume MSB-LSB order)
1614 								paramNum[0] = paramTemp[0];
1615 								paramNum[1] = paramTemp[1];
1616 							}
1617 						}
1618 						break;
1619 					case ChannelParamNums.RingMod: 
1620 						static if (is(T == uint)) {
1621 							channels[chNum].rmAmount = val>>16;
1622 						} else static if (is(T == ubyte)) {
1623 							if (type)
1624 								paramTemp[2] = val;
1625 							else
1626 								paramTemp[3] = val;
1627 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1628 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1629 								channels[chNum].eeg.sustainLevel = val32<<2 | val32>>12;
1630 							} else {		//Set temp for next command (assume MSB-LSB order)
1631 								paramNum[0] = paramTemp[0];
1632 								paramNum[1] = paramTemp[1];
1633 							}
1634 						}
1635 						break;
1636 					case ChannelParamNums.EEGToLeft:
1637 						static if (is(T == uint)) {
1638 							const double valF = cast(double)val / uint.max;
1639 							channels[chNum].eegLevels[0] = valF * valF;
1640 						} else static if (is(T == ubyte)) {
1641 							if (type)
1642 								paramTemp[2] = val;
1643 							else
1644 								paramTemp[3] = val;
1645 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1646 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1647 								const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1648 								channels[chNum].eegLevels[0] = valF * valF;
1649 							} else {		//Set temp for next command (assume MSB-LSB order)
1650 								paramNum[0] = paramTemp[0];
1651 								paramNum[1] = paramTemp[1];
1652 							}
1653 						}
1654 						break;
1655 					case ChannelParamNums.EEGToRight:
1656 						static if (is(T == uint)) {
1657 							const double valF = cast(double)val / uint.max;
1658 							channels[chNum].eegLevels[1] = valF * valF;
1659 						} else static if (is(T == ubyte)) {
1660 							if (type)
1661 								paramTemp[2] = val;
1662 							else
1663 								paramTemp[3] = val;
1664 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1665 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1666 								const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1667 								channels[chNum].eegLevels[1] = valF * valF;
1668 							} else {		//Set temp for next command (assume MSB-LSB order)
1669 								paramNum[0] = paramTemp[0];
1670 								paramNum[1] = paramTemp[1];
1671 							}
1672 						}
1673 						break;
1674 					case ChannelParamNums.EEGToAuxA:
1675 						static if (is(T == uint)) {
1676 							const double valF = cast(double)val / uint.max;
1677 							channels[chNum].eegLevels[2] = valF * valF;
1678 						} else static if (is(T == ubyte)) {
1679 							if (type)
1680 								paramTemp[2] = val;
1681 							else
1682 								paramTemp[3] = val;
1683 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1684 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1685 								const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1686 								channels[chNum].eegLevels[2] = valF * valF;
1687 							} else {		//Set temp for next command (assume MSB-LSB order)
1688 								paramNum[0] = paramTemp[0];
1689 								paramNum[1] = paramTemp[1];
1690 							}
1691 						}
1692 						break;
1693 					case ChannelParamNums.EEGToAuxB:
1694 						static if (is(T == uint)) {
1695 							const double valF = cast(double)val / uint.max;
1696 							channels[chNum].eegLevels[3] = valF * valF;
1697 						} else static if (is(T == ubyte)) {
1698 							if (type)
1699 								paramTemp[2] = val;
1700 							else
1701 								paramTemp[3] = val;
1702 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1703 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1704 								const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1705 								channels[chNum].eegLevels[3] = valF * valF;
1706 							} else {		//Set temp for next command (assume MSB-LSB order)
1707 								paramNum[0] = paramTemp[0];
1708 								paramNum[1] = paramTemp[1];
1709 							}
1710 						}
1711 						break;
1712 					case ChannelParamNums.LFOToLeft:
1713 						static if (is(T == uint)) {
1714 							const double valF = cast(double)val / uint.max;
1715 							channels[chNum].aLFOlevels[0] = valF * valF;
1716 						} else static if (is(T == ubyte)) {
1717 							if (type)
1718 								paramTemp[2] = val;
1719 							else
1720 								paramTemp[3] = val;
1721 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1722 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1723 								const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1724 								channels[chNum].aLFOlevels[0] = valF * valF;
1725 							} else {		//Set temp for next command (assume MSB-LSB order)
1726 								paramNum[0] = paramTemp[0];
1727 								paramNum[1] = paramTemp[1];
1728 							}
1729 						}
1730 						break;
1731 					case ChannelParamNums.LFOToRight:
1732 						static if (is(T == uint)) {
1733 							const double valF = cast(double)val / uint.max;
1734 							channels[chNum].aLFOlevels[1] = valF * valF;
1735 						} else static if (is(T == ubyte)) {
1736 							if (type)
1737 								paramTemp[2] = val;
1738 							else
1739 								paramTemp[3] = val;
1740 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1741 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1742 								const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1743 								channels[chNum].aLFOlevels[1] = valF * valF;
1744 							} else {		//Set temp for next command (assume MSB-LSB order)
1745 								paramNum[0] = paramTemp[0];
1746 								paramNum[1] = paramTemp[1];
1747 							}
1748 						}
1749 						break;
1750 					case ChannelParamNums.LFOToAuxA:
1751 						static if (is(T == uint)) {
1752 							const double valF = cast(double)val / uint.max;
1753 							channels[chNum].aLFOlevels[2] = valF * valF;
1754 						} else static if (is(T == ubyte)) {
1755 							if (type)
1756 								paramTemp[2] = val;
1757 							else
1758 								paramTemp[3] = val;
1759 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1760 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1761 								const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1762 								channels[chNum].aLFOlevels[2] = valF * valF;
1763 							} else {		//Set temp for next command (assume MSB-LSB order)
1764 								paramNum[0] = paramTemp[0];
1765 								paramNum[1] = paramTemp[1];
1766 							}
1767 						}
1768 						break;
1769 					case ChannelParamNums.LFOToAuxB:
1770 						static if (is(T == uint)) {
1771 							const double valF = cast(double)val / uint.max;
1772 							channels[chNum].aLFOlevels[3] = valF * valF;
1773 						} else static if (is(T == ubyte)) {
1774 							if (type)
1775 								paramTemp[2] = val;
1776 							else
1777 								paramTemp[3] = val;
1778 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1779 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1780 								const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1781 								channels[chNum].aLFOlevels[3] = valF * valF;
1782 							} else {		//Set temp for next command (assume MSB-LSB order)
1783 								paramNum[0] = paramTemp[0];
1784 								paramNum[1] = paramTemp[1];
1785 							}
1786 						}
1787 						break;
1788 					default:
1789 						break;
1790 				}
1791 				break;
1792 			case 16:		//LFO and master filter settings
1793 				void setFilterFreq(int num) @nogc @safe pure nothrow {
1794 					static if (is(T == uint)) {
1795 						const double valF = cast(double)val / uint.max;
1796 						filterCtrl[num] = valF * valF * 22_000;
1797 					} else static if (is(T == ubyte)) {
1798 						if (type)
1799 							paramTemp[2] = val;
1800 						else
1801 							paramTemp[3] = val;
1802 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1803 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1804 							const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1805 							filterCtrl[num] = valF * valF * 22_000;
1806 						} else {		//Set temp for next command (assume MSB-LSB order)
1807 							paramNum[0] = paramTemp[0];
1808 							paramNum[1] = paramTemp[1];
1809 						}
1810 					}
1811 				}
1812 				void setFilterQ(int num) @nogc @safe pure nothrow {
1813 					static if (is(T == uint)) {
1814 						const double valF = cast(double)val / uint.max;
1815 						filterCtrl[num] = valF * 2;
1816 					} else static if (is(T == ubyte)) {
1817 						if (type)
1818 							paramTemp[2] = val;
1819 						else
1820 							paramTemp[3] = val;
1821 						if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1822 							const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1823 							const double valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1824 							filterCtrl[num] = valF * 2;
1825 						} else {		//Set temp for next command (assume MSB-LSB order)
1826 							paramNum[0] = paramTemp[0];
1827 							paramNum[1] = paramTemp[1];
1828 						}
1829 					}
1830 				}
1831 				switch (paramNum[0]) {
1832 					case GlobalParamNums.PLFORate:
1833 						double valF;
1834 						static if (is(T == uint)) {
1835 							valF = cast(double)val / uint.max;
1836 						} else static if (is(T == ubyte)) {
1837 							if (type)
1838 								paramTemp[2] = val;
1839 							else
1840 								paramTemp[3] = val;
1841 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1842 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1843 								valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1844 							} else {		//Set temp for next command (assume MSB-LSB order)
1845 								paramNum[0] = paramTemp[0];
1846 								paramNum[1] = paramTemp[1];
1847 								return;
1848 							}
1849 						}
1850 						valF *= 16;
1851 						const double cycleLen = sampleRate / (1.0 / valF);
1852 						pLFORate = cast(int)(cycleLen * ((1<<20) / 1024.0) * bufferSize);
1853 						break;
1854 					case GlobalParamNums.PLFOWF:
1855 						static if (is(T == uint)) {
1856 							lfoWaveform[0] = cast(ubyte)(val >> 25);
1857 						} else static if (is(T == ubyte)) {
1858 							lfoWaveform[0] = val;
1859 						}
1860 						break;
1861 					case GlobalParamNums.ALFORate:
1862 						double valF;
1863 						static if (is(T == uint)) {
1864 							valF = cast(double)val / uint.max;
1865 						} else static if (is(T == ubyte)) {
1866 							if (type)
1867 								paramTemp[2] = val;
1868 							else
1869 								paramTemp[3] = val;
1870 							if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) {	//Set parameter if  found.
1871 								const uint val32 = paramTemp[3] | paramTemp[2]<<7;
1872 								valF = cast(double)(val32) / cast(double)(ushort.max>>2);
1873 							} else {		//Set temp for next command (assume MSB-LSB order)
1874 								paramNum[0] = paramTemp[0];
1875 								paramNum[1] = paramTemp[1];
1876 								return;
1877 							}
1878 						}
1879 						valF *= 16;
1880 						const double cycleLen = sampleRate / (1.0 / valF);
1881 						aLFORate = cast(int)(cycleLen * ((1<<20) / 1024.0));
1882 						break;
1883 					case GlobalParamNums.ALFOWF:
1884 						static if (is(T == uint)) {
1885 							lfoWaveform[1] = cast(ubyte)(val >> 25);
1886 						} else static if (is(T == ubyte)) {
1887 							lfoWaveform[1] = val;
1888 						}
1889 						break;
1890 					case GlobalParamNums.FilterLCFreq:
1891 						setFilterFreq(0);
1892 						break;
1893 					case GlobalParamNums.FilterLCQ: 
1894 						setFilterQ(1);
1895 						break;
1896 					case GlobalParamNums.FilterRCFreq: 
1897 						setFilterFreq(2);
1898 						break;
1899 					case GlobalParamNums.FilterRCQ: 
1900 						setFilterQ(3);
1901 						break;
1902 					case GlobalParamNums.FilterACFreq:
1903 						setFilterFreq(4);
1904 						break;
1905 					case GlobalParamNums.FilterACQ: 
1906 						setFilterQ(5);
1907 						break;
1908 					case GlobalParamNums.FilterBCFreq: 
1909 						setFilterFreq(6);
1910 						break;
1911 					case GlobalParamNums.FilterBCQ: 
1912 						setFilterQ(7);
1913 						break;
1914 					default:
1915 						break;
1916 				}
1917 				break;
1918 			default: break;
1919 		}
1920 	}
1921 	/**
1922 	 * Renders the current audio frame.
1923 	 * 
1924 	 * input: the input buffers if any, null if none.
1925 	 * output: the output buffers if any, null if none.
1926 	 * length: the lenth of the current audio frame in samples.
1927 	 *
1928 	 * NOTE: Buffers must have matching sizes.
1929 	 */
1930 	public override void renderFrame(float*[] input, float*[] output) @nogc nothrow {
1931 		//Generate aLFO table
1932 		for (int i ; i < bufferSize ; i++) {
1933 			aLFOBuf[i] = (wavetables[lfoWaveform[1]][(aLFOPos>>20) & 1023] - short.min) * (1 / cast(float)(ushort.max));
1934 			aLFOPos += aLFORate;
1935 		}
1936 		//Generate pLFO out
1937 		{
1938 			pLFOOut = (wavetables[lfoWaveform[0]][(pLFOPos>>20) & 1023]) * (1 / cast(float)(short.max));
1939 			pLFOPos += pLFORate;
1940 		}
1941 		//Render each channel
1942 		foreach (size_t i, ChFun fun ; chDeleg) {
1943 			fun(cast(int)i, bufferSize);
1944 		}
1945 		//Filter and mix outputs
1946 		float*[4] outBuf;
1947 		for (ubyte i, j ; i < 4 ; i++) {
1948 			if (enabledOutputs.has(i)) {
1949 				outBuf[i] = output[j];
1950 				j++;
1951 			} else {
1952 				outBuf[i] = dummyBuf.ptr;
1953 			}
1954 		}
1955 		const __m128 b0_a0 = filterVals[3] / filterVals[0], b1_a0 = filterVals[4] / filterVals[0], 
1956 				b2_a0 = filterVals[5] / filterVals[0], a1_a0 = filterVals[1] / filterVals[0], a2_a0 = filterVals[2] / filterVals[0];
1957 		for (int i ; i < bufferSize ; i++) {
1958 			__m128 input0 = _mm_load_ps(initBuffers.ptr + i);
1959 			input0 *= __m128(mixdownVal);
1960 			input0 = _mm_max_ps(input0, __m128(-1.0));
1961 			input0 = _mm_min_ps(input0, __m128(1.0));
1962 			__m128 output0 = b0_a0 * input0 + b1_a0 * filterVals[6] + b2_a0 * filterVals[7] - a1_a0 * filterVals[8] - 
1963 					a2_a0 * filterVals[9];
1964 			for (int j ; j < 4 ; j++)
1965 				outBuf[j][i] += output0[j];
1966 			filterVals[7] = filterVals[6];
1967 			filterVals[6] = input0;
1968 			filterVals[9] = filterVals[8];
1969 			filterVals[8] = output0;
1970 		}
1971 	}
1972 	///Updates an operator for a cycle
1973 	///chCtrl index notation: 0: velocity, 1: modulation wheel, 2: Amplitude LFO, 3: Extra Envelop Generator
1974 	pragma(inline, true)
1975 	protected final void updateOperator(ref Operator op, __m128 chCtrl) @nogc @safe pure nothrow {
1976 		op.output = wavetables[op.opCtrl & Operator.OpCtrlFlags.WavetableSelect][(op.pos>>20 + op.input>>4 + op.feedback>>3) 
1977 				& 0x3_FF];
1978 		const double egOut = op.eg.shp(op.eg.position == ADSREnvelopGenerator.Stage.Attack ? op.shpA0 : op.shpR0);
1979 		const double out0 = op.output;
1980 		__m128 outCtrl = (op.outLCtrl * chCtrl) + (__m128(1.0) - (__m128(1.0) * op.outLCtrl));
1981 		__m128 fbCtrl = (op.fbLCtrl * chCtrl) + (__m128(1.0) - (__m128(1.0) * op.fbLCtrl));
1982 		const double out1 = out0 * egOut;
1983 		//vel = op.opCtrl & Operator.OpCtrlFlags.VelNegative ? 1.0 - vel : vel;
1984 		op.feedback = cast(int)((op.opCtrl & Operator.OpCtrlFlags.FBMode ? out0 : out1) * op.fbL * fbCtrl[0] * fbCtrl[1] * 
1985 				fbCtrl[2] * fbCtrl[3]);
1986 		//op.feedback *= op.opCtrl & Operator.OpCtrlFlags.FBNeg ? -1 : 1;
1987 		op.output_0 = cast(int)(out1 * op.outL * outCtrl[0] * outCtrl[1] * outCtrl[2]);
1988 		op.pos += op.step;
1989 		//op.input = 0;
1990 		op.eg.advance();
1991 	}
1992 	///Macro for channel update constants that need to be calculated once per frame
1993 	///Kept in at one place to make updates easier and more consistent
1994 	static immutable string CHNL_UPDATE_CONSTS =
1995 		`const int opOffset = chNum * 2;` ~
1996 		`__m128 aLFOOutMW = __m128(channels[chNum].chCtrl & Channel.ChCtrlFlags.MWToTrem ? chCtrls[chNum].modwheel : 1.0);` ~
1997 		`const float auxSendAmMW = (channels[chNum].chCtrl & Channel.ChCtrlFlags.MWToAux ? chCtrls[chNum].modwheel : 1.0);` ~
1998 		`__m128 opCtrl0, opCtrl1, mwAuxCtrl;` ~
1999 		`opCtrl0[0] = operators[opOffset].opCtrl & Operator.OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : ` ~
2000 				`chCtrls[chNum].velocity;` ~
2001 		`opCtrl1[0] = operators[opOffset + 1].opCtrl & Operator.OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : ` ~
2002 				`chCtrls[chNum].velocity;` ~
2003 		`opCtrl0[1] = operators[opOffset].opCtrl & Operator.OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : ` ~
2004 				`chCtrls[chNum].modwheel;` ~
2005 		`opCtrl1[1] = operators[opOffset + 1].opCtrl & Operator.OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : ` ~
2006 				`chCtrls[chNum].modwheel;` ~
2007 		`mwAuxCtrl[0] = 1.0;` ~
2008 		`mwAuxCtrl[1] = 1.0;` ~
2009 		`mwAuxCtrl[2] = auxSendAmMW;` ~
2010 		`mwAuxCtrl[3] = auxSendAmMW;` ~
2011 		`const float lfopan = (channels[chNum].chCtrl & Channel.ChCtrlFlags.LFOPan ? 1.0 : 0);` ~
2012 		`const float eegpan = (channels[chNum].chCtrl & Channel.ChCtrlFlags.EEGPan ? 1.0 : 0);`
2013 		;
2014 	///Macro for channel update constants that need to be calculated once per frame, for combined channels' second half
2015 	///Kept in at one place to make updates easier and more consistent
2016 	static immutable string CHNL_UPDATE_CONSTS0 =
2017 		`__m128 opCtrl2, opCtrl3;` ~
2018 		`opCtrl2[0] = operators[opOffset + 16].opCtrl & Operator.OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : ` ~
2019 				`chCtrls[chNum].velocity;` ~
2020 		`opCtrl3[0] = operators[opOffset + 17].opCtrl & Operator.OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : ` ~
2021 				`chCtrls[chNum].velocity;` ~
2022 		`opCtrl2[1] = operators[opOffset + 16].opCtrl & Operator.OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : ` ~
2023 				`chCtrls[chNum].modwheel;` ~
2024 		`opCtrl3[1] = operators[opOffset + 17].opCtrl & Operator.OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : ` ~
2025 				`chCtrls[chNum].modwheel;` ~
2026 		`const float eegpan0 = (channels[chNum + 8].chCtrl & Channel.ChCtrlFlags.EEGPan ? 1.0 : 0);`
2027 		;
2028 	///Macro for channel update constants that need to be calculated for each cycle
2029 	///Kept in at one place to make updates easier and more consistent
2030 	static immutable string CHNL_UPDATE_CONSTS_CYCL = 
2031 		`const float eegOut = channels[chNum].eeg.shp(channels[chNum].eeg.position == ADSREnvelopGenerator.Stage.Attack ? ` ~
2032 				`channels[chNum].shpAX : channels[chNum].shpRX);` ~
2033 		`__m128 eegToMast = __m128(eegOut), lfoToMast = __m128(aLFOBuf[i]);` ~
2034 		`eegToMast[0] = abs(eegpan - eegToMast[0]);` ~
2035 		`lfoToMast[0] = abs(lfopan - lfoToMast[0]);` ~
2036 		`opCtrl0[2] = aLFOBuf[i];` ~
2037 		`opCtrl1[2] = aLFOBuf[i];` ~
2038 		`opCtrl0[3] = eegOut;` ~
2039 		`opCtrl1[3] = eegOut;`
2040 		;
2041 	
2042 	///Macro for channel update constants that need to be calculated for each cycle for combined channels' second half
2043 	///Kept in at one place to make updates easier and more consistent
2044 	static immutable string CHNL_UPDATE_CONSTS_CYCL0 = 
2045 		`const float eegOut0 = channels[chNum + 8].eeg.shp(channels[chNum + 8].eeg.position == ` ~
2046 				`ADSREnvelopGenerator.Stage.Attack ? channels[chNum + 8].shpAX : channels[chNum + 8].shpRX);` ~
2047 		`__m128 eegToMast0 = __m128(eegOut0);` ~
2048 		`eegToMast0[0] = abs(eegpan0 - eegToMast0[0]);` ~
2049 		`opCtrl2[2] = aLFOBuf[i];` ~
2050 		`opCtrl3[2] = aLFOBuf[i];` ~
2051 		`opCtrl2[3] = eegOut0;` ~
2052 		`opCtrl3[3] = eegOut0;`
2053 		;
2054 			
2055 	///Macro for output mixing
2056 	static immutable string CHNL_UPDATE_MIX =
2057 		"__m128 outlevels = channels[chNum].outLevels * mwAuxCtrl;" ~
2058 		"outlevels *= (channels[chNum].eegLevels * eegToMast) + (__m128(1.0) - (__m128(1.0) * channels[chNum].eegLevels));" ~
2059 		"outlevels *= (channels[chNum].aLFOlevels * lfoToMast) + (__m128(1.0) - (__m128(1.0) * channels[chNum].aLFOlevels));"~
2060 		"_mm_store1_ps(initBuffers.ptr + (i<<2), _mm_load_ps(initBuffers.ptr + (i<<2)) + outlevels *" ~ 
2061 		"		_mm_cvtepi32_ps(outSum));"
2062 		;
2063 	///Macro for output mixing in case of combo modes
2064 	static immutable string CHNL_UPDATE_MIX0 =
2065 		"__m128 outlevels = channels[chNum].outLevels * mwAuxCtrl;" ~
2066 		"outlevels *= (channels[chNum].eegLevels * eegToMast) + (__m128(1.0) - (__m128(1.0) * channels[chNum].eegLevels));" ~
2067 		"outlevels *= (channels[chNum + 8].eegLevels * eegToMast0) + (__m128(1.0) - " ~
2068 		" (__m128(1.0) * channels[chNum + 8].eegLevels));" ~
2069 		"outlevels *= (channels[chNum].aLFOlevels * lfoToMast) + (__m128(1.0) - (__m128(1.0) * channels[chNum].aLFOlevels));"~
2070 		"_mm_store1_ps(initBuffers.ptr + (i<<2), _mm_load_ps(initBuffers.ptr + (i<<2)) + outlevels *" ~ 
2071 		"		_mm_cvtepi32_ps(outSum));"
2072 		;
2073 	
2074 
2075 	///Algorithm Mode 0/0 (Serial)
2076 	protected void updateChannelM00(int chNum, size_t length) @nogc pure nothrow {
2077 		mixin(CHNL_UPDATE_CONSTS);
2078 		for (size_t i ; i < length ; i++) {
2079 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2080 			updateOperator(operators[opOffset], opCtrl0);
2081 			operators[opOffset + 1].input = operators[opOffset].output_0;
2082 			updateOperator(operators[opOffset + 1], opCtrl1);
2083 			//const int outSum = operators[opOffset].output_0;
2084 			__m128i outSum = __m128i(operators[opOffset + 1].output_0);
2085 			mixin(CHNL_UPDATE_MIX);
2086 			channels[chNum].eeg.advance();
2087 		}
2088 	}
2089 	///Algorithm Mode0/1 (Parallel)
2090 	protected void updateChannelM01(int chNum, size_t length) @nogc pure nothrow {
2091 		mixin(CHNL_UPDATE_CONSTS);
2092 		for (size_t i ; i < length ; i++) {
2093 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2094 			updateOperator(operators[opOffset], opCtrl0);
2095 			updateOperator(operators[opOffset + 1], opCtrl1);
2096 			//const int outSum = operators[opOffset].output_0 + operators[opOffset + 1].output_0;
2097 			__m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 
2098 					((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].rmAmount)>>16);
2099 			mixin(CHNL_UPDATE_MIX);
2100 			channels[chNum].eeg.advance();
2101 		}
2102 	}
2103 	///Algorithm Mode1/00 ([S0]->[S1]->[P0]->[P1])
2104 	protected void updateChannelM100(int chNum, size_t length) @nogc pure nothrow {
2105 		mixin(CHNL_UPDATE_CONSTS);
2106 		mixin(CHNL_UPDATE_CONSTS0);
2107 		for (size_t i ; i < length ; i++) {
2108 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2109 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2110 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2111 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2112 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2113 			operators[opOffset].input = operators[opOffset + 17].output_0;
2114 			updateOperator(operators[opOffset], opCtrl0);		//P0
2115 			operators[opOffset + 1].input = operators[opOffset].output_0;
2116 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2117 			//const int outSum = operators[opOffset + 1].output_0;
2118 			__m128i outSum = __m128i(operators[opOffset + 1].output_0);
2119 			mixin(CHNL_UPDATE_MIX);
2120 			channels[chNum].eeg.advance();
2121 			channels[chNum + 8].eeg.advance();
2122 		}
2123 	}
2124 	///Dummy algorithm for combined channels
2125 	protected void updateChannelMD(int chNum, size_t length) @nogc pure nothrow {
2126 
2127 	}
2128 	/**
2129 	Algorithm Mode1/10
2130 	[S0]\
2131     	 ->[P0]->[P1]->
2132 	[S1]/
2133 	*/
2134 	protected void updateChannelM110(int chNum, size_t length) @nogc pure nothrow {
2135 		mixin(CHNL_UPDATE_CONSTS);
2136 		mixin(CHNL_UPDATE_CONSTS0);
2137 		for (size_t i ; i < length ; i++) {
2138 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2139 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2140 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2141 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2142 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2143 			operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
2144 			updateOperator(operators[opOffset], opCtrl0);		//P0
2145 			operators[opOffset + 1].input = operators[opOffset].output_0;
2146 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2147 			//const int outSum = operators[opOffset + 1].output_0;
2148 			__m128i outSum = __m128i(operators[opOffset + 1].output_0);
2149 			mixin(CHNL_UPDATE_MIX);
2150 			channels[chNum].eeg.advance();
2151 			channels[chNum + 8].eeg.advance();
2152 		}
2153 	}
2154 	/**
2155 	Algorithm Mode1/01
2156 	[S0]->[S1]->[P0]->
2157             	[P1]->
2158 	*/
2159 	protected void updateChannelM101(int chNum, size_t length) @nogc pure nothrow {
2160 		mixin(CHNL_UPDATE_CONSTS);
2161 		mixin(CHNL_UPDATE_CONSTS0);
2162 		for (size_t i ; i < length ; i++) {
2163 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2164 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2165 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2166 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2167 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2168 			operators[opOffset].input = operators[opOffset + 17].output_0;
2169 			updateOperator(operators[opOffset], opCtrl0);		//P0
2170 			//operators[opOffset + 1].input = operators[opOffset].output_0;
2171 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2172 			//const int outSum = operators[opOffset + 1].output_0;
2173 			__m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 
2174 					((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].rmAmount)>>16);
2175 			mixin(CHNL_UPDATE_MIX);
2176 			channels[chNum].eeg.advance();
2177 			channels[chNum + 8].eeg.advance();
2178 		}
2179 	}
2180 	/**
2181 	Algorithm Mode1/11
2182 	[S0]\
2183     	 ->[P0]->
2184 	[S1]/  [P1]->
2185 	*/
2186 	protected void updateChannelM111(int chNum, size_t length) @nogc pure nothrow {
2187 		mixin(CHNL_UPDATE_CONSTS);
2188 		mixin(CHNL_UPDATE_CONSTS0);
2189 		for (size_t i ; i < length ; i++) {
2190 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2191 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2192 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2193 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2194 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2195 			operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
2196 			updateOperator(operators[opOffset], opCtrl0);		//P0
2197 			//operators[opOffset + 1].input = operators[opOffset].output_0;
2198 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2199 			//const int outSum = operators[opOffset + 1].output_0;
2200 			__m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 
2201 					((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].rmAmount)>>16);
2202 			mixin(CHNL_UPDATE_MIX);
2203 			channels[chNum].eeg.advance();
2204 			channels[chNum + 8].eeg.advance();
2205 		}
2206 	}
2207 	/**
2208 	Algorithm Mode2/00
2209 	[S0]->[S1]\
2210 	           ->[P1]->
2211     	  [P0]/
2212 	*/
2213 	protected void updateChannelM200(int chNum, size_t length) @nogc pure nothrow {
2214 		mixin(CHNL_UPDATE_CONSTS);
2215 		mixin(CHNL_UPDATE_CONSTS0);
2216 		for (size_t i ; i < length ; i++) {
2217 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2218 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2219 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2220 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2221 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2222 			//operators[opOffset].input = operators[opOffset + 17].output_0;
2223 			updateOperator(operators[opOffset], opCtrl0);		//P0
2224 			operators[opOffset + 1].input = operators[opOffset].output_0 + operators[opOffset + 17].output_0;
2225 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2226 			//const int outSum = operators[opOffset + 1].output_0;
2227 			__m128i outSum = __m128i(operators[opOffset + 1].output_0);
2228 			mixin(CHNL_UPDATE_MIX);
2229 			channels[chNum].eeg.advance();
2230 			channels[chNum + 8].eeg.advance();
2231 		}
2232 	}
2233 	/**
2234 	Algorithm Mode2/10
2235 	[S0]\
2236 	[S1]-->[P1]->
2237 	[P0]/
2238 	*/
2239 	protected void updateChannelM210(int chNum, size_t length) @nogc pure nothrow {
2240 		mixin(CHNL_UPDATE_CONSTS);
2241 		mixin(CHNL_UPDATE_CONSTS0);
2242 		for (size_t i ; i < length ; i++) {
2243 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2244 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2245 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2246 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2247 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2248 			//operators[opOffset].input = operators[opOffset + 17].output_0;
2249 			updateOperator(operators[opOffset], opCtrl0);		//P0
2250 			operators[opOffset + 1].input = operators[opOffset].output_0 + operators[opOffset + 17].output_0 + 
2251 					operators[opOffset + 16].output_0;
2252 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2253 			//const int outSum = operators[opOffset + 1].output_0;
2254 			__m128i outSum = __m128i(operators[opOffset + 1].output_0);
2255 			mixin(CHNL_UPDATE_MIX);
2256 			channels[chNum].eeg.advance();
2257 			channels[chNum + 8].eeg.advance();
2258 		}
2259 	}
2260 	/**
2261 	Algorithm Mode2/01
2262 	          /[P0]->
2263 	[S0]->[S1]
2264     	      \[P1]->
2265 	*/
2266 	protected void updateChannelM201(int chNum, size_t length) @nogc pure nothrow {
2267 		mixin(CHNL_UPDATE_CONSTS);
2268 		mixin(CHNL_UPDATE_CONSTS0);
2269 		for (size_t i ; i < length ; i++) {
2270 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2271 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2272 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2273 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2274 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2275 			operators[opOffset].input = operators[opOffset + 17].output_0;
2276 			updateOperator(operators[opOffset], opCtrl0);		//P0
2277 			operators[opOffset + 1].input = operators[opOffset + 17].output_0;
2278 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2279 			//const int outSum = operators[opOffset + 1].output_0;
2280 			__m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset].output_0 + 
2281 					((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].rmAmount)>>16);
2282 			mixin(CHNL_UPDATE_MIX);
2283 			channels[chNum].eeg.advance();
2284 			channels[chNum + 8].eeg.advance();
2285 		}
2286 	}
2287 	/**
2288 	Algorithm Mode2/11
2289 	[S0]\ /[P0]->
2290 	     -
2291 	[S1]/ \[P1]->
2292 	*/
2293 	protected void updateChannelM211(int chNum, size_t length) @nogc pure nothrow {
2294 		mixin(CHNL_UPDATE_CONSTS);
2295 		mixin(CHNL_UPDATE_CONSTS0);
2296 		for (size_t i ; i < length ; i++) {
2297 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2298 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2299 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2300 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2301 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2302 			operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
2303 			updateOperator(operators[opOffset], opCtrl0);		//P0
2304 			operators[opOffset + 1].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
2305 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2306 			//const int outSum = operators[opOffset + 1].output_0;
2307 			__m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset].output_0 + 
2308 					((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].rmAmount)>>16);
2309 			mixin(CHNL_UPDATE_MIX);
2310 			channels[chNum].eeg.advance();
2311 			channels[chNum + 8].eeg.advance();
2312 		}
2313 	}
2314 	/**
2315 	Algorithm Mode3/00
2316 	[S0]->[S1]->
2317 	[P0]->[P1]->
2318 	*/
2319 	protected void updateChannelM300(int chNum, size_t length) @nogc pure nothrow {
2320 		mixin(CHNL_UPDATE_CONSTS);
2321 		mixin(CHNL_UPDATE_CONSTS0);
2322 		for (size_t i ; i < length ; i++) {
2323 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2324 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2325 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2326 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2327 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2328 			//operators[opOffset].input = operators[opOffset + 17].output_0;
2329 			updateOperator(operators[opOffset], opCtrl0);		//P0
2330 			operators[opOffset + 1].input = operators[opOffset].output_0;
2331 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2332 			//const int outSum = operators[opOffset + 1].output_0;
2333 			__m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset + 17].output_0 + 
2334 					((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].rmAmount)>>16);
2335 			mixin(CHNL_UPDATE_MIX);
2336 			channels[chNum].eeg.advance();
2337 			channels[chNum + 8].eeg.advance();
2338 		}
2339 	}
2340 	/**
2341 	Algorithm Mode3/10
2342 	      [S0]->
2343     	  [S1]->
2344 	[P0]->[P1]->
2345 	*/
2346 	protected void updateChannelM310(int chNum, size_t length) @nogc pure nothrow {
2347 		mixin(CHNL_UPDATE_CONSTS);
2348 		mixin(CHNL_UPDATE_CONSTS0);
2349 		for (size_t i ; i < length ; i++) {
2350 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2351 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2352 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2353 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2354 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2355 			//operators[opOffset].input = operators[opOffset + 17].output_0;
2356 			updateOperator(operators[opOffset], opCtrl0);		//P0
2357 			operators[opOffset + 1].input = operators[opOffset].output_0;
2358 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2359 			//const int outSum = operators[opOffset + 1].output_0;
2360 			__m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset + 17].output_0 + 
2361 					operators[opOffset + 16].output_0 + 
2362 					((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].rmAmount)>>16);
2363 			mixin(CHNL_UPDATE_MIX);
2364 			channels[chNum].eeg.advance();
2365 			channels[chNum + 8].eeg.advance();
2366 		}
2367 	}
2368 	/**
2369 	Algorithm Mode3/01
2370 	    />[S1]->
2371 	[S0]->[P0]->
2372     	\>[P1]->
2373 	*/
2374 	protected void updateChannelM301(int chNum, size_t length) @nogc pure nothrow {
2375 		mixin(CHNL_UPDATE_CONSTS);
2376 		mixin(CHNL_UPDATE_CONSTS0);
2377 		for (size_t i ; i < length ; i++) {
2378 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2379 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2380 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2381 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2382 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2383 			operators[opOffset].input = operators[opOffset + 16].output_0;
2384 			updateOperator(operators[opOffset], opCtrl0);		//P0
2385 			operators[opOffset + 1].input = operators[opOffset + 16].output_0;
2386 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2387 			//const int outSum = operators[opOffset + 1].output_0;
2388 			__m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 
2389 					operators[opOffset + 17].output_0 + 
2390 					((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].rmAmount)>>16);
2391 			mixin(CHNL_UPDATE_MIX);
2392 			channels[chNum].eeg.advance();
2393 			channels[chNum + 8].eeg.advance();
2394 		}
2395 	}
2396 	/**
2397 	Algorithm Mode3/11
2398 	[S0]->
2399 	[S1]->
2400 	[P0]->
2401 	[P1]->
2402 	*/
2403 	protected void updateChannelM311(int chNum, size_t length) @nogc pure nothrow {
2404 		mixin(CHNL_UPDATE_CONSTS);
2405 		mixin(CHNL_UPDATE_CONSTS0);
2406 		for (size_t i ; i < length ; i++) {
2407 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2408 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2409 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2410 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2411 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2412 			//operators[opOffset].input = operators[opOffset + 17].output_0;
2413 			updateOperator(operators[opOffset], opCtrl0);		//P0
2414 			//operators[opOffset + 1].input = operators[opOffset].output_0;
2415 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2416 			//const int outSum = operators[opOffset + 1].output_0;
2417 			__m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset].output_0 +
2418 					operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0 + 
2419 					((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].rmAmount)>>16);
2420 			mixin(CHNL_UPDATE_MIX);
2421 			channels[chNum].eeg.advance();
2422 			channels[chNum + 8].eeg.advance();
2423 		}
2424 	}
2425 }