1 /*
2  * Copyright (C) 2015-2018, by Laszlo Szeremi under the Boost license.
3  *
4  * Pixel Perfect Engine, audio.pcm32 module
5  */
6 
7 module PixelPerfectEngine.audio.pcm32;
8 
9 import PixelPerfectEngine.audio.common;
10 import PixelPerfectEngine.audio.firFilter;
11 import PixelPerfectEngine.audio.envGen;
12 import PixelPerfectEngine.audio.lfo;
13 
14 import PixelPerfectEngine.system.platform;
15 import PixelPerfectEngine.system.binarySearchTree;
16 
17 static if(USE_INTEL_INTRINSICS)
18 	import inteli.emmintrin;
19 
20 import libPCM.codecs;
21 import libPCM.common;
22 import libPCM.file;
23 import libPCM.types;
24 
25 import std.bitmanip;
26 import std.math;
27 import std.container.array;
28 
29 import core.stdc.stdlib;
30 import core.stdc..string;
31 
32 /**
33  * Sampling synthesizer implementation. Has per channel FIR (1024 stage) and IIR (low-pass) filters, and four stereo outputs.
34  */
35 public class PCM32 : AbstractPPEFX{
36 	enum LFO_TABLE_LENGTH = 256;
37 	enum FIR_TABLE_LENGTH = 1024;
38 	enum WHOLE_STEP_FORWARD = 1_048_576;
39 	/**
40 	 * Defines the source of certain modifier values
41 	 */
42 	public enum ControlSource : ubyte{
43 		NULL			=	0,
44 		Pitch			=	1,
45 		Velocity		=	2,
46 		ExpressiveVal	=	3,
47 	}
48 	/**
49 	 * Control data.
50 	 * Bitfield:
51 	 * <ul>
52 	 * <li>cSource: Enables input for controlling parameters with key command parameters</li>
53 	 * <li>damping: Sets per-octave dampening of the value</li>
54 	 * <li>invertCS: Inverts Velocity and ExpressiveVal control sources</li>
55 	 * <li>modifyEG: Modifies the output levels of the envelope generators by the control source</li>
56 	 * <li>envGenA: Enables envelope generator A to modify this parameter</li>
57 	 * <li>invertEGA: Inverts the output of the envelope generator A</li>
58 	 * <li>envGenB: Enables envelope generator A to modify this parameter</li>
59 	 * <li>invertEGB: Inverts the output of the envelope generator A</li>
60 	 * <li>fixValue: Toggles the role of the fix value: sets a fix value if true, sets the ratio of the modifiers if false</li>
61 	 * <li>lfo: Toggles the LFO</li>
62 	 * <li>reserved: Unused, might have some role in the future</li>
63 	 * </ul>
64 	 */
65 	public struct ControlData{
66 		mixin(bitfields!(
67 			ubyte, "cSource", 2,
68 			ubyte, "damping", 2,
69 			bool, "invertCS", 1,
70 			bool, "modifyEG", 1,
71 			bool, "envGenA", 1,
72 			bool, "invertEGA", 1,
73 			bool, "envGenB", 1,
74 			bool, "invertEGB", 1,
75 			bool, "fixValue", 1,
76 			bool, "lfo", 1,
77 			ubyte, "reserved", 4,
78 		));
79 	}
80 	/**
81 	 * Defines the type of IIR filter
82 	 */
83 	public enum IIRFilterType : ubyte{
84 		Bypass			=	0,
85 		LPF				=	1,
86 		HPF				=	2,
87 		BPF				=	3,
88 	}
89 	/**
90 	 * Per-octave dampening
91 	 */
92 	public enum Dampening : ubyte{
93 		DB00			=	0,	///No dampening
94 		DB15			=	1,	///1.5db dampening
95 		DB30			=	2,	///3.0db dampening
96 		DB60			=	3,	///6.0db dampening
97 	}
98 	/**
99 	 * Preset data.
100 	 * Does not store the data regarding instrument samples.
101 	 */
102 	public struct ChannelPresetMain{
103 		ubyte firTypeL;		///Selects the FIR filter type for the left channel
104 		ubyte firTypeR;		///Selects the FIR filter type for the right channel
105 		ubyte iirType;		///Selects the IIR filter type
106 		ubyte lfoWave;		///Selects the LFO Waveform
107 
108 		short firLevel;		///Sets the output level of the FIR filter, negative values invert the signal
109 		short firFeedback;	///Sets the feedback level of the FIR filter, negative values invert the signal
110 
111 		float _Q;			///Mostly Q
112 		float f0;			///Frequency center of the filtering
113 		float iirDryLevel;	///Sets the level of the dry signal
114 		float iirWetLevel;	///Sets the level of the wet signal
115 		float lfoFreq;		///Sets the LFO frequency
116 
117 		float[4] sendLevels;	///1: Main left; 2: Main right; 3: Aux left; 4: Aux right
118 
119 		ControlData firLevelCtrl;		///Sets the modifiers for the firLevel (fixValue controls don't work)
120 		ControlData firFeedbackCtrl;	///Sets the modifiers for the firFeedback (fixValue controls don't work)
121 
122 		ControlData sendLevelLCtrl;		///Modifies all left channel outputs
123 		ControlData sendLevelRCtrl;		///Modifies all right channel outputs
124 
125 		ControlData _QCtrl;
126 		ControlData f0Ctrl;
127 		ControlData iirDryLevelCtrl;
128 		ControlData iirWetLevelCtrl;
129 		ControlData lfoFreqCtrl;
130 		/*
131 		 * Routing policies:
132 		 * enableIIR: Enables IIR filter
133 		 * enableFIR: Enables FIR filter
134 		 * serialFIR: If true, it runs the two FIR filters in serial [L -> R]
135 		 * monoFIR: If true, only the left channel will be used, and serialFIR is ignored
136 		 * routeFIRintoIIR: Reverses the routing of the two filters
137 		 *
138 		 * Legato:
139 		 * resetSample: Disables sample resetting if keyOn command received without keyoff
140 		 * resetEGA: Disables resetting of envelope generator A
141 		 * resetEGB: Disables resetting of envelope generator B
142 		 * resetLFO: Disables resetting of LFO
143 		 *
144 		 * Other:
145 		 * loopOnKeyOff: Enables the use of release stages of the LFO to control the runtime after key off commands.
146 		 * Recommended for wavetables.
147 		 */
148 		mixin(bitfields!(
149 			bool,"enableIIR",1,
150 			bool,"enableFIR",1,
151 			bool,"serialFIR",1,
152 			bool,"monoFIR",1,
153 			bool,"routeFIRintoIIR",1,
154 
155 			bool,"resetSample",1,
156 			bool,"resetEGA",1,
157 			bool,"resetEGB",1,
158 			bool,"resetLFO",1,
159 			bool,"loopOnKeyOff",1,
160 
161 			ushort,"reserved",6,
162 		));
163 	}
164 	/**
165 	 * Preset data.
166 	 * Stores data on how to handle instrument samples.
167 	 * Important: fromX are always the lower values. Overlapping values are not supported.
168 	 */
169 	public struct ChannelPresetSamples{
170 		///Sets certain properties of the sample
171 		enum Flags : ushort{
172 			///Enables sample looping
173 			enableLoop = 0b0000_0000_0000_0001,
174 			///Changes looping from one-way to ping-pong (doesn't work with most differental codecs)
175 			pingPongLoop = 0b0000_0000_0000_0010,
176 			///Disables pitch changes on different notes.
177 			isPercussive = 0b0000_0000_0000_0100,
178 			///Plays only a slice from the sample (doesn't work with most differental codecs)
179 			slice = 0b0000_0000_0000_1000,
180 		}
181 		uint sampleSelect;	///Selects the sample that will be used
182 		uint loopFrom;
183 		uint loopTo;
184 		float midFreq;
185 		ushort loopFlags;	///See enum Flags for options
186 		ushort midNote;
187 		ushort fromNote = 0x0FFF;
188 		ushort toNote = 0x0FFF + 0x7F;
189 		/+ushort fromVelocity;
190 		ushort toVelocity = ushort.max;
191 		ushort fromExpressiveVal;
192 		ushort toExpressiveVal = ushort.max;+/
193 		@nogc @property bool isPercussive(){
194 			return (loopFlags & Flags.isPercussive) != 0;
195 		}
196 		@nogc @property bool isLooping(){
197 			return (loopFlags & Flags.isPercussive) != 0;
198 		}
199 		@nogc @property bool pingPongLoop(){
200 			return (loopFlags & Flags.isPercussive) != 0;
201 		}
202 		/**
203 		 * Used mainly for ordering them in a BSTree.
204 		 */
205 		@nogc int opCmp(ChannelPresetSamples rhs){
206 			if(this.toNote < rhs.fromNote)
207 				return -1;
208 			else if(this.fromNote > rhs.toNote)
209 				return 1;
210 			else
211 				return 0;
212 		}
213 		/**
214 		 * Range lookup.
215 		 */
216 		@nogc int opCmp(ushort rhs){
217 			if(this.fromNote > rhs){//hit from lower range
218 				if(this.toNote < rhs){//hit from upper range
219 					return 0;
220 				}else{//overshoot
221 					return 1;
222 				}
223 			}else{//undershoot
224 				return -1;
225 			}
226 		}
227 		/**
228 		 * Equals function for other ChannelPresetSamples.
229 		 */
230 		@nogc bool opEquals(ChannelPresetSamples b) {
231 			return opCmp(b) == 0;
232 		}
233 		/**
234 		 * Equals function for ushort by note.
235 		 */
236 		@nogc bool opEquals(ushort b) {
237 			return opCmp(b) == 0;
238 		}
239 	}
240 	/**
241 	 * Stores information regarding to samples.
242 	 * IMPORTANT: Always call unloadSample for unloading samples from the memory.
243 	 */
244 	public struct Sample{
245 		size_t length;		///Length of sample
246 		ubyte* dataPtr;		///Points to the first sample of the stream
247 		CodecType codec;	///Selects the codec type
248 		ushort flags;		///Mainly for 32bit alignment, placeholder for future flags (stereo sample support?)
249 		float sampleFreq;	///Overrides the *.pcm file's sampling frequency
250 		this(size_t length, ubyte* dataPtr, CodecType codec){
251 			this.length = length;
252 			this.dataPtr = dataPtr;
253 			this.codec = codec;
254 		}
255 		/**
256 		 * Unloads the sample from memory.
257 		 */
258 		@nogc void unloadSample(){
259 			length = 0;
260 			free(dataPtr);
261 		}
262 	}
263 	/**
264 	 * Stores sample preset data for editing and storing purposes.
265 	 */
266 	public struct SamplePreset{
267 		char[32] name;		///Must match file source name without the .pcm extension in the sample pool(s) being used
268 		float freq;
269 		uint id;
270 	}
271 	/**
272 	 * Stores data on LFO or FIR for editing and storing purposes.
273 	 */
274 	public struct FXSamplePreset{
275 		char[32] name;		///Must match file source name without the .pcm extension in the sample pool(s) being used
276 		ubyte id;
277 		ubyte[3] unused;
278 	}
279 	/**
280 	 * Stores instrument preset data for editing and storing purposes.
281 	 */
282 	public struct InstrumentPreset{
283 		char[32] name;
284 		ushort id;
285 		ushort egaStages;
286 		ushort egbStages;
287 		ushort sampleLayers;
288 	}
289 	/**
290 	 * Stores global settings of the instrument.
291 	 */
292 	public struct GlobalSettings{
293 		float tuning = 440.0;		///base tuning
294 		///Used for channel masking. The channel indicated by this value is used as the first channel that won't be ignored.
295 		///Last channel not to be ignored is baseChannel + 31
296 		ushort baseChannel;
297 		/*
298 		 * Bitfields:
299 		 * enablePassthruCH29 - 32: Enables the channels to be used for external effecting purposes.
300 		 * Note commands can be used to control the filters if needed.
301 		 * Input for CH29 is PPEFXinput 0
302 		 * Input for CH30 is PPEFXinput 1
303 		 * Input for CH31 is PPEFXinput 2
304 		 * Input for CH32 is PPEFXinput 3
305 		 */
306 		mixin(bitfields!(
307 			bool,"enablePassthruCH29",1,
308 			bool,"enablePassthruCH30",1,
309 			bool,"enablePassthruCH31",1,
310 			bool,"enablePassthruCH32",1,
311 			ushort,"unused",12,
312 		));
313 	}
314 	/**
315 	 * RIFF header to identify preset data in banks.
316 	 */
317 	enum RIFFID : char[4]{
318 		riffInitial = "RIFF",		///to initialize the RIFF format
319 		bankInitial = "BANK",		///currently unused
320 		globalSettings = "GLOB",	///global settings (eg. tunings, routing, channel masking)
321 		instrumentPreset = "INSP",	///indicates that the next chunk is an instrument preset. length = InstrumentPreset.sizeof + ChannelPresetMain.sizeof
322 		envGenA = "ENVA",			///indicates that there's envelope generator data for the current preset. length = EnvelopeStage.sizeof * egaStages
323 		envGenB = "ENVB",			///indicates that there's envelope generator data for the current preset. length = EnvelopeStage.sizeof * egbStages
324 		instrumentData = "INSD",	///indicates that the next chunk contains sample layer data for the current preset. length = ChannelPresetSamples.sizeof * sampleLayers
325 		samplePreset = "SLMP",		///indicates that the next chunk is a sample preset. length = SamplePreset * sizeof
326 		lfoPreset = "LFOP",			///indicates that the next chunk is an LFO preset. length = FXSamplePreset * sizeof
327 		fiResponse = "FIRS",		///indicates that the next chunk is an FIR preset. length = FXSamplePreset * sizeof
328 	}
329 	/**
330 	 * Stores data for a single channel.
331 	 */
332 	protected struct Channel{
333 		ChannelPresetMain preset;
334 		@nogc short function(ubyte*, DecoderWorkpad*) codec;
335 		uint loopfrom, loopto;	///describe a loop cycle between the two values for the current sample
336 		uint stepping;			///describes how much the sample should go forward, 1_048_576 equals a whole step
337 		ulong forward;			///current position
338 		Sample* sample;
339 		short*[3] intBuff;		///buffer for FIR-filters [0,1], output [2], IIR-filter output converted to int [3]
340 		CodecType codecType;
341 		DecoderWorkpad workpad, secWorkpad;
342 		ushort presetID;
343 		ushort note;
344 		ushort vel;
345 		ushort exprVal;
346 		float freq;
347 		float baseFreq;
348 		float pitchbend = 0f;
349 		float iirF0;
350 		float iir_q;
351 		float[4] sendLevels;
352 		EnvelopeGenerator envGenA;
353 		EnvelopeGenerator envGenB;
354 		FiniteImpulseResponseFilter!(FIR_TABLE_LENGTH)[2] firFilter;
355 		LowFreqOsc!(LFO_TABLE_LENGTH) lfo;
356 		//bool keyON;
357 		//bool isRunning;
358 		ushort arpeggiatorSpeed;	///ms between notes
359 
360 		enum ArpMode : ubyte{
361 			off,
362 			ascending,
363 			descending,
364 			ascThenDesc,
365 		}
366 		mixin(bitfields!(
367 			bool,"keyON",1,
368 			bool,"isRunning",1,
369 			bool,"enableLooping",1,
370 			bool,"pingPongLoop",1,
371 			bool,"slice",1,
372 			ubyte,"arpMode",3,
373 			ubyte,"octaves",4,
374 			bool,"arpWay",1,
375 			ubyte,"nOfNotes",3,
376 		));
377 		ushort[4] arpeggiatorNotes;	///notes to arpeggiate
378 		ushort arpPos;
379 		ubyte curOctave, curNote;
380 		short output, firBuf0, firBuf1;				///Previous outputs
381 		short firLevel0, firLevel1, firFbk0, firFbk1;
382 	}
383 
384 	static if(ARCH_INTEL_X86){
385 		static if(USE_INTEL_INTRINSICS){
386 			/**
387 			 * Contains IIR related registers in order for use in SSE2 applications
388 			 */
389 			protected struct IIRFilterBuff{
390 				__m128 b0a0;
391 				//__m128 x_n;
392 				__m128 b1a0;
393 				__m128 x_n_minus1;
394 				__m128 b2a0;
395 				__m128 x_n_minus2;
396 				__m128 a1a0;
397 				__m128 y_n_minus1;
398 				__m128 a2a0;
399 				__m128 y_n_minus2;
400 				//__m128 y_n;
401 			}
402 		}else{
403 			/**
404 			 * Contains IIR related registers in order for use in SSE2 applications
405 			 */
406 			protected struct IIRFilterBuff{
407 				float[4] b0a0;
408 				//float[4] x_n;
409 				float[4] b1a0;
410 				float[4] x_n_minus1;
411 				float[4] b2a0;
412 				float[4] x_n_minus2;
413 				float[4] a1a0;
414 				float[4] y_n_minus1;
415 				float[4] a2a0;
416 				float[4] y_n_minus2;
417 				//float[4] y_n;
418 			}
419 		}
420 		IIRFilterBuff[8] iirFilters;
421 		void* iirFiltersPtr;
422 	}else{
423 		protected float[32] x_n_minus1, x_n_minus2, y_n_minus1, y_n_minus2, b0a0, b1a0, b2a0, a1a0, a2a0;
424 	}
425 	protected BinarySearchTree!(ushort,EnvelopeStageList) envGenA;
426 	protected BinarySearchTree!(ushort,EnvelopeStageList) envGenB;
427 	protected BinarySearchTree!(ushort,ChannelPresetMain) presets;
428 	protected BinarySearchTree!(ushort,BinarySearchTree2!(ChannelPresetSamples)) sampleLayers;
429 
430 	protected float*[32] y_n; ///Output
431 	protected float*[32] x_n; ///Input
432 	protected float[32] iirDryLevel, iirWetLevel;
433 	protected Channel[32] channels;
434 	protected float sampleRate;
435 	protected size_t frameLength, nOfFrames;
436 	protected BinarySearchTree!(ubyte, FiniteImpulseResponse!(1024)) finiteImpulseResponses;
437 	protected BinarySearchTree!(uint, Sample) samples;
438 	protected BinarySearchTree!(ubyte, ubyte[256]) lfoTables;
439 
440 	//global parameters
441 	protected GlobalSettings globals;
442 
443 	protected string samplePoolPath;	///Specifies the path for the sample pool
444 	/**
445 	 * Make sure that the string describes a valid path.
446 	 */
447 	public this(string samplePoolPath = "./audio/samples/"){
448 		this.samplePoolPath = samplePoolPath;
449 		this.globals.tuning = 440.0f;
450 	}
451 	public @nogc @property BinarySearchTree!(ushort,ChannelPresetMain)* presetPtr(){
452 		return &presets;
453 	}
454 	public @nogc @property BinarySearchTree!(ushort,EnvelopeStageList)* envGenAPtr(){
455 		return &envGenA;
456 	}
457 	public @nogc @property BinarySearchTree!(ushort,EnvelopeStageList)* envGenBPtr(){
458 		return &envGenB;
459 	}
460 	public @nogc @property BinarySearchTree!(ushort,BinarySearchTree2!(ChannelPresetSamples))* sampleLayersPtr(){
461 		return &sampleLayers;
462 	}
463 	protected @nogc void calculateIIR(){
464 		static if(USE_INTEL_INTRINSICS){
465 			//float* y_nptr = cast(float*)y_n.ptr;
466 			//float* x_nptr = cast(float*)x_n.ptr;
467 			float* vals = cast(float*)iirFiltersPtr;
468 			float* iirDryLevelPtr = iirDryLevel.ptr;
469 			float* iirWetLevelPtr = iirWetLevel.ptr;
470 			for(size_t i = frameLength ; i >= 0 ; i--){
471 				for(int j ; j < 8 ; j++){
472 					const int k = j << 2;
473 					__m128 workVal = _mm_load_ps(vals);//b0a0
474 					__m128 x_n0;// = [x_n[k][i],x_n[k+1][i],x_n[k+2][i],x_n[k+3][i]];
475 					x_n0[0] = x_n[k][i];
476 					x_n0[1] = x_n[k+1][i];
477 					x_n0[2] = x_n[k+2][i];
478 					x_n0[3] = x_n[k+3][i];
479 					__m128 y_n0;//output
480 					y_n0 = workVal * x_n0;//(b0/a0)*x_n0
481 					vals += 4;
482 					workVal = _mm_load_ps(vals);//b1a0
483 					vals += 4;
484 					__m128 x_n1 = _mm_load_ps(vals);//x_n1
485 					_mm_store_ps(vals,x_n0);//store current x_n0 as x_n1
486 					y_n0 += x_n1 * workVal;//(b0/a0)*x_n0 + (b1/a0)*x_n1
487 					vals += 4;
488 					workVal = _mm_load_ps(vals);//b2a0
489 					vals += 4;
490 					const __m128 x_n2 = _mm_load_ps(vals);//x_n2
491 					_mm_store_ps(vals,x_n1);//store current x_n1 as x_n2
492 					y_n0 += x_n2 * workVal;//(b0/a0)*x_n0 + (b1/a0)*x_n1 + (b2/a0)*x_n2
493 					vals += 4;
494 					workVal = _mm_load_ps(vals);//a1a0
495 					vals += 4;
496 					__m128 y_n1 = _mm_load_ps(vals);//y_n1
497 					float* vals_y_n0 = vals;//store current position for storing the new output
498 					y_n0 -= y_n1 * workVal;//(b0/a0)*x_n0 + (b1/a0)*x_n1 + (b2/a0)*x_n2 - (a1/a0)*x_n2
499 					vals += 4;
500 					workVal = _mm_load_ps(vals);//a2a0
501 					vals += 4;
502 					const __m128 y_n2 = _mm_load_ps(vals);//y_n2 (I know, the variable has a different name)
503 					_mm_store_ps(vals,y_n1);//store current y_n1 as y_n2
504 					y_n0 -= y_n2 * workVal;//(b0/a0)*x_n0 + (b1/a0)*x_n1 + (b2/a0)*x_n2 - (a1/a0)*x_n2
505 					_mm_store_ps(vals_y_n0,y_n0);//store current y_n0 as y_n1
506 					//calculate mixing
507 					y_n0 = y_n0 * _mm_load_ps(iirWetLevelPtr) + x_n0 * _mm_load_ps(iirDryLevelPtr);
508 					//_mm_store_ps(y_nptr,y_n0);//store output in buffer
509 					y_n[k][i] = y_n0[0];
510 					y_n[k+1][i] = y_n0[1];
511 					y_n[k+2][i] = y_n0[2];
512 					y_n[k+3][i] = y_n0[3];
513 					vals += 4;
514 					//x_nptr += 4;
515 					//y_nptr += 4;
516 				}
517 				vals = cast(float*)iirFiltersPtr;
518 			}
519 		}else{
520 			float* y_nptr = cast(float*)y_n.ptr;
521 			float* x_nptr = cast(float*)x_n.ptr;
522 			for(int i = frameLength ; i >= 0 ; i--){
523 				asm @nogc{
524 					mov		ECX, 8;
525 					//mov		ESI, iirFiltersPtr[EBP];
526 					mov		EDI, y_nptr;
527 					mov		EBX, x_nptr;
528 				iirLoop:
529 					movaps	XMM0, [ESI];//load b0/a0
530 					movaps	XMM1, [EBX];//load x_n
531 					mulps	XMM0, XMM1;	//(b0/a0) * x_n
532 					add		ESI, 16;	//offset ESI to b1a0
533 					movaps	XMM2, [ESI];//load b1a0
534 					add		ESI, 16;	//offset ESI to x_n_minus1
535 					movaps	XMM3, [ESI];//load x_n_minus1
536 					movaps	[ESI], XMM1;//store current x_n as x_n_minus1
537 					mulps	XMM2, XMM3;	//(b1/a0) * x_n_minus1
538 					addps	XMM0, XMM2;	//(b0/a0) * x_n + (b1/a0) * x_n_minus1
539 					add		ESI, 16;	//offset ESI to b2a0
540 					movaps	XMM2, [ESI];//load b2a0
541 					add		ESI, 16;	//offset ESI to x_n_minus2
542 					movaps	XMM4, [ESI];//load x_n_minus2
543 					movaps	[ESI], XMM3;//store current x_n_minus1 as x_n_minus2
544 					mulps	XMM2, XMM4;	//(b2/a0) * x_n_minus2
545 					addps	XMM0, XMM2;	//(b0/a0) * x_n + (b1/a0) * x_n_minus1 + (b2/a0) * x_n_minus2
546 					add		ESI, 16;	//offset ESI to a1a0
547 					movaps	XMM1, [ESI];//load a1a0
548 					add		ESI, 16;	//offset ESI to y_n_minus1
549 					movaps	XMM2, [ESI];//load y_n_minus1
550 					mulps	XMM1, XMM2;	//(a1/a0) * y_n_minus1
551 					subps	XMM0, XMM1;	//(b0/a0) * x_n + (b1/a0) * x_n_minus1 + (b2/a0) * x_n_minus2 - (a1/a0) * y_n_minus1
552 					add		ESI, 16;	//offset ESI to a2a0
553 					movaps	XMM1, [ESI];//load a2a0
554 					add		ESI, 16;	//offset ESI to y_n_minus2
555 					movaps	XMM3, [ESI];//load y_n_minus2
556 					movaps	[ESI], XMM2;//store y_n_minus1 as new y_n_minus2
557 					mulps	XMM1, XMM3;	//(a2/a0) * y_n_minus2
558 					subps	XMM0, XMM1;	//(b0/a0) * x_n + (b1/a0) * x_n_minus1 + (b2/a0) * x_n_minus2 - (a1/a0) * y_n_minus1 - (a2/a0) * y_n_minus2
559 					sub		ESI, 48;	//set back pointer to  y_n_minus1
560 					movaps	[ESI], XMM0;//store y_n as y_n_minus1
561 					movaps	[EDI], XMM0;//store y_n as output
562 					add		EDI, 16;
563 					add		ESI, 48;
564 					dec		ECX;
565 					cmp		ECX, 0;
566 					jne		iirLoop;
567 				}
568 				x_nptr += 32;
569 				y_nptr += 32;
570 			}
571 		}
572 	}
573 	public @nogc void refreshFilter(int ch, IIRFilterType type, float freq, float Q){
574 
575 	}
576 	override public @nogc void render(float** inputBuffers, float** outputBuffers){
577 		float* mainL = outputBuffers[0], mainR = outputBuffers[1], auxL = outputBuffers[2], auxR = outputBuffers[3];
578 		float* ch29 = inputBuffers[0], ch30 = inputBuffers[1], ch31 = inputBuffers[2], ch32 = inputBuffers[3];
579 		for(int fr; fr < nOfFrames; fr++){
580 			int ch;
581 			for(; ch < 28; ch++){
582 				if(channels[ch].isRunning){
583 					for(int s; s < frameLength; s++){
584 						ulong prevForvard = channels[ch].forward;
585 						channels[ch].forward += channels[ch].stepping;
586 						while(prevForvard>>10 < channels[ch].forward>>10){
587 							channels[ch].output = channels[ch].codec(channels[ch].sample.dataPtr, &channels[ch].workpad);
588 							prevForvard += WHOLE_STEP_FORWARD;
589 							if(channels[ch].enableLooping){
590 								if(channels[ch].workpad.position == channels[ch].loopfrom){
591 									channels[ch].secWorkpad = channels[ch].workpad;
592 								}else if(channels[ch].workpad.position == channels[ch].loopto){
593 									channels[ch].workpad = channels[ch].secWorkpad;
594 								}
595 							}
596 						}
597 						if(channels[ch].sample.length <= channels[ch].workpad.position){
598 							channels[ch].isRunning = false;
599 							break;
600 						}
601 						channels[ch].intBuff[2][s] = channels[ch].output;
602 					}
603 
604 					if(channels[ch].preset.enableFIR){
605 						if(channels[ch].preset.routeFIRintoIIR){
606 							for(int s; s < frameLength; s++){
607 								channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
608 										(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
609 								channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
610 							}
611 							if(!channels[ch].preset.monoFIR){
612 								if(channels[ch].preset.serialFIR){
613 									for(int s; s < frameLength; s++){
614 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
615 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
616 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
617 									}
618 									int16ToFloat(channels[ch].intBuff[1],x_n[ch],frameLength);
619 								}else{//parralel mixing due to channel limit
620 									for(int s; s < frameLength; s++){
621 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
622 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
623 										channels[ch].intBuff[0][s] += cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
624 									}
625 									int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
626 								}
627 							}else{
628 								int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
629 							}
630 							mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
631 							mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
632 							mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
633 							mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
634 						}else{
635 							int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
636 							floatToInt16(y_n[ch],channels[ch].intBuff[2],frameLength);
637 							for(int s; s < frameLength; s++){
638 								channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
639 										(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
640 								channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
641 							}
642 							if(!channels[ch].preset.monoFIR){
643 								if(channels[ch].preset.serialFIR){
644 									for(int s; s < frameLength; s++){
645 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
646 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
647 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
648 									}
649 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainL, frameLength, channels[ch].sendLevels[0]);
650 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
651 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxL, frameLength, channels[ch].sendLevels[2]);
652 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
653 								}else{
654 									for(int s; s < frameLength; s++){
655 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
656 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
657 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
658 									}
659 									convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
660 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
661 									convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
662 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
663 								}
664 							}else{
665 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
666 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainR, frameLength, channels[ch].sendLevels[1]);
667 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
668 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxR, frameLength, channels[ch].sendLevels[3]);
669 							}
670 						}
671 
672 
673 					}else{
674 						int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
675 						mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
676 						mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
677 						mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
678 						mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
679 					}
680 					channels[ch].envGenA.step;
681 					channels[ch].envGenB.step;
682 					channels[ch].lfo.step;
683 				}
684 			}
685 			if(globals.enablePassthruCH29){
686 				if(channels[ch].preset.enableFIR){
687 					if(channels[ch].preset.routeFIRintoIIR){
688 						floatToInt16(ch29, channels[ch].intBuff[2], frameLength);
689 						for(int s; s < frameLength; s++){
690 							channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
691 									(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
692 							channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
693 						}
694 						if(!channels[ch].preset.monoFIR){
695 							if(channels[ch].preset.serialFIR){
696 								for(int s; s < frameLength; s++){
697 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
698 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
699 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
700 								}
701 								int16ToFloat(channels[ch].intBuff[1],x_n[ch],frameLength);
702 							}else{//parralel mixing due to channel limit
703 								for(int s; s < frameLength; s++){
704 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
705 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
706 									channels[ch].intBuff[0][s] += cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
707 								}
708 								int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
709 							}
710 						}else{
711 							int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
712 						}
713 						mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
714 						mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
715 						mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
716 						mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
717 					}else{
718 						//int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
719 						memcpy(x_n[ch], ch29, frameLength * float.sizeof);
720 						floatToInt16(y_n[ch],channels[ch].intBuff[2],frameLength);
721 						for(int s; s < frameLength; s++){
722 							channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
723 									(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
724 							channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
725 						}
726 						if(!channels[ch].preset.monoFIR){
727 							if(channels[ch].preset.serialFIR){
728 								for(int s; s < frameLength; s++){
729 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
730 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
731 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
732 								}
733 
734 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainL, frameLength, channels[ch].sendLevels[0]);
735 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
736 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxL, frameLength, channels[ch].sendLevels[2]);
737 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
738 							}else{
739 								for(int s; s < frameLength; s++){
740 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
741 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
742 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
743 								}
744 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
745 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
746 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
747 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
748 							}
749 						}else{
750 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
751 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainR, frameLength, channels[ch].sendLevels[1]);
752 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
753 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxR, frameLength, channels[ch].sendLevels[3]);
754 						}
755 					}
756 				}else{
757 					memcpy(x_n[ch], ch29, frameLength * float.sizeof);
758 					mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
759 					mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
760 					mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
761 					mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
762 				}
763 				channels[ch].envGenA.step;
764 				channels[ch].envGenB.step;
765 				channels[ch].lfo.step;
766 			}else{
767 				if(channels[ch].isRunning){
768 					for(int s; s < frameLength; s++){
769 						ulong prevForvard = channels[ch].forward;
770 						channels[ch].forward += channels[ch].stepping;
771 						while(prevForvard>>10 < channels[ch].forward>>10){
772 							channels[ch].output = channels[ch].codec(channels[ch].sample.dataPtr, &channels[ch].workpad);
773 							prevForvard += WHOLE_STEP_FORWARD;
774 							if(channels[ch].enableLooping){
775 								if(channels[ch].workpad.position == channels[ch].loopfrom){
776 									channels[ch].secWorkpad = channels[ch].workpad;
777 								}else if(channels[ch].workpad.position == channels[ch].loopto){
778 									channels[ch].workpad = channels[ch].secWorkpad;
779 								}
780 							}
781 						}
782 						if(channels[ch].sample.length <= channels[ch].workpad.position){
783 							channels[ch].isRunning = false;
784 							break;
785 						}
786 						channels[ch].intBuff[2][s] = channels[ch].output;
787 					}
788 
789 					if(channels[ch].preset.enableFIR){
790 						if(channels[ch].preset.routeFIRintoIIR){
791 							for(int s; s < frameLength; s++){
792 								channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
793 										(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
794 								channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
795 							}
796 							if(!channels[ch].preset.monoFIR){
797 								if(channels[ch].preset.serialFIR){
798 									for(int s; s < frameLength; s++){
799 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
800 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
801 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
802 									}
803 									int16ToFloat(channels[ch].intBuff[1],x_n[ch],frameLength);
804 								}else{//parralel mixing due to channel limit
805 									for(int s; s < frameLength; s++){
806 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
807 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
808 										channels[ch].intBuff[0][s] += cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
809 									}
810 									int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
811 								}
812 							}else{
813 								int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
814 							}
815 							mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
816 							mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
817 							mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
818 							mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
819 						}else{
820 							int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
821 							floatToInt16(y_n[ch],channels[ch].intBuff[2],frameLength);
822 							for(int s; s < frameLength; s++){
823 								channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
824 										(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
825 								channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
826 							}
827 							if(!channels[ch].preset.monoFIR){
828 								if(channels[ch].preset.serialFIR){
829 									for(int s; s < frameLength; s++){
830 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
831 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
832 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
833 									}
834 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainL, frameLength, channels[ch].sendLevels[0]);
835 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
836 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxL, frameLength, channels[ch].sendLevels[2]);
837 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
838 								}else{
839 									for(int s; s < frameLength; s++){
840 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
841 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
842 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
843 									}
844 									convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
845 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
846 									convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
847 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
848 								}
849 							}else{
850 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
851 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainR, frameLength, channels[ch].sendLevels[1]);
852 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
853 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxR, frameLength, channels[ch].sendLevels[3]);
854 							}
855 						}
856 
857 
858 					}else{
859 						int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
860 						mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
861 						mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
862 						mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
863 						mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
864 					}
865 					channels[ch].envGenA.step;
866 					channels[ch].envGenB.step;
867 					channels[ch].lfo.step;
868 				}
869 			}
870 			ch++;
871 			if(globals.enablePassthruCH30){
872 				if(channels[ch].preset.enableFIR){
873 					if(channels[ch].preset.routeFIRintoIIR){
874 						floatToInt16(ch29, channels[ch].intBuff[2], frameLength);
875 						for(int s; s < frameLength; s++){
876 							channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
877 									(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
878 							channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
879 						}
880 						if(!channels[ch].preset.monoFIR){
881 							if(channels[ch].preset.serialFIR){
882 								for(int s; s < frameLength; s++){
883 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
884 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
885 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
886 								}
887 								int16ToFloat(channels[ch].intBuff[1],x_n[ch],frameLength);
888 							}else{//parralel mixing due to channel limit
889 								for(int s; s < frameLength; s++){
890 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
891 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
892 									channels[ch].intBuff[0][s] += cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
893 								}
894 								int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
895 							}
896 						}else{
897 							int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
898 						}
899 						mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
900 						mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
901 						mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
902 						mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
903 					}else{
904 						//int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
905 						memcpy(x_n[ch], ch29, frameLength * float.sizeof);
906 						floatToInt16(y_n[ch],channels[ch].intBuff[2],frameLength);
907 						for(int s; s < frameLength; s++){
908 							channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
909 									(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
910 							channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
911 						}
912 						if(!channels[ch].preset.monoFIR){
913 							if(channels[ch].preset.serialFIR){
914 								for(int s; s < frameLength; s++){
915 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
916 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
917 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
918 								}
919 
920 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainL, frameLength, channels[ch].sendLevels[0]);
921 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
922 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxL, frameLength, channels[ch].sendLevels[2]);
923 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
924 							}else{
925 								for(int s; s < frameLength; s++){
926 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
927 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
928 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
929 								}
930 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
931 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
932 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
933 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
934 							}
935 						}else{
936 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
937 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainR, frameLength, channels[ch].sendLevels[1]);
938 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
939 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxR, frameLength, channels[ch].sendLevels[3]);
940 						}
941 					}
942 				}else{
943 					memcpy(x_n[ch], ch29, frameLength * float.sizeof);
944 					mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
945 					mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
946 					mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
947 					mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
948 				}
949 				channels[ch].envGenA.step;
950 				channels[ch].envGenB.step;
951 				channels[ch].lfo.step;
952 			}else{
953 				if(channels[ch].isRunning){
954 					for(int s; s < frameLength; s++){
955 						ulong prevForvard = channels[ch].forward;
956 						channels[ch].forward += channels[ch].stepping;
957 						while(prevForvard>>10 < channels[ch].forward>>10){
958 							channels[ch].output = channels[ch].codec(channels[ch].sample.dataPtr, &channels[ch].workpad);
959 							prevForvard += WHOLE_STEP_FORWARD;
960 							if(channels[ch].enableLooping){
961 								if(channels[ch].workpad.position == channels[ch].loopfrom){
962 									channels[ch].secWorkpad = channels[ch].workpad;
963 								}else if(channels[ch].workpad.position == channels[ch].loopto){
964 									channels[ch].workpad = channels[ch].secWorkpad;
965 								}
966 							}
967 						}
968 						if(channels[ch].sample.length <= channels[ch].workpad.position){
969 							channels[ch].isRunning = false;
970 							break;
971 						}
972 						channels[ch].intBuff[2][s] = channels[ch].output;
973 					}
974 
975 					if(channels[ch].preset.enableFIR){
976 						if(channels[ch].preset.routeFIRintoIIR){
977 							for(int s; s < frameLength; s++){
978 								channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
979 										(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
980 								channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
981 							}
982 							if(!channels[ch].preset.monoFIR){
983 								if(channels[ch].preset.serialFIR){
984 									for(int s; s < frameLength; s++){
985 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
986 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
987 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
988 									}
989 									int16ToFloat(channels[ch].intBuff[1],x_n[ch],frameLength);
990 								}else{//parralel mixing due to channel limit
991 									for(int s; s < frameLength; s++){
992 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
993 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
994 										channels[ch].intBuff[0][s] += cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
995 									}
996 									int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
997 								}
998 							}else{
999 								int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
1000 							}
1001 							mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
1002 							mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
1003 							mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
1004 							mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
1005 						}else{
1006 							int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
1007 							floatToInt16(y_n[ch],channels[ch].intBuff[2],frameLength);
1008 							for(int s; s < frameLength; s++){
1009 								channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
1010 										(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
1011 								channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
1012 							}
1013 							if(!channels[ch].preset.monoFIR){
1014 								if(channels[ch].preset.serialFIR){
1015 									for(int s; s < frameLength; s++){
1016 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
1017 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1018 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
1019 									}
1020 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainL, frameLength, channels[ch].sendLevels[0]);
1021 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
1022 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxL, frameLength, channels[ch].sendLevels[2]);
1023 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
1024 								}else{
1025 									for(int s; s < frameLength; s++){
1026 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
1027 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1028 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
1029 									}
1030 									convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
1031 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
1032 									convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
1033 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
1034 								}
1035 							}else{
1036 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
1037 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainR, frameLength, channels[ch].sendLevels[1]);
1038 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
1039 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxR, frameLength, channels[ch].sendLevels[3]);
1040 							}
1041 						}
1042 
1043 
1044 					}else{
1045 						int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
1046 						mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
1047 						mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
1048 						mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
1049 						mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
1050 					}
1051 					channels[ch].envGenA.step;
1052 					channels[ch].envGenB.step;
1053 					channels[ch].lfo.step;
1054 				}
1055 			}
1056 			ch++;
1057 			if(globals.enablePassthruCH31){
1058 				if(channels[ch].preset.enableFIR){
1059 					if(channels[ch].preset.routeFIRintoIIR){
1060 						floatToInt16(ch29, channels[ch].intBuff[2], frameLength);
1061 						for(int s; s < frameLength; s++){
1062 							channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
1063 									(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
1064 							channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
1065 						}
1066 						if(!channels[ch].preset.monoFIR){
1067 							if(channels[ch].preset.serialFIR){
1068 								for(int s; s < frameLength; s++){
1069 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
1070 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1071 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
1072 								}
1073 								int16ToFloat(channels[ch].intBuff[1],x_n[ch],frameLength);
1074 							}else{//parralel mixing due to channel limit
1075 								for(int s; s < frameLength; s++){
1076 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
1077 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1078 									channels[ch].intBuff[0][s] += cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
1079 								}
1080 								int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
1081 							}
1082 						}else{
1083 							int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
1084 						}
1085 						mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
1086 						mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
1087 						mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
1088 						mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
1089 					}else{
1090 						//int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
1091 						memcpy(x_n[ch], ch29, frameLength * float.sizeof);
1092 						floatToInt16(y_n[ch],channels[ch].intBuff[2],frameLength);
1093 						for(int s; s < frameLength; s++){
1094 							channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
1095 									(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
1096 							channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
1097 						}
1098 						if(!channels[ch].preset.monoFIR){
1099 							if(channels[ch].preset.serialFIR){
1100 								for(int s; s < frameLength; s++){
1101 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
1102 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1103 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
1104 								}
1105 
1106 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainL, frameLength, channels[ch].sendLevels[0]);
1107 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
1108 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxL, frameLength, channels[ch].sendLevels[2]);
1109 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
1110 							}else{
1111 								for(int s; s < frameLength; s++){
1112 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
1113 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1114 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
1115 								}
1116 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
1117 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
1118 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
1119 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
1120 							}
1121 						}else{
1122 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
1123 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainR, frameLength, channels[ch].sendLevels[1]);
1124 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
1125 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxR, frameLength, channels[ch].sendLevels[3]);
1126 						}
1127 					}
1128 				}else{
1129 					memcpy(x_n[ch], ch29, frameLength * float.sizeof);
1130 					mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
1131 					mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
1132 					mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
1133 					mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
1134 				}
1135 				channels[ch].envGenA.step;
1136 				channels[ch].envGenB.step;
1137 				channels[ch].lfo.step;
1138 			}else{
1139 				if(channels[ch].isRunning){
1140 					for(int s; s < frameLength; s++){
1141 						ulong prevForvard = channels[ch].forward;
1142 						channels[ch].forward += channels[ch].stepping;
1143 						while(prevForvard>>10 < channels[ch].forward>>10){
1144 							channels[ch].output = channels[ch].codec(channels[ch].sample.dataPtr, &channels[ch].workpad);
1145 							prevForvard += WHOLE_STEP_FORWARD;
1146 							if(channels[ch].enableLooping){
1147 								if(channels[ch].workpad.position == channels[ch].loopfrom){
1148 									channels[ch].secWorkpad = channels[ch].workpad;
1149 								}else if(channels[ch].workpad.position == channels[ch].loopto){
1150 									channels[ch].workpad = channels[ch].secWorkpad;
1151 								}
1152 							}
1153 						}
1154 						if(channels[ch].sample.length <= channels[ch].workpad.position){
1155 							channels[ch].isRunning = false;
1156 							break;
1157 						}
1158 						channels[ch].intBuff[2][s] = channels[ch].output;
1159 					}
1160 
1161 					if(channels[ch].preset.enableFIR){
1162 						if(channels[ch].preset.routeFIRintoIIR){
1163 							for(int s; s < frameLength; s++){
1164 								channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
1165 										(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
1166 								channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
1167 							}
1168 							if(!channels[ch].preset.monoFIR){
1169 								if(channels[ch].preset.serialFIR){
1170 									for(int s; s < frameLength; s++){
1171 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
1172 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1173 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
1174 									}
1175 									int16ToFloat(channels[ch].intBuff[1],x_n[ch],frameLength);
1176 								}else{//parralel mixing due to channel limit
1177 									for(int s; s < frameLength; s++){
1178 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
1179 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1180 										channels[ch].intBuff[0][s] += cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
1181 									}
1182 									int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
1183 								}
1184 							}else{
1185 								int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
1186 							}
1187 							mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
1188 							mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
1189 							mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
1190 							mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
1191 						}else{
1192 							int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
1193 							floatToInt16(y_n[ch],channels[ch].intBuff[2],frameLength);
1194 							for(int s; s < frameLength; s++){
1195 								channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
1196 										(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
1197 								channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
1198 							}
1199 							if(!channels[ch].preset.monoFIR){
1200 								if(channels[ch].preset.serialFIR){
1201 									for(int s; s < frameLength; s++){
1202 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
1203 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1204 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
1205 									}
1206 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainL, frameLength, channels[ch].sendLevels[0]);
1207 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
1208 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxL, frameLength, channels[ch].sendLevels[2]);
1209 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
1210 								}else{
1211 									for(int s; s < frameLength; s++){
1212 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
1213 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1214 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
1215 									}
1216 									convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
1217 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
1218 									convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
1219 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
1220 								}
1221 							}else{
1222 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
1223 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainR, frameLength, channels[ch].sendLevels[1]);
1224 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
1225 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxR, frameLength, channels[ch].sendLevels[3]);
1226 							}
1227 						}
1228 
1229 
1230 					}else{
1231 						int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
1232 						mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
1233 						mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
1234 						mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
1235 						mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
1236 					}
1237 					channels[ch].envGenA.step;
1238 					channels[ch].envGenB.step;
1239 					channels[ch].lfo.step;
1240 				}
1241 			}
1242 			ch++;
1243 			if(globals.enablePassthruCH32){
1244 				if(channels[ch].preset.enableFIR){
1245 					if(channels[ch].preset.routeFIRintoIIR){
1246 						floatToInt16(ch29, channels[ch].intBuff[2], frameLength);
1247 						for(int s; s < frameLength; s++){
1248 							channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
1249 									(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
1250 							channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
1251 						}
1252 						if(!channels[ch].preset.monoFIR){
1253 							if(channels[ch].preset.serialFIR){
1254 								for(int s; s < frameLength; s++){
1255 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
1256 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1257 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
1258 								}
1259 								int16ToFloat(channels[ch].intBuff[1],x_n[ch],frameLength);
1260 							}else{//parralel mixing due to channel limit
1261 								for(int s; s < frameLength; s++){
1262 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
1263 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1264 									channels[ch].intBuff[0][s] += cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
1265 								}
1266 								int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
1267 							}
1268 						}else{
1269 							int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
1270 						}
1271 						mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
1272 						mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
1273 						mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
1274 						mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
1275 					}else{
1276 						//int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
1277 						memcpy(x_n[ch], ch29, frameLength * float.sizeof);
1278 						floatToInt16(y_n[ch],channels[ch].intBuff[2],frameLength);
1279 						for(int s; s < frameLength; s++){
1280 							channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
1281 									(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
1282 							channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
1283 						}
1284 						if(!channels[ch].preset.monoFIR){
1285 							if(channels[ch].preset.serialFIR){
1286 								for(int s; s < frameLength; s++){
1287 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
1288 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1289 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
1290 								}
1291 
1292 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainL, frameLength, channels[ch].sendLevels[0]);
1293 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
1294 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxL, frameLength, channels[ch].sendLevels[2]);
1295 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
1296 							}else{
1297 								for(int s; s < frameLength; s++){
1298 									channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
1299 											(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1300 									channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
1301 								}
1302 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
1303 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
1304 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
1305 								convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
1306 							}
1307 						}else{
1308 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
1309 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainR, frameLength, channels[ch].sendLevels[1]);
1310 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
1311 							convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxR, frameLength, channels[ch].sendLevels[3]);
1312 						}
1313 					}
1314 				}else{
1315 					memcpy(x_n[ch], ch29, frameLength * float.sizeof);
1316 					mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
1317 					mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
1318 					mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
1319 					mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
1320 				}
1321 				channels[ch].envGenA.step;
1322 				channels[ch].envGenB.step;
1323 				channels[ch].lfo.step;
1324 			}else{
1325 				if(channels[ch].isRunning){
1326 					for(int s; s < frameLength; s++){
1327 						ulong prevForvard = channels[ch].forward;
1328 						channels[ch].forward += channels[ch].stepping;
1329 						while(prevForvard>>10 < channels[ch].forward>>10){
1330 							channels[ch].output = channels[ch].codec(channels[ch].sample.dataPtr, &channels[ch].workpad);
1331 							prevForvard += WHOLE_STEP_FORWARD;
1332 							if(channels[ch].enableLooping){
1333 								if(channels[ch].workpad.position == channels[ch].loopfrom){
1334 									channels[ch].secWorkpad = channels[ch].workpad;
1335 								}else if(channels[ch].workpad.position == channels[ch].loopto){
1336 									channels[ch].workpad = channels[ch].secWorkpad;
1337 								}
1338 							}
1339 						}
1340 						if(channels[ch].sample.length <= channels[ch].workpad.position){
1341 							channels[ch].isRunning = false;
1342 							break;
1343 						}
1344 						channels[ch].intBuff[2][s] = channels[ch].output;
1345 					}
1346 
1347 					if(channels[ch].preset.enableFIR){
1348 						if(channels[ch].preset.routeFIRintoIIR){
1349 							for(int s; s < frameLength; s++){
1350 								channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
1351 										(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
1352 								channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
1353 							}
1354 							if(!channels[ch].preset.monoFIR){
1355 								if(channels[ch].preset.serialFIR){
1356 									for(int s; s < frameLength; s++){
1357 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
1358 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1359 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
1360 									}
1361 									int16ToFloat(channels[ch].intBuff[1],x_n[ch],frameLength);
1362 								}else{//parralel mixing due to channel limit
1363 									for(int s; s < frameLength; s++){
1364 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
1365 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1366 										channels[ch].intBuff[0][s] += cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
1367 									}
1368 									int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
1369 								}
1370 							}else{
1371 								int16ToFloat(channels[ch].intBuff[0],x_n[ch],frameLength);
1372 							}
1373 							mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
1374 							mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
1375 							mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
1376 							mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
1377 						}else{
1378 							int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
1379 							floatToInt16(y_n[ch],channels[ch].intBuff[2],frameLength);
1380 							for(int s; s < frameLength; s++){
1381 								channels[ch].firBuf0 = cast(short)channels[ch].firFilter[0].calculate(cast(short)(channels[ch].intBuff[2][s] +
1382 										(channels[ch].firBuf0 * channels[ch].firFbk0)>>16));
1383 								channels[ch].intBuff[0][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel0);
1384 							}
1385 							if(!channels[ch].preset.monoFIR){
1386 								if(channels[ch].preset.serialFIR){
1387 									for(int s; s < frameLength; s++){
1388 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[0][s] +
1389 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1390 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf0 * channels[ch].firLevel1);
1391 									}
1392 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainL, frameLength, channels[ch].sendLevels[0]);
1393 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
1394 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxL, frameLength, channels[ch].sendLevels[2]);
1395 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
1396 								}else{
1397 									for(int s; s < frameLength; s++){
1398 										channels[ch].firBuf1 = cast(short)channels[ch].firFilter[1].calculate(cast(short)(channels[ch].intBuff[2][s] +
1399 												(channels[ch].firBuf1 * channels[ch].firFbk1)>>16));
1400 										channels[ch].intBuff[1][s] = cast(short)(channels[ch].firBuf1 * channels[ch].firLevel1);
1401 									}
1402 									convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
1403 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], mainR, frameLength, channels[ch].sendLevels[1]);
1404 									convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
1405 									convAndMixStreamIntoTarget(channels[ch].intBuff[1], auxR, frameLength, channels[ch].sendLevels[3]);
1406 								}
1407 							}else{
1408 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainL, frameLength, channels[ch].sendLevels[0]);
1409 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], mainR, frameLength, channels[ch].sendLevels[1]);
1410 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxL, frameLength, channels[ch].sendLevels[2]);
1411 								convAndMixStreamIntoTarget(channels[ch].intBuff[0], auxR, frameLength, channels[ch].sendLevels[3]);
1412 							}
1413 						}
1414 
1415 
1416 					}else{
1417 						int16ToFloat(channels[ch].intBuff[2],x_n[ch],frameLength);
1418 						mixStreamIntoTarget(y_n[ch], mainL, frameLength, channels[ch].sendLevels[0]);
1419 						mixStreamIntoTarget(y_n[ch], mainR, frameLength, channels[ch].sendLevels[1]);
1420 						mixStreamIntoTarget(y_n[ch], auxL, frameLength, channels[ch].sendLevels[2]);
1421 						mixStreamIntoTarget(y_n[ch], auxR, frameLength, channels[ch].sendLevels[3]);
1422 					}
1423 					channels[ch].envGenA.step;
1424 					channels[ch].envGenB.step;
1425 					channels[ch].lfo.step;
1426 				}
1427 			}
1428 			//update arpeggiators on all channels
1429 			updateArppegiators();
1430 			calculateIIR();
1431 		}
1432 
1433 	}
1434 	protected @nogc void updateArppegiators(){
1435 		for(int ch; ch < 32; ch++){
1436 			if(channels[ch].arpMode != Channel.ArpMode.off){
1437 				if(channels[ch].arpPos++ >= channels[ch].arpeggiatorSpeed){
1438 					channels[ch].arpPos = 0;
1439 					final switch(channels[ch].arpMode){
1440 						case Channel.ArpMode.ascending:
1441 							if(channels[ch].arpPos++ == channels[ch].nOfNotes){
1442 								channels[ch].arpPos = 0;
1443 								if(channels[ch].curOctave++ == channels[ch].octaves){
1444 									channels[ch].curOctave = 0;
1445 								}
1446 							}
1447 							break;
1448 						case Channel.ArpMode.descending:
1449 							if(channels[ch].arpPos-- == 0){
1450 								channels[ch].arpPos = channels[ch].nOfNotes;
1451 								if(channels[ch].curOctave-- == 0){
1452 									channels[ch].curOctave = channels[ch].octaves;
1453 								}
1454 							}
1455 							break;
1456 						case Channel.ArpMode.ascThenDesc:
1457 							if(channels[ch].arpWay){
1458 								if(channels[ch].arpPos++ == channels[ch].nOfNotes){
1459 									channels[ch].arpPos = 0;
1460 									if(channels[ch].curOctave++ == channels[ch].octaves){
1461 										channels[ch].curOctave = 0;
1462 										channels[ch].arpWay = false;
1463 									}
1464 								}
1465 							}else{
1466 								if(channels[ch].arpPos-- == 0){
1467 									channels[ch].arpPos = channels[ch].nOfNotes;
1468 									if(channels[ch].curOctave-- == 0){
1469 										channels[ch].curOctave = channels[ch].octaves;
1470 										channels[ch].arpWay = true;
1471 									}
1472 								}
1473 							}
1474 							break;
1475 					}
1476 					keyOn(cast(ubyte)ch, cast(ushort)(channels[ch].arpeggiatorNotes[channels[ch].arpPos] + channels[ch].curOctave * 12),
1477 							channels[ch].vel, channels[ch].exprVal);
1478 				}
1479 			}
1480 		}
1481 	}
1482 	override public @nogc void receiveMICPCommand(MICPCommand cmd){
1483 		cmd.channel = cast(ushort)(cmd.channel - globals.baseChannel);
1484 		switch(cmd.command){
1485 			case MICPCommandList.KeyOn:
1486 				keyOn(cast(ubyte)cmd.channel, cmd.val0, cmd.vals[0], cmd.vals[1]);
1487 				break;
1488 			case MICPCommandList.KeyOff:
1489 				keyOff(cast(ubyte)cmd.channel, cmd.val0, cmd.vals[0], cmd.vals[1]);
1490 				break;
1491 			case MICPCommandList.ParamEdit:
1492 				break;
1493 			case MICPCommandList.ParamEditFP:
1494 				break;
1495 			default:
1496 				break;
1497 		}
1498 	}
1499 	/**
1500 	 * Changes the preset of a given channel.
1501 	 * ch must be between 0 and 31.
1502 	 */
1503 	public @nogc void changePreset(ubyte ch, ushort preset){
1504 		channels[ch].presetID = preset;
1505 		channels[ch].envGenA.reset;
1506 		channels[ch].envGenA.stages = envGenA.getPtr(preset);
1507 		channels[ch].envGenB.reset;
1508 		channels[ch].envGenB.stages = envGenB.getPtr(preset);
1509 		channels[ch].preset = presets[preset];
1510 		channels[ch].lfo.reset;
1511 		channels[ch].lfo.table = lfoTables.getPtr(channels[ch].preset.lfoWave);
1512 		channels[ch].presetID = preset;
1513 		channels[ch].firFilter[0].impulseResponse = finiteImpulseResponses.getPtr(channels[ch].preset.firTypeL);
1514 		channels[ch].firFilter[1].impulseResponse = finiteImpulseResponses.getPtr(channels[ch].preset.firTypeR);
1515 
1516 	}
1517 	/**
1518 	 * Sets a key-on command on the selected channel with the given note, velocity, and expressive value.
1519 	 */
1520 	public @nogc void keyOn(ubyte ch, ushort note, ushort vel, ushort exprVal){
1521 		channels[ch].keyON = true;
1522 		channels[ch].isRunning = true;
1523 		channels[ch].note = note;
1524 		channels[ch].vel = vel;
1525 		channels[ch].exprVal = exprVal;
1526 		channels[ch].forward = 0;
1527 		//get sample to play
1528 		ChannelPresetSamples cps = sampleLayers[channels[ch].presetID].lookup(note);
1529 		channels[ch].sample = samples.getPtr(cps.sampleSelect);
1530 		//calculate stepping
1531 		if(cps.isPercussive){//if percussive, ignore pitch change except for the pitch bend commands
1532 			channels[ch].baseFreq = cps.midFreq;
1533 			channels[ch].freq = bendFreqByPitch(channels[ch].pitchbend, channels[ch].baseFreq);
1534 			channels[ch].stepping = calculateStepping(channels[ch].freq);
1535 		}else{//calculate note frequency with pitchbend
1536 			const float delta_note = cast(float)note - cast(float)cps.midNote;
1537 			channels[ch].baseFreq = bendFreqByPitch(delta_note, cps.midFreq);
1538 			channels[ch].freq = bendFreqByPitch(channels[ch].pitchbend, channels[ch].baseFreq);
1539 			channels[ch].stepping = calculateStepping(channels[ch].freq);
1540 		}
1541 		channels[ch].enableLooping = cps.isLooping;
1542 		channels[ch].pingPongLoop = cps.pingPongLoop;
1543 		if(channels[ch].preset.resetEGA){
1544 			channels[ch].envGenA.setKeyOn;
1545 		}
1546 		if(channels[ch].preset.resetEGB){
1547 			channels[ch].envGenB.setKeyOn;
1548 		}
1549 		if(channels[ch].preset.resetLFO){
1550 			channels[ch].lfo.reset;
1551 		}
1552 
1553 	}
1554 	/**
1555 	 * Sets a key-off command on the selected channel with the given note, velocity, and expressive value.
1556 	 */
1557 	public @nogc void keyOff(ubyte ch, ushort note, ushort vel, ushort exprVal){
1558 		channels[ch].keyON = false;
1559 		channels[ch].note = note;
1560 		channels[ch].vel = vel;
1561 		channels[ch].exprVal = exprVal;
1562 		channels[ch].envGenA.setKeyOff;
1563 		channels[ch].envGenB.setKeyOff;
1564 	}
1565 	/**
1566 	 * Programs a note into the channel's sequencer.
1567 	 * If exprVal not 0, it sets which note has to be rewritten, otherwise it adds a new note to the sequencer.
1568 	 */
1569 	public @nogc void prgKeyOn(ubyte ch, ushort note, ushort vel, ushort exprVal){
1570 		if(exprVal){
1571 			exprVal--;
1572 			exprVal &= 3;
1573 			channels[ch].arpeggiatorNotes[exprVal] = note;
1574 		}else{
1575 			if(channels[ch].nOfNotes < 3){
1576 				channels[ch].arpeggiatorNotes[channels[ch].nOfNotes] = note;
1577 				channels[ch].nOfNotes = cast(ubyte)(channels[ch].nOfNotes + 1);
1578 			}
1579 		}
1580 	}
1581 	/**
1582 	 * Removes a note from the channel's sequencer.
1583 	 * If note not 0, it removes the note from the list if there's an equal of it.
1584 	 * If exprVal not 0, it removes the given note.
1585 	 */
1586 	public @nogc void prgKeyOff(ubyte ch, ushort note, ushort vel, ushort exprVal){
1587 		if(note){
1588 			for(int i; i < 4; i++)
1589 				if(channels[ch].arpeggiatorNotes[exprVal] == note)
1590 					exprVal = cast(ushort)(i+1);
1591 		}
1592 		if(exprVal){
1593 			exprVal--;
1594 			exprVal &= 3;
1595 			channels[ch].arpeggiatorNotes[exprVal] = 0;
1596 			for(; exprVal < 3; exprVal++)
1597 				channels[ch].arpeggiatorNotes[exprVal] = channels[ch].arpeggiatorNotes[exprVal + 1];
1598 
1599 			if(channels[ch].nOfNotes)
1600 				channels[ch].nOfNotes = cast(ubyte)(channels[ch].nOfNotes - 1);
1601 		}else{
1602 			if(channels[ch].nOfNotes > 0){
1603 				channels[ch].arpeggiatorNotes[channels[ch].nOfNotes] = 0;
1604 				channels[ch].nOfNotes = cast(ubyte)(channels[ch].nOfNotes - 1);
1605 			}
1606 		}
1607 
1608 	}
1609 	/**
1610 	 * Calculates the length of the stepping for each sample.
1611 	 * Uses double precision to ensure precision.
1612 	 */
1613 	protected @nogc uint calculateStepping(float freq){
1614 		return cast(uint)((cast(double)freq / cast(double)sampleRate) * cast(double)WHOLE_STEP_FORWARD);
1615 	}
1616 	override public @nogc int setRenderParams(float samplerate, size_t framelength, size_t nOfFrames){
1617 		this.sampleRate = samplerate;
1618 		this.frameLength = framelength;
1619 		this.nOfFrames = nOfFrames;
1620 		return 0;
1621 	}
1622 	/**
1623 	 * Loads a bank into the synthesizer, also loads samples on the way from the selected sample pool.
1624 	 * For the latter, it'll be able to use compression through lzbacon's datapak file format (default path for
1625 	 * that is ./audio/samplepool.dpk), otherwise a folder with uncompressed data is used (default path for that
1626 	 * is ./audio/samplepool/).
1627 	 */
1628 	override public void loadConfig(ref void[] data){
1629 		import PixelPerfectEngine.system.file : RIFFHeader;
1630 		import std..string : toStringz;
1631 		size_t pos;
1632 		bool riffHeaderFound, envGenAFound, envGenBFound, cpsFound;
1633 		InstrumentPreset currentInstr;
1634 		while(data.length < pos){
1635 			RIFFHeader header = *cast(RIFFHeader*)(data.ptr + pos);
1636 			pos += RIFFHeader.sizeof;
1637 			switch(header.data){
1638 				case RIFFID.riffInitial:
1639 					riffHeaderFound = true;
1640 					break;
1641 				case RIFFID.instrumentPreset:
1642 					envGenAFound = false;
1643 					envGenBFound = false;
1644 					cpsFound = false;
1645 					currentInstr = *cast(InstrumentPreset*)(data.ptr + pos);
1646 					pos += InstrumentPreset.sizeof;
1647 					presets[currentInstr.id] = *cast(ChannelPresetMain*)(data.ptr + pos);
1648 					pos += ChannelPresetMain.sizeof;
1649 					break;
1650 				case RIFFID.envGenA:
1651 					if(!envGenAFound){
1652 						envGenAFound = true;
1653 						EnvelopeStageList ega;
1654 						ega.reserve(currentInstr.egaStages);
1655 						for(int i ; i < currentInstr.egaStages ; i++){
1656 							ega.insertBack(*cast(EnvelopeStage*)(data.ptr + pos));
1657 							pos += EnvelopeStage.sizeof;
1658 						}
1659 						envGenA[currentInstr.id] = ega;
1660 					}
1661 					break;
1662 				case RIFFID.envGenB:
1663 					if(!envGenBFound){
1664 						envGenBFound = true;
1665 						EnvelopeStageList egb;
1666 						egb.reserve(currentInstr.egbStages);
1667 						for(int i ; i < currentInstr.egbStages ; i++){
1668 							egb.insertBack(*cast(EnvelopeStage*)(data.ptr + pos));
1669 							pos += EnvelopeStage.sizeof;
1670 						}
1671 						envGenB[currentInstr.id] = egb;
1672 					}
1673 					break;
1674 				case RIFFID.instrumentData:
1675 					if(!envGenBFound){
1676 						cpsFound = true;
1677 						for(int i ; i < currentInstr.sampleLayers ; i++){
1678 							sampleLayers[currentInstr.id].add(*cast(ChannelPresetSamples*)(data.ptr + pos));
1679 							pos += ChannelPresetSamples.sizeof;
1680 						}
1681 					}
1682 					break;
1683 				/*case RIFFID.instrumentPreset:
1684 					presets[currentInstr.id] = *cast(ChannelPresetMain*)(data.ptr + pos);
1685 					pos += ChannelPresetMain.sizeof;
1686 					break;*/
1687 				case RIFFID.samplePreset:
1688 					SamplePreset slmp = *cast(SamplePreset*)(data.ptr + pos);
1689 					pos += SamplePreset.sizeof;
1690 					string filename = samplePoolPath;
1691 					foreach(c ; slmp.name){
1692 						if(c){
1693 							filename ~= c;
1694 						}else{
1695 							break;
1696 						}
1697 					}
1698 					filename ~= ".pcm";
1699 					PCMFile file = loadPCMFile(toStringz(filename));
1700 					//sampleSrc ~= file.data;
1701 					Sample s;
1702 					s.codec = file.data.codecType;
1703 					s.sampleFreq = slmp.freq;
1704 					s.length = file.header.length;
1705 					s.dataPtr = cast(ubyte*)malloc(file.data.data.length);
1706 					memcpy(s.dataPtr, file.data.data.ptr, file.data.data.length);
1707 					file.destroy;
1708 					samples[slmp.id] = s;
1709 					break;
1710 				case RIFFID.fiResponse:
1711 					FXSamplePreset slmp = *cast(FXSamplePreset*)(data.ptr + pos);
1712 					pos += FXSamplePreset.sizeof;
1713 					string filename = samplePoolPath;
1714 					foreach(c ; slmp.name){
1715 						if(c){
1716 							filename ~= c;
1717 						}else{
1718 							break;
1719 						}
1720 					}
1721 					filename ~= ".pcm";
1722 					PCMFile file = loadPCMFile(toStringz(filename));
1723 					FiniteImpulseResponse!(FIR_TABLE_LENGTH) fir;
1724 					memcpy(fir.vals.ptr, file.data.data.ptr, FIR_TABLE_LENGTH);
1725 					file.destroy;
1726 					finiteImpulseResponses[slmp.id] = fir;
1727 					break;
1728 				case RIFFID.lfoPreset:
1729 					FXSamplePreset slmp = *cast(FXSamplePreset*)(data.ptr + pos);
1730 					pos += FXSamplePreset.sizeof;
1731 					string filename = samplePoolPath;
1732 					foreach(c ; slmp.name){
1733 						if(c){
1734 							filename ~= c;
1735 						}else{
1736 							break;
1737 						}
1738 					}
1739 					filename ~= ".pcm";
1740 					PCMFile file = loadPCMFile(toStringz(filename));
1741 					ubyte[LFO_TABLE_LENGTH] table;
1742 					memcpy(table.ptr, file.data.data.ptr, FIR_TABLE_LENGTH);
1743 					file.destroy;
1744 					lfoTables[slmp.id] = table;
1745 					break;
1746 				case RIFFID.globalSettings:
1747 					globals = *cast(GlobalSettings*)(data.ptr + pos);
1748 					pos += GlobalSettings.sizeof;
1749 					break;
1750 				default:
1751 					throw new Exception("Invalid data error!");
1752 			}
1753 		}
1754 	}
1755 	/**
1756 	 *Not supported currently
1757 	 */
1758 	override public ref void[] saveConfig(){
1759 		throw new Exception("Unimplemented feature!");
1760 	}
1761 }
1762