1 module pixelperfectengine.audio.modules.pcm8;
2 
3 import pixelperfectengine.audio.base.modulebase;
4 import pixelperfectengine.audio.base.types;
5 import pixelperfectengine.audio.base.envgen;
6 import pixelperfectengine.audio.base.func;
7 import pixelperfectengine.audio.base.envgen;
8 import pixelperfectengine.audio.base.osc;
9 import pixelperfectengine.system.etc : min;
10 
11 import std.math;
12 import core.stdc.string;
13 
14 import collections.treemap;
15 
16 import inteli.emmintrin;
17 
18 import midi2.types.structs;
19 import midi2.types.enums;
20 
21 import bitleveld.datatypes;
22 
23 /**
24 PCM8 - implements a sample-based synthesizer.
25 
26 It has support for 
27  * 8 bit and 16 bit linear PCM
28  * Mu-Law and A-Law PCM
29  * IMA ADPCM
30  * Dialogic ADPCM
31 
32 The module has 8 sample-based channels with looping capabilities and each has an ADSR envelop, and 4 outputs with a filter.
33 */
34 public class PCM8 : AudioModule {
35 	shared static this () {
36 		import std.range : iota;
37 		import std.conv : to;
38 		for (uint i ; i < 128 ; i++) {		//TODO: Make a version to leave this out, otherwise it'll just consume memory for the end user.
39 			SAMPLE_SET_VALS ~= MValue(MValueType.Int32, i | 0x10_00, "Sample-"~to!string(i)~"_Select");
40 			SAMPLE_SET_VALS ~= MValue(MValueType.Float, i | 0x11_00, "Sample-"~to!string(i)~"_SlmpFreq");
41 			SAMPLE_SET_VALS ~= MValue(MValueType.Int32, i | 0x12_00, "Sample-"~to!string(i)~"_LoopBegin");
42 			SAMPLE_SET_VALS ~= MValue(MValueType.Int32, i | 0x13_00, "Sample-"~to!string(i)~"_LoopEnd");
43 		}
44 		for (int i ; i < 128 ; i++) {
45 			ADSR_TIME_TABLE[i] = pow(i / 64.0, 1.8);
46 		}
47 	}
48 	protected static immutable MValue[] SAMPLE_SET_VALS;
49 	public static immutable float[128] ADSR_TIME_TABLE;
50 	/**
51 	Contains a table to calculate Sustain control values.
52 
53 	All values are seconds with fractions. Actual values are live-calculated depending on sustain level and sampling
54 	frequency. Please note that with certain levels of sustain, the actual max time might be altered.
55 	*/
56 	public static immutable float[63] SUSTAIN_CONTROL_TIME_TABLE = [
57 	//	0     |1     |2     |3     |4     |5     |6     |7     |8     |9     |A     |B     |C     |D     |E     |F
58 		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
59 		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
60 		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
61 		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
62 	];
63 	alias DecodeFunc = void function(ubyte[] src, int[] dest, ref DecoderWorkpad wp) @nogc nothrow pure;
64 	/**
65 	Defines a single sample.
66 	*/
67 	protected struct Sample {
68 		///Stores sample data, which later can be decompressed
69 		ubyte[]		sampleData;
70 		///Stores what kind of format the sample has
71 		WaveFormat	format;
72 		///Points to the decoder function
73 		DecodeFunc	decode;
74 		size_t samplesLength() @nogc @safe pure nothrow const {
75 			return (sampleData.length * 8) / format.bitsPerSample;
76 		}
77 	}
78 	/**
79 	Defines a single sample-to-note assignment.
80 	*/
81 	protected struct SampleAssignment {
82 		///Number of sample that is assigned.
83 		uint		sampleNum;
84 		///The base frequency of the sample.
85 		///Overrides the format definition.
86 		float		baseFreq;
87 		///Start of a looppoint.
88 		///-1, if looppoint is not available.
89 		int			loopBegin	=	-1;
90 		///End of a looppoint.
91 		///-1, if looppoint is not available.
92 		int			loopEnd		=	-1;
93 	}
94 	/** 
95 	Stores preset information.
96 	*/
97 	protected struct Preset {
98 		/// Stores sample mappings for each note.
99 		SampleAssignment[128]	sampleMapping;
100 		ubyte			eAtk;		///Attack time selector
101 		ubyte			eDec;		///Decay time selector
102 		ubyte			eSusC;		///Sustain control (0: percussive; 1-63: descending; 64: constant; 65-127: ascending)
103 		ubyte			eRel;		///Release time selector
104 		float			eAtkShp = 0.5;///Attack shaping
105 		float			eRelShp = 0.5;///Release shaping
106 		float			eSusLev = 1;///Sustain level
107 		float			masterVol = 1;///Master output volume
108 		float			balance = 0.5;///Master output balance
109 		float			auxSendA = 0;///Aux send level A
110 		float			auxSendB = 0;///Aux send level B
111 		float			velToLevelAm = 0;///Assigns velocity to output levels
112 		float			velToAuxSendAm = 0;///Assigns velocity to aux send levels
113 		float			velToAtkShp = 0;///Assigns velocity to attack shape of envelop generator
114 		float			velToRelShp = 0;///Assigns velocity to release shape of envelop generator
115 		float			lfoToVol = 0;	///Tremolo level (LFO to volume)
116 		float			adsrToVol = 0;	///ADSR to output level amount 
117 		float			adsrToDetune = 0;///ADSR to pitch bend amount
118 		float			vibrAm = 0;	///FLO to pitch bend amount
119 
120 		float			pitchBendAm = 2;///Pitch bend range
121 
122 		uint			flags;		///Contains various binary settings
123 	}
124 	///Defines preset setting flags.
125 	protected enum PresetFlags {
126 		cutoffOnKeyOff		=	1<<0,		///If set, the sample playback will cut off on every key off event
127 		modwheelToLFO		=	1<<1,		///Assigns modulation wheel to amplitude and/or pitch LFO levels
128 		panningLFO			=	1<<2,		///Sets amplitude LFO to panning on this channel
129 		/* ADSRtoVol			=	1<<3,		///If set, then envGen will control the volume */
130 	}
131 	///Defines LFO setting flags.
132 	protected enum LFOFlags {
133 		saw					=	1<<0,
134 		triangle			=	1<<1,
135 		pulse				=	1<<2,
136 		sawpulse			=	1<<3,
137 		invert				=	1<<4,
138 		ringmod				=	1<<5
139 	}
140 	///Defines channel statuses.
141 	protected enum ChannelStatusFlags {
142 		noteOn				=	1<<0,	///Set if key is on
143 		sampleRunout		=	1<<1,	///Set if sample have ran out (decoder proceeds to stop)
144 		inLoop				=	1<<2,	///Set if sample is looping
145 	}
146 	/**
147 	Defines a single channel's statuses.
148 	*/
149 	protected struct Channel {
150 		//int[256]		decoderBuffer;
151 		int[256]		decoderBuffer;		///Stores decoded samples.
152 		Preset			presetCopy;			///The copy of the preset.
153 		DecoderWorkpad	decoderWorkpad;		///Stores the current state of the decoder.
154 		DecoderWorkpad	savedDWState;		///The state of the decoder when the beginning of the looppoint has been reached.
155 		WavemodWorkpad	waveModWorkpad;		///Stores the current state of the wave modulator.
156 		double			freqRatio;			///Sampling-to-playback frequency ratio, with pitch bend, LFO, and envGen applied.
157 		long			outPos;				///Position in decoded amount with fractions.
158 		uint			decodeAm;			///Decoded amount
159 		uint 			jumpAm;				///Jump amount for current sample, calculated from freqRatio.
160 		//WavemodWorkpad	savedWMWState;		///The state of the wave modulator when the beginning of the looppoint has been reached.
161 		ADSREnvelopGenerator	envGen;		///Channel envelop generator.
162 
163 		ubyte			currNote = 255;		///The currently played note + Bit 8 indicates suspension.
164 		ubyte			presetNum;			///Selected preset.
165 		ushort			bankNum;			///Bank select number.
166 		uint			status;				///Channel status flags. Bit 1: Note on, Bit 2: Sample run out approaching, Bit 3: In loop
167 
168 		float			pitchBend = 0;		///Current amount of pitch bend.
169 
170 		float			velocity;			///Velocity normalized between 0 and 1
171 		float			modWheel;			///Modulation wheel normalized between 0 and 1
172 
173 		float			currShpA;			///The current attack shape
174 		float			currShpR;			///The current release shape
175 		/**
176 		Decodes one more block worth of samples, depending on internal state.
177 		*/
178 		void decodeMore(ref SampleAssignment sa, ref Sample slmp) @nogc nothrow pure {
179 			if (status & ChannelStatusFlags.sampleRunout) {
180 				currNote = 255;
181 			}
182 			if (currNote == 255) {
183 				return;
184 			}
185 			//Determine how much samples we will need.
186 			size_t samplesNeeded = 128;
187 			//Determine offset based on which cycle we will need
188 			size_t offset = decodeAm & 0x80 ? 128 : 0;
189 			
190 			const bool keyOn = (status & 1) == 1;
191 			const bool isLooping = (sa.loopBegin != -1 && sa.loopEnd != -1) && ((sa.loopEnd - sa.loopBegin) > 0) && keyOn;
192 			
193 			//Case 1: sample is running out, and there are no looppoints.
194 			if (!isLooping && (decoderWorkpad.pos + samplesNeeded >= slmp.samplesLength())) {
195 				samplesNeeded -= decoderWorkpad.pos + samplesNeeded - slmp.samplesLength();
196 				status |= ChannelStatusFlags.sampleRunout;
197 				for (size_t i = samplesNeeded ; i < 128 ; i++) 
198 					decoderBuffer[offset + i] = 0;
199 			}
200 			size_t dPos = offset;	//Decoder position
201 			while (samplesNeeded > 0) {
202 				//Case 2: sample might enter the beginning or the end of the loop.
203 				//If loop is short enough, it can happen multiple times
204 				const bool loopBegin = isLooping && (decoderWorkpad.pos + samplesNeeded >= sa.loopBegin) && 
205 						!(status & ChannelStatusFlags.inLoop);
206 				const bool loopEnd = isLooping && (decoderWorkpad.pos + samplesNeeded >= sa.loopEnd);
207 				const size_t samplesToDecode = loopBegin ? decoderWorkpad.pos + samplesNeeded - sa.loopBegin : (loopEnd ? 
208 						decoderWorkpad.pos + samplesNeeded - sa.loopEnd : samplesNeeded);
209 				slmp.decode(slmp.sampleData, decoderBuffer[dPos..offset + samplesToDecode], decoderWorkpad);
210 				if (loopBegin) {
211 					status |= ChannelStatusFlags.inLoop;
212 					savedDWState = decoderWorkpad;
213 				} else if (loopEnd) {
214 					decoderWorkpad = savedDWState;
215 					outPos = savedDWState.pos<<24;
216 				}
217 				samplesNeeded -= samplesToDecode;
218 				dPos += samplesToDecode;
219 				decodeAm += samplesToDecode;
220 				//outPos += samplesToAdvance;
221 			}
222 		}
223 		///Calculates jump amount for the sample.
224 		void calculateJumpAm(int sampleRate) @nogc @safe pure nothrow {
225 			freqRatio = sampleRate / bendFreq(presetCopy.sampleMapping[currNote & 127].baseFreq, pitchBend);
226 			jumpAm = cast(uint)((1<<24) / freqRatio);
227 		}
228 		///Resets all internal states.
229 		void reset() @nogc @safe pure nothrow {
230 			outPos = 0;
231 			status = 0;
232 			decodeAm = 0;
233 			decoderWorkpad = DecoderWorkpad.init;
234 			savedDWState = DecoderWorkpad.init;
235 			waveModWorkpad = WavemodWorkpad.init;
236 		}
237 		///Recalculates shape params.
238 		void setShpVals(float vel = 1.0) @nogc @safe pure nothrow {
239 			currShpA = presetCopy.eAtkShp - (presetCopy.velToAtkShp * presetCopy.eAtkShp) + 
240 					(presetCopy.velToAtkShp * presetCopy.eAtkShp * vel);
241 			currShpR = presetCopy.eRelShp - (presetCopy.velToRelShp * presetCopy.eRelShp) + 
242 					(presetCopy.velToRelShp * presetCopy.eRelShp * vel);
243 		}
244 	}
245 	alias SampleMap = TreeMap!(uint, Sample);
246 	alias PresetMap = TreeMap!(uint, Preset);
247 	protected SampleMap		sampleBank;			///Stores all current samples.
248 	protected PresetMap		presetBank;			///Stores all current presets. (bits: 0-6: preset number, 7-13: bank lsb, 14-20: bank msb)
249 	protected Channel[8]	channels;			///Channel status data.
250 	protected MultiTapOsc	lfo;				///Low frequency oscillator to modify values in real-time
251 	protected float[]		lfoOut;				///LFO output buffer
252 	protected uint			lfoFlags;			///LFO state flags
253 	protected float			lfoFreq;			///LFO frequency
254 	protected float			lfoPWM;				///LFO pulse width modulation
255 	protected float[]		dummyBuf;			///Dummy buffer if one or more output aren't used
256 	protected int[]			iBuf;				///Integer output buffers
257 	protected __m128[]		lBuf;				///Local output buffer
258 	///Stores output filter values.
259 	///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]
260 	protected __m128[10]		filterVals;
261 	///Stores control values of the output values.
262 	///Layout: [LF, LQ, RF, RQ, AF, AQ, BF, BQ]
263 	protected float[8]			filterCtrl	=	[16_000, 0.707, 16_000, 0.707, 16_000, 0.707, 16_000, 0.707];
264 	protected float				mixdownVal = short.max + 1;
265 	protected ubyte[32]			sysExBuf;		///SysEx command buffer [0-30] + length [31]
266 	protected ubyte[68][9]		chCtrlLower;	///Lower parts of the channel controllers (0-31 / 32-63) + (Un)registered parameter select (64-65)
267 	public this() @safe nothrow {
268 		info.nOfAudioInput = 0;
269 		info.nOfAudioOutput = 4;
270 		info.outputChNames = ["mainL", "mainR", "auxSendA", "auxSendB"];
271 		info.isInstrument = true;
272 		info.hasMidiIn = true;
273 		info.hasMidiOut = true;
274 		info.midiSendback = true;
275 		lfo = MultiTapOsc.init;
276 	}
277 	/**
278 	 * Sets the module up.
279 	 *
280 	 * Can be overridden in child classes to allow resets.
281 	 */
282 	public override void moduleSetup(ubyte[] inputs, ubyte[] outputs, int sampleRate, size_t bufferSize, 
283 			ModuleManager handler) @safe nothrow {
284 		enabledInputs = StreamIDSet(inputs);
285 		enabledOutputs = StreamIDSet(outputs);
286 		this.sampleRate = sampleRate;
287 		this.bufferSize = bufferSize;
288 		/+for (int i ; i < 8 ; i++) {
289 			channels[i].decoderBuffer.length = bufferSize * 2;
290 		}+/
291 		dummyBuf.length = bufferSize;
292 		iBuf.length = bufferSize;
293 		lBuf.length = bufferSize;
294 		lfoOut.length = bufferSize;
295 		this.handler = handler;
296 		//Reset filters
297 		for (int i ; i < 4 ; i++) {
298 			resetLPF(i);
299 			filterVals[6][i] = 0;
300 			filterVals[7][i] = 0;
301 			filterVals[8][i] = 0;
302 			filterVals[9][i] = 0;
303 		}
304 	}
305 	///Recalculates the low pass filter vlues for the given output channel.
306 	protected void resetLPF(int i) @nogc @safe pure nothrow {
307 		BiquadFilterValues vals = createLPF(sampleRate, filterCtrl[i * 2], filterCtrl[(i * 2) + 1]);
308 		filterVals[0][i] = vals.a0;
309 		filterVals[1][i] = vals.a1;
310 		filterVals[2][i] = vals.a2;
311 		filterVals[3][i] = vals.b0;
312 		filterVals[4][i] = vals.b1;
313 		filterVals[5][i] = vals.b2;
314 	}
315 	/**
316 	 * MIDI 2.0 data received here.
317 	 *
318 	 * data0: Header of the up to 128 bit MIDI 2.0 data.
319 	 * data1-3: Other packets if needed.
320 	 */
321 	public override void midiReceive(UMP data0, uint data1 = 0, uint data2 = 0, uint data3 = 0) @nogc nothrow {
322 		switch (data0.msgType) {
323 			case MessageType.MIDI1:
324 				if (data0.channel < 8) {
325 					switch (data0.status) {
326 						case MIDI1_0Cmd.PitchBend:
327 							channels[data0.channel].pitchBend = channels[data0.channel].presetCopy.pitchBendAm * 
328 									((cast(double)data0.bend - 0x20_00) / 0x3F_FF);
329 							channels[data0.channel].calculateJumpAm(sampleRate);
330 							break;
331 						case MIDI1_0Cmd.NoteOn:
332 							keyOn(data0.note, data0.channel, data0.value/127.0);
333 							break;
334 						case MIDI1_0Cmd.NoteOff:
335 							keyOff(data0.note, data0.channel, data0.value/127.0);
336 							break;
337 						case MIDI1_0Cmd.CtrlCh:
338 							uint val;
339 							if (data0.note < 64) {
340 								chCtrlLower[data0.channel][data0.note] = data0.value;
341 								val = convertM1CtrlValToM2(chCtrlLower[data0.channel][data0.note & 0x1F], 
342 										chCtrlLower[data0.channel][data0.note | 0x20]);
343 							} else if (data0.note >= 70 && data0.note <= 73) {
344 								val = data0.value<<25;
345 							} else {
346 								val = convertM1CtrlValToM2(data0.value, data0.value);
347 							}
348 							if (data0.note == 0 || data0.note == 32)
349 								channels[data0.channel].bankNum = (chCtrlLower[data0.channel][0]<<7) | chCtrlLower[data0.channel][32];
350 							else
351 								ctrlCh (data0.channel, data0.note, val);
352 							break;
353 						case MIDI1_0Cmd.PrgCh:
354 							channels[data0.channel].presetCopy = presetBank[(channels[data0.channel].bankNum<<7) | data0.note];
355 							channels[data0.channel].presetNum = data0.note;
356 							break;
357 						default:
358 							break;
359 					}
360 				}
361 				break;
362 			case MessageType.MIDI2:
363 				if (data0.channel < 8) {
364 					switch (data0.status) {
365 						case MIDI2_0Cmd.PitchBend:
366 							channels[data0.channel].pitchBend = channels[data0.channel].presetCopy.pitchBendAm * 
367 									((cast(double)data1 - int.max) / (int.max));
368 							channels[data0.channel].calculateJumpAm(sampleRate);
369 							break;
370 						case MIDI2_0Cmd.NoteOn:
371 							NoteVals nv = *cast(NoteVals*)&data1;
372 							keyOn(data0.note, data0.channel, nv.velocity / ushort.max);
373 							break;
374 						case MIDI2_0Cmd.NoteOff:
375 							NoteVals nv = *cast(NoteVals*)&data1;
376 							keyOff(data0.note, data0.channel, nv.velocity / ushort.max);
377 							break;
378 						case MIDI2_0Cmd.CtrlChOld, MIDI2_0Cmd.CtrlCh:
379 							ctrlCh(data0.channel, data0.note, data1);
380 							break;
381 						case MIDI2_0Cmd.PrgCh:
382 							channels[data0.channel].bankNum = data1 & ushort.max;
383 							channels[data0.channel].presetNum = data1>>24;
384 							presetRecall(data0.channel);
385 							break;
386 						default:
387 							break;
388 					}
389 				}
390 				break;
391 			case MessageType.Data64:
392 				if (data0.status == SysExSt.Start || data0.status == SysExSt.Complete)
393 					sysExBuf[31] = 0;
394 				ubyte[4] packet1 = [cast(ubyte)(data1>>24), cast(ubyte)(data1>>16), cast(ubyte)(data1>>8), cast(ubyte)data1];
395 				int length = data0.channel;
396 				for (int i ; i < 2 && length - 4 > 0 ; i++, length--) {
397 					sysExBuf[sysExBuf[31]] = data0.bytes[i];
398 					sysExBuf[31]++;
399 					if (sysExBuf[31] > 30) {
400 						length = 0;
401 						sysExBuf[31] = 0;
402 					}
403 				}
404 				for (int i ; i < 4 && length > 0 ; i++, length--) {
405 					sysExBuf[sysExBuf[31]] = packet1[i];
406 					sysExBuf[31]++;
407 					if (sysExBuf[31] > 30) {
408 						length = 0;
409 						sysExBuf[31] = 0;
410 					}
411 				}
412 				if (data0.status == SysExSt.Complete || data0.status == SysExSt.End)
413 					sysExCmd(sysExBuf[0..sysExBuf[31]]);
414 				break;
415 			case MessageType.Data128:
416 				if (data0.status == SysExSt.Start || data0.status == SysExSt.Complete)
417 					sysExBuf[31] = 0;
418 				ubyte[13] data = [data0.value, 
419 						cast(ubyte)(data1>>24), cast(ubyte)(data1>>16), cast(ubyte)(data1>>8), cast(ubyte)data1,
420 						cast(ubyte)(data2>>24), cast(ubyte)(data2>>16), cast(ubyte)(data2>>8), cast(ubyte)data2,
421 						cast(ubyte)(data3>>24), cast(ubyte)(data3>>16), cast(ubyte)(data3>>8), cast(ubyte)data3];
422 				for (int i ; i < data0.channel ; i++, sysExBuf[31]++) {
423 					sysExBuf[sysExBuf[31]] = data[i];
424 					if (sysExBuf[31] > 30)
425 						sysExBuf[31] = 0;
426 				}
427 				if (data0.status == SysExSt.Complete || data0.status == SysExSt.End)
428 					sysExCmd(sysExBuf[0..sysExBuf[31]]);
429 				break;
430 			default:
431 				break;
432 		}
433 	}
434 	protected void keyOn(ubyte note, ubyte ch, float vel) @nogc pure nothrow {
435 		channels[ch].currNote = note;
436 		channels[ch].velocity = vel;
437 		channels[ch].calculateJumpAm(sampleRate);
438 		channels[ch].setShpVals(vel);
439 		//reset all on channel
440 		channels[ch].reset();
441 		//set noteOn status flag
442 		channels[ch].status |= ChannelStatusFlags.noteOn;
443 	}
444 	protected void keyOff(ubyte note, ubyte ch, float vel) @nogc pure nothrow {
445 		if (!(channels[ch].currNote & 128))
446 			channels[ch].currNote = note;
447 		channels[ch].velocity = vel;
448 		channels[ch].calculateJumpAm(sampleRate);
449 		channels[ch].setShpVals(vel);
450 		channels[ch].status &= ~ChannelStatusFlags.noteOn;
451 	}
452 	protected void ctrlCh(ubyte ch, ubyte param, uint val) @nogc pure nothrow {
453 		if (param >= 32 && param < 64) param &= 0x1F;
454 		if (ch <= 7) {	//Channel locals
455 			switch (param) {
456 				case 7:
457 					channels[ch].presetCopy.masterVol = (1.0 / uint.max) * val;
458 					break;
459 				case 8:
460 					channels[ch].presetCopy.balance = (1.0 / uint.max) * val;
461 					break;
462 				case 91:
463 					channels[ch].presetCopy.auxSendA = (1.0 / uint.max) * val;
464 					break;
465 				case 92:
466 					channels[ch].presetCopy.auxSendB = (1.0 / uint.max) * val;
467 					break;
468 				case 73:
469 					channels[ch].presetCopy.eAtk = cast(ubyte)(val>>25);
470 					break;
471 				case 14:
472 					channels[ch].presetCopy.eAtkShp = (1.0 / uint.max) * val;
473 					break;
474 				case 70:
475 					channels[ch].presetCopy.eDec = cast(ubyte)(val>>25);
476 					break;
477 				case 71:
478 					channels[ch].presetCopy.eSusC = cast(ubyte)(val>>25);
479 					break;
480 				case 9:
481 					channels[ch].presetCopy.eSusLev = (1.0 / uint.max) * val;
482 					break;
483 				case 72:
484 					channels[ch].presetCopy.eRel = cast(ubyte)(val>>25);
485 					break;
486 				case 15:
487 					channels[ch].presetCopy.eRelShp = (1.0 / uint.max) * val;
488 					break;
489 				case 20:
490 					channels[ch].presetCopy.velToLevelAm = (1.0 / uint.max) * val;
491 					break;
492 				case 21:
493 					channels[ch].presetCopy.velToAuxSendAm = (1.0 / uint.max) * val;
494 					break;
495 				case 22:
496 					channels[ch].presetCopy.velToAtkShp = (1.0 / uint.max) * val;
497 					break;
498 				case 23:
499 					channels[ch].presetCopy.velToRelShp = (1.0 / uint.max) * val;
500 					break;
501 				case 24:
502 					channels[ch].presetCopy.lfoToVol = (1.0 / uint.max) * val;
503 					break;
504 				case 25:
505 					channels[ch].presetCopy.adsrToVol = (1.0 / uint.max) * val;
506 					break;
507 				case 26:
508 					channels[ch].presetCopy.adsrToDetune = (1.0 / uint.max) * val * 24;
509 					break;
510 				case 27:
511 					channels[ch].presetCopy.vibrAm = (1.0 / uint.max) * val * 12;
512 					break;
513 				case 102:
514 					if (val)
515 						channels[ch].presetCopy.flags |= PresetFlags.cutoffOnKeyOff;
516 					else
517 						channels[ch].presetCopy.flags &= ~PresetFlags.cutoffOnKeyOff;
518 					break;
519 				case 103:
520 					if (val)
521 						channels[ch].presetCopy.flags |= PresetFlags.modwheelToLFO;
522 					else
523 						channels[ch].presetCopy.flags &= ~PresetFlags.modwheelToLFO;
524 					break;
525 				case 104:
526 					if (val)
527 						channels[ch].presetCopy.flags |= PresetFlags.panningLFO;
528 					else
529 						channels[ch].presetCopy.flags &= ~PresetFlags.panningLFO;
530 					break;
531 				default:
532 					break;
533 			}
534 		} else if (ch == 8) {	//Module globals
535 			switch (param) {
536 				case 2:
537 					filterCtrl[0] = (1.0 / uint.max) * val * 16_000;
538 					resetLPF(0);
539 					break;
540 				case 3:
541 					filterCtrl[1] = (1.0 / uint.max) * val * 40;
542 					resetLPF(0);
543 					break;
544 				case 4:
545 					filterCtrl[2] = (1.0 / uint.max) * val * 16_000;
546 					resetLPF(1);
547 					break;
548 				case 5:
549 					filterCtrl[3] = (1.0 / uint.max) * val * 40;
550 					resetLPF(1);
551 					break;
552 				case 6:
553 					filterCtrl[4] = (1.0 / uint.max) * val * 16_000;
554 					resetLPF(2);
555 					break;
556 				case 7:
557 					filterCtrl[5] = (1.0 / uint.max) * val * 40;
558 					resetLPF(2);
559 					break;
560 				case 8:
561 					filterCtrl[6] = (1.0 / uint.max) * val * 16_000;
562 					resetLPF(3);
563 					break;
564 				case 9:
565 					filterCtrl[7] = (1.0 / uint.max) * val * 40;
566 					resetLPF(3);
567 					break;
568 				case 10:
569 					if (lfoFlags & LFOFlags.ringmod)
570 						lfoFreq = noteToFreq((1.0 / uint.max) * val * 127);
571 					else
572 						lfoFreq = (1.0 / uint.max) * val * 20;
573 					resetLFO();
574 					break;
575 				case 11:
576 					lfoPWM = (1.0 / uint.max) * val;
577 					resetLFO();
578 					break;
579 				case 102:
580 					if (val)
581 						lfoFlags |= LFOFlags.saw;
582 					else
583 						lfoFlags &= ~LFOFlags.saw;
584 					resetLFO();
585 					break;
586 				case 103:
587 					if (val)
588 						lfoFlags |= LFOFlags.triangle;
589 					else
590 						lfoFlags &= ~LFOFlags.triangle;
591 					resetLFO();
592 					break;
593 				case 104:
594 					if (val)
595 						lfoFlags |= LFOFlags.pulse;
596 					else
597 						lfoFlags &= ~LFOFlags.pulse;
598 					resetLFO();
599 					break;
600 				case 105:
601 					if (val)
602 						lfoFlags |= LFOFlags.sawpulse;
603 					else
604 						lfoFlags &= ~LFOFlags.sawpulse;
605 					resetLFO();
606 					break;
607 				case 106:
608 					if (val)
609 						lfoFlags |= LFOFlags.invert;
610 					else
611 						lfoFlags &= ~LFOFlags.invert;
612 					resetLFO();
613 					break;
614 				case 107:
615 					if (val)
616 						lfoFlags |= LFOFlags.ringmod;
617 					else
618 						lfoFlags &= ~LFOFlags.ringmod;
619 					resetLFO();
620 					break;
621 				default:
622 					break;
623 			}
624 		}
625 	}
626 	protected void sysExCmd(ubyte[] msg) @nogc nothrow {
627 		//Check manufacturer ID (7D: internal use)
628 		if (msg[0] == 0x7D || msg[1] == 0x7D) {
629 			const int msgPos = msg[0] ? 1 : 2;
630 			switch (msg[msgPos]) {
631 				case 0x01:	//Suspend channel
632 					if (msg[msgPos + 1] >= 8) return;
633 					if (!(channels[msg[msgPos + 1]].status & ChannelStatusFlags.sampleRunout)) {
634 						channels[msg[msgPos + 1]].currNote |= 0x80;
635 					}
636 					break;
637 				case 0x02:	//Resume channel
638 					if (msg[msgPos + 1] >= 8) return;
639 					if (!(channels[msg[msgPos + 1]].status & ChannelStatusFlags.sampleRunout)) {
640 						channels[msg[msgPos + 1]].currNote &= 0x7F;
641 					}
642 					break;
643 				case 0x03:	//Overwrite preset
644 					if (msg[msgPos + 1] >= 8) return;
645 					if (msg.length == msgPos + 5) {
646 						channels[msg[msgPos + 1]].presetNum = msg[msgPos + 2];
647 						channels[msg[msgPos + 1]].bankNum = (msg[msgPos + 3]>>1) | msg[msgPos + 4];
648 					}
649 					*(presetBank.ptrOf((channels[msg[msgPos + 1]].bankNum<<7) | channels[msg[msgPos + 1]].presetNum)) = 
650 							channels[msg[msgPos + 1]].presetCopy;
651 					break;
652 				case 0x20:	//Jump to sample position by restoring codec data
653 					if (msg[msgPos + 1] >= 8) return;
654 					channels[msg[msgPos + 1]].decoderWorkpad.pos = (msg[msgPos + 2] << 21) | (msg[msgPos + 3] << 14) | 
655 						(msg[msgPos + 4] << 7) | msg[msgPos + 5];
656 					channels[msg[msgPos + 1]].waveModWorkpad.lookupVal = 0;
657 					if (msg.length == msgPos + 10) {
658 						channels[msg[msgPos + 1]].decoderWorkpad.pred = msg[msgPos + 6];
659 						channels[msg[msgPos + 1]].decoderWorkpad.outn1 = (msg[msgPos + 7]<<30) | (msg[msgPos + 8]<<23) | 
660 								(msg[msgPos + 9]<<16);
661 						channels[msg[msgPos + 1]].decoderWorkpad.outn1>>=16;
662 					}
663 					//decode the sample
664 					if (channels[msg[msgPos + 1]].currNote & 128) return;
665 					//get the data for the sample
666 					SampleAssignment sa = channels[msg[msgPos + 1]].presetCopy.sampleMapping[channels[msg[msgPos + 1]].currNote];
667 					Sample slmp = sampleBank[sa.sampleNum];
668 					channels[msg[msgPos + 1]].decodeMore(sa, slmp);
669 					break;
670 				case 0x21:	//Dump codec data
671 					if (msg[msgPos + 1] >= 8) return;
672 					uint[2] dump;
673 					const int delta = channels[msg[msgPos + 1]].decoderWorkpad.outn1;
674 					dump[0] = cast(uint)channels[msg[msgPos + 1]].decoderWorkpad.pos;
675 					dump[0] = ((dump[0] & 0xF_E0_00_00)<<3) | ((dump[0] & 0x1F_C0_00)<<2) | ((dump[0] & 0x3F_80)<<1) | (dump[0] & 0x7F);
676 					dump[1] = channels[msg[msgPos + 1]].decoderWorkpad.pred<<24;
677 					dump[1] |= ((delta & 0xC0_00)<<2) | ((delta & 0x3F_80)<<1) | (delta & 0x7F);
678 					if (midiOut !is null) midiOut(UMP(MessageType.Data128, 0x0, SysExSt.Complete, 9, 0x0, 0x7D), dump[0], 
679 							dump[1]);
680 					break;
681 				case 0xA0:	//Jump to sample position by restoring codec data (8bit)
682 					if (msg[msgPos + 1] >= 8) return;
683 					channels[msg[msgPos + 1]].decoderWorkpad.pos = (msg[msgPos + 2] << 24) | (msg[msgPos + 3] << 16) | 
684 						(msg[msgPos + 4] << 8) | msg[msgPos + 5];
685 					channels[msg[msgPos + 1]].waveModWorkpad.lookupVal = 0;
686 					if (msg.length == msgPos + 9) {
687 						channels[msg[msgPos + 1]].decoderWorkpad.pred = msg[msgPos + 6];
688 						channels[msg[msgPos + 1]].decoderWorkpad.outn1 = (msg[msgPos + 7]<<24) | (msg[msgPos + 8]<<16);
689 						channels[msg[msgPos + 1]].decoderWorkpad.outn1>>=16;
690 					}
691 					//decode the sample
692 					if (channels[msg[msgPos + 1]].currNote & 128) return;
693 					//get the data for the sample
694 					SampleAssignment sa = channels[msg[msgPos + 1]].presetCopy.sampleMapping[channels[msg[msgPos + 1]].currNote];
695 					Sample slmp = sampleBank[sa.sampleNum];
696 					channels[msg[msgPos + 1]].decodeMore(sa, slmp);
697 					break;
698 				case 0xA1:	//Dump codec data (8bit)
699 					if (msg[msgPos + 1] >= 8) return;
700 					uint[2] dump;
701 					dump[0] = cast(uint)channels[msg[msgPos + 1]].decoderWorkpad.pos;
702 					dump[1] = channels[msg[msgPos + 1]].decoderWorkpad.pred<<24;
703 					dump[1] |= (channels[msg[msgPos + 1]].decoderWorkpad.outn1 & ushort.max)<<8;
704 					if (midiOut !is null) midiOut(UMP(MessageType.Data128, 0x0, SysExSt.Complete, 8, 0x0, 0x7D), dump[0], 
705 							dump[1]);
706 					break;
707 				default:
708 					break;
709 			}
710 		}
711 	}
712 	protected void resetLFO() @nogc @safe pure nothrow {
713 		const int divident = ((lfoFlags>>3) & 1) + ((lfoFlags>>2) & 1) + ((lfoFlags>>1) & 1) + (lfoFlags & 1);
714 		const short value = cast(short)(short.max / divident * (lfoFlags & LFOFlags.invert ? -1 : 1));
715 		if (lfoFlags & LFOFlags.pulse)
716 			lfo.pulseAm = value;
717 		if (lfoFlags & LFOFlags.saw)
718 			lfo.sawAm = value;
719 		if (lfoFlags & LFOFlags.sawpulse)
720 			lfo.sawPulseAm = value;
721 		if (lfoFlags & LFOFlags.triangle)
722 			lfo.triAm = value;
723 		lfo.pulseWidth = cast(uint)(lfoPWM * uint.max);
724 		lfo.setRate(sampleRate, lfoFreq);
725 	}
726 	protected void presetRecall(ubyte ch) @nogc pure nothrow {
727 		channels[ch].presetCopy = presetBank[channels[ch].presetNum | (channels[ch].bankNum<<7)];
728 	}
729 	/** 
730 	 * Creates a decoder function.
731 	 * Params:
732 	 *   fmt = the format of the sample.
733 	 * Returns: The decoder function, or null if format not supported.
734 	 */
735 	protected DecodeFunc getDecoderFunction(WaveFormat fmt) @nogc pure nothrow {
736 		switch (fmt.format) {		//Hope this branching won't impact performance too much
737 			case AudioFormat.PCM:
738 				if (fmt.bitsPerSample == 8)
739 					return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) {decode8bitPCM(cast(const(ubyte)[])src, dest, wp);};
740 				else if (fmt.bitsPerSample == 16)
741 					return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) {decode16bitPCM(cast(const(short)[])src, dest, wp);};
742 				return null;
743 			case AudioFormat.ADPCM:
744 				return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) 
745 						{decode4bitIMAADPCM(ADPCMStream(src, src.length*2), dest, wp);};
746 				
747 			case AudioFormat.DIALOGIC_OKI_ADPCM:
748 				return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) 
749 						{decode4bitDialogicADPCM(ADPCMStream(src, src.length*2), dest, wp);};
750 				
751 			case AudioFormat.MULAW:
752 				return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) {decodeMuLawStream(cast(const(ubyte)[])src, dest, wp);};
753 				
754 			case AudioFormat.ALAW:
755 				return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) {decodeALawStream(cast(const(ubyte)[])src, dest, wp);};
756 				
757 			default:
758 				return null;
759 		}
760 	}
761 	/**
762 	 * Renders the current audio frame.
763 	 * 
764 	 * input: the input buffers if any, null if none.
765 	 * output: the output buffers if any, null if none.
766 	 *
767 	 * NOTE: Buffers must have matching sizes.
768 	 */
769 	public override void renderFrame(float*[] input, float*[] output) @nogc nothrow {
770 		for (int i ; i < bufferSize ; i++) {
771 			lfoOut[i] = lfo.outputF(0.5, 1.0 / ushort.max);
772 		}
773 		for (int i ; i < 8 ; i++) {
774 			if (!(channels[i].currNote & 128)) {
775 				//get the data for the sample
776 				SampleAssignment sa = channels[i].presetCopy.sampleMapping[channels[i].currNote];
777 				Sample slmp = sampleBank[sa.sampleNum];
778 				if (!slmp.sampleData.length) continue;
779 				size_t samplesNeeded = bufferSize;
780 				size_t outpos;
781 				while (samplesNeeded && !(channels[i].currNote & 128)) {
782 					//Calculate the amount of samples that are needed for this block
783 					ulong samplesToAdvance = channels[i].jumpAm * samplesNeeded;
784 					if ((channels[i].outPos + (channels[i].waveModWorkpad.lookupVal)) >= (channels[i].decoderWorkpad.pos<<24L)) 
785 						channels[i].decodeMore(sa, slmp);
786 					const ulong decoderBufPos = (channels[i].decoderWorkpad.pos<<24L) - channels[i].outPos;
787 					//Determine if there's enough decoded samples, if not then reduce the amount of samplesToAdvance
788 					if ((128<<24L) - decoderBufPos <= samplesToAdvance){
789 						samplesToAdvance = (128<<24L) - decoderBufPos;
790 					}
791 					//Calculate how many samples will be outputted
792 					const size_t samplesOutputted = 
793 							cast(size_t)(samplesToAdvance / channels[i].jumpAm);
794 					stretchAudioNoIterpol(channels[i].decoderBuffer, iBuf[outpos..outpos + samplesOutputted], 
795 							channels[i].waveModWorkpad, channels[i].jumpAm);
796 					samplesNeeded -= samplesOutputted;
797 					channels[i].outPos += samplesToAdvance;
798 					outpos += samplesOutputted;
799 				}
800 				//apply envelop (if needed) and volume, then mix it to the local buffer
801 				__m128 levels;
802 				levels[0] = channels[i].presetCopy.masterVol * channels[i].presetCopy.balance;
803 				levels[1] = channels[i].presetCopy.masterVol * (1 - channels[i].presetCopy.balance);
804 				levels[2] = channels[i].presetCopy.auxSendA;
805 				levels[3] = channels[i].presetCopy.auxSendB;
806 				for (int j ; j < bufferSize ; j++) {
807 					__m128 sample = _mm_cvtepi32_ps(__m128i(iBuf[j]));
808 					const float adsrEnv = channels[i].envGen.shp(channels[i].envGen.position == ADSREnvelopGenerator.Stage.Attack ? 
809 							channels[i].currShpA : channels[i].currShpR) * channels[i].presetCopy.adsrToVol;
810 					channels[i].envGen.advance();
811 					sample *= __m128((1 - channels[i].presetCopy.adsrToVol) + adsrEnv) * __m128((1 - channels[i].presetCopy.lfoToVol) + 
812 							(lfoOut[j] * channels[i].presetCopy.lfoToVol)) * levels;
813 					lBuf[j] += sample;
814 				}
815 				resetBuffer(iBuf);
816 			}
817 		}
818 		float*[4] outBuf;
819 		for (ubyte i, j ; i < 4 ; i++) {
820 			if (enabledOutputs.has(i)) {
821 				outBuf[i] = output[j];
822 				j++;
823 			} else {
824 				outBuf[i] = dummyBuf.ptr;
825 			}
826 		}
827 		//apply filtering and mix to destination
828 		const __m128 b0_a0 = filterVals[3] / filterVals[0], b1_a0 = filterVals[4] / filterVals[0], 
829 				b2_a0 = filterVals[5] / filterVals[0], a1_a0 = filterVals[1] / filterVals[0], a2_a0 = filterVals[2] / filterVals[0];
830 		for (int i ; i < bufferSize ; i++) {
831 			__m128 input0 = lBuf[i];
832 			input0 /= __m128(mixdownVal);
833 			input0 = _mm_max_ps(input0, __m128(-1.0));
834 			input0 = _mm_min_ps(input0, __m128(1.0));
835 			__m128 output0 = b0_a0 * input0 + b1_a0 * filterVals[6] + b2_a0 * filterVals[7] - a1_a0 * filterVals[8] - 
836 					a2_a0 * filterVals[9];
837 			for (int j ; j < 4 ; j++)
838 				outBuf[j][i] += output0[j];
839 			//	outBuf[j][i] += input0[j];
840 			filterVals[7] = filterVals[6];
841 			filterVals[6] = input0;
842 			filterVals[9] = filterVals[8];
843 			filterVals[8] = output0;
844 		}
845 		resetBuffer(lBuf);
846 	}
847 	/**
848 	 * Receives waveform data that has been loaded from disk for reading. Returns zero if successful, or a specific 
849 	 * errorcode.
850 	 *
851 	 * id: The ID of the waveform.
852 	 * rawData: The data itself, in unprocessed form.
853 	 * format: The format of the wave data, including the data type, bit depth, base sampling rate
854 	 */
855 	public override int waveformDataReceive(uint id, ubyte[] rawData, WaveFormat format) nothrow {
856 		int result;
857 		if (!(format.format == AudioFormat.PCM || format.format == AudioFormat.MULAW || format.format == AudioFormat.ALAW || 
858 				format.format == AudioFormat.ADPCM || format.format == AudioFormat.DIALOGIC_OKI_ADPCM)) 
859 			result |= SampleLoadErrorCode.FormatNotSupported; 
860 		result |= format.channels == 1 ? 0 : SampleLoadErrorCode.ChNumNotSupported;
861 		if (result) {
862 			return result; 
863 		} else {
864 			sampleBank[id] = Sample(rawData, format, getDecoderFunction(format));
865 			return 0;
866 		}
867 	}
868 	/**
869 	 * Restores a parameter to the given preset.
870 	 * Returns an errorcode on failure.
871 	 */
872 	public override int writeParam_int(uint presetID, uint paramID, int value) nothrow {
873 		Preset* presetPtr = presetBank.ptrOf(presetID);
874 		if (presetPtr is null) {
875 			presetBank[presetID] = Preset.init;
876 			presetPtr = presetBank.ptrOf(presetID);
877 		}
878 		if (paramID & 0x10_00) {
879 			switch (paramID & 0x0F_00) {
880 				case 0x00_00:
881 					presetPtr.sampleMapping[paramID & 0x7F].sampleNum = value;
882 					return 0;
883 				case 0x02_00:
884 					presetPtr.sampleMapping[paramID & 0x7F].loopBegin = value;
885 					return 0;
886 				case 0x03_00:
887 					presetPtr.sampleMapping[paramID & 0x7F].loopEnd = value;
888 					return 0;
889 				default:
890 					break;
891 			}
892 		} else if (paramID & 0x80_00) {
893 			switch (paramID) {
894 				case 0x80_09:
895 					if (value)
896 						lfoFlags |= LFOFlags.saw;
897 					else
898 						lfoFlags &= ~LFOFlags.saw;
899 					resetLFO();
900 					return 0;
901 				case 0x80_0a:
902 					if (value)
903 						lfoFlags |= LFOFlags.triangle;
904 					else
905 						lfoFlags &= ~LFOFlags.triangle;
906 					resetLFO();
907 					return 0;
908 				case 0x80_0b:
909 					if (value)
910 						lfoFlags |= LFOFlags.pulse;
911 					else
912 						lfoFlags &= ~LFOFlags.pulse;
913 					resetLFO();
914 					return 0;
915 				case 0x80_0c:
916 					if (value)
917 						lfoFlags |= LFOFlags.sawpulse;
918 					else
919 						lfoFlags &= ~LFOFlags.sawpulse;
920 					resetLFO();
921 					return 0;
922 				case 0x80_0d:
923 					if (value)
924 						lfoFlags |= LFOFlags.invert;
925 					else
926 						lfoFlags &= ~LFOFlags.invert;
927 					resetLFO();
928 					return 0;
929 				case 0x80_0f:
930 					if (value)
931 						lfoFlags |= LFOFlags.ringmod;
932 					else
933 						lfoFlags &= ~LFOFlags.ringmod;
934 					resetLFO();
935 					return 0;
936 				default:
937 					break;
938 			}
939 		} else {
940 			switch (paramID) {
941 				case 0x00:
942 					presetPtr.eAtk = cast(ubyte)value;
943 					return 0;
944 				case 0x01:
945 					presetPtr.eDec = cast(ubyte)value;
946 					return 0;
947 				case 0x02:
948 					presetPtr.eSusC = cast(ubyte)value;
949 					return 0;
950 				case 0x03:
951 					presetPtr.eRel = cast(ubyte)value;
952 					return 0;
953 				case 0x10:
954 					presetPtr.flags = value;
955 					return 0;
956 				case 0x00_11:
957 					if (value)
958 						presetPtr.flags |= PresetFlags.cutoffOnKeyOff;
959 					else
960 						presetPtr.flags &= ~PresetFlags.cutoffOnKeyOff;
961 					return 0;
962 				case 0x00_12:
963 					if (value)
964 						presetPtr.flags |= PresetFlags.modwheelToLFO;
965 					else
966 						presetPtr.flags &= ~PresetFlags.modwheelToLFO;
967 					return 0;
968 				case 0x00_13:
969 					if (value)
970 						presetPtr.flags |= PresetFlags.panningLFO;
971 					else
972 						presetPtr.flags &= ~PresetFlags.panningLFO;
973 					return 0;
974 				/* case 0x00_14:
975 					if (value)
976 						presetPtr.flags |= PresetFlags.ADSRtoVol;
977 					else
978 						presetPtr.flags &= ~PresetFlags.ADSRtoVol;
979 					return 0; */
980 				default:
981 					break;
982 			}
983 		}
984 		return 1;
985 	}
986 	/**
987 	 * Restores a parameter to the given preset.
988 	 * Returns an errorcode on failure.
989 	 */
990 	public override int writeParam_long(uint presetID, uint paramID, long value) nothrow {
991 		return 0;
992 	}
993 	/**
994 	 * Restores a parameter to the given preset.
995 	 * Returns an errorcode on failure.
996 	 */
997 	public override int writeParam_double(uint presetID, uint paramID, double value) nothrow {
998 		Preset* presetPtr = presetBank.ptrOf(presetID);
999 		if (presetPtr is null) {
1000 			presetBank[presetID] = Preset.init;
1001 			presetPtr = presetBank.ptrOf(presetID);
1002 		}
1003 		if (paramID & 0x10_00) {
1004 			switch (paramID & 0x0F_00) {
1005 				case 0x01_00:
1006 					presetPtr.sampleMapping[paramID & 0x7F].baseFreq = value;
1007 					return 0;
1008 				default:
1009 					break;
1010 			}
1011 		} else if (paramID & 0x80_00) {
1012 			switch (paramID) {
1013 				case 0x80_00: 
1014 					filterCtrl[0] = value; 
1015 					resetLPF(0); 
1016 					return 0;
1017 				case 0x80_01: 
1018 					filterCtrl[1] = value; 
1019 					resetLPF(0); 
1020 					return 0;
1021 				case 0x80_02: 
1022 					filterCtrl[2] = value; 
1023 					resetLPF(1); 
1024 					return 0;
1025 				case 0x80_03: 
1026 					filterCtrl[3] = value; 
1027 					resetLPF(1); 
1028 					return 0;
1029 				case 0x80_04: 
1030 					filterCtrl[4] = value; 
1031 					resetLPF(2); 
1032 					return 0;
1033 				case 0x80_05: 
1034 					filterCtrl[5] = value; 
1035 					resetLPF(2); 
1036 					return 0;
1037 				case 0x80_06: 
1038 					filterCtrl[6] = value; 
1039 					resetLPF(3); 
1040 					return 0;
1041 				case 0x80_07: 
1042 					filterCtrl[7] = value; 
1043 					resetLPF(3); 
1044 					return 0;
1045 				case 0x80_08: 
1046 					lfoFreq = value;
1047 					resetLFO();
1048 					return 0;
1049 				case 0x80_0e: 
1050 					lfoPWM = value;
1051 					resetLFO();
1052 					return 0;
1053 				default:
1054 					break;
1055 			}
1056 		} else {
1057 			
1058 			if (value < 0 || value > 1) return 2;
1059 			switch (paramID) {
1060 				case 0x00_04:
1061 					presetPtr.eAtkShp = value;
1062 					return 0;
1063 				case 0x00_05:
1064 					presetPtr.eRelShp = value;
1065 					return 0;
1066 				case 0x00_06:
1067 					presetPtr.eSusLev = value;
1068 					return 0;
1069 				case 0x00_07:
1070 					presetPtr.masterVol = value;
1071 					return 0;
1072 				case 0x00_08:
1073 					presetPtr.balance = value;
1074 					return 0;
1075 				case 0x00_09:
1076 					presetPtr.auxSendA = value;
1077 					return 0;
1078 				case 0x00_0A:
1079 					presetPtr.auxSendB = value;
1080 					return 0;
1081 				case 0x00_0B:
1082 					presetPtr.velToLevelAm = value;
1083 					return 0;
1084 				case 0x00_0C:
1085 					presetPtr.velToAuxSendAm = value;
1086 					return 0;
1087 				case 0x00_0D:
1088 					presetPtr.velToAtkShp = value;
1089 					return 0;
1090 				case 0x00_0E:
1091 					presetPtr.velToRelShp = value;
1092 					return 0;
1093 				case 0x00_0F:
1094 					presetPtr.adsrToVol = value;
1095 					return 0;
1096 				case 0x00_20:
1097 					presetPtr.pitchBendAm = value;
1098 					return 0;
1099 				default:
1100 					break;
1101 			}
1102 		}
1103 		return 1;
1104 	}
1105 	/**
1106 	 * Restores a parameter to the given preset.
1107 	 * Returns an errorcode on failure.
1108 	 */
1109 	public override int writeParam_string(uint presetID, uint paramID, string value) nothrow {
1110 		return 0;
1111 	}
1112 	/** 
1113 	 * Returns all the possible parameters this module has.
1114 	 */
1115 	public override MValue[] getParameters() nothrow {
1116 		return [
1117 			MValue(MValueType.Int32, 0x00_00, "envGenAtk"), MValue(MValueType.Int32, 0x00_01, "envGenDec"),
1118 			MValue(MValueType.Int32, 0x00_02, "envGenSusC"), MValue(MValueType.Int32, 0x00_03, "envGenDec"),
1119 			MValue(MValueType.Float, 0x00_04, "envGenAtkShp"), MValue(MValueType.Float, 0x00_05, "envGenDecShp"),
1120 			MValue(MValueType.Float, 0x00_06, "envGenSusLevel"), MValue(MValueType.Float, 0x00_07, "masterVol"),
1121 			MValue(MValueType.Float, 0x00_08, "balance"), MValue(MValueType.Float, 0x00_09, "auxSendA"),
1122 			MValue(MValueType.Float, 0x00_0A, "auxSendB"), MValue(MValueType.Float, 0x00_0B, "velToLevelAm"),
1123 			MValue(MValueType.Float, 0x00_0C, "velToAuxSendAm"), MValue(MValueType.Float, 0x00_0D, "velToAtkShp"),
1124 			MValue(MValueType.Float, 0x00_0E, "velToRelShp"), MValue(MValueType.Float, 0x00_0F, "adsrToVol"),
1125 			MValue(MValueType.Int32, 0x00_10, "flags"),
1126 			MValue(MValueType.Boolean, 0x00_11, "f_cutoffOnKeyOff"),
1127 			MValue(MValueType.Boolean, 0x00_12, "f_modwheelToLFO"),
1128 			MValue(MValueType.Boolean, 0x00_13, "f_panningLFO"),
1129 			MValue(MValueType.Float, 0x00_20, "pitchBendRange"),
1130 			/* MValue(MValueType.Boolean, 0x00_13, "f_ADSRtoVol"), */
1131 		] ~ SAMPLE_SET_VALS.dup ~ [
1132 			MValue(MValueType.Float, 0x80_00, `_FilterLCFreq`), MValue(MValueType.Float, 0x80_01, `_FilterLCQ`),
1133 			MValue(MValueType.Float, 0x80_02, `_FilterRCFreq`), MValue(MValueType.Float, 0x80_03, `_FilterRCQ`),
1134 			MValue(MValueType.Float, 0x80_04, `_FilterACFreq`), MValue(MValueType.Float, 0x80_05, `_FilterACQ`),
1135 			MValue(MValueType.Float, 0x80_06, `_FilterBCFreq`), MValue(MValueType.Float, 0x80_07, `_FilterBCQ`),
1136 			MValue(MValueType.Float, 0x80_08, "_LFOFreq"), MValue(MValueType.Boolean, 0x80_09, "_LFOSaw"),
1137 			MValue(MValueType.Boolean, 0x80_0a, "_LFOTri"), MValue(MValueType.Boolean, 0x80_0b, "_LFOPul"), 
1138 			MValue(MValueType.Boolean, 0x80_0c, "_LFOSawPul"), MValue(MValueType.Boolean, 0x80_0d, "_LFOInv"),
1139 			MValue(MValueType.Float, 0x80_0e, "_LFOPWM"), MValue(MValueType.Boolean, 0x80_0f, "_LFORingmod")
1140 		];
1141 	}
1142 	/** 
1143 	 * Reads the given value (int).
1144 	 * Params:
1145 	 *   presetID = The preset ID, or uint.max for global module values.
1146 	 *   paramID = The parameter ID.
1147 	 * Returns: The value of the given preset and parameter
1148 	 */
1149 	public override int readParam_int(uint presetID, uint paramID) nothrow {
1150 		Preset* presetPtr = presetBank.ptrOf(presetID);
1151 		if (presetPtr is null) return 0;
1152 		if (paramID & 0x10_00) {
1153 			switch (paramID & 0x0F_00) {
1154 				case 0x00_00:
1155 					return presetPtr.sampleMapping[paramID & 0x7F].sampleNum;
1156 				case 0x02_00:
1157 					return presetPtr.sampleMapping[paramID & 0x7F].loopBegin;
1158 				case 0x03_00:
1159 					return presetPtr.sampleMapping[paramID & 0x7F].loopEnd;
1160 				default:
1161 					break;
1162 			}
1163 		} else if (paramID & 0x80_00) {
1164 			switch (paramID) {
1165 				case 0x80_09:
1166 					return lfoFlags & LFOFlags.saw ? 1 : 0;
1167 				case 0x80_0a:
1168 					return lfoFlags & LFOFlags.triangle ? 1 : 0;
1169 				case 0x80_0b:
1170 					return lfoFlags & LFOFlags.pulse ? 1 : 0;
1171 				case 0x80_0c:
1172 					return lfoFlags & LFOFlags.sawpulse ? 1 : 0;
1173 				case 0x80_0d:
1174 					return lfoFlags & LFOFlags.invert ? 1 : 0;
1175 				case 0x80_0f:
1176 					return lfoFlags & LFOFlags.ringmod ? 1 : 0;
1177 				default:
1178 					break;
1179 			}
1180 		} else {
1181 			switch (paramID) {
1182 				case 0x00:
1183 					return presetPtr.eAtk;
1184 				case 0x01:
1185 					return presetPtr.eDec;
1186 				case 0x02:
1187 					return presetPtr.eSusC;
1188 				case 0x03:
1189 					return presetPtr.eRel;
1190 				case 0x10:
1191 					return presetPtr.flags;
1192 				case 0x00_11:
1193 					return presetPtr.flags & PresetFlags.cutoffOnKeyOff ? 1 : 0;
1194 				case 0x00_12:
1195 					return presetPtr.flags & PresetFlags.modwheelToLFO ? 1 : 0;
1196 				case 0x00_13:
1197 					return presetPtr.flags & PresetFlags.panningLFO ? 1 : 0;
1198 				/* case 0x00_14:
1199 					return presetPtr.flags |= PresetFlags.ADSRtoVol ? 1 : 0; */
1200 				default:
1201 					break;
1202 			}
1203 		}
1204 		return 0;
1205 	}
1206 	/** 
1207 	 * Reads the given value (int).
1208 	 * Params:
1209 	 *   presetID = The preset ID, or uint.max for global module values.
1210 	 *   paramID = The parameter ID.
1211 	 * Returns: The value of the given preset and parameter
1212 	 */
1213 	public override long readParam_long(uint presetID, uint paramID) nothrow {
1214 		return 0;
1215 	}
1216 	/** 
1217 	 * Reads the given value (int).
1218 	 * Params:
1219 	 *   presetID = The preset ID, or uint.max for global module values.
1220 	 *   paramID = The parameter ID.
1221 	 * Returns: The value of the given preset and parameter
1222 	 */
1223 	public override double readParam_double(uint presetID, uint paramID) nothrow {
1224 		Preset* presetPtr = presetBank.ptrOf(presetID);
1225 		if (presetPtr is null) return double.nan;
1226 		if (paramID & 0x10_00) {
1227 			switch (paramID & 0x0F_00) {
1228 				case 0x01_00:
1229 					return presetPtr.sampleMapping[paramID & 0x7F].baseFreq;
1230 				default:
1231 					break;
1232 			}
1233 		} else if (paramID & 0x80_00) {
1234 			switch (paramID) {
1235 				case 0x80_00: 
1236 					return filterCtrl[0];
1237 				case 0x80_01: 
1238 					return filterCtrl[1];
1239 				case 0x80_02: 
1240 					return filterCtrl[2];
1241 				case 0x80_03: 
1242 					return filterCtrl[3];
1243 				case 0x80_04: 
1244 					return filterCtrl[4];
1245 				case 0x80_05: 
1246 					return filterCtrl[5];
1247 				case 0x80_06: 
1248 					return filterCtrl[6];
1249 				case 0x80_07: 
1250 					return filterCtrl[7];
1251 				case 0x80_08: 
1252 					return lfoFreq;
1253 				case 0x80_0e: 
1254 					return lfoPWM;
1255 				default:
1256 					break;
1257 			}
1258 		} else {
1259 			switch (paramID) {
1260 				case 0x00_04:
1261 					return presetPtr.eAtkShp;
1262 				case 0x00_05:
1263 					return presetPtr.eRelShp;
1264 				case 0x00_06:
1265 					return presetPtr.eSusLev;
1266 				case 0x00_07:
1267 					return presetPtr.masterVol;
1268 				case 0x00_08:
1269 					return presetPtr.balance;
1270 				case 0x00_09:
1271 					return presetPtr.auxSendA;
1272 				case 0x00_0A:
1273 					return presetPtr.auxSendB;
1274 				case 0x00_0B:
1275 					return presetPtr.velToLevelAm;
1276 				case 0x00_0C:
1277 					return presetPtr.velToAuxSendAm;
1278 				case 0x00_0D:
1279 					return presetPtr.velToAtkShp;
1280 				case 0x00_0E:
1281 					return presetPtr.velToRelShp;
1282 				case 0x00_0F:
1283 					return presetPtr.adsrToVol;
1284 				case 0x0020:
1285 					return presetPtr.pitchBendAm;
1286 				default:
1287 					break;
1288 			}
1289 		}
1290 		return double.nan;
1291 	}
1292 	/** 
1293 	 * Reads the given value (int).
1294 	 * Params:
1295 	 *   presetID = The preset ID, or uint.max for global module values.
1296 	 *   paramID = The parameter ID.
1297 	 * Returns: The value of the given preset and parameter
1298 	 */
1299 	public override string readParam_string(uint presetID, uint paramID) nothrow {
1300 		return null;
1301 	}
1302 }