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 }