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 import pixelperfectengine.audio.base.filter;
7 
8 import pixelperfectengine.system.etc : hashCalc;
9 
10 import midi2.types.structs;
11 import midi2.types.enums;
12 
13 import inteli.emmintrin;
14 
15 import bitleveld.reinterpret;
16 
17 import std.math;
18 
19 /**
20 QM816 - implements a Quadrature-Amplitude synthesizer. This technique was used in early 
21 digital FM synths, since it allowed allowed a cheap implementation of the same thing as
22 long as the modulator was a sinusoidal waveform.
23 
24 It has 16 2 operator channels that can be individually paired-up for 4 operator channels,
25 for more complex sounds. Also all operators have the option for feedback, including 
26 carriers. 2 operator channels have 2, 4 operator channels have 3*4 algorithms.
27 
28 The audio module generates a few default waveforms upon startup, but further ones can be
29 supplied from files, or generated by code. Some waveform generation code is already
30 supplied with the synth's code.
31 
32 To do:
33 * Implement glissando/legato support.
34 * Maybe replace the interpolation filter later on.
35 */
36 public class QM816 : AudioModule {
37 	shared static this() {
38 		
39 		for (int i ; i < 128 ; i++) {
40 			ADSR_TIME_TABLE[i] = pow(i / 64.0, 1.8);
41 		}
42 	}
43 	/**
44 	Generates a waveform from a sinewave fragment (quarter).
45 
46 	q flags:
47 	bit 0 = If set, then the sine fragment is present. If not, this portion will be replaced with all zeros instead.
48 	bit 1-2 = Doubling mode:
49 		0 = No doubling.
50 		1 = Same cycle twice.
51 		2 = Same cycle mirrored, effectively putting a half-sine into a quarter with the right settings.
52 		3 = The second half is all zeros, the sine fragment is effectively "stuffed" into an eight of the waveform.
53 	bit 3 = Horizontal mirroring of the cycle.
54 	bit 4 = Vertical mirroring of the cycle.
55 	bit 5 = Modifies the curve of the sinewave for a bit more square-ish shape.
56 	*/
57 	public static short[1024] generateSinewave(ubyte[4] q) @nogc @safe pure nothrow {
58 		short sineWave(int i, bool shape) @nogc @safe pure nothrow {
59 			real val = sin((PI_2 / 256) * i);
60 			if (shape) {
61 				if (val > 0) return cast(short)(sqrt(val) * short.max);
62 				else if (val < 0) return cast(short)(sqrt(val * -1) * short.max * -1);
63 				else return 0;
64 			} else return cast(short)(val * short.max);
65 		}
66 		short[1024] result;
67 		for (int j ; j < 4 ; j++) {
68 			if (q[j] & 1) {
69 				const int offset = 256 * j;
70 				const int hMir = q[j] & 0x8 ? 256 : 0;
71 				//int hBegin = q[j] & 0x8 ? 255 : 0;
72 				//const int vOffset = q[j] & 0x10 ? -1 : 0;
73 				const int vMir = q[j] & 0x10 ? 512 : 0;
74 				const bool shape = q[j] & 0x20 ? true : false;
75 				//const short[256] fragment = SINEWAVE_FRAGMENT;
76 				switch (q[j]>>1 & 3) {
77 					case 1:
78 						for (int i ; i < 256 ; i++) {
79 							result[offset + i] = sineWave(((i * 2) & 255) + hMir + vMir, shape);
80 						}
81 						break;
82 					case 2:
83 						for (int i ; i < 128 ; i++) {
84 							result[offset + i] = sineWave(((i * 2) & 255) + hMir + vMir, shape);
85 						}
86 						for (int i ; i < 128 ; i++) {
87 							result[offset + i + 128] = sineWave((((127 - i) * 2) & 255) + hMir + vMir, shape);
88 						}
89 						break;
90 					case 3:
91 						for (int i ; i < 128 ; i++) {
92 							result[offset + i] = sineWave(((i * 2) & 255) + hMir + vMir, shape);
93 						}
94 						break;
95 					default:
96 						for (int i ; i < 256 ; i++) {
97 							result[offset + i] = sineWave(i + hMir + vMir, shape);
98 						}
99 						break;
100 				}
101 				/+const int offset = 256 * j;
102 				int hMir = q[j] & 0x8 ? -1 : 1;
103 				int hBegin = q[j] & 0x8 ? 255 : 0;
104 				const int vOffset = q[j] & 0x10 ? -1 : 0;
105 				const int vMir = q[j] & 0x10 ? -1 : 1;
106 				const short[256] fragment = SINEWAVE_FRAGMENT;
107 				switch (q[j]>>1 & 3) {
108 					case 1:
109 						hMir *= 2;
110 						for (int i ; i < 256 ; i++) {
111 							result[offset + i] = cast(short)(fragment[(hBegin + hMir * i) & 255] * vMir + vOffset);
112 						}
113 						break;
114 					case 2:
115 						hMir *= 2;
116 						for (int i ; i < 128 ; i++) {
117 							result[offset + i] = cast(short)(fragment[(hBegin + hMir * i) & 255] * vMir + vOffset);
118 						}
119 						hMir *= -1;
120 						hBegin = q[j] & 0x8 ? 0 : 255;
121 						for (int i ; i < 128 ; i++) {
122 							result[offset + i + 128] = cast(short)(fragment[(hBegin + hMir * i) & 255] * vMir + vOffset);
123 						}
124 						break;
125 					case 3:
126 						hMir *= 2;
127 						for (int i ; i < 128 ; i++) {
128 							result[offset + i] = cast(short)(fragment[(hBegin + hMir * i) & 255] * vMir + vOffset);
129 						}
130 						break;
131 					default:
132 						for (int i ; i < 256 ; i++) {
133 							result[offset + i] = cast(short)(fragment[hBegin + hMir * i] * vMir + vOffset);
134 						}
135 						break;
136 				}+/
137 			}
138 		}
139 		return result;
140 	}	
141 	/**
142 	Generates a pulse wave.
143 
144 	`width` controls the pulse width.
145 	*/
146 	public static short[1024] generatePulseWave(int width = 512) @nogc @safe pure nothrow {
147 		short[1024] result;
148 		for (int i ; i < 1024 ; i++) {
149 			result[i] = i < width ? short.max : short.min;
150 		}
151 		return result;
152 	}
153 	/**
154 	Generates a triangular waveform.
155 	`shape` controls the shape of the triangular waveform, allowing it to be morphed between triangle, saw, and ramp.
156 	``
157 	*/
158 	public static short[1024] generateTriangularWave(int shape = 512) @nogc @safe pure nothrow {
159 		import pixelperfectengine.system.etc : clamp;
160 		short[1024] result;
161 		int state;
162 		const int upwardSlope = ushort.max / shape;
163 		const int downwardSlope = ushort.max / (1024 - shape);
164 		for (int i ; i < shape / 2 ; i++) {
165 			state += upwardSlope;
166 			clamp(state, short.min, short.max);
167 			result[i] = cast(short)state;
168 		}
169 		for (int i = shape / 2 ; i < (shape / 2) + (1024 - shape) ; i++) {
170 			state -= downwardSlope;
171 			clamp(state, short.min, short.max);
172 			result[i] = cast(short)state;
173 		}
174 		for (int i = (shape / 2) + (1024 - shape) ; i < 1024 ; i++) {
175 			state += upwardSlope;
176 			clamp(state, short.min, short.max);
177 			result[i] = cast(short)state;
178 		}
179 		return result;
180 	}
181 	public static short[1024] integrateTriangularWave(short[1024] input) @nogc @safe pure nothrow {
182 		import pixelperfectengine.system.etc : clamp;
183 		short[1024] result;
184 		for (int i ; i < input.length ; i++) {
185 			result[i] = cast(short)((input[i] * input[i] * (input[i] < 0 ? -1 : 1))>>15);
186 		}
187 		return result;
188 	}
189 	/** 
190 	Contains a table to calculate Attack, Decay, and Release values.
191 
192 	All values are seconds with factions. Actual values are live-calculated depending on sustain-level and sampling
193 	frequency.
194 
195 	Current formula for the ADSR time table:
196 
197 	yn = (x/64)^1.8
198 	*/
199 	public static immutable float[128] ADSR_TIME_TABLE;
200 	/**
201 	Contains a table to calculate Sustain control values.
202 
203 	All values are seconds with fractions. Actual values are live-calculated depending on sustain level and sampling
204 	frequency. Please note that with certain levels of sustain, the actual max time might be altered.
205 	*/
206 	public static immutable float[63] SUSTAIN_CONTROL_TIME_TABLE = [
207 	//	0     |1     |2     |3     |4     |5     |6     |7     |8     |9     |A     |B     |C     |D     |E     |F
208 		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
209 		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
210 		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
211 		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
212 	];
213 	/**
214 	Used for quick resampling of the 55.125/60kHz output to 44.1/48kHz, based on Cubic Lagrange interpolation.
215 
216 	So far this has the best results.
217 	*/
218 	public static immutable float[4][4] RESAMPLING_TABLE = [
219 		[ 0.0,         1.0,         0.0,         0.0],
220 		[-0.0546_875,  0.8203_125,  0.2734_375, -0.0390_625],
221 		[-0.0625    ,  0.5625    ,  0.5625    , -0.0625    ],
222 		[-0.0390_625,  0.2734_375,  0.8203_125, -0.0546_875]
223 	];
224 	/**
225 	Defines operator parameter numbers, within the unregistered namespace.
226 	*/
227 	public enum OperatorParamNums {
228 		//Unregistered
229 		Level		=	0,
230 		Attack		=	1,
231 		Decay		=	2,
232 		SusLevel	=	3,
233 		SusCtrl		=	4,
234 		Release		=	5,
235 		Waveform	=	6,
236 		Feedback	=	7,
237 		TuneCor		=	8,
238 		TuneFine	=	9,
239 		ShpA		=	10,
240 		ShpR		=	11,
241 		VelToLevel	=	12,
242 		MWToLevel	=	13,
243 		LFOToLevel	=	14,
244 		OpCtrl		=	15,
245 		VelToFB		=	16,
246 		MWToFB		=	17,
247 		LFOToFB		=	18,
248 		EEGToFB		=	19,
249 		VelToShpA	=	20,
250 		VelToShpR	=	21,
251 		KSLBegin	=	22,
252 		KSLAttenOut	=	23,
253 		KSLAttenFB	=	24,
254 		KSLAttenADSR=	25,
255 	}
256 	/**
257 	Defines channel parameter numbers, within the unregistered namespace.
258 	*/
259 	public enum ChannelParamNums {
260 		MasterVol	=	0,
261 		Bal			=	1,
262 		AuxSLA		=	2,
263 		AuxSLB		=	3,
264 		EEGDetune	=	4,
265 		PLFO		=	5,
266 		Attack		=	6,
267 		Decay		=	7,
268 		SusLevel	=	8,
269 		SusCtrl		=	9,
270 		Release		=	10,
271 		ShpA		=	11,
272 		ShpR		=	12,
273 		GlobalFB	=	13,
274 		ChCtrl		=	16,
275 		EEGToLeft	=	18,
276 		EEGToRight	=	19,
277 		EEGToAuxA	=	20,
278 		EEGToAuxB	=	21,
279 		LFOToLeft	=	22,
280 		LFOToRight	=	23,
281 		LFOToAuxA	=	24,
282 		LFOToAuxB	=	25,
283 		MWToGFB		=	26,
284 		VelToGFB	=	27,
285 	}
286 	/**
287 	Defines channel parameters within the registered namespace
288 	*/
289 	public enum ChannelRegParams {
290 		PitchBendSens,
291 		TuneCor,
292 		TuneFine,
293 	}
294 	/**
295 	Defines global parameter nummbers, within the unregistered namespace
296 	*/
297 	public enum GlobalParamNums {
298 		PLFORate	=	0,
299 		PLFOWF		=	1,
300 		ALFORate	=	2,
301 		ALFOWF		=	3,
302 		FilterLCFreq=	4,
303 		FilterLCQ	=	5,
304 		FilterRCFreq=	6,
305 		FilterRCQ	=	7,
306 		FilterACFreq=	8,
307 		FilterACQ	=	9,
308 		FilterBCFreq=	10,
309 		FilterBCQ	=	11,
310 		HPFLCFreq	=	12,
311 		HPFLCQ		=	13,
312 		HPFRCFreq	=	14,
313 		HPFRCQ		=	15,
314 		HPFACFreq	=	16,
315 		HPFACQ		=	17,
316 		HPFBCFreq	=	18,
317 		HPFBCQ		=	19,
318 		RingMod		=	20,
319 	}
320 	enum TuneCtrlFlags : uint {
321 		FineTuneMidPoint	=	0x1_00_00_00,
322 		CorTuneMidPoint		=	36<<25,
323 		FineTuneTest		=	0x1_FF_FF_FF,
324 		CorTuneTest			=	0xFE_00_00_00,
325 	}
326 	///Defines control values
327 	enum OpCtrlFlags {
328 		WavetableSelect	=	127,		///Wavetable select flags
329 		FBMode			=	1 << 7,		///Feedback mode (L: After Envelop Generator, H: Before Envelop Generator)
330 		FBNeg			=	1 << 8,		///Feedback mode (L: Positive, H: Negative)
331 		MWNeg			=	1 << 9,		///Invert modulation wheel control
332 		VelNeg			=	1 << 10,	///Invert velocity control
333 		EGRelAdaptive	=	1 << 11,	///Adaptive release time based on current output level
334 		FixedPitch		=	1 << 12,	///Enables fixed pitch mode
335 		EasyTune		=	1 << 13,	///Enables easy tune mode
336 		ContiTune		=	1 << 14,	///Enables continuous tuning through the coarsetune parameter
337 		ExprToMW		=	1 << 15,	///Switches modwheel to auxilliary control on this operator
338 	}
339 	/**
340 	Implements a single operator.
341 	
342 	Contains an oscillator, an ADSR envelop generator, and locals.
343 	*/
344 	public struct Operator {
345 		///Local copy of operator preset data.
346 		Preset.Op		preset;
347 		///The envelop generator of the operator.
348 		ADSREnvelopGenerator	eg;
349 		///The current position of the oscillator, including fractions.
350 		uint			pos;	
351 		///The amount the oscillator must be stepped forward each cycle, including fractions.
352 		uint			step;	
353 		///Input register.
354 		///The amount which the oscillator will be offsetted.
355 		int				input;
356 		///Feedback register. Either out_0[n-1] or out[n-1] multiplied by feedback amount.
357 		///The amount which the oscillator will be offsetted.
358 		///Negative if inverted.
359 		int				feedback;
360 		///Output register.
361 		///Not affected by either level or EG
362 		///Might be used for ring modulation.
363 		int				output;
364 		///Output affected by EEG and level.
365 		///Either used for audible output, or to modulate other operators
366 		int				output_0;
367 		///Calculated output level containing KSL damping
368 		float			outL	=	0;
369 		///Calculated feedback level containing KSL damping
370 		float			fbL		=	0;
371 		///Live calculated out of shpA
372 		float			shpA0	=	0.0;
373 		///Live calculated out of shpR
374 		float			shpR0	=	0.0;
375 
376 		///Sets the frequency of the operator
377 		///Also calculates KSL levels
378 		void setFrequency(int slmpFreq, ubyte note, double pitchBend, double tuning) @nogc @safe pure nothrow {
379 			double actualNote, oscFreq;
380 			const int tuneAm = preset.opCtrl>>>25;//const int tuneAm = (preset.opCtrl>>>25) - 36;
381 			if (preset.opCtrl & OpCtrlFlags.EasyTune) {
382 				double ratio;
383 				switch (tuneAm) {
384 					case 0:
385 						ratio = 1.0/8;
386 						break;
387 					case 1: .. case 5:
388 						ratio = 1.0/6;
389 						break;
390 					case 6: .. case 8:
391 						ratio = 1.0/5;
392 						break;
393 					case 9: .. case 12:
394 						ratio = 1.0/4;
395 						break;
396 					case 13: .. case 18:
397 						ratio = 1.0/3;
398 						break;
399 					case 19: .. case 24:
400 						ratio = 1.0/2;
401 						break;
402 					case 25: .. case 42:
403 						ratio = 1;
404 						break;
405 					case 43: .. case 47:
406 						ratio = 1.5;
407 						break;
408 					case 48: .. case 54:
409 						ratio = 2;
410 						break;
411 					case 55: .. case 59:
412 						ratio = 3;
413 						break;
414 					case 60: .. case 63:
415 						ratio = 4;
416 						break;
417 					case 64: .. case 66:
418 						ratio = 5;
419 						break;
420 					case 67: .. case 69:
421 						ratio = 6;
422 						break;
423 					case 70, 71:
424 						ratio = 7;
425 						break;
426 					case 72, 73:
427 						ratio = 8;
428 						break;
429 					case 74, 75:
430 						ratio = 9;
431 						break;
432 					case 76, 77:
433 						ratio = 10;
434 						break;
435 					case 78:
436 						ratio = 11;
437 						break;
438 					case 79, 80:
439 						ratio = 12;
440 						break;
441 					case 81:
442 						ratio = 13;
443 						break;
444 					case 82:
445 						ratio = 14;
446 						break;
447 					case 83:
448 						ratio = 15;
449 						break;
450 					default:
451 						ratio = 16;
452 						break;
453 				}
454 				oscFreq = noteToFreq(note + pitchBend, tuning) * ratio;
455 			} else if (preset.opCtrl & OpCtrlFlags.ContiTune) {
456 				if (preset.opCtrl & OpCtrlFlags.FixedPitch) {
457 					actualNote = preset.tune;
458 				} else {
459 					actualNote = note + pitchBend + preset.tune;
460 				}
461 				oscFreq = noteToFreq(actualNote, tuning);
462 			} else {
463 				const double tuneOffset = tuneAm + preset.tune;
464 				if (!(preset.opCtrl & OpCtrlFlags.FixedPitch)) {
465 					actualNote = note + pitchBend + tuneOffset;
466 				}
467 				oscFreq = noteToFreq(actualNote, tuning);
468 			}
469 			calculateKSL(note);
470 			const double cycLen = oscFreq / ((slmpFreq - 1) / 1024.0);
471 			//step = cast(uint)(cast(double)(1<<21) * cycLen);
472 			step = cast(uint)(cast(double)(1<<22) * cycLen);
473 		}
474 		///Calculates KSL values
475 		void calculateKSL(ubyte note) @nogc @safe pure nothrow {
476 			if (!(preset.opCtrl & OpCtrlFlags.FixedPitch) && preset.kslBegin < note) {
477 				const double octaves = (note - preset.kslBegin) / 12.0;
478 				outL = preset.outL * (1.0 - (octaves * ((preset.kslAttenOut / ubyte.max) * 0.75)));
479 				fbL = (preset.opCtrl & OpCtrlFlags.FBNeg ? -1 : 1) * 
480 						preset.fbL * (1.0 - (octaves * ((preset.kslAttenFB / ubyte.max) * 0.75)));
481 			} else {
482 				outL = preset.outL;
483 				fbL = (preset.opCtrl & OpCtrlFlags.FBNeg ? -1 : 1) * preset.fbL;
484 			}
485 		}
486 		///Sets the Envelop generator
487 		void setEG(int sampleRate, ubyte note, float vel = 1.0) @nogc @safe pure nothrow {
488 			const double timeAmount = (!(preset.opCtrl & OpCtrlFlags.FixedPitch) && preset.kslBegin < note) ?
489 					1 - ((note - preset.kslBegin) * (0.1 * (preset.kslAttenADSR / 255))) : 1;
490 			eg.sustainLevel = preset.susLevel;
491 			//Set attack phase
492 			if (preset.atk) {
493 				eg.attackRate = calculateRate(ADSR_TIME_TABLE[preset.atk] * timeAmount, sampleRate);
494 			} else {
495 				eg.attackRate = 1.0;
496 			}
497 			//Set decay phase
498 			if (preset.dec) {
499 				eg.decayRate = calculateRate(ADSR_TIME_TABLE[preset.dec] * 2 * timeAmount, sampleRate, 
500 						ADSREnvelopGenerator.maxOutput, eg.sustainLevel);
501 			} else {
502 				eg.decayRate = 1.0;
503 			}
504 			//Set sustain phase
505 			if (preset.susCC) {
506 				eg.isPercussive = false;
507 				if (preset.susCC == 64) {
508 					eg.sustainControl = 0.0;
509 				} else if (preset.susCC < 64) {
510 					eg.sustainControl =  
511 							calculateRate(SUSTAIN_CONTROL_TIME_TABLE[62 - (preset.susCC - 1)], sampleRate);
512 				} else {
513 					eg.sustainControl = -1.0 *
514 							calculateRate(SUSTAIN_CONTROL_TIME_TABLE[preset.susCC - 65], sampleRate);
515 				}
516 			} else {
517 				eg.isPercussive = true;
518 				eg.sustainControl = 0.0;
519 			}
520 			//Set release phase
521 			if (preset.rel) {
522 				eg.releaseRate = calculateRate(ADSR_TIME_TABLE[preset.rel] * 2, sampleRate, eg.sustainLevel);
523 			} else {
524 				eg.releaseRate = 1.0;
525 			}
526 			setShpVals(vel);
527 		}
528 		///Recalculates shape params.
529 		void setShpVals(float vel = 1.0) @nogc @safe pure nothrow {
530 			shpA0 = preset.shpA - (preset.shpA * preset.shpAVel) + (preset.shpA * preset.shpAVel * vel);
531 			shpR0 = preset.shpR - (preset.shpR * preset.shpRVel) + (preset.shpR * preset.shpRVel * vel);
532 		}
533 		///Sets the key to off on this channel. Also calculates adaptive release rates if needed.
534 		void keyOff(int sampleRate) @nogc @safe pure nothrow {
535 			eg.keyOff();
536 			if (preset.rel && (preset.opCtrl & OpCtrlFlags.EGRelAdaptive)) {
537 				eg.releaseRate = calculateRate(ADSR_TIME_TABLE[preset.rel] * 2, sampleRate, eg.sustainLevel);
538 			}
539 		}
540 	}
541 	///Defines channel control flags.
542 	enum ChCtrlFlags {
543 		///Channel combination turned off, the channel pair is independent
544 		ComboModeOff	=	0b0000,	
545 		///Channel combination mode 1: Secondary channel's output is fed into primary operator 0.
546 		ComboMode1		=	0b0001,
547 		///Channel combination mode 2: Secondary channel's output is fed into primary operator 1 if primary 
548 		///is in serial mode, or into both if primary is in parallel mode.
549 		ComboMode2		=	0b0010,
550 		///Channel combination mode 3: Secondary channel's output is fed into main output, except if primary 
551 		///channel set to parallel and secondary set to serial, then S1, P0, and P1 are connected to output, while
552 		///S0 is modulating all of them.
553 		ComboMode3		=	0b0011,
554 		///Used for testing combo mode.
555 		ComboModeTest	=	ComboMode3,
556 		Algorithm		=	1<<2,	///Channel algorithm (H: Parallel, L: Series)
557 		IndivOutChLev	=	1<<3,	///Enables the setting of individual output channel levels
558 		LFOPan			=	1<<4,	///Enables LFO Panning
559 		EEGPan			=	1<<5,	///Enables EEG Panning
560 		MWToTrem		=	1<<6,	///Assigns modwheel to amplitude LFO
561 		MWToVibr		=	1<<7,	///Assigns modwheel to pitch LFO
562 		MWToAux			=	1<<8,	///Assigns modwheel to aux levels
563 		ResetOnKeyOn	=	1<<9,	///Resets all operators and envelops belonging to this channel on key on event
564 		ResetMode		=	1<<10,	///If set, then reset only occurs of all envelops have reached `Off` state after a keyOff event
565 		FBMode			=	1<<11,	///Feedback mode (L: After Envelop Generator, H: Before Envelop Generator)
566 		FBNeg			=	1<<12,	///Feedback mode (L: Positive, H: Negative)
567 		ResMode			=	1<<13,	///Enables resonant mode if available for the given algorithm
568 		ResSrc			=	1<<14,	///Selects the source for the resonance if available for the given algorithm
569 	}
570 	/**
571 	Defines channel common parameters.
572 	*/
573 	public struct Channel {
574 		///Copy of channel relevant preset data
575 		Preset.Ch		preset;
576 		///Extra envelop generator that can be assigned for multiple purpose.
577 		ADSREnvelopGenerator	eeg;
578 		///Calculated output level controls + aux send levels
579 		///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B
580 		__m128			outLevels;
581 		///Sets the Extra Envelop generator
582 		void setEEG(int sampleRate) @nogc @safe pure nothrow {
583 			//Set attack phase
584 			if (preset.atkX) {
585 				eeg.attackRate = calculateRate(ADSR_TIME_TABLE[preset.atkX], sampleRate);
586 			} else {
587 				eeg.attackRate = 1.0;
588 			}
589 			//Set decay phase
590 			if (preset.decX) {
591 				eeg.decayRate = calculateRate(ADSR_TIME_TABLE[preset.decX] * 2, sampleRate, ADSREnvelopGenerator.maxOutput, 
592 						eeg.sustainLevel);
593 			} else {
594 				eeg.decayRate = 1.0;
595 			}
596 			//Set sustain phase
597 			if (preset.susCCX) {
598 				eeg.isPercussive = false;
599 				if (preset.susCCX == 64) {
600 					eeg.sustainControl = 0.0;
601 				} else if (preset.susCCX < 64) {
602 					eeg.sustainControl =  
603 							calculateRate(SUSTAIN_CONTROL_TIME_TABLE[62 - (preset.susCCX - 1)], sampleRate);
604 				} else {
605 					eeg.sustainControl = -1.0 *
606 							calculateRate(SUSTAIN_CONTROL_TIME_TABLE[preset.susCCX - 64], sampleRate);
607 				}
608 			} else {
609 				eeg.isPercussive = true;
610 				eeg.sustainControl = 0.0;
611 			}
612 			//Set release phase
613 			if (preset.relX) {
614 				eeg.releaseRate = calculateRate(ADSR_TIME_TABLE[preset.relX] * 2, sampleRate, eeg.sustainLevel);
615 			} else {
616 				eeg.releaseRate = 1.0;
617 			}
618 		}
619 		/** 
620 		 * Recalculates the output levels for the channel.
621 		 */
622 		void recalculateOutLevels() @nogc @safe pure nothrow {
623 			if (preset.chCtrl == ChCtrlFlags.IndivOutChLev) {
624 				outLevels[0] = preset.masterVol;
625 				outLevels[1] = preset.masterBal;
626 			} else {
627 				outLevels[0] = preset.masterVol * preset.masterBal;
628 				outLevels[1] = preset.masterVol * (1 - preset.masterBal);
629 			}
630 			outLevels[2] = preset.auxSendA;
631 			outLevels[3] = preset.auxSendB;
632 		}
633 	}
634 	/**
635 	Stores channel controller values (modwheel, velocity, etc.)
636 	*/
637 	public struct ChControllers {
638 		///Modulation wheel parameter, normalized between 0.0 and 1.0
639 		float			modwheel	=	0;
640 		///Auxilliary controller parameter, normalized between 0.0 and 1.0
641 		float			auxCtrl		=	0;
642 		///Velocity parameter, normalized between 0.0 and 1.0
643 		float			velocity	=	0;
644 		///Pitch bend parameter, with the amount of pitch shifting in semitones + fractions
645 		float			pitchBend	=	0;
646 		///The note that is currently being played
647 		ubyte			note;
648 	}
649 	/**
650 	Defines a preset.
651 	*/
652 	public struct Preset {
653 		///Defines parameters of a single operator
654 		public struct Op {
655 			/+ ///Operator tuning
656 			///Bit 31-25: Coarse detuning (-36 to +91 seminotes)
657 			///Bit 24-0: Fine detuning (-100 to 100 cents), 0x1_00_00_00 is center
658 			///If fixed mode is being used, then top 7 bits are the note, the rest are fine tuning.
659 			uint			tune	=	TuneCtrlFlags.CorTuneMidPoint | TuneCtrlFlags.FineTuneMidPoint;+/
660 			///Sets the fine detuning or the whole tuning of the operator depending on tuning mode.
661 			float			tune	=	0.0;
662 			///Output level (between 0.0 and 1.0)
663 			float			outL	=	0.50;
664 			///Feedback level (between 0.0 and 1.0)
665 			float			fbL		=	0.0;
666 			///Control flags and Wavetable selector
667 			uint			opCtrl = OpCtrlFlags.EasyTune | TuneCtrlFlags.CorTuneMidPoint;
668 			///Output level controller assignment
669 			///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: unused
670 			__m128			outLCtrl=	[0,0,0,0];
671 			///Feedback level controller assignment
672 			///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: Extra envelop generator
673 			__m128			fbLCtrl	=	[0,0,0,0];
674 			///Attack time control (between 0 and 127)
675 			ubyte			atk;
676 			///Decay time control (between 0 and 127)
677 			ubyte			dec;
678 			///Release time control (between 0 and 127)
679 			ubyte			rel = 1;
680 			///Sustain curve control (between 0 and 127)
681 			///0: Percussive mode
682 			///1 - 63: Descending over time
683 			///64: Constant
684 			///65 - 127: Ascending over time
685 			ubyte			susCC = 64;
686 			///Sustain level for the EG
687 			float			susLevel=	1.0;
688 			///ADSR shaping parameter (for the attack phase)
689 			float			shpA	=	0.5;
690 			///ADSR shaping parameter (for the decay/release phase)
691 			float			shpR	=	0.5;
692 			///Assigns velocity to shpA
693 			float			shpAVel	=	0.0;
694 			///Assigns velocity to shpR
695 			float			shpRVel =	0.0;
696 			///Key Scale Level beginning point
697 			ubyte			kslBegin = ubyte.max;
698 			///Key Scale Level attenuation amount for output (0 = 0.0db/Oct ; 255 = 6.0db/Oct)
699 			ubyte			kslAttenOut;
700 			///Key Scale Level attenuation amount for feedback (0 = 0.0db/Oct ; 255 = 6.0db/Oct)
701 			ubyte			kslAttenFB;
702 			///Key Scale Level attenuation amount for attack/decay times (0 = 0%/Oct ; 255 = 10%/Oct)
703 			ubyte			kslAttenADSR;
704 		}
705 		///Defines parameters of a single channel.
706 		public struct Ch {
707 			///ADSR shaping parameter (for the attack phase)
708 			float			shpAX	=	0.5;
709 			///ADSR shaping parameter (for the decay/release phase)
710 			float			shpRX	=	0.5;
711 			///Pitch amount for EEG
712 			float			eegDetuneAm	=	0;
713 			///Pitch bend sensitivity
714 			///Up to +/-2 octaves
715 			float			pitchBendSens = 2;
716 			///A-4 channel tuning in hertz.
717 			float			chnlTun = 440.0;
718 			///Stores channel control flags.
719 			uint			chCtrl = ChCtrlFlags.ResetMode;
720 			///Master volume (0.0 to 1.0)
721 			float			masterVol=	1;
722 			///Master balance (0.0 to 1.0)
723 			float			masterBal=	0.5;//
724 			///Aux send A
725 			float			auxSendA=	0;
726 			///Aux send B
727 			float			auxSendB=	0;
728 			///Modwheel to global feedback
729 			float			mwToGFB	=	0;
730 			///Velocity to global feedback
731 			float			velToGFB=	0;//
732 			///EEG assign levels
733 			///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B
734 			__m128			eegLevels=	[0,0,0,0];
735 			///Amplitude LFO assign levels
736 			///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B
737 			__m128			aLFOlevels=	[0,0,0,0];
738 			///Global feedback
739 			///Only available on certain algorithms
740 			float			globalFb	=	0;
741 			///Pitch LFO level
742 			float			pLFOlevel	=	0;
743 			///Amplitude LFO to 
744 			///Attack time control (between 0 and 127)
745 			ubyte			atkX;
746 			///Decay time control (between 0 and 127)
747 			ubyte			decX;
748 			///Release time control (between 0 and 127)
749 			ubyte			relX;
750 			///Sustain curve control (between 0 and 127)
751 			///0: Percussive mode
752 			///1 - 63: Descending over time
753 			///64: Constant
754 			///65 - 127: Ascending over time
755 			ubyte			susCCX	=	64;
756 			///Sustain level
757 			float			susLevel	=	1;
758 		}
759 		Op[2]			operators;		///The operators belonging to this channel
760 		Ch				channel;		///Channel common values
761 	}
762 	///Contains the wavetables for the operators and LFOs.
763 	///Loaded from a 16 bit wave file.
764 	///Full range is used for extra precision.
765 	protected short[1024][128]	wavetables;
766 	///Stores presets.
767 	///8 banks of 128 presets are available for a total of 1024.
768 	///If a channel combination is being used, then bank pairs (0-1, 2-3, etc) will store their primary and secondary
769 	///halves, and calling either will load both halves.
770 	protected Preset[128][8]	soundBank;
771 	///Operator data.
772 	///See rendering function on updating.
773 	protected Operator[32]		operators;
774 	///Channel data.
775 	///See rendering function on updating.
776 	protected Channel[16]		channels;
777 	///Channel control data.
778 	protected ChControllers[16]	chCtrls;
779 	///Preset numbers per channels.
780 	protected ubyte[16]			presetNum;
781 	///Bank numbers per channels.
782 	protected ubyte[16]			bankNum;
783 	///Keeps the registered/unregistered parameter positions (LSB = 1).
784 	//protected ubyte[2]			paramNum;
785 	///Stores LFO waveform selection. 0: Pitch; 1: Amplitude/Ringmod (if bit 7 is set)
786 	protected ubyte[2]			lfoWaveform;
787 	///Stores temporary parameter values 
788 	///0: MSB of sel unregistered param 1: LSB of sel unregistered param 
789 	///2: MSB of sel registered param 3: LSB of sel registered param
790 	protected ubyte[4]			paramTemp;
791 	///Stores ALFO position
792 	protected uint				aLFOPos;
793 	///Stores ALFO rate
794 	protected uint				aLFORate;
795 	///ALFO filter y[n-1]
796 	//protected float				aLFO_y1;
797 	///ALFO filter factor 0 to 1
798 	//protected float				aLFOff	=	1;
799 	///ALFO frequency
800 	protected float				aLFOFreq = 6;
801 	///Low pass filter, before interpolation filter.
802 	protected IIRBank			lpf;
803 	///High pass filter, after interpolation filter.
804 	protected IIRBank			hpf;
805 	///Stores control values of the output values.
806 	///Layout: [LF, LQ, RF, RQ, AF, AQ, BF, BQ]
807 	protected float[8]			filterCtrl	=	[16_000, 0.707, 16_000, 0.707, 16_000, 0.707, 16_000, 0.707];
808 	
809 	///Stores high-pass filter control values
810 	protected float[8]			hpfCtrl	=	[32, 0.707, 32, 0.707, 32, 0.707, 32, 0.707];
811 	///Initial mixing buffers
812 	///Output is directed there before filtering and resampling
813 	///Layout is: LRAB
814 	protected __m128[]			initBuffers;
815 	//protected __m128[]			resamplBuffers;
816 	///Dummy buffer
817 	///Only used if one or more outputs haven't been defined
818 	protected float[]			dummyBuf;
819 	///Amplitude LFO buffer. Values are between 0.0 and 1.0
820 	protected float[]			aLFOBuf;
821 	///Pitch LFO output. Values are between -1.0 and 1.0
822 	protected float				pLFOOut	=	0;
823 	///Stores PLFO position
824 	protected uint				pLFOPos;
825 	///Stores PLFO rate
826 	protected uint				pLFORate;
827 	///Current frequency of PLFO
828 	protected float				pLFOFreq = 6;
829 	///Mixdown value.
830 	///Used for final mixing.
831 	protected float				mixdownVal = short.max + 1;
832 	///Internal sampling frequency
833 	protected int				intSlmpRate;
834 	///Internal buffer sizes
835 	protected size_t			intBufSize;
836 	alias ChFun = void delegate(int chNum, size_t length) @nogc pure nothrow;
837 	///Channel update delegates
838 	protected ChFun[16]			chDeleg;
839 	///Used as a keepsake for MIDI 1.0 control change values.
840 	protected ubyte[64][16]		ccLow;
841 	protected ubyte[32]			sysExBuf;		///SysEx command buffer [0-30] + length [31]
842 	/**
843 	Creates an instance of QM816
844 	*/
845 	public this() @trusted nothrow {
846 		info.nOfAudioInput = 0;
847 		info.nOfAudioOutput = 4;
848 		info.outputChNames = ["mainL", "mainR", "auxSendA", "auxSendB"];
849 		info.isInstrument = true;
850 		info.hasMidiIn = true;
851 		info.hasMidiOut = true;
852 		info.midiSendback = true;
853 		try {
854 			WaveFormat f = WaveFormat(0, 0, AudioFormat.PCM, 1, 0, 16);
855 			short[1024] buffer = generateSinewave([0x01, 0x09, 0x11, 0x19]);
856 			waveformDataReceive(0, reinterpretCast!ubyte(buffer), f);		///Sine (from OPL2)
857 			buffer = generateSinewave([0x01, 0x09, 0x00, 0x00]);
858 			waveformDataReceive(1, reinterpretCast!ubyte(buffer), f);		///Half-sine (from OPL2)
859 			buffer = generateSinewave([0x01, 0x09, 0x01, 0x09]);
860 			waveformDataReceive(2, reinterpretCast!ubyte(buffer), f);		///Full-sine (from OPL2)
861 			buffer = generateSinewave([0x01, 0x00, 0x01, 0x00]);
862 			waveformDataReceive(3, reinterpretCast!ubyte(buffer), f);		///Pulse-sine (from OPL2)
863 			buffer = generateSinewave([0x01, 0x09, 0x11, 0x00]);
864 			waveformDataReceive(4, reinterpretCast!ubyte(buffer), f);		///Pulse-sine 75%
865 			buffer = generateSinewave([0x01, 0x00, 0x00, 0x00]);
866 			waveformDataReceive(5, reinterpretCast!ubyte(buffer), f);		///Pulse-sine 25%
867 			buffer = generateSinewave([0x01, 0x00, 0x11, 0x00]);
868 			waveformDataReceive(6, reinterpretCast!ubyte(buffer), f);		///Alternating pulse-sine
869 			buffer = generateSinewave([0x05, 0x15, 0x00, 0x00]);
870 			waveformDataReceive(7, reinterpretCast!ubyte(buffer), f);		///Alternating sine (from OPL3)
871 			buffer = generateSinewave([0x05, 0x05, 0x15, 0x15]);
872 			waveformDataReceive(8, reinterpretCast!ubyte(buffer), f);		///Camel sine (from OPL3)
873 			buffer = generateSinewave([0x01, 0x09, 0x11, 0x1f]);
874 			waveformDataReceive(9, reinterpretCast!ubyte(buffer), f);		///Variant sine 0
875 			buffer = generateSinewave([0x01, 0x09, 0x1d, 0x1d]);
876 			waveformDataReceive(10, reinterpretCast!ubyte(buffer), f);		///Variant sine 1
877 			buffer = generateSinewave([0x01, 0x09, 0x0d, 0x0d]);
878 			waveformDataReceive(11, reinterpretCast!ubyte(buffer), f);		///Variant sine 2
879 			buffer = generateSinewave([0x01, 0x09, 0x00, 0x1d]);
880 			waveformDataReceive(12, reinterpretCast!ubyte(buffer), f);		///Variant sine 3
881 			buffer = generateSinewave([0x01, 0x09, 0x1d, 0x00]);
882 			waveformDataReceive(13, reinterpretCast!ubyte(buffer), f);		///Variant sine 4
883 			buffer = generateSinewave([0x01, 0x09, 0x00, 0x0d]);
884 			waveformDataReceive(14, reinterpretCast!ubyte(buffer), f);		///Variant sine 5
885 			buffer = generateSinewave([0x01, 0x09, 0x0d, 0x00]);
886 			waveformDataReceive(15, reinterpretCast!ubyte(buffer), f);		///Variant sine 6
887 			buffer = generateSinewave([0x01, 0x0F, 0x17, 0x19]);
888 			waveformDataReceive(16, reinterpretCast!ubyte(buffer), f);		///Variant sine 7
889 			buffer = generatePulseWave(768);
890 			waveformDataReceive(17, reinterpretCast!ubyte(buffer), f);		///Pulse wave 75%
891 			buffer = generatePulseWave(512);
892 			waveformDataReceive(18, reinterpretCast!ubyte(buffer), f);		///Pulse wave 50%
893 			buffer = generatePulseWave(256);
894 			waveformDataReceive(19, reinterpretCast!ubyte(buffer), f);		///Pulse wave 25%
895 			buffer = generatePulseWave(128);
896 			waveformDataReceive(20, reinterpretCast!ubyte(buffer), f);		///Pulse wave 12.5%
897 			buffer = generatePulseWave(100);
898 			waveformDataReceive(21, reinterpretCast!ubyte(buffer), f);		///Pulse wave 10%
899 			buffer = generatePulseWave(50);
900 			waveformDataReceive(22, reinterpretCast!ubyte(buffer), f);		///Pulse wave 5%
901 			buffer = generateTriangularWave(1023);
902 			waveformDataReceive(23, reinterpretCast!ubyte(buffer), f);		///Ramp wave
903 			buffer = integrateTriangularWave(buffer);
904 			waveformDataReceive(28, reinterpretCast!ubyte(buffer), f);		///Integrated Ramp wave
905 			buffer = generateTriangularWave(768);
906 			waveformDataReceive(24, reinterpretCast!ubyte(buffer), f);		///Morphed ramp
907 			buffer = integrateTriangularWave(buffer);
908 			waveformDataReceive(29, reinterpretCast!ubyte(buffer), f);		///Integrated Morphed ramp
909 			buffer = generateTriangularWave(512);
910 			waveformDataReceive(25, reinterpretCast!ubyte(buffer), f);		///Triangle wave
911 			buffer = integrateTriangularWave(buffer);
912 			waveformDataReceive(30, reinterpretCast!ubyte(buffer), f);		///Integrated triangle wave
913 			buffer = generateTriangularWave(256);
914 			waveformDataReceive(26, reinterpretCast!ubyte(buffer), f);		///Morphed saw
915 			buffer = integrateTriangularWave(buffer);
916 			waveformDataReceive(31, reinterpretCast!ubyte(buffer), f);		///Integrated Morphed saw
917 			buffer = generateTriangularWave(2);
918 			waveformDataReceive(27, reinterpretCast!ubyte(buffer), f);		///Saw wave
919 			buffer = integrateTriangularWave(buffer);
920 			waveformDataReceive(32, reinterpretCast!ubyte(buffer), f);		///Integrated Saw wave
921 		} catch (Exception e) {
922 
923 		}
924 		//Reset delegates
925 		for (int i ; i < chDeleg.length ; i++) {
926 			chDeleg[i] = &updateChannelM00;
927 		}
928 	}
929 	/**
930 	 * Sets the module up.
931 	 *
932 	 * Can be overridden in child classes to allow resets.
933 	 */
934 	public override void moduleSetup(ubyte[] inputs, ubyte[] outputs, int sampleRate, size_t bufferSize, 
935 			ModuleManager handler) @safe nothrow {
936 		// void test() @trusted nothrow {
937 			// midiReceive(UMP(MessageType.MIDI2, 0x0, MIDI2_0Cmd.NoteOn, 0x0, 0x3f, 0x0));
938 		// }
939 		enabledInputs = StreamIDSet(inputs);
940 		enabledOutputs = StreamIDSet(outputs);
941 		this.sampleRate = sampleRate;
942 		this.bufferSize = bufferSize;
943 		this.handler = handler;
944 		//set up internal sample rate and buffer sizes
945 		intBufSize = bufferSize + (bufferSize / 4);
946 		intSlmpRate = sampleRate + (sampleRate / 4);
947 		//set up and reset buffers
948 		//initBuffers.length = intBufSize;
949 		initBuffers.length = intBufSize + 2;
950 		resetBuffer(initBuffers);
951 		dummyBuf.length = bufferSize;
952 		resetBuffer(dummyBuf);
953 		aLFOBuf.length = intBufSize;
954 		resetBuffer(aLFOBuf);
955 		//Reset filters
956 		lpf.reset();
957 		hpf.reset();
958 		setALFO();
959 		setPLFO();
960 		//Reset operator EGs
961 		for (int i ; i < operators.length ; i++) {
962 			operators[i].setEG(intSlmpRate, 40);
963 		}
964 		//Reset channel EGs
965 		for (int i ; i < channels.length ; i++) {
966 			channels[i].setEEG(intSlmpRate);
967 			channels[i].recalculateOutLevels();
968 		}
969 		//Set initial filter vals.
970 		for (int i ; i < 4 ; i++) {
971 			resetLPF(i);
972 			resetHPF(i);
973 		}
974 		//test();
975 	}
976 	/**
977 	Sets the given LPF with the given value.
978 	Params:
979 	* i = The ID of the LPF that needs to be set.
980 	*/
981 	protected void resetLPF(int i) @nogc @safe pure nothrow {
982 		BiquadFilterValues vals = createLPF(intSlmpRate, filterCtrl[i * 2], filterCtrl[(i * 2) + 1]);
983 		lpf.setFilter(vals, i);
984 		
985 	}
986 	/**
987 	Sets the given HPF with the given value.
988 	Params:
989 	* i = The ID of the HPF that needs to be set.
990 	*/
991 	protected void resetHPF(int i) @nogc @safe pure nothrow {
992 		BiquadFilterValues vals = createHPF(sampleRate, hpfCtrl[i * 2], hpfCtrl[(i * 2) + 1]);
993 		hpf.setFilter(vals, i);
994 	}
995 	/**
996 	 * Receives waveform data that has been loaded from disk for reading. Returns zero if successful, or a specific 
997 	 * errorcode.
998 	 *
999 	 * id: The ID of the waveform.
1000 	 * rawData: The data itself, in unprocessed form.
1001 	 * format: The format of the wave data, including the data type, bit depth, base sampling rate
1002 	 */
1003 	public override int waveformDataReceive(uint id, ubyte[] rawData, WaveFormat format) nothrow {
1004 		int errorcode;
1005 		if (format.channels != 1) errorcode |= SampleLoadErrorCode.ChNumNotSupported;
1006 		if (format.bitsPerSample != 16) errorcode |= SampleLoadErrorCode.BitdepthNotSupported;
1007 		if (format.format != AudioFormat.PCM) errorcode |= SampleLoadErrorCode.FormatNotSupported;
1008 		if (rawData.length != 128 * 1024 * 2 && rawData.length != 1024 * 2) 
1009 			errorcode |= SampleLoadErrorCode.SampleLenghtNotSupported;
1010 		if (errorcode) {
1011 			return errorcode;
1012 		} else {
1013 			import core.stdc.string : memcpy;
1014 			if (rawData.length == 128 * 1024 * 2)
1015 				memcpy(wavetables.ptr, rawData.ptr, 128 * 1024 * 2);
1016 			else
1017 				memcpy(wavetables[id].ptr, rawData.ptr, 1024 * 2);
1018 			return 0;
1019 		}
1020 	}
1021 	/** 
1022 	 * Returns the waveform data from the
1023 	 * Params:
1024 	 *   id = The ID of the waveform
1025 	 * Returns: The raw waveform data, or null on error (unsupported feature, waveform not found, etc.)
1026 	 */
1027 	public override const(ubyte)[] getWaveformData(uint id) nothrow {
1028 		if (id <= 127)
1029 			return cast(const(ubyte)[])wavetables[id];
1030 		else
1031 			return null;
1032 	}
1033 	/** 
1034 	 * Returns the format of the selected waveform
1035 	 * Params:
1036 	 *   id = The ID of the waveform.
1037 	 * Returns: The format of the waveform data, or WaveFormat.init if not available.
1038 	 */
1039 	public override WaveFormat getWaveformDataFormat(uint id) nothrow {
1040 		if (id <= 127)
1041 			return WaveFormat(intSlmpRate, intSlmpRate * 2, AudioFormat.PCM, 1, 2, 16);
1042 		else
1043 			return WaveFormat.init;
1044 	}
1045 	///Returns the available waveform ID list
1046 	public override uint[] getWaveformIDList() nothrow {
1047 		uint[] result;
1048 		result.length = 128;
1049 		for (int i = 0; i < result.length ; i++) {
1050 			result[i] = i;
1051 		}
1052 		return result;
1053 	}
1054 	///Returns the list of internal waveform IDs if there are any.
1055 	public override uint[] getInternalWaveformIDList() nothrow {
1056 		uint[] result;
1057 		result.length = 33;
1058 		for (int i = 0; i < result.length ; i++) {
1059 			result[i] = i;
1060 		}
1061 		return result;
1062 	}
1063 	///Returns the names of the internal waveforms if there are any.
1064 	public override string[] getInternalWaveformNames() nothrow {
1065 		return ["Sine", "Half Sine", "Full Sine", "Pulse Sine", "75% Sine", "25% Sine", "Alt Pulse Sine", "Alt Sine", 
1066 				"Camel Sine", "Var Sine 0", "Var Sine 1", "Var Sine 2", "Var Sine 3", "Var Sine 4", "Var Sine 5", "Var Sine 6", 
1067 				"Var Sine 7", "Pulse 75%", "Pulse 50%", "Pulse 25%", "Pulse 12.5%", "Pulse 10%", "Pulse 5%", "Ramp", "Morphed Ramp",
1068 				"Triangle", "Morphed Saw", "Saw", "Int Ramp", "Int M Ramp", "Int Tri", "Int M Saw", "Int Saw"];
1069 	}
1070 	/**
1071 	 * MIDI 2.0 data received here.
1072 	 *
1073 	 * data0: Header of the up to 128 bit MIDI 2.0 data.
1074 	 * data1-3: Other packets if needed.
1075 	 */
1076 	public override void midiReceive(UMP data0, uint data1 = 0, uint data2 = 0, uint data3 = 0) @nogc nothrow {
1077 		//data0 = UMP(MessageType.MIDI2, 0x0, MIDI2_0Cmd.NoteOn, 0x0, 0x3f, 0x0);
1078 		switch (data0.msgType) {
1079 			case MessageType.SysCommMsg:	//Process system common message
1080 				break;
1081 			case MessageType.MIDI1:			//Process MIDI 1.0 messages
1082 				ubyte ch = data0.channel;
1083 				switch (data0.status) {
1084 					case MIDI1_0Cmd.CtrlCh:	//Process MIDI 1.0 control change messages
1085 						switch (data0.note) {
1086 							case 0, 32:			//Bank select
1087 								bankNum[data0.channel] = data0.value & 7;
1088 								break;
1089 							case 1, 33:			//Modulation wheel
1090 								ccLow[ch][data0.note] = data0.value;
1091 								chCtrls[ch].modwheel = cast(double)((ccLow[ch][1]<<7) + ccLow[ch][33]) / (ushort.max>>2);
1092 								break;
1093 							case 2, 34:
1094 								ccLow[ch][data0.note] = data0.value;
1095 								chCtrls[ch].auxCtrl = cast(double)((ccLow[ch][2]<<7) + ccLow[ch][34]) / (ushort.max>>2);
1096 								break;
1097 							case 6, 38:			//Data Entry
1098 								ccLow[ch][data0.note] = data0.value;
1099 								//paramTemp = [0xFF,0xFF,0xFF,0xFF];
1100 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][18], ccLow[ch][32+18]), [paramTemp[0], paramTemp[1]], ch);
1101 								break;
1102 							case 18, (32+18):
1103 								ccLow[ch][data0.note] = data0.value;
1104 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][18], ccLow[ch][32+18]), [0, OperatorParamNums.Level], ch);
1105 								break;
1106 							case 19, (32+19):
1107 								ccLow[ch][data0.note] = data0.value;
1108 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][19], ccLow[ch][32+19]), [1, OperatorParamNums.Level], ch);
1109 								break;
1110 							case 16, (32+16):
1111 								ccLow[ch][data0.note] = data0.value;
1112 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][16], ccLow[ch][32+16]), [0, OperatorParamNums.SusLevel], 
1113 										ch);
1114 								break;
1115 							case 17, (32+17):
1116 								ccLow[ch][data0.note] = data0.value;
1117 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][17], ccLow[ch][32+17]), [1, OperatorParamNums.SusLevel], 
1118 										ch);
1119 								break;
1120 							case 20, (32+20):
1121 								ccLow[ch][data0.note] = data0.value;
1122 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][20], ccLow[ch][32+20]), [0, OperatorParamNums.ShpA], ch);
1123 								break;
1124 							case 22, (32+22):
1125 								ccLow[ch][data0.note] = data0.value;
1126 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][22], ccLow[ch][32+22]), [1, OperatorParamNums.ShpA], ch);
1127 								break;
1128 							case 21, (32+21):
1129 								ccLow[ch][data0.note] = data0.value;
1130 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][21], ccLow[ch][32+21]), [0, OperatorParamNums.ShpR], ch);
1131 								break;
1132 							case 23, (32+23):
1133 								ccLow[ch][data0.note] = data0.value;
1134 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][23], ccLow[ch][32+23]), [1, OperatorParamNums.ShpR], ch);
1135 								break;
1136 							case 30, (32+30):
1137 								ccLow[ch][data0.note] = data0.value;
1138 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][30], ccLow[ch][32+30]), [0, OperatorParamNums.TuneFine], 
1139 										ch);
1140 								break;
1141 							case 31, (32+31):
1142 								ccLow[ch][data0.note] = data0.value;
1143 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][31], ccLow[ch][32+31]), [1, OperatorParamNums.TuneFine], 
1144 										ch);
1145 								break;
1146 //
1147 							case 73:
1148 								setUnregisteredParam(data0.value<<25, [1, 1], data0.channel);
1149 								break;
1150 							case 78:
1151 								setUnregisteredParam(data0.value<<25, [0, 1], data0.channel);
1152 								break;
1153 							case 74:
1154 								setUnregisteredParam(data0.value<<25, [1, 2], data0.channel);
1155 								break;
1156 							case 79:
1157 								setUnregisteredParam(data0.value<<25, [0, 2], data0.channel);
1158 								break;
1159 							case 85:
1160 								setUnregisteredParam(data0.value<<25, [0, 4], data0.channel);
1161 								break;
1162 							case 86:
1163 								setUnregisteredParam(data0.value<<25, [1, 4], data0.channel);
1164 								break;
1165 							case 87:
1166 								setUnregisteredParam(data0.value<<25, [0, 8], data0.channel);
1167 								break;
1168 							case 88:
1169 								setUnregisteredParam(data0.value<<25, [1, 8], data0.channel);
1170 								break;
1171 							case 72:
1172 								setUnregisteredParam(data0.value<<25, [1, 5], data0.channel);
1173 								break;
1174 							case 77:
1175 								setUnregisteredParam(data0.value<<25, [0, 5], data0.channel);
1176 								break;
1177 							case 70:
1178 								setUnregisteredParam(data0.value<<25, [1, 6], data0.channel);
1179 								break;
1180 							case 75:
1181 								setUnregisteredParam(data0.value<<25, [0, 6], data0.channel);
1182 								break;
1183 							case 71:
1184 								setUnregisteredParam(data0.value<<25, [1, 7], data0.channel);
1185 								break;
1186 							case 76:
1187 								setUnregisteredParam(data0.value<<25, [0, 7], data0.channel);
1188 								break;
1189 //Channel common 14 bit
1190 							case 7, 32+7:
1191 								ccLow[ch][data0.note] = data0.value;
1192 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][7], ccLow[ch][32+7]), [4, ChannelParamNums.MasterVol], 
1193 										data0.channel);
1194 								break;
1195 							case 8, 32+8:
1196 								ccLow[ch][data0.note] = data0.value;
1197 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][8], ccLow[ch][32+8]), [4, ChannelParamNums.Bal], 
1198 										data0.channel);
1199 								break;
1200 							case 24, 32+24:
1201 								ccLow[ch][data0.note] = data0.value;
1202 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][24], ccLow[ch][32+24]), [4, ChannelParamNums.ShpA], 
1203 										data0.channel);
1204 								break;
1205 							case 25, 32+25:
1206 								ccLow[ch][data0.note] = data0.value;
1207 								setUnregisteredParam(convertM1CtrlValToM2(ccLow[ch][25], ccLow[ch][32+25]), [4, ChannelParamNums.ShpR], 
1208 										data0.channel);
1209 								break;
1210 //
1211 							case 91:
1212 								setUnregisteredParam(data0.value<<25, [4, 2], data0.channel);
1213 								break;
1214 							case 92:
1215 								setUnregisteredParam(data0.value<<25, [4, 3], data0.channel);
1216 								break;
1217 							case 93:
1218 								setUnregisteredParam(data0.value<<25, [4, 4], data0.channel);
1219 								break;
1220 							case 94:
1221 								setUnregisteredParam(data0.value<<25, [4, 5], data0.channel);
1222 								break;
1223 							case 102:
1224 								setUnregisteredParam(data0.value<<25, [4, 6], data0.channel);
1225 								break;
1226 							case 103:
1227 								setUnregisteredParam(data0.value<<25, [4, 7], data0.channel);
1228 								break;
1229 							case 104:
1230 								setUnregisteredParam(data0.value<<25, [4, 8], data0.channel);
1231 								break;
1232 							case 105:
1233 								setUnregisteredParam(data0.value<<25, [4, 9], data0.channel);
1234 								break;
1235 							case 106:
1236 								setUnregisteredParam(data0.value<<25, [4, 10], data0.channel);
1237 								break;
1238 							case 107:
1239 								setUnregisteredParam(data0.value<<25, [4, 13], data0.channel);
1240 								break;
1241 //
1242 							case 98:		//Non Registered Parameter Number MSB (handle through MIDI 2.0)
1243 								paramTemp[0] = data0.value;
1244 								/* if (paramTemp[0] != 0xFF)
1245 									setUnregisteredParam(convertM1CtrlValToM2(paramTemp[0], paramTemp[1]), [ccLow[ch][6], ccLow[ch][38]], data0.channel); */
1246 								break;
1247 							case 99:		//Non Registered Parameter Number LSB (handle through MIDI 2.0)
1248 								//setUnregisteredParam(data0.value, paramNum, 0, data0.channel);
1249 								paramTemp[1] = data0.value;
1250 								/* if (paramTemp[0] != 0xFF)
1251 									setUnregisteredParam(convertM1CtrlValToM2(paramTemp[0], paramTemp[1]), [ccLow[ch][6], ccLow[ch][38]], data0.channel); */
1252 								break;
1253 							default:
1254 								break;
1255 						}
1256 						break;
1257 					case MIDI1_0Cmd.NoteOn:	//Note on command
1258 						keyOn(data0.note, data0.channel, data0.value/127.0);
1259 						break;
1260 					case MIDI1_0Cmd.NoteOff://Note off command
1261 						keyOff(data0.note, data0.channel, data0.value/127.0);
1262 						break;
1263 					case MIDI1_0Cmd.ChAftrTch:
1264 						chCtrls[data0.channel].velocity = cast(double)data0.note / cast(double)byte.max;
1265 						break;
1266 					case MIDI1_0Cmd.PolyAftrTch:
1267 						chCtrls[data0.channel].velocity = cast(double)data0.velocity / cast(double)byte.max;
1268 						break;
1269 					case MIDI1_0Cmd.PrgCh:	//Program change
1270 						const uint chOffset = data0.channel;
1271 						presetNum[chOffset] = data0.program;
1272 						const uint chCtrl = soundBank[bankNum[chOffset] & 7][presetNum[chOffset]].channel.chCtrl;
1273 						if (chCtrl & ChCtrlFlags.ComboModeTest) {
1274 							const uint chX = chOffset & 7, bankX = bankNum[chOffset] & 7 & ~1;
1275 							prgRecall(chX, presetNum[chX], bankX);
1276 							prgRecall(chX + 8, presetNum[chX], bankX + 1);
1277 						} else {
1278 							prgRecall(chOffset, presetNum[chOffset], bankNum[chOffset]);
1279 						}
1280 						break;
1281 					case MIDI1_0Cmd.PitchBend:
1282 						//const uint ch = data0.channel;
1283 						chCtrls[ch].pitchBend = channels[ch].preset.pitchBendSens * ((cast(double)data0.bend - 0x20_00) / 0x3F_FF);
1284 						break;
1285 					default:
1286 						//assert(0, "MIDI 1.0 data error!");
1287 						break;
1288 				}
1289 				break;
1290 			case MessageType.MIDI2:
1291 				switch (data0.status) {
1292 					case MIDI2_0Cmd.CtrlChOld:
1293 						switch (data0.index) {
1294 							case 1:
1295 								chCtrls[data0.channel].modwheel = cast(double)data1 / uint.max;
1296 								break;
1297 							case 2:
1298 								chCtrls[data0.channel].auxCtrl = cast(double)data1 / uint.max;
1299 								break;
1300 							default:
1301 								break;
1302 						}
1303 						break;
1304 					case MIDI2_0Cmd.CtrlCh:	//Control change
1305 						setUnregisteredParam(data1, [data0.index, data0.value], data0.channel);
1306 						break;
1307 					case MIDI2_0Cmd.CtrlChR://Registered control change
1308 						//setRegisteredParam(data[1], [data0.index, data0.value], data0.channel);
1309 						break;
1310 					case MIDI2_0Cmd.PrgCh:	//Program change
1311 						const uint chOffset = data0.channel;
1312 						//const uint prg = data[1]>>24, bank = data[1] & 7;
1313 						presetNum[chOffset] = cast(ubyte)(data1>>24);
1314 						if (data0.value & 1) bankNum[chOffset] = cast(ubyte)(data1 & 7);
1315 						const uint chCtrl = soundBank[bankNum[chOffset] & 7][presetNum[chOffset]].channel.chCtrl;
1316 						if (chCtrl & ChCtrlFlags.ComboModeTest) {
1317 							const uint chX = chOffset & 7, bankX = bankNum[chOffset] & 7 & ~1;
1318 							prgRecall(chX, presetNum[chX], bankX);
1319 							prgRecall(chX + 8, presetNum[chX], bankX + 1);
1320 						} else {
1321 							prgRecall(chOffset, presetNum[chOffset], bankNum[chOffset]);
1322 						}
1323 						break;
1324 					case MIDI2_0Cmd.NoteOn:
1325 						NoteVals v = *cast(NoteVals*)(&data1);
1326 						keyOn(data0.note, data0.channel, v.velocity/65_535.0);
1327 						break;
1328 					case MIDI2_0Cmd.NoteOff:
1329 						NoteVals v = *cast(NoteVals*)(&data1);
1330 						keyOff(data0.note, data0.channel, v.velocity/65_535.0);
1331 						break;
1332 					case MIDI2_0Cmd.PitchBend:
1333 						const uint ch = data0.channel;
1334 						/+const double pitchBendSens = (channels[ch].preset.pitchBendSens>>25) + 
1335 								(cast(double)(channels[ch].preset.pitchBendSens & 0x01_FF_FF_FF) / 0x01_FF_FF_FF);+/
1336 						chCtrls[ch].pitchBend = channels[ch].preset.pitchBendSens * ((cast(double)data1 - int.max) / (int.max));
1337 						break;
1338 					default:
1339 						assert(0, "MIDI 2.0 data error!");
1340 						//break;
1341 				}
1342 				break;
1343 			case MessageType.Data64:
1344 				if (data0.status == SysExSt.Start || data0.status == SysExSt.Complete)
1345 					sysExBuf[31] = 0;
1346 				ubyte[4] packet1 = [cast(ubyte)(data1>>24), cast(ubyte)(data1>>16), cast(ubyte)(data1>>8), cast(ubyte)data1];
1347 				int length = data0.channel;
1348 				for (int i ; i < 2 && length - 4 > 0 ; i++, length--) {
1349 					sysExBuf[sysExBuf[31]] = data0.bytes[i];
1350 					sysExBuf[31]++;
1351 					if (sysExBuf[31] > 30) {
1352 						length = 0;
1353 						sysExBuf[31] = 0;
1354 					}
1355 				}
1356 				for (int i ; i < 4 && length > 0 ; i++, length--) {
1357 					sysExBuf[sysExBuf[31]] = packet1[i];
1358 					sysExBuf[31]++;
1359 					if (sysExBuf[31] > 30) {
1360 						length = 0;
1361 						sysExBuf[31] = 0;
1362 					}
1363 				}
1364 				if (data0.status == SysExSt.Complete || data0.status == SysExSt.End)
1365 					sysExCmd(sysExBuf[0..sysExBuf[31]]);
1366 				break;
1367 			case MessageType.Data128:
1368 				if (data0.status == SysExSt.Start || data0.status == SysExSt.Complete)
1369 					sysExBuf[31] = 0;
1370 				ubyte[13] data = [data0.value, 
1371 						cast(ubyte)(data1>>24), cast(ubyte)(data1>>16), cast(ubyte)(data1>>8), cast(ubyte)data1,
1372 						cast(ubyte)(data2>>24), cast(ubyte)(data2>>16), cast(ubyte)(data2>>8), cast(ubyte)data2,
1373 						cast(ubyte)(data3>>24), cast(ubyte)(data3>>16), cast(ubyte)(data3>>8), cast(ubyte)data3];
1374 				for (int i ; i < data0.channel ; i++, sysExBuf[31]++) {
1375 					sysExBuf[sysExBuf[31]] = data[i];
1376 					if (sysExBuf[31] > 30)
1377 						sysExBuf[31] = 0;
1378 				}
1379 				if (data0.status == SysExSt.Complete || data0.status == SysExSt.End)
1380 					sysExCmd(sysExBuf[0..sysExBuf[31]]);
1381 				break;
1382 			default:
1383 				//assert(0, "Something went really wrong!");
1384 				break;
1385 		}
1386 	}
1387 	/** 
1388 	 * Implements a key-on event.
1389 	 * Params:
1390 	 *   note = identifies which key is being pressed. Affects KSL control parameters
1391 	 *   ch = channel number
1392 	 *   vel = key velocity
1393 	 *   bend = amount of initial bend (MIDI 2.0 only)
1394 	 */
1395 	protected void keyOn(ubyte note, ubyte ch, float vel, float bend = float.nan) @nogc pure nothrow {
1396 		const int opOffset = ch * 2;
1397 		void hardReset() @safe @nogc pure nothrow {
1398 			channels[ch].eeg.keyOn();
1399 			operators[opOffset].eg.keyOn();
1400 			operators[opOffset + 1].eg.keyOn();
1401 			operators[opOffset].pos = 0;
1402 			operators[opOffset + 1].pos = 0;
1403 		}
1404 		void softReset() @safe @nogc pure nothrow {
1405 			channels[ch].eeg.keyOnNoReset();
1406 			operators[opOffset].eg.keyOnNoReset();
1407 			operators[opOffset + 1].eg.keyOnNoReset();
1408 		}
1409 		void hardResetCmb() @safe @nogc pure nothrow {
1410 			channels[ch + 8].eeg.keyOn();
1411 			operators[opOffset + 16].eg.keyOn();
1412 			operators[opOffset + 17].eg.keyOn();
1413 			operators[opOffset + 16].pos = 0;
1414 			operators[opOffset + 17].pos = 0;
1415 		}
1416 		void softResetCmb() @safe @nogc pure nothrow {
1417 			channels[ch + 8].eeg.keyOnNoReset();
1418 			operators[opOffset + 16].eg.keyOnNoReset();
1419 			operators[opOffset + 17].eg.keyOnNoReset();
1420 		}
1421 		if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch > 7) return;
1422 		chCtrls[ch].note = note;
1423 		chCtrls[ch].velocity = vel;
1424 		if (!isNaN(bend)) chCtrls[ch].pitchBend = bend;
1425 		operators[opOffset].setFrequency(intSlmpRate, note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun);
1426 		operators[opOffset].setEG(intSlmpRate, note, vel);
1427 		operators[opOffset + 1].setFrequency(intSlmpRate, note, chCtrls[ch + 1].pitchBend, channels[ch].preset.chnlTun);
1428 		operators[opOffset + 1].setEG(intSlmpRate, note, vel);
1429 		if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch <= 7) {
1430 			operators[opOffset + 16].setFrequency(intSlmpRate, note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun);
1431 			operators[opOffset + 16].setEG(intSlmpRate, note, vel);
1432 			operators[opOffset + 17].setFrequency(intSlmpRate, note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun);
1433 			operators[opOffset + 17].setEG(intSlmpRate, note, vel);
1434 			if (channels[ch].preset.chCtrl & ChCtrlFlags.ResetOnKeyOn) {
1435 				hardReset();
1436 				hardResetCmb();
1437 			} else if (channels[ch].preset.chCtrl & ChCtrlFlags.ResetMode) {
1438 				if ((channels[ch].eeg.position | channels[ch + 8].eeg.position | operators[ch].eg.position |
1439 						operators[opOffset + 1].eg.position | operators[opOffset + 16].eg.position | operators[opOffset + 17].eg.position) 
1440 						== ADSREnvelopGenerator.Stage.Off) {
1441 					hardReset();
1442 					hardResetCmb();
1443 				} else {
1444 					softReset();
1445 					softResetCmb();
1446 				}
1447 			} else {
1448 				softReset();
1449 				softResetCmb();
1450 			}
1451 		} else {
1452 			if (channels[ch].preset.chCtrl & ChCtrlFlags.ResetOnKeyOn) {
1453 				hardReset();
1454 			} else if (channels[ch].preset.chCtrl & ChCtrlFlags.ResetMode) {
1455 				if ((channels[ch].eeg.position | operators[ch].eg.position | operators[ch + 1].eg.position) == 
1456 						ADSREnvelopGenerator.Stage.Off) {
1457 					hardReset();
1458 				} else {
1459 					softReset();
1460 				}
1461 			} else {
1462 				softReset();
1463 			}
1464 		}
1465 	}
1466 	/** 
1467 	 * Implements a key-off event.
1468 	 * Params:
1469 	 *   note = 
1470 	 *   ch = 
1471 	 *   vel = 
1472 	 */
1473 	protected void keyOff(ubyte note, ubyte ch, float vel, float bend = 0) @nogc pure nothrow {
1474 		if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch > 7) return;
1475 		const int opOffset = ch * 2;
1476 		chCtrls[ch].note = note;
1477 		chCtrls[ch].velocity = vel;
1478 		channels[ch].eeg.keyOff();
1479 		operators[opOffset].keyOff(intSlmpRate);
1480 		operators[opOffset + 1].keyOff(intSlmpRate);
1481 		if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch <= 7) {
1482 			channels[ch + 8].eeg.keyOff();
1483 			operators[opOffset + 16].keyOff(intSlmpRate);
1484 			operators[opOffset + 17].keyOff(intSlmpRate);
1485 		}
1486 	}
1487 	/**
1488 	Implements system exclusive command handling.
1489 	
1490 	Params:
1491 	  msg = Message data.
1492 	*/
1493 	protected void sysExCmd(ubyte[] msg) @nogc pure nothrow {
1494 		//Check manufacturer ID (7D: internal use)
1495 		if (msg[0] == 0x7D || msg[1] == 0x7D) {
1496 			const int msgPos = msg[0] ? 1 : 2;
1497 			switch (msg[msgPos]) {
1498 				case 0x01:	//Suspend channel
1499 					if (msg[msgPos + 1] >= 16) return;
1500 					chDeleg[msg[msgPos + 1]] = &updateChannelMD;
1501 					break;
1502 				case 0x02:	//Resume channel
1503 					if (msg[msgPos + 1] >= 16) return;
1504 					ubyte ch = msg[msgPos + 1];
1505 					if (ch < 8)
1506 						setChDeleg(channels[ch].preset.chCtrl, ch, channels[ch + 8].preset.chCtrl);
1507 					else
1508 						setChDeleg(channels[ch].preset.chCtrl, ch);
1509 					break;
1510 				case 0x03:	//Overwrite preset
1511 					if (msg[msgPos + 1] >= 16) return;
1512 					ubyte ch = msg[msgPos + 1];
1513 					if (msg.length == msgPos + 5) {
1514 						presetNum[ch] = msg[msgPos + 2];
1515 						if (channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) {
1516 							bankNum[ch] = msg[msgPos + 4] & ~0x01;
1517 							presetNum[ch + 8] = msg[msgPos + 2];
1518 							bankNum[ch + 8] = msg[msgPos + 4] | 0x01;
1519 						} else
1520 							bankNum[ch] = msg[msgPos + 4];
1521 					}
1522 					soundBank[bankNum[ch]][presetNum[ch]] = Preset([operators[ch*2].preset, operators[(ch*2) + 1].preset], 
1523 							channels[ch].preset);
1524 					if (ch < 8 && (channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest)) {
1525 						ch += 8;
1526 						soundBank[bankNum[ch]][presetNum[ch]] = Preset([operators[ch*2].preset, operators[(ch*2) + 1].preset], 
1527 							channels[ch].preset);
1528 					}
1529 					break;
1530 				default:
1531 					break;
1532 			}
1533 		}
1534 	}
1535 	/**
1536 	Sets the channel delegates
1537 	
1538 	Params:
1539 	  chCtrl = Main channel control flags.
1540 	  chNum = Channel number.
1541 	  chCtrl0 = Secondary channel control flags, used for channel combinations.
1542 	*/
1543 	protected void setChDeleg(uint chCtrl, uint chNum, uint chCtrl0 = 0) @nogc @safe pure nothrow {
1544 		if (chCtrl & ChCtrlFlags.ComboModeTest) {	//Test if channel is combined or not
1545 			if (chNum < 8) {
1546 				const uint algID = (chCtrl & (ChCtrlFlags.ComboModeTest | ChCtrlFlags.Algorithm)) | 
1547 						((chCtrl0 & ChCtrlFlags.Algorithm)<<1);
1548 				enum priChAlg = ChCtrlFlags.Algorithm;
1549 				enum secChAlg = ChCtrlFlags.Algorithm<<1;
1550 				switch (algID) {
1551 					case ChCtrlFlags.ComboMode1:
1552 						chDeleg[chNum] = &updateChannelM100;
1553 						break;
1554 					case ChCtrlFlags.ComboMode1 | secChAlg:
1555 						chDeleg[chNum] = &updateChannelM110;
1556 						break;
1557 					case ChCtrlFlags.ComboMode1 | priChAlg:
1558 						chDeleg[chNum] = &updateChannelM101;
1559 						break;
1560 					case ChCtrlFlags.ComboMode1 | secChAlg | priChAlg:
1561 						chDeleg[chNum] = &updateChannelM111;
1562 						break;
1563 					case ChCtrlFlags.ComboMode2:
1564 						chDeleg[chNum] = &updateChannelM200;
1565 						break;
1566 					case ChCtrlFlags.ComboMode2 | secChAlg:
1567 						chDeleg[chNum] = &updateChannelM210;
1568 						break;
1569 					case ChCtrlFlags.ComboMode2 | priChAlg:
1570 						chDeleg[chNum] = &updateChannelM201;
1571 						break;
1572 					case ChCtrlFlags.ComboMode2 | secChAlg | priChAlg:
1573 						chDeleg[chNum] = &updateChannelM211;
1574 						break;
1575 					case ChCtrlFlags.ComboMode3:
1576 						chDeleg[chNum] = &updateChannelM300;
1577 						break;
1578 					case ChCtrlFlags.ComboMode3 | secChAlg:
1579 						chDeleg[chNum] = &updateChannelM310;
1580 						break;
1581 					case ChCtrlFlags.ComboMode3 | priChAlg:
1582 						chDeleg[chNum] = &updateChannelM301;
1583 						break;
1584 					case ChCtrlFlags.ComboMode3 | secChAlg | priChAlg:
1585 						chDeleg[chNum] = &updateChannelM311;
1586 						break;
1587 					default:
1588 						chDeleg[chNum] = &updateChannelMD;
1589 						break;
1590 				}
1591 				chDeleg[chNum + 8] = &updateChannelMD;
1592 			} else {
1593 				chDeleg[chNum] = &updateChannelMD;
1594 			}
1595 		} else {
1596 			if (chCtrl & ChCtrlFlags.Algorithm) 
1597 				chDeleg[chNum] = &updateChannelM01;
1598 			else
1599 				chDeleg[chNum] = &updateChannelM00;
1600 		}
1601 	}
1602 	/**
1603 	Recalls a program
1604 	Params:
1605 	  ch = channel number.
1606 	  prg = program number.
1607 	  bank = bank number LSB. MSB is not used.
1608 	*/
1609 	protected void prgRecall(ubyte ch, ubyte prg, ubyte bank) @nogc @safe pure nothrow {
1610 		Preset p = soundBank[bank & 7][prg];
1611 		if (p.channel.chCtrl & ChCtrlFlags.ComboModeTest) {
1612 			if (ch > 7) ch -= 8;
1613 			if (bank & 1)
1614 				p = soundBank[bank & 6][prg];
1615 			const int opOffset = ch * 2;
1616 			operators[opOffset].preset = p.operators[0];
1617 			operators[opOffset].setEG(intSlmpRate, 40);
1618 			operators[opOffset + 1].preset = p.operators[1];
1619 			operators[opOffset + 1].setEG(intSlmpRate, 40);
1620 			channels[ch].preset = p.channel;
1621 			channels[ch].setEEG(intSlmpRate);
1622 			Preset upper = soundBank[(bank & 6) + 1][prg];
1623 			operators[opOffset + 16].preset = upper.operators[0];
1624 			operators[opOffset + 16].setEG(intSlmpRate, 40);
1625 			operators[opOffset + 17].preset = upper.operators[1];
1626 			operators[opOffset + 17].setEG(intSlmpRate, 40);
1627 			channels[ch + 8].preset = upper.channel;
1628 			channels[ch + 8].setEEG(intSlmpRate);
1629 		} else {
1630 			const int opOffset = ch * 2;
1631 			operators[opOffset].preset = p.operators[0];
1632 			operators[opOffset].setEG(intSlmpRate, 40);
1633 			operators[opOffset + 1].preset = p.operators[1];
1634 			operators[opOffset + 1].setEG(intSlmpRate, 40);
1635 			channels[ch].preset = p.channel;
1636 			channels[ch].setEEG(intSlmpRate);
1637 		}
1638 		if (channels[ch].preset.chCtrl & ChCtrlFlags.IndivOutChLev) {
1639 			channels[ch].outLevels[0] = channels[ch].preset.masterVol;
1640 			channels[ch].outLevels[1] = channels[ch].preset.masterBal;
1641 		} else {
1642 			channels[ch].outLevels[0] = channels[ch].preset.masterVol * sqrt(channels[ch].preset.masterBal);
1643 			channels[ch].outLevels[1] = channels[ch].preset.masterVol * (1.0 - sqrt(channels[ch].preset.masterBal));
1644 		}
1645 		if (ch <= 7)
1646 			setChDeleg(channels[ch].preset.chCtrl, ch, channels[ch + 8].preset.chCtrl);
1647 		else
1648 			setChDeleg(channels[ch].preset.chCtrl, ch);
1649 	}
1650 	protected void setALFO() @nogc @safe pure nothrow {
1651 		//aLFOff = calculateLP6factor(intSlmpRate, aLFOFreq * 512);
1652 		const double cycleLen = aLFOFreq / (intSlmpRate / 1024);
1653 		aLFORate = cast(uint)(cycleLen * (1<<22));
1654 	}
1655 	protected void setPLFO() @nogc @safe pure nothrow {
1656 		const double cycleLen = pLFOFreq / (intSlmpRate / 1024);
1657 		pLFORate = cast(uint)(cycleLen * (1<<22) * intBufSize);
1658 	}
1659 	/**
1660 	Sets a registered parameter
1661 
1662 	If type is not zero, then the MSB is being set, otherwise the LSB will be used
1663 	*/
1664 	protected void setRegisteredParam(T)(T val, ubyte[2] paramNum, ubyte type, ubyte chNum) @nogc @safe pure nothrow {
1665 		switch (paramNum[0]) {
1666 			case ChannelRegParams.PitchBendSens:
1667 				static if (is(T == uint)) {
1668 					channels[chNum].pitchBendSens = (cast(double)val / (uint.max / 127.0));
1669 				} else static if (is(T == ubyte)) {
1670 					const int whole = cast(int)(channels[chNum].pitchBendSens);
1671 					if (type) {
1672 						channels[chNum].pitchBendSens = whole + (val / byte.max);
1673 					} else {
1674 						channels[chNum].pitchBendSens = (channels[chNum].pitchBendSens - whole) * val;
1675 					}
1676 				}
1677 				break;
1678 			case ChannelRegParams.TuneFine:			//Channel master tuning (fine)
1679 				break;
1680 			case ChannelRegParams.TuneCor:			//Channel master tuning (coarse)
1681 				break;
1682 			default: break;
1683 		}
1684 	}
1685 	/**
1686 	Sets an unregistered parameter (MIDI 2.0)
1687 
1688 	If type is not zero, then the MSB is being set, otherwise the LSB will be used
1689 	*/
1690 	protected void setUnregisteredParam(uint val, ubyte[2] paramNum, ubyte chNum) @nogc @safe pure nothrow {
1691 		void setOpParam(int opNum) {
1692 			switch (paramNum[0]) {
1693 				case OperatorParamNums.Attack:
1694 					operators[opNum].preset.atk = cast(ubyte)(val >> 25);
1695 					operators[opNum].setEG(intSlmpRate, chCtrls[chNum].note);
1696 					break;
1697 				case OperatorParamNums.Decay:
1698 					operators[opNum].preset.dec = cast(ubyte)(val >> 25);
1699 					operators[opNum].setEG(intSlmpRate, chCtrls[chNum].note);
1700 					break;
1701 				case OperatorParamNums.Feedback:
1702 					const double valF = cast(double)val / uint.max;
1703 					operators[opNum].preset.fbL = pow(valF, 2.5) * (operators[opNum].preset.opCtrl & OpCtrlFlags.FBNeg ? -1 : 1);
1704 					break;
1705 				case OperatorParamNums.Level:
1706 					const double valF = cast(double)val / uint.max;
1707 					operators[opNum].preset.outL = valF * valF;
1708 					operators[opNum].calculateKSL(chCtrls[chNum].note);
1709 					break;
1710 				case OperatorParamNums.OpCtrl:
1711 					operators[opNum].preset.opCtrl &= OpCtrlFlags.WavetableSelect;
1712 					operators[opNum].preset.opCtrl |= val<<7;
1713 					break;
1714 				case OperatorParamNums.Release:
1715 					operators[opNum].preset.rel = cast(ubyte)(val >> 25);
1716 					operators[opNum].setEG(intSlmpRate, chCtrls[chNum].note);
1717 					break;
1718 				case OperatorParamNums.ShpA:
1719 					operators[opNum].preset.shpA = cast(double)val / uint.max;
1720 					operators[opNum].setShpVals(chCtrls[chNum].velocity);
1721 					break;
1722 				case OperatorParamNums.ShpR:
1723 					operators[opNum].preset.shpR = cast(double)val / uint.max;
1724 					operators[opNum].setShpVals(chCtrls[chNum].velocity);
1725 					break;
1726 				case OperatorParamNums.SusCtrl:
1727 					operators[opNum].preset.susCC = cast(ubyte)(val >> 25);
1728 					operators[opNum].setEG(intSlmpRate, chCtrls[chNum].note);
1729 					break;
1730 				case OperatorParamNums.SusLevel:
1731 					operators[opNum].eg.sustainLevel = cast(double)val / uint.max;
1732 					//Recalculate decay and release rates to new sustain levels
1733 					if (operators[opNum].preset.dec) {
1734 						operators[opNum].eg.decayRate = calculateRate(ADSR_TIME_TABLE[operators[opNum].preset.dec] * 2, intSlmpRate, 
1735 								ADSREnvelopGenerator.maxOutput, operators[opNum].eg.sustainLevel);
1736 					} else {
1737 						operators[opNum].eg.decayRate = 1.0;
1738 					}
1739 					if (operators[opNum].preset.rel) {
1740 						operators[opNum].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[opNum].preset.rel] * 2, intSlmpRate, 
1741 								operators[opNum].eg.sustainLevel);
1742 					} else {
1743 						operators[opNum].eg.releaseRate = 1.0;
1744 					}
1745 					break;
1746 				case OperatorParamNums.TuneCor:
1747 					if (operators[opNum].preset.opCtrl & OpCtrlFlags.ContiTune) {
1748 						operators[opNum].preset.tune = cast(double)val / 0x02_00_00_00;
1749 					} else {
1750 						operators[opNum].preset.opCtrl &= ~TuneCtrlFlags.CorTuneTest; 
1751 						operators[opNum].preset.opCtrl |= val & TuneCtrlFlags.CorTuneTest;
1752 					}
1753 					
1754 					break;
1755 				case OperatorParamNums.TuneFine:
1756 					if (!(operators[opNum].preset.opCtrl & OpCtrlFlags.ContiTune))
1757 						operators[opNum].preset.tune = (cast(double)val - int.min) / int.max;
1758 					break;
1759 				case OperatorParamNums.VelToLevel:
1760 					operators[opNum].preset.outLCtrl[0] = cast(double)val / uint.max;
1761 					break;
1762 				case OperatorParamNums.MWToLevel:
1763 					operators[opNum].preset.outLCtrl[1] = cast(double)val / uint.max;
1764 					break;
1765 				case OperatorParamNums.LFOToLevel:
1766 					operators[opNum].preset.outLCtrl[2] = cast(double)val / uint.max;
1767 					break;
1768 				case OperatorParamNums.VelToFB:
1769 					operators[opNum].preset.fbLCtrl[0] = cast(double)val / uint.max;
1770 					break;
1771 				case OperatorParamNums.MWToFB:
1772 					operators[opNum].preset.fbLCtrl[1] = cast(double)val / uint.max;
1773 					break;
1774 				case OperatorParamNums.LFOToFB:
1775 					operators[opNum].preset.fbLCtrl[2] = cast(double)val / uint.max;
1776 					break;
1777 				case OperatorParamNums.EEGToFB:
1778 					operators[opNum].preset.fbLCtrl[3] = cast(double)val / uint.max;
1779 					break;
1780 				case OperatorParamNums.VelToShpA:
1781 					operators[opNum].preset.shpAVel = cast(double)val / uint.max;
1782 					break;
1783 				case OperatorParamNums.VelToShpR:
1784 					operators[opNum].preset.shpRVel = cast(double)val / uint.max;
1785 					break;
1786 				case OperatorParamNums.Waveform:
1787 					operators[opNum].preset.opCtrl &= ~OpCtrlFlags.WavetableSelect;
1788 					operators[opNum].preset.opCtrl |= cast(ubyte)(val >> 25);
1789 					break;
1790 				case OperatorParamNums.KSLBegin:
1791 					const ubyte newval = cast(ubyte)(val>>25);
1792 					if (newval == 127)
1793 						operators[opNum].preset.kslBegin = ubyte.max;
1794 					else
1795 						operators[opNum].preset.kslBegin = newval;
1796 					break;
1797 				case OperatorParamNums.KSLAttenOut:
1798 					operators[opNum].preset.kslAttenOut = cast(ubyte)(val>>24);
1799 					break;
1800 				case OperatorParamNums.KSLAttenFB:
1801 					operators[opNum].preset.kslAttenFB = cast(ubyte)(val>>24);
1802 					break;
1803 				case OperatorParamNums.KSLAttenADSR:
1804 					operators[opNum].preset.kslAttenADSR = cast(ubyte)(val>>24);
1805 					break;
1806 				default: break;
1807 			}
1808 		}
1809 		void setOpFlag(int opNum){
1810 			if (val) 
1811 				operators[opNum].preset.opCtrl |= 1<<(paramNum[0] + 7);
1812 			else
1813 				operators[opNum].preset.opCtrl &= ~(1<<(paramNum[0] + 7));
1814 		}
1815 		switch (paramNum[1]) {
1816 			case 0:			//Channel operator 0
1817 				//chNum *= 2;
1818 				setOpParam(chNum * 2);
1819 				break;
1820 			case 1:			//Channel operator 1
1821 				//chNum *= 2;
1822 				setOpParam((chNum * 2) + 1);
1823 				break;
1824 			case 2:			//Channel operator 0 flags
1825 				setOpFlag(chNum * 2);
1826 				break;
1827 			case 3:			//Channel operator 1 flags
1828 				setOpFlag((chNum * 2) + 1);
1829 				break;
1830 			case 4:			//Channel common values
1831 				switch (paramNum[0]) { 
1832 					//case ChannelParamNums.ALFO: break;
1833 					case ChannelParamNums.Attack:
1834 						channels[chNum].preset.atkX = cast(ubyte)(val >> 25);
1835 						if (channels[chNum].preset.atkX) {
1836 							channels[chNum].eeg.attackRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].preset.atkX], intSlmpRate);
1837 						} else {
1838 							channels[chNum].eeg.attackRate = 1.0;
1839 						}
1840 						break;
1841 					case ChannelParamNums.AuxSLA:
1842 						const double valF = cast(double)val / uint.max;
1843 						channels[chNum].outLevels[2] = valF * valF;
1844 						channels[chNum].preset.auxSendA = channels[chNum].outLevels[2];
1845 						break;
1846 					case ChannelParamNums.AuxSLB: 
1847 						const double valF = cast(double)val / uint.max;
1848 						channels[chNum].outLevels[2] = valF * valF;
1849 						channels[chNum].preset.auxSendB = channels[chNum].outLevels[3];
1850 						break;
1851 					case ChannelParamNums.Bal: 
1852 						channels[chNum].preset.masterBal = cast(double)val / uint.max;
1853 						if (channels[chNum].preset.chCtrl & ChCtrlFlags.IndivOutChLev) {
1854 							channels[chNum].outLevels[1] = channels[chNum].preset.masterBal * channels[chNum].preset.masterBal;
1855 						} else {
1856 							channels[chNum].outLevels[0] = channels[chNum].preset.masterVol * sqrt(channels[chNum].preset.masterBal);
1857 							channels[chNum].outLevels[1] = channels[chNum].preset.masterVol * (1.0 - sqrt(channels[chNum].preset.masterBal));
1858 						}
1859 						break;
1860 					case ChannelParamNums.ChCtrl:
1861 						channels[chNum].preset.chCtrl = val;
1862 						//mirror operator configuration parameters between paired channels
1863 						if (chNum < 8) {
1864 							channels[chNum + 8].preset.chCtrl &= ~ChCtrlFlags.ComboModeTest;
1865 							channels[chNum + 8].preset.chCtrl |= ChCtrlFlags.ComboModeTest & channels[chNum].preset.chCtrl;
1866 						} else {
1867 							channels[chNum - 8].preset.chCtrl &= ~ChCtrlFlags.ComboModeTest;
1868 							channels[chNum - 8].preset.chCtrl |= ChCtrlFlags.ComboModeTest & channels[chNum].preset.chCtrl;
1869 						}
1870 						break;
1871 					//case ChannelParamNums.ChCtrlL: break;
1872 					case ChannelParamNums.Decay:
1873 						channels[chNum].preset.decX = cast(ubyte)(val >> 25);
1874 						if (channels[chNum].preset.decX) {
1875 							channels[chNum].eeg.decayRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].preset.decX] * 2, intSlmpRate);
1876 						} else {
1877 							channels[chNum].eeg.decayRate = 1.0;
1878 						}
1879 						break;
1880 					case ChannelParamNums.EEGDetune:
1881 						channels[chNum].preset.eegDetuneAm = ((cast(double)(uint.max>>1) - cast(double)val) / (uint.max>>1)) * 24;
1882 						break;
1883 					case ChannelParamNums.MasterVol: 
1884 						const double valF = cast(double)val / uint.max;
1885 						channels[chNum].preset.masterVol = valF * valF;
1886 						if (channels[chNum].preset.chCtrl & ChCtrlFlags.IndivOutChLev) {
1887 							channels[chNum].outLevels[1] = channels[chNum].preset.masterBal * channels[chNum].preset.masterBal;
1888 						} else {
1889 							channels[chNum].outLevels[0] = channels[chNum].preset.masterVol * sqrt(channels[chNum].preset.masterBal);
1890 							channels[chNum].outLevels[1] = channels[chNum].preset.masterVol * (1.0 - sqrt(channels[chNum].preset.masterBal));
1891 						}
1892 						break;
1893 					case ChannelParamNums.PLFO: 
1894 						channels[chNum].preset.pLFOlevel = cast(double)val / uint.max;
1895 						break;
1896 					case ChannelParamNums.Release: 
1897 						channels[chNum].preset.relX = cast(ubyte)(val >> 25);
1898 						if (channels[chNum].preset.relX) {
1899 							channels[chNum].eeg.releaseRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].preset.relX] * 2, intSlmpRate);
1900 						} else {
1901 							channels[chNum].eeg.releaseRate = 1.0;
1902 						}
1903 						break;
1904 					case ChannelParamNums.ShpA:
1905 						channels[chNum].preset.shpAX = cast(double)val / uint.max;
1906 						break;
1907 					case ChannelParamNums.ShpR:
1908 						channels[chNum].preset.shpRX = cast(double)val / uint.max;
1909 						break;
1910 					case ChannelParamNums.SusCtrl: 
1911 						channels[chNum].preset.susCCX = cast(ubyte)(val >> 25);
1912 						if (channels[chNum].preset.susCCX) {
1913 							channels[chNum].eeg.isPercussive = false;
1914 							if (channels[chNum].preset.susCCX == 64) {
1915 								channels[chNum].eeg.sustainControl = 0.0;
1916 							} else if (channels[chNum].preset.susCCX < 64) {
1917 								channels[chNum].eeg.sustainControl = -1.0 * 
1918 										calculateRate(SUSTAIN_CONTROL_TIME_TABLE[channels[chNum].preset.susCCX - 1], intSlmpRate);
1919 							} else {
1920 								channels[chNum].eeg.sustainControl = 
1921 										calculateRate(SUSTAIN_CONTROL_TIME_TABLE[channels[chNum].preset.susCCX - 64], intSlmpRate);
1922 							}
1923 						} else {
1924 							channels[chNum].eeg.isPercussive = true;
1925 							channels[chNum].eeg.sustainControl = 0.0;
1926 						}
1927 						break;
1928 					case ChannelParamNums.SusLevel: 
1929 						channels[chNum].eeg.sustainLevel = cast(double)val / uint.max;
1930 						channels[chNum].preset.susLevel = channels[chNum].eeg.sustainLevel;
1931 						break;
1932 					case ChannelParamNums.GlobalFB: 
1933 						const double valF = cast(double)val / uint.max;
1934 						channels[chNum].preset.globalFb = valF * valF;
1935 						break;
1936 					case ChannelParamNums.EEGToLeft:
1937 						const double valF = cast(double)val / uint.max;
1938 						channels[chNum].preset.eegLevels[0] = valF * valF;
1939 						break;
1940 					case ChannelParamNums.EEGToRight:
1941 						const double valF = cast(double)val / uint.max;
1942 						channels[chNum].preset.eegLevels[1] = valF * valF;
1943 						break;
1944 					case ChannelParamNums.EEGToAuxA:
1945 						const double valF = cast(double)val / uint.max;
1946 						channels[chNum].preset.eegLevels[2] = valF * valF;
1947 						break;
1948 					case ChannelParamNums.EEGToAuxB:
1949 						const double valF = cast(double)val / uint.max;
1950 						channels[chNum].preset.eegLevels[3] = valF * valF;
1951 						break;
1952 					case ChannelParamNums.LFOToLeft:
1953 						const double valF = cast(double)val / uint.max;
1954 						channels[chNum].preset.aLFOlevels[0] = valF * valF;
1955 						break;
1956 					case ChannelParamNums.LFOToRight:
1957 						const double valF = cast(double)val / uint.max;
1958 						channels[chNum].preset.aLFOlevels[1] = valF * valF;
1959 						break;
1960 					case ChannelParamNums.LFOToAuxA:
1961 						const double valF = cast(double)val / uint.max;
1962 						channels[chNum].preset.aLFOlevels[2] = valF * valF;
1963 						break;
1964 					case ChannelParamNums.LFOToAuxB:
1965 						const double valF = cast(double)val / uint.max;
1966 						channels[chNum].preset.aLFOlevels[3] = valF * valF;
1967 						break;
1968 					case ChannelParamNums.MWToGFB:
1969 						const double valF = cast(double)val / uint.max;
1970 						channels[chNum].preset.mwToGFB = valF;
1971 						break;
1972 					case ChannelParamNums.VelToGFB:
1973 						const double valF = cast(double)val / uint.max;
1974 						channels[chNum].preset.velToGFB = valF;
1975 						break;
1976 					default:
1977 						break;
1978 				}
1979 				break;
1980 			case 5:		//Channel common flags
1981 				if (val)
1982 					channels[chNum].preset.chCtrl |= 1<<paramNum[0];
1983 				else
1984 					channels[chNum].preset.chCtrl &= ~(1<<paramNum[0]);
1985 				if (chNum < 8) {
1986 					channels[chNum + 8].preset.chCtrl &= ~ChCtrlFlags.ComboModeTest;
1987 					channels[chNum + 8].preset.chCtrl |= ChCtrlFlags.ComboModeTest & channels[chNum].preset.chCtrl;
1988 					setChDeleg(channels[chNum].preset.chCtrl, chNum, channels[chNum + 8].preset.chCtrl);
1989 					setChDeleg(channels[chNum + 8].preset.chCtrl, chNum + 8);
1990 				} else {
1991 					channels[chNum - 8].preset.chCtrl &= ~ChCtrlFlags.ComboModeTest;
1992 					channels[chNum - 8].preset.chCtrl |= ChCtrlFlags.ComboModeTest & channels[chNum].preset.chCtrl;
1993 					setChDeleg(channels[chNum - 8].preset.chCtrl, chNum - 8, channels[chNum].preset.chCtrl);
1994 					setChDeleg(channels[chNum].preset.chCtrl, chNum);
1995 				}
1996 				break;
1997 			case 16:		//LFO and master filter settings
1998 				void setFilterFreq(int num) @nogc @safe pure nothrow {
1999 					const double valF = cast(double)val / uint.max;
2000 					filterCtrl[num] = valF * valF * 20_000;
2001 				}
2002 
2003 				void setFilterQ(int num) @nogc @safe pure nothrow {
2004 					const double valF = cast(double)val / uint.max;
2005 					filterCtrl[num] = valF * 40;
2006 				}
2007 
2008 				switch (paramNum[0]) {
2009 					case GlobalParamNums.PLFORate:
2010 						double valF;
2011 						valF = cast(double)val / uint.max;
2012 						valF *= 16;
2013 						setPLFO();
2014 						break;
2015 					case GlobalParamNums.PLFOWF:
2016 						lfoWaveform[0] = cast(ubyte)(val >> 25);
2017 						break;
2018 					case GlobalParamNums.ALFORate:
2019 						if (lfoWaveform[1 & 0x80]) {
2020 							aLFOFreq = noteToFreq((cast(double)val) / 0x02_00_00_00, 440);
2021 						} else {
2022 							aLFOFreq = cast(double)val / uint.max;
2023 							aLFOFreq *= 16;
2024 						}
2025 						setALFO();
2026 						break;
2027 					case GlobalParamNums.ALFOWF:
2028 						lfoWaveform[1] = cast(ubyte)(val >> 25);
2029 						break;
2030 					case GlobalParamNums.FilterLCFreq:
2031 						const double valF = cast(double)val / uint.max;
2032 						filterCtrl[0] = valF * valF * 20_000;
2033 						resetLPF(0);
2034 						break;
2035 					case GlobalParamNums.FilterLCQ: 
2036 						const double valF = cast(double)val / uint.max;
2037 						filterCtrl[1] = valF * 2;
2038 						resetLPF(0);
2039 						break;
2040 					case GlobalParamNums.FilterRCFreq: 
2041 						const double valF = cast(double)val / uint.max;
2042 						filterCtrl[2] = valF * valF * 20_000;
2043 						resetLPF(1);
2044 						break;
2045 					case GlobalParamNums.FilterRCQ: 
2046 						const double valF = cast(double)val / uint.max;
2047 						filterCtrl[3] = valF * 2;
2048 						resetLPF(1);
2049 						break;
2050 					case GlobalParamNums.FilterACFreq:
2051 						const double valF = cast(double)val / uint.max;
2052 						filterCtrl[4] = valF * valF * 20_000;
2053 						resetLPF(2);
2054 						break;
2055 					case GlobalParamNums.FilterACQ: 
2056 						const double valF = cast(double)val / uint.max;
2057 						filterCtrl[5] = valF * 2;
2058 						resetLPF(2);
2059 						break;
2060 					case GlobalParamNums.FilterBCFreq: 
2061 						const double valF = cast(double)val / uint.max;
2062 						filterCtrl[6] = valF * valF * 20_000;
2063 						resetLPF(3);
2064 						break;
2065 					case GlobalParamNums.FilterBCQ: 
2066 						const double valF = cast(double)val / uint.max;
2067 						filterCtrl[7] = valF * 2;
2068 						resetLPF(3);
2069 						break;
2070 					case GlobalParamNums.HPFLCFreq:
2071 						const double valF = cast(double)val / uint.max;
2072 						hpfCtrl[0] = valF * valF * 20_000;
2073 						resetHPF(0);
2074 						break;
2075 					case GlobalParamNums.HPFLCQ: 
2076 						const double valF = cast(double)val / uint.max;
2077 						hpfCtrl[1] = valF * 2;
2078 						resetHPF(0);
2079 						break;
2080 					case GlobalParamNums.HPFRCFreq: 
2081 						const double valF = cast(double)val / uint.max;
2082 						hpfCtrl[2] = valF * valF * 20_000;
2083 						resetHPF(1);
2084 						break;
2085 					case GlobalParamNums.HPFRCQ: 
2086 						const double valF = cast(double)val / uint.max;
2087 						hpfCtrl[3] = valF * 2;
2088 						resetHPF(1);
2089 						break;
2090 					case GlobalParamNums.HPFACFreq:
2091 						const double valF = cast(double)val / uint.max;
2092 						hpfCtrl[4] = valF * valF * 20_000;
2093 						resetHPF(2);
2094 						break;
2095 					case GlobalParamNums.HPFACQ: 
2096 						const double valF = cast(double)val / uint.max;
2097 						hpfCtrl[5] = valF * 2;
2098 						resetHPF(2);
2099 						break;
2100 					case GlobalParamNums.HPFBCFreq: 
2101 						const double valF = cast(double)val / uint.max;
2102 						hpfCtrl[6] = valF * valF * 20_000;
2103 						resetHPF(3);
2104 						break;
2105 					case GlobalParamNums.HPFBCQ: 
2106 						const double valF = cast(double)val / uint.max;
2107 						hpfCtrl[7] = valF * 2;
2108 						resetHPF(3);
2109 						break;
2110 					case GlobalParamNums.RingMod:
2111 						if (val)
2112 							lfoWaveform[1] |= 0b1000_0000;
2113 						else
2114 							lfoWaveform[1] &= 0b0111_1111;
2115 						break;
2116 					default:
2117 						break;
2118 				}
2119 				break;
2120 			default: break;
2121 		}
2122 	}
2123 	/**
2124 	 * Renders the current audio frame.
2125 	 * 
2126 	 * input: the input buffers if any, null if none.
2127 	 * output: the output buffers if any, null if none.
2128 	 *
2129 	 * NOTE: Buffers must have matching sizes.
2130 	 */
2131 	public override void renderFrame(float*[] input, float*[] output) @nogc nothrow {
2132 		//Generate aLFO table with filtering
2133 		for (int i ; i < intBufSize ; i++) {
2134 			const double x_0 = (wavetables[lfoWaveform[1] & byte.max][(aLFOPos>>22) & 0x0000_03FF] - short.min) * 
2135 					(1 / cast(double)(ushort.max));
2136 			const double x_1 = (wavetables[lfoWaveform[1] & byte.max][((aLFOPos>>22) + 1) & 0x0000_03FF] - short.min) * 
2137 					(1 / cast(double)(ushort.max));
2138 			const double p = (aLFOPos & 0x003F_FFFF) / cast(double)0x003F_FFFF;
2139 			//aLFOBuf[i] = smoothstep(x_0, x_1, p);
2140 			aLFOBuf[i] = (x_0 * (1 - p)) + (x_1 * p);
2141 			aLFOPos += aLFORate;
2142 		}
2143 		//Generate pLFO out
2144 		{
2145 			pLFOOut = (wavetables[lfoWaveform[0]][pLFOPos>>22]) * (1 / cast(float)(short.max));
2146 			pLFOPos += pLFORate;
2147 		}
2148 		//Render each channel
2149 		foreach (size_t i, ChFun fun ; chDeleg) {	
2150 			fun(cast(int)i, intBufSize);
2151 		}
2152 		//Filter and mix outputs
2153 		//Do the initial low-pass filtering to avoid issues from resampling later
2154 		for (int i = 2 ; i < initBuffers.length ; i++) {
2155 			initBuffers[i] = lpf.output(_mm_min_ps(_mm_max_ps(initBuffers[i], __m128(short.min)), 
2156 					__m128(short.max)));
2157 			//initBuffers[i+2] = initBuffers[i+2] / __m128(mixdownVal);
2158 		}
2159 		//Set up output targets
2160 		float*[4] outBuf;
2161 		for (ubyte i, j ; i < 4 ; i++) {
2162 			if (enabledOutputs.has(i)) {
2163 				outBuf[i] = output[j];
2164 				j++;
2165 			} else {
2166 				outBuf[i] = dummyBuf.ptr;
2167 			}
2168 		}
2169 		//Mix to target alongside with reinterpolate to target frequency and high-pass filtering
2170 		for (int i ; i < bufferSize ; i++) {
2171 			const int intBufPos = (i>>2) * 5;
2172 			const int intBP0 = intBufPos + (i & 3);
2173 			//Apply Cubic Lagrange interpolation
2174 			const __m128 input0 = (initBuffers[intBP0 + 0] * __m128(RESAMPLING_TABLE[i & 3][0])) + 
2175 					(initBuffers[intBP0 + 1] * __m128(RESAMPLING_TABLE[i & 3][1])) +
2176 					(initBuffers[intBP0 + 2] * __m128(RESAMPLING_TABLE[i & 3][2])) +
2177 					(initBuffers[intBP0 + 3] * __m128(RESAMPLING_TABLE[i & 3][3]));
2178 			//Apply high-pass filter
2179 			const __m128 output0 = hpf.output(input0) / __m128(mixdownVal);
2180 			//Mix to target
2181 			for (int j ; j < 4 ; j++)
2182 				outBuf[j][i] += output0[j];
2183 		}
2184 		//Save last two samples of the internal buffer for interpolation, then reset it.
2185 		initBuffers[0] = initBuffers[$-2];
2186 		initBuffers[1] = initBuffers[$-1];
2187 		resetBuffer(initBuffers[2..$]);
2188 	}
2189 	///Updates an operator for a cycle
2190 	///chCtrl index notation: 0: velocity, 1: modulation wheel, 2: Amplitude LFO, 3: Extra Envelop Generator
2191 	///Returns the sum of the level control values for use with the resonant mode
2192 	pragma(inline, true)
2193 	protected double updateOperator(ref Operator op, __m128 chCtrl) @nogc @safe pure nothrow {
2194 		op.output = wavetables
2195 				[op.preset.opCtrl & OpCtrlFlags.WavetableSelect][(op.pos + (op.input<<8) + (op.feedback<<6))>>22 & 1023];
2196 		const double egOut = op.eg.shp(op.eg.position == ADSREnvelopGenerator.Stage.Attack ? op.shpA0 : op.shpR0);
2197 		__m128 outCtrl = (__m128(1.0) - op.preset.outLCtrl) + (op.preset.outLCtrl * chCtrl);
2198 		__m128 fbCtrl = (__m128(1.0) - op.preset.fbLCtrl) + (op.preset.fbLCtrl * chCtrl);
2199 		
2200 		op.feedback = cast(int)((op.preset.opCtrl & OpCtrlFlags.FBMode ? (op.output<<12) : (op.output<<12) * egOut) * op.fbL * 
2201 				fbCtrl[0] * fbCtrl[1] * fbCtrl[2] * fbCtrl[3]);
2202 		const double levelCtrl = egOut * op.outL * outCtrl[0] * outCtrl[1] * outCtrl[2];
2203 		op.output_0 = cast(int)((op.output<<12) * levelCtrl);
2204 		op.pos += op.step;
2205 		//op.input = 0;
2206 		op.eg.advance();
2207 		return levelCtrl;
2208 	}
2209 	///Updates automatic and manual pitchbend values (channel-assignable envelop, LFO, pitchbend CTRL) for 2 operators.
2210 	pragma(inline, true)
2211 	protected final void updatePitchbend2Op(ref Operator op0, ref Operator op1, ref Channel ch, ref ChControllers chCtrl) 
2212 			@nogc @safe pure nothrow {
2213 		if (!isClose(ch.preset.eegDetuneAm, 0.0, 0.1) || !isClose(ch.preset.pLFOlevel, 0.0, 0.01)
2214 				|| !isClose(chCtrl.pitchBend, 0.0, 0.01)) {
2215 			const float eegOut = ch.eeg.shp(ch.eeg.position == ADSREnvelopGenerator.Stage.Attack ? 
2216 					ch.preset.shpAX : ch.preset.shpRX);
2217 			const float vibrAm = pLFOOut * ch.preset.pLFOlevel * 
2218 					(ch.preset.chCtrl & ChCtrlFlags.MWToVibr ? chCtrl.modwheel : 1.0);
2219 			op0.setFrequency(intSlmpRate, chCtrl.note, chCtrl.pitchBend + (ch.preset.eegDetuneAm * eegOut) + vibrAm, 
2220 					ch.preset.chnlTun);
2221 			op1.setFrequency(intSlmpRate, chCtrl.note, chCtrl.pitchBend + (ch.preset.eegDetuneAm * eegOut) + vibrAm, 
2222 					ch.preset.chnlTun);
2223 		}
2224 	}
2225 	///Updates automatic and manual pitchbend values (channel-assignable envelop, LFO, pitchbend CTRL) for 4 operators.
2226 	pragma(inline, true)
2227 	protected final void updatePitchbend4Op(ref Operator op0, ref Operator op1, ref Operator op2, ref Operator op3, 
2228 			ref Channel ch, ref ChControllers chCtrl) @nogc @safe pure nothrow {
2229 		if (!isClose(ch.preset.eegDetuneAm, 0.0, 0.1) || !isClose(ch.preset.pLFOlevel, 0.0, 0.01)
2230 				|| !isClose(chCtrl.pitchBend, 0.0, 0.01)) {
2231 			const float eegOut = ch.eeg.shp(ch.eeg.position == ADSREnvelopGenerator.Stage.Attack ? 
2232 					ch.preset.shpAX : ch.preset.shpRX);
2233 			const float vibrAm = pLFOOut * ch.preset.pLFOlevel * 
2234 					(ch.preset.chCtrl & ChCtrlFlags.MWToVibr ? chCtrl.modwheel : 1.0);
2235 			op0.setFrequency(intSlmpRate, chCtrl.note, chCtrl.pitchBend + (ch.preset.eegDetuneAm * eegOut) + vibrAm, 
2236 					ch.preset.chnlTun);
2237 			op1.setFrequency(intSlmpRate, chCtrl.note, chCtrl.pitchBend + (ch.preset.eegDetuneAm * eegOut) + vibrAm, 
2238 					ch.preset.chnlTun);
2239 			op2.setFrequency(intSlmpRate, chCtrl.note, chCtrl.pitchBend + (ch.preset.eegDetuneAm * eegOut) + vibrAm, 
2240 					ch.preset.chnlTun);
2241 			op3.setFrequency(intSlmpRate, chCtrl.note, chCtrl.pitchBend + (ch.preset.eegDetuneAm * eegOut) + vibrAm, 
2242 					ch.preset.chnlTun);
2243 		}
2244 	}
2245 	///Macro for channel update constants that need to be calculated once per frame
2246 	///Kept in at one place to make updates easier and more consistent
2247 	static immutable string CHNL_UPDATE_CONSTS =
2248 		q{
2249 			const int opOffset = chNum * 2;
2250 			__m128 aLFOOutMW = __m128(channels[chNum].preset.chCtrl & ChCtrlFlags.MWToTrem ? 
2251 					chCtrls[chNum].modwheel : 1.0);
2252 			const float auxSendAmMW = (channels[chNum].preset.chCtrl & ChCtrlFlags.MWToAux ? 
2253 					chCtrls[chNum].modwheel : 1.0);
2254 			__m128 opCtrl0 = __m128(0), opCtrl1 = __m128(0), mwAuxCtrl;
2255 			opCtrl0[0] = operators[opOffset].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 
2256 					chCtrls[chNum].velocity;
2257 			opCtrl1[0] = operators[opOffset + 1].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 
2258 					chCtrls[chNum].velocity;
2259 			opCtrl0[1] = operators[opOffset].preset.opCtrl & OpCtrlFlags.ExprToMW ? chCtrls[chNum].auxCtrl : 
2260 					chCtrls[chNum].modwheel;
2261 			opCtrl1[1] = operators[opOffset + 1].preset.opCtrl & OpCtrlFlags.ExprToMW ? chCtrls[chNum].auxCtrl : 
2262 					chCtrls[chNum].modwheel;
2263 			opCtrl0[1] = operators[opOffset].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - opCtrl0[1] : opCtrl0[1];
2264 			opCtrl1[1] = operators[opOffset + 1].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - opCtrl0[1] : opCtrl0[1];
2265 			mwAuxCtrl[0] = 1.0;
2266 			mwAuxCtrl[1] = 1.0;
2267 			mwAuxCtrl[2] = auxSendAmMW;
2268 			mwAuxCtrl[3] = auxSendAmMW;
2269 			const float lfopan = (channels[chNum].preset.chCtrl & ChCtrlFlags.LFOPan ? 1.0 : 0);
2270 			const float eegpan = (channels[chNum].preset.chCtrl & ChCtrlFlags.EEGPan ? 1.0 : 0);
2271 		};
2272 	///Macro for channel update constants that need to be calculated once per frame, for combined channels' second half
2273 	///Kept in at one place to make updates easier and more consistent
2274 	static immutable string CHNL_UPDATE_CONSTS0 =
2275 		q{
2276 			__m128 opCtrl2 = __m128(0), opCtrl3 = __m128(0);
2277 			opCtrl2[0] = operators[opOffset + 16].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 
2278 					chCtrls[chNum].velocity;
2279 			opCtrl3[0] = operators[opOffset + 17].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 
2280 					chCtrls[chNum].velocity;
2281 			opCtrl2[1] = operators[opOffset + 16].preset.opCtrl & OpCtrlFlags.ExprToMW ? chCtrls[chNum].auxCtrl : 
2282 					chCtrls[chNum].modwheel;
2283 			opCtrl3[1] = operators[opOffset + 17].preset.opCtrl & OpCtrlFlags.ExprToMW ? chCtrls[chNum].auxCtrl : 
2284 					chCtrls[chNum].modwheel;
2285 			opCtrl2[1] = operators[opOffset + 16].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - opCtrl0[1] : opCtrl0[1];
2286 			opCtrl3[1] = operators[opOffset + 17].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - opCtrl0[1] : opCtrl0[1];
2287 			const float eegpan0 = (channels[chNum + 8].preset.chCtrl & ChCtrlFlags.EEGPan ? 1.0 : 0);
2288 		};
2289 	///Macro for channel update constants that need to be calculated for each cycle
2290 	///Kept in at one place to make updates easier and more consistent
2291 	static immutable string CHNL_UPDATE_CONSTS_CYCL = 
2292 		q{
2293 			const float eegOut = channels[chNum].eeg.shp(channels[chNum].eeg.position == 
2294 					ADSREnvelopGenerator.Stage.Attack ? channels[chNum].preset.shpAX : channels[chNum].preset.shpRX);
2295 			__m128 eegToMast = __m128(eegOut), lfoToMast = __m128(aLFOBuf[i]);
2296 			eegToMast[0] = abs(eegpan - eegToMast[0]);
2297 			lfoToMast[0] = abs(lfopan - lfoToMast[0]);
2298 			opCtrl0[2] = aLFOBuf[i];
2299 			opCtrl1[2] = aLFOBuf[i];
2300 			opCtrl0[3] = eegOut;
2301 			opCtrl1[3] = eegOut;
2302 		};
2303 	
2304 	///Macro for channel update constants that need to be calculated for each cycle for combined channels' second half
2305 	///Kept in at one place to make updates easier and more consistent
2306 	static immutable string CHNL_UPDATE_CONSTS_CYCL0 = 
2307 		q{
2308 			const float eegOut0 = channels[chNum + 8].eeg.shp(channels[chNum + 8].eeg.position == 
2309 					ADSREnvelopGenerator.Stage.Attack ? channels[chNum + 8].preset.shpAX : 
2310 					channels[chNum + 8].preset.shpRX);
2311 			__m128 eegToMast0 = __m128(eegOut0);
2312 			eegToMast0[0] = abs(eegpan0 - eegToMast0[0]);
2313 			opCtrl2[2] = aLFOBuf[i];
2314 			opCtrl3[2] = aLFOBuf[i];
2315 			opCtrl2[3] = eegOut0;
2316 			opCtrl3[3] = eegOut0;
2317 		};
2318 			
2319 	///Macro for output mixing
2320 	static immutable string CHNL_UPDATE_MIX =
2321 		q{
2322 			__m128 outlevels = channels[chNum].outLevels * mwAuxCtrl;
2323 			outlevels *= (channels[chNum].preset.eegLevels * eegToMast) + (__m128(1.0) - channels[chNum].preset.eegLevels);
2324 			outlevels *= (channels[chNum].preset.aLFOlevels * lfoToMast) + (__m128(1.0) - channels[chNum].preset.aLFOlevels);
2325 			initBuffers[i + 2] += outlevels * outSum;
2326 		};
2327 	///Macro for output mixing in case of combo modes
2328 	static immutable string CHNL_UPDATE_MIX0 =
2329 		q{
2330 			__m128 outlevels = channels[chNum].outLevels * mwAuxCtrl;
2331 			outlevels *= (channels[chNum].preset.eegLevels * eegToMast) + (__m128(1.0) - channels[chNum].preset.eegLevels);
2332 			outlevels *= (channels[chNum + 8].preset.eegLevels * eegToMast0) + (__m128(1.0) - channels[chNum + 8].preset.eegLevels);
2333 			outlevels *= (channels[chNum].preset.aLFOlevels * lfoToMast) + (__m128(1.0) - channels[chNum].preset.aLFOlevels);
2334 			initBuffers[i + 2] += outlevels * outSum;
2335 		};
2336 	
2337 
2338 	///Algorithm Mode 0/0 (Serial)
2339 	protected void updateChannelM00(int chNum, size_t length) @nogc pure nothrow {
2340 		mixin(CHNL_UPDATE_CONSTS);
2341 		updatePitchbend2Op(operators[opOffset], operators[opOffset + 1], channels[chNum], chCtrls[chNum]);
2342 		for (size_t i ; i < length ; i++) {
2343 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2344 			updateOperator(operators[opOffset], opCtrl0);
2345 			operators[opOffset + 1].input = operators[opOffset].output_0;
2346 			updateOperator(operators[opOffset + 1], opCtrl1);
2347 			operators[opOffset].feedback += 
2348 				cast(int)(operators[opOffset + 1].output_0 * channels[chNum].preset.globalFb * 
2349 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2350 			__m128 outSum = _mm_min_ps(
2351 					_mm_max_ps(__m128(operators[opOffset + 1].output_0>>12), __m128(short.min)), __m128(short.max));
2352 			mixin(CHNL_UPDATE_MIX);
2353 			channels[chNum].eeg.advance();
2354 		}
2355 	}
2356 	///Algorithm Mode 0/1 (Parallel)
2357 	protected void updateChannelM01(int chNum, size_t length) @nogc pure nothrow {
2358 		mixin(CHNL_UPDATE_CONSTS);
2359 		updatePitchbend2Op(operators[opOffset], operators[opOffset + 1], channels[chNum], chCtrls[chNum]);
2360 		const int resMode = (channels[chNum].preset.chCtrl & ChCtrlFlags.ResMode) ? 1 : 0;
2361 		for (size_t i ; i < length ; i++) {
2362 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2363 			updateOperator(operators[opOffset], opCtrl0);
2364 			const double outCtrlOp1 = updateOperator(operators[opOffset + 1], opCtrl1);
2365 			//const int outSum = operators[opOffset].output_0 + operators[opOffset + 1].output_0;
2366 			const float outSum0 = (operators[opOffset].output_0 + operators[opOffset + 1].output_0)>>12;
2367 			const float outSum1 = ((cast(uint)(operators[opOffset].output - short.min) * 
2368 					cast(uint)(operators[opOffset + 1].output - short.min))>>16) * outCtrlOp1 + (operators[opOffset].output_0>>12);
2369 			//__m128 outSum = __m128((channels[chNum].preset.chCtrl & ChCtrlFlags.ResMode) ? outSum1 : outSum0);
2370 			__m128 outSum = _mm_min_ps(
2371 					_mm_max_ps(__m128((outSum1 * resMode) + (outSum0 * (1 - resMode))),__m128(short.min)), __m128(short.max));
2372 			mixin(CHNL_UPDATE_MIX);
2373 			channels[chNum].eeg.advance();
2374 		}
2375 	}
2376 	///Algorithm Mode1/00 ([S0]->[S1]->[P0]->[P1])
2377 	protected void updateChannelM100(int chNum, size_t length) @nogc pure nothrow {
2378 		mixin(CHNL_UPDATE_CONSTS);
2379 		mixin(CHNL_UPDATE_CONSTS0);
2380 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2381 				channels[chNum], chCtrls[chNum]);
2382 		for (size_t i ; i < length ; i++) {
2383 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2384 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2385 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2386 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2387 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2388 			operators[opOffset].input = operators[opOffset + 17].output_0;
2389 			updateOperator(operators[opOffset], opCtrl0);		//P0
2390 			operators[opOffset + 1].input = operators[opOffset].output_0;
2391 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2392 			operators[opOffset + 16].feedback += 
2393 				cast(int)(operators[opOffset + 1].output_0 * channels[chNum].preset.globalFb * 
2394 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2395 			__m128 outSum = _mm_min_ps(
2396 					_mm_max_ps(__m128(operators[opOffset + 1].output_0>>12), __m128(short.min)), __m128(short.max));
2397 			mixin(CHNL_UPDATE_MIX0);
2398 			channels[chNum].eeg.advance();
2399 			channels[chNum + 8].eeg.advance();
2400 		}
2401 	}
2402 	///Dummy algorithm for combined channels
2403 	protected void updateChannelMD(int chNum, size_t length) @nogc pure nothrow {
2404 
2405 	}
2406 	/**
2407 	Algorithm Mode1/10
2408 	[S0]\
2409     	 ->[P0]->[P1]->
2410 	[S1]/
2411 	*/
2412 	protected void updateChannelM110(int chNum, size_t length) @nogc pure nothrow {
2413 		mixin(CHNL_UPDATE_CONSTS);
2414 		mixin(CHNL_UPDATE_CONSTS0);
2415 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2416 				channels[chNum], chCtrls[chNum]);
2417 		for (size_t i ; i < length ; i++) {
2418 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2419 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2420 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2421 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2422 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2423 			operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
2424 			updateOperator(operators[opOffset], opCtrl0);		//P0
2425 			operators[opOffset + 1].input = operators[opOffset].output_0;
2426 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2427 			operators[opOffset + 16].feedback += 
2428 				cast(int)(operators[opOffset + 1].output_0 * channels[chNum].preset.globalFb * 
2429 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2430 			__m128 outSum = _mm_min_ps(
2431 					_mm_max_ps(__m128(operators[opOffset + 1].output_0>>12), __m128(short.min)), __m128(short.max));
2432 			mixin(CHNL_UPDATE_MIX0);
2433 			channels[chNum].eeg.advance();
2434 			channels[chNum + 8].eeg.advance();
2435 		}
2436 	}
2437 	/**
2438 	Algorithm Mode1/01
2439 	[S0]->[S1]->[P0]->
2440             	[P1]->
2441 	*/
2442 	protected void updateChannelM101(int chNum, size_t length) @nogc pure nothrow {
2443 		mixin(CHNL_UPDATE_CONSTS);
2444 		mixin(CHNL_UPDATE_CONSTS0);
2445 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2446 				channels[chNum], chCtrls[chNum]);
2447 		const int resMode = (channels[chNum].preset.chCtrl & ChCtrlFlags.ResMode) ? 1 : 0;
2448 		for (size_t i ; i < length ; i++) {
2449 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2450 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2451 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2452 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2453 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2454 			operators[opOffset].input = operators[opOffset + 17].output_0;
2455 			updateOperator(operators[opOffset], opCtrl0);		//P0
2456 			//operators[opOffset + 1].input = operators[opOffset].output_0;
2457 			const double outCtrlOp1 = updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2458 			//const int outSum = operators[opOffset + 1].output_0;
2459 			operators[opOffset + 16].feedback += 
2460 				cast(int)(operators[opOffset].output_0 * channels[chNum].preset.globalFb * 
2461 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2462 			const float outSum0 = (operators[opOffset].output_0 + operators[opOffset + 1].output_0)>>12;
2463 			const float outSum1 = ((cast(uint)(operators[opOffset].output - short.min) * 
2464 					cast(uint)(operators[opOffset + 1].output - short.min))>>16) * outCtrlOp1 + (operators[opOffset].output_0>>12);
2465 			//__m128 outSum = __m128((channels[chNum].preset.chCtrl & ChCtrlFlags.ResMode) ? outSum1 : outSum0);
2466 			__m128 outSum = _mm_min_ps(
2467 					_mm_max_ps(__m128((outSum1 * resMode) + (outSum0 * (1 - resMode))), __m128(short.min)), __m128(short.max));
2468 			mixin(CHNL_UPDATE_MIX0);
2469 			channels[chNum].eeg.advance();
2470 			channels[chNum + 8].eeg.advance();
2471 		}
2472 	}
2473 	/**
2474 	Algorithm Mode1/11
2475 	[S0]\
2476     	 ->[P0]->
2477 	[S1]/  [P1]->
2478 	*/
2479 	protected void updateChannelM111(int chNum, size_t length) @nogc pure nothrow {
2480 		mixin(CHNL_UPDATE_CONSTS);
2481 		mixin(CHNL_UPDATE_CONSTS0);
2482 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2483 				channels[chNum], chCtrls[chNum]);
2484 		const int resMode = (channels[chNum].preset.chCtrl & ChCtrlFlags.ResMode) ? 1 : 0;
2485 		for (size_t i ; i < length ; i++) {
2486 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2487 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2488 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2489 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2490 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2491 			operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
2492 			updateOperator(operators[opOffset], opCtrl0);		//P0
2493 			//operators[opOffset + 1].input = operators[opOffset].output_0;
2494 			const double outCtrlOp1 = updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2495 			//const int outSum = operators[opOffset + 1].output_0;
2496 			operators[opOffset + 16].feedback += 
2497 				cast(int)(operators[opOffset].output_0 * channels[chNum].preset.globalFb * 
2498 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2499 			const float outSum0 = (operators[opOffset].output_0 + operators[opOffset + 1].output_0)>>12;
2500 			const float outSum1 = ((cast(uint)(operators[opOffset].output - short.min) * 
2501 					cast(uint)(operators[opOffset + 1].output - short.min))>>16) * outCtrlOp1 + (operators[opOffset].output_0>>12);
2502 			//__m128 outSum = __m128((channels[chNum].preset.chCtrl & ChCtrlFlags.ResMode) ? outSum1 : outSum0);
2503 			__m128 outSum = _mm_min_ps(
2504 					_mm_max_ps(__m128((outSum1 * resMode) + (outSum0 * (1 - resMode))), __m128(short.min)), __m128(short.max));
2505 			mixin(CHNL_UPDATE_MIX0);
2506 			channels[chNum].eeg.advance();
2507 			channels[chNum + 8].eeg.advance();
2508 		}
2509 	}
2510 	/**
2511 	Algorithm Mode2/00
2512 	[S0]->[S1]\
2513 	           ->[P1]->
2514     	  [P0]/
2515 	*/
2516 	protected void updateChannelM200(int chNum, size_t length) @nogc pure nothrow {
2517 		mixin(CHNL_UPDATE_CONSTS);
2518 		mixin(CHNL_UPDATE_CONSTS0);
2519 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2520 				channels[chNum], chCtrls[chNum]);
2521 		for (size_t i ; i < length ; i++) {
2522 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2523 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2524 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2525 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2526 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2527 			//operators[opOffset].input = operators[opOffset + 17].output_0;
2528 			updateOperator(operators[opOffset], opCtrl0);		//P0
2529 			operators[opOffset + 1].input = operators[opOffset].output_0 + operators[opOffset + 17].output_0;
2530 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2531 			//const int outSum = operators[opOffset + 1].output_0;
2532 			operators[opOffset + 16].feedback += 
2533 				cast(int)(operators[opOffset + 1].output_0 * channels[chNum].preset.globalFb * 
2534 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2535 			__m128 outSum = _mm_min_ps(
2536 					_mm_max_ps(__m128(operators[opOffset + 1].output_0>>12), __m128(short.min)), __m128(short.max));
2537 			mixin(CHNL_UPDATE_MIX0);
2538 			channels[chNum].eeg.advance();
2539 			channels[chNum + 8].eeg.advance();
2540 		}
2541 	}
2542 	/**
2543 	Algorithm Mode2/10
2544 	[S0]\
2545 	[S1]-->[P1]->
2546 	[P0]/
2547 	*/
2548 	protected void updateChannelM210(int chNum, size_t length) @nogc pure nothrow {
2549 		mixin(CHNL_UPDATE_CONSTS);
2550 		mixin(CHNL_UPDATE_CONSTS0);
2551 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2552 				channels[chNum], chCtrls[chNum]);
2553 		for (size_t i ; i < length ; i++) {
2554 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2555 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2556 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2557 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2558 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2559 			//operators[opOffset].input = operators[opOffset + 17].output_0;
2560 			updateOperator(operators[opOffset], opCtrl0);		//P0
2561 			operators[opOffset + 1].input = operators[opOffset].output_0 + operators[opOffset + 17].output_0 + 
2562 					operators[opOffset + 16].output_0;
2563 			const double outCtrlOp1 = updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2564 			operators[opOffset + 16].feedback += 
2565 				cast(int)(operators[opOffset + 1].output_0 * channels[chNum].preset.globalFb * 
2566 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2567 			//const int outSum = operators[opOffset + 1].output_0;
2568 			__m128 outSum = _mm_min_ps(
2569 					_mm_max_ps(__m128(operators[opOffset + 1].output_0>>12), __m128(short.min)), __m128(short.max));
2570 			mixin(CHNL_UPDATE_MIX0);
2571 			channels[chNum].eeg.advance();
2572 			channels[chNum + 8].eeg.advance();
2573 		}
2574 	}
2575 	/**
2576 	Algorithm Mode2/01
2577 	          /[P0]->
2578 	[S0]->[S1]
2579     	      \[P1]->
2580 	*/
2581 	protected void updateChannelM201(int chNum, size_t length) @nogc pure nothrow {
2582 		mixin(CHNL_UPDATE_CONSTS);
2583 		mixin(CHNL_UPDATE_CONSTS0);
2584 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2585 				channels[chNum], chCtrls[chNum]);
2586 		for (size_t i ; i < length ; i++) {
2587 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2588 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2589 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2590 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2591 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2592 			operators[opOffset].input = operators[opOffset + 17].output_0;
2593 			updateOperator(operators[opOffset], opCtrl0);		//P0
2594 			operators[opOffset + 1].input = operators[opOffset + 17].output_0;
2595 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2596 			//const int outSum = operators[opOffset + 1].output_0;
2597 			operators[opOffset + 16].feedback += 
2598 				cast(int)(operators[opOffset].output_0 * channels[chNum].preset.globalFb * 
2599 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2600 			__m128 outSum = _mm_min_ps(_mm_max_ps(
2601 					__m128((operators[opOffset + 1].output_0 + operators[opOffset].output_0)>>12), __m128(short.min)), 
2602 					__m128(short.max));
2603 			mixin(CHNL_UPDATE_MIX0);
2604 			channels[chNum].eeg.advance();
2605 			channels[chNum + 8].eeg.advance();
2606 		}
2607 	}
2608 	/**
2609 	Algorithm Mode2/11
2610 	[S0]\ /[P0]->
2611 	     -
2612 	[S1]/ \[P1]->
2613 	*/
2614 	protected void updateChannelM211(int chNum, size_t length) @nogc pure nothrow {
2615 		mixin(CHNL_UPDATE_CONSTS);
2616 		mixin(CHNL_UPDATE_CONSTS0);
2617 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2618 				channels[chNum], chCtrls[chNum]);
2619 		for (size_t i ; i < length ; i++) {
2620 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2621 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2622 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2623 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2624 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2625 			operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
2626 			updateOperator(operators[opOffset], opCtrl0);		//P0
2627 			operators[opOffset + 1].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0;
2628 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2629 			//const int outSum = operators[opOffset + 1].output_0;
2630 			operators[opOffset + 16].feedback += 
2631 				cast(int)(operators[opOffset].output_0 * channels[chNum].preset.globalFb * 
2632 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2633 			__m128 outSum = _mm_min_ps(
2634 					_mm_max_ps(__m128((operators[opOffset + 1].output_0 + operators[opOffset].output_0)>>12), __m128(short.min)), 
2635 					__m128(short.max));
2636 			mixin(CHNL_UPDATE_MIX0);
2637 			channels[chNum].eeg.advance();
2638 			channels[chNum + 8].eeg.advance();
2639 		}
2640 	}
2641 	/**
2642 	Algorithm Mode3/00
2643 	[S0]->[S1]->
2644 	[P0]->[P1]->
2645 	*/
2646 	protected void updateChannelM300(int chNum, size_t length) @nogc pure nothrow {
2647 		mixin(CHNL_UPDATE_CONSTS);
2648 		mixin(CHNL_UPDATE_CONSTS0);
2649 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2650 				channels[chNum], chCtrls[chNum]);
2651 		for (size_t i ; i < length ; i++) {
2652 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2653 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2654 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2655 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2656 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2657 			//operators[opOffset].input = operators[opOffset + 17].output_0;
2658 			updateOperator(operators[opOffset], opCtrl0);		//P0
2659 			operators[opOffset + 1].input = operators[opOffset].output_0;
2660 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2661 			//const int outSum = operators[opOffset + 1].output_0;
2662 			operators[opOffset + 16].feedback += 
2663 				cast(int)(operators[opOffset + 17].output_0 * channels[chNum].preset.globalFb * 
2664 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2665 			__m128 outSum = _mm_min_ps(
2666 					_mm_max_ps(__m128((operators[opOffset + 1].output_0 + operators[opOffset + 17].output_0)>>12), __m128(short.min)), 
2667 					__m128(short.max));
2668 			mixin(CHNL_UPDATE_MIX0);
2669 			channels[chNum].eeg.advance();
2670 			channels[chNum + 8].eeg.advance();
2671 		}
2672 	}
2673 	/**
2674 	Algorithm Mode3/10
2675 	      [S0]->
2676     	  [S1]->
2677 	[P0]->[P1]->
2678 	*/
2679 	protected void updateChannelM310(int chNum, size_t length) @nogc pure nothrow {
2680 		mixin(CHNL_UPDATE_CONSTS);
2681 		mixin(CHNL_UPDATE_CONSTS0);
2682 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2683 				channels[chNum], chCtrls[chNum]);
2684 		const int resMode = (channels[chNum].preset.chCtrl & ChCtrlFlags.ResMode) ? 1 : 0;
2685 		const int resSrc = (channels[chNum].preset.chCtrl & ChCtrlFlags.ResSrc) ? 1 : 0;
2686 		for (size_t i ; i < length ; i++) {
2687 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2688 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2689 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2690 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2691 			const double outCtrlOp1 = updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2692 			//operators[opOffset].input = operators[opOffset + 17].output_0;
2693 			updateOperator(operators[opOffset], opCtrl0);		//P0
2694 			operators[opOffset + 1].input = operators[opOffset].output_0;
2695 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2696 			//const int outSum = operators[opOffset + 1].output_0;
2697 			operators[opOffset].feedback += 
2698 				cast(int)(operators[opOffset + 1].output_0 * channels[chNum].preset.globalFb * 
2699 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2700 			const float outSum0 = (operators[opOffset + 1].output_0 + operators[opOffset + 17].output_0 + 
2701 					operators[opOffset + 16].output_0)>>12;
2702 			/* const float outSum1 = ((cast(uint)(((channels[chNum].preset.chCtrl & ChCtrlFlags.ResSrc) ? operators[opOffset].output :
2703 					operators[opOffset + 16].output) - short.min) * 
2704 					cast(uint)(operators[opOffset + 17].output - short.min))>>16) * outCtrlOp1 + 
2705 					operators[opOffset + 1].output_0 + operators[opOffset + 16].output_0; */
2706 			const float outSum1 = ((cast(uint)(((resSrc * operators[opOffset + 1].output) + 
2707 					(operators[opOffset + 16].output * (1 - resSrc))) - short.min) * 
2708 					cast(uint)(operators[opOffset + 17].output - short.min))>>16) * outCtrlOp1 + 
2709 					((operators[opOffset + 1].output_0 + operators[opOffset + 16].output_0)>>12);
2710 			__m128 outSum = _mm_min_ps(
2711 					_mm_max_ps(__m128((outSum1 * resMode) + (outSum0 * (1 - resMode))), __m128(short.min)), __m128(short.max));
2712 			//__m128 outSum = __m128((channels[chNum].preset.chCtrl & ChCtrlFlags.ResMode) ? outSum1 : outSum0);
2713 			/* __m128 outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset + 17].output_0 + 
2714 					operators[opOffset + 16].output_0); */
2715 			mixin(CHNL_UPDATE_MIX0);
2716 			channels[chNum].eeg.advance();
2717 			channels[chNum + 8].eeg.advance();
2718 		}
2719 	}
2720 	/**
2721 	Algorithm Mode3/01
2722 	    />[S1]->
2723 	[S0]->[P0]->
2724     	\>[P1]->
2725 	*/
2726 	protected void updateChannelM301(int chNum, size_t length) @nogc pure nothrow {
2727 		mixin(CHNL_UPDATE_CONSTS);
2728 		mixin(CHNL_UPDATE_CONSTS0);
2729 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2730 				channels[chNum], chCtrls[chNum]);
2731 		for (size_t i ; i < length ; i++) {
2732 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2733 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2734 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2735 			operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2736 			updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2737 			operators[opOffset].input = operators[opOffset + 16].output_0;
2738 			updateOperator(operators[opOffset], opCtrl0);		//P0
2739 			operators[opOffset + 1].input = operators[opOffset + 16].output_0;
2740 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2741 			//const int outSum = operators[opOffset + 1].output_0;
2742 			operators[opOffset + 16].feedback += 
2743 				cast(int)(operators[opOffset + 17].output_0 * channels[chNum].preset.globalFb * 
2744 				(channels[chNum].preset.chCtrl & ChCtrlFlags.FBMode ? eegOut : 1));
2745 			__m128 outSum = _mm_min_ps(
2746 					_mm_max_ps(__m128((operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 
2747 					operators[opOffset + 17].output_0)>>12), __m128(short.min)), __m128(short.max));
2748 			mixin(CHNL_UPDATE_MIX0);
2749 			channels[chNum].eeg.advance();
2750 			channels[chNum + 8].eeg.advance();
2751 		}
2752 	}
2753 	/**
2754 	Algorithm Mode3/11
2755 	[S0]->
2756 	[S1]->
2757 	[P0]->
2758 	[P1]->
2759 	*/
2760 	protected void updateChannelM311(int chNum, size_t length) @nogc pure nothrow {
2761 		mixin(CHNL_UPDATE_CONSTS);
2762 		mixin(CHNL_UPDATE_CONSTS0);
2763 		updatePitchbend4Op(operators[opOffset], operators[opOffset + 1], operators[opOffset + 16], operators[opOffset + 17], 
2764 				channels[chNum], chCtrls[chNum]);
2765 		const int resMode = (channels[chNum].preset.chCtrl & ChCtrlFlags.ResMode) ? 1 : 0;
2766 		for (size_t i ; i < length ; i++) {
2767 			mixin(CHNL_UPDATE_CONSTS_CYCL);
2768 			mixin(CHNL_UPDATE_CONSTS_CYCL0);
2769 			updateOperator(operators[opOffset + 16], opCtrl2);	//S0
2770 			//operators[opOffset + 17].input = operators[opOffset + 16].output_0;
2771 			const double outCtrlOp1 = updateOperator(operators[opOffset + 17], opCtrl3);	//S1
2772 			//operators[opOffset].input = operators[opOffset + 17].output_0;
2773 			updateOperator(operators[opOffset], opCtrl0);		//P0
2774 			//operators[opOffset + 1].input = operators[opOffset].output_0;
2775 			updateOperator(operators[opOffset + 1], opCtrl1);	//P1
2776 			//const int outSum = operators[opOffset + 1].output_0;
2777 			const float outSum0 = (operators[opOffset].output_0 + operators[opOffset + 1].output_0 +
2778 					operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0)>>12;
2779 			const float outSum1 = ((operators[opOffset].output_0 + operators[opOffset + 1].output_0)>>12) +
2780 					((cast(uint)(operators[opOffset + 16].output - short.min) * 
2781 					cast(uint)(operators[opOffset + 17].output - short.min))>>16) * outCtrlOp1 + 
2782 					(operators[opOffset + 17].output_0>>12);
2783 			__m128 outSum = _mm_min_ps(
2784 					_mm_max_ps(__m128((outSum1 * resMode) + (outSum0 * (1 - resMode))), __m128(short.min)), __m128(short.max));
2785 			//__m128 outSum = __m128((channels[chNum].preset.chCtrl & ChCtrlFlags.ResMode) ? outSum1 : outSum0);
2786 			mixin(CHNL_UPDATE_MIX0);
2787 			channels[chNum].eeg.advance();
2788 			channels[chNum + 8].eeg.advance();
2789 		}
2790 	}
2791 
2792 	/**
2793 	 * Restores a parameter to the given preset.
2794 	 * Returns an errorcode on failure.
2795 	 */
2796 	public override int writeParam_int(uint presetID, uint paramID, int value) nothrow {
2797 		const ubyte bankNum = cast(ubyte)(presetID>>7), presetNum = cast(ubyte)(presetID & 127);
2798 		switch (paramID) {
2799 			//op0 begin
2800 			case hashCalc(`op0_Attack`):
2801 				if (value >=0 && value <= 127) {
2802 					soundBank[bankNum][presetNum].operators[0].atk = cast(ubyte)value;
2803 					return 0;
2804 				}
2805 				break;
2806 			case hashCalc(`op0_Decay`):
2807 				if (value >=0 && value <= 127) {
2808 					soundBank[bankNum][presetNum].operators[0].dec = cast(ubyte)value;
2809 					return 0;
2810 				}
2811 				break;
2812 			case hashCalc(`op0_SusCtrl`):
2813 				if (value >=0 && value <= 127) {
2814 					soundBank[bankNum][presetNum].operators[0].susCC = cast(ubyte)value;
2815 					return 0;
2816 				}
2817 				break;
2818 			case hashCalc(`op0_Release`):
2819 				if (value >=0 && value <= 127) {
2820 					soundBank[bankNum][presetNum].operators[0].rel = cast(ubyte)value;
2821 					return 0;
2822 				}
2823 				break;
2824 			case hashCalc(`op0_Waveform`):
2825 				if (value >=0 && value <= 127) {
2826 					soundBank[bankNum][presetNum].operators[0].opCtrl &= ~OpCtrlFlags.WavetableSelect;
2827 					soundBank[bankNum][presetNum].operators[0].opCtrl |= cast(ubyte)value;
2828 					return 0;
2829 				}
2830 				break;
2831 			case hashCalc(`op0_TuneCor`):
2832 				if (value >=0 && value <= 127) {
2833 					soundBank[bankNum][presetNum].operators[0].opCtrl &= ~TuneCtrlFlags.CorTuneTest;
2834 					soundBank[bankNum][presetNum].operators[0].opCtrl |= (cast(ubyte)value)<<25;
2835 					return 0;
2836 				}
2837 				break;
2838 			case hashCalc(`op0_KSLBegin`):
2839 				if (value >=0 && value <= 255) {
2840 					soundBank[bankNum][presetNum].operators[0].kslBegin = cast(ubyte)value;
2841 					return 0;
2842 				}
2843 				break;
2844 			case hashCalc(`op0_KSLAttenOut`):
2845 				if (value >=0 && value <= 255) {
2846 					soundBank[bankNum][presetNum].operators[0].kslAttenOut = cast(ubyte)value;
2847 					return 0;
2848 				}
2849 				break;
2850 			case hashCalc(`op0_KSLAttenFB`):
2851 				if (value >=0 && value <= 255) {
2852 					soundBank[bankNum][presetNum].operators[1].kslAttenFB = cast(ubyte)value;
2853 					return 0;
2854 				}
2855 				break;
2856 			case hashCalc(`op0_KSLAttenADSR`):
2857 				if (value >=0 && value <= 255) {
2858 					soundBank[bankNum][presetNum].operators[1].kslAttenADSR = cast(ubyte)value;
2859 					return 0;
2860 				}
2861 				break;
2862 			//op0 end
2863 
2864 			//op1 begin
2865 			case hashCalc(`op1_Attack`):
2866 				if (value >=0 && value <= 127) {
2867 					soundBank[bankNum][presetNum].operators[1].atk = cast(ubyte)value;
2868 					return 0;
2869 				}
2870 				break;
2871 			case hashCalc(`op1_Decay`):
2872 				if (value >=0 && value <= 127) {
2873 					soundBank[bankNum][presetNum].operators[1].dec = cast(ubyte)value;
2874 					return 0;
2875 				}
2876 				break;
2877 			case hashCalc(`op1_SusCtrl`):
2878 				if (value >=0 && value <= 127) {
2879 					soundBank[bankNum][presetNum].operators[1].susCC = cast(ubyte)value;
2880 					return 0;
2881 				}
2882 				break;
2883 			case hashCalc(`op1_Release`):
2884 				if (value >=0 && value <= 127) {
2885 					soundBank[bankNum][presetNum].operators[1].rel = cast(ubyte)value;
2886 					return 0;
2887 				}
2888 				break;
2889 			case hashCalc(`op1_Waveform`):
2890 				if (value >=0 && value <= 127) {
2891 					soundBank[bankNum][presetNum].operators[1].opCtrl &= ~OpCtrlFlags.WavetableSelect;
2892 					soundBank[bankNum][presetNum].operators[1].opCtrl |= cast(ubyte)value;
2893 					return 0;
2894 				}
2895 				break;
2896 			case hashCalc(`op1_TuneCor`):
2897 				if (value >=0 && value <= 127) {
2898 					soundBank[bankNum][presetNum].operators[1].opCtrl &= ~TuneCtrlFlags.CorTuneTest;
2899 					soundBank[bankNum][presetNum].operators[1].opCtrl |= (cast(ubyte)value)<<25;
2900 					return 0;
2901 				}
2902 				break;
2903 			case hashCalc(`op1_KSLBegin`):
2904 				if (value >=0 && value <= 255) {
2905 					soundBank[bankNum][presetNum].operators[1].kslBegin = cast(ubyte)value;
2906 					return 0;
2907 				}
2908 				break;
2909 			case hashCalc(`op1_KSLAttenOut`):
2910 				if (value >=0 && value <= 255) {
2911 					soundBank[bankNum][presetNum].operators[1].kslAttenOut = cast(ubyte)value;
2912 					return 0;
2913 				}
2914 				break;
2915 			case hashCalc(`op1_KSLAttenFB`):
2916 				if (value >=0 && value <= 255) {
2917 					soundBank[bankNum][presetNum].operators[1].kslAttenFB = cast(ubyte)value;
2918 					return 0;
2919 				}
2920 				break;
2921 			case hashCalc(`op1_KSLAttenADSR`):
2922 				if (value >=0 && value <= 255) {
2923 					soundBank[bankNum][presetNum].operators[1].kslAttenADSR = cast(ubyte)value;
2924 					return 0;
2925 				}
2926 				break;
2927 			//op1 end
2928 
2929 			//op0 flags begin
2930 			case hashCalc(`op0f_FBMode`):
2931 				if (value == 0) {
2932 					soundBank[bankNum][presetNum].operators[0].opCtrl &= ~OpCtrlFlags.FBMode;
2933 				} else {
2934 					soundBank[bankNum][presetNum].operators[0].opCtrl |= OpCtrlFlags.FBMode;
2935 				}
2936 				return 0;
2937 			case hashCalc(`op0f_FBNeg`):
2938 				if (value == 0) {
2939 					soundBank[bankNum][presetNum].operators[0].opCtrl &= ~OpCtrlFlags.FBNeg;
2940 				} else {
2941 					soundBank[bankNum][presetNum].operators[0].opCtrl |= OpCtrlFlags.FBNeg;
2942 				}
2943 				return 0;
2944 			case hashCalc(`op0f_MWNeg`):
2945 				if (value == 0) {
2946 					soundBank[bankNum][presetNum].operators[0].opCtrl &= ~OpCtrlFlags.MWNeg;
2947 				} else {
2948 					soundBank[bankNum][presetNum].operators[0].opCtrl |= OpCtrlFlags.MWNeg;
2949 				}
2950 				return 0;
2951 			case hashCalc(`op0f_VelNeg`):
2952 				if (value == 0) {
2953 					soundBank[bankNum][presetNum].operators[0].opCtrl &= ~OpCtrlFlags.VelNeg;
2954 				} else {
2955 					soundBank[bankNum][presetNum].operators[0].opCtrl |= OpCtrlFlags.VelNeg;
2956 				}
2957 				return 0;
2958 			case hashCalc(`op0f_EGRelAdaptive`):
2959 				if (value == 0) {
2960 					soundBank[bankNum][presetNum].operators[0].opCtrl &= ~OpCtrlFlags.EGRelAdaptive;
2961 				} else {
2962 					soundBank[bankNum][presetNum].operators[0].opCtrl |= OpCtrlFlags.EGRelAdaptive;
2963 				}
2964 				return 0;
2965 			case hashCalc(`op0f_FixedPitch`):
2966 				if (value == 0) {
2967 					soundBank[bankNum][presetNum].operators[0].opCtrl &= ~OpCtrlFlags.FixedPitch;
2968 				} else {
2969 					soundBank[bankNum][presetNum].operators[0].opCtrl |= OpCtrlFlags.FixedPitch;
2970 				}
2971 				return 0;
2972 			case hashCalc(`op0f_EasyTune`):
2973 				if (value == 0) {
2974 					soundBank[bankNum][presetNum].operators[0].opCtrl &= ~OpCtrlFlags.EasyTune;
2975 				} else {
2976 					soundBank[bankNum][presetNum].operators[0].opCtrl |= OpCtrlFlags.EasyTune;
2977 				}
2978 				return 0;
2979 			case hashCalc(`op0f_ContiTune`):
2980 				if (value == 0) {
2981 					soundBank[bankNum][presetNum].operators[0].opCtrl &= ~OpCtrlFlags.ContiTune;
2982 				} else {
2983 					soundBank[bankNum][presetNum].operators[0].opCtrl |= OpCtrlFlags.ContiTune;
2984 				}
2985 				return 0;
2986 			case hashCalc(`op0f_ExprToMW`):
2987 				if (value == 0) {
2988 					soundBank[bankNum][presetNum].operators[0].opCtrl &= ~OpCtrlFlags.ExprToMW;
2989 				} else {
2990 					soundBank[bankNum][presetNum].operators[0].opCtrl |= OpCtrlFlags.ExprToMW;
2991 				}
2992 				return 0;
2993 			//op0 flags end
2994 
2995 			//op1 flags begin
2996 			case hashCalc(`op1f_FBMode`):
2997 				if (value == 0) {
2998 					soundBank[bankNum][presetNum].operators[1].opCtrl &= ~OpCtrlFlags.FBMode;
2999 				} else {
3000 					soundBank[bankNum][presetNum].operators[1].opCtrl |= OpCtrlFlags.FBMode;
3001 				}
3002 				return 0;
3003 			case hashCalc(`op1f_FBNeg`):
3004 				if (value == 0) {
3005 					soundBank[bankNum][presetNum].operators[1].opCtrl &= ~OpCtrlFlags.FBNeg;
3006 				} else {
3007 					soundBank[bankNum][presetNum].operators[1].opCtrl |= OpCtrlFlags.FBNeg;
3008 				}
3009 				return 0;
3010 			case hashCalc(`op1f_MWNeg`):
3011 				if (value == 0) {
3012 					soundBank[bankNum][presetNum].operators[1].opCtrl &= ~OpCtrlFlags.MWNeg;
3013 				} else {
3014 					soundBank[bankNum][presetNum].operators[1].opCtrl |= OpCtrlFlags.MWNeg;
3015 				}
3016 				return 0;
3017 			case hashCalc(`op1f_VelNeg`):
3018 				if (value == 0) {
3019 					soundBank[bankNum][presetNum].operators[1].opCtrl &= ~OpCtrlFlags.VelNeg;
3020 				} else {
3021 					soundBank[bankNum][presetNum].operators[1].opCtrl |= OpCtrlFlags.VelNeg;
3022 				}
3023 				return 0;
3024 			case hashCalc(`op1f_EGRelAdaptive`):
3025 				if (value == 0) {
3026 					soundBank[bankNum][presetNum].operators[1].opCtrl &= ~OpCtrlFlags.EGRelAdaptive;
3027 				} else {
3028 					soundBank[bankNum][presetNum].operators[1].opCtrl |= OpCtrlFlags.EGRelAdaptive;
3029 				}
3030 				return 0;
3031 			case hashCalc(`op1f_FixedPitch`):
3032 				if (value == 0) {
3033 					soundBank[bankNum][presetNum].operators[1].opCtrl &= ~OpCtrlFlags.FixedPitch;
3034 				} else {
3035 					soundBank[bankNum][presetNum].operators[1].opCtrl |= OpCtrlFlags.FixedPitch;
3036 				}
3037 				return 0;
3038 			case hashCalc(`op1f_EasyTune`):
3039 				if (value == 0) {
3040 					soundBank[bankNum][presetNum].operators[1].opCtrl &= ~OpCtrlFlags.EasyTune;
3041 				} else {
3042 					soundBank[bankNum][presetNum].operators[1].opCtrl |= OpCtrlFlags.EasyTune;
3043 				}
3044 				return 0;
3045 			case hashCalc(`op1f_ContiTune`):
3046 				if (value == 0) {
3047 					soundBank[bankNum][presetNum].operators[1].opCtrl &= ~OpCtrlFlags.ContiTune;
3048 				} else {
3049 					soundBank[bankNum][presetNum].operators[1].opCtrl |= OpCtrlFlags.ContiTune;
3050 				}
3051 				return 0;
3052 			case hashCalc(`op1f_ExprToMW`):
3053 				if (value == 0) {
3054 					soundBank[bankNum][presetNum].operators[1].opCtrl &= ~OpCtrlFlags.ExprToMW;
3055 				} else {
3056 					soundBank[bankNum][presetNum].operators[1].opCtrl |= OpCtrlFlags.ExprToMW;
3057 				}
3058 				return 0;
3059 			//op1 flags end
3060 
3061 			//ch begin
3062 			case hashCalc(`ch_Attack`):
3063 				if (value >=0 && value <= 127) {
3064 					soundBank[bankNum][presetNum].channel.atkX = cast(ubyte)value;
3065 					return 0;
3066 				}
3067 				break;
3068 			case hashCalc(`ch_Decay`):
3069 				if (value >=0 && value <= 127) {
3070 					soundBank[bankNum][presetNum].channel.decX = cast(ubyte)value;
3071 					return 0;
3072 				}
3073 				break;
3074 			case hashCalc(`ch_SusCtrl`):
3075 				if (value >=0 && value <= 127) {
3076 					soundBank[bankNum][presetNum].channel.susCCX = cast(ubyte)value;
3077 					return 0;
3078 				}
3079 				break;
3080 			case hashCalc(`ch_Release`):
3081 				if (value >=0 && value <= 127) {
3082 					soundBank[bankNum][presetNum].channel.relX = cast(ubyte)value;
3083 					return 0;
3084 				}
3085 				break;
3086 			//ch end
3087 
3088 			//ch flags begins
3089 			case hashCalc(`chf_ComboMode`):
3090 				if (value >= 0 && value <=3) {
3091 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.ComboModeTest;
3092 					soundBank[bankNum][presetNum].channel.chCtrl |= value;
3093 					return 0;
3094 				}
3095 				break;
3096 			case hashCalc(`chf_Algorithm`):
3097 				if (value == 0) {
3098 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.Algorithm;
3099 				} else {
3100 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.Algorithm;
3101 				}
3102 				return 0;
3103 			case hashCalc(`chf_IndivOutChLev`):
3104 				if (value == 0) {
3105 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.IndivOutChLev;
3106 				} else {
3107 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.IndivOutChLev;
3108 				}
3109 				return 0;
3110 			case hashCalc(`chf_LFOPan`):
3111 				if (value == 0) {
3112 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.LFOPan;
3113 				} else {
3114 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.LFOPan;
3115 				}
3116 				return 0;
3117 			case hashCalc(`chf_EEGPan`):
3118 				if (value == 0) {
3119 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.EEGPan;
3120 				} else {
3121 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.EEGPan;
3122 				}
3123 				return 0;
3124 			case hashCalc(`chf_MWToTrem`):
3125 				if (value == 0) {
3126 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.MWToTrem;
3127 				} else {
3128 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.MWToTrem;
3129 				}
3130 				return 0;
3131 			case hashCalc(`chf_MWToVibr`):
3132 				if (value == 0) {
3133 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.MWToVibr;
3134 				} else {
3135 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.MWToVibr;
3136 				}
3137 				return 0;
3138 			case hashCalc(`chf_MWToAux`):
3139 				if (value == 0) {
3140 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.MWToAux;
3141 				} else {
3142 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.MWToAux;
3143 				}
3144 				return 0;
3145 			case hashCalc(`chf_ResetOnKeyOn`):
3146 				if (value == 0) {
3147 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.ResetOnKeyOn;
3148 				} else {
3149 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.ResetOnKeyOn;
3150 				}
3151 				return 0;
3152 			case hashCalc(`chf_ResetMode`):
3153 				if (value == 0) {
3154 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.ResetMode;
3155 				} else {
3156 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.ResetMode;
3157 				}
3158 				return 0;
3159 			case hashCalc(`chf_FBMode`):
3160 				if (value == 0) {
3161 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.FBMode;
3162 				} else {
3163 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.FBMode;
3164 				}
3165 				return 0;
3166 			case hashCalc(`chf_FBNeg`):
3167 				if (value == 0) {
3168 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.FBNeg;
3169 				} else {
3170 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.FBNeg;
3171 				}
3172 				return 0;
3173 			case hashCalc(`chf_ResMode`):
3174 				if (value == 0) {
3175 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.ResMode;
3176 				} else {
3177 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.ResMode;
3178 				}
3179 				return 0;
3180 			case hashCalc(`chf_ResSrc`):
3181 				if (value == 0) {
3182 					soundBank[bankNum][presetNum].channel.chCtrl &= ~ChCtrlFlags.ResSrc;
3183 				} else {
3184 					soundBank[bankNum][presetNum].channel.chCtrl |= ChCtrlFlags.ResSrc;
3185 				}
3186 				return 0;
3187 			//ch flags end
3188 
3189 			//common values begin
3190 			case hashCalc(`_PLFOWF`):
3191 				if (value >=0 && value <= 127){
3192 					lfoWaveform[0] = cast(ubyte)value;
3193 					return 0;
3194 				}
3195 				break;
3196 			case hashCalc(`_ALFOWF`):
3197 				if (value >=0 && value <= 127) {
3198 					lfoWaveform[1] &= 0b1000_0000;
3199 					lfoWaveform[1] |= cast(ubyte)value;
3200 					return 0;
3201 				}
3202 				break;
3203 			case hashCalc(`_Ringmod`):
3204 				if (value == 0)
3205 					lfoWaveform[1] &= 0b0111_1111;
3206 				else
3207 					lfoWaveform[1] |= 0b1000_0000;
3208 				return 0;
3209 			//common values end
3210 			default:
3211 				return 1;
3212 		}
3213 		return 2;
3214 	}
3215 	/**
3216 	 * Restores a parameter to the given preset.
3217 	 * Returns an errorcode on failure.
3218 	 */
3219 	public override int writeParam_long(uint presetID, uint paramID, long value) nothrow {
3220 		const ubyte bankNum = cast(ubyte)(presetID>>7), presetNum = cast(ubyte)(presetID & 127);
3221 		switch (paramID) {
3222 			//case hashCalc(`op0_Tune`):break;
3223 			case hashCalc(`op0_OpCtrl`):
3224 				soundBank[bankNum][presetNum].operators[0].opCtrl = cast(uint)value;
3225 				break;
3226 
3227 			//case hashCalc(`op1_Tune`):break;
3228 			case hashCalc(`op1_OpCtrl`):
3229 				soundBank[bankNum][presetNum].operators[1].opCtrl = cast(uint)value;
3230 				break;
3231 
3232 			case hashCalc(`ch_ChCtrl`):
3233 				soundBank[bankNum][presetNum].channel.chCtrl = cast(uint)value;
3234 				break;
3235 			default:
3236 				return 1;
3237 		}
3238 		return 0;
3239 	}
3240 	/**
3241 	 * Restores a parameter to the given preset.
3242 	 * Returns an errorcode on failure.
3243 	 */
3244 	public override int writeParam_double(uint presetID, uint paramID, double value) nothrow {
3245 		const ubyte bankNum = cast(ubyte)(presetID>>7), presetNum = cast(ubyte)(presetID & 127);
3246 		switch (paramID) {
3247 			//op0 begin
3248 			case hashCalc(`op0_Level`):
3249 				if (value >= 0 && value <= 1) {
3250 					soundBank[bankNum][presetNum].operators[0].outL = value;
3251 					return 0;
3252 				}
3253 				break;
3254 			case hashCalc(`op0_SusLevel`):
3255 				if (value >= 0 && value <= 1) {
3256 					soundBank[bankNum][presetNum].operators[0].susLevel = value;
3257 					return 0;
3258 				}
3259 				break;
3260 			case hashCalc(`op0_Feedback`):
3261 				if (value >= 0 && value <= 1) {
3262 					soundBank[bankNum][presetNum].operators[0].fbL = value;
3263 					return 0;
3264 				}
3265 				break;
3266 			case hashCalc(`op0_Tune`):
3267 				soundBank[bankNum][presetNum].operators[0].tune = value;
3268 				
3269 				return 0;
3270 			//case hashCalc(`op0_FreqRate`):break;
3271 			case hashCalc(`op0_ShpA`):
3272 				if (value >= 0 && value <= 1) {
3273 					soundBank[bankNum][presetNum].operators[0].shpA = value;
3274 					return 0;
3275 				}
3276 				break;
3277 			case hashCalc(`op0_ShpR`):
3278 				if (value >= 0 && value <= 1) {
3279 					soundBank[bankNum][presetNum].operators[0].shpR = value;
3280 					return 0;
3281 				}
3282 				break;
3283 			case hashCalc(`op0_VelToLevel`):
3284 				if (value >= 0 && value <= 1) {
3285 					soundBank[bankNum][presetNum].operators[0].outLCtrl[0] = value;
3286 					return 0;
3287 				}
3288 				break;
3289 			case hashCalc(`op0_MWToLevel`):
3290 				if (value >= 0 && value <= 1) {
3291 					soundBank[bankNum][presetNum].operators[0].outLCtrl[1] = value;
3292 					return 0;
3293 				}
3294 				break;
3295 			case hashCalc(`op0_LFOToLevel`):
3296 				if (value >= 0 && value <= 1) {
3297 					soundBank[bankNum][presetNum].operators[0].outLCtrl[2] = value;
3298 					return 0;
3299 				}
3300 				break;
3301 			case hashCalc(`op0_VelToFB`):
3302 				if (value >= 0 && value <= 1) {
3303 					soundBank[bankNum][presetNum].operators[0].fbLCtrl[0] = value;
3304 					return 0;
3305 				}
3306 				break;
3307 			case hashCalc(`op0_MWToFB`):
3308 				if (value >= 0 && value <= 1) {
3309 					soundBank[bankNum][presetNum].operators[0].fbLCtrl[1] = value;
3310 					return 0;
3311 				}
3312 				break;
3313 			case hashCalc(`op0_LFOToFB`):
3314 				if (value >= 0 && value <= 1) {
3315 					soundBank[bankNum][presetNum].operators[0].fbLCtrl[2] = value;
3316 					return 0;
3317 				}
3318 				break;
3319 			case hashCalc(`op0_EEGToFB`):
3320 				if (value >= 0 && value <= 1) {
3321 					soundBank[bankNum][presetNum].operators[0].fbLCtrl[3] = value;
3322 					return 0;
3323 				}
3324 				break;
3325 			case hashCalc(`op0_VelToShpA`):
3326 				if (value >= 0 && value <= 1) {
3327 					soundBank[bankNum][presetNum].operators[0].shpAVel = value;
3328 					return 0;
3329 				}
3330 				break;
3331 			case hashCalc(`op0_VelToShpR`):
3332 				if (value >= 0 && value <= 1) {
3333 					soundBank[bankNum][presetNum].operators[0].shpRVel = value;
3334 					return 0;
3335 				}
3336 				break;
3337 			//op0 end
3338 
3339 			//op1 begin
3340 			case hashCalc(`op1_Level`):
3341 				if (value >= 0 && value <= 1) {
3342 					soundBank[bankNum][presetNum].operators[1].outL = value;
3343 					return 0;
3344 				}
3345 				break;
3346 			case hashCalc(`op1_SusLevel`):
3347 				if (value >= 0 && value <= 1) {
3348 					soundBank[bankNum][presetNum].operators[1].susLevel = value;
3349 					return 0;
3350 				}
3351 				break;
3352 			case hashCalc(`op1_Feedback`):
3353 				if (value >= 0 && value <= 1) {
3354 					soundBank[bankNum][presetNum].operators[1].fbL = value;
3355 					return 0;
3356 				}
3357 				break;
3358 			case hashCalc(`op1_Tune`):
3359 				soundBank[bankNum][presetNum].operators[1].tune = value;
3360 				
3361 				return 0;
3362 			//case hashCalc(`op1_FreqRate`):break;
3363 			case hashCalc(`op1_ShpA`):
3364 				if (value >= 0 && value <= 1) {
3365 					soundBank[bankNum][presetNum].operators[1].shpA = value;
3366 					return 0;
3367 				}
3368 				break;
3369 			case hashCalc(`op1_ShpR`):
3370 				if (value >= 0 && value <= 1) {
3371 					soundBank[bankNum][presetNum].operators[1].shpR = value;
3372 					return 0;
3373 				}
3374 				break;
3375 			case hashCalc(`op1_VelToLevel`):
3376 				if (value >= 0 && value <= 1) {
3377 					soundBank[bankNum][presetNum].operators[1].outLCtrl[0] = value;
3378 					return 0;
3379 				}
3380 				break;
3381 			case hashCalc(`op1_MWToLevel`):
3382 				if (value >= 0 && value <= 1) {
3383 					soundBank[bankNum][presetNum].operators[1].outLCtrl[1] = value;
3384 					return 0;
3385 				}
3386 				break;
3387 			case hashCalc(`op1_LFOToLevel`):
3388 				if (value >= 0 && value <= 1) {
3389 					soundBank[bankNum][presetNum].operators[1].outLCtrl[2] = value;
3390 					return 0;
3391 				}
3392 				break;
3393 			case hashCalc(`op1_VelToFB`):
3394 				if (value >= 0 && value <= 1) {
3395 					soundBank[bankNum][presetNum].operators[1].fbLCtrl[0] = value;
3396 					return 0;
3397 				}
3398 				break;
3399 			case hashCalc(`op1_MWToFB`):
3400 				if (value >= 0 && value <= 1) {
3401 					soundBank[bankNum][presetNum].operators[1].fbLCtrl[1] = value;
3402 					return 0;
3403 				}
3404 				break;
3405 			case hashCalc(`op1_LFOToFB`):
3406 				if (value >= 0 && value <= 1) {
3407 					soundBank[bankNum][presetNum].operators[1].fbLCtrl[2] = value;
3408 					return 0;
3409 				}
3410 				break;
3411 			case hashCalc(`op1_EEGToFB`):
3412 				if (value >= 0 && value <= 1) {
3413 					soundBank[bankNum][presetNum].operators[1].fbLCtrl[3] = value;
3414 					return 0;
3415 				}
3416 				break;
3417 			case hashCalc(`op1_VelToShpA`):
3418 				if (value >= 0 && value <= 1) {
3419 					soundBank[bankNum][presetNum].operators[1].shpAVel = value;
3420 					return 0;
3421 				}
3422 				break;
3423 			case hashCalc(`op1_VelToShpR`):
3424 				if (value >= 0 && value <= 1) {
3425 					soundBank[bankNum][presetNum].operators[1].shpRVel = value;
3426 					return 0;
3427 				}
3428 				break;
3429 			//op1 end
3430 
3431 			//ch begin
3432 			case hashCalc(`ch_MasterVol`):
3433 				if (value >= 0 && value <= 1) {
3434 					soundBank[bankNum][presetNum].channel.masterVol = value;
3435 					return 0;
3436 				}
3437 				break;
3438 			case hashCalc(`ch_Bal`):
3439 				if (value >= 0 && value <= 1) {
3440 					soundBank[bankNum][presetNum].channel.masterBal = value;
3441 					return 0;
3442 				}
3443 				break;
3444 			case hashCalc(`ch_AuxSLA`):
3445 				if (value >= 0 && value <= 1) {
3446 					soundBank[bankNum][presetNum].channel.auxSendA = value;
3447 					return 0;
3448 				}
3449 				break;
3450 			case hashCalc(`ch_AuxSLB`):
3451 				if (value >= 0 && value <= 1) {
3452 					soundBank[bankNum][presetNum].channel.auxSendB = value;
3453 					return 0;
3454 				}
3455 				break;
3456 			case hashCalc(`ch_EEGDetune`):
3457 				soundBank[bankNum][presetNum].channel.eegDetuneAm = value;
3458 				return 0;
3459 			case hashCalc(`ch_PitchBendSens`):
3460 				soundBank[bankNum][presetNum].channel.pitchBendSens = value;
3461 				return 0;
3462 			case hashCalc(`ch_Tune`):
3463 				soundBank[bankNum][presetNum].channel.chnlTun = value;
3464 				return 0;
3465 			case hashCalc(`ch_PLFO`):
3466 				soundBank[bankNum][presetNum].channel.pLFOlevel = value;
3467 				return 0;
3468 			case hashCalc(`ch_SusLevel`):
3469 				if (value >= 0 && value <= 1) {
3470 					soundBank[bankNum][presetNum].channel.susLevel = value;
3471 					return 0;
3472 				}
3473 				break;
3474 			case hashCalc(`ch_ShpA`):
3475 				if (value >= 0 && value <= 1) {
3476 					soundBank[bankNum][presetNum].channel.shpAX = value;
3477 					return 0;
3478 				}
3479 				break;
3480 			case hashCalc(`ch_ShpR`):
3481 				if (value >= 0 && value <= 1) {
3482 					soundBank[bankNum][presetNum].channel.shpRX = value;
3483 					return 0;
3484 				}
3485 				break;
3486 			case hashCalc(`ch_GlobalFB`):
3487 				if (value >= 0 && value <= 1) {
3488 					soundBank[bankNum][presetNum].channel.globalFb = value;
3489 					return 0;
3490 				}
3491 				break;
3492 			case hashCalc(`ch_EEGToLeft`):
3493 				if (value >= 0 && value <= 1) {
3494 					soundBank[bankNum][presetNum].channel.eegLevels[0] = value;
3495 					return 0;
3496 				}
3497 				break;
3498 			case hashCalc(`ch_EEGToRight`):
3499 				if (value >= 0 && value <= 1) {
3500 					soundBank[bankNum][presetNum].channel.eegLevels[1] = value;
3501 					return 0;
3502 				}
3503 				break;
3504 			case hashCalc(`ch_EEGToAuxA`):
3505 				if (value >= 0 && value <= 1) {
3506 					soundBank[bankNum][presetNum].channel.eegLevels[2] = value;
3507 					return 0;
3508 				}
3509 				break;
3510 			case hashCalc(`ch_EEGToAuxB`):
3511 				if (value >= 0 && value <= 1) {
3512 					soundBank[bankNum][presetNum].channel.eegLevels[3] = value;
3513 					return 0;
3514 				}
3515 				break;
3516 			case hashCalc(`ch_LFOToLeft`):
3517 				if (value >= 0 && value <= 1) {
3518 					soundBank[bankNum][presetNum].channel.aLFOlevels[0] = value;
3519 					return 0;
3520 				}
3521 				break;
3522 			case hashCalc(`ch_LFOToRight`):
3523 				if (value >= 0 && value <= 1) {
3524 					soundBank[bankNum][presetNum].channel.aLFOlevels[1] = value;
3525 					return 0;
3526 				}
3527 				break;
3528 			case hashCalc(`ch_LFOToAuxA`):
3529 				if (value >= 0 && value <= 1) {
3530 					soundBank[bankNum][presetNum].channel.aLFOlevels[2] = value;
3531 					return 0;
3532 				}
3533 				break;
3534 			case hashCalc(`ch_LFOToAuxB`):
3535 				if (value >= 0 && value <= 1) {
3536 					soundBank[bankNum][presetNum].channel.aLFOlevels[3] = value;
3537 					return 0;
3538 				}
3539 				break;
3540 			case hashCalc(`ch_MWToGFB`):
3541 				if (value >= 0 && value <= 1) {
3542 					soundBank[bankNum][presetNum].channel.mwToGFB = value;
3543 					return 0;
3544 				}
3545 				break;
3546 			case hashCalc(`ch_VelToGFB`):
3547 				if (value >= 0 && value <= 1) {
3548 					soundBank[bankNum][presetNum].channel.velToGFB = value;
3549 					return 0;
3550 				}
3551 				break;
3552 			//ch end
3553 
3554 			//commons begin
3555 			case hashCalc(`_PLFORate`):
3556 				pLFOFreq = value;
3557 				setPLFO();
3558 				return 0;
3559 			case hashCalc(`_ALFORate`):
3560 				aLFOFreq = value;
3561 				setALFO();
3562 				return 0;
3563 			case hashCalc(`_FilterLCFreq`):
3564 				filterCtrl[0] = value;
3565 				resetLPF(0);
3566 				return 0;
3567 			case hashCalc(`_FilterLCQ`):
3568 				filterCtrl[1] = value;
3569 				resetLPF(0);
3570 				return 0;
3571 			case hashCalc(`_FilterRCFreq`):
3572 				filterCtrl[2] = value;
3573 				resetLPF(1);
3574 				return 0;
3575 			case hashCalc(`_FilterRCQ`):
3576 				filterCtrl[3] = value;
3577 				resetLPF(1);
3578 				return 0;
3579 			case hashCalc(`_FilterACFreq`):
3580 				filterCtrl[4] = value;
3581 				resetLPF(2);
3582 				return 0;
3583 			case hashCalc(`_FilterACQ`):
3584 				filterCtrl[5] = value;
3585 				resetLPF(2);
3586 				return 0;
3587 			case hashCalc(`_FilterBCFreq`):
3588 				filterCtrl[6] = value;
3589 				resetLPF(3);
3590 				return 0;
3591 			case hashCalc(`_FilterBCQ`):
3592 				filterCtrl[7] = value;
3593 				resetLPF(3);
3594 				return 0;
3595 			case hashCalc(`_HPFLCFreq`):
3596 				hpfCtrl[0] = value;
3597 				resetHPF(0);
3598 				return 0;
3599 			case hashCalc(`_HPFLCQ`):
3600 				hpfCtrl[1] = value;
3601 				resetHPF(0);
3602 				return 0;
3603 			case hashCalc(`_HPFRCFreq`):
3604 				hpfCtrl[2] = value;
3605 				resetHPF(1);
3606 				return 0;
3607 			case hashCalc(`_HPFRCQ`):
3608 				hpfCtrl[3] = value;
3609 				resetHPF(1);
3610 				return 0;
3611 			case hashCalc(`_HPFACFreq`):
3612 				hpfCtrl[4] = value;
3613 				resetHPF(2);
3614 				return 0;
3615 			case hashCalc(`_HPFACQ`):
3616 				hpfCtrl[5] = value;
3617 				resetHPF(2);
3618 				return 0;
3619 			case hashCalc(`_HPFBCFreq`):
3620 				hpfCtrl[6] = value;
3621 				resetHPF(3);
3622 				return 0;
3623 			case hashCalc(`_HPFBCQ`):
3624 				hpfCtrl[6] = value;
3625 				resetHPF(3);
3626 				return 0;
3627 			//commons end
3628 			default:
3629 				return 1;
3630 		}
3631 		return 2;
3632 	}
3633 	/**
3634 	 * Restores a parameter to the given preset.
3635 	 * Returns an errorcode on failure.
3636 	 */
3637 	public override int writeParam_string(uint presetID, uint paramID, string value) nothrow {
3638 		return 0;
3639 	}
3640 	/** 
3641 	 * Returns all the possible parameters this module has.
3642 	 */
3643 	public override MValue[] getParameters() nothrow {
3644 		return [
3645 			MValue(MValueType.Float,`op0_Level`), MValue(MValueType.Int32,`op0_Attack`), MValue(MValueType.Int32,`op0_Decay`), 
3646 			MValue(MValueType.Float,`op0_SusLevel`), MValue(MValueType.Int32,`op0_SusCtrl`), 
3647 			MValue(MValueType.Int32,`op0_Release`), MValue(MValueType.Int32,`op0_Waveform`), 
3648 			MValue(MValueType.Float,`op0_Feedback`), MValue(MValueType.Int32,`op0_TuneCor`), 
3649 			MValue(MValueType.Float,`op0_Tune`), MValue(MValueType.Float,`op0_ShpA`),
3650 			MValue(MValueType.Float,`op0_ShpR`), MValue(MValueType.Float,`op0_VelToLevel`), 
3651 			MValue(MValueType.Float,`op0_MWToLevel`), MValue(MValueType.Float,`op0_LFOToLevel`), 
3652 			MValue(MValueType.Int64,`op0_OpCtrl`), MValue(MValueType.Float,`op0_VelToFB`), MValue(MValueType.Float,`op0_MWToFB`), 
3653 			MValue(MValueType.Float,`op0_LFOToFB`), MValue(MValueType.Float,`op0_EEGToFB`),
3654 			MValue(MValueType.Float,`op0_VelToShpA`), MValue(MValueType.Float,`op0_VelToShpR`), 
3655 			MValue(MValueType.Int32,`op0_KSLBegin`), MValue(MValueType.Int32,`op0_KSLAttenOut`), 
3656 			MValue(MValueType.Int32,`op0_KSLAttenFB`), MValue(MValueType.Int32,`op0_KSLAttenADSR`),
3657 
3658 			MValue(MValueType.Boolean,`op0f_FBMode`), MValue(MValueType.Boolean,`op0f_FBNeg`), 
3659 			MValue(MValueType.Boolean,`op0f_MWNeg`), MValue(MValueType.Boolean,`op0f_VelNeg`), 
3660 			MValue(MValueType.Boolean,`op0f_EGRelAdaptive`), MValue(MValueType.Boolean,`op0f_FixedPitch`),
3661 			MValue(MValueType.Boolean,`op0f_EasyTune`), MValue(MValueType.Boolean,`op0f_ContiTune`),
3662 			MValue(MValueType.Boolean,`op0f_ExprToMW`),
3663 
3664 			MValue(MValueType.Float,`op1_Level`), MValue(MValueType.Int32,`op1_Attack`), MValue(MValueType.Int32,`op1_Decay`), 
3665 			MValue(MValueType.Float,`op1_SusLevel`), MValue(MValueType.Int32,`op1_SusCtrl`), 
3666 			MValue(MValueType.Int32,`op1_Release`), MValue(MValueType.Int32,`op1_Waveform`), 
3667 			MValue(MValueType.Float,`op1_Feedback`), MValue(MValueType.Int32,`op1_TuneCor`), 
3668 			MValue(MValueType.Float,`op1_Tune`), MValue(MValueType.Float,`op1_ShpA`),
3669 			MValue(MValueType.Float,`op1_ShpR`), MValue(MValueType.Float,`op1_VelToLevel`), 
3670 			MValue(MValueType.Float,`op1_MWToLevel`), MValue(MValueType.Float,`op1_LFOToLevel`), 
3671 			MValue(MValueType.Int64,`op1_OpCtrl`), MValue(MValueType.Float,`op1_VelToFB`), MValue(MValueType.Float,`op1_MWToFB`), 
3672 			MValue(MValueType.Float,`op1_LFOToFB`), MValue(MValueType.Float,`op1_EEGToFB`),
3673 			MValue(MValueType.Float,`op1_VelToShpA`), MValue(MValueType.Float,`op1_VelToShpR`), 
3674 			MValue(MValueType.Int32,`op1_KSLBegin`), MValue(MValueType.Int32,`op1_KSLAttenOut`), 
3675 			MValue(MValueType.Int32,`op1_KSLAttenFB`), MValue(MValueType.Int32,`op1_KSLAttenADSR`),
3676 
3677 			MValue(MValueType.Boolean,`op1f_FBMode`), MValue(MValueType.Boolean,`op1f_FBNeg`),
3678 			MValue(MValueType.Boolean,`op1f_MWNeg`), MValue(MValueType.Boolean,`op1f_VelNeg`),
3679 			MValue(MValueType.Boolean,`op1f_EGRelAdaptive`), MValue(MValueType.Boolean,`op1f_FixedPitch`),
3680 			MValue(MValueType.Boolean,`op1f_EasyTune`), MValue(MValueType.Boolean,`op1f_ContiTune`),
3681 			MValue(MValueType.Boolean,`op1f_ExprToMW`),
3682 
3683 			MValue(MValueType.Float,`ch_MasterVol`), MValue(MValueType.Float,`ch_Bal`), MValue(MValueType.Float,`ch_AuxSLA`),
3684 			MValue(MValueType.Float,`ch_AuxSLB`), MValue(MValueType.Float,`ch_EEGDetune`), MValue(MValueType.Float,`ch_PLFO`),
3685 			MValue(MValueType.Int32,`ch_Attack`), MValue(MValueType.Int32,`ch_Decay`), MValue(MValueType.Float,`ch_SusLevel`),
3686 			MValue(MValueType.Int32,`ch_SusCtrl`), MValue(MValueType.Int32,`ch_Release`), MValue(MValueType.Float,`ch_ShpA`),
3687 			MValue(MValueType.Float,`ch_ShpR`), MValue(MValueType.Float,`ch_GlobalFB`), MValue(MValueType.Int64,`ch_ChCtrl`),
3688 			MValue(MValueType.Float,`ch_EEGToLeft`), MValue(MValueType.Float,`ch_EEGToRight`), 
3689 			MValue(MValueType.Float,`ch_EEGToAuxA`), MValue(MValueType.Float,`ch_EEGToAuxB`), 
3690 			MValue(MValueType.Float,`ch_LFOToLeft`), MValue(MValueType.Float,`ch_LFOToRight`),
3691 			MValue(MValueType.Float,`ch_LFOToAuxA`), MValue(MValueType.Float,`ch_LFOToAuxB`),
3692 			MValue(MValueType.Float,`ch_MWToGFB`), MValue(MValueType.Float,`ch_VelToGFB`),
3693 
3694 			MValue(MValueType.Int32,`chf_ComboMode`), MValue(MValueType.Boolean,`chf_Algorithm`),
3695 			MValue(MValueType.Boolean,`chf_IndivOutChLev`), MValue(MValueType.Boolean,`chf_LFOPan`),
3696 			MValue(MValueType.Boolean,`chf_EEGPan`), MValue(MValueType.Boolean,`chf_MWToTrem`), 
3697 			MValue(MValueType.Boolean,`chf_MWToVibr`), MValue(MValueType.Boolean,`chf_MWToAux`),
3698 			MValue(MValueType.Boolean,`chf_ResetOnKeyOn`), MValue(MValueType.Boolean,`chf_ResetMode`),
3699 			MValue(MValueType.Boolean,`chf_FBMode`), MValue(MValueType.Boolean,`chf_FBNeg`),
3700 			MValue(MValueType.Boolean,`chf_ResMode`), MValue(MValueType.Boolean,`chf_ResSrc`),
3701 
3702 			MValue(MValueType.Float,`_PLFORate`), MValue(MValueType.Int32,`_PLFOWF`),
3703 			MValue(MValueType.Float,`_ALFORate`), MValue(MValueType.Int32,`_ALFOWF`),
3704 			MValue(MValueType.Float,`_FilterLCFreq`),MValue(MValueType.Float,`_FilterLCQ`),
3705 			MValue(MValueType.Float,`_FilterRCFreq`),MValue(MValueType.Float,`_FilterRCQ`),
3706 			MValue(MValueType.Float,`_FilterACFreq`),MValue(MValueType.Float,`_FilterACQ`),
3707 			MValue(MValueType.Float,`_FilterBCFreq`),MValue(MValueType.Float,`_FilterBCQ`),
3708 			MValue(MValueType.Float,`_HPFLCFreq`),MValue(MValueType.Float,`_HPFLCQ`),
3709 			MValue(MValueType.Float,`_HPFRCFreq`),MValue(MValueType.Float,`_HPFRCQ`),
3710 			MValue(MValueType.Float,`_HPFACFreq`),MValue(MValueType.Float,`_HPFACQ`),
3711 			MValue(MValueType.Float,`_HPFBCFreq`),MValue(MValueType.Float,`_HPFBCQ`),
3712 			MValue(MValueType.Boolean,`_Ringmod`),
3713 			];
3714 	}
3715 	/** 
3716 	 * Reads the given value (int).
3717 	 * Params:
3718 	 *   presetID = The preset ID, or uint.max for global module values.
3719 	 *   paramID = The parameter ID.
3720 	 * Returns: The value of the given preset and parameter
3721 	 */
3722 	public override int readParam_int(uint presetID, uint paramID) nothrow {
3723 		const ubyte bankNum = cast(ubyte)(presetID>>7), presetNum = cast(ubyte)(presetID & 127);
3724 		switch (paramID) {
3725 			//op0 begin
3726 			case hashCalc(`op0_Attack`):
3727 				return soundBank[bankNum][presetNum].operators[0].atk;
3728 			case hashCalc(`op0_Decay`):
3729 				return soundBank[bankNum][presetNum].operators[0].dec;
3730 			case hashCalc(`op0_SusCtrl`):
3731 				return soundBank[bankNum][presetNum].operators[0].susCC;
3732 			case hashCalc(`op0_Release`):
3733 				return soundBank[bankNum][presetNum].operators[0].rel;
3734 			case hashCalc(`op0_Waveform`):
3735 				return soundBank[bankNum][presetNum].operators[0].opCtrl & OpCtrlFlags.WavetableSelect;
3736 			case hashCalc(`op0_TuneCor`):
3737 				return (soundBank[bankNum][presetNum].operators[0].opCtrl & TuneCtrlFlags.CorTuneTest)>>>25;
3738 			case hashCalc(`op0_KSLBegin`):
3739 				return soundBank[bankNum][presetNum].operators[0].kslBegin;
3740 			case hashCalc(`op0_KSLAttenOut`):
3741 				return soundBank[bankNum][presetNum].operators[0].kslAttenOut;
3742 			case hashCalc(`op0_KSLAttenFB`):
3743 				return soundBank[bankNum][presetNum].operators[1].kslAttenFB;
3744 			case hashCalc(`op0_KSLAttenADSR`):
3745 				return soundBank[bankNum][presetNum].operators[1].kslAttenADSR;
3746 			//op0 end
3747 
3748 			//op1 begin
3749 			case hashCalc(`op1_Attack`):
3750 				return soundBank[bankNum][presetNum].operators[1].atk;
3751 			case hashCalc(`op1_Decay`):
3752 				return soundBank[bankNum][presetNum].operators[1].dec;
3753 			case hashCalc(`op1_SusCtrl`):
3754 				return soundBank[bankNum][presetNum].operators[1].susCC;
3755 			case hashCalc(`op1_Release`):
3756 				return soundBank[bankNum][presetNum].operators[1].rel;
3757 			case hashCalc(`op1_Waveform`):
3758 				return soundBank[bankNum][presetNum].operators[1].opCtrl & OpCtrlFlags.WavetableSelect;
3759 			case hashCalc(`op1_TuneCor`):
3760 				return (soundBank[bankNum][presetNum].operators[1].opCtrl & TuneCtrlFlags.CorTuneTest)>>25;
3761 			case hashCalc(`op1_KSLBegin`):
3762 				return soundBank[bankNum][presetNum].operators[1].kslBegin;
3763 			case hashCalc(`op1_KSLAttenOut`):
3764 				return soundBank[bankNum][presetNum].operators[1].kslAttenOut;
3765 			case hashCalc(`op1_KSLAttenFB`):
3766 				return soundBank[bankNum][presetNum].operators[1].kslAttenFB;
3767 			case hashCalc(`op1_KSLAttenADSR`):
3768 				return soundBank[bankNum][presetNum].operators[1].kslAttenADSR;
3769 			//op1 end
3770 
3771 			//op0 flags begin
3772 			case hashCalc(`op0f_FBMode`):
3773 				return (soundBank[bankNum][presetNum].operators[0].opCtrl & OpCtrlFlags.FBMode) ? 1 : 0;
3774 			case hashCalc(`op0f_FBNeg`):
3775 				return (soundBank[bankNum][presetNum].operators[0].opCtrl & OpCtrlFlags.FBNeg) ? 1 : 0;
3776 			case hashCalc(`op0f_MWNeg`):
3777 				return (soundBank[bankNum][presetNum].operators[0].opCtrl & OpCtrlFlags.MWNeg) ? 1 : 0;
3778 			case hashCalc(`op0f_VelNeg`):
3779 				return (soundBank[bankNum][presetNum].operators[0].opCtrl & OpCtrlFlags.VelNeg) ? 1 : 0;
3780 			case hashCalc(`op0f_EGRelAdaptive`):
3781 				return (soundBank[bankNum][presetNum].operators[0].opCtrl & OpCtrlFlags.EGRelAdaptive) ? 1 : 0;
3782 			case hashCalc(`op0f_FixedPitch`):
3783 				return (soundBank[bankNum][presetNum].operators[0].opCtrl & OpCtrlFlags.FixedPitch) ? 1 : 0;
3784 			case hashCalc(`op0f_EasyTune`):
3785 				return (soundBank[bankNum][presetNum].operators[0].opCtrl & OpCtrlFlags.EasyTune) ? 1 : 0;
3786 			case hashCalc(`op0f_ContiTune`):
3787 				return (soundBank[bankNum][presetNum].operators[0].opCtrl & OpCtrlFlags.ContiTune) ? 1 : 0;
3788 			case hashCalc(`op0f_ExprToMW`):
3789 				return (soundBank[bankNum][presetNum].operators[0].opCtrl & OpCtrlFlags.ExprToMW) ? 1 : 0;
3790 			//op0 flags end
3791 
3792 			//op1 flags begin
3793 			case hashCalc(`op1f_FBMode`):
3794 				return (soundBank[bankNum][presetNum].operators[1].opCtrl & OpCtrlFlags.FBMode) ? 1 : 0;
3795 			case hashCalc(`op1f_FBNeg`):
3796 				return (soundBank[bankNum][presetNum].operators[1].opCtrl & OpCtrlFlags.FBNeg) ? 1 : 0;
3797 			case hashCalc(`op1f_MWNeg`):
3798 				return (soundBank[bankNum][presetNum].operators[1].opCtrl & OpCtrlFlags.MWNeg) ? 1 : 0;
3799 			case hashCalc(`op1f_VelNeg`):
3800 				return (soundBank[bankNum][presetNum].operators[1].opCtrl & OpCtrlFlags.VelNeg) ? 1 : 0;
3801 			case hashCalc(`op1f_EGRelAdaptive`):
3802 				return (soundBank[bankNum][presetNum].operators[1].opCtrl & OpCtrlFlags.EGRelAdaptive) ? 1 : 0;
3803 			case hashCalc(`op1f_FixedPitch`):
3804 				return (soundBank[bankNum][presetNum].operators[1].opCtrl & OpCtrlFlags.FixedPitch) ? 1 : 0;
3805 			case hashCalc(`op1f_EasyTune`):
3806 				return (soundBank[bankNum][presetNum].operators[1].opCtrl & OpCtrlFlags.EasyTune) ? 1 : 0;
3807 			case hashCalc(`op1f_ContiTune`):
3808 				return (soundBank[bankNum][presetNum].operators[1].opCtrl & OpCtrlFlags.ContiTune) ? 1 : 0;
3809 			case hashCalc(`op1f_ExprToMW`):
3810 				return (soundBank[bankNum][presetNum].operators[1].opCtrl & OpCtrlFlags.ExprToMW) ? 1 : 0;
3811 			//op1 flags end
3812 
3813 			//ch begin
3814 			case hashCalc(`ch_Attack`):
3815 				return soundBank[bankNum][presetNum].channel.atkX;
3816 			case hashCalc(`ch_Decay`):
3817 				return soundBank[bankNum][presetNum].channel.decX;
3818 			case hashCalc(`ch_SusCtrl`):
3819 				return soundBank[bankNum][presetNum].channel.susCCX;
3820 			case hashCalc(`ch_Release`):
3821 				return soundBank[bankNum][presetNum].channel.relX;
3822 			//ch end
3823 
3824 			//ch flags begins
3825 			case hashCalc(`chf_ComboMode`):
3826 				return soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.ComboModeTest;
3827 			case hashCalc(`chf_Algorithm`):
3828 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.Algorithm) ? 1 : 0;
3829 			case hashCalc(`chf_IndivOutChLev`):
3830 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.IndivOutChLev) ? 1 : 0;
3831 			case hashCalc(`chf_LFOPan`):
3832 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.LFOPan) ? 1 : 0;
3833 			case hashCalc(`chf_EEGPan`):
3834 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.EEGPan) ? 1 : 0;
3835 			case hashCalc(`chf_MWToTrem`):
3836 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.MWToTrem) ? 1 : 0;
3837 			case hashCalc(`chf_MWToVibr`):
3838 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.MWToVibr) ? 1 : 0;
3839 			case hashCalc(`chf_MWToAux`):
3840 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.MWToAux) ? 1 : 0;
3841 			case hashCalc(`chf_ResetOnKeyOn`):
3842 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.ResetOnKeyOn) ? 1 : 0;
3843 			case hashCalc(`chf_ResetMode`):
3844 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.ResetMode) ? 1 : 0;
3845 			case hashCalc(`chf_FBMode`):
3846 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.FBMode) ? 1 : 0;
3847 			case hashCalc(`chf_FBNeg`):
3848 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.FBNeg) ? 1 : 0;
3849 			case hashCalc(`chf_ResMode`):
3850 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.ResMode) ? 1 : 0;
3851 			case hashCalc(`chf_ResSrc`):
3852 				return (soundBank[bankNum][presetNum].channel.chCtrl & ChCtrlFlags.ResSrc) ? 1 : 0;
3853 			//ch flags end
3854 
3855 			//common values begin
3856 			case hashCalc(`_PLFOWF`):
3857 				return lfoWaveform[0];
3858 			case hashCalc(`_ALFOWF`):
3859 				return lfoWaveform[1] & 0b0111_1111;
3860 			case hashCalc(`_Ringmod`):
3861 				return (lfoWaveform[1] & 0b1000_0000) ? 1 : 0;
3862 			//common values end
3863 			default:
3864 				return 0;
3865 		}
3866 	}
3867 	/** 
3868 	 * Reads the given value (int).
3869 	 * Params:
3870 	 *   presetID = The preset ID, or uint.max for global module values.
3871 	 *   paramID = The parameter ID.
3872 	 * Returns: The value of the given preset and parameter
3873 	 */
3874 	public override long readParam_long(uint presetID, uint paramID) nothrow {
3875 		const ubyte bankNum = cast(ubyte)(presetID>>7), presetNum = cast(ubyte)(presetID & 127);
3876 		switch (paramID) {
3877 			//case hashCalc(`op0_Tune`):break;
3878 			case hashCalc(`op0_OpCtrl`):
3879 				return soundBank[bankNum][presetNum].operators[0].opCtrl;
3880 
3881 			//case hashCalc(`op1_Tune`):break;
3882 			case hashCalc(`op1_OpCtrl`):
3883 				return soundBank[bankNum][presetNum].operators[1].opCtrl;
3884 
3885 			case hashCalc(`ch_ChCtrl`):
3886 				return soundBank[bankNum][presetNum].channel.chCtrl;
3887 			default:
3888 				return 0;
3889 		}
3890 	}
3891 	/** 
3892 	 * Reads the given value (int).
3893 	 * Params:
3894 	 *   presetID = The preset ID, or uint.max for global module values.
3895 	 *   paramID = The parameter ID.
3896 	 * Returns: The value of the given preset and parameter
3897 	 */
3898 	public override double readParam_double(uint presetID, uint paramID) nothrow {
3899 		const ubyte bankNum = cast(ubyte)(presetID>>7), presetNum = cast(ubyte)(presetID & 127);
3900 		switch (paramID) {
3901 			//op0 begin
3902 			case hashCalc(`op0_Level`):
3903 				return soundBank[bankNum][presetNum].operators[0].outL;
3904 			case hashCalc(`op0_SusLevel`):
3905 				return soundBank[bankNum][presetNum].operators[0].susLevel;
3906 			case hashCalc(`op0_Feedback`):
3907 				return soundBank[bankNum][presetNum].operators[0].fbL;
3908 			case hashCalc(`op0_Tune`):
3909 				return soundBank[bankNum][presetNum].operators[0].tune;
3910 			//case hashCalc(`op0_FreqRate`):break;
3911 			case hashCalc(`op0_ShpA`):
3912 				return soundBank[bankNum][presetNum].operators[0].shpA;
3913 			case hashCalc(`op0_ShpR`):
3914 				return soundBank[bankNum][presetNum].operators[0].shpR;
3915 			case hashCalc(`op0_VelToLevel`):
3916 				return soundBank[bankNum][presetNum].operators[0].outLCtrl[0];
3917 			case hashCalc(`op0_MWToLevel`):
3918 				return soundBank[bankNum][presetNum].operators[0].outLCtrl[1];
3919 			case hashCalc(`op0_LFOToLevel`):
3920 				return soundBank[bankNum][presetNum].operators[0].outLCtrl[2];
3921 			case hashCalc(`op0_VelToFB`):
3922 				return soundBank[bankNum][presetNum].operators[0].fbLCtrl[0];
3923 			case hashCalc(`op0_MWToFB`):
3924 				return soundBank[bankNum][presetNum].operators[0].fbLCtrl[1];
3925 
3926 			case hashCalc(`op0_LFOToFB`):
3927 				return soundBank[bankNum][presetNum].operators[0].fbLCtrl[2];
3928 			case hashCalc(`op0_EEGToFB`):
3929 				return soundBank[bankNum][presetNum].operators[0].fbLCtrl[3];
3930 			case hashCalc(`op0_VelToShpA`):
3931 				return soundBank[bankNum][presetNum].operators[0].shpAVel;
3932 			case hashCalc(`op0_VelToShpR`):
3933 				return soundBank[bankNum][presetNum].operators[0].shpRVel;
3934 			//op0 end
3935 
3936 			//op1 begin
3937 			case hashCalc(`op1_Level`):
3938 				return soundBank[bankNum][presetNum].operators[1].outL;
3939 			case hashCalc(`op1_SusLevel`):
3940 				return soundBank[bankNum][presetNum].operators[1].susLevel;
3941 			case hashCalc(`op1_Feedback`):
3942 				return soundBank[bankNum][presetNum].operators[1].fbL;
3943 			case hashCalc(`op1_Tune`):
3944 				return soundBank[bankNum][presetNum].operators[1].tune;
3945 			//case hashCalc(`op1_FreqRate`):break;
3946 			case hashCalc(`op1_ShpA`):
3947 				return soundBank[bankNum][presetNum].operators[1].shpA;
3948 			case hashCalc(`op1_ShpR`):
3949 				return soundBank[bankNum][presetNum].operators[1].shpR;
3950 			case hashCalc(`op1_VelToLevel`):
3951 				return soundBank[bankNum][presetNum].operators[1].outLCtrl[0];
3952 			case hashCalc(`op1_MWToLevel`):
3953 				return soundBank[bankNum][presetNum].operators[1].outLCtrl[1];
3954 			case hashCalc(`op1_LFOToLevel`):
3955 				return soundBank[bankNum][presetNum].operators[1].outLCtrl[2];
3956 			case hashCalc(`op1_VelToFB`):
3957 				return soundBank[bankNum][presetNum].operators[1].fbLCtrl[0];
3958 			case hashCalc(`op1_MWToFB`):
3959 				return soundBank[bankNum][presetNum].operators[1].fbLCtrl[1];
3960 			case hashCalc(`op1_LFOToFB`):
3961 				return soundBank[bankNum][presetNum].operators[1].fbLCtrl[2];
3962 			case hashCalc(`op1_EEGToFB`):
3963 				return soundBank[bankNum][presetNum].operators[1].fbLCtrl[3];
3964 			case hashCalc(`op1_VelToShpA`):
3965 				return soundBank[bankNum][presetNum].operators[1].shpAVel;
3966 			case hashCalc(`op1_VelToShpR`):
3967 				return soundBank[bankNum][presetNum].operators[1].shpRVel;
3968 			//op1 end
3969 
3970 			//ch begin
3971 			case hashCalc(`ch_MasterVol`):
3972 				return soundBank[bankNum][presetNum].channel.masterVol;
3973 			case hashCalc(`ch_Bal`):
3974 				return soundBank[bankNum][presetNum].channel.masterBal;
3975 			case hashCalc(`ch_AuxSLA`):
3976 				return soundBank[bankNum][presetNum].channel.auxSendA;
3977 			case hashCalc(`ch_AuxSLB`):
3978 				return soundBank[bankNum][presetNum].channel.auxSendB;
3979 			case hashCalc(`ch_EEGDetune`):
3980 				return soundBank[bankNum][presetNum].channel.eegDetuneAm;
3981 			case hashCalc(`ch_PitchBendSens`):
3982 				return soundBank[bankNum][presetNum].channel.pitchBendSens;
3983 			case hashCalc(`ch_Tune`):
3984 				return soundBank[bankNum][presetNum].channel.chnlTun;
3985 			case hashCalc(`ch_PLFO`):
3986 				return soundBank[bankNum][presetNum].channel.pLFOlevel;
3987 			case hashCalc(`ch_SusLevel`):
3988 				return soundBank[bankNum][presetNum].channel.susLevel;
3989 			case hashCalc(`ch_ShpA`):
3990 				return soundBank[bankNum][presetNum].channel.shpAX;
3991 			case hashCalc(`ch_ShpR`):
3992 				return soundBank[bankNum][presetNum].channel.shpRX;
3993 			case hashCalc(`ch_GlobalFB`):
3994 				return soundBank[bankNum][presetNum].channel.globalFb;
3995 			case hashCalc(`ch_EEGToLeft`):
3996 				return soundBank[bankNum][presetNum].channel.eegLevels[0];
3997 			case hashCalc(`ch_EEGToRight`):
3998 				return soundBank[bankNum][presetNum].channel.eegLevels[1];
3999 			case hashCalc(`ch_EEGToAuxA`):
4000 				return soundBank[bankNum][presetNum].channel.eegLevels[2];
4001 			case hashCalc(`ch_EEGToAuxB`):
4002 				return soundBank[bankNum][presetNum].channel.eegLevels[3];
4003 			case hashCalc(`ch_LFOToLeft`):
4004 				return soundBank[bankNum][presetNum].channel.aLFOlevels[0];
4005 			case hashCalc(`ch_LFOToRight`):
4006 				return soundBank[bankNum][presetNum].channel.aLFOlevels[1];
4007 			case hashCalc(`ch_LFOToAuxA`):
4008 				return soundBank[bankNum][presetNum].channel.aLFOlevels[2];
4009 			case hashCalc(`ch_LFOToAuxB`):
4010 				return soundBank[bankNum][presetNum].channel.aLFOlevels[3];
4011 			case hashCalc(`ch_MWToGFB`):
4012 				return soundBank[bankNum][presetNum].channel.mwToGFB;
4013 			case hashCalc(`ch_VelToGFB`):
4014 				return soundBank[bankNum][presetNum].channel.velToGFB;
4015 			//ch end
4016 
4017 			//commons begin
4018 			case hashCalc(`_PLFORate`): return pLFOFreq;
4019 			case hashCalc(`_ALFORate`): return aLFOFreq;
4020 			case hashCalc(`_FilterLCFreq`):
4021 				return filterCtrl[0];
4022 			case hashCalc(`_FilterLCQ`):
4023 				return filterCtrl[1];
4024 			case hashCalc(`_FilterRCFreq`):
4025 				return filterCtrl[2];
4026 			case hashCalc(`_FilterRCQ`):
4027 				return filterCtrl[3];
4028 			case hashCalc(`_FilterACFreq`):
4029 				return filterCtrl[4];
4030 			case hashCalc(`_FilterACQ`):
4031 				return filterCtrl[5];
4032 			case hashCalc(`_FilterBCFreq`):
4033 				return filterCtrl[6];
4034 			case hashCalc(`_FilterBCQ`):
4035 				return filterCtrl[7];
4036 			case hashCalc(`_HPFLCFreq`):
4037 				return hpfCtrl[0];
4038 			case hashCalc(`_HPFLCQ`):
4039 				return hpfCtrl[1];
4040 			case hashCalc(`_HPFRCFreq`):
4041 				return hpfCtrl[2];
4042 			case hashCalc(`_HPFRCQ`):
4043 				return hpfCtrl[3];
4044 			case hashCalc(`_HPFACFreq`):
4045 				return hpfCtrl[4];
4046 			case hashCalc(`_HPFACQ`):
4047 				return hpfCtrl[5];
4048 			case hashCalc(`_HPFBCFreq`):
4049 				return hpfCtrl[6];
4050 			case hashCalc(`_HPFBCQ`):
4051 				return hpfCtrl[6];
4052 			//commons end
4053 			default:
4054 				return double.nan;
4055 		}
4056 		
4057 	}
4058 	/** 
4059 	 * Reads the given value (int).
4060 	 * Params:
4061 	 *   presetID = The preset ID, or uint.max for global module values.
4062 	 *   paramID = The parameter ID.
4063 	 * Returns: The value of the given preset and parameter
4064 	 */
4065 	public override string readParam_string(uint presetID, uint paramID) nothrow {
4066 		return null;
4067 	}
4068 }