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 bitleveld.reinterpret;
13 
14 import std.math;
15 
16 /**
17 QM816 - implements a Quadrature-Amplitude synthesizer. This technique was used in early 
18 digital FM synths, since it allowed allowed a cheap implementation of the same thing as
19 long as the modulator was a sinusoidal waveform.
20 
21 It has 16 2 operator channels that can be individually paired-up for 4 operator channels,
22 for more complex sounds. Also all operators have the option for feedback, including 
23 carriers. 2 operator channels have 2, 4 operator channels have 3*4 algorithms.
24 
25 The audiomodule generates a few default waveforms upon startup, but further ones can be
26 supplied from files, or generated by code. Some waveform generation code is already
27 supplied with the synth's code.
28 */
29 public class QM816 : AudioModule {
30 	shared static this() {
31 		for (int i ; i < 256 ; i++) {
32 			SINEWAVE_FRAGMENT[i] = cast(short)(sin((PI_2 / 256) * i) * short.max);
33 		}
34 	}
35 	/**
36 	Generates a waveform from a sinewave fragment (quarter).
37 
38 	q flags:
39 	bit 0 = If set, then the sine fragment is present. If not, this portion will be replaced with all zeros instead.
40 	bit 1-2 = Doubling mode:
41 		0 = No doubling.
42 		1 = Same cycle twice.
43 		2 = Same cycle mirrored, effectively putting a half-sine into a quarter with the right settings.
44 		3 = The second half is all zeros, the sine fragment is effectively "stuffed" into an eight of the waveform.
45 	bit 3 = Horizontal mirroring of the cycle.
46 	bit 4 = Vertical mirroring of the cycle.
47 	*/
48 	public static short[1024] generateSinewave(ubyte[4] q) @nogc @safe pure nothrow {
49 		short[1024] result;
50 		for (int j ; j < 4 ; j++) {
51 			if (q[j] & 1) {
52 				const int offset = 256 * j;
53 				int hMir = q[j] & 0x8 ? -1 : 1;
54 				int hBegin = q[j] & 0x8 ? 255 : 0;
55 				const int vOffset = q[j] & 0x10 ? -1 : 0;
56 				const int vMir = q[j] & 0x10 ? -1 : 1;
57 				switch (q[j]>>1 & 3) {
58 					case 1:
59 						hMir *= 2;
60 						for (int i ; i < 256 ; i++) {
61 							result[offset + i] = cast(short)(SINEWAVE_FRAGMENT[(hBegin + hMir * i) & 255] * vMir + vOffset);
62 						}
63 						break;
64 					case 2:
65 						hMir *= 2;
66 						for (int i ; i < 128 ; i++) {
67 							result[offset + i] = cast(short)(SINEWAVE_FRAGMENT[(hBegin + hMir * i) & 255] * vMir + vOffset);
68 						}
69 						hMir *= -1;
70 						hBegin = q[j] & 0x8 ? 0 : 255;
71 						for (int i ; i < 128 ; i++) {
72 							result[offset + i + 128] = cast(short)(SINEWAVE_FRAGMENT[(hBegin + hMir * i) & 255] * vMir + vOffset);
73 						}
74 						break;
75 					case 3:
76 						hMir *= 2;
77 						for (int i ; i < 128 ; i++) {
78 							result[offset + i] = cast(short)(SINEWAVE_FRAGMENT[(hBegin + hMir * i) & 255] * vMir + vOffset);
79 						}
80 						break;
81 					default:
82 						for (int i ; i < 256 ; i++) {
83 							result[offset + i] = cast(short)(SINEWAVE_FRAGMENT[hBegin + hMir * i] * vMir + vOffset);
84 						}
85 						break;
86 				}
87 			}
88 		}
89 		return result;
90 	}	
91 	/**
92 	Generates a pulse wave.
93 
94 	`width` controls the pulse width.
95 	*/
96 	public static short[1024] generatePulseWave(int width = 512) @nogc @safe pure nothrow {
97 		short[1024] result;
98 		for (int i ; i < 1024 ; i++) {
99 			result[i] = i < width ? short.max : short.min;
100 		}
101 		return result;
102 	}
103 	/**
104 	Generates a triangular waveform.
105 	`shape` controls the shape of the triangular waveform, allowing it to be morphed between triangle, saw, and ramp.
106 	``
107 	*/
108 	public static short[1024] generateTriangularWave(int shape = 512) @nogc @safe pure nothrow {
109 		import pixelperfectengine.system.etc : clamp;
110 		short[1024] result;
111 		real state = short.min;
112 		const real upwardSlope = (ushort.max / shape) + short.min;
113 		const real downwardSlope = (ushort.max / (1024 - shape)) + short.min;
114 		for (int i ; i < 1024 ; i++) {
115 			state += i < shape ? upwardSlope : downwardSlope;
116 			clamp(state, cast(real)short.min, cast(real)short.max);
117 			result[i] = cast(short)state;
118 		}
119 		return result;
120 	}
121 	/** 
122 	Contains a table to calculate Attack, Decay, and Release values.
123 
124 	All values are seconds with factions. Actual values are live-calculated depending on sustain-level and sampling
125 	frequency.
126 	*/
127 	public static immutable float[128] ADSR_TIME_TABLE = [
128 	//	0     |1     |2     |3     |4     |5     |6     |7     |8     |9     |A     |B     |C     |D     |E     |F
129 		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
130 		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
131 		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
132 		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
133 		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
134 		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
135 		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
136 		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
137 		
138 	];
139 	/**
140 	Contains a table to calculate Sustain control values.
141 
142 	All values are seconds with fractions. Actual values are live-calculated depending on sustain level and sampling
143 	frequency. Please note that with certain levels of sustain, the actual max time might be altered.
144 	*/
145 	public static immutable float[63] SUSTAIN_CONTROL_TIME_TABLE = [
146 	//	0     |1     |2     |3     |4     |5     |6     |7     |8     |9     |A     |B     |C     |D     |E     |F
147 		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
148 		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
149 		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
150 		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
151 	];
152 	/**
153 	Contains a quarter sine wave, can be used for waveform generation.
154 
155 	Generated by the static constructor.
156 	*/
157 	public static immutable short[256] SINEWAVE_FRAGMENT;
158 	/**
159 	Defines operator parameter numbers, within the unregistered namespace.
160 	*/
161 	public enum OperatorParamNums {
162 		//Unregistered
163 		Level		=	0,
164 		Attack		=	1,
165 		Decay		=	2,
166 		SusLevel	=	3,
167 		SusCtrl		=	4,
168 		Release		=	5,
169 		Waveform	=	6,
170 		Feedback	=	7,
171 		TuneCor		=	8,
172 		TuneFine	=	9,
173 		ShpA		=	10,
174 		ShpR		=	11,
175 		VelToLevel	=	12,
176 		MWToLevel	=	13,
177 		LFOToLevel	=	14,
178 		OpCtrl		=	15,
179 		VelToFB		=	16,
180 		MWToFB		=	17,
181 		LFOToFB		=	18,
182 		EEGToFB		=	19,
183 		VelToShpA	=	20,
184 		VelToShpR	=	21,
185 	}
186 	/**
187 	Defines channel parameter numbers, within the unregistered namespace.
188 	*/
189 	public enum ChannelParamNums {
190 		MasterVol	=	0,
191 		Bal			=	1,
192 		AuxSLA		=	2,
193 		AuxSLB		=	3,
194 		EEGDetune	=	4,
195 		PLFO		=	5,
196 		Attack		=	6,
197 		Decay		=	7,
198 		SusLevel	=	8,
199 		SusCtrl		=	9,
200 		Release		=	10,
201 		ShpA		=	11,
202 		ShpR		=	12,
203 		ChCtrl		=	16,
204 		RingMod		=	17,
205 		EEGToLeft	=	18,
206 		EEGToRight	=	19,
207 		EEGToAuxA	=	20,
208 		EEGToAuxB	=	21,
209 		LFOToLeft	=	22,
210 		LFOToRight	=	23,
211 		LFOToAuxA	=	24,
212 		LFOToAuxB	=	25,
213 	}
214 	/**
215 	Defines channel parameters within the registered namespace
216 	*/
217 	public enum ChannelRegParams {
218 		PitchBendSens,
219 		TuneCor,
220 		TuneFine,
221 	}
222 	/**
223 	Defines global parameter nummbers, within the unregistered namespace
224 	*/
225 	public enum GlobalParamNums {
226 		PLFORate	=	0,
227 		PLFOWF		=	1,
228 		ALFORate	=	2,
229 		ALFOWF		=	3,
230 		FilterLCFreq=	4,
231 		FilterLCQ	=	5,
232 		FilterRCFreq=	6,
233 		FilterRCQ	=	7,
234 		FilterACFreq=	8,
235 		FilterACQ	=	9,
236 		FilterBCFreq=	10,
237 		FilterBCQ	=	11,
238 	}
239 	enum TuneCtrlFlags : uint {
240 		FineTuneMidPoint	=	0x1_00_00_00,
241 		CorTuneMidPoint		=	0x30_00_00_00,
242 		FineTuneTest		=	0x1_FF_FF_FF,
243 		CorTuneTest			=	0xFE_00_00_00,
244 	}
245 	///Defines control values
246 	enum OpCtrlFlags {
247 		WavetableSelect	=	127,		///Wavetable select flags
248 		FBMode			=	1 << 7,		///Feedback mode (L: After Envelop Generator, H: Before Envelop Generator)
249 		FBNeg			=	1 << 8,		///Feedback mode (L: Positive, H: Negative)
250 		MWNeg			=	1 << 9,		///Invert modulation wheel control
251 		VelNeg			=	1 << 10,	///Invert velocity control
252 		EGRelAdaptive	=	1 << 11,	///Adaptive release time based on current output level
253 		FixedPitch		=	1 << 12,	///Enables fixed pitch mode
254 	}
255 	/**
256 	Implements a single operator.
257 	
258 	Contains an oscillator, an ADSR envelop generator, and locals.
259 	*/
260 	public struct Operator {
261 		///Local copy of operator preset data.
262 		Preset.Op		preset;
263 		///The envelop generator of the operator.
264 		ADSREnvelopGenerator	eg;
265 		///The current position of the oscillator, including fractions.
266 		uint			pos;	
267 		///The amount the oscillator must be stepped forward each cycle, including fractions.
268 		uint			step;	
269 		///Input register.
270 		///The amount which the oscillator will be offsetted.
271 		int				input;
272 		///Feedback register. Either out_0[n-1] or out[n-1] multiplied by feedback amount.
273 		///The amount which the oscillator will be offsetted.
274 		///Negative if inverted.
275 		int				feedback;
276 		///Output register.
277 		///Not affected by either level or EG
278 		///Might be used for ring modulation.
279 		int				output;
280 		///Live calculated out of shpA
281 		float			shpA0	=	0.0;
282 		///Live calculated out of shpR
283 		float			shpR0	=	0.0;
284 		///Output affected by EEG and level.
285 		///Either used for audible output, or to modulate other operators
286 		int				output_0;
287 
288 		///Sets the frequency of the operator
289 		void setFrequency(int slmpFreq, ubyte note, double pitchBend, double tuning) @nogc @safe pure nothrow {
290 			/+const double actualNote = (opCtrl & OpCtrlFlags.FixedPitch) ? 
291 					(tune>>25) + ((cast(double)(tune & TuneCtrlFlags.FineTuneTest) - TuneCtrlFlags.FineTuneMidPoint) / 
292 					TuneCtrlFlags.FineTuneTest) : pitchBend + note ;+/
293 			double actualNote;
294 			if (preset.opCtrl & OpCtrlFlags.FixedPitch) {
295 				actualNote = (preset.tune>>25) + ((cast(double)(preset.tune & TuneCtrlFlags.FineTuneTest) - 
296 						TuneCtrlFlags.FineTuneMidPoint) / TuneCtrlFlags.FineTuneTest);
297 			} else {
298 				actualNote = pitchBend + note + cast(int)((preset.tune>>25) - TuneCtrlFlags.CorTuneMidPoint) + 
299 						((cast(double)(preset.tune & TuneCtrlFlags.FineTuneTest) - TuneCtrlFlags.FineTuneMidPoint) / 
300 						TuneCtrlFlags.FineTuneTest);
301 			}
302 			const double oscFreq = noteToFreq(actualNote, tuning);
303 			const double cycLen = oscFreq / (slmpFreq / 1024.0);
304 			step = cast(uint)(cast(double)(1<<20) / cycLen);
305 		}
306 		///Resets the Envelop generator
307 		void resetEG(int sampleRate) @nogc @safe pure nothrow {
308 			//Set attack phase
309 			if (preset.atk) {
310 				eg.attackRate = calculateRate(ADSR_TIME_TABLE[preset.atk], sampleRate);
311 			} else {
312 				eg.attackRate = 1.0;
313 			}
314 			//Set decay phase
315 			if (preset.dec) {
316 				eg.decayRate = calculateRate(ADSR_TIME_TABLE[preset.dec] * 2, sampleRate, ADSREnvelopGenerator.maxOutput, eg.sustainLevel);
317 			} else {
318 				eg.decayRate = 1.0;
319 			}
320 			//Set sustain phase
321 			if (preset.susCC) {
322 				eg.isPercussive = false;
323 				if (preset.susCC == 64) {
324 					eg.sustainControl = 0.0;
325 				} else if (preset.susCC < 64) {
326 					eg.sustainControl = -1.0 * 
327 							calculateRate(SUSTAIN_CONTROL_TIME_TABLE[preset.susCC - 1], sampleRate);
328 				} else {
329 					eg.sustainControl = 
330 							calculateRate(SUSTAIN_CONTROL_TIME_TABLE[preset.susCC - 64], sampleRate);
331 				}
332 			} else {
333 				eg.isPercussive = true;
334 				eg.sustainControl = 0.0;
335 			}
336 			//Set release phase
337 			if (preset.rel) {
338 				eg.releaseRate = calculateRate(ADSR_TIME_TABLE[preset.rel] * 2, sampleRate, eg.sustainLevel);
339 			} else {
340 				eg.releaseRate = 1.0;
341 			}
342 		}
343 		
344 	}
345 	///Defines channel control flags.
346 	enum ChCtrlFlags {
347 		///Channel combination turned off, the channel pair is independent
348 		ComboModeOff	=	0b0000,	
349 		///Channel combination mode 1: Secondary channel's output is fed into primary operator 0.
350 		ComboMode1		=	0b0001,
351 		///Channel combination mode 2: Secondary channel's output is fed into primary operator 1 if primary 
352 		///is in serial mode, or into both if primary is in parallel mode.
353 		ComboMode2		=	0b0010,
354 		///Channel combination mode 3: Secondary channel's output is fed into main output, except if primary 
355 		///channel set to parallel and secondary set to serial, then S1, P0, and P1 are connected to output, while
356 		///S0 is modulating all of them.
357 		ComboMode3		=	0b0011,
358 		///Used for testing combo mode.
359 		ComboModeTest	=	ComboMode3,
360 		Algorithm		=	1<<2,	///Channel algorithm (H: Parallel, L: Series)
361 		IndivOutChLev	=	1<<3,	///Enables the setting of individual output channel levels
362 		LFOPan			=	1<<4,	///Enables LFO Panning
363 		EEGPan			=	1<<5,	///Enables EEG Panning
364 		MWToTrem		=	1<<6,	///Assigns modwheel to amplitude LFO
365 		MWToVibr		=	1<<7,	///Assigns modwheel to pitch LFO
366 		MWToAux			=	1<<8,	///Assigns modwheel to aux levels
367 	}
368 	/**
369 	Defines channel common parameters.
370 	*/
371 	public struct Channel {
372 		///Copy of channel relevant preset data
373 		Preset.Ch		preset;
374 		///Extra envelop generator that can be assigned for multiple purpose.
375 		ADSREnvelopGenerator	eeg;
376 		///Calculated output level controls + aux send levels
377 		///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B
378 		__m128			outLevels;
379 		///Resets the Extra Envelop generator
380 		void resetEEG(int sampleRate) @nogc @safe pure nothrow {
381 			//Set attack phase
382 			if (preset.atkX) {
383 				eeg.attackRate = calculateRate(ADSR_TIME_TABLE[preset.atkX], sampleRate);
384 			} else {
385 				eeg.attackRate = 1.0;
386 			}
387 			//Set decay phase
388 			if (preset.decX) {
389 				eeg.decayRate = calculateRate(ADSR_TIME_TABLE[preset.decX] * 2, sampleRate, ADSREnvelopGenerator.maxOutput, 
390 						eeg.sustainLevel);
391 			} else {
392 				eeg.decayRate = 1.0;
393 			}
394 			//Set sustain phase
395 			if (preset.susCCX) {
396 				eeg.isPercussive = false;
397 				if (preset.susCCX == 64) {
398 					eeg.sustainControl = 0.0;
399 				} else if (preset.susCCX < 64) {
400 					eeg.sustainControl = -1.0 * calculateRate(SUSTAIN_CONTROL_TIME_TABLE[preset.susCCX - 1], sampleRate);
401 				} else {
402 					eeg.sustainControl = calculateRate(SUSTAIN_CONTROL_TIME_TABLE[preset.susCCX - 64], sampleRate);
403 				}
404 			} else {
405 				eeg.isPercussive = true;
406 				eeg.sustainControl = 0.0;
407 			}
408 			//Set release phase
409 			if (preset.relX) {
410 				eeg.releaseRate = calculateRate(ADSR_TIME_TABLE[preset.relX] * 2, sampleRate, eeg.sustainLevel);
411 			} else {
412 				eeg.releaseRate = 1.0;
413 			}
414 		}
415 		
416 	}
417 	/**
418 	Stores channel controller values (modwheel, velocity, etc.)
419 	*/
420 	public struct ChControllers {
421 		///Modulation wheel parameter, normalized between 0.0 and 1.0
422 		float			modwheel	=	0;
423 		///Velocity parameter, normalized between 0.0 and 1.0
424 		float			velocity	=	0;
425 		///Pitch bend parameter, with the amount of pitch shifting in semitones + fractions
426 		float			pitchBend	=	0;
427 		///The note that is currently being played
428 		ubyte			note;
429 	}
430 	/**
431 	Defines a preset.
432 	*/
433 	public struct Preset {
434 		///Defines parameters of a single operator
435 		public struct Op {
436 			///Operator tuning
437 			///Bit 31-25: Coarse detuning (-24 to +103 seminotes)
438 			///Bit 24-0: Fine detuning (-100 to 100 cents), 0x1_00_00_00 is center
439 			///If fixed mode is being used, then top 7 bits are the note, the rest are fine tuning.
440 			uint			tune	=	0x31_00_00_00;
441 			///Output level (between 0.0 and 1.0)
442 			float			outL	=	0.25;
443 			///Feedback level (between 0.0 and 1.0)
444 			float			fbL		=	0.0;
445 			///Control flags and Wavetable selector
446 			uint			opCtrl;
447 			///Output level controller assignment
448 			///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: unused
449 			__m128			outLCtrl=	[0,0,0,0];
450 			///Feedback level controller assignment
451 			///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: Extra envelop generator
452 			__m128			fbLCtrl	=	[0,0,0,0];
453 			///Attack time control (between 0 and 127)
454 			ubyte			atk;
455 			///Decay time control (between 0 and 127)
456 			ubyte			dec;
457 			///Release time control (between 0 and 127)
458 			ubyte			rel;
459 			///Sustain curve control (between 0 and 127)
460 			///0: Percussive mode
461 			///1 - 63: Descending over time
462 			///64: Constant
463 			///65 - 127: Ascending over time
464 			ubyte			susCC;
465 			///Sustain level for the EG
466 			float			susLevel=	1.0;
467 			///ADSR shaping parameter (for the attack phase)
468 			float			shpA	=	0.5;
469 			///ADSR shaping parameter (for the decay/release phase)
470 			float			shpR	=	0.5;
471 			///Assigns velocity to shpA
472 			float			shpAVel	=	0.0;
473 			///Assigns velocity to shpR
474 			float			shpRVel =	0.0;
475 			///Sets control level for X controller affecting this operator
476 			float			ctrlXLevel = 0.5;
477 			///Sets control level for X controller affecting this operator
478 			float			ctrlYLevel = 0.5;
479 		}
480 		///Defines parameters of a single channel.
481 		public struct Ch {
482 			///ADSR shaping parameter (for the attack phase)
483 			float			shpAX	=	0.5;
484 			///ADSR shaping parameter (for the decay/release phase)
485 			float			shpRX	=	0.5;
486 			///Pitch amount for EEG
487 			///Bit 31-25: Coarse (-64 to +63 seminotes)
488 			///Bit 24-0: Fine (0 to 100 cents)
489 			uint			eegDetuneAm;
490 			///Pitch bend sensitivity
491 			///Bit 31-25: Coarse (0 to 127 seminotes)
492 			///Bit 24-0: Fine (0 to 100 cents)
493 			uint			pitchBendSens = 2<<24;
494 			///A-4 channel tuning in hertz.
495 			float			chnlTun = 440.0;
496 			///Stores channel control flags.
497 			uint			chCtrl;
498 			///Master volume (0.0 to 1.0)
499 			float			masterVol=	1;
500 			///Master balance (0.0 to 1.0)
501 			float			masterBal=	0.5;
502 			///Aux send A
503 			float			auxSendA =	0;
504 			///Aux send B
505 			float			auxSendB =	0;
506 			///X and Y controller assign
507 			ushort[2]		xyCtrlAssign0;
508 			///X and Y controller assign (secondary)
509 			ushort[2]		xyCtrlAssign1;
510 			///EEG assign levels
511 			///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B
512 			__m128			eegLevels=	[0,0,0,0];
513 			///Amplitude LFO assign levels
514 			///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B
515 			__m128			aLFOlevels=	[0,0,0,0];
516 			///Ring modulation amount
517 			///Only available on select algorithms
518 			int				rmAmount;
519 			///Pitch LFO level
520 			float			pLFOlevel=	1;
521 			///Amplitude LFO to 
522 			///Attack time control (between 0 and 127)
523 			ubyte			atkX;
524 			///Decay time control (between 0 and 127)
525 			ubyte			decX;
526 			///Release time control (between 0 and 127)
527 			ubyte			relX;
528 			///Sustain curve control (between 0 and 127)
529 			///0: Percussive mode
530 			///1 - 63: Descending over time
531 			///64: Constant
532 			///65 - 127: Ascending over time
533 			ubyte			susCCX;
534 			///Sustain level
535 			float			susLevel	=	1;
536 		}
537 		Op[2]			operators;		///The operators belonging to this channel
538 		Ch				channel;		///Channel common values
539 	}
540 	///Contains the wavetables for the operators and LFOs.
541 	///Value might be divided to limit the values between 2047 and -2048 via bitshifting,
542 	///otherwise the full range can be used for audio output, etc.
543 	///Loaded from a 16 bit wave file.
544 	protected short[1024][128]	wavetables;
545 	///Stores presets.
546 	///8 banks of 128 presets are available for a total of 1024.
547 	///If a channel combination is being used, then bank pairs (0-1, 2-3, etc) will store their primary and secondary
548 	///halves, and calling either will load both halves.
549 	protected Preset[128][8]	soundBank;
550 	///Operator data.
551 	///See rendering function on updating.
552 	protected Operator[32]		operators;
553 	///Channel data.
554 	///See rendering function on updating.
555 	protected Channel[16]		channels;
556 	///Channel control data.
557 	protected ChControllers[16]	chCtrls;
558 	///Preset numbers per channels.
559 	protected ubyte[16]			presetNum;
560 	///Bank numbers per channels.
561 	protected ubyte[16]			bankNum;
562 	///Keeps the registered/unregistered parameter positions (LSB = 1).
563 	protected ubyte[2]			paramNum;
564 	///Stores LFO waveform selection. 1: Amplitude; 0: Pitch
565 	protected ubyte[2]			lfoWaveform;
566 	///Stores temporary parameter values 
567 	///0: MSB of sel unregistered param 1: LSB of sel unregistered param 
568 	///2: MSB of sel registered param 3: LSB of sel registered param
569 	protected ubyte[4]			paramTemp;
570 	///Stores ALFO position
571 	protected uint				aLFOPos;
572 	///Stores ALFO rate
573 	protected uint				aLFORate;
574 	///Stores output filter values.
575 	///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]
576 	protected __m128[10]		filterVals;
577 	///Stores control values of the output values.
578 	///Layout: [LF, LQ, RF, RQ, AF, AQ, BF, BQ]
579 	protected float[8]			filterCtrl	=	[17_000, 0.707, 17_000, 0.707, 17_000, 0.707, 17_000, 0.707];
580 	///Initial mixing buffers
581 	///Output is directed there before filtering
582 	///Layout is: LRAB
583 	protected float[]			initBuffers;
584 	///Dummy buffer
585 	///Only used if one or more outputs haven't been defined
586 	protected float[]			dummyBuf;
587 	///Amplitude LFO buffer. Values are between 0.0 and 1.0
588 	protected float[]			aLFOBuf;
589 	///Pitch LFO output. Values are between -1.0 and 1.0
590 	protected float				pLFOOut	=	0;
591 	///Stores PLFO position
592 	protected uint				pLFOPos;
593 	///Stores PLFO rate
594 	protected uint				pLFORate;
595 	///Mixdown value.
596 	///Used for final mixing.
597 	protected float				mixdownVal = 1.0 / (ushort.max);
598 	alias ChFun = void delegate(int chNum, size_t length) @nogc pure nothrow;
599 	///Channel update delegates
600 	protected ChFun[16]			chDeleg;
601 	/**
602 	Creates an instance of QM816
603 	*/
604 	public this() @trusted nothrow {
605 		info.nOfAudioInput = 0;
606 		info.nOfAudioOutput = 4;
607 		info.outputChNames = ["mainL", "mainR", "auxSendA", "auxSendB"];
608 		info.isInstrument = true;
609 		info.hasMidiIn = true;
610 		info.hasMidiOut = true;
611 		info.midiSendback = true;
612 		try {
613 			WaveFormat f = WaveFormat(0, 0, AudioFormat.PCM, 1, 0, 16);
614 			short[1024] buffer = generateSinewave([0x01, 0x09, 0x11, 0x19]);
615 			waveformDataReceive(0, reinterpretCast!ubyte(buffer), f);		///Sine (from OPL2)
616 			buffer = generateSinewave([0x01, 0x09, 0x00, 0x00]);
617 			waveformDataReceive(1, reinterpretCast!ubyte(buffer), f);		///Half-sine (from OPL2)
618 			buffer = generateSinewave([0x01, 0x09, 0x01, 0x09]);
619 			waveformDataReceive(2, reinterpretCast!ubyte(buffer), f);		///Full-sine (from OPL2)
620 			buffer = generateSinewave([0x01, 0x00, 0x01, 0x00]);
621 			waveformDataReceive(3, reinterpretCast!ubyte(buffer), f);		///Pulse-sine (from OPL2)
622 			buffer = generateSinewave([0x01, 0x09, 0x11, 0x00]);
623 			waveformDataReceive(4, reinterpretCast!ubyte(buffer), f);		///Pulse-sine 75%
624 			buffer = generateSinewave([0x01, 0x00, 0x00, 0x00]);
625 			waveformDataReceive(5, reinterpretCast!ubyte(buffer), f);		///Pulse-sine 25%
626 			buffer = generateSinewave([0x01, 0x00, 0x11, 0x00]);
627 			waveformDataReceive(6, reinterpretCast!ubyte(buffer), f);		///Alternating pulse-sine
628 			buffer = generateSinewave([0x05, 0x00, 0x1d, 0x00]);
629 			waveformDataReceive(7, reinterpretCast!ubyte(buffer), f);		///Alternating sine (from OPL3)
630 			buffer = generateSinewave([0x05, 0x05, 0x1d, 0x1d]);
631 			waveformDataReceive(8, reinterpretCast!ubyte(buffer), f);		///Camel sine (from OPL3)
632 			buffer = generateSinewave([0x01, 0x09, 0x11, 0x1f]);
633 			waveformDataReceive(9, reinterpretCast!ubyte(buffer), f);		///Resonant sine 0
634 			buffer = generateSinewave([0x01, 0x09, 0x1d, 0x1d]);
635 			waveformDataReceive(10, reinterpretCast!ubyte(buffer), f);		///Resonant sine 1
636 			buffer = generateSinewave([0x01, 0x09, 0x0d, 0x0d]);
637 			waveformDataReceive(11, reinterpretCast!ubyte(buffer), f);		///Resonant sine 2
638 			buffer = generateSinewave([0x01, 0x09, 0x00, 0x1d]);
639 			waveformDataReceive(12, reinterpretCast!ubyte(buffer), f);		///Resonant sine 3
640 			buffer = generateSinewave([0x01, 0x09, 0x1d, 0x00]);
641 			waveformDataReceive(13, reinterpretCast!ubyte(buffer), f);		///Resonant sine 4
642 			buffer = generateSinewave([0x01, 0x09, 0x00, 0x0d]);
643 			waveformDataReceive(14, reinterpretCast!ubyte(buffer), f);		///Resonant sine 5
644 			buffer = generateSinewave([0x01, 0x09, 0x0d, 0x00]);
645 			waveformDataReceive(15, reinterpretCast!ubyte(buffer), f);		///Resonant sine 6
646 			buffer = generateSinewave([0x01, 0x09, 0x1f, 0x1f]);
647 			waveformDataReceive(16, reinterpretCast!ubyte(buffer), f);		///Resonant sine 7
648 			buffer = generatePulseWave(768);
649 			waveformDataReceive(17, reinterpretCast!ubyte(buffer), f);		///Pulse wave 75%
650 			buffer = generatePulseWave(512);
651 			waveformDataReceive(18, reinterpretCast!ubyte(buffer), f);		///Pulse wave 50%
652 			buffer = generatePulseWave(256);
653 			waveformDataReceive(19, reinterpretCast!ubyte(buffer), f);		///Pulse wave 25%
654 			buffer = generatePulseWave(128);
655 			waveformDataReceive(20, reinterpretCast!ubyte(buffer), f);		///Pulse wave 12.5%
656 			buffer = generatePulseWave(100);
657 			waveformDataReceive(21, reinterpretCast!ubyte(buffer), f);		///Pulse wave 10%
658 			buffer = generatePulseWave(50);
659 			waveformDataReceive(22, reinterpretCast!ubyte(buffer), f);		///Pulse wave 5%
660 			buffer = generateTriangularWave(1023);
661 			waveformDataReceive(23, reinterpretCast!ubyte(buffer), f);		///Ramp wave
662 			buffer = generateTriangularWave(768);
663 			waveformDataReceive(24, reinterpretCast!ubyte(buffer), f);		///Morphed ramp
664 			buffer = generateTriangularWave(512);
665 			waveformDataReceive(25, reinterpretCast!ubyte(buffer), f);		///Triangle wave
666 			buffer = generateTriangularWave(256);
667 			waveformDataReceive(26, reinterpretCast!ubyte(buffer), f);		///Morphed saw
668 			buffer = generateTriangularWave(1);
669 			waveformDataReceive(27, reinterpretCast!ubyte(buffer), f);		///Saw wave
670 		} catch (Exception e) {
671 
672 		}
673 		//Reset delegates
674 		for (int i ; i < chDeleg.length ; i++) {
675 			chDeleg[i] = &updateChannelM00;
676 		}
677 	}
678 	/**
679 	 * Sets the module up.
680 	 *
681 	 * Can be overridden in child classes to allow resets.
682 	 */
683 	public override void moduleSetup(ubyte[] inputs, ubyte[] outputs, int sampleRate, size_t bufferSize, 
684 			ModuleManager handler) @safe nothrow {
685 		enabledInputs = StreamIDSet(inputs);
686 		enabledOutputs = StreamIDSet(outputs);
687 		this.sampleRate = sampleRate;
688 		this.bufferSize = bufferSize;
689 		this.handler = handler;
690 		//set up and reset buffers
691 		initBuffers.length = bufferSize * 4;
692 		resetBuffer(initBuffers);
693 		dummyBuf.length = bufferSize;
694 		resetBuffer(dummyBuf);
695 		aLFOBuf.length = bufferSize;
696 		resetBuffer(aLFOBuf);
697 		//Reset filters
698 		for (int i ; i < 4 ; i++) {
699 			BiquadFilterValues vals = createLPF(sampleRate, filterCtrl[i * 2], filterCtrl[(i * 2) + 1]);
700 			filterVals[0][i] = vals.a0;
701 			filterVals[1][i] = vals.a1;
702 			filterVals[2][i] = vals.a2;
703 			filterVals[3][i] = vals.b0;
704 			filterVals[4][i] = vals.b1;
705 			filterVals[5][i] = vals.b2;
706 			filterVals[6][i] = 0;
707 			filterVals[7][i] = 0;
708 			filterVals[8][i] = 0;
709 			filterVals[9][i] = 0;
710 		}
711 		//Reset operator EGs
712 		for (int i ; i < operators.length ; i++) {
713 			operators[i].resetEG(sampleRate);
714 		}
715 		//Reset channel EGs
716 		for (int i ; i < channels.length ; i++) {
717 			channels[i].resetEEG(sampleRate);
718 		}
719 	}
720 	/**
721 	 * Receives waveform data that has been loaded from disk for reading. Returns zero if successful, or a specific 
722 	 * errorcode.
723 	 *
724 	 * id: The ID of the waveform.
725 	 * rawData: The data itself, in unprocessed form.
726 	 * format: The format of the wave data, including the data type, bit depth, base sampling rate
727 	 *
728 	 * Note: This function needs the audio system to be unlocked.
729 	 */
730 	public override int waveformDataReceive(uint id, ubyte[] rawData, WaveFormat format) nothrow {
731 		int errorcode;
732 		if (format.channels != 1) errorcode |= SampleLoadErrorCode.ChNumNotSupported;
733 		if (format.bitsPerSample != 16) errorcode |= SampleLoadErrorCode.BitdepthNotSupported;
734 		if (format.format != AudioFormat.PCM) errorcode |= SampleLoadErrorCode.FormatNotSupported;
735 		if (rawData.length != 128 * 1024 * 2 && rawData.length != 1024 * 2) 
736 			errorcode |= SampleLoadErrorCode.SampleLenghtNotSupported;
737 		if (errorcode) {
738 			return errorcode;
739 		} else {
740 			import core.stdc.string : memcpy;
741 			if (rawData.length == 128 * 1024 * 2)
742 				memcpy(wavetables.ptr, rawData.ptr, 128 * 1024 * 2);
743 			else
744 				memcpy(wavetables[id].ptr, rawData.ptr, 1024 * 2);
745 			return 0;
746 		}
747 	}
748 	/**
749 	 * MIDI 2.0 data received here.
750 	 *
751 	 * data: up to 128 bits of MIDI 2.0 commands. Any packets that are shorter should be padded with zeros.
752 	 * offset: time offset of the command. This can reduce jitter caused by the asynchronous operation of the 
753 	 * sequencer and the audio plugin system.
754 	 */
755 	public override void midiReceive(uint[4] data, uint offset) @nogc nothrow {
756 		UMP firstPacket;
757 		firstPacket.base = data[0];
758 		switch (firstPacket.msgType) {
759 			case MessageType.SysCommMsg:	//Process system common message
760 				break;
761 			case MessageType.MIDI1:			//Process MIDI 1.0 messages
762 				switch (firstPacket.status) {
763 					case MIDI1_0Cmd.CtrlCh:	//Process MIDI 1.0 control change messages
764 						switch (firstPacket.note) {
765 							case 0, 32:			//Bank select
766 								bankNum[firstPacket.channel] = firstPacket.value & 7;
767 								break;
768 							case 1:				//Modulation wheel
769 								chCtrls[firstPacket.channel].modwheel = cast(double)(firstPacket.value) / byte.max;
770 								break;
771 							case 6:			//Data Entry MSB
772 								paramNum[0] = firstPacket.value;
773 								paramTemp = [0xFF,0xFF,0xFF,0xFF];
774 								break;
775 							case 38:		//Data Entry LSB
776 								paramNum[1] = firstPacket.value;
777 								paramTemp = [0xFF,0xFF,0xFF,0xFF];
778 								break;
779 							case 98:		//Non Registered Parameter Number MSB (handle through MIDI 2.0)
780 								//setUnregisteredParam(firstPacket.value, paramNum, 0, firstPacket.channel);
781 								paramTemp[0] = firstPacket.value;
782 								setUnregisteredParam(convertM1CtrlValToM2(paramTemp[0], paramTemp[1]), paramNum, firstPacket.channel);
783 								break;
784 							case 99:		//Non Registered Parameter Number LSB (handle through MIDI 2.0)
785 								//setUnregisteredParam(firstPacket.value, paramNum, 0, firstPacket.channel);
786 								paramTemp[1] = firstPacket.value;
787 								if (paramTemp[0] != 0xFF)
788 									setUnregisteredParam(convertM1CtrlValToM2(paramTemp[0], paramTemp[1]), paramNum, firstPacket.channel);
789 								break;
790 							default:
791 								break;
792 						}
793 						break;
794 					case MIDI1_0Cmd.NoteOn:	//Note on command
795 						const uint ch = firstPacket.channel;
796 						if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch > 7) return;
797 						chCtrls[ch].note = firstPacket.note;
798 						chCtrls[ch].velocity = cast(double)firstPacket.velocity / cast(double)byte.max;
799 						channels[ch].eeg.keyOn();
800 						operators[ch].eg.keyOn();
801 						operators[ch].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun);
802 						operators[ch + 1].eg.keyOn();
803 						operators[ch + 1].setFrequency(sampleRate, firstPacket.note, chCtrls[ch + 1].pitchBend, channels[ch].preset.chnlTun);
804 						if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch <= 7) {
805 							channels[ch + 8].eeg.keyOn();
806 							operators[ch + 16].eg.keyOn();
807 							operators[ch + 16].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun);
808 							operators[ch + 17].eg.keyOn();
809 							operators[ch + 17].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun);
810 						}
811 						break;
812 					case MIDI1_0Cmd.NoteOff://Note off command
813 						const uint ch = firstPacket.channel;
814 						if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch > 7) return;
815 						chCtrls[ch].velocity = cast(double)firstPacket.velocity / cast(double)byte.max;
816 						channels[ch].eeg.keyOff();
817 						operators[ch].eg.keyOff();
818 						if (operators[ch].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) {
819 							if (operators[ch].preset.rel) {
820 								operators[ch].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch].preset.rel] * 2, sampleRate, 
821 										operators[ch].eg.sustainLevel);
822 							} else {
823 								operators[ch].eg.releaseRate = 1.0;
824 							}
825 						}
826 						operators[ch + 1].eg.keyOff();
827 						if (operators[ch + 1].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) {
828 							if (operators[ch + 1].preset.rel) {
829 								operators[ch + 1].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 1].preset.rel] * 2, sampleRate, 
830 										operators[ch + 1].eg.sustainLevel);
831 							} else {
832 								operators[ch + 1].eg.releaseRate = 1.0;
833 							}
834 						}
835 						if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch <= 7) {
836 							channels[ch + 8].eeg.keyOff();
837 							operators[ch + 16].eg.keyOff();
838 							if (operators[ch + 16].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) {
839 								if (operators[ch + 16].preset.rel) {
840 									operators[ch + 16].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 16].preset.rel] * 2, sampleRate, 
841 											operators[ch + 16].eg.sustainLevel);
842 								} else {
843 									operators[ch + 16].eg.releaseRate = 1.0;
844 								}
845 							}
846 							operators[ch + 17].eg.keyOff();
847 							if (operators[ch + 17].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) {
848 								if (operators[ch + 17].preset.rel) {
849 									operators[ch + 17].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 17].preset.rel] * 2, sampleRate, 
850 											operators[ch + 17].eg.sustainLevel);
851 								} else {
852 									operators[ch + 17].eg.releaseRate = 1.0;
853 								}
854 							}
855 						}
856 						break;
857 					case MIDI1_0Cmd.ChAftrTch:
858 						chCtrls[firstPacket.channel].velocity = cast(double)firstPacket.note / cast(double)byte.max;
859 						break;
860 					case MIDI1_0Cmd.PolyAftrTch:
861 						chCtrls[firstPacket.channel].velocity = cast(double)firstPacket.velocity / cast(double)byte.max;
862 						break;
863 					case MIDI1_0Cmd.PrgCh:	//Program change
864 						const uint chOffset = firstPacket.channel;
865 						const uint chCtrl = soundBank[bankNum[chOffset] & 7][presetNum[chOffset]].channel.chCtrl;
866 						if (chCtrl & ChCtrlFlags.ComboModeTest) {
867 							const uint chX = chOffset & 7, bankX = bankNum[chOffset] & 7 & ~1;
868 							prgRecall(chX, presetNum[chX], bankX);
869 							prgRecall(chX + 8, presetNum[chX], bankX + 1);
870 						} else {
871 							prgRecall(chOffset, presetNum[chOffset], bankNum[chOffset]);
872 						}
873 						break;
874 					case MIDI1_0Cmd.PitchBend:
875 						const uint ch = firstPacket.channel;
876 						const double pitchBendSens = (channels[ch].preset.pitchBendSens>>25) + 
877 								(cast(double)(channels[ch].preset.pitchBendSens & 0x01_FF_FF_FF) / 0x01_FF_FF_FF);
878 						chCtrls[ch].pitchBend = pitchBendSens * ((cast(double)firstPacket.bend - 0x20_00) / 0x3F_FF);
879 						break;
880 					default:
881 						break;
882 				}
883 				break;
884 			case MessageType.MIDI2:
885 				switch (firstPacket.status) {
886 					case MIDI2_0Cmd.CtrlCh:	//Control change
887 						setUnregisteredParam(data[1], [firstPacket.index, firstPacket.value], firstPacket.channel);
888 						break;
889 					case MIDI2_0Cmd.CtrlChR://Registered control change
890 						//setRegisteredParam(data[1], [firstPacket.index, firstPacket.value], firstPacket.channel);
891 						break;
892 					case MIDI2_0Cmd.PrgCh:	//Program change
893 						const uint chOffset = firstPacket.channel;
894 						//const uint prg = data[1]>>24, bank = data[1] & 7;
895 						presetNum[chOffset] = cast(ubyte)(data[1]>>24);
896 						if (firstPacket.value & 1) bankNum[chOffset] = cast(ubyte)(data[1] & 7);
897 						const uint chCtrl = soundBank[bankNum[chOffset] & 7][presetNum[chOffset]].channel.chCtrl;
898 						if (chCtrl & ChCtrlFlags.ComboModeTest) {
899 							const uint chX = chOffset & 7, bankX = bankNum[chOffset] & 7 & ~1;
900 							prgRecall(chX, presetNum[chX], bankX);
901 							prgRecall(chX + 8, presetNum[chX], bankX + 1);
902 						} else {
903 							prgRecall(chOffset, presetNum[chOffset], bankNum[chOffset]);
904 						}
905 						break;
906 					case MIDI2_0Cmd.NoteOn:
907 						NoteVals v = *cast(NoteVals*)(&data[1]);
908 						const uint ch = firstPacket.channel;
909 						if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch > 7) return;
910 						chCtrls[ch].note = firstPacket.note;
911 						chCtrls[ch].velocity = v.velocity / cast(double)ushort.max;
912 						channels[ch].eeg.keyOn();
913 						operators[ch].eg.keyOn();
914 						operators[ch].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun);
915 						operators[ch + 1].eg.keyOn();
916 						operators[ch + 1].setFrequency(sampleRate, firstPacket.note, chCtrls[ch + 1].pitchBend, channels[ch].preset.chnlTun);
917 						if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch <= 7) {
918 							channels[ch + 8].eeg.keyOn();
919 							operators[ch + 16].eg.keyOn();
920 							operators[ch + 16].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun);
921 							operators[ch + 17].eg.keyOn();
922 							operators[ch + 17].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun);
923 						}
924 						break;
925 					case MIDI2_0Cmd.NoteOff:
926 						NoteVals v = *cast(NoteVals*)(&data[1]);
927 						const uint ch = firstPacket.channel;
928 						if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch > 7) return;
929 						//chCtrls[ch].note = firstPacket.note;
930 						chCtrls[ch].velocity = v.velocity / cast(double)ushort.max;
931 						channels[ch].eeg.keyOff();
932 						operators[ch].eg.keyOff();
933 						if (operators[ch].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) {
934 							if (operators[ch].preset.rel) {
935 								operators[ch].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch].preset.rel] * 2, sampleRate, 
936 										operators[ch].eg.sustainLevel);
937 							} else {
938 								operators[ch].eg.releaseRate = 1.0;
939 							}
940 						}
941 						operators[ch + 1].eg.keyOff();
942 						if (operators[ch + 1].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) {
943 							if (operators[ch + 1].preset.rel) {
944 								operators[ch + 1].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 1].preset.rel] * 2, sampleRate, 
945 										operators[ch + 1].eg.sustainLevel);
946 							} else {
947 								operators[ch + 1].eg.releaseRate = 1.0;
948 							}
949 						}
950 						if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch <= 7) {
951 							channels[ch + 8].eeg.keyOff();
952 							operators[ch + 16].eg.keyOff();
953 							if (operators[ch + 16].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) {
954 								if (operators[ch + 16].preset.rel) {
955 									operators[ch + 16].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 16].preset.rel] * 2, sampleRate, 
956 											operators[ch + 16].eg.sustainLevel);
957 								} else {
958 									operators[ch + 16].eg.releaseRate = 1.0;
959 								}
960 							}
961 							operators[ch + 17].eg.keyOff();
962 							if (operators[ch + 17].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) {
963 								if (operators[ch + 17].preset.rel) {
964 									operators[ch + 17].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 17].preset.rel] * 2, sampleRate, 
965 											operators[ch + 17].eg.sustainLevel);
966 								} else {
967 									operators[ch + 17].eg.releaseRate = 1.0;
968 								}
969 							}
970 						}
971 						break;
972 					case MIDI2_0Cmd.PitchBend:
973 						const uint ch = firstPacket.channel;
974 						const double pitchBendSens = (channels[ch].preset.pitchBendSens>>25) + 
975 								(cast(double)(channels[ch].preset.pitchBendSens & 0x01_FF_FF_FF) / 0x01_FF_FF_FF);
976 						chCtrls[ch].pitchBend = pitchBendSens * (cast(double)(firstPacket.bend - (uint.max / 2)) / (uint.max / 2));
977 						break;
978 					default:
979 						break;
980 				}
981 				break;
982 			default:
983 				break;
984 		}
985 	}
986 	/**
987 	Sets the channel delegates
988 	*/
989 	protected void setChDeleg(uint chCtrl, uint chNum, uint chCtrl0 = 0) @nogc @safe pure nothrow {
990 		if (chCtrl & ChCtrlFlags.ComboModeTest) {	//Test if channel is combined or not
991 			if (chNum < 8) {
992 				const uint algID = chCtrl & (ChCtrlFlags.ComboModeTest & ChCtrlFlags.Algorithm) | 
993 						((chCtrl0 & ChCtrlFlags.Algorithm)<<1);
994 				enum priChAlg = ChCtrlFlags.Algorithm;
995 				enum secChAlg = ChCtrlFlags.Algorithm<<1;
996 				switch (algID) {
997 					case ChCtrlFlags.ComboMode1:
998 						chDeleg[chNum] = &updateChannelM100;
999 						break;
1000 					case ChCtrlFlags.ComboMode1 | secChAlg:
1001 						chDeleg[chNum] = &updateChannelM110;
1002 						break;
1003 					case ChCtrlFlags.ComboMode1 | priChAlg:
1004 						chDeleg[chNum] = &updateChannelM101;
1005 						break;
1006 					case ChCtrlFlags.ComboMode1 | secChAlg | priChAlg:
1007 						chDeleg[chNum] = &updateChannelM111;
1008 						break;
1009 					case ChCtrlFlags.ComboMode2:
1010 						chDeleg[chNum] = &updateChannelM200;
1011 						break;
1012 					case ChCtrlFlags.ComboMode2 | secChAlg:
1013 						chDeleg[chNum] = &updateChannelM210;
1014 						break;
1015 					case ChCtrlFlags.ComboMode2 | priChAlg:
1016 						chDeleg[chNum] = &updateChannelM201;
1017 						break;
1018 					case ChCtrlFlags.ComboMode2 | secChAlg | priChAlg:
1019 						chDeleg[chNum] = &updateChannelM211;
1020 						break;
1021 					case ChCtrlFlags.ComboMode3:
1022 						chDeleg[chNum] = &updateChannelM300;
1023 						break;
1024 					case ChCtrlFlags.ComboMode3 | secChAlg:
1025 						chDeleg[chNum] = &updateChannelM310;
1026 						break;
1027 					case ChCtrlFlags.ComboMode3 | priChAlg:
1028 						chDeleg[chNum] = &updateChannelM301;
1029 						break;
1030 					case ChCtrlFlags.ComboMode3 | secChAlg | priChAlg:
1031 						chDeleg[chNum] = &updateChannelM311;
1032 						break;
1033 					default:
1034 						chDeleg[chNum] = &updateChannelMD;
1035 						break;
1036 				}
1037 			} else {
1038 				chDeleg[chNum] = &updateChannelMD;
1039 			}
1040 		} else {
1041 			if (chCtrl & ChCtrlFlags.Algorithm) 
1042 				chDeleg[chNum] = &updateChannelM01;
1043 			else
1044 				chDeleg[chNum] = &updateChannelM00;
1045 		}
1046 	}
1047 	/**
1048 	Recalls a program
1049 	*/
1050 	protected void prgRecall(ubyte ch, ubyte prg, ubyte bank) @nogc @safe pure nothrow {
1051 		Preset p = soundBank[bank & 7][prg];
1052 		operators[ch].preset = p.operators[0];
1053 		operators[ch].resetEG(sampleRate);
1054 		operators[ch + 1].preset = p.operators[1];
1055 		operators[ch + 1].resetEG(sampleRate);
1056 		channels[ch].preset = p.channel;
1057 		channels[ch].resetEEG(sampleRate);
1058 	}
1059 	/**
1060 	Sets a registered parameter
1061 
1062 	If type is not zero, then the MSB is being set, otherwise the LSB will be used
1063 	*/
1064 	protected void setRegisteredParam(T)(T val, ubyte[2] paramNum, ubyte type, ubyte chNum) @nogc @safe pure nothrow {
1065 		switch (paramNum[0]) {
1066 			case ChannelRegParams.PitchBendSens:
1067 				static if (is(T == uint)) {
1068 					channels[chNum].pitchBendSens = val;
1069 				} else static if (is(T == ubyte)) {
1070 					if (type) {
1071 						channels[chNum].pitchBendSens &= ~(byte.max<<25);
1072 						channels[chNum].pitchBendSens |= val<<25;
1073 					} else {
1074 						channels[chNum].pitchBendSens &= ~(byte.max<<18);
1075 						channels[chNum].pitchBendSens |= val<<18;
1076 					}
1077 				}
1078 				break;
1079 			case ChannelRegParams.TuneFine:			//Channel master tuning (fine)
1080 				break;
1081 			case ChannelRegParams.TuneCor:			//Channel master tuning (coarse)
1082 				break;
1083 			default: break;
1084 		}
1085 	}
1086 	/**
1087 	Sets an unregistered parameter (MIDI 2.0)
1088 
1089 	If type is not zero, then the MSB is being set, otherwise the LSB will be used
1090 	*/
1091 	protected void setUnregisteredParam(uint val, ubyte[2] paramNum, ubyte chNum) @nogc @safe pure nothrow {
1092 		void setOpParam(int chNum) {
1093 			switch (paramNum[0]) {
1094 				case OperatorParamNums.Attack:
1095 					operators[chNum].preset.atk = cast(ubyte)(val >> 25);
1096 					
1097 					if (operators[chNum].preset.atk) {
1098 						operators[chNum].eg.attackRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].preset.atk], sampleRate);
1099 					} else {
1100 						operators[chNum].eg.attackRate = 1.0;
1101 					}
1102 					break;
1103 				case OperatorParamNums.Decay:
1104 					operators[chNum].preset.dec = cast(ubyte)(val >> 25);
1105 					
1106 					if (operators[chNum].preset.dec) {
1107 						operators[chNum].eg.decayRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].preset.dec] * 2, sampleRate, 
1108 								ADSREnvelopGenerator.maxOutput, operators[chNum].eg.sustainLevel);
1109 					} else {
1110 						operators[chNum].eg.decayRate = 1.0;
1111 					}
1112 					break;
1113 				case OperatorParamNums.Feedback:
1114 					const double valF = cast(double)val / uint.max;
1115 					operators[chNum].preset.fbL = valF * valF;
1116 					break;
1117 				case OperatorParamNums.Level:
1118 					const double valF = cast(double)val / uint.max;
1119 					operators[chNum].preset.outL = valF * valF;
1120 					break;
1121 				case OperatorParamNums.OpCtrl:
1122 					operators[chNum].preset.opCtrl = val;
1123 					break;
1124 				case OperatorParamNums.Release:
1125 					operators[chNum].preset.rel = cast(ubyte)(val >> 25);
1126 					if (operators[chNum].preset.rel) {
1127 						operators[chNum].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].preset.rel] * 2, sampleRate, 
1128 								operators[chNum].eg.sustainLevel);
1129 					} else {
1130 						operators[chNum].eg.releaseRate = 1.0;
1131 					}
1132 					break;
1133 				case OperatorParamNums.ShpA:
1134 					operators[chNum].preset.shpA = cast(double)val / uint.max;
1135 					break;
1136 				case OperatorParamNums.ShpR:
1137 					operators[chNum].preset.shpR = cast(double)val / uint.max;
1138 					break;
1139 				case OperatorParamNums.SusCtrl:
1140 					operators[chNum].preset.susCC = cast(ubyte)(val >> 25);
1141 					if (operators[chNum].preset.susCC) {
1142 						operators[chNum].eg.isPercussive = false;
1143 						if (operators[chNum].preset.susCC == 64) {
1144 							operators[chNum].eg.sustainControl = 0.0;
1145 						} else if (operators[chNum].preset.susCC < 64) {
1146 							operators[chNum].eg.sustainControl = -1.0 * 
1147 									calculateRate(SUSTAIN_CONTROL_TIME_TABLE[operators[chNum].preset.susCC - 1], sampleRate);
1148 						} else {
1149 							operators[chNum].eg.sustainControl = 
1150 									calculateRate(SUSTAIN_CONTROL_TIME_TABLE[operators[chNum].preset.susCC - 64], sampleRate);
1151 						}
1152 					} else {
1153 						operators[chNum].eg.isPercussive = true;
1154 						operators[chNum].eg.sustainControl = 0.0;
1155 					}
1156 					break;
1157 				case OperatorParamNums.SusLevel:
1158 					operators[chNum].eg.sustainLevel = cast(double)val / uint.max;
1159 					//Recalculate decay and release rates to new sustain levels
1160 					if (operators[chNum].preset.dec) {
1161 						operators[chNum].eg.decayRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].preset.dec] * 2, sampleRate, 
1162 								ADSREnvelopGenerator.maxOutput, operators[chNum].eg.sustainLevel);
1163 					} else {
1164 						operators[chNum].eg.decayRate = 1.0;
1165 					}
1166 					if (operators[chNum].preset.rel) {
1167 						operators[chNum].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].preset.rel] * 2, sampleRate, 
1168 								operators[chNum].eg.sustainLevel);
1169 					} else {
1170 						operators[chNum].eg.releaseRate = 1.0;
1171 					}
1172 					break;
1173 				case OperatorParamNums.TuneCor:
1174 					operators[chNum].preset.tune = val;
1175 					
1176 					break;
1177 				case OperatorParamNums.TuneFine:
1178 					operators[chNum].preset.tune &= ~uint.max>>7;
1179 					operators[chNum].preset.tune |= val>>7;
1180 					break;
1181 				case OperatorParamNums.VelToLevel:
1182 					operators[chNum].preset.outLCtrl[0] = cast(double)val / uint.max;
1183 					break;
1184 				case OperatorParamNums.MWToLevel:
1185 					operators[chNum].preset.outLCtrl[1] = cast(double)val / uint.max;
1186 					break;
1187 				case OperatorParamNums.LFOToLevel:
1188 					operators[chNum].preset.outLCtrl[2] = cast(double)val / uint.max;
1189 					break;
1190 				case OperatorParamNums.VelToFB:
1191 					operators[chNum].preset.fbLCtrl[0] = cast(double)val / uint.max;
1192 					break;
1193 				case OperatorParamNums.MWToFB:
1194 					operators[chNum].preset.fbLCtrl[1] = cast(double)val / uint.max;
1195 					break;
1196 				case OperatorParamNums.LFOToFB:
1197 					operators[chNum].preset.fbLCtrl[2] = cast(double)val / uint.max;
1198 					break;
1199 				case OperatorParamNums.EEGToFB:
1200 					operators[chNum].preset.fbLCtrl[3] = cast(double)val / uint.max;
1201 					break;
1202 				case OperatorParamNums.VelToShpA:
1203 					operators[chNum].preset.shpAVel = cast(double)val / uint.max;
1204 					break;
1205 				case OperatorParamNums.VelToShpR:
1206 					operators[chNum].preset.shpRVel = cast(double)val / uint.max;
1207 					break;
1208 				case OperatorParamNums.Waveform:
1209 					operators[chNum].preset.opCtrl &= ~OpCtrlFlags.WavetableSelect;
1210 					operators[chNum].preset.opCtrl |= cast(ubyte)(val >> 25);
1211 					break;
1212 				default: break;
1213 			}
1214 		}
1215 		switch (paramNum[1]) {
1216 			case 0:			//Channel operator 0
1217 				chNum *= 2;
1218 				setOpParam(chNum);
1219 				break;
1220 			case 1:			//Channel operator 1
1221 				chNum *= 2;
1222 				setOpParam(chNum + 1);
1223 				break;
1224 			case 2:			//Channel common values
1225 				switch (paramNum[0]) { 
1226 					//case ChannelParamNums.ALFO: break;
1227 					case ChannelParamNums.Attack:
1228 						channels[chNum].preset.atkX = cast(ubyte)(val >> 25);
1229 						if (channels[chNum].preset.atkX) {
1230 							channels[chNum].eeg.attackRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].preset.atkX], sampleRate);
1231 						} else {
1232 							channels[chNum].eeg.attackRate = 1.0;
1233 						}
1234 						break;
1235 					case ChannelParamNums.AuxSLA:
1236 						const double valF = cast(double)val / uint.max;
1237 						channels[chNum].outLevels[2] = valF * valF;
1238 						channels[chNum].preset.auxSendA = channels[chNum].outLevels[2];
1239 						break;
1240 					case ChannelParamNums.AuxSLB: 
1241 						const double valF = cast(double)val / uint.max;
1242 						channels[chNum].outLevels[2] = valF * valF;
1243 						channels[chNum].preset.auxSendB = channels[chNum].outLevels[3];
1244 						break;
1245 					case ChannelParamNums.Bal: 
1246 						channels[chNum].preset.masterBal = cast(double)val / uint.max;
1247 						if (channels[chNum].preset.chCtrl & ChCtrlFlags.IndivOutChLev) {
1248 							channels[chNum].outLevels[1] = channels[chNum].preset.masterBal * channels[chNum].preset.masterBal;
1249 						} else {
1250 							channels[chNum].outLevels[0] = channels[chNum].preset.masterVol - channels[chNum].preset.masterBal;
1251 							channels[chNum].outLevels[1] = channels[chNum].preset.masterVol - (1.0 - channels[chNum].preset.masterBal);
1252 						}
1253 						break;
1254 					case ChannelParamNums.ChCtrl:
1255 						channels[chNum].preset.chCtrl = val;
1256 						//mirror operator configuration parameters between paired channels
1257 						if (chNum < 8) {
1258 							channels[chNum + 8].preset.chCtrl &= ~ChCtrlFlags.ComboModeTest;
1259 							channels[chNum + 8].preset.chCtrl |= ChCtrlFlags.ComboModeTest & channels[chNum].preset.chCtrl;
1260 						} else {
1261 							channels[chNum - 8].preset.chCtrl &= ~ChCtrlFlags.ComboModeTest;
1262 							channels[chNum - 8].preset.chCtrl |= ChCtrlFlags.ComboModeTest & channels[chNum].preset.chCtrl;
1263 						}
1264 						break;
1265 					//case ChannelParamNums.ChCtrlL: break;
1266 					case ChannelParamNums.Decay:
1267 						channels[chNum].preset.decX = cast(ubyte)(val >> 25);
1268 						if (channels[chNum].preset.decX) {
1269 							channels[chNum].eeg.decayRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].preset.decX] * 2, sampleRate);
1270 						} else {
1271 							channels[chNum].eeg.decayRate = 1.0;
1272 						}
1273 						break;
1274 					case ChannelParamNums.EEGDetune:
1275 						channels[chNum].preset.eegDetuneAm = val;
1276 						break;
1277 					case ChannelParamNums.MasterVol: 
1278 						const double valF = cast(double)val / uint.max;
1279 						channels[chNum].outLevels[2] = valF * valF;
1280 						if (channels[chNum].preset.chCtrl & ChCtrlFlags.IndivOutChLev) {
1281 							channels[chNum].outLevels[1] = channels[chNum].preset.masterBal * channels[chNum].preset.masterBal;
1282 						} else {
1283 							channels[chNum].outLevels[0] = channels[chNum].preset.masterVol - channels[chNum].preset.masterBal;
1284 							channels[chNum].outLevels[1] = channels[chNum].preset.masterVol - (1.0 - channels[chNum].preset.masterBal);
1285 						}
1286 						break;
1287 					case ChannelParamNums.PLFO: 
1288 						channels[chNum].preset.pLFOlevel = cast(double)val / uint.max;
1289 						break;
1290 					case ChannelParamNums.Release: 
1291 						channels[chNum].preset.relX = cast(ubyte)(val >> 25);
1292 						if (channels[chNum].preset.relX) {
1293 							channels[chNum].eeg.releaseRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].preset.relX] * 2, sampleRate);
1294 						} else {
1295 							channels[chNum].eeg.releaseRate = 1.0;
1296 						}
1297 						break;
1298 					case ChannelParamNums.ShpA:
1299 						channels[chNum].preset.shpAX = cast(double)val / uint.max;
1300 						break;
1301 					case ChannelParamNums.ShpR:
1302 						channels[chNum].preset.shpRX = cast(double)val / uint.max;
1303 						break;
1304 					case ChannelParamNums.SusCtrl: 
1305 						channels[chNum].preset.susCCX = cast(ubyte)(val >> 25);
1306 						if (channels[chNum].preset.susCCX) {
1307 							channels[chNum].eeg.isPercussive = false;
1308 							if (channels[chNum].preset.susCCX == 64) {
1309 								channels[chNum].eeg.sustainControl = 0.0;
1310 							} else if (channels[chNum].preset.susCCX < 64) {
1311 								channels[chNum].eeg.sustainControl = -1.0 * 
1312 										calculateRate(SUSTAIN_CONTROL_TIME_TABLE[channels[chNum].preset.susCCX - 1], sampleRate);
1313 							} else {
1314 								channels[chNum].eeg.sustainControl = 
1315 										calculateRate(SUSTAIN_CONTROL_TIME_TABLE[channels[chNum].preset.susCCX - 64], sampleRate);
1316 							}
1317 						} else {
1318 							channels[chNum].eeg.isPercussive = true;
1319 							channels[chNum].eeg.sustainControl = 0.0;
1320 						}
1321 						break;
1322 					case ChannelParamNums.SusLevel: 
1323 						channels[chNum].eeg.sustainLevel = cast(double)val / uint.max;
1324 						channels[chNum].preset.susLevel = channels[chNum].eeg.sustainLevel;
1325 						break;
1326 					case ChannelParamNums.RingMod: 
1327 						channels[chNum].preset.rmAmount = val>>16;
1328 						break;
1329 					case ChannelParamNums.EEGToLeft:
1330 						const double valF = cast(double)val / uint.max;
1331 						channels[chNum].preset.eegLevels[0] = valF * valF;
1332 						break;
1333 					case ChannelParamNums.EEGToRight:
1334 						const double valF = cast(double)val / uint.max;
1335 						channels[chNum].preset.eegLevels[1] = valF * valF;
1336 						break;
1337 					case ChannelParamNums.EEGToAuxA:
1338 						const double valF = cast(double)val / uint.max;
1339 						channels[chNum].preset.eegLevels[2] = valF * valF;
1340 						break;
1341 					case ChannelParamNums.EEGToAuxB:
1342 						const double valF = cast(double)val / uint.max;
1343 						channels[chNum].preset.eegLevels[3] = valF * valF;
1344 						break;
1345 					case ChannelParamNums.LFOToLeft:
1346 						const double valF = cast(double)val / uint.max;
1347 						channels[chNum].preset.aLFOlevels[0] = valF * valF;
1348 						
1349 						break;
1350 					case ChannelParamNums.LFOToRight:
1351 						const double valF = cast(double)val / uint.max;
1352 						channels[chNum].preset.aLFOlevels[1] = valF * valF;
1353 						break;
1354 					case ChannelParamNums.LFOToAuxA:
1355 						const double valF = cast(double)val / uint.max;
1356 						channels[chNum].preset.aLFOlevels[2] = valF * valF;
1357 						break;
1358 					case ChannelParamNums.LFOToAuxB:
1359 						const double valF = cast(double)val / uint.max;
1360 						channels[chNum].preset.aLFOlevels[3] = valF * valF;
1361 						break;
1362 					default:
1363 						break;
1364 				}
1365 				break;
1366 			case 16:		//LFO and master filter settings
1367 				void setFilterFreq(int num) @nogc @safe pure nothrow {
1368 					const double valF = cast(double)val / uint.max;
1369 					filterCtrl[num] = valF * valF * 20_000;
1370 
1371 				}
1372 				void setFilterQ(int num) @nogc @safe pure nothrow {
1373 					const double valF = cast(double)val / uint.max;
1374 					filterCtrl[num] = valF * 2;
1375 				}
1376 				switch (paramNum[0]) {
1377 					case GlobalParamNums.PLFORate:
1378 						double valF;
1379 						valF = cast(double)val / uint.max;
1380 						valF *= 16;
1381 						const double cycleLen = sampleRate / (1.0 / valF);
1382 						pLFORate = cast(int)(cycleLen * ((1<<20) / 1024.0) * bufferSize);
1383 						break;
1384 					case GlobalParamNums.PLFOWF:
1385 						lfoWaveform[0] = cast(ubyte)(val >> 25);
1386 						break;
1387 					case GlobalParamNums.ALFORate:
1388 						double valF;
1389 						valF = cast(double)val / uint.max;
1390 						valF *= 16;
1391 						const double cycleLen = sampleRate / (1.0 / valF);
1392 						aLFORate = cast(int)(cycleLen * ((1<<20) / 1024.0));
1393 						break;
1394 					case GlobalParamNums.ALFOWF:
1395 						lfoWaveform[1] = cast(ubyte)(val >> 25);
1396 						break;
1397 					case GlobalParamNums.FilterLCFreq:
1398 						setFilterFreq(0);
1399 						break;
1400 					case GlobalParamNums.FilterLCQ: 
1401 						setFilterQ(1);
1402 						break;
1403 					case GlobalParamNums.FilterRCFreq: 
1404 						setFilterFreq(2);
1405 						break;
1406 					case GlobalParamNums.FilterRCQ: 
1407 						setFilterQ(3);
1408 						break;
1409 					case GlobalParamNums.FilterACFreq:
1410 						setFilterFreq(4);
1411 						break;
1412 					case GlobalParamNums.FilterACQ: 
1413 						setFilterQ(5);
1414 						break;
1415 					case GlobalParamNums.FilterBCFreq: 
1416 						setFilterFreq(6);
1417 						break;
1418 					case GlobalParamNums.FilterBCQ: 
1419 						setFilterQ(7);
1420 						break;
1421 					default:
1422 						break;
1423 				}
1424 				break;
1425 			default: break;
1426 		}
1427 	}
1428 	/**
1429 	 * Renders the current audio frame.
1430 	 * 
1431 	 * input: the input buffers if any, null if none.
1432 	 * output: the output buffers if any, null if none.
1433 	 *
1434 	 * NOTE: Buffers must have matching sizes.
1435 	 */
1436 	public override void renderFrame(float*[] input, float*[] output) @nogc nothrow {
1437 		//Generate aLFO table
1438 		for (int i ; i < bufferSize ; i++) {
1439 			aLFOBuf[i] = (wavetables[lfoWaveform[1]][(aLFOPos>>20) & 1023] - short.min) * (1 / cast(float)(ushort.max));
1440 			aLFOPos += aLFORate;
1441 		}
1442 		//Generate pLFO out
1443 		{
1444 			pLFOOut = (wavetables[lfoWaveform[0]][(pLFOPos>>20) & 1023]) * (1 / cast(float)(short.max));
1445 			pLFOPos += pLFORate;
1446 		}
1447 		//Render each channel
1448 		foreach (size_t i, ChFun fun ; chDeleg) {
1449 			fun(cast(int)i, bufferSize);
1450 		}
1451 		//Filter and mix outputs
1452 		float*[4] outBuf;
1453 		for (ubyte i, j ; i < 4 ; i++) {
1454 			if (enabledOutputs.has(i)) {
1455 				outBuf[i] = output[j];
1456 				j++;
1457 			} else {
1458 				outBuf[i] = dummyBuf.ptr;
1459 			}
1460 		}
1461 		const __m128 b0_a0 = filterVals[3] / filterVals[0], b1_a0 = filterVals[4] / filterVals[0], 
1462 				b2_a0 = filterVals[5] / filterVals[0], a1_a0 = filterVals[1] / filterVals[0], a2_a0 = filterVals[2] / filterVals[0];
1463 		for (int i ; i < bufferSize ; i++) {
1464 			__m128 input0 = _mm_load_ps(initBuffers.ptr + (i * 4));
1465 			input0 *= __m128(mixdownVal);
1466 			input0 = _mm_max_ps(input0, __m128(-1.0));
1467 			input0 = _mm_min_ps(input0, __m128(1.0));
1468 			__m128 output0 = b0_a0 * input0 + b1_a0 * filterVals[6] + b2_a0 * filterVals[7] - a1_a0 * filterVals[8] - 
1469 					a2_a0 * filterVals[9];
1470 			for (int j ; j < 4 ; j++)
1471 				outBuf[j][i] += output0[j];
1472 			filterVals[7] = filterVals[6];
1473 			filterVals[6] = input0;
1474 			filterVals[9] = filterVals[8];
1475 			filterVals[8] = output0;
1476 		}
1477 	}
1478 	///Updates an operator for a cycle
1479 	///chCtrl index notation: 0: velocity, 1: modulation wheel, 2: Amplitude LFO, 3: Extra Envelop Generator
1480 	pragma(inline, true)
1481 	protected final void updateOperator(ref Operator op, __m128 chCtrl) @nogc @safe pure nothrow {
1482 		op.output = wavetables[op.preset.opCtrl & OpCtrlFlags.WavetableSelect][(op.pos>>20 + op.input>>4 + op.feedback>>3) 
1483 				& 0x3_FF];
1484 		const double egOut = op.eg.shp(op.eg.position == ADSREnvelopGenerator.Stage.Attack ? op.shpA0 : op.shpR0);
1485 		const double out0 = op.output;
1486 		__m128 outCtrl = (op.preset.outLCtrl * chCtrl) + (__m128(1.0) - (__m128(1.0) * op.preset.outLCtrl));
1487 		__m128 fbCtrl = (op.preset.fbLCtrl * chCtrl) + (__m128(1.0) - (__m128(1.0) * op.preset.fbLCtrl));
1488 		const double out1 = out0 * egOut;
1489 		//vel = op.opCtrl & OpCtrlFlags.VelNegative ? 1.0 - vel : vel;
1490 		op.feedback = cast(int)((op.preset.opCtrl & OpCtrlFlags.FBMode ? out0 : out1) * op.preset.fbL * fbCtrl[0] * fbCtrl[1] * 
1491 				fbCtrl[2] * fbCtrl[3]);
1492 		//op.feedback *= op.opCtrl & OpCtrlFlags.FBNeg ? -1 : 1;
1493 		op.output_0 = cast(int)(out1 * op.preset.outL * outCtrl[0] * outCtrl[1] * outCtrl[2]);
1494 		op.pos += op.step;
1495 		//op.input = 0;
1496 		op.eg.advance();
1497 	}
1498 	///Macro for channel update constants that need to be calculated once per frame
1499 	///Kept in at one place to make updates easier and more consistent
1500 	static immutable string CHNL_UPDATE_CONSTS =
1501 		q{
1502 			const int opOffset = chNum * 2;
1503 			__m128 aLFOOutMW = __m128(channels[chNum].preset.chCtrl & ChCtrlFlags.MWToTrem ? 
1504 					chCtrls[chNum].modwheel : 1.0);
1505 			const float auxSendAmMW = (channels[chNum].preset.chCtrl & ChCtrlFlags.MWToAux ? 
1506 					chCtrls[chNum].modwheel : 1.0);
1507 			__m128 opCtrl0, opCtrl1, mwAuxCtrl;
1508 			opCtrl0[0] = operators[opOffset].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 
1509 					chCtrls[chNum].velocity;
1510 			opCtrl1[0] = operators[opOffset + 1].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 
1511 					chCtrls[chNum].velocity;
1512 			opCtrl0[1] = operators[opOffset].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : 
1513 					chCtrls[chNum].modwheel;
1514 			opCtrl1[1] = operators[opOffset + 1].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : 
1515 					chCtrls[chNum].modwheel;
1516 			mwAuxCtrl[0] = 1.0;
1517 			mwAuxCtrl[1] = 1.0;
1518 			mwAuxCtrl[2] = auxSendAmMW;
1519 			mwAuxCtrl[3] = auxSendAmMW;
1520 			const float lfopan = (channels[chNum].preset.chCtrl & ChCtrlFlags.LFOPan ? 1.0 : 0);
1521 			const float eegpan = (channels[chNum].preset.chCtrl & ChCtrlFlags.EEGPan ? 1.0 : 0);
1522 		};
1523 	///Macro for channel update constants that need to be calculated once per frame, for combined channels' second half
1524 	///Kept in at one place to make updates easier and more consistent
1525 	static immutable string CHNL_UPDATE_CONSTS0 =
1526 		q{
1527 			__m128 opCtrl2, opCtrl3;
1528 			opCtrl2[0] = operators[opOffset + 16].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 
1529 					chCtrls[chNum].velocity;
1530 			opCtrl3[0] = operators[opOffset + 17].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 
1531 					chCtrls[chNum].velocity;
1532 			opCtrl2[1] = operators[opOffset + 16].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : 
1533 					chCtrls[chNum].modwheel;
1534 			opCtrl3[1] = operators[opOffset + 17].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : 
1535 					chCtrls[chNum].modwheel;
1536 			const float eegpan0 = (channels[chNum + 8].preset.chCtrl & ChCtrlFlags.EEGPan ? 1.0 : 0);
1537 		};
1538 	///Macro for channel update constants that need to be calculated for each cycle
1539 	///Kept in at one place to make updates easier and more consistent
1540 	static immutable string CHNL_UPDATE_CONSTS_CYCL = 
1541 		q{
1542 			const float eegOut = channels[chNum].eeg.shp(channels[chNum].eeg.position == 
1543 					ADSREnvelopGenerator.Stage.Attack ? channels[chNum].preset.shpAX : channels[chNum].preset.shpRX);
1544 			__m128 eegToMast = __m128(eegOut), lfoToMast = __m128(aLFOBuf[i]);
1545 			eegToMast[0] = abs(eegpan - eegToMast[0]);
1546 			lfoToMast[0] = abs(lfopan - lfoToMast[0]);
1547 			opCtrl0[2] = aLFOBuf[i];
1548 			opCtrl1[2] = aLFOBuf[i];
1549 			opCtrl0[3] = eegOut;
1550 			opCtrl1[3] = eegOut;
1551 		};
1552 	
1553 	///Macro for channel update constants that need to be calculated for each cycle for combined channels' second half
1554 	///Kept in at one place to make updates easier and more consistent
1555 	static immutable string CHNL_UPDATE_CONSTS_CYCL0 = 
1556 		q{
1557 			const float eegOut0 = channels[chNum + 8].eeg.shp(channels[chNum + 8].eeg.position == 
1558 					ADSREnvelopGenerator.Stage.Attack ? channels[chNum + 8].preset.shpAX : 
1559 					channels[chNum + 8].preset.shpRX);
1560 			__m128 eegToMast0 = __m128(eegOut0);
1561 			eegToMast0[0] = abs(eegpan0 - eegToMast0[0]);
1562 			opCtrl2[2] = aLFOBuf[i];
1563 			opCtrl3[2] = aLFOBuf[i];
1564 			opCtrl2[3] = eegOut0;
1565 			opCtrl3[3] = eegOut0;
1566 		};
1567 			
1568 	///Macro for output mixing
1569 	static immutable string CHNL_UPDATE_MIX =
1570 		q{
1571 			__m128 outlevels = channels[chNum].outLevels * mwAuxCtrl;
1572 			outlevels *= (channels[chNum].preset.eegLevels * eegToMast) + (__m128(1.0) - (__m128(1.0) * 
1573 					channels[chNum].preset.eegLevels));
1574 			outlevels *= (channels[chNum].preset.aLFOlevels * lfoToMast) + (__m128(1.0) - (__m128(1.0) * 
1575 					channels[chNum].preset.aLFOlevels));
1576 			_mm_store1_ps(initBuffers.ptr + (i<<2), _mm_load_ps(initBuffers.ptr + (i<<2)) + outlevels *
1577 					_mm_cvtepi32_ps(outSum));
1578 		};
1579 	///Macro for output mixing in case of combo modes
1580 	static immutable string CHNL_UPDATE_MIX0 =
1581 		q{
1582 			__m128 outlevels = channels[chNum].outLevels * mwAuxCtrl;
1583 			outlevels *= (channels[chNum].eegLevels * eegToMast) + (__m128(1.0) - (__m128(1.0) * 
1584 					channels[chNum].eegLevels));
1585 			outlevels *= (channels[chNum + 8].eegLevels * eegToMast0) + (__m128(1.0) - 
1586 			 (__m128(1.0) * channels[chNum + 8].eegLevels));
1587 			outlevels *= (channels[chNum].aLFOlevels * lfoToMast) + (__m128(1.0) - (__m128(1.0) * 
1588 					channels[chNum].aLFOlevels);
1589 			_mm_store1_ps(initBuffers.ptr + (i<<2), _mm_load_ps(initBuffers.ptr + (i<<2)) + outlevels *
1590 					_mm_cvtepi32_ps(outSum));
1591 		};
1592 	
1593 
1594 	///Algorithm Mode 0/0 (Serial)
1595 	protected void updateChannelM00(int chNum, size_t length) @nogc pure nothrow {
1596 		mixin(CHNL_UPDATE_CONSTS);
1597 		for (size_t i ; i < length ; i++) {
1598 			channels[chNum].eeg.advance();
1599 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1600 			updateOperator(operators[opOffset], opCtrl0);
1601 			operators[opOffset + 1].input = operators[opOffset].output_0;
1602 			updateOperator(operators[opOffset + 1], opCtrl1);
1603 			//const int outSum = operators[opOffset].output_0;
1604 			__m128i outSum = __m128i(operators[opOffset + 1].output_0);
1605 			mixin(CHNL_UPDATE_MIX);
1606 		}
1607 	}
1608 	///Algorithm Mode0/1 (Parallel)
1609 	protected void updateChannelM01(int chNum, size_t length) @nogc pure nothrow {
1610 		mixin(CHNL_UPDATE_CONSTS);
1611 		for (size_t i ; i < length ; i++) {
1612 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1613 			updateOperator(operators[opOffset], opCtrl0);
1614 			updateOperator(operators[opOffset + 1], opCtrl1);
1615 			//const int outSum = operators[opOffset].output_0 + operators[opOffset + 1].output_0;
1616 			__m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 
1617 					((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].preset.rmAmount)>>16);
1618 			mixin(CHNL_UPDATE_MIX);
1619 			channels[chNum].eeg.advance();
1620 		}
1621 	}
1622 	///Algorithm Mode1/00 ([S0]->[S1]->[P0]->[P1])
1623 	protected void updateChannelM100(int chNum, size_t length) @nogc pure nothrow {
1624 		mixin(CHNL_UPDATE_CONSTS);
1625 		mixin(CHNL_UPDATE_CONSTS0);
1626 		for (size_t i ; i < length ; i++) {
1627 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1628 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1629 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1630 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1631 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1632 			operators[opOffset].input = operators[opOffset + 17].output_0;
1633 			updateOperator(operators[opOffset], opCtrl0);		//P0
1634 			operators[opOffset + 1].input = operators[opOffset].output_0;
1635 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1636 			//const int outSum = operators[opOffset + 1].output_0;
1637 			__m128i outSum = __m128i(operators[opOffset + 1].output_0);
1638 			mixin(CHNL_UPDATE_MIX);
1639 			channels[chNum].eeg.advance();
1640 			channels[chNum + 8].eeg.advance();
1641 		}
1642 	}
1643 	///Dummy algorithm for combined channels
1644 	protected void updateChannelMD(int chNum, size_t length) @nogc pure nothrow {
1645 
1646 	}
1647 	/**
1648 	Algorithm Mode1/10
1649 	[S0]\
1650     	 ->[P0]->[P1]->
1651 	[S1]/
1652 	*/
1653 	protected void updateChannelM110(int chNum, size_t length) @nogc pure nothrow {
1654 		mixin(CHNL_UPDATE_CONSTS);
1655 		mixin(CHNL_UPDATE_CONSTS0);
1656 		for (size_t i ; i < length ; i++) {
1657 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1658 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1659 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1660 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1661 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1662 			operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
1663 			updateOperator(operators[opOffset], opCtrl0);		//P0
1664 			operators[opOffset + 1].input = operators[opOffset].output_0;
1665 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1666 			//const int outSum = operators[opOffset + 1].output_0;
1667 			__m128i outSum = __m128i(operators[opOffset + 1].output_0);
1668 			mixin(CHNL_UPDATE_MIX);
1669 			channels[chNum].eeg.advance();
1670 			channels[chNum + 8].eeg.advance();
1671 		}
1672 	}
1673 	/**
1674 	Algorithm Mode1/01
1675 	[S0]->[S1]->[P0]->
1676             	[P1]->
1677 	*/
1678 	protected void updateChannelM101(int chNum, size_t length) @nogc pure nothrow {
1679 		mixin(CHNL_UPDATE_CONSTS);
1680 		mixin(CHNL_UPDATE_CONSTS0);
1681 		for (size_t i ; i < length ; i++) {
1682 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1683 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1684 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1685 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1686 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1687 			operators[opOffset].input = operators[opOffset + 17].output_0;
1688 			updateOperator(operators[opOffset], opCtrl0);		//P0
1689 			//operators[opOffset + 1].input = operators[opOffset].output_0;
1690 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1691 			//const int outSum = operators[opOffset + 1].output_0;
1692 			__m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 
1693 					((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].preset.rmAmount)>>16);
1694 			mixin(CHNL_UPDATE_MIX);
1695 			channels[chNum].eeg.advance();
1696 			channels[chNum + 8].eeg.advance();
1697 		}
1698 	}
1699 	/**
1700 	Algorithm Mode1/11
1701 	[S0]\
1702     	 ->[P0]->
1703 	[S1]/  [P1]->
1704 	*/
1705 	protected void updateChannelM111(int chNum, size_t length) @nogc pure nothrow {
1706 		mixin(CHNL_UPDATE_CONSTS);
1707 		mixin(CHNL_UPDATE_CONSTS0);
1708 		for (size_t i ; i < length ; i++) {
1709 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1710 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1711 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1712 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1713 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1714 			operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
1715 			updateOperator(operators[opOffset], opCtrl0);		//P0
1716 			//operators[opOffset + 1].input = operators[opOffset].output_0;
1717 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1718 			//const int outSum = operators[opOffset + 1].output_0;
1719 			__m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 
1720 					((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].preset.rmAmount)>>16);
1721 			mixin(CHNL_UPDATE_MIX);
1722 			channels[chNum].eeg.advance();
1723 			channels[chNum + 8].eeg.advance();
1724 		}
1725 	}
1726 	/**
1727 	Algorithm Mode2/00
1728 	[S0]->[S1]\
1729 	           ->[P1]->
1730     	  [P0]/
1731 	*/
1732 	protected void updateChannelM200(int chNum, size_t length) @nogc pure nothrow {
1733 		mixin(CHNL_UPDATE_CONSTS);
1734 		mixin(CHNL_UPDATE_CONSTS0);
1735 		for (size_t i ; i < length ; i++) {
1736 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1737 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1738 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1739 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1740 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1741 			//operators[opOffset].input = operators[opOffset + 17].output_0;
1742 			updateOperator(operators[opOffset], opCtrl0);		//P0
1743 			operators[opOffset + 1].input = operators[opOffset].output_0 + operators[opOffset + 17].output_0;
1744 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1745 			//const int outSum = operators[opOffset + 1].output_0;
1746 			__m128i outSum = __m128i(operators[opOffset + 1].output_0);
1747 			mixin(CHNL_UPDATE_MIX);
1748 			channels[chNum].eeg.advance();
1749 			channels[chNum + 8].eeg.advance();
1750 		}
1751 	}
1752 	/**
1753 	Algorithm Mode2/10
1754 	[S0]\
1755 	[S1]-->[P1]->
1756 	[P0]/
1757 	*/
1758 	protected void updateChannelM210(int chNum, size_t length) @nogc pure nothrow {
1759 		mixin(CHNL_UPDATE_CONSTS);
1760 		mixin(CHNL_UPDATE_CONSTS0);
1761 		for (size_t i ; i < length ; i++) {
1762 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1763 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1764 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1765 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1766 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1767 			//operators[opOffset].input = operators[opOffset + 17].output_0;
1768 			updateOperator(operators[opOffset], opCtrl0);		//P0
1769 			operators[opOffset + 1].input = operators[opOffset].output_0 + operators[opOffset + 17].output_0 + 
1770 					operators[opOffset + 16].output_0;
1771 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1772 			//const int outSum = operators[opOffset + 1].output_0;
1773 			__m128i outSum = __m128i(operators[opOffset + 1].output_0);
1774 			mixin(CHNL_UPDATE_MIX);
1775 			channels[chNum].eeg.advance();
1776 			channels[chNum + 8].eeg.advance();
1777 		}
1778 	}
1779 	/**
1780 	Algorithm Mode2/01
1781 	          /[P0]->
1782 	[S0]->[S1]
1783     	      \[P1]->
1784 	*/
1785 	protected void updateChannelM201(int chNum, size_t length) @nogc pure nothrow {
1786 		mixin(CHNL_UPDATE_CONSTS);
1787 		mixin(CHNL_UPDATE_CONSTS0);
1788 		for (size_t i ; i < length ; i++) {
1789 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1790 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1791 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1792 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1793 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1794 			operators[opOffset].input = operators[opOffset + 17].output_0;
1795 			updateOperator(operators[opOffset], opCtrl0);		//P0
1796 			operators[opOffset + 1].input = operators[opOffset + 17].output_0;
1797 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1798 			//const int outSum = operators[opOffset + 1].output_0;
1799 			__m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset].output_0 + 
1800 					((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].preset.rmAmount)>>16);
1801 			mixin(CHNL_UPDATE_MIX);
1802 			channels[chNum].eeg.advance();
1803 			channels[chNum + 8].eeg.advance();
1804 		}
1805 	}
1806 	/**
1807 	Algorithm Mode2/11
1808 	[S0]\ /[P0]->
1809 	     -
1810 	[S1]/ \[P1]->
1811 	*/
1812 	protected void updateChannelM211(int chNum, size_t length) @nogc pure nothrow {
1813 		mixin(CHNL_UPDATE_CONSTS);
1814 		mixin(CHNL_UPDATE_CONSTS0);
1815 		for (size_t i ; i < length ; i++) {
1816 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1817 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1818 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1819 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1820 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1821 			operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
1822 			updateOperator(operators[opOffset], opCtrl0);		//P0
1823 			operators[opOffset + 1].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
1824 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1825 			//const int outSum = operators[opOffset + 1].output_0;
1826 			__m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset].output_0 + 
1827 					((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].preset.rmAmount)>>16);
1828 			mixin(CHNL_UPDATE_MIX);
1829 			channels[chNum].eeg.advance();
1830 			channels[chNum + 8].eeg.advance();
1831 		}
1832 	}
1833 	/**
1834 	Algorithm Mode3/00
1835 	[S0]->[S1]->
1836 	[P0]->[P1]->
1837 	*/
1838 	protected void updateChannelM300(int chNum, size_t length) @nogc pure nothrow {
1839 		mixin(CHNL_UPDATE_CONSTS);
1840 		mixin(CHNL_UPDATE_CONSTS0);
1841 		for (size_t i ; i < length ; i++) {
1842 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1843 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1844 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1845 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1846 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1847 			//operators[opOffset].input = operators[opOffset + 17].output_0;
1848 			updateOperator(operators[opOffset], opCtrl0);		//P0
1849 			operators[opOffset + 1].input = operators[opOffset].output_0;
1850 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1851 			//const int outSum = operators[opOffset + 1].output_0;
1852 			__m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset + 17].output_0 + 
1853 					((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].preset.rmAmount)>>16);
1854 			mixin(CHNL_UPDATE_MIX);
1855 			channels[chNum].eeg.advance();
1856 			channels[chNum + 8].eeg.advance();
1857 		}
1858 	}
1859 	/**
1860 	Algorithm Mode3/10
1861 	      [S0]->
1862     	  [S1]->
1863 	[P0]->[P1]->
1864 	*/
1865 	protected void updateChannelM310(int chNum, size_t length) @nogc pure nothrow {
1866 		mixin(CHNL_UPDATE_CONSTS);
1867 		mixin(CHNL_UPDATE_CONSTS0);
1868 		for (size_t i ; i < length ; i++) {
1869 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1870 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1871 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1872 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1873 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1874 			//operators[opOffset].input = operators[opOffset + 17].output_0;
1875 			updateOperator(operators[opOffset], opCtrl0);		//P0
1876 			operators[opOffset + 1].input = operators[opOffset].output_0;
1877 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1878 			//const int outSum = operators[opOffset + 1].output_0;
1879 			__m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset + 17].output_0 + 
1880 					operators[opOffset + 16].output_0 + 
1881 					((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].preset.rmAmount)>>16);
1882 			mixin(CHNL_UPDATE_MIX);
1883 			channels[chNum].eeg.advance();
1884 			channels[chNum + 8].eeg.advance();
1885 		}
1886 	}
1887 	/**
1888 	Algorithm Mode3/01
1889 	    />[S1]->
1890 	[S0]->[P0]->
1891     	\>[P1]->
1892 	*/
1893 	protected void updateChannelM301(int chNum, size_t length) @nogc pure nothrow {
1894 		mixin(CHNL_UPDATE_CONSTS);
1895 		mixin(CHNL_UPDATE_CONSTS0);
1896 		for (size_t i ; i < length ; i++) {
1897 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1898 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1899 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1900 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1901 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1902 			operators[opOffset].input = operators[opOffset + 16].output_0;
1903 			updateOperator(operators[opOffset], opCtrl0);		//P0
1904 			operators[opOffset + 1].input = operators[opOffset + 16].output_0;
1905 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1906 			//const int outSum = operators[opOffset + 1].output_0;
1907 			__m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 
1908 					operators[opOffset + 17].output_0 + 
1909 					((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].preset.rmAmount)>>16);
1910 			mixin(CHNL_UPDATE_MIX);
1911 			channels[chNum].eeg.advance();
1912 			channels[chNum + 8].eeg.advance();
1913 		}
1914 	}
1915 	/**
1916 	Algorithm Mode3/11
1917 	[S0]->
1918 	[S1]->
1919 	[P0]->
1920 	[P1]->
1921 	*/
1922 	protected void updateChannelM311(int chNum, size_t length) @nogc pure nothrow {
1923 		mixin(CHNL_UPDATE_CONSTS);
1924 		mixin(CHNL_UPDATE_CONSTS0);
1925 		for (size_t i ; i < length ; i++) {
1926 			mixin(CHNL_UPDATE_CONSTS_CYCL);
1927 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
1928 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
1929 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
1930 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
1931 			//operators[opOffset].input = operators[opOffset + 17].output_0;
1932 			updateOperator(operators[opOffset], opCtrl0);		//P0
1933 			//operators[opOffset + 1].input = operators[opOffset].output_0;
1934 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
1935 			//const int outSum = operators[opOffset + 1].output_0;
1936 			__m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset].output_0 +
1937 					operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0 + 
1938 					((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].preset.rmAmount)>>16);
1939 			mixin(CHNL_UPDATE_MIX);
1940 			channels[chNum].eeg.advance();
1941 			channels[chNum + 8].eeg.advance();
1942 		}
1943 	}
1944 
1945 	/**
1946 	 * Restores a parameter to the given preset.
1947 	 * Returns an errorcode on failure.
1948 	 */
1949 	public override int recallParam_int(uint presetID, uint paramID, int value) @nogc nothrow {
1950 		return 0;
1951 	}
1952 	/**
1953 	 * Restores a parameter to the given preset.
1954 	 * Returns an errorcode on failure.
1955 	 */
1956 	public override int recallParam_uint(uint presetID, uint paramID, uint value) @nogc nothrow {
1957 		return 0;
1958 	}
1959 	/**
1960 	 * Restores a parameter to the given preset.
1961 	 * Returns an errorcode on failure.
1962 	 */
1963 	public override int recallParam_double(uint presetID, uint paramID, double value) @nogc nothrow {
1964 		return 0;
1965 	}
1966 	/**
1967 	 * Restores a parameter to the given preset.
1968 	 * Returns an errorcode on failure.
1969 	 */
1970 	public override int recallParam_string(uint presetID, uint paramID, string value) @nogc nothrow {
1971 		return 0;
1972 	}
1973 }