1 module pixelperfectengine.audio.modules.qm816; 2 3 import pixelperfectengine.audio.base.modulebase; 4 import pixelperfectengine.audio.base.envgen; 5 import pixelperfectengine.audio.base.func; 6 7 import midi2.types.structs; 8 import midi2.types.enums; 9 10 import inteli.emmintrin; 11 12 import std.math; 13 14 /** 15 QM816 - implements a Quadrature-Amplitude synthesizer. This technique was used in early 16 digital FM synths, since it allowed allowed a cheap implementation of the same thing as 17 long as the modulator was a sinusoidal waveform. 18 19 It has 16 2 operator channels that can be individually paired-up for 4 operator channels, 20 for more complex sounds. Also all operators have the option for feedback, including 21 carriers. 2 operator channels have 2, 4 operator channels have 3*4 algorithms. 22 23 Before use, the synth needs to be supplied with a wavetable file, in 16 bit wav format. 24 */ 25 public class QM816 : AudioModule { 26 /** 27 Contains a table to calculate Attack, Decay, and Release values. 28 29 All values are seconds with factions. Actual values are live-calculated depending on sustain-level and sampling 30 frequency. 31 */ 32 public static immutable float[128] ADSR_TIME_TABLE = [ 33 // 0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |A |B |C |D |E |F 34 0.000, 0.0005,0.001, 0.0015,0.002, 0.0025,0.003, 0.0035,0.004, 0.0045,0.005, 0.006, 0.007, 0.008, 0.009, 0.010,//0 35 0.011, 0.012, 0.013, 0.014, 0.015, 0.017, 0.019, 0.021, 0.023, 0.025, 0.028, 0.031, 0.034, 0.038, 0.042, 0.047,//1 36 0.052, 0.057, 0.062, 0.067, 0.073, 0.079, 0.085, 0.092, 0.099, 0.107, 0.116, 0.126, 0.137, 0.149, 0.162, 0.176,//2 37 0.191, 0.207, 0.224, 0.242, 0.261, 0.281, 0.302, 0.324, 0.347, 0.371, 0.396, 0.422, 0.449, 0.477, 0.506, 0.536,//3 38 0.567, 0.599, 0.632, 0.666, 0.701, 0.737, 0.774, 0.812, 0.851, 0.891, 0.932, 0.974, 1.017, 1.061, 1.106, 1.152,//4 39 1.199, 1.247, 1.296, 1.346, 1.397, 1.499, 1.502, 1.556, 1.611, 1.667, 1.724, 1.782, 1.841, 1.901, 1.962, 2.024,//5 40 2.087, 2.151, 2.216, 2.282, 2.349, 2.417, 2.486, 2.556, 2.627, 2.699, 2.772, 2.846, 2.921, 2.997, 3.074, 3.152,//6 41 3.231, 3.331, 3.392, 3.474, 3.557, 3.621, 3.726, 3.812, 3.899, 3.987, 4.076, 4.166, 4.257, 4.349, 4.442, 4.535,//7 42 43 ]; 44 /** 45 Contains a table to calculate Sustain control values. 46 47 All values are seconds with fractions. Actual values are live-calculated depending on sustain level and sampling 48 frequency. Please note that with certain levels of sustain, the actual max time might be altered. 49 */ 50 public static immutable float[63] SUSTAIN_CONTROL_TIME_TABLE = [ 51 // 0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |A |B |C |D |E |F 52 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 53 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 54 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 55 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 56 ]; 57 /** 58 Defines operator parameter numbers, within the unregistered namespace. 59 */ 60 public enum OperatorParamNums { 61 //Unregistered 62 Level = 0, 63 Attack = 1, 64 Decay = 2, 65 SusLevel = 3, 66 SusCtrl = 4, 67 Release = 5, 68 Waveform = 6, 69 Feedback = 7, 70 TuneCor = 8, 71 TuneFine = 9, 72 ShpA = 10, 73 ShpR = 11, 74 VelToLevel = 12, 75 MWToLevel = 13, 76 LFOToLevel = 14, 77 OpCtrl = 15, 78 VelToFB = 16, 79 MWToFB = 17, 80 LFOToFB = 18, 81 EEGToFB = 19, 82 VelToShpA = 20, 83 VelToShpR = 21, 84 } 85 /** 86 Defines channel parameter numbers, within the unregistered namespace. 87 */ 88 public enum ChannelParamNums { 89 MasterVol = 0, 90 Bal = 1, 91 AuxSLA = 2, 92 AuxSLB = 3, 93 EEGDetune = 4, 94 PLFO = 5, 95 Attack = 6, 96 Decay = 7, 97 SusLevel = 8, 98 SusCtrl = 9, 99 Release = 10, 100 ShpA = 11, 101 ShpR = 12, 102 ChCtrl = 16, 103 RingMod = 17, 104 EEGToLeft = 18, 105 EEGToRight = 19, 106 EEGToAuxA = 20, 107 EEGToAuxB = 21, 108 LFOToLeft = 22, 109 LFOToRight = 23, 110 LFOToAuxA = 24, 111 LFOToAuxB = 25, 112 } 113 /** 114 Defines channel parameters within the registered namespace 115 */ 116 public enum ChannelRegParams { 117 PitchBendSens, 118 TuneCor, 119 TuneFine, 120 } 121 /** 122 Defines global parameter nummbers, within the unregistered namespace 123 */ 124 public enum GlobalParamNums { 125 PLFORate = 0, 126 PLFOWF = 1, 127 ALFORate = 2, 128 ALFOWF = 3, 129 FilterLCFreq= 4, 130 FilterLCQ = 5, 131 FilterRCFreq= 6, 132 FilterRCQ = 7, 133 FilterACFreq= 8, 134 FilterACQ = 9, 135 FilterBCFreq= 10, 136 FilterBCQ = 11, 137 } 138 /** 139 Implements a single operator. 140 141 Contains an oscillator, an ADSR envelop generator, and locals. 142 */ 143 public struct Operator { 144 ///The envelop generator of the operator. 145 ADSREnvelopGenerator eg; 146 ///The current position of the oscillator, including fractions. 147 uint pos; 148 ///The amount the oscillator must be stepped forward each cycle, including fractions. 149 uint step; 150 ///Operator tuning 151 ///Bit 31-25: Coarse detuning (-24 to +103 seminotes) 152 ///Bit 24-0: Fine detuning (-100 to 100 cents), 0x1_00_00_00 is center 153 ///If fixed mode is being used, then top 7 bits are the note, the rest are fine tuning. 154 uint tune = 0x31_00_00_00; 155 enum TuneCtrlFlags : uint { 156 FineTuneMidPoint = 0x1_00_00_00, 157 CorTuneMidPoint = 0x30_00_00_00, 158 FineTuneTest = 0x1_FF_FF_FF, 159 CorTuneTest = 0xFE_00_00_00, 160 } 161 ///Input register. 162 ///The amount which the oscillator will be offsetted. 163 int input; 164 ///Feedback register. Either out_0[n-1] or out[n-1] multiplied by feedback amount. 165 ///The amount which the oscillator will be offsetted. 166 ///Negative if inverted. 167 int feedback; 168 ///Output register. 169 ///Not affected by either level or EG 170 int output; 171 ///Output level (between 0.0 and 1.0) 172 float outL = 1.0; 173 ///Feedback level (between 0.0 and 1.0) 174 float fbL = 0.0; 175 ///Output level controller assignment 176 ///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: unused 177 __m128 outLCtrl= __m128(0.0); 178 ///Feedback level controller assignment 179 ///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: Extra envelop generator 180 __m128 fbLCtrl = __m128(0.0); 181 ///Live calculated out of shpA 182 float shpA0 = 0.0; 183 ///Live calculated out of shpR 184 float shpR0 = 0.0; 185 ///Output affected by EEG and level. 186 ///Either used for audible output, or to modulate other operators 187 int output_0; 188 ///Control flags and Wavetable selector 189 uint opCtrl; 190 ///Defines control values 191 enum OpCtrlFlags { 192 WavetableSelect = 127, ///Wavetable select flags 193 FBMode = 1 << 7, ///Feedback mode (L: After Envelop Generator, H: Before Envelop Generator) 194 FBNeg = 1 << 8, ///Feedback mode (L: Positive, H: Negative) 195 MWNeg = 1 << 9, ///Invert modulation wheel control 196 VelNeg = 1 << 10, ///Invert velocity control 197 EGRelAdaptive = 1 << 11, ///Adaptive release time based on current output level 198 FixedPitch = 1 << 12, ///Enables fixed pitch mode 199 } 200 ///Attack time control (between 0 and 127) 201 ubyte atk; 202 ///Decay time control (between 0 and 127) 203 ubyte dec; 204 ///Release time control (between 0 and 127) 205 ubyte rel; 206 ///Sustain curve control (between 0 and 127) 207 ///0: Percussive mode 208 ///1 - 63: Descending over time 209 ///64: Constant 210 ///65 - 127: Ascending over time 211 ubyte susCC; 212 ///ADSR shaping parameter (for the attack phase) 213 float shpA = 0.5; 214 ///ADSR shaping parameter (for the decay/release phase) 215 float shpR = 0.5; 216 ///Assigns velocity to shpA 217 float shpAVel = 0.0; 218 ///Assigns velocity to shpR 219 float shpRVel = 0.0; 220 221 ///Sets the frequency of the operator 222 void setFrequency(int slmpFreq, ubyte note, double pitchBend, double tuning) @nogc @safe pure nothrow { 223 /+const double actualNote = (opCtrl & OpCtrlFlags.FixedPitch) ? 224 (tune>>25) + ((cast(double)(tune & TuneCtrlFlags.FineTuneTest) - TuneCtrlFlags.FineTuneMidPoint) / 225 TuneCtrlFlags.FineTuneTest) : pitchBend + note ;+/ 226 double actualNote; 227 if (opCtrl & OpCtrlFlags.FixedPitch) { 228 actualNote = (tune>>25) + ((cast(double)(tune & TuneCtrlFlags.FineTuneTest) - TuneCtrlFlags.FineTuneMidPoint) / 229 TuneCtrlFlags.FineTuneTest); 230 } else { 231 actualNote = pitchBend + note + cast(int)((tune>>25) - TuneCtrlFlags.CorTuneMidPoint) + ((cast(double)(tune & 232 TuneCtrlFlags.FineTuneTest) - TuneCtrlFlags.FineTuneMidPoint) / TuneCtrlFlags.FineTuneTest); 233 } 234 const double oscFreq = noteToFreq(actualNote, tuning); 235 const double cycLen = oscFreq / (slmpFreq / 1024.0); 236 step = cast(uint)(cast(double)(1<<20) / cycLen); 237 } 238 ///Resets the Envelop generator 239 void resetEG(int sampleRate) @nogc @safe pure nothrow { 240 //Set attack phase 241 if (atk) { 242 eg.attackRate = calculateRate(ADSR_TIME_TABLE[atk], sampleRate); 243 } else { 244 eg.attackRate = 1.0; 245 } 246 //Set decay phase 247 if (dec) { 248 eg.decayRate = calculateRate(ADSR_TIME_TABLE[dec] * 2, sampleRate, ADSREnvelopGenerator.maxOutput, eg.sustainLevel); 249 } else { 250 eg.decayRate = 1.0; 251 } 252 //Set sustain phase 253 if (susCC) { 254 eg.isPercussive = false; 255 if (susCC == 64) { 256 eg.sustainControl = 0.0; 257 } else if (susCC < 64) { 258 eg.sustainControl = -1.0 * 259 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[susCC - 1], sampleRate); 260 } else { 261 eg.sustainControl = 262 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[susCC - 64], sampleRate); 263 } 264 } else { 265 eg.isPercussive = true; 266 eg.sustainControl = 0.0; 267 } 268 //Set release phase 269 if (rel) { 270 eg.releaseRate = calculateRate(ADSR_TIME_TABLE[rel] * 2, sampleRate, eg.sustainLevel); 271 } else { 272 eg.releaseRate = 1.0; 273 } 274 } 275 auto opAssign(Preset.Op value) @nogc @safe pure nothrow { 276 eg.sustainLevel = value.susLevel; 277 tune = value.tune; 278 outL = value.outL; 279 fbL = value.fbL; 280 for (int i ; i < 4 ; i++) 281 outLCtrl[i] = value.outLCtrl[i]; 282 for (int i ; i < 4 ; i++) 283 fbLCtrl[i] = value.fbLCtrl[i]; 284 opCtrl = value.opCtrl; 285 atk = value.atk; 286 dec = value.dec; 287 susCC = value.susCC; 288 rel = value.rel; 289 return this; 290 } 291 } 292 /** 293 Defines channel common parameters. 294 */ 295 public struct Channel { 296 ///Extra envelop generator that can be assigned for multiple purpose. 297 ADSREnvelopGenerator eeg; 298 ///ADSR shaping parameter (for the attack phase) 299 float shpAX; 300 ///ADSR shaping parameter (for the decay/release phase) 301 float shpRX; 302 ///Pitch amount for EEG 303 ///Bit 31-25: Coarse (-64 to +63 seminotes) 304 ///Bit 24-0: Fine (0 to 100 cents) 305 uint eegDetuneAm; 306 ///Pitch bend sensitivity 307 ///Bit 31-25: Coarse (0 to 127 seminotes) 308 ///Bit 24-0: Fine (0 to 100 cents) 309 uint pitchBendSens; 310 ///A-4 channel tuning in hertz. 311 float chnlTun = 440.0; 312 ///Stores channel control flags. 313 uint chCtrl; 314 ///Defines channel control flags. 315 enum ChCtrlFlags { 316 ///Channel combination turned off, the channel pair is independent 317 ComboModeOff = 0b0000, 318 ///Channel combination mode 1: Secondary channel's output is fed into primary operator 0. 319 ComboMode1 = 0b0001, 320 ///Channel combination mode 2: Secondary channel's output is fed into primary operator 1 if primary 321 ///is in serial mode, or into both if primary is in parallel mode. 322 ComboMode2 = 0b0010, 323 ///Channel combination mode 3: Secondary channel's output is fed into main output, except if primary 324 ///channel set to parallel and secondary set to serial, then S1, P0, and P1 are connected to output, while 325 ///S0 is modulating all of them. 326 ComboMode3 = 0b0011, 327 ///Used for testing combo mode. 328 ComboModeTest = ComboMode3, 329 Algorithm = 1<<2, ///Channel algorithm (H: Parallel, L: Series) 330 IndivOutChLev = 1<<3, ///Enables the setting of individual output channel levels 331 LFOPan = 1<<4, ///Enables LFO Panning 332 EEGPan = 1<<5, ///Enables EEG Panning 333 MWToTrem = 1<<6, ///Assigns modwheel to amplitude LFO 334 MWToVibr = 1<<7, ///Assigns modwheel to pitch LFO 335 MWToAux = 1<<8, ///Assigns modwheel to aux levels 336 } 337 ///Master volume (0.0 to 1.0) 338 float masterVol; 339 ///Master balance (0.0 to 1.0) 340 float masterBal; 341 ///Calculated output level controls + aux send levels 342 ///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B 343 __m128 outLevels; 344 ///EEG assign levels 345 ///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B 346 __m128 eegLevels; 347 ///Amplitude LFO assign levels 348 ///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B 349 __m128 aLFOlevels; 350 ///Ring modulation amount 351 ///Only available on select algorithms 352 int rmAmount; 353 ///Pitch LFO level 354 float pLFOlevel; 355 ///Amplitude LFO to 356 ///Attack time control (between 0 and 127) 357 ubyte atkX; 358 ///Decay time control (between 0 and 127) 359 ubyte decX; 360 ///Release time control (between 0 and 127) 361 ubyte relX; 362 ///Sustain curve control (between 0 and 127) 363 ///0: Percussive mode 364 ///1 - 63: Descending over time 365 ///64: Constant 366 ///65 - 127: Ascending over time 367 ubyte susCCX; 368 ///Resets the Extra Envelop generator 369 void resetEEG(int sampleRate) @nogc @safe pure nothrow { 370 //Set attack phase 371 if (atkX) { 372 eeg.attackRate = calculateRate(ADSR_TIME_TABLE[atkX], sampleRate); 373 } else { 374 eeg.attackRate = 1.0; 375 } 376 //Set decay phase 377 if (decX) { 378 eeg.decayRate = calculateRate(ADSR_TIME_TABLE[decX] * 2, sampleRate, ADSREnvelopGenerator.maxOutput, eeg.sustainLevel); 379 } else { 380 eeg.decayRate = 1.0; 381 } 382 //Set sustain phase 383 if (susCCX) { 384 eeg.isPercussive = false; 385 if (susCCX == 64) { 386 eeg.sustainControl = 0.0; 387 } else if (susCCX < 64) { 388 eeg.sustainControl = -1.0 * calculateRate(SUSTAIN_CONTROL_TIME_TABLE[susCCX - 1], sampleRate); 389 } else { 390 eeg.sustainControl = calculateRate(SUSTAIN_CONTROL_TIME_TABLE[susCCX - 64], sampleRate); 391 } 392 } else { 393 eeg.isPercussive = true; 394 eeg.sustainControl = 0.0; 395 } 396 //Set release phase 397 if (relX) { 398 eeg.releaseRate = calculateRate(ADSR_TIME_TABLE[relX] * 2, sampleRate, eeg.sustainLevel); 399 } else { 400 eeg.releaseRate = 1.0; 401 } 402 } 403 auto opAssign(Preset.Ch value) @nogc @safe pure nothrow { 404 eeg.sustainLevel = value.susLevel; 405 shpAX = value.shpAX; 406 shpRX = value.shpRX; 407 eegDetuneAm = value.eegDetuneAm; 408 pitchBendSens = value.pitchBendSens; 409 chnlTun = value.chnlTun; 410 chCtrl = value.chCtrl; 411 masterVol = value.masterVol; 412 masterBal = value.masterBal; 413 outLevels[2] = value.auxSendA; 414 outLevels[3] = value.auxSendB; 415 for (int i ; i < 4 ; i++) 416 eegLevels[i] = value.eegLevels[i]; 417 for (int i ; i < 4 ; i++) 418 aLFOlevels[i] = value.aLFOlevels[i]; 419 rmAmount = value.rmAmount; 420 pLFOlevel = value.pLFOlevel; 421 atkX = value.atkX; 422 decX = value.decX; 423 relX = value.relX; 424 susCCX = value.susCCX; 425 if (chCtrl & ChCtrlFlags.IndivOutChLev) { 426 outLevels[1] = masterBal * masterBal; 427 } else { 428 outLevels[0] = masterVol - masterBal; 429 outLevels[1] = masterVol - (1.0 - masterBal); 430 } 431 return this; 432 } 433 } 434 /** 435 Stores channel controller values (modwheel, velocity, etc.) 436 */ 437 public struct ChControllers { 438 ///Modulation wheel parameter, normalized between 0.0 and 1.0 439 float modwheel; 440 ///Velocity parameter, normalized between 0.0 and 1.0 441 float velocity; 442 ///Pitch bend parameter, with the amount of pitch shifting in semitones + fractions 443 float pitchBend; 444 ///The note that is currently being played 445 ubyte note; 446 } 447 /** 448 Defines a preset. 449 */ 450 public struct Preset { 451 ///Defines parameters of a single operator 452 public struct Op { 453 ///Operator tuning 454 ///Bit 31-25: Coarse detuning (-24 to +103 seminotes) 455 ///Bit 24-0: Fine detuning (-100 to 100 cents), 0x1_00_00_00 is center 456 ///If fixed mode is being used, then top 7 bits are the note, the rest are fine tuning. 457 uint tune = 0x31_00_00_00; 458 ///Output level (between 0.0 and 1.0) 459 float outL; 460 ///Feedback level (between 0.0 and 1.0) 461 float fbL; 462 ///Output level controller assignment 463 ///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: unused 464 float[4] outLCtrl; 465 ///Feedback level controller assignment 466 ///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: Extra envelop generator 467 float[4] fbLCtrl; 468 ///Control flags and Wavetable selector 469 uint opCtrl; 470 ///Attack time control (between 0 and 127) 471 ubyte atk; 472 ///Decay time control (between 0 and 127) 473 ubyte dec; 474 ///Release time control (between 0 and 127) 475 ubyte rel; 476 ///Sustain curve control (between 0 and 127) 477 ///0: Percussive mode 478 ///1 - 63: Descending over time 479 ///64: Constant 480 ///65 - 127: Ascending over time 481 ubyte susCC; 482 ///Sustain level for the EG 483 float susLevel; 484 ///ADSR shaping parameter (for the attack phase) 485 float shpA = 0.5; 486 ///ADSR shaping parameter (for the decay/release phase) 487 float shpR = 0.5; 488 ///Assigns velocity to shpA 489 float shpAVel = 0.0; 490 ///Assigns velocity to shpR 491 float shpRVel = 0.0; 492 } 493 ///Defines parameters of a single channel. 494 public struct Ch { 495 ///ADSR shaping parameter (for the attack phase) 496 float shpAX; 497 ///ADSR shaping parameter (for the decay/release phase) 498 float shpRX; 499 ///Pitch amount for EEG 500 ///Bit 31-25: Coarse (-64 to +63 seminotes) 501 ///Bit 24-0: Fine (0 to 100 cents) 502 uint eegDetuneAm; 503 ///Pitch bend sensitivity 504 ///Bit 31-25: Coarse (0 to 127 seminotes) 505 ///Bit 24-0: Fine (0 to 100 cents) 506 uint pitchBendSens; 507 ///A-4 channel tuning in hertz. 508 float chnlTun = 440.0; 509 ///Stores channel control flags. 510 uint chCtrl; 511 ///Master volume (0.0 to 1.0) 512 float masterVol; 513 ///Master balance (0.0 to 1.0) 514 float masterBal; 515 ///Aux send A 516 float auxSendA; 517 ///Aux send B 518 float auxSendB; 519 ///EEG assign levels 520 ///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B 521 float[4] eegLevels; 522 ///Amplitude LFO assign levels 523 ///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B 524 float[4] aLFOlevels; 525 ///Ring modulation amount 526 ///Only available on select algorithms 527 int rmAmount; 528 ///Pitch LFO level 529 float pLFOlevel; 530 ///Amplitude LFO to 531 ///Attack time control (between 0 and 127) 532 ubyte atkX; 533 ///Decay time control (between 0 and 127) 534 ubyte decX; 535 ///Release time control (between 0 and 127) 536 ubyte relX; 537 ///Sustain curve control (between 0 and 127) 538 ///0: Percussive mode 539 ///1 - 63: Descending over time 540 ///64: Constant 541 ///65 - 127: Ascending over time 542 ubyte susCCX; 543 ///Sustain level 544 float susLevel; 545 } 546 Op[2] operators; ///The operators belonging to this channel 547 Ch channel; ///Channel common values 548 } 549 ///Contains the wavetables for the operators and LFOs. 550 ///Value might be divided to limit the values between 2047 and -2048 via bitshifting, 551 ///otherwise the full range can be used for audio output, etc. 552 ///Loaded from a 16 bit wave file. 553 protected short[1024][128] wavetables; 554 ///Stores presets. 555 ///8 banks of 128 presets are available for a total of 1024. 556 ///If a channel combination is being used, then bank pairs (0-1, 2-3, etc) will store their primary and secondary 557 ///halves, and calling either will load both halves. 558 protected Preset[128][8] soundBank; 559 ///Operator data. 560 ///See rendering function on updating. 561 protected Operator[32] operators; 562 ///Channel data. 563 ///See rendering function on updating. 564 protected Channel[16] channels; 565 ///Channel control data. 566 protected ChControllers[16] chCtrls; 567 ///Preset numbers per channels. 568 protected ubyte[16] presetNum; 569 ///Bank numbers per channels. 570 protected ubyte[16] bankNum; 571 ///Keeps the registered/unregistered parameter positions (LSB = 0). 572 protected ubyte[2] paramNum; 573 ///Stores LFO waveform selection. 1: Amplitude; 0: Pitch 574 protected ubyte[2] lfoWaveform; 575 ///Stores temporary parameter values 576 protected ubyte[4] paramTemp; 577 ///Stores ALFO position 578 protected uint aLFOPos; 579 ///Stores ALFO rate 580 protected uint aLFORate; 581 ///Stores output filter values. 582 ///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] 583 protected __m128[10] filterVals; 584 ///Stores control values of the output values. 585 ///Layout: [LF, LQ, RF, RQ, AF, AQ, BF, BQ] 586 protected float[8] filterCtrl; 587 ///Initial mixing buffers 588 ///Output is directed there before filtering 589 ///Layout is: LRAB 590 protected float[] initBuffers; 591 ///Dummy buffer 592 ///Only used if one or more outputs haven't been defined 593 protected float[] dummyBuf; 594 ///Amplitude LFO buffer. Values are between 0.0 and 1.0 595 protected float[] aLFOBuf; 596 ///Pitch LFO output. Values are between -1.0 and 1.0 597 protected float pLFOOut; 598 ///Stores PLFO position 599 protected uint pLFOPos; 600 ///Stores PLFO rate 601 protected uint pLFORate; 602 ///Mixdown value. 603 ///Used for final mixing. 604 protected float mixdownVal = 1.0 / (ushort.max); 605 alias ChFun = void delegate(int chNum, size_t length) @nogc pure nothrow; 606 ///Channel update delegates 607 protected ChFun[16] chDeleg; 608 /** 609 Creates an instance of QM816 610 */ 611 public this(ModuleManager handler) @safe nothrow { 612 this.handler = handler; 613 info.nOfAudioInput = 0; 614 info.nOfAudioOutput = 4; 615 info.outputChNames = ["mainL", "mainR", "auxSendA", "auxSendB"]; 616 info.isInstrument = true; 617 info.hasMidiIn = true; 618 info.hasMidiOut = true; 619 info.midiSendback = true; 620 } 621 /** 622 * Receives waveform data that has been loaded from disk for reading. Returns zero if successful, or a specific 623 * errorcode. 624 * 625 * id: The ID of the waveform. 626 * rawData: The data itself, in unprocessed form. 627 * format: The format of the wave data, including the data type, bit depth, base sampling rate 628 * 629 * Note: This function needs the audio system to be unlocked. 630 */ 631 public override int waveformDataReceive(uint id, ubyte[] rawData, WaveFormat format) nothrow { 632 int errorcode; 633 if (format.channels != 1) errorcode |= SampleLoadErrorCode.ChNumNotSupported; 634 if (format.bitsPerSample != 16) errorcode |= SampleLoadErrorCode.BitdepthNotSupported; 635 if (format.format != AudioFormat.PCM) errorcode |= SampleLoadErrorCode.FormatNotSupported; 636 if (rawData.length != 128 * 1024 * 2) errorcode |= SampleLoadErrorCode.SampleLenghtNotSupported; 637 if (errorcode) { 638 return errorcode; 639 } else { 640 import core.stdc.string : memcpy; 641 memcpy (wavetables.ptr, rawData.ptr, 128 * 1024 * 2); 642 return 0; 643 } 644 } 645 /** 646 * MIDI 2.0 data received here. 647 * 648 * data: up to 128 bits of MIDI 2.0 commands. Any packets that are shorter should be padded with zeros. 649 * offset: time offset of the command. This can reduce jitter caused by the asynchronous operation of the 650 * sequencer and the audio plugin system. 651 */ 652 public override void midiReceive(uint[4] data, uint offset) @nogc nothrow { 653 UMP firstPacket; 654 firstPacket.base = data[0]; 655 switch (firstPacket.msgType) { 656 case MessageType.SysCommMsg: //Process system common message 657 break; 658 case MessageType.MIDI1: //Process MIDI 1.0 messages 659 switch (firstPacket.status) { 660 case MIDI1_0Cmd.CtrlCh: //Process MIDI 1.0 control change messages 661 switch (firstPacket.note) { 662 case 0, 32: //Bank select 663 bankNum[firstPacket.channel] = firstPacket.value; 664 break; 665 case 1: //Modulation wheel 666 chCtrls[firstPacket.channel].modwheel = cast(double)(firstPacket.value) / byte.max; 667 break; 668 case 6: //Data Entry MSB 669 paramNum[1] = firstPacket.value; 670 break; 671 case 38: //Data Entry LSB 672 paramNum[0] = firstPacket.value; 673 break; 674 case 98: //Non Registered Parameter Number LSB 675 setUnregisteredParam(firstPacket.value, paramNum, 0, firstPacket.channel); 676 break; 677 case 99: //Non Registered Parameter Number LSB 678 setUnregisteredParam(firstPacket.value, paramNum, 0, firstPacket.channel); 679 break; 680 default: 681 break; 682 } 683 break; 684 case MIDI1_0Cmd.NoteOn: //Note on command 685 const uint ch = firstPacket.channel; 686 if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch > 7) return; 687 chCtrls[ch].note = firstPacket.note; 688 chCtrls[ch].velocity = cast(double)firstPacket.velocity / cast(double)byte.max; 689 channels[ch].eeg.keyOn(); 690 operators[ch].eg.keyOn(); 691 operators[ch].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun); 692 operators[ch + 1].eg.keyOn(); 693 operators[ch + 1].setFrequency(sampleRate, firstPacket.note, chCtrls[ch + 1].pitchBend, channels[ch].chnlTun); 694 if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch <= 7) { 695 channels[ch + 8].eeg.keyOn(); 696 operators[ch + 16].eg.keyOn(); 697 operators[ch + 16].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun); 698 operators[ch + 17].eg.keyOn(); 699 operators[ch + 17].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun); 700 } 701 break; 702 case MIDI1_0Cmd.NoteOff://Note off command 703 const uint ch = firstPacket.channel; 704 if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch > 7) return; 705 chCtrls[ch].velocity = cast(double)firstPacket.velocity / cast(double)byte.max; 706 channels[ch].eeg.keyOff(); 707 operators[ch].eg.keyOff(); 708 if (operators[ch].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) { 709 if (operators[ch].rel) { 710 operators[ch].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch].rel] * 2, sampleRate, 711 operators[ch].eg.sustainLevel); 712 } else { 713 operators[ch].eg.releaseRate = 1.0; 714 } 715 } 716 operators[ch + 1].eg.keyOff(); 717 if (operators[ch + 1].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) { 718 if (operators[ch + 1].rel) { 719 operators[ch + 1].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 1].rel] * 2, sampleRate, 720 operators[ch + 1].eg.sustainLevel); 721 } else { 722 operators[ch + 1].eg.releaseRate = 1.0; 723 } 724 } 725 if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch <= 7) { 726 channels[ch + 8].eeg.keyOff(); 727 operators[ch + 16].eg.keyOff(); 728 if (operators[ch + 16].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) { 729 if (operators[ch + 16].rel) { 730 operators[ch + 16].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 16].rel] * 2, sampleRate, 731 operators[ch + 16].eg.sustainLevel); 732 } else { 733 operators[ch + 16].eg.releaseRate = 1.0; 734 } 735 } 736 operators[ch + 17].eg.keyOff(); 737 if (operators[ch + 17].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) { 738 if (operators[ch + 17].rel) { 739 operators[ch + 17].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 17].rel] * 2, sampleRate, 740 operators[ch + 17].eg.sustainLevel); 741 } else { 742 operators[ch + 17].eg.releaseRate = 1.0; 743 } 744 } 745 } 746 break; 747 case MIDI1_0Cmd.ChAftrTch: 748 chCtrls[firstPacket.channel].velocity = cast(double)firstPacket.note / cast(double)byte.max; 749 break; 750 case MIDI1_0Cmd.PolyAftrTch: 751 chCtrls[firstPacket.channel].velocity = cast(double)firstPacket.velocity / cast(double)byte.max; 752 break; 753 case MIDI1_0Cmd.PrgCh: //Program change 754 const uint chOffset = firstPacket.channel; 755 const uint chCtrl = soundBank[bankNum[chOffset] & 7][presetNum[chOffset]].channel.chCtrl; 756 if (chCtrl & Channel.ChCtrlFlags.ComboModeTest) { 757 const uint chX = chOffset & 7, bankX = bankNum[chOffset] & 7 & ~1; 758 prgRecall(chX, presetNum[chX], bankX); 759 prgRecall(chX + 8, presetNum[chX], bankX + 1); 760 } else { 761 prgRecall(chOffset, presetNum[chOffset], bankNum[chOffset]); 762 } 763 break; 764 case MIDI1_0Cmd.PitchBend: 765 const uint ch = firstPacket.channel; 766 const double pitchBendSens = (channels[ch].pitchBendSens>>25) + 767 (cast(double)(channels[ch].pitchBendSens & 0x01_FF_FF_FF) / 0x01_FF_FF_FF); 768 chCtrls[ch].pitchBend = pitchBendSens * ((cast(double)firstPacket.bend - 0x20_00) / 0x3F_FF); 769 break; 770 default: 771 break; 772 } 773 break; 774 case MessageType.MIDI2: 775 switch (firstPacket.status) { 776 case MIDI2_0Cmd.CtrlCh: //Control change 777 setUnregisteredParam(data[1], [firstPacket.index, firstPacket.value], 0, firstPacket.channel); 778 break; 779 case MIDI2_0Cmd.CtrlChR://Registered control change 780 setRegisteredParam(data[1], [firstPacket.index, firstPacket.value], 0, firstPacket.channel); 781 break; 782 case MIDI2_0Cmd.PrgCh: //Program change 783 const uint chOffset = firstPacket.channel; 784 //const uint prg = data[1]>>24, bank = data[1] & 7; 785 presetNum[chOffset] = cast(ubyte)(data[1]>>24); 786 if (firstPacket.value & 1) bankNum[chOffset] = cast(ubyte)(data[1] & 7); 787 const uint chCtrl = soundBank[bankNum[chOffset] & 7][presetNum[chOffset]].channel.chCtrl; 788 if (chCtrl & Channel.ChCtrlFlags.ComboModeTest) { 789 const uint chX = chOffset & 7, bankX = bankNum[chOffset] & 7 & ~1; 790 prgRecall(chX, presetNum[chX], bankX); 791 prgRecall(chX + 8, presetNum[chX], bankX + 1); 792 } else { 793 prgRecall(chOffset, presetNum[chOffset], bankNum[chOffset]); 794 } 795 break; 796 case MIDI2_0Cmd.NoteOn: 797 NoteVals v = *cast(NoteVals*)(&data[1]); 798 const uint ch = firstPacket.channel; 799 if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch > 7) return; 800 chCtrls[ch].note = firstPacket.note; 801 chCtrls[ch].velocity = v.velocity / cast(double)ushort.max; 802 channels[ch].eeg.keyOn(); 803 operators[ch].eg.keyOn(); 804 operators[ch].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun); 805 operators[ch + 1].eg.keyOn(); 806 operators[ch + 1].setFrequency(sampleRate, firstPacket.note, chCtrls[ch + 1].pitchBend, channels[ch].chnlTun); 807 if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch <= 7) { 808 channels[ch + 8].eeg.keyOn(); 809 operators[ch + 16].eg.keyOn(); 810 operators[ch + 16].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun); 811 operators[ch + 17].eg.keyOn(); 812 operators[ch + 17].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].chnlTun); 813 } 814 break; 815 case MIDI2_0Cmd.NoteOff: 816 NoteVals v = *cast(NoteVals*)(&data[1]); 817 const uint ch = firstPacket.channel; 818 if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch > 7) return; 819 //chCtrls[ch].note = firstPacket.note; 820 chCtrls[ch].velocity = v.velocity / cast(double)ushort.max; 821 channels[ch].eeg.keyOff(); 822 operators[ch].eg.keyOff(); 823 if (operators[ch].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) { 824 if (operators[ch].rel) { 825 operators[ch].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch].rel] * 2, sampleRate, 826 operators[ch].eg.sustainLevel); 827 } else { 828 operators[ch].eg.releaseRate = 1.0; 829 } 830 } 831 operators[ch + 1].eg.keyOff(); 832 if (operators[ch + 1].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) { 833 if (operators[ch + 1].rel) { 834 operators[ch + 1].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 1].rel] * 2, sampleRate, 835 operators[ch + 1].eg.sustainLevel); 836 } else { 837 operators[ch + 1].eg.releaseRate = 1.0; 838 } 839 } 840 if ((channels[ch].chCtrl & Channel.ChCtrlFlags.ComboModeTest) && ch <= 7) { 841 channels[ch + 8].eeg.keyOff(); 842 operators[ch + 16].eg.keyOff(); 843 if (operators[ch + 16].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) { 844 if (operators[ch + 16].rel) { 845 operators[ch + 16].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 16].rel] * 2, sampleRate, 846 operators[ch + 16].eg.sustainLevel); 847 } else { 848 operators[ch + 16].eg.releaseRate = 1.0; 849 } 850 } 851 operators[ch + 17].eg.keyOff(); 852 if (operators[ch + 17].opCtrl & Operator.OpCtrlFlags.EGRelAdaptive) { 853 if (operators[ch + 17].rel) { 854 operators[ch + 17].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 17].rel] * 2, sampleRate, 855 operators[ch + 17].eg.sustainLevel); 856 } else { 857 operators[ch + 17].eg.releaseRate = 1.0; 858 } 859 } 860 } 861 break; 862 case MIDI2_0Cmd.PitchBend: 863 const uint ch = firstPacket.channel; 864 const double pitchBendSens = (channels[ch].pitchBendSens>>25) + 865 (cast(double)(channels[ch].pitchBendSens & 0x01_FF_FF_FF) / 0x01_FF_FF_FF); 866 chCtrls[ch].pitchBend = pitchBendSens * (cast(double)(firstPacket.bend - (uint.max / 2)) / (uint.max / 2)); 867 break; 868 default: 869 break; 870 } 871 break; 872 default: 873 break; 874 } 875 } 876 /** 877 Sets the channel delegates 878 */ 879 protected void setChDeleg(uint chCtrl, uint chNum, uint chCtrl0 = 0) @nogc @safe pure nothrow { 880 if (chCtrl & Channel.ChCtrlFlags.ComboModeTest) { //Test if channel is combined or not 881 if (chNum < 8) { 882 const uint algID = chCtrl & (Channel.ChCtrlFlags.ComboModeTest | Channel.ChCtrlFlags.Algorithm) | 883 ((chCtrl0 | Channel.ChCtrlFlags.Algorithm)<<1); 884 enum priChAlg = Channel.ChCtrlFlags.Algorithm; 885 enum secChAlg = Channel.ChCtrlFlags.Algorithm<<1; 886 switch (algID) { 887 case Channel.ChCtrlFlags.ComboMode1: 888 chDeleg[chNum] = &updateChannelM100; 889 break; 890 case Channel.ChCtrlFlags.ComboMode1 | secChAlg: 891 chDeleg[chNum] = &updateChannelM110; 892 break; 893 case Channel.ChCtrlFlags.ComboMode1 | priChAlg: 894 chDeleg[chNum] = &updateChannelM101; 895 break; 896 case Channel.ChCtrlFlags.ComboMode1 | secChAlg | priChAlg: 897 chDeleg[chNum] = &updateChannelM111; 898 break; 899 case Channel.ChCtrlFlags.ComboMode2: 900 chDeleg[chNum] = &updateChannelM200; 901 break; 902 case Channel.ChCtrlFlags.ComboMode2 | secChAlg: 903 chDeleg[chNum] = &updateChannelM210; 904 break; 905 case Channel.ChCtrlFlags.ComboMode2 | priChAlg: 906 chDeleg[chNum] = &updateChannelM201; 907 break; 908 case Channel.ChCtrlFlags.ComboMode2 | secChAlg | priChAlg: 909 chDeleg[chNum] = &updateChannelM211; 910 break; 911 case Channel.ChCtrlFlags.ComboMode3: 912 chDeleg[chNum] = &updateChannelM300; 913 break; 914 case Channel.ChCtrlFlags.ComboMode3 | secChAlg: 915 chDeleg[chNum] = &updateChannelM310; 916 break; 917 case Channel.ChCtrlFlags.ComboMode3 | priChAlg: 918 chDeleg[chNum] = &updateChannelM301; 919 break; 920 case Channel.ChCtrlFlags.ComboMode3 | secChAlg | priChAlg: 921 chDeleg[chNum] = &updateChannelM311; 922 break; 923 default: 924 chDeleg[chNum] = &updateChannelMD; 925 break; 926 } 927 } else { 928 chDeleg[chNum] = &updateChannelMD; 929 } 930 } else { 931 if (chCtrl & Channel.ChCtrlFlags.Algorithm) 932 chDeleg[chNum] = &updateChannelM01; 933 else 934 chDeleg[chNum] = &updateChannelM00; 935 } 936 } 937 /** 938 Recalls a program 939 */ 940 protected void prgRecall(ubyte ch, ubyte prg, ubyte bank) @nogc @safe pure nothrow { 941 Preset p = soundBank[bank & 7][prg]; 942 operators[ch] = p.operators[0]; 943 operators[ch].resetEG(sampleRate); 944 operators[ch + 1] = p.operators[1]; 945 operators[ch + 1].resetEG(sampleRate); 946 channels[ch] = p.channel; 947 channels[ch].resetEEG(sampleRate); 948 } 949 /** 950 Sets a registered parameter 951 952 If type is not zero, then the MSB is being set, otherwise the LSB will be used 953 */ 954 protected void setRegisteredParam(T)(T val, ubyte[2] paramNum, ubyte type, ubyte chNum) @nogc @safe pure nothrow { 955 switch (paramNum[0]) { 956 case ChannelRegParams.PitchBendSens: 957 static if (is(T == uint)) { 958 channels[chNum].pitchBendSens = val; 959 } else static if (is(T == ubyte)) { 960 if (type) { 961 channels[chNum].pitchBendSens &= ~(byte.max<<25); 962 channels[chNum].pitchBendSens |= val<<25; 963 } else { 964 channels[chNum].pitchBendSens &= ~(byte.max<<18); 965 channels[chNum].pitchBendSens |= val<<18; 966 } 967 } 968 break; 969 case ChannelRegParams.TuneFine: //Channel master tuning (fine) 970 break; 971 case ChannelRegParams.TuneCor: //Channel master tuning (coarse) 972 break; 973 default: break; 974 } 975 } 976 /** 977 Sets an unregistered parameter 978 979 If type is not zero, then the MSB is being set, otherwise the LSB will be used 980 */ 981 protected void setUnregisteredParam(T)(T val, ubyte[2] paramNum, ubyte type, ubyte chNum) @nogc @safe pure nothrow { 982 void setOpParam(int chNum) { 983 switch (paramNum[0]) { 984 case OperatorParamNums.Attack: 985 static if (is(T == uint)) { 986 operators[chNum].atk = cast(ubyte)(val >> 25); 987 } else static if (is(T == ubyte)) { 988 operators[chNum].atk = val; 989 } 990 if (operators[chNum].atk) { 991 operators[chNum].eg.attackRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].atk], sampleRate); 992 } else { 993 operators[chNum].eg.attackRate = 1.0; 994 } 995 break; 996 case OperatorParamNums.Decay: 997 static if (is(T == uint)) { 998 operators[chNum].dec = cast(ubyte)(val >> 25); 999 } else static if (is(T == ubyte)) { 1000 operators[chNum].dec = val; 1001 } 1002 if (operators[chNum].dec) { 1003 operators[chNum].eg.decayRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].dec] * 2, sampleRate, 1004 ADSREnvelopGenerator.maxOutput, operators[chNum].eg.sustainLevel); 1005 } else { 1006 operators[chNum].eg.decayRate = 1.0; 1007 } 1008 break; 1009 case OperatorParamNums.Feedback: 1010 static if (is(T == uint)) { 1011 const double valF = cast(double)val / uint.max; 1012 operators[chNum].fbL = valF * valF; 1013 } else static if (is(T == ubyte)) { 1014 if (type) 1015 paramTemp[2] = val; 1016 else 1017 paramTemp[3] = val; 1018 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1019 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1020 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1021 operators[chNum].fbL = valF * valF; 1022 } else { //Set temp for next command (assume MSB-LSB order) 1023 paramNum[0] = paramTemp[0]; 1024 paramNum[1] = paramTemp[1]; 1025 } 1026 } 1027 break; 1028 case OperatorParamNums.Level: 1029 static if (is(T == uint)) { 1030 const double valF = cast(double)val / uint.max; 1031 operators[chNum].outL = valF * valF; 1032 } else static if (is(T == ubyte)) { 1033 if (type) 1034 paramTemp[2] = val; 1035 else 1036 paramTemp[3] = val; 1037 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1038 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1039 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1040 operators[chNum].outL = valF * valF; 1041 } else { //Set temp for next command (assume MSB-LSB order) 1042 paramNum[0] = paramTemp[0]; 1043 paramNum[1] = paramTemp[1]; 1044 } 1045 } 1046 break; 1047 case OperatorParamNums.OpCtrl: 1048 static if (is(T == uint)) { 1049 operators[chNum].opCtrl = val; 1050 } else static if (is(T == ubyte)) { 1051 operators[chNum].opCtrl &= ~(byte.max<<7); 1052 operators[chNum].opCtrl |= val<<7; 1053 } 1054 break; 1055 case OperatorParamNums.Release: 1056 static if (is(T == uint)) { 1057 operators[chNum].rel = cast(ubyte)(val >> 25); 1058 } else static if (is(T == ubyte)) { 1059 operators[chNum].rel = val; 1060 } 1061 if (operators[chNum].rel) { 1062 operators[chNum].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].rel] * 2, sampleRate, 1063 operators[chNum].eg.sustainLevel); 1064 } else { 1065 operators[chNum].eg.releaseRate = 1.0; 1066 } 1067 break; 1068 case OperatorParamNums.ShpA: 1069 static if (is(T == uint)) { 1070 operators[chNum].shpA = cast(double)val / uint.max; 1071 } else static if (is(T == ubyte)) { 1072 if (type) 1073 paramTemp[2] = val; 1074 else 1075 paramTemp[3] = val; 1076 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1077 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1078 operators[chNum].shpA = cast(double)(val32) / cast(double)(ushort.max>>2); 1079 } else { //Set temp for next command (assume MSB-LSB order) 1080 paramNum[0] = paramTemp[0]; 1081 paramNum[1] = paramTemp[1]; 1082 } 1083 } 1084 break; 1085 case OperatorParamNums.ShpR: 1086 static if (is(T == uint)) { 1087 operators[chNum].shpR = cast(double)val / uint.max; 1088 } else static if (is(T == ubyte)) { 1089 if (type) 1090 paramTemp[2] = val; 1091 else 1092 paramTemp[3] = val; 1093 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1094 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1095 operators[chNum].shpR = cast(double)(val32) / cast(double)(ushort.max>>2); 1096 } else { //Set temp for next command (assume MSB-LSB order) 1097 paramNum[0] = paramTemp[0]; 1098 paramNum[1] = paramTemp[1]; 1099 } 1100 } 1101 break; 1102 case OperatorParamNums.SusCtrl: 1103 static if (is(T == uint)) { 1104 operators[chNum].susCC = cast(ubyte)(val >> 25); 1105 } else static if (is(T == ubyte)) { 1106 operators[chNum].susCC = val; 1107 } 1108 if (operators[chNum].susCC) { 1109 operators[chNum].eg.isPercussive = false; 1110 if (operators[chNum].susCC == 64) { 1111 operators[chNum].eg.sustainControl = 0.0; 1112 } else if (operators[chNum].susCC < 64) { 1113 operators[chNum].eg.sustainControl = -1.0 * 1114 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[operators[chNum].susCC - 1], sampleRate); 1115 } else { 1116 operators[chNum].eg.sustainControl = 1117 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[operators[chNum].susCC - 64], sampleRate); 1118 } 1119 } else { 1120 operators[chNum].eg.isPercussive = true; 1121 operators[chNum].eg.sustainControl = 0.0; 1122 } 1123 break; 1124 case OperatorParamNums.SusLevel: 1125 static if (is(T == uint)) { 1126 operators[chNum].eg.sustainLevel = cast(double)val / uint.max; 1127 } else static if (is(T == ubyte)) { 1128 if (type) 1129 paramTemp[2] = val; 1130 else 1131 paramTemp[3] = val; 1132 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1133 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1134 operators[chNum].eg.sustainLevel = cast(double)(val32) / cast(double)(ushort.max>>2); 1135 } else { //Set temp for next command (assume MSB-LSB order) 1136 paramNum[0] = paramTemp[0]; 1137 paramNum[1] = paramTemp[1]; 1138 } 1139 1140 } 1141 //Recalculate decay and release rates to new sustain levels 1142 if (operators[chNum].dec) { 1143 operators[chNum].eg.decayRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].dec] * 2, sampleRate, 1144 ADSREnvelopGenerator.maxOutput, operators[chNum].eg.sustainLevel); 1145 } else { 1146 operators[chNum].eg.decayRate = 1.0; 1147 } 1148 if (operators[chNum].rel) { 1149 operators[chNum].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].rel] * 2, sampleRate, 1150 operators[chNum].eg.sustainLevel); 1151 } else { 1152 operators[chNum].eg.releaseRate = 1.0; 1153 } 1154 break; 1155 case OperatorParamNums.TuneCor: 1156 static if (is(T == uint)) { 1157 operators[chNum].tune = val; 1158 } else static if (is(T == ubyte)) { 1159 if (type) 1160 paramTemp[2] = val; 1161 else 1162 paramTemp[3] = val; 1163 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1164 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1165 //operators[chNum].velAm = val32 / ushort.max>>2; 1166 operators[chNum].tune &= ~(uint.max<<18); 1167 operators[chNum].tune |= val32<<18; 1168 } else { //Set temp for next command (assume MSB-LSB order) 1169 paramNum[0] = paramTemp[0]; 1170 paramNum[1] = paramTemp[1]; 1171 } 1172 } 1173 break; 1174 case OperatorParamNums.TuneFine: 1175 operators[chNum].tune &= uint.max>>7; 1176 static if (is(T == uint)) { 1177 operators[chNum].tune |= val>>7; 1178 } else static if (is(T == ubyte)) { 1179 if (type) 1180 paramTemp[2] = val; 1181 else 1182 paramTemp[3] = val; 1183 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1184 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1185 operators[chNum].tune |= val32<<10 | val32>>5; 1186 } else { //Set temp for next command (assume MSB-LSB order) 1187 paramNum[0] = paramTemp[0]; 1188 paramNum[1] = paramTemp[1]; 1189 } 1190 } 1191 break; 1192 case OperatorParamNums.VelToLevel: 1193 static if (is(T == uint)) { 1194 operators[chNum].outLCtrl[0] = cast(double)val / uint.max; 1195 } else static if (is(T == ubyte)) { 1196 if (type) 1197 paramTemp[2] = val; 1198 else 1199 paramTemp[3] = val; 1200 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1201 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1202 operators[chNum].outLCtrl[0] = cast(double)(val32) / cast(double)(ushort.max>>2); 1203 } else { //Set temp for next command (assume MSB-LSB order) 1204 paramNum[0] = paramTemp[0]; 1205 paramNum[1] = paramTemp[1]; 1206 } 1207 } 1208 break; 1209 case OperatorParamNums.MWToLevel: 1210 static if (is(T == uint)) { 1211 operators[chNum].outLCtrl[1] = cast(double)val / uint.max; 1212 } else static if (is(T == ubyte)) { 1213 if (type) 1214 paramTemp[2] = val; 1215 else 1216 paramTemp[3] = val; 1217 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1218 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1219 operators[chNum].outLCtrl[1] = cast(double)(val32) / cast(double)(ushort.max>>2); 1220 } else { //Set temp for next command (assume MSB-LSB order) 1221 paramNum[0] = paramTemp[0]; 1222 paramNum[1] = paramTemp[1]; 1223 } 1224 } 1225 break; 1226 case OperatorParamNums.LFOToLevel: 1227 static if (is(T == uint)) { 1228 operators[chNum].outLCtrl[2] = cast(double)val / uint.max; 1229 } else static if (is(T == ubyte)) { 1230 if (type) 1231 paramTemp[2] = val; 1232 else 1233 paramTemp[3] = val; 1234 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1235 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1236 operators[chNum].outLCtrl[2] = cast(double)(val32) / cast(double)(ushort.max>>2); 1237 } else { //Set temp for next command (assume MSB-LSB order) 1238 paramNum[0] = paramTemp[0]; 1239 paramNum[1] = paramTemp[1]; 1240 } 1241 } 1242 break; 1243 case OperatorParamNums.VelToFB: 1244 static if (is(T == uint)) { 1245 operators[chNum].fbLCtrl[0] = cast(double)val / uint.max; 1246 } else static if (is(T == ubyte)) { 1247 if (type) 1248 paramTemp[2] = val; 1249 else 1250 paramTemp[3] = val; 1251 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1252 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1253 operators[chNum].fbLCtrl[0] = cast(double)(val32) / cast(double)(ushort.max>>2); 1254 } else { //Set temp for next command (assume MSB-LSB order) 1255 paramNum[0] = paramTemp[0]; 1256 paramNum[1] = paramTemp[1]; 1257 } 1258 } 1259 break; 1260 case OperatorParamNums.MWToFB: 1261 static if (is(T == uint)) { 1262 operators[chNum].fbLCtrl[1] = cast(double)val / uint.max; 1263 } else static if (is(T == ubyte)) { 1264 if (type) 1265 paramTemp[2] = val; 1266 else 1267 paramTemp[3] = val; 1268 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1269 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1270 operators[chNum].fbLCtrl[1] = cast(double)(val32) / cast(double)(ushort.max>>2); 1271 } else { //Set temp for next command (assume MSB-LSB order) 1272 paramNum[0] = paramTemp[0]; 1273 paramNum[1] = paramTemp[1]; 1274 } 1275 } 1276 break; 1277 case OperatorParamNums.LFOToFB: 1278 static if (is(T == uint)) { 1279 operators[chNum].fbLCtrl[2] = cast(double)val / uint.max; 1280 } else static if (is(T == ubyte)) { 1281 if (type) 1282 paramTemp[2] = val; 1283 else 1284 paramTemp[3] = val; 1285 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1286 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1287 operators[chNum].fbLCtrl[2] = cast(double)(val32) / cast(double)(ushort.max>>2); 1288 } else { //Set temp for next command (assume MSB-LSB order) 1289 paramNum[0] = paramTemp[0]; 1290 paramNum[1] = paramTemp[1]; 1291 } 1292 } 1293 break; 1294 case OperatorParamNums.EEGToFB: 1295 static if (is(T == uint)) { 1296 operators[chNum].fbLCtrl[3] = cast(double)val / uint.max; 1297 } else static if (is(T == ubyte)) { 1298 if (type) 1299 paramTemp[2] = val; 1300 else 1301 paramTemp[3] = val; 1302 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1303 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1304 operators[chNum].fbLCtrl[3] = cast(double)(val32) / cast(double)(ushort.max>>2); 1305 } else { //Set temp for next command (assume MSB-LSB order) 1306 paramNum[0] = paramTemp[0]; 1307 paramNum[1] = paramTemp[1]; 1308 } 1309 } 1310 break; 1311 case OperatorParamNums.VelToShpA: 1312 static if (is(T == uint)) { 1313 operators[chNum].shpAVel = cast(double)val / uint.max; 1314 } else static if (is(T == ubyte)) { 1315 if (type) 1316 paramTemp[2] = val; 1317 else 1318 paramTemp[3] = val; 1319 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1320 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1321 operators[chNum].shpAVel = cast(double)(val32) / cast(double)(ushort.max>>2); 1322 } else { //Set temp for next command (assume MSB-LSB order) 1323 paramNum[0] = paramTemp[0]; 1324 paramNum[1] = paramTemp[1]; 1325 } 1326 } 1327 break; 1328 case OperatorParamNums.VelToShpR: 1329 static if (is(T == uint)) { 1330 operators[chNum].shpRVel = cast(double)val / uint.max; 1331 } else static if (is(T == ubyte)) { 1332 if (type) 1333 paramTemp[2] = val; 1334 else 1335 paramTemp[3] = val; 1336 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1337 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1338 operators[chNum].shpRVel = cast(double)(val32) / cast(double)(ushort.max>>2); 1339 } else { //Set temp for next command (assume MSB-LSB order) 1340 paramNum[0] = paramTemp[0]; 1341 paramNum[1] = paramTemp[1]; 1342 } 1343 } 1344 break; 1345 case OperatorParamNums.Waveform: 1346 operators[chNum].opCtrl &= ~Operator.OpCtrlFlags.WavetableSelect; 1347 static if (is(T == uint)) { 1348 operators[chNum].opCtrl |= cast(ubyte)(val >> 25); 1349 } else static if (is(T == ubyte)) { 1350 operators[chNum].opCtrl |= val; 1351 } 1352 break; 1353 default: break; 1354 } 1355 } 1356 switch (paramNum[1]) { 1357 case 0: //Channel operator 0 1358 chNum *= 2; 1359 setOpParam(chNum); 1360 break; 1361 case 1: //Channel operator 1 1362 chNum *= 2; 1363 setOpParam(chNum + 1); 1364 break; 1365 case 2: //Channel common values 1366 switch (paramNum[0]) { 1367 //case ChannelParamNums.ALFO: break; 1368 case ChannelParamNums.Attack: 1369 static if (is(T == uint)) { 1370 channels[chNum].atkX = cast(ubyte)(val >> 25); 1371 } else static if (is(T == ubyte)) { 1372 channels[chNum].atkX = val; 1373 } 1374 if (channels[chNum].atkX) { 1375 channels[chNum].eeg.attackRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].atkX], sampleRate); 1376 } else { 1377 channels[chNum].eeg.attackRate = 1.0; 1378 } 1379 break; 1380 case ChannelParamNums.AuxSLA: 1381 static if (is(T == uint)) { 1382 const double valF = cast(double)val / uint.max; 1383 channels[chNum].outLevels[2] = valF * valF; 1384 } else static if (is(T == ubyte)) { 1385 if (type) 1386 paramTemp[2] = val; 1387 else 1388 paramTemp[3] = val; 1389 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1390 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1391 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1392 channels[chNum].outLevels[2] = valF * valF; 1393 } else { //Set temp for next command (assume MSB-LSB order) 1394 paramNum[0] = paramTemp[0]; 1395 paramNum[1] = paramTemp[1]; 1396 } 1397 } 1398 break; 1399 case ChannelParamNums.AuxSLB: 1400 static if (is(T == uint)) { 1401 const double valF = cast(double)val / uint.max; 1402 channels[chNum].outLevels[2] = valF * valF; 1403 } else static if (is(T == ubyte)) { 1404 if (type) 1405 paramTemp[2] = val; 1406 else 1407 paramTemp[3] = val; 1408 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1409 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1410 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1411 channels[chNum].outLevels[2] = valF * valF; 1412 } else { //Set temp for next command (assume MSB-LSB order) 1413 paramNum[0] = paramTemp[0]; 1414 paramNum[1] = paramTemp[1]; 1415 } 1416 } 1417 break; 1418 case ChannelParamNums.Bal: 1419 static if (is(T == uint)) { 1420 channels[chNum].masterBal = cast(double)val / uint.max; 1421 } else static if (is(T == ubyte)) { 1422 if (type) 1423 paramTemp[2] = val; 1424 else 1425 paramTemp[3] = val; 1426 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1427 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1428 channels[chNum].masterBal = cast(double)(val32) / cast(double)(ushort.max>>2); 1429 } else { //Set temp for next command (assume MSB-LSB order) 1430 paramNum[0] = paramTemp[0]; 1431 paramNum[1] = paramTemp[1]; 1432 return; 1433 } 1434 } 1435 if (channels[chNum].chCtrl & Channel.ChCtrlFlags.IndivOutChLev) { 1436 channels[chNum].outLevels[1] = channels[chNum].masterBal * channels[chNum].masterBal; 1437 } else { 1438 channels[chNum].outLevels[0] = channels[chNum].masterVol - channels[chNum].masterBal; 1439 channels[chNum].outLevels[1] = channels[chNum].masterVol - (1.0 - channels[chNum].masterBal); 1440 } 1441 break; 1442 case ChannelParamNums.ChCtrl: 1443 static if (is(T == uint)) { 1444 channels[chNum].chCtrl = val; 1445 } else static if (is(T == ubyte)) { 1446 if (type) { 1447 channels[chNum].chCtrl &= ~(byte.max<<7); 1448 channels[chNum].chCtrl |= val<<7; 1449 } else { 1450 channels[chNum].chCtrl &= ~(cast(uint)byte.max); 1451 channels[chNum].chCtrl |= val; 1452 } 1453 } 1454 //mirror operator configuration parameters between paired channels 1455 if (chNum < 8) { 1456 channels[chNum + 8].chCtrl &= ~Channel.ChCtrlFlags.ComboModeTest; 1457 channels[chNum + 8].chCtrl |= Channel.ChCtrlFlags.ComboModeTest & channels[chNum].chCtrl; 1458 } else { 1459 channels[chNum - 8].chCtrl &= ~Channel.ChCtrlFlags.ComboModeTest; 1460 channels[chNum - 8].chCtrl |= Channel.ChCtrlFlags.ComboModeTest & channels[chNum].chCtrl; 1461 } 1462 break; 1463 //case ChannelParamNums.ChCtrlL: break; 1464 case ChannelParamNums.Decay: 1465 static if (is(T == uint)) { 1466 channels[chNum].decX = cast(ubyte)(val >> 25); 1467 } else static if (is(T == ubyte)) { 1468 channels[chNum].decX = val; 1469 } 1470 if (channels[chNum].decX) { 1471 channels[chNum].eeg.decayRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].decX] * 2, sampleRate); 1472 } else { 1473 channels[chNum].eeg.decayRate = 1.0; 1474 } 1475 break; 1476 case ChannelParamNums.EEGDetune: 1477 static if (is(T == uint)) { 1478 channels[chNum].eegDetuneAm = val; 1479 } else static if (is(T == ubyte)) { 1480 if (type) 1481 paramTemp[2] = val; 1482 else 1483 paramTemp[3] = val; 1484 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1485 channels[chNum].eegDetuneAm = paramTemp[3] | paramTemp[2]<<7; 1486 } else { //Set temp for next command (assume MSB-LSB order) 1487 paramNum[0] = paramTemp[0]; 1488 paramNum[1] = paramTemp[1]; 1489 } 1490 } 1491 break; 1492 case ChannelParamNums.MasterVol: 1493 static if (is(T == uint)) { 1494 const double valF = cast(double)val / uint.max; 1495 channels[chNum].outLevels[2] = valF * valF; 1496 } else static if (is(T == ubyte)) { 1497 if (type) 1498 paramTemp[2] = val; 1499 else 1500 paramTemp[3] = val; 1501 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1502 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1503 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1504 channels[chNum].outLevels[2] = valF * valF; 1505 } else { //Set temp for next command (assume MSB-LSB order) 1506 paramNum[0] = paramTemp[0]; 1507 paramNum[1] = paramTemp[1]; 1508 } 1509 } 1510 if (channels[chNum].chCtrl & Channel.ChCtrlFlags.IndivOutChLev) { 1511 channels[chNum].outLevels[1] = channels[chNum].masterBal * channels[chNum].masterBal; 1512 } else { 1513 channels[chNum].outLevels[0] = channels[chNum].masterVol - channels[chNum].masterBal; 1514 channels[chNum].outLevels[1] = channels[chNum].masterVol - (1.0 - channels[chNum].masterBal); 1515 } 1516 break; 1517 case ChannelParamNums.PLFO: 1518 static if (is(T == uint)) { 1519 channels[chNum].pLFOlevel = cast(double)val / uint.max; 1520 } else static if (is(T == ubyte)) { 1521 if (type) 1522 paramTemp[2] = val; 1523 else 1524 paramTemp[3] = val; 1525 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1526 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1527 channels[chNum].pLFOlevel = cast(double)(val32) / cast(double)(ushort.max>>2); 1528 } else { //Set temp for next command (assume MSB-LSB order) 1529 paramNum[0] = paramTemp[0]; 1530 paramNum[1] = paramTemp[1]; 1531 } 1532 } 1533 break; 1534 case ChannelParamNums.Release: 1535 static if (is(T == uint)) { 1536 channels[chNum].relX = cast(ubyte)(val >> 25); 1537 } else static if (is(T == ubyte)) { 1538 channels[chNum].relX = val; 1539 } 1540 if (channels[chNum].relX) { 1541 channels[chNum].eeg.releaseRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].relX] * 2, sampleRate); 1542 } else { 1543 channels[chNum].eeg.releaseRate = 1.0; 1544 } 1545 break; 1546 case ChannelParamNums.ShpA: 1547 static if (is(T == uint)) { 1548 channels[chNum].shpAX = cast(double)val / uint.max; 1549 } else static if (is(T == ubyte)) { 1550 if (type) 1551 paramTemp[2] = val; 1552 else 1553 paramTemp[3] = val; 1554 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1555 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1556 channels[chNum].shpAX = cast(double)(val32) / cast(double)(ushort.max>>2); 1557 } else { //Set temp for next command (assume MSB-LSB order) 1558 paramNum[0] = paramTemp[0]; 1559 paramNum[1] = paramTemp[1]; 1560 } 1561 } 1562 break; 1563 case ChannelParamNums.ShpR: 1564 static if (is(T == uint)) { 1565 channels[chNum].shpRX = cast(double)val / uint.max; 1566 } else static if (is(T == ubyte)) { 1567 if (type) 1568 paramTemp[2] = val; 1569 else 1570 paramTemp[3] = val; 1571 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1572 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1573 channels[chNum].shpRX = cast(double)(val32) / cast(double)(ushort.max>>2); 1574 } else { //Set temp for next command (assume MSB-LSB order) 1575 paramNum[0] = paramTemp[0]; 1576 paramNum[1] = paramTemp[1]; 1577 } 1578 } 1579 break; 1580 case ChannelParamNums.SusCtrl: 1581 static if (is(T == uint)) { 1582 channels[chNum].susCCX = cast(ubyte)(val >> 25); 1583 } else static if (is(T == ubyte)) { 1584 channels[chNum].susCCX = val; 1585 } 1586 if (channels[chNum].susCCX) { 1587 channels[chNum].eeg.isPercussive = false; 1588 if (channels[chNum].susCCX == 64) { 1589 channels[chNum].eeg.sustainControl = 0.0; 1590 } else if (channels[chNum].susCCX < 64) { 1591 channels[chNum].eeg.sustainControl = -1.0 * 1592 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[channels[chNum].susCCX - 1], sampleRate); 1593 } else { 1594 channels[chNum].eeg.sustainControl = 1595 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[channels[chNum].susCCX - 64], sampleRate); 1596 } 1597 } else { 1598 channels[chNum].eeg.isPercussive = true; 1599 channels[chNum].eeg.sustainControl = 0.0; 1600 } 1601 break; 1602 case ChannelParamNums.SusLevel: 1603 static if (is(T == uint)) { 1604 channels[chNum].eeg.sustainLevel = cast(double)val / uint.max; 1605 } else static if (is(T == ubyte)) { 1606 if (type) 1607 paramTemp[2] = val; 1608 else 1609 paramTemp[3] = val; 1610 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1611 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1612 channels[chNum].eeg.sustainLevel = cast(double)(val32) / cast(double)(ushort.max>>2); 1613 } else { //Set temp for next command (assume MSB-LSB order) 1614 paramNum[0] = paramTemp[0]; 1615 paramNum[1] = paramTemp[1]; 1616 } 1617 } 1618 break; 1619 case ChannelParamNums.RingMod: 1620 static if (is(T == uint)) { 1621 channels[chNum].rmAmount = val>>16; 1622 } else static if (is(T == ubyte)) { 1623 if (type) 1624 paramTemp[2] = val; 1625 else 1626 paramTemp[3] = val; 1627 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1628 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1629 channels[chNum].eeg.sustainLevel = val32<<2 | val32>>12; 1630 } else { //Set temp for next command (assume MSB-LSB order) 1631 paramNum[0] = paramTemp[0]; 1632 paramNum[1] = paramTemp[1]; 1633 } 1634 } 1635 break; 1636 case ChannelParamNums.EEGToLeft: 1637 static if (is(T == uint)) { 1638 const double valF = cast(double)val / uint.max; 1639 channels[chNum].eegLevels[0] = valF * valF; 1640 } else static if (is(T == ubyte)) { 1641 if (type) 1642 paramTemp[2] = val; 1643 else 1644 paramTemp[3] = val; 1645 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1646 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1647 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1648 channels[chNum].eegLevels[0] = valF * valF; 1649 } else { //Set temp for next command (assume MSB-LSB order) 1650 paramNum[0] = paramTemp[0]; 1651 paramNum[1] = paramTemp[1]; 1652 } 1653 } 1654 break; 1655 case ChannelParamNums.EEGToRight: 1656 static if (is(T == uint)) { 1657 const double valF = cast(double)val / uint.max; 1658 channels[chNum].eegLevels[1] = valF * valF; 1659 } else static if (is(T == ubyte)) { 1660 if (type) 1661 paramTemp[2] = val; 1662 else 1663 paramTemp[3] = val; 1664 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1665 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1666 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1667 channels[chNum].eegLevels[1] = valF * valF; 1668 } else { //Set temp for next command (assume MSB-LSB order) 1669 paramNum[0] = paramTemp[0]; 1670 paramNum[1] = paramTemp[1]; 1671 } 1672 } 1673 break; 1674 case ChannelParamNums.EEGToAuxA: 1675 static if (is(T == uint)) { 1676 const double valF = cast(double)val / uint.max; 1677 channels[chNum].eegLevels[2] = valF * valF; 1678 } else static if (is(T == ubyte)) { 1679 if (type) 1680 paramTemp[2] = val; 1681 else 1682 paramTemp[3] = val; 1683 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1684 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1685 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1686 channels[chNum].eegLevels[2] = valF * valF; 1687 } else { //Set temp for next command (assume MSB-LSB order) 1688 paramNum[0] = paramTemp[0]; 1689 paramNum[1] = paramTemp[1]; 1690 } 1691 } 1692 break; 1693 case ChannelParamNums.EEGToAuxB: 1694 static if (is(T == uint)) { 1695 const double valF = cast(double)val / uint.max; 1696 channels[chNum].eegLevels[3] = valF * valF; 1697 } else static if (is(T == ubyte)) { 1698 if (type) 1699 paramTemp[2] = val; 1700 else 1701 paramTemp[3] = val; 1702 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1703 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1704 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1705 channels[chNum].eegLevels[3] = valF * valF; 1706 } else { //Set temp for next command (assume MSB-LSB order) 1707 paramNum[0] = paramTemp[0]; 1708 paramNum[1] = paramTemp[1]; 1709 } 1710 } 1711 break; 1712 case ChannelParamNums.LFOToLeft: 1713 static if (is(T == uint)) { 1714 const double valF = cast(double)val / uint.max; 1715 channels[chNum].aLFOlevels[0] = valF * valF; 1716 } else static if (is(T == ubyte)) { 1717 if (type) 1718 paramTemp[2] = val; 1719 else 1720 paramTemp[3] = val; 1721 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1722 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1723 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1724 channels[chNum].aLFOlevels[0] = valF * valF; 1725 } else { //Set temp for next command (assume MSB-LSB order) 1726 paramNum[0] = paramTemp[0]; 1727 paramNum[1] = paramTemp[1]; 1728 } 1729 } 1730 break; 1731 case ChannelParamNums.LFOToRight: 1732 static if (is(T == uint)) { 1733 const double valF = cast(double)val / uint.max; 1734 channels[chNum].aLFOlevels[1] = valF * valF; 1735 } else static if (is(T == ubyte)) { 1736 if (type) 1737 paramTemp[2] = val; 1738 else 1739 paramTemp[3] = val; 1740 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1741 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1742 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1743 channels[chNum].aLFOlevels[1] = valF * valF; 1744 } else { //Set temp for next command (assume MSB-LSB order) 1745 paramNum[0] = paramTemp[0]; 1746 paramNum[1] = paramTemp[1]; 1747 } 1748 } 1749 break; 1750 case ChannelParamNums.LFOToAuxA: 1751 static if (is(T == uint)) { 1752 const double valF = cast(double)val / uint.max; 1753 channels[chNum].aLFOlevels[2] = valF * valF; 1754 } else static if (is(T == ubyte)) { 1755 if (type) 1756 paramTemp[2] = val; 1757 else 1758 paramTemp[3] = val; 1759 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1760 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1761 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1762 channels[chNum].aLFOlevels[2] = valF * valF; 1763 } else { //Set temp for next command (assume MSB-LSB order) 1764 paramNum[0] = paramTemp[0]; 1765 paramNum[1] = paramTemp[1]; 1766 } 1767 } 1768 break; 1769 case ChannelParamNums.LFOToAuxB: 1770 static if (is(T == uint)) { 1771 const double valF = cast(double)val / uint.max; 1772 channels[chNum].aLFOlevels[3] = valF * valF; 1773 } else static if (is(T == ubyte)) { 1774 if (type) 1775 paramTemp[2] = val; 1776 else 1777 paramTemp[3] = val; 1778 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1779 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1780 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1781 channels[chNum].aLFOlevels[3] = valF * valF; 1782 } else { //Set temp for next command (assume MSB-LSB order) 1783 paramNum[0] = paramTemp[0]; 1784 paramNum[1] = paramTemp[1]; 1785 } 1786 } 1787 break; 1788 default: 1789 break; 1790 } 1791 break; 1792 case 16: //LFO and master filter settings 1793 void setFilterFreq(int num) @nogc @safe pure nothrow { 1794 static if (is(T == uint)) { 1795 const double valF = cast(double)val / uint.max; 1796 filterCtrl[num] = valF * valF * 22_000; 1797 } else static if (is(T == ubyte)) { 1798 if (type) 1799 paramTemp[2] = val; 1800 else 1801 paramTemp[3] = val; 1802 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1803 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1804 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1805 filterCtrl[num] = valF * valF * 22_000; 1806 } else { //Set temp for next command (assume MSB-LSB order) 1807 paramNum[0] = paramTemp[0]; 1808 paramNum[1] = paramTemp[1]; 1809 } 1810 } 1811 } 1812 void setFilterQ(int num) @nogc @safe pure nothrow { 1813 static if (is(T == uint)) { 1814 const double valF = cast(double)val / uint.max; 1815 filterCtrl[num] = valF * 2; 1816 } else static if (is(T == ubyte)) { 1817 if (type) 1818 paramTemp[2] = val; 1819 else 1820 paramTemp[3] = val; 1821 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1822 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1823 const double valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1824 filterCtrl[num] = valF * 2; 1825 } else { //Set temp for next command (assume MSB-LSB order) 1826 paramNum[0] = paramTemp[0]; 1827 paramNum[1] = paramTemp[1]; 1828 } 1829 } 1830 } 1831 switch (paramNum[0]) { 1832 case GlobalParamNums.PLFORate: 1833 double valF; 1834 static if (is(T == uint)) { 1835 valF = cast(double)val / uint.max; 1836 } else static if (is(T == ubyte)) { 1837 if (type) 1838 paramTemp[2] = val; 1839 else 1840 paramTemp[3] = val; 1841 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1842 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1843 valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1844 } else { //Set temp for next command (assume MSB-LSB order) 1845 paramNum[0] = paramTemp[0]; 1846 paramNum[1] = paramTemp[1]; 1847 return; 1848 } 1849 } 1850 valF *= 16; 1851 const double cycleLen = sampleRate / (1.0 / valF); 1852 pLFORate = cast(int)(cycleLen * ((1<<20) / 1024.0) * bufferSize); 1853 break; 1854 case GlobalParamNums.PLFOWF: 1855 static if (is(T == uint)) { 1856 lfoWaveform[0] = cast(ubyte)(val >> 25); 1857 } else static if (is(T == ubyte)) { 1858 lfoWaveform[0] = val; 1859 } 1860 break; 1861 case GlobalParamNums.ALFORate: 1862 double valF; 1863 static if (is(T == uint)) { 1864 valF = cast(double)val / uint.max; 1865 } else static if (is(T == ubyte)) { 1866 if (type) 1867 paramTemp[2] = val; 1868 else 1869 paramTemp[3] = val; 1870 if (paramNum[0] == paramTemp[0] && paramNum[1] == paramTemp[1]) { //Set parameter if found. 1871 const uint val32 = paramTemp[3] | paramTemp[2]<<7; 1872 valF = cast(double)(val32) / cast(double)(ushort.max>>2); 1873 } else { //Set temp for next command (assume MSB-LSB order) 1874 paramNum[0] = paramTemp[0]; 1875 paramNum[1] = paramTemp[1]; 1876 return; 1877 } 1878 } 1879 valF *= 16; 1880 const double cycleLen = sampleRate / (1.0 / valF); 1881 aLFORate = cast(int)(cycleLen * ((1<<20) / 1024.0)); 1882 break; 1883 case GlobalParamNums.ALFOWF: 1884 static if (is(T == uint)) { 1885 lfoWaveform[1] = cast(ubyte)(val >> 25); 1886 } else static if (is(T == ubyte)) { 1887 lfoWaveform[1] = val; 1888 } 1889 break; 1890 case GlobalParamNums.FilterLCFreq: 1891 setFilterFreq(0); 1892 break; 1893 case GlobalParamNums.FilterLCQ: 1894 setFilterQ(1); 1895 break; 1896 case GlobalParamNums.FilterRCFreq: 1897 setFilterFreq(2); 1898 break; 1899 case GlobalParamNums.FilterRCQ: 1900 setFilterQ(3); 1901 break; 1902 case GlobalParamNums.FilterACFreq: 1903 setFilterFreq(4); 1904 break; 1905 case GlobalParamNums.FilterACQ: 1906 setFilterQ(5); 1907 break; 1908 case GlobalParamNums.FilterBCFreq: 1909 setFilterFreq(6); 1910 break; 1911 case GlobalParamNums.FilterBCQ: 1912 setFilterQ(7); 1913 break; 1914 default: 1915 break; 1916 } 1917 break; 1918 default: break; 1919 } 1920 } 1921 /** 1922 * Renders the current audio frame. 1923 * 1924 * input: the input buffers if any, null if none. 1925 * output: the output buffers if any, null if none. 1926 * length: the lenth of the current audio frame in samples. 1927 * 1928 * NOTE: Buffers must have matching sizes. 1929 */ 1930 public override void renderFrame(float*[] input, float*[] output) @nogc nothrow { 1931 //Generate aLFO table 1932 for (int i ; i < bufferSize ; i++) { 1933 aLFOBuf[i] = (wavetables[lfoWaveform[1]][(aLFOPos>>20) & 1023] - short.min) * (1 / cast(float)(ushort.max)); 1934 aLFOPos += aLFORate; 1935 } 1936 //Generate pLFO out 1937 { 1938 pLFOOut = (wavetables[lfoWaveform[0]][(pLFOPos>>20) & 1023]) * (1 / cast(float)(short.max)); 1939 pLFOPos += pLFORate; 1940 } 1941 //Render each channel 1942 foreach (size_t i, ChFun fun ; chDeleg) { 1943 fun(cast(int)i, bufferSize); 1944 } 1945 //Filter and mix outputs 1946 float*[4] outBuf; 1947 for (ubyte i, j ; i < 4 ; i++) { 1948 if (enabledOutputs.has(i)) { 1949 outBuf[i] = output[j]; 1950 j++; 1951 } else { 1952 outBuf[i] = dummyBuf.ptr; 1953 } 1954 } 1955 const __m128 b0_a0 = filterVals[3] / filterVals[0], b1_a0 = filterVals[4] / filterVals[0], 1956 b2_a0 = filterVals[5] / filterVals[0], a1_a0 = filterVals[1] / filterVals[0], a2_a0 = filterVals[2] / filterVals[0]; 1957 for (int i ; i < bufferSize ; i++) { 1958 __m128 input0 = _mm_load_ps(initBuffers.ptr + i); 1959 input0 *= __m128(mixdownVal); 1960 input0 = _mm_max_ps(input0, __m128(-1.0)); 1961 input0 = _mm_min_ps(input0, __m128(1.0)); 1962 __m128 output0 = b0_a0 * input0 + b1_a0 * filterVals[6] + b2_a0 * filterVals[7] - a1_a0 * filterVals[8] - 1963 a2_a0 * filterVals[9]; 1964 for (int j ; j < 4 ; j++) 1965 outBuf[j][i] += output0[j]; 1966 filterVals[7] = filterVals[6]; 1967 filterVals[6] = input0; 1968 filterVals[9] = filterVals[8]; 1969 filterVals[8] = output0; 1970 } 1971 } 1972 ///Updates an operator for a cycle 1973 ///chCtrl index notation: 0: velocity, 1: modulation wheel, 2: Amplitude LFO, 3: Extra Envelop Generator 1974 pragma(inline, true) 1975 protected final void updateOperator(ref Operator op, __m128 chCtrl) @nogc @safe pure nothrow { 1976 op.output = wavetables[op.opCtrl & Operator.OpCtrlFlags.WavetableSelect][(op.pos>>20 + op.input>>4 + op.feedback>>3) 1977 & 0x3_FF]; 1978 const double egOut = op.eg.shp(op.eg.position == ADSREnvelopGenerator.Stage.Attack ? op.shpA0 : op.shpR0); 1979 const double out0 = op.output; 1980 __m128 outCtrl = (op.outLCtrl * chCtrl) + (__m128(1.0) - (__m128(1.0) * op.outLCtrl)); 1981 __m128 fbCtrl = (op.fbLCtrl * chCtrl) + (__m128(1.0) - (__m128(1.0) * op.fbLCtrl)); 1982 const double out1 = out0 * egOut; 1983 //vel = op.opCtrl & Operator.OpCtrlFlags.VelNegative ? 1.0 - vel : vel; 1984 op.feedback = cast(int)((op.opCtrl & Operator.OpCtrlFlags.FBMode ? out0 : out1) * op.fbL * fbCtrl[0] * fbCtrl[1] * 1985 fbCtrl[2] * fbCtrl[3]); 1986 //op.feedback *= op.opCtrl & Operator.OpCtrlFlags.FBNeg ? -1 : 1; 1987 op.output_0 = cast(int)(out1 * op.outL * outCtrl[0] * outCtrl[1] * outCtrl[2]); 1988 op.pos += op.step; 1989 //op.input = 0; 1990 op.eg.advance(); 1991 } 1992 ///Macro for channel update constants that need to be calculated once per frame 1993 ///Kept in at one place to make updates easier and more consistent 1994 static immutable string CHNL_UPDATE_CONSTS = 1995 `const int opOffset = chNum * 2;` ~ 1996 `__m128 aLFOOutMW = __m128(channels[chNum].chCtrl & Channel.ChCtrlFlags.MWToTrem ? chCtrls[chNum].modwheel : 1.0);` ~ 1997 `const float auxSendAmMW = (channels[chNum].chCtrl & Channel.ChCtrlFlags.MWToAux ? chCtrls[chNum].modwheel : 1.0);` ~ 1998 `__m128 opCtrl0, opCtrl1, mwAuxCtrl;` ~ 1999 `opCtrl0[0] = operators[opOffset].opCtrl & Operator.OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : ` ~ 2000 `chCtrls[chNum].velocity;` ~ 2001 `opCtrl1[0] = operators[opOffset + 1].opCtrl & Operator.OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : ` ~ 2002 `chCtrls[chNum].velocity;` ~ 2003 `opCtrl0[1] = operators[opOffset].opCtrl & Operator.OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : ` ~ 2004 `chCtrls[chNum].modwheel;` ~ 2005 `opCtrl1[1] = operators[opOffset + 1].opCtrl & Operator.OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : ` ~ 2006 `chCtrls[chNum].modwheel;` ~ 2007 `mwAuxCtrl[0] = 1.0;` ~ 2008 `mwAuxCtrl[1] = 1.0;` ~ 2009 `mwAuxCtrl[2] = auxSendAmMW;` ~ 2010 `mwAuxCtrl[3] = auxSendAmMW;` ~ 2011 `const float lfopan = (channels[chNum].chCtrl & Channel.ChCtrlFlags.LFOPan ? 1.0 : 0);` ~ 2012 `const float eegpan = (channels[chNum].chCtrl & Channel.ChCtrlFlags.EEGPan ? 1.0 : 0);` 2013 ; 2014 ///Macro for channel update constants that need to be calculated once per frame, for combined channels' second half 2015 ///Kept in at one place to make updates easier and more consistent 2016 static immutable string CHNL_UPDATE_CONSTS0 = 2017 `__m128 opCtrl2, opCtrl3;` ~ 2018 `opCtrl2[0] = operators[opOffset + 16].opCtrl & Operator.OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : ` ~ 2019 `chCtrls[chNum].velocity;` ~ 2020 `opCtrl3[0] = operators[opOffset + 17].opCtrl & Operator.OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : ` ~ 2021 `chCtrls[chNum].velocity;` ~ 2022 `opCtrl2[1] = operators[opOffset + 16].opCtrl & Operator.OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : ` ~ 2023 `chCtrls[chNum].modwheel;` ~ 2024 `opCtrl3[1] = operators[opOffset + 17].opCtrl & Operator.OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : ` ~ 2025 `chCtrls[chNum].modwheel;` ~ 2026 `const float eegpan0 = (channels[chNum + 8].chCtrl & Channel.ChCtrlFlags.EEGPan ? 1.0 : 0);` 2027 ; 2028 ///Macro for channel update constants that need to be calculated for each cycle 2029 ///Kept in at one place to make updates easier and more consistent 2030 static immutable string CHNL_UPDATE_CONSTS_CYCL = 2031 `const float eegOut = channels[chNum].eeg.shp(channels[chNum].eeg.position == ADSREnvelopGenerator.Stage.Attack ? ` ~ 2032 `channels[chNum].shpAX : channels[chNum].shpRX);` ~ 2033 `__m128 eegToMast = __m128(eegOut), lfoToMast = __m128(aLFOBuf[i]);` ~ 2034 `eegToMast[0] = abs(eegpan - eegToMast[0]);` ~ 2035 `lfoToMast[0] = abs(lfopan - lfoToMast[0]);` ~ 2036 `opCtrl0[2] = aLFOBuf[i];` ~ 2037 `opCtrl1[2] = aLFOBuf[i];` ~ 2038 `opCtrl0[3] = eegOut;` ~ 2039 `opCtrl1[3] = eegOut;` 2040 ; 2041 2042 ///Macro for channel update constants that need to be calculated for each cycle for combined channels' second half 2043 ///Kept in at one place to make updates easier and more consistent 2044 static immutable string CHNL_UPDATE_CONSTS_CYCL0 = 2045 `const float eegOut0 = channels[chNum + 8].eeg.shp(channels[chNum + 8].eeg.position == ` ~ 2046 `ADSREnvelopGenerator.Stage.Attack ? channels[chNum + 8].shpAX : channels[chNum + 8].shpRX);` ~ 2047 `__m128 eegToMast0 = __m128(eegOut0);` ~ 2048 `eegToMast0[0] = abs(eegpan0 - eegToMast0[0]);` ~ 2049 `opCtrl2[2] = aLFOBuf[i];` ~ 2050 `opCtrl3[2] = aLFOBuf[i];` ~ 2051 `opCtrl2[3] = eegOut0;` ~ 2052 `opCtrl3[3] = eegOut0;` 2053 ; 2054 2055 ///Macro for output mixing 2056 static immutable string CHNL_UPDATE_MIX = 2057 "__m128 outlevels = channels[chNum].outLevels * mwAuxCtrl;" ~ 2058 "outlevels *= (channels[chNum].eegLevels * eegToMast) + (__m128(1.0) - (__m128(1.0) * channels[chNum].eegLevels));" ~ 2059 "outlevels *= (channels[chNum].aLFOlevels * lfoToMast) + (__m128(1.0) - (__m128(1.0) * channels[chNum].aLFOlevels));"~ 2060 "_mm_store1_ps(initBuffers.ptr + (i<<2), _mm_load_ps(initBuffers.ptr + (i<<2)) + outlevels *" ~ 2061 " _mm_cvtepi32_ps(outSum));" 2062 ; 2063 ///Macro for output mixing in case of combo modes 2064 static immutable string CHNL_UPDATE_MIX0 = 2065 "__m128 outlevels = channels[chNum].outLevels * mwAuxCtrl;" ~ 2066 "outlevels *= (channels[chNum].eegLevels * eegToMast) + (__m128(1.0) - (__m128(1.0) * channels[chNum].eegLevels));" ~ 2067 "outlevels *= (channels[chNum + 8].eegLevels * eegToMast0) + (__m128(1.0) - " ~ 2068 " (__m128(1.0) * channels[chNum + 8].eegLevels));" ~ 2069 "outlevels *= (channels[chNum].aLFOlevels * lfoToMast) + (__m128(1.0) - (__m128(1.0) * channels[chNum].aLFOlevels));"~ 2070 "_mm_store1_ps(initBuffers.ptr + (i<<2), _mm_load_ps(initBuffers.ptr + (i<<2)) + outlevels *" ~ 2071 " _mm_cvtepi32_ps(outSum));" 2072 ; 2073 2074 2075 ///Algorithm Mode 0/0 (Serial) 2076 protected void updateChannelM00(int chNum, size_t length) @nogc pure nothrow { 2077 mixin(CHNL_UPDATE_CONSTS); 2078 for (size_t i ; i < length ; i++) { 2079 mixin(CHNL_UPDATE_CONSTS_CYCL); 2080 updateOperator(operators[opOffset], opCtrl0); 2081 operators[opOffset + 1].input = operators[opOffset].output_0; 2082 updateOperator(operators[opOffset + 1], opCtrl1); 2083 //const int outSum = operators[opOffset].output_0; 2084 __m128i outSum = __m128i(operators[opOffset + 1].output_0); 2085 mixin(CHNL_UPDATE_MIX); 2086 channels[chNum].eeg.advance(); 2087 } 2088 } 2089 ///Algorithm Mode0/1 (Parallel) 2090 protected void updateChannelM01(int chNum, size_t length) @nogc pure nothrow { 2091 mixin(CHNL_UPDATE_CONSTS); 2092 for (size_t i ; i < length ; i++) { 2093 mixin(CHNL_UPDATE_CONSTS_CYCL); 2094 updateOperator(operators[opOffset], opCtrl0); 2095 updateOperator(operators[opOffset + 1], opCtrl1); 2096 //const int outSum = operators[opOffset].output_0 + operators[opOffset + 1].output_0; 2097 __m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 2098 ((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].rmAmount)>>16); 2099 mixin(CHNL_UPDATE_MIX); 2100 channels[chNum].eeg.advance(); 2101 } 2102 } 2103 ///Algorithm Mode1/00 ([S0]->[S1]->[P0]->[P1]) 2104 protected void updateChannelM100(int chNum, size_t length) @nogc pure nothrow { 2105 mixin(CHNL_UPDATE_CONSTS); 2106 mixin(CHNL_UPDATE_CONSTS0); 2107 for (size_t i ; i < length ; i++) { 2108 mixin(CHNL_UPDATE_CONSTS_CYCL); 2109 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2110 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2111 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2112 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2113 operators[opOffset].input = operators[opOffset + 17].output_0; 2114 updateOperator(operators[opOffset], opCtrl0); //P0 2115 operators[opOffset + 1].input = operators[opOffset].output_0; 2116 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2117 //const int outSum = operators[opOffset + 1].output_0; 2118 __m128i outSum = __m128i(operators[opOffset + 1].output_0); 2119 mixin(CHNL_UPDATE_MIX); 2120 channels[chNum].eeg.advance(); 2121 channels[chNum + 8].eeg.advance(); 2122 } 2123 } 2124 ///Dummy algorithm for combined channels 2125 protected void updateChannelMD(int chNum, size_t length) @nogc pure nothrow { 2126 2127 } 2128 /** 2129 Algorithm Mode1/10 2130 [S0]\ 2131 ->[P0]->[P1]-> 2132 [S1]/ 2133 */ 2134 protected void updateChannelM110(int chNum, size_t length) @nogc pure nothrow { 2135 mixin(CHNL_UPDATE_CONSTS); 2136 mixin(CHNL_UPDATE_CONSTS0); 2137 for (size_t i ; i < length ; i++) { 2138 mixin(CHNL_UPDATE_CONSTS_CYCL); 2139 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2140 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2141 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2142 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2143 operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0; 2144 updateOperator(operators[opOffset], opCtrl0); //P0 2145 operators[opOffset + 1].input = operators[opOffset].output_0; 2146 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2147 //const int outSum = operators[opOffset + 1].output_0; 2148 __m128i outSum = __m128i(operators[opOffset + 1].output_0); 2149 mixin(CHNL_UPDATE_MIX); 2150 channels[chNum].eeg.advance(); 2151 channels[chNum + 8].eeg.advance(); 2152 } 2153 } 2154 /** 2155 Algorithm Mode1/01 2156 [S0]->[S1]->[P0]-> 2157 [P1]-> 2158 */ 2159 protected void updateChannelM101(int chNum, size_t length) @nogc pure nothrow { 2160 mixin(CHNL_UPDATE_CONSTS); 2161 mixin(CHNL_UPDATE_CONSTS0); 2162 for (size_t i ; i < length ; i++) { 2163 mixin(CHNL_UPDATE_CONSTS_CYCL); 2164 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2165 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2166 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2167 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2168 operators[opOffset].input = operators[opOffset + 17].output_0; 2169 updateOperator(operators[opOffset], opCtrl0); //P0 2170 //operators[opOffset + 1].input = operators[opOffset].output_0; 2171 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2172 //const int outSum = operators[opOffset + 1].output_0; 2173 __m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 2174 ((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].rmAmount)>>16); 2175 mixin(CHNL_UPDATE_MIX); 2176 channels[chNum].eeg.advance(); 2177 channels[chNum + 8].eeg.advance(); 2178 } 2179 } 2180 /** 2181 Algorithm Mode1/11 2182 [S0]\ 2183 ->[P0]-> 2184 [S1]/ [P1]-> 2185 */ 2186 protected void updateChannelM111(int chNum, size_t length) @nogc pure nothrow { 2187 mixin(CHNL_UPDATE_CONSTS); 2188 mixin(CHNL_UPDATE_CONSTS0); 2189 for (size_t i ; i < length ; i++) { 2190 mixin(CHNL_UPDATE_CONSTS_CYCL); 2191 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2192 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2193 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2194 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2195 operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0; 2196 updateOperator(operators[opOffset], opCtrl0); //P0 2197 //operators[opOffset + 1].input = operators[opOffset].output_0; 2198 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2199 //const int outSum = operators[opOffset + 1].output_0; 2200 __m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 2201 ((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].rmAmount)>>16); 2202 mixin(CHNL_UPDATE_MIX); 2203 channels[chNum].eeg.advance(); 2204 channels[chNum + 8].eeg.advance(); 2205 } 2206 } 2207 /** 2208 Algorithm Mode2/00 2209 [S0]->[S1]\ 2210 ->[P1]-> 2211 [P0]/ 2212 */ 2213 protected void updateChannelM200(int chNum, size_t length) @nogc pure nothrow { 2214 mixin(CHNL_UPDATE_CONSTS); 2215 mixin(CHNL_UPDATE_CONSTS0); 2216 for (size_t i ; i < length ; i++) { 2217 mixin(CHNL_UPDATE_CONSTS_CYCL); 2218 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2219 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2220 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2221 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2222 //operators[opOffset].input = operators[opOffset + 17].output_0; 2223 updateOperator(operators[opOffset], opCtrl0); //P0 2224 operators[opOffset + 1].input = operators[opOffset].output_0 + operators[opOffset + 17].output_0; 2225 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2226 //const int outSum = operators[opOffset + 1].output_0; 2227 __m128i outSum = __m128i(operators[opOffset + 1].output_0); 2228 mixin(CHNL_UPDATE_MIX); 2229 channels[chNum].eeg.advance(); 2230 channels[chNum + 8].eeg.advance(); 2231 } 2232 } 2233 /** 2234 Algorithm Mode2/10 2235 [S0]\ 2236 [S1]-->[P1]-> 2237 [P0]/ 2238 */ 2239 protected void updateChannelM210(int chNum, size_t length) @nogc pure nothrow { 2240 mixin(CHNL_UPDATE_CONSTS); 2241 mixin(CHNL_UPDATE_CONSTS0); 2242 for (size_t i ; i < length ; i++) { 2243 mixin(CHNL_UPDATE_CONSTS_CYCL); 2244 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2245 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2246 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2247 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2248 //operators[opOffset].input = operators[opOffset + 17].output_0; 2249 updateOperator(operators[opOffset], opCtrl0); //P0 2250 operators[opOffset + 1].input = operators[opOffset].output_0 + operators[opOffset + 17].output_0 + 2251 operators[opOffset + 16].output_0; 2252 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2253 //const int outSum = operators[opOffset + 1].output_0; 2254 __m128i outSum = __m128i(operators[opOffset + 1].output_0); 2255 mixin(CHNL_UPDATE_MIX); 2256 channels[chNum].eeg.advance(); 2257 channels[chNum + 8].eeg.advance(); 2258 } 2259 } 2260 /** 2261 Algorithm Mode2/01 2262 /[P0]-> 2263 [S0]->[S1] 2264 \[P1]-> 2265 */ 2266 protected void updateChannelM201(int chNum, size_t length) @nogc pure nothrow { 2267 mixin(CHNL_UPDATE_CONSTS); 2268 mixin(CHNL_UPDATE_CONSTS0); 2269 for (size_t i ; i < length ; i++) { 2270 mixin(CHNL_UPDATE_CONSTS_CYCL); 2271 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2272 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2273 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2274 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2275 operators[opOffset].input = operators[opOffset + 17].output_0; 2276 updateOperator(operators[opOffset], opCtrl0); //P0 2277 operators[opOffset + 1].input = operators[opOffset + 17].output_0; 2278 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2279 //const int outSum = operators[opOffset + 1].output_0; 2280 __m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset].output_0 + 2281 ((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].rmAmount)>>16); 2282 mixin(CHNL_UPDATE_MIX); 2283 channels[chNum].eeg.advance(); 2284 channels[chNum + 8].eeg.advance(); 2285 } 2286 } 2287 /** 2288 Algorithm Mode2/11 2289 [S0]\ /[P0]-> 2290 - 2291 [S1]/ \[P1]-> 2292 */ 2293 protected void updateChannelM211(int chNum, size_t length) @nogc pure nothrow { 2294 mixin(CHNL_UPDATE_CONSTS); 2295 mixin(CHNL_UPDATE_CONSTS0); 2296 for (size_t i ; i < length ; i++) { 2297 mixin(CHNL_UPDATE_CONSTS_CYCL); 2298 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2299 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2300 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2301 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2302 operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0; 2303 updateOperator(operators[opOffset], opCtrl0); //P0 2304 operators[opOffset + 1].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0; 2305 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2306 //const int outSum = operators[opOffset + 1].output_0; 2307 __m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset].output_0 + 2308 ((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].rmAmount)>>16); 2309 mixin(CHNL_UPDATE_MIX); 2310 channels[chNum].eeg.advance(); 2311 channels[chNum + 8].eeg.advance(); 2312 } 2313 } 2314 /** 2315 Algorithm Mode3/00 2316 [S0]->[S1]-> 2317 [P0]->[P1]-> 2318 */ 2319 protected void updateChannelM300(int chNum, size_t length) @nogc pure nothrow { 2320 mixin(CHNL_UPDATE_CONSTS); 2321 mixin(CHNL_UPDATE_CONSTS0); 2322 for (size_t i ; i < length ; i++) { 2323 mixin(CHNL_UPDATE_CONSTS_CYCL); 2324 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2325 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2326 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2327 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2328 //operators[opOffset].input = operators[opOffset + 17].output_0; 2329 updateOperator(operators[opOffset], opCtrl0); //P0 2330 operators[opOffset + 1].input = operators[opOffset].output_0; 2331 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2332 //const int outSum = operators[opOffset + 1].output_0; 2333 __m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset + 17].output_0 + 2334 ((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].rmAmount)>>16); 2335 mixin(CHNL_UPDATE_MIX); 2336 channels[chNum].eeg.advance(); 2337 channels[chNum + 8].eeg.advance(); 2338 } 2339 } 2340 /** 2341 Algorithm Mode3/10 2342 [S0]-> 2343 [S1]-> 2344 [P0]->[P1]-> 2345 */ 2346 protected void updateChannelM310(int chNum, size_t length) @nogc pure nothrow { 2347 mixin(CHNL_UPDATE_CONSTS); 2348 mixin(CHNL_UPDATE_CONSTS0); 2349 for (size_t i ; i < length ; i++) { 2350 mixin(CHNL_UPDATE_CONSTS_CYCL); 2351 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2352 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2353 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2354 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2355 //operators[opOffset].input = operators[opOffset + 17].output_0; 2356 updateOperator(operators[opOffset], opCtrl0); //P0 2357 operators[opOffset + 1].input = operators[opOffset].output_0; 2358 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2359 //const int outSum = operators[opOffset + 1].output_0; 2360 __m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset + 17].output_0 + 2361 operators[opOffset + 16].output_0 + 2362 ((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].rmAmount)>>16); 2363 mixin(CHNL_UPDATE_MIX); 2364 channels[chNum].eeg.advance(); 2365 channels[chNum + 8].eeg.advance(); 2366 } 2367 } 2368 /** 2369 Algorithm Mode3/01 2370 />[S1]-> 2371 [S0]->[P0]-> 2372 \>[P1]-> 2373 */ 2374 protected void updateChannelM301(int chNum, size_t length) @nogc pure nothrow { 2375 mixin(CHNL_UPDATE_CONSTS); 2376 mixin(CHNL_UPDATE_CONSTS0); 2377 for (size_t i ; i < length ; i++) { 2378 mixin(CHNL_UPDATE_CONSTS_CYCL); 2379 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2380 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2381 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2382 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2383 operators[opOffset].input = operators[opOffset + 16].output_0; 2384 updateOperator(operators[opOffset], opCtrl0); //P0 2385 operators[opOffset + 1].input = operators[opOffset + 16].output_0; 2386 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2387 //const int outSum = operators[opOffset + 1].output_0; 2388 __m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 2389 operators[opOffset + 17].output_0 + 2390 ((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].rmAmount)>>16); 2391 mixin(CHNL_UPDATE_MIX); 2392 channels[chNum].eeg.advance(); 2393 channels[chNum + 8].eeg.advance(); 2394 } 2395 } 2396 /** 2397 Algorithm Mode3/11 2398 [S0]-> 2399 [S1]-> 2400 [P0]-> 2401 [P1]-> 2402 */ 2403 protected void updateChannelM311(int chNum, size_t length) @nogc pure nothrow { 2404 mixin(CHNL_UPDATE_CONSTS); 2405 mixin(CHNL_UPDATE_CONSTS0); 2406 for (size_t i ; i < length ; i++) { 2407 mixin(CHNL_UPDATE_CONSTS_CYCL); 2408 mixin(CHNL_UPDATE_CONSTS_CYCL0); 2409 updateOperator(operators[opOffset + 16], opCtrl2); //S0 2410 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 2411 updateOperator(operators[opOffset + 17], opCtrl3); //S1 2412 //operators[opOffset].input = operators[opOffset + 17].output_0; 2413 updateOperator(operators[opOffset], opCtrl0); //P0 2414 //operators[opOffset + 1].input = operators[opOffset].output_0; 2415 updateOperator(operators[opOffset + 1], opCtrl1); //P1 2416 //const int outSum = operators[opOffset + 1].output_0; 2417 __m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset].output_0 + 2418 operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0 + 2419 ((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].rmAmount)>>16); 2420 mixin(CHNL_UPDATE_MIX); 2421 channels[chNum].eeg.advance(); 2422 channels[chNum + 8].eeg.advance(); 2423 } 2424 } 2425 }