1 module pixelperfectengine.audio.modules.delaylines;
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.audio.base.filter;
10 import pixelperfectengine.system.etc : isPowerOf2;
11 
12 import inteli.emmintrin;
13 
14 import midi2.types.structs;
15 import midi2.types.enums;
16 
17 import collections.treemap;
18 
19 import std.bitmanip : bitfields;
20 import std.math;
21 
22 /**
23  * Implements a configurable delay line device, that can be used to create various time-based effects.
24  * It contains:
25  * * two delay lines
26  * * four taps per delay line
27  * * a short 16 element FIR per tap
28  * * 4 parallel band-pass filters for applying EQ for the effect
29  * The module is controllable via MIDI CC commands.
30  */
31 public class DelayLines : AudioModule {
32 	shared static this () {
33 		import std.conv : to;
34 		for (uint i ; i < 8 ; i++) {
35 			for (uint j ; j < 16 ; j++) {
36 				SET_VALS ~= MValue(MValueType.Float, (i<<7) | j, "Tap" ~ i.to!string ~ "_FIR" ~ j.to!string);
37 			}
38 			
39 			SET_VALS ~= MValue(MValueType.Float, (i<<7) | (16), "Tap" ~ i.to!string ~ "_OutputL");
40 			SET_VALS ~= MValue(MValueType.Float, (i<<7) | (17), "Tap" ~ i.to!string ~ "_OutputR");
41 			SET_VALS ~= MValue(MValueType.Float, (i<<7) | (18), "Tap" ~ i.to!string ~ "_FeedbackPri");
42 			SET_VALS ~= MValue(MValueType.Float, (i<<7) | (19), "Tap" ~ i.to!string ~ "_FeedbackSec");
43 			SET_VALS ~= MValue(MValueType.Int32, (i<<7) | (20), "Tap" ~ i.to!string ~ "_Pos");
44 			SET_VALS ~= MValue(MValueType.Boolean, (i<<7) | (21), "Tap" ~ i.to!string ~ "_TapEnable");
45 			SET_VALS ~= MValue(MValueType.Boolean, (i<<7) | (22), "Tap" ~ i.to!string ~ "_BypassFIR");
46 		}
47 		/* for (uint i ; i < 4 ; i++) {
48 			SET_VALS ~= MValue(MValueType.Int32, (8<<7) | (i<<3) | (0), "LFO" ~ i.to!string ~ "_Waveform");
49 			SET_VALS ~= MValue(MValueType.Int32, (8<<7) | (i<<3) | (1), "LFO" ~ i.to!string ~ "_Level");
50 			SET_VALS ~= MValue(MValueType.Float, (8<<7) | (i<<3) | (2), "LFO" ~ i.to!string ~ "_Freq");
51 			SET_VALS ~= MValue(MValueType.Float, (8<<7) | (i<<3) | (3), "LFO" ~ i.to!string ~ "_PWM");
52 			SET_VALS ~= MValue(MValueType.Int32, (8<<7) | (i<<3) | (4), "LFO" ~ i.to!string ~ "_Target");
53 		} */
54 		for (uint i ; i < 8 ; i++) {
55 			SET_VALS ~= MValue(MValueType.Float, (9<<7) | (i<<2) | (0), "EQ" ~ i.to!string ~ "_Level");
56 			SET_VALS ~= MValue(MValueType.Float, (9<<7) | (i<<2) | (1), "EQ" ~ i.to!string ~ "_Freq");
57 			SET_VALS ~= MValue(MValueType.Float, (9<<7) | (i<<2) | (2), "EQ" ~ i.to!string ~ "_Q");
58 		}
59 		SET_VALS ~= MValue(MValueType.Float, (10<<7) | (0), "InputAtoPri");
60 		SET_VALS ~= MValue(MValueType.Float, (10<<7) | (1), "InputAtoSec");
61 		SET_VALS ~= MValue(MValueType.Float, (10<<7) | (2), "InputBtoPri");
62 		SET_VALS ~= MValue(MValueType.Float, (10<<7) | (3), "InputBtoSec");
63 		SET_VALS ~= MValue(MValueType.Float, (10<<7) | (4), "MasterL");
64 		SET_VALS ~= MValue(MValueType.Float, (10<<7) | (5), "MasterR");
65 
66 	}
67 	protected static MValue[] SET_VALS;
68 	/** 
69 	 * Defines a delay line tap.
70 	 */
71 	protected struct Tap {
72 		__m128		outLevels	= __m128(0.0);///Output levels (0: Left; 1: Right, 2: Primary feedback, 3: Secondary feedback)
73 		__m128[4]	fir = [__m128(0.0),__m128(0.0),__m128(0.0),__m128(0.0)];///Short finite impulse response for the tap tap
74 		uint		pos;		///Median position of the tap (unaffected by LFO)
75 		bool		tapEnable;	///True if tap is enabled
76 		bool		bypassFIR;	///Bypasses FIR calculation
77 	}
78 	/* 
79 	///Defines an LFO target
80 	protected enum OscTarget : ubyte {
81 		init		=	0,
82 		TapOut		=	1,
83 		TapFeedback	=	2,
84 		TapPosition	=	4,
85 		ToA			=	8,
86 		ToB			=	16,
87 	} */
88 	///Contains recallable preset data.
89 	protected struct Preset {
90 		///Defines oscillator waveform selection data.
91 		///Bitfield notation:
92 		///  sawtooth = Enables or disables sawtooth output.
93 		///  triangle = Enables or disables triangle output.
94 		///  pulse = Enables or disables pulse output.
95 		///  sawpulse = Enables or disables sawpulse output.
96 		///  integrate = Compensates triangle/saw output for position offsetting.
97 		///  phaseInvert = Inverts the output phase of the oscillator.
98 		struct OscWaveform {
99 			union {
100 				mixin(bitfields!(
101 					bool, "sawtooth", 1,
102 					bool, "triangle", 1,
103 					bool, "pulse", 1,
104 					bool, "sawpulse", 1,
105 					bool, "integrate", 1,
106 					bool, "phaseInvert", 1,
107 					ubyte, "", 2,
108 				));
109 				ubyte raw;
110 			}
111 		}
112 		Tap[4][2]				taps;			///Defines delay line taps
113 		__m128[2]				iirFreq = [__m128([100, 500, 1000, 10_000]), __m128([100, 500, 1000, 10_000])];///Defines IIR frequencies
114 		__m128[2]				iirQ = [__m128(0.707), __m128(0.707)];///Defines IIR Q value
115 		__m128[2]				eqLevels = [__m128(0), __m128(0)];///Stores EQ send levels
116 		__m128					inputLevel = __m128(1);
117 		/* __m128i					oscLevels = __m128i(0);///Defines the amount of effect a given LFO has on a parameter
118 		float[4]				oscFrequencies = [4, 4, 4, 4];///Defines LFO freqencies
119 		uint[4]					oscPWM;			///Defines the PWM of the LFOs */
120 		float[2]				outputLevel = [1.0, 1.0];
121 		/* ubyte[4]				oscTargets;		///Sets the target of a given LFO
122 		OscWaveform[4]			oscWaveform;	///Sets the waveform output of the LFOs */
123 		
124 	}
125 	protected TreeMap!(uint,Preset)	presetBank;	///Stores presets
126 	protected Preset			currPreset;		///Contains the copy of the current preset
127 	protected IIRBank[2]		filterBanks;	///Stores filter data for the EQ
128 	protected float[2]			feedbackSends;	///Stores feedback send levels
129 	protected float[][2]		delayLines;		///The two delay lines of the 
130 	protected __m128			inLevel;		///0: A to pri, 1: A to sec, 2: B to pri, 3: B to sec
131 	protected float[2]			outLevel;		///Output levels
132 	protected float[2]			feedbackSum;	///Feedback sums to be mixed in with the inputs
133 	/* protected QuadMultitapOsc	osc;			///Oscillators to modify fix tap points
134 	protected __m128i[]			oscOut;			///LFO buffer */
135 	protected size_t[2]			dLPos;			///Delay line positions
136 	protected size_t[2]			dLMod;			///Delay line modulo
137 	protected float[]			dummyBuf;		///Buffer used for unused inputs/outputs
138 	protected uint				presetNum;
139 	protected ubyte[68][8]		chCtrlLower;	///Lower parts of the channel controllers (0-31 / 32-63) + Unregistered parameter set
140 	protected __m128			allSums = __m128(0.0);
141 	
142 	/**
143 	 * Creates an instance of this module using the supplied parameters.
144 	 * Params:
145 	 *   priLen = Primary buffer length. Must be power of two.
146 	 *   secLen = Secondary buffer length. Must be power of two.
147 	 */
148 	public this(size_t priLen, size_t secLen) {
149 		assert(isPowerOf2(priLen));
150 		assert(isPowerOf2(secLen) || !secLen);
151 		info.nOfAudioInput = 2;
152 		info.nOfAudioOutput = 2;
153 		info.inputChNames = ["inputA", "inputB"];
154 		info.outputChNames = ["mainL", "mainR"];
155 		info.hasMidiIn = true;
156 		delayLines[0].length = priLen;
157 		delayLines[1].length = secLen;
158 		dLMod[0] = priLen - 1;
159 		dLMod[1] = secLen - 1;
160 		resetBuffer(delayLines[0]);
161 		resetBuffer(delayLines[1]);
162 	}
163 	/**
164 	 * Sets the module up.
165 	 *
166 	 * Can be overridden in child classes to allow resets.
167 	 */
168 	public override void moduleSetup(ubyte[] inputs, ubyte[] outputs, int sampleRate, size_t bufferSize, 
169 			ModuleManager handler) @safe nothrow {
170 		enabledInputs = StreamIDSet(inputs);
171 		enabledOutputs = StreamIDSet(outputs);
172 		this.sampleRate = sampleRate;
173 		this.bufferSize = bufferSize;
174 		this.handler = handler;
175 		/* oscOut.length = bufferSize; */
176 		dummyBuf.length = bufferSize;
177 		feedbackSum[0] = 0;
178 		feedbackSum[1] = 0;
179 		//resetBuffer(oscOut);
180 		/* foreach (ref __m128i key; oscOut) {
181 			key = __m128i(0);
182 		} */
183 		resetBuffer(dummyBuf);
184 		filterBanks[0].reset();
185 		filterBanks[1].reset();
186 	}
187 
188 	override public void midiReceive(UMP data0, uint data1 = 0, uint data2 = 0, uint data3 = 0) @nogc nothrow {
189 		switch (data0.msgType) {
190 			case MessageType.MIDI1:
191 				switch (data0.status) {
192 					case MIDI1_0Cmd.CtrlCh:
193 						if (data0.channel >= 8)
194 							return;
195 						if (data0.note < 63) {
196 							chCtrlLower[data0.channel][data0.note] = data0.value;
197 							if ((data0.note & 31) >= 16 && (data0.note & 31) <= 31) {
198 								controlChangeCmd(data0.channel, cast(ubyte)((data0.note & 31) - 16), 
199 										convertM1CtrlValToM2(chCtrlLower[data0.channel][data0.note & 31], 
200 										chCtrlLower[data0.channel][(data0.note & 31) + 32]));
201 							} else {
202 								switch (data0.note & 31) {
203 									case 0:
204 										chCtrlLower[0][data0.note] = data0.value;
205 										break;
206 									default:
207 										break;
208 								}
209 							}
210 						}
211 						break;
212 					case MIDI1_0Cmd.PrgCh:
213 						presetChangeCmd((data0.program) | (chCtrlLower[0][0]<<8) | (chCtrlLower[0][32]<<16));
214 						break;
215 					default:
216 						break;
217 				}
218 				break;
219 			case MessageType.MIDI2:
220 				switch (data0.status) {
221 					case MIDI2_0Cmd.CtrlCh:
222 						controlChangeCmd(data0.note, data0.value, data1);
223 						break;
224 					case MIDI2_0Cmd.PrgCh:
225 						chCtrlLower[0][0] = cast(ubyte)((data1>>8) & ubyte.max);
226 						chCtrlLower[0][32] = cast(ubyte)(data1 & ubyte.max);
227 						presetChangeCmd((data1>>24) | (chCtrlLower[0][0]<<8) | (chCtrlLower[0][32]<<16));
228 						break;
229 					default:
230 						break;
231 				}
232 				break;
233 			default:
234 				break;
235 		}
236 	}
237 
238 	protected void controlChangeCmd(ubyte paramMSB, ubyte paramLSB, uint val) @nogc nothrow {
239 		switch (paramMSB) {
240 			case 0: .. case 7://Taps
241 				switch ( paramLSB ) {
242 					case 0: .. case 15:
243 						const int firGr = paramLSB / 4;
244 						currPreset.taps[paramMSB>>2][paramMSB&3].fir[firGr][paramLSB - 0] = (val / cast(double)int.max) - 1.0;
245 						break;
246 					case 16: .. case 19:
247 						currPreset.taps[paramMSB>>2][paramMSB&3].outLevels[paramMSB - 16] = val / cast(double)uint.max;
248 						break;
249 					case 20:
250 						currPreset.taps[paramMSB>>2][paramMSB&3].pos = 
251 								cast(uint)((val / cast(double)uint.max) * delayLines[paramMSB>>2].length);
252 						break;
253 					case 21:
254 						currPreset.taps[paramMSB>>2][paramMSB&3].tapEnable = val != 0;
255 						break;
256 					case 22:
257 						currPreset.taps[paramMSB>>2][paramMSB&3].bypassFIR = val != 0;
258 						break;
259 					default:
260 						break;
261 				}
262 				break;
263 			/* case 8://LFOs
264 				const int lfoGr = paramLSB>>3;
265 				switch (paramLSB & 7) {
266 					case 0:
267 						currPreset.oscWaveform[lfoGr].raw = cast(ubyte)val;
268 						break;
269 					case 1:
270 						currPreset.oscLevels[lfoGr] = cast(short)(val>>17);
271 						break;
272 					case 2:
273 						currPreset.oscFrequencies[lfoGr] = val / cast(double)uint.max * 20;
274 						break;
275 					case 3:
276 						currPreset.oscPWM[lfoGr] = val;
277 						break;
278 					case 4:
279 						currPreset.oscTargets = cast(ubyte)val;
280 						break;
281 					default:
282 						break;
283 				}
284 				resetLFO(lfoGr);
285 				break; */
286 			case 9://EQ
287 				const int eqGr = (paramLSB>>2) & 7;
288 				switch (paramLSB & 3) {
289 					case 0:
290 						currPreset.eqLevels[eqGr>>2][eqGr&3] = sqrt(val / cast(double)uint.max) * 1.5 - 0.5;
291 						break;
292 					case 1:
293 						currPreset.iirFreq[eqGr>>2][eqGr&3] = pow(val / cast(double)uint.max, 2) * 20_000;
294 						break;
295 					case 2:
296 						currPreset.iirQ[eqGr>>2][eqGr&3] = pow(val / cast(double)uint.max, 2) * 9.99 + 0.01;
297 						break;
298 					default:
299 						break;
300 				}
301 				resetFilter(eqGr);
302 				break;
303 			case 10://Master
304 				switch (paramLSB) {
305 					case 0: .. case 3:
306 						currPreset.inputLevel[paramLSB] = pow(val / cast(double)uint.max, 2);
307 						break;
308 					case 4: case 5:
309 						currPreset.outputLevel[paramLSB - 4] = pow(val / cast(double)uint.max, 2);
310 						break;
311 					default:
312 						break;
313 				}
314 				break;
315 			default:
316 				break;
317 		}
318 	}
319 
320 	protected void resetFilter(int filterID) @safe @nogc nothrow pure {
321 		filterBanks[filterID>>2].setFilter(createBPF1(sampleRate, currPreset.iirFreq[filterID>>2][filterID & 3], 
322 				currPreset.iirFreq[filterID>>2][filterID & 3]), filterID & 3);
323 		filterBanks[filterID>>2].fixFilter();
324 	}
325 
326 	/* protected void resetLFO(int lfoID) @safe @nogc nothrow pure {
327 		osc.setRate(sampleRate, currPreset.oscFrequencies[lfoID], lfoID);
328 		osc.pulseWidth[lfoID] = currPreset.oscPWM[lfoID];
329 		const int waveNum = cast(int)currPreset.oscWaveform[lfoID].sawtooth + cast(int)currPreset.oscWaveform[lfoID].triangle 
330 				+ cast(int)currPreset.oscWaveform[lfoID].pulse + cast(int)currPreset.oscWaveform[lfoID].sawpulse;
331 		if (waveNum) {
332 			const short level = cast(short)((currPreset.oscLevels[lfoID] / waveNum) * 
333 					(currPreset.oscWaveform[lfoID].phaseInvert ? -1 : 1));
334 			if (currPreset.oscWaveform[lfoID].sawtooth)
335 				osc.levelCtrl01[lfoID * 2] = level;
336 			if (currPreset.oscWaveform[lfoID].triangle)
337 				osc.levelCtrl01[lfoID * 2 + 1] = level;
338 			if (currPreset.oscWaveform[lfoID].pulse)
339 				osc.levelCtrl23[lfoID * 2] = level;
340 			if (currPreset.oscWaveform[lfoID].sawpulse)
341 				osc.levelCtrl23[lfoID * 2 + 1] = level;
342 		}
343 	} */
344 
345 	protected void presetChangeCmd(uint preset) @nogc nothrow {
346 		Preset* presetPtr = presetBank.ptrOf(preset);
347 		if (presetPtr is null) return;
348 		currPreset = *presetPtr;
349 		for (int i = 0 ; i < 8 ; i++) {
350 			resetFilter(i);
351 		}
352 		/* for (int i = 0 ; i < 4 ; i++) {
353 			resetLFO(i);
354 		} */
355 	}
356 
357 	override public void renderFrame(float*[] input, float*[] output) @nogc nothrow {
358 		//function to read from the delay line
359 		__m128[4] readDL(int lineNum, uint pos) @nogc @safe pure nothrow {
360 			__m128[4] result;
361 			for (int i ; i < 4 ; i++) {
362 				for (int j ; j < 4 ; j++) {
363 					result[i][j] = delayLines[lineNum][dLMod[lineNum] & (dLPos[lineNum] - pos - j - (i<<2))];
364 				}
365 			}
366 			return result;
367 		}
368 		float readDL0(int linenum, uint pos) @nogc @safe pure nothrow {
369 			return delayLines[linenum][dLMod[linenum] & (dLPos[linenum] - pos)];
370 		}
371 		float*[2] inBuf, outBuf;			//Set up input and output buffers
372 		for (ubyte i, j, k ; i < 2 ; i++) {
373 			if (enabledInputs.has(i)) {
374 				inBuf[i] = output[j];
375 				j++;
376 			} else {
377 				inBuf[i] = dummyBuf.ptr;
378 			}
379 			if (enabledOutputs.has(i)) {
380 				outBuf[i] = output[k];
381 				k++;
382 			} else {
383 				outBuf[i] = dummyBuf.ptr;
384 			}
385 		}
386 		//Precalculate values, so they don't need to be done on a per-cycle basis.
387 		
388 		/* __m128i[2] tapLFOOffset;
389 		__m128[2] tapLFOLevel;
390 		__m128[2] tapLFOFB;
391 		for (int j ; j < 4 ; j++) {
392 			if (currPreset.oscTargets[j] & OscTarget.ToA) {
393 				tapLFOLevel[0][j] = (currPreset.oscTargets[j] & OscTarget.TapOut) ? 1.0 / short.max : 0.0;
394 				tapLFOOffset[0][j] = (currPreset.oscTargets[j] & OscTarget.TapPosition) ? 1 : 0;
395 				tapLFOFB[0][j] = (currPreset.oscTargets[j] & OscTarget.TapFeedback) ? 1.0 / short.max : 0.0;
396 			}
397 			if (currPreset.oscTargets[j] & OscTarget.ToB) {
398 				tapLFOLevel[1][j] = (currPreset.oscTargets[j] & OscTarget.TapOut) ? 1.0 / short.max : 0.0;
399 				tapLFOOffset[1][j] = (currPreset.oscTargets[j] & OscTarget.TapPosition) ? 1 : 0;
400 				tapLFOFB[1][j] = (currPreset.oscTargets[j] & OscTarget.TapFeedback) ? 1.0 / short.max : 0.0;
401 			}
402 		} */
403 		
404 		/* {	//Render LFO outs.
405 			for (int lfoPos ; lfoPos < bufferSize ; lfoPos++) {
406 				oscOut[lfoPos] = osc.output();
407 				oscOut[lfoPos][0]>>=15;
408 				oscOut[lfoPos][1]>>=15;
409 				oscOut[lfoPos][2]>>=15;
410 				oscOut[lfoPos][3]>>=15;
411 			}
412 			for (int i ; i < 4 ; i++) {
413 				if (currPreset.oscWaveform[i].integrate){	//integrate output if needed
414 					for (int lfoPos ; lfoPos < bufferSize ; lfoPos++) {
415 						oscOut[lfoPos][i] = (abs(oscOut[lfoPos][i]) * oscOut[lfoPos][i])>>16;
416 					}
417 				}
418 			}
419 		} */
420 		
421 		for (int outputPos ; outputPos < bufferSize ; outputPos++) {
422 			delayLines[0][dLMod[0] & dLPos[0]] = inBuf[0][outputPos] * currPreset.inputLevel[0] + 
423 					inBuf[1][outputPos] * currPreset.inputLevel[1] + allSums[2];
424 			delayLines[1][dLMod[1] & dLPos[1]] = inBuf[0][outputPos] * currPreset.inputLevel[0] + 
425 					inBuf[1][outputPos] * currPreset.inputLevel[1] + allSums[3];
426 			allSums = __m128(0.0);
427 			for (int d ; d < 2 ; d++) {
428 				for (int t ; t < 4 ; t++) {
429 					if (currPreset.taps[d][t].tapEnable) {
430 						float sum;
431 						if (currPreset.taps[d][t].bypassFIR) {
432 							sum = readDL0(d, currPreset.taps[d][t].pos/*  + (oscOut[outputPos][t] * tapLFOOffset[d][t]) */);
433 						} else {
434 							__m128[4] impulse = readDL(d, currPreset.taps[d][t].pos);
435 							__m128 acc = __m128(0.0);
436 							for (int i ; i < 4 ; i++) {
437 								acc += impulse[i] * currPreset.taps[d][t].fir[i];
438 							}
439 							sum = acc[0] + acc[1] + acc[2] + acc[3];
440 						}
441 						allSums += currPreset.taps[d][t].outLevels * __m128(sum);
442 					}
443 				}
444 			}
445 			__m128 filterOutL = filterBanks[0].output(__m128(allSums[0])) * currPreset.eqLevels[0];
446 			__m128 filterOutR = filterBanks[1].output(__m128(allSums[1])) * currPreset.eqLevels[1];
447 			outBuf[0][outputPos] += allSums[0] + filterOutL[0] + filterOutL[1] + filterOutL[2] + filterOutL[3];
448 			outBuf[1][outputPos] += allSums[1] + filterOutR[0] + filterOutR[1] + filterOutR[2] + filterOutR[3];
449 			dLPos[0]++;
450 			dLPos[1]++;
451 			//delayLines[0][dLMod[0] & dLPos[0]] = allSums[2];
452 			//delayLines[1][dLMod[1] & dLPos[1]] = allSums[3];
453 		}
454 	}
455 
456 	override public int waveformDataReceive(uint id, ubyte[] rawData, WaveFormat format) nothrow {
457 		return SampleLoadErrorCode.SampleLoadingNotSupported;
458 	}
459 
460 	override public int writeParam_int(uint presetID, uint paramID, int value) nothrow {
461 		Preset* presetPtr = presetBank.ptrOf(presetID);
462 		if (presetPtr is null) {
463 			presetBank[presetID] = Preset.init;
464 			presetPtr = presetBank.ptrOf(presetID);
465 		}
466 		const uint paramGr = (paramID)>>7;
467 		switch (paramGr) {
468 			case 0: .. case 7:
469 				const uint tapID = paramGr & 3, lineID = paramGr>>2;
470 				const uint subParamID = paramID & 0x3F;
471 				switch (subParamID) {
472 					case 0: .. case 19:
473 						return 1;
474 					case 20:	//Position
475 						presetPtr.taps[lineID][tapID].pos = value;
476 						return 0;
477 					case 21:	//Tap enable
478 						presetPtr.taps[lineID][tapID].tapEnable = value != 0;
479 						return 0;
480 					case 22:	//Bypass FIR
481 						presetPtr.taps[lineID][tapID].bypassFIR = value != 0;
482 						return 0;
483 					default:
484 						break;
485 				}
486 				break;
487 			/* case 8:		//LFO
488 				const uint lfoID = (paramID>>3) & 3, subParamID = paramID & 7;
489 				switch (subParamID) {
490 					case 0:
491 						presetPtr.oscWaveform[lfoID].raw = cast(ubyte)value;
492 						return 0;
493 					case 1:
494 						presetPtr.oscLevels[lfoID] = value;
495 						return 0;
496 					case 4:
497 						presetPtr.oscTargets[lfoID] = cast(ubyte)value;
498 						return 0;
499 					default:
500 						break;
501 				} 
502 				break; */
503 			default:
504 				break;
505 		}
506 		return 1;
507 	}
508 
509 	override public int writeParam_long(uint presetID, uint paramID, long value) nothrow {
510 		return 1;
511 	}
512 
513 	override public int writeParam_double(uint presetID, uint paramID, double value) nothrow {
514 		Preset* presetPtr = presetBank.ptrOf(presetID);
515 		if (presetPtr is null) {
516 			presetBank[presetID] = Preset.init;
517 			presetPtr = presetBank.ptrOf(presetID);
518 		}
519 		const uint paramGr = (paramID)>>7;
520 		switch (paramGr) {
521 			case 0: .. case 7:
522 				const uint tapID = paramGr & 3, lineID = paramGr>>2;
523 				const uint subParamID = paramID & 0x3F;
524 				switch (subParamID) {
525 					case 0: .. case 3:	//FIR 0
526 						presetPtr.taps[lineID][tapID].fir[0][subParamID] = value;
527 						return 0;
528 					case 4: .. case 7:	//FIR 1
529 						presetPtr.taps[lineID][tapID].fir[1][subParamID - 4] = value;
530 						return 0;
531 					case 8: .. case 11:	//FIR 2
532 						presetPtr.taps[lineID][tapID].fir[2][subParamID - 8] = value;
533 						return 0;
534 					case 12: .. case 15://FIR 3
535 						presetPtr.taps[lineID][tapID].fir[3][subParamID - 12] = value;
536 						return 0;
537 					
538 					case 16: .. case 19:	//Output Levels
539 						const uint levelID = (subParamID - 16) & 3;
540 						presetPtr.taps[lineID][tapID].outLevels[levelID] = value;
541 						return 0;
542 					default:
543 						break;
544 				}
545 				break;
546 			/* case 8:	//LFO
547 				const uint lfoID = (paramID>>3) & 3, subParamID = paramID & 7;
548 				switch (subParamID) {
549 					//case 1:
550 					//	presetPtr.oscLevels[lfoID] = value;
551 					//	return 0;
552 					case 2:
553 						presetPtr.oscFrequencies[lfoID] = value;
554 						return 0;
555 					case 3:
556 						presetPtr.oscPWM[lfoID] = cast(uint)(value * uint.max);
557 						return 0;
558 					default:
559 						break;
560 				}
561 				break; */
562 			case 9: //EQ
563 				const uint EQID = (paramID>>2) & 7;
564 				switch (paramID & 3) {
565 					case 0:
566 						presetPtr.eqLevels[EQID>>2][EQID & 3] = value;
567 						return 0;
568 					case 1:
569 						presetPtr.iirFreq[EQID>>2][EQID & 3] = value;
570 						return 0;
571 					case 2:
572 						presetPtr.iirQ[EQID>>2][EQID & 3] = value;
573 						return 0;
574 					default:
575 						break;
576 				}
577 				break;
578 			case 10: //Levels
579 				const uint subParamID = paramID & 7;
580 				switch (subParamID) {
581 					case 0: .. case 3:
582 						presetPtr.inputLevel[subParamID] = value;
583 						return 0;
584 					case 4, 5:
585 						presetPtr.outputLevel[subParamID - 4] = value;
586 						return 0;
587 					default:
588 						break;
589 				}
590 				break;
591 			default:
592 				break;
593 		}
594 		return 1;
595 	}
596 
597 	override public int writeParam_string(uint presetID, uint paramID, string value) nothrow {
598 		return int.init; // TODO: implement
599 	}
600 
601 	override public MValue[] getParameters() nothrow {
602 		return SET_VALS;
603 	}
604 
605 	override public int readParam_int(uint presetID, uint paramID) nothrow {
606 		Preset* presetPtr = presetBank.ptrOf(presetID);
607 		if (presetPtr is null) {
608 			return int.init;
609 		}
610 		const uint paramGr = (paramID)>>7;
611 		switch (paramGr) {
612 			case 0: .. case 7:
613 				const uint tapID = paramGr & 3, lineID = paramGr>>2;
614 				const uint subParamID = paramID & 0x3F;
615 				switch (subParamID) {
616 					
617 					case 20:	//Position
618 						return presetPtr.taps[lineID][tapID].pos;
619 					case 21:	//Tap enable
620 						return presetPtr.taps[lineID][tapID].tapEnable ? 1 : 0;
621 					case 22:	//Bypass FIR
622 						return presetPtr.taps[lineID][tapID].bypassFIR ? 1 : 0;
623 					default:
624 						break;
625 				}
626 				break;
627 			/* case 8:		//LFO
628 				const uint lfoID = (paramID>>3) & 3, subParamID = paramID & 7;
629 				switch (subParamID) {
630 					case 0:
631 						return presetPtr.oscWaveform[lfoID].raw;
632 					case 1:
633 						return presetPtr.oscLevels[lfoID];
634 					case 4:
635 						return presetPtr.oscTargets[lfoID];
636 					default:
637 						break;
638 				}
639 				break; */
640 			default:
641 				break;
642 		}
643 		return int.init;
644 	}
645 
646 	override public double readParam_double(uint presetID, uint paramID) nothrow {
647 		Preset* presetPtr = presetBank.ptrOf(presetID);
648 		if (presetPtr is null) {
649 			return double.init;
650 		}
651 		const uint paramGr = (paramID)>>7;
652 		switch (paramGr) {
653 			case 0: .. case 7:
654 				const uint tapID = paramGr & 3, lineID = paramGr>>2;
655 				const uint subParamID = paramID & 0x3F;
656 				switch (subParamID) {
657 					case 0: .. case 3:	//FIR 0
658 						return presetPtr.taps[lineID][tapID].fir[0][subParamID];
659 					case 4: .. case 7:	//FIR 1
660 						return presetPtr.taps[lineID][tapID].fir[1][subParamID - 4];
661 					case 8: .. case 11:	//FIR 2
662 						return presetPtr.taps[lineID][tapID].fir[2][subParamID - 8];
663 					case 12: .. case 15://FIR 3
664 						return presetPtr.taps[lineID][tapID].fir[3][subParamID - 12];
665 					case 16: .. case 19:	//Output Levels
666 						const uint levelID = (subParamID - 24) & 3;
667 						return presetPtr.taps[lineID][tapID].outLevels[levelID];
668 					default:
669 						break;
670 				}
671 				break;
672 			/* case 8:	//LFO
673 				const uint lfoID = (paramID>>3) & 3, subParamID = paramID & 7;
674 				switch (subParamID) {
675 					//case 1:
676 					//	return presetPtr.oscLevels[lfoID];
677 					case 2:
678 						return presetPtr.oscFrequencies[lfoID];
679 					case 3:
680 						return presetPtr.oscPWM[lfoID] / uint.max;
681 					default:
682 						break;
683 				}
684 				break; */
685 			case 9:	//EQ
686 				const uint EQID = (paramID>>2) & 7;
687 				switch (paramID & 3) {
688 					case 0:
689 						return presetPtr.eqLevels[EQID>>2][EQID & 3];
690 					case 1:
691 						return presetPtr.iirFreq[EQID>>2][EQID & 3];
692 					case 2:
693 						return presetPtr.iirQ[EQID>>2][EQID & 3];
694 					default:
695 						break;
696 				}
697 				break;
698 			case 10: //Levels
699 				const uint subParamID = paramID & 7;
700 				switch (subParamID) {
701 					case 0: .. case 3:
702 						return presetPtr.inputLevel[subParamID];
703 					case 4, 5:
704 						return presetPtr.outputLevel[subParamID - 4];
705 					default:
706 						break;
707 				}
708 				break;
709 			default:
710 				break;
711 		}
712 		return double.init; // TODO: implement
713 	}
714 
715 	override public long readParam_long(uint presetID, uint paramID) nothrow {
716 		return long.init; // TODO: implement
717 	}
718 
719 	override public string readParam_string(uint presetID, uint paramID) nothrow {
720 		return string.init; // TODO: implement
721 	}
722 }