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