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 bitleveld.reinterpret; 13 14 import std.math; 15 16 /** 17 QM816 - implements a Quadrature-Amplitude synthesizer. This technique was used in early 18 digital FM synths, since it allowed allowed a cheap implementation of the same thing as 19 long as the modulator was a sinusoidal waveform. 20 21 It has 16 2 operator channels that can be individually paired-up for 4 operator channels, 22 for more complex sounds. Also all operators have the option for feedback, including 23 carriers. 2 operator channels have 2, 4 operator channels have 3*4 algorithms. 24 25 The audiomodule generates a few default waveforms upon startup, but further ones can be 26 supplied from files, or generated by code. Some waveform generation code is already 27 supplied with the synth's code. 28 */ 29 public class QM816 : AudioModule { 30 shared static this() { 31 for (int i ; i < 256 ; i++) { 32 SINEWAVE_FRAGMENT[i] = cast(short)(sin((PI_2 / 256) * i) * short.max); 33 } 34 } 35 /** 36 Generates a waveform from a sinewave fragment (quarter). 37 38 q flags: 39 bit 0 = If set, then the sine fragment is present. If not, this portion will be replaced with all zeros instead. 40 bit 1-2 = Doubling mode: 41 0 = No doubling. 42 1 = Same cycle twice. 43 2 = Same cycle mirrored, effectively putting a half-sine into a quarter with the right settings. 44 3 = The second half is all zeros, the sine fragment is effectively "stuffed" into an eight of the waveform. 45 bit 3 = Horizontal mirroring of the cycle. 46 bit 4 = Vertical mirroring of the cycle. 47 */ 48 public static short[1024] generateSinewave(ubyte[4] q) @nogc @safe pure nothrow { 49 short[1024] result; 50 for (int j ; j < 4 ; j++) { 51 if (q[j] & 1) { 52 const int offset = 256 * j; 53 int hMir = q[j] & 0x8 ? -1 : 1; 54 int hBegin = q[j] & 0x8 ? 255 : 0; 55 const int vOffset = q[j] & 0x10 ? -1 : 0; 56 const int vMir = q[j] & 0x10 ? -1 : 1; 57 switch (q[j]>>1 & 3) { 58 case 1: 59 hMir *= 2; 60 for (int i ; i < 256 ; i++) { 61 result[offset + i] = cast(short)(SINEWAVE_FRAGMENT[(hBegin + hMir * i) & 255] * vMir + vOffset); 62 } 63 break; 64 case 2: 65 hMir *= 2; 66 for (int i ; i < 128 ; i++) { 67 result[offset + i] = cast(short)(SINEWAVE_FRAGMENT[(hBegin + hMir * i) & 255] * vMir + vOffset); 68 } 69 hMir *= -1; 70 hBegin = q[j] & 0x8 ? 0 : 255; 71 for (int i ; i < 128 ; i++) { 72 result[offset + i + 128] = cast(short)(SINEWAVE_FRAGMENT[(hBegin + hMir * i) & 255] * vMir + vOffset); 73 } 74 break; 75 case 3: 76 hMir *= 2; 77 for (int i ; i < 128 ; i++) { 78 result[offset + i] = cast(short)(SINEWAVE_FRAGMENT[(hBegin + hMir * i) & 255] * vMir + vOffset); 79 } 80 break; 81 default: 82 for (int i ; i < 256 ; i++) { 83 result[offset + i] = cast(short)(SINEWAVE_FRAGMENT[hBegin + hMir * i] * vMir + vOffset); 84 } 85 break; 86 } 87 } 88 } 89 return result; 90 } 91 /** 92 Generates a pulse wave. 93 94 `width` controls the pulse width. 95 */ 96 public static short[1024] generatePulseWave(int width = 512) @nogc @safe pure nothrow { 97 short[1024] result; 98 for (int i ; i < 1024 ; i++) { 99 result[i] = i < width ? short.max : short.min; 100 } 101 return result; 102 } 103 /** 104 Generates a triangular waveform. 105 `shape` controls the shape of the triangular waveform, allowing it to be morphed between triangle, saw, and ramp. 106 `` 107 */ 108 public static short[1024] generateTriangularWave(int shape = 512) @nogc @safe pure nothrow { 109 import pixelperfectengine.system.etc : clamp; 110 short[1024] result; 111 real state = short.min; 112 const real upwardSlope = (ushort.max / shape) + short.min; 113 const real downwardSlope = (ushort.max / (1024 - shape)) + short.min; 114 for (int i ; i < 1024 ; i++) { 115 state += i < shape ? upwardSlope : downwardSlope; 116 clamp(state, cast(real)short.min, cast(real)short.max); 117 result[i] = cast(short)state; 118 } 119 return result; 120 } 121 /** 122 Contains a table to calculate Attack, Decay, and Release values. 123 124 All values are seconds with factions. Actual values are live-calculated depending on sustain-level and sampling 125 frequency. 126 */ 127 public static immutable float[128] ADSR_TIME_TABLE = [ 128 // 0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |A |B |C |D |E |F 129 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 130 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 131 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 132 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 133 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 134 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 135 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 136 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 137 138 ]; 139 /** 140 Contains a table to calculate Sustain control values. 141 142 All values are seconds with fractions. Actual values are live-calculated depending on sustain level and sampling 143 frequency. Please note that with certain levels of sustain, the actual max time might be altered. 144 */ 145 public static immutable float[63] SUSTAIN_CONTROL_TIME_TABLE = [ 146 // 0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |A |B |C |D |E |F 147 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 148 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 149 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 150 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 151 ]; 152 /** 153 Contains a quarter sine wave, can be used for waveform generation. 154 155 Generated by the static constructor. 156 */ 157 public static immutable short[256] SINEWAVE_FRAGMENT; 158 /** 159 Defines operator parameter numbers, within the unregistered namespace. 160 */ 161 public enum OperatorParamNums { 162 //Unregistered 163 Level = 0, 164 Attack = 1, 165 Decay = 2, 166 SusLevel = 3, 167 SusCtrl = 4, 168 Release = 5, 169 Waveform = 6, 170 Feedback = 7, 171 TuneCor = 8, 172 TuneFine = 9, 173 ShpA = 10, 174 ShpR = 11, 175 VelToLevel = 12, 176 MWToLevel = 13, 177 LFOToLevel = 14, 178 OpCtrl = 15, 179 VelToFB = 16, 180 MWToFB = 17, 181 LFOToFB = 18, 182 EEGToFB = 19, 183 VelToShpA = 20, 184 VelToShpR = 21, 185 } 186 /** 187 Defines channel parameter numbers, within the unregistered namespace. 188 */ 189 public enum ChannelParamNums { 190 MasterVol = 0, 191 Bal = 1, 192 AuxSLA = 2, 193 AuxSLB = 3, 194 EEGDetune = 4, 195 PLFO = 5, 196 Attack = 6, 197 Decay = 7, 198 SusLevel = 8, 199 SusCtrl = 9, 200 Release = 10, 201 ShpA = 11, 202 ShpR = 12, 203 ChCtrl = 16, 204 RingMod = 17, 205 EEGToLeft = 18, 206 EEGToRight = 19, 207 EEGToAuxA = 20, 208 EEGToAuxB = 21, 209 LFOToLeft = 22, 210 LFOToRight = 23, 211 LFOToAuxA = 24, 212 LFOToAuxB = 25, 213 } 214 /** 215 Defines channel parameters within the registered namespace 216 */ 217 public enum ChannelRegParams { 218 PitchBendSens, 219 TuneCor, 220 TuneFine, 221 } 222 /** 223 Defines global parameter nummbers, within the unregistered namespace 224 */ 225 public enum GlobalParamNums { 226 PLFORate = 0, 227 PLFOWF = 1, 228 ALFORate = 2, 229 ALFOWF = 3, 230 FilterLCFreq= 4, 231 FilterLCQ = 5, 232 FilterRCFreq= 6, 233 FilterRCQ = 7, 234 FilterACFreq= 8, 235 FilterACQ = 9, 236 FilterBCFreq= 10, 237 FilterBCQ = 11, 238 } 239 enum TuneCtrlFlags : uint { 240 FineTuneMidPoint = 0x1_00_00_00, 241 CorTuneMidPoint = 0x30_00_00_00, 242 FineTuneTest = 0x1_FF_FF_FF, 243 CorTuneTest = 0xFE_00_00_00, 244 } 245 ///Defines control values 246 enum OpCtrlFlags { 247 WavetableSelect = 127, ///Wavetable select flags 248 FBMode = 1 << 7, ///Feedback mode (L: After Envelop Generator, H: Before Envelop Generator) 249 FBNeg = 1 << 8, ///Feedback mode (L: Positive, H: Negative) 250 MWNeg = 1 << 9, ///Invert modulation wheel control 251 VelNeg = 1 << 10, ///Invert velocity control 252 EGRelAdaptive = 1 << 11, ///Adaptive release time based on current output level 253 FixedPitch = 1 << 12, ///Enables fixed pitch mode 254 } 255 /** 256 Implements a single operator. 257 258 Contains an oscillator, an ADSR envelop generator, and locals. 259 */ 260 public struct Operator { 261 ///Local copy of operator preset data. 262 Preset.Op preset; 263 ///The envelop generator of the operator. 264 ADSREnvelopGenerator eg; 265 ///The current position of the oscillator, including fractions. 266 uint pos; 267 ///The amount the oscillator must be stepped forward each cycle, including fractions. 268 uint step; 269 ///Input register. 270 ///The amount which the oscillator will be offsetted. 271 int input; 272 ///Feedback register. Either out_0[n-1] or out[n-1] multiplied by feedback amount. 273 ///The amount which the oscillator will be offsetted. 274 ///Negative if inverted. 275 int feedback; 276 ///Output register. 277 ///Not affected by either level or EG 278 ///Might be used for ring modulation. 279 int output; 280 ///Live calculated out of shpA 281 float shpA0 = 0.0; 282 ///Live calculated out of shpR 283 float shpR0 = 0.0; 284 ///Output affected by EEG and level. 285 ///Either used for audible output, or to modulate other operators 286 int output_0; 287 288 ///Sets the frequency of the operator 289 void setFrequency(int slmpFreq, ubyte note, double pitchBend, double tuning) @nogc @safe pure nothrow { 290 /+const double actualNote = (opCtrl & OpCtrlFlags.FixedPitch) ? 291 (tune>>25) + ((cast(double)(tune & TuneCtrlFlags.FineTuneTest) - TuneCtrlFlags.FineTuneMidPoint) / 292 TuneCtrlFlags.FineTuneTest) : pitchBend + note ;+/ 293 double actualNote; 294 if (preset.opCtrl & OpCtrlFlags.FixedPitch) { 295 actualNote = (preset.tune>>25) + ((cast(double)(preset.tune & TuneCtrlFlags.FineTuneTest) - 296 TuneCtrlFlags.FineTuneMidPoint) / TuneCtrlFlags.FineTuneTest); 297 } else { 298 actualNote = pitchBend + note + cast(int)((preset.tune>>25) - TuneCtrlFlags.CorTuneMidPoint) + 299 ((cast(double)(preset.tune & TuneCtrlFlags.FineTuneTest) - TuneCtrlFlags.FineTuneMidPoint) / 300 TuneCtrlFlags.FineTuneTest); 301 } 302 const double oscFreq = noteToFreq(actualNote, tuning); 303 const double cycLen = oscFreq / (slmpFreq / 1024.0); 304 step = cast(uint)(cast(double)(1<<20) / cycLen); 305 } 306 ///Resets the Envelop generator 307 void resetEG(int sampleRate) @nogc @safe pure nothrow { 308 //Set attack phase 309 if (preset.atk) { 310 eg.attackRate = calculateRate(ADSR_TIME_TABLE[preset.atk], sampleRate); 311 } else { 312 eg.attackRate = 1.0; 313 } 314 //Set decay phase 315 if (preset.dec) { 316 eg.decayRate = calculateRate(ADSR_TIME_TABLE[preset.dec] * 2, sampleRate, ADSREnvelopGenerator.maxOutput, eg.sustainLevel); 317 } else { 318 eg.decayRate = 1.0; 319 } 320 //Set sustain phase 321 if (preset.susCC) { 322 eg.isPercussive = false; 323 if (preset.susCC == 64) { 324 eg.sustainControl = 0.0; 325 } else if (preset.susCC < 64) { 326 eg.sustainControl = -1.0 * 327 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[preset.susCC - 1], sampleRate); 328 } else { 329 eg.sustainControl = 330 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[preset.susCC - 64], sampleRate); 331 } 332 } else { 333 eg.isPercussive = true; 334 eg.sustainControl = 0.0; 335 } 336 //Set release phase 337 if (preset.rel) { 338 eg.releaseRate = calculateRate(ADSR_TIME_TABLE[preset.rel] * 2, sampleRate, eg.sustainLevel); 339 } else { 340 eg.releaseRate = 1.0; 341 } 342 } 343 344 } 345 ///Defines channel control flags. 346 enum ChCtrlFlags { 347 ///Channel combination turned off, the channel pair is independent 348 ComboModeOff = 0b0000, 349 ///Channel combination mode 1: Secondary channel's output is fed into primary operator 0. 350 ComboMode1 = 0b0001, 351 ///Channel combination mode 2: Secondary channel's output is fed into primary operator 1 if primary 352 ///is in serial mode, or into both if primary is in parallel mode. 353 ComboMode2 = 0b0010, 354 ///Channel combination mode 3: Secondary channel's output is fed into main output, except if primary 355 ///channel set to parallel and secondary set to serial, then S1, P0, and P1 are connected to output, while 356 ///S0 is modulating all of them. 357 ComboMode3 = 0b0011, 358 ///Used for testing combo mode. 359 ComboModeTest = ComboMode3, 360 Algorithm = 1<<2, ///Channel algorithm (H: Parallel, L: Series) 361 IndivOutChLev = 1<<3, ///Enables the setting of individual output channel levels 362 LFOPan = 1<<4, ///Enables LFO Panning 363 EEGPan = 1<<5, ///Enables EEG Panning 364 MWToTrem = 1<<6, ///Assigns modwheel to amplitude LFO 365 MWToVibr = 1<<7, ///Assigns modwheel to pitch LFO 366 MWToAux = 1<<8, ///Assigns modwheel to aux levels 367 } 368 /** 369 Defines channel common parameters. 370 */ 371 public struct Channel { 372 ///Copy of channel relevant preset data 373 Preset.Ch preset; 374 ///Extra envelop generator that can be assigned for multiple purpose. 375 ADSREnvelopGenerator eeg; 376 ///Calculated output level controls + aux send levels 377 ///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B 378 __m128 outLevels; 379 ///Resets the Extra Envelop generator 380 void resetEEG(int sampleRate) @nogc @safe pure nothrow { 381 //Set attack phase 382 if (preset.atkX) { 383 eeg.attackRate = calculateRate(ADSR_TIME_TABLE[preset.atkX], sampleRate); 384 } else { 385 eeg.attackRate = 1.0; 386 } 387 //Set decay phase 388 if (preset.decX) { 389 eeg.decayRate = calculateRate(ADSR_TIME_TABLE[preset.decX] * 2, sampleRate, ADSREnvelopGenerator.maxOutput, 390 eeg.sustainLevel); 391 } else { 392 eeg.decayRate = 1.0; 393 } 394 //Set sustain phase 395 if (preset.susCCX) { 396 eeg.isPercussive = false; 397 if (preset.susCCX == 64) { 398 eeg.sustainControl = 0.0; 399 } else if (preset.susCCX < 64) { 400 eeg.sustainControl = -1.0 * calculateRate(SUSTAIN_CONTROL_TIME_TABLE[preset.susCCX - 1], sampleRate); 401 } else { 402 eeg.sustainControl = calculateRate(SUSTAIN_CONTROL_TIME_TABLE[preset.susCCX - 64], sampleRate); 403 } 404 } else { 405 eeg.isPercussive = true; 406 eeg.sustainControl = 0.0; 407 } 408 //Set release phase 409 if (preset.relX) { 410 eeg.releaseRate = calculateRate(ADSR_TIME_TABLE[preset.relX] * 2, sampleRate, eeg.sustainLevel); 411 } else { 412 eeg.releaseRate = 1.0; 413 } 414 } 415 416 } 417 /** 418 Stores channel controller values (modwheel, velocity, etc.) 419 */ 420 public struct ChControllers { 421 ///Modulation wheel parameter, normalized between 0.0 and 1.0 422 float modwheel = 0; 423 ///Velocity parameter, normalized between 0.0 and 1.0 424 float velocity = 0; 425 ///Pitch bend parameter, with the amount of pitch shifting in semitones + fractions 426 float pitchBend = 0; 427 ///The note that is currently being played 428 ubyte note; 429 } 430 /** 431 Defines a preset. 432 */ 433 public struct Preset { 434 ///Defines parameters of a single operator 435 public struct Op { 436 ///Operator tuning 437 ///Bit 31-25: Coarse detuning (-24 to +103 seminotes) 438 ///Bit 24-0: Fine detuning (-100 to 100 cents), 0x1_00_00_00 is center 439 ///If fixed mode is being used, then top 7 bits are the note, the rest are fine tuning. 440 uint tune = 0x31_00_00_00; 441 ///Output level (between 0.0 and 1.0) 442 float outL = 0.25; 443 ///Feedback level (between 0.0 and 1.0) 444 float fbL = 0.0; 445 ///Control flags and Wavetable selector 446 uint opCtrl; 447 ///Output level controller assignment 448 ///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: unused 449 __m128 outLCtrl= [0,0,0,0]; 450 ///Feedback level controller assignment 451 ///Index notation: 0: velocity 1: modulation wheel 2: Amplitude LFO 3: Extra envelop generator 452 __m128 fbLCtrl = [0,0,0,0]; 453 ///Attack time control (between 0 and 127) 454 ubyte atk; 455 ///Decay time control (between 0 and 127) 456 ubyte dec; 457 ///Release time control (between 0 and 127) 458 ubyte rel; 459 ///Sustain curve control (between 0 and 127) 460 ///0: Percussive mode 461 ///1 - 63: Descending over time 462 ///64: Constant 463 ///65 - 127: Ascending over time 464 ubyte susCC; 465 ///Sustain level for the EG 466 float susLevel= 1.0; 467 ///ADSR shaping parameter (for the attack phase) 468 float shpA = 0.5; 469 ///ADSR shaping parameter (for the decay/release phase) 470 float shpR = 0.5; 471 ///Assigns velocity to shpA 472 float shpAVel = 0.0; 473 ///Assigns velocity to shpR 474 float shpRVel = 0.0; 475 ///Sets control level for X controller affecting this operator 476 float ctrlXLevel = 0.5; 477 ///Sets control level for X controller affecting this operator 478 float ctrlYLevel = 0.5; 479 } 480 ///Defines parameters of a single channel. 481 public struct Ch { 482 ///ADSR shaping parameter (for the attack phase) 483 float shpAX = 0.5; 484 ///ADSR shaping parameter (for the decay/release phase) 485 float shpRX = 0.5; 486 ///Pitch amount for EEG 487 ///Bit 31-25: Coarse (-64 to +63 seminotes) 488 ///Bit 24-0: Fine (0 to 100 cents) 489 uint eegDetuneAm; 490 ///Pitch bend sensitivity 491 ///Bit 31-25: Coarse (0 to 127 seminotes) 492 ///Bit 24-0: Fine (0 to 100 cents) 493 uint pitchBendSens = 2<<24; 494 ///A-4 channel tuning in hertz. 495 float chnlTun = 440.0; 496 ///Stores channel control flags. 497 uint chCtrl; 498 ///Master volume (0.0 to 1.0) 499 float masterVol= 1; 500 ///Master balance (0.0 to 1.0) 501 float masterBal= 0.5; 502 ///Aux send A 503 float auxSendA = 0; 504 ///Aux send B 505 float auxSendB = 0; 506 ///X and Y controller assign 507 ushort[2] xyCtrlAssign0; 508 ///X and Y controller assign (secondary) 509 ushort[2] xyCtrlAssign1; 510 ///EEG assign levels 511 ///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B 512 __m128 eegLevels= [0,0,0,0]; 513 ///Amplitude LFO assign levels 514 ///Index notation: 0: Left channel 1: Right channel 2: Aux send A, 3: Aux send B 515 __m128 aLFOlevels= [0,0,0,0]; 516 ///Ring modulation amount 517 ///Only available on select algorithms 518 int rmAmount; 519 ///Pitch LFO level 520 float pLFOlevel= 1; 521 ///Amplitude LFO to 522 ///Attack time control (between 0 and 127) 523 ubyte atkX; 524 ///Decay time control (between 0 and 127) 525 ubyte decX; 526 ///Release time control (between 0 and 127) 527 ubyte relX; 528 ///Sustain curve control (between 0 and 127) 529 ///0: Percussive mode 530 ///1 - 63: Descending over time 531 ///64: Constant 532 ///65 - 127: Ascending over time 533 ubyte susCCX; 534 ///Sustain level 535 float susLevel = 1; 536 } 537 Op[2] operators; ///The operators belonging to this channel 538 Ch channel; ///Channel common values 539 } 540 ///Contains the wavetables for the operators and LFOs. 541 ///Value might be divided to limit the values between 2047 and -2048 via bitshifting, 542 ///otherwise the full range can be used for audio output, etc. 543 ///Loaded from a 16 bit wave file. 544 protected short[1024][128] wavetables; 545 ///Stores presets. 546 ///8 banks of 128 presets are available for a total of 1024. 547 ///If a channel combination is being used, then bank pairs (0-1, 2-3, etc) will store their primary and secondary 548 ///halves, and calling either will load both halves. 549 protected Preset[128][8] soundBank; 550 ///Operator data. 551 ///See rendering function on updating. 552 protected Operator[32] operators; 553 ///Channel data. 554 ///See rendering function on updating. 555 protected Channel[16] channels; 556 ///Channel control data. 557 protected ChControllers[16] chCtrls; 558 ///Preset numbers per channels. 559 protected ubyte[16] presetNum; 560 ///Bank numbers per channels. 561 protected ubyte[16] bankNum; 562 ///Keeps the registered/unregistered parameter positions (LSB = 1). 563 protected ubyte[2] paramNum; 564 ///Stores LFO waveform selection. 1: Amplitude; 0: Pitch 565 protected ubyte[2] lfoWaveform; 566 ///Stores temporary parameter values 567 ///0: MSB of sel unregistered param 1: LSB of sel unregistered param 568 ///2: MSB of sel registered param 3: LSB of sel registered param 569 protected ubyte[4] paramTemp; 570 ///Stores ALFO position 571 protected uint aLFOPos; 572 ///Stores ALFO rate 573 protected uint aLFORate; 574 ///Stores output filter values. 575 ///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] 576 protected __m128[10] filterVals; 577 ///Stores control values of the output values. 578 ///Layout: [LF, LQ, RF, RQ, AF, AQ, BF, BQ] 579 protected float[8] filterCtrl = [17_000, 0.707, 17_000, 0.707, 17_000, 0.707, 17_000, 0.707]; 580 ///Initial mixing buffers 581 ///Output is directed there before filtering 582 ///Layout is: LRAB 583 protected float[] initBuffers; 584 ///Dummy buffer 585 ///Only used if one or more outputs haven't been defined 586 protected float[] dummyBuf; 587 ///Amplitude LFO buffer. Values are between 0.0 and 1.0 588 protected float[] aLFOBuf; 589 ///Pitch LFO output. Values are between -1.0 and 1.0 590 protected float pLFOOut = 0; 591 ///Stores PLFO position 592 protected uint pLFOPos; 593 ///Stores PLFO rate 594 protected uint pLFORate; 595 ///Mixdown value. 596 ///Used for final mixing. 597 protected float mixdownVal = 1.0 / (ushort.max); 598 alias ChFun = void delegate(int chNum, size_t length) @nogc pure nothrow; 599 ///Channel update delegates 600 protected ChFun[16] chDeleg; 601 /** 602 Creates an instance of QM816 603 */ 604 public this() @trusted nothrow { 605 info.nOfAudioInput = 0; 606 info.nOfAudioOutput = 4; 607 info.outputChNames = ["mainL", "mainR", "auxSendA", "auxSendB"]; 608 info.isInstrument = true; 609 info.hasMidiIn = true; 610 info.hasMidiOut = true; 611 info.midiSendback = true; 612 try { 613 WaveFormat f = WaveFormat(0, 0, AudioFormat.PCM, 1, 0, 16); 614 short[1024] buffer = generateSinewave([0x01, 0x09, 0x11, 0x19]); 615 waveformDataReceive(0, reinterpretCast!ubyte(buffer), f); ///Sine (from OPL2) 616 buffer = generateSinewave([0x01, 0x09, 0x00, 0x00]); 617 waveformDataReceive(1, reinterpretCast!ubyte(buffer), f); ///Half-sine (from OPL2) 618 buffer = generateSinewave([0x01, 0x09, 0x01, 0x09]); 619 waveformDataReceive(2, reinterpretCast!ubyte(buffer), f); ///Full-sine (from OPL2) 620 buffer = generateSinewave([0x01, 0x00, 0x01, 0x00]); 621 waveformDataReceive(3, reinterpretCast!ubyte(buffer), f); ///Pulse-sine (from OPL2) 622 buffer = generateSinewave([0x01, 0x09, 0x11, 0x00]); 623 waveformDataReceive(4, reinterpretCast!ubyte(buffer), f); ///Pulse-sine 75% 624 buffer = generateSinewave([0x01, 0x00, 0x00, 0x00]); 625 waveformDataReceive(5, reinterpretCast!ubyte(buffer), f); ///Pulse-sine 25% 626 buffer = generateSinewave([0x01, 0x00, 0x11, 0x00]); 627 waveformDataReceive(6, reinterpretCast!ubyte(buffer), f); ///Alternating pulse-sine 628 buffer = generateSinewave([0x05, 0x00, 0x1d, 0x00]); 629 waveformDataReceive(7, reinterpretCast!ubyte(buffer), f); ///Alternating sine (from OPL3) 630 buffer = generateSinewave([0x05, 0x05, 0x1d, 0x1d]); 631 waveformDataReceive(8, reinterpretCast!ubyte(buffer), f); ///Camel sine (from OPL3) 632 buffer = generateSinewave([0x01, 0x09, 0x11, 0x1f]); 633 waveformDataReceive(9, reinterpretCast!ubyte(buffer), f); ///Resonant sine 0 634 buffer = generateSinewave([0x01, 0x09, 0x1d, 0x1d]); 635 waveformDataReceive(10, reinterpretCast!ubyte(buffer), f); ///Resonant sine 1 636 buffer = generateSinewave([0x01, 0x09, 0x0d, 0x0d]); 637 waveformDataReceive(11, reinterpretCast!ubyte(buffer), f); ///Resonant sine 2 638 buffer = generateSinewave([0x01, 0x09, 0x00, 0x1d]); 639 waveformDataReceive(12, reinterpretCast!ubyte(buffer), f); ///Resonant sine 3 640 buffer = generateSinewave([0x01, 0x09, 0x1d, 0x00]); 641 waveformDataReceive(13, reinterpretCast!ubyte(buffer), f); ///Resonant sine 4 642 buffer = generateSinewave([0x01, 0x09, 0x00, 0x0d]); 643 waveformDataReceive(14, reinterpretCast!ubyte(buffer), f); ///Resonant sine 5 644 buffer = generateSinewave([0x01, 0x09, 0x0d, 0x00]); 645 waveformDataReceive(15, reinterpretCast!ubyte(buffer), f); ///Resonant sine 6 646 buffer = generateSinewave([0x01, 0x09, 0x1f, 0x1f]); 647 waveformDataReceive(16, reinterpretCast!ubyte(buffer), f); ///Resonant sine 7 648 buffer = generatePulseWave(768); 649 waveformDataReceive(17, reinterpretCast!ubyte(buffer), f); ///Pulse wave 75% 650 buffer = generatePulseWave(512); 651 waveformDataReceive(18, reinterpretCast!ubyte(buffer), f); ///Pulse wave 50% 652 buffer = generatePulseWave(256); 653 waveformDataReceive(19, reinterpretCast!ubyte(buffer), f); ///Pulse wave 25% 654 buffer = generatePulseWave(128); 655 waveformDataReceive(20, reinterpretCast!ubyte(buffer), f); ///Pulse wave 12.5% 656 buffer = generatePulseWave(100); 657 waveformDataReceive(21, reinterpretCast!ubyte(buffer), f); ///Pulse wave 10% 658 buffer = generatePulseWave(50); 659 waveformDataReceive(22, reinterpretCast!ubyte(buffer), f); ///Pulse wave 5% 660 buffer = generateTriangularWave(1023); 661 waveformDataReceive(23, reinterpretCast!ubyte(buffer), f); ///Ramp wave 662 buffer = generateTriangularWave(768); 663 waveformDataReceive(24, reinterpretCast!ubyte(buffer), f); ///Morphed ramp 664 buffer = generateTriangularWave(512); 665 waveformDataReceive(25, reinterpretCast!ubyte(buffer), f); ///Triangle wave 666 buffer = generateTriangularWave(256); 667 waveformDataReceive(26, reinterpretCast!ubyte(buffer), f); ///Morphed saw 668 buffer = generateTriangularWave(1); 669 waveformDataReceive(27, reinterpretCast!ubyte(buffer), f); ///Saw wave 670 } catch (Exception e) { 671 672 } 673 //Reset delegates 674 for (int i ; i < chDeleg.length ; i++) { 675 chDeleg[i] = &updateChannelM00; 676 } 677 } 678 /** 679 * Sets the module up. 680 * 681 * Can be overridden in child classes to allow resets. 682 */ 683 public override void moduleSetup(ubyte[] inputs, ubyte[] outputs, int sampleRate, size_t bufferSize, 684 ModuleManager handler) @safe nothrow { 685 enabledInputs = StreamIDSet(inputs); 686 enabledOutputs = StreamIDSet(outputs); 687 this.sampleRate = sampleRate; 688 this.bufferSize = bufferSize; 689 this.handler = handler; 690 //set up and reset buffers 691 initBuffers.length = bufferSize * 4; 692 resetBuffer(initBuffers); 693 dummyBuf.length = bufferSize; 694 resetBuffer(dummyBuf); 695 aLFOBuf.length = bufferSize; 696 resetBuffer(aLFOBuf); 697 //Reset filters 698 for (int i ; i < 4 ; i++) { 699 BiquadFilterValues vals = createLPF(sampleRate, filterCtrl[i * 2], filterCtrl[(i * 2) + 1]); 700 filterVals[0][i] = vals.a0; 701 filterVals[1][i] = vals.a1; 702 filterVals[2][i] = vals.a2; 703 filterVals[3][i] = vals.b0; 704 filterVals[4][i] = vals.b1; 705 filterVals[5][i] = vals.b2; 706 filterVals[6][i] = 0; 707 filterVals[7][i] = 0; 708 filterVals[8][i] = 0; 709 filterVals[9][i] = 0; 710 } 711 //Reset operator EGs 712 for (int i ; i < operators.length ; i++) { 713 operators[i].resetEG(sampleRate); 714 } 715 //Reset channel EGs 716 for (int i ; i < channels.length ; i++) { 717 channels[i].resetEEG(sampleRate); 718 } 719 } 720 /** 721 * Receives waveform data that has been loaded from disk for reading. Returns zero if successful, or a specific 722 * errorcode. 723 * 724 * id: The ID of the waveform. 725 * rawData: The data itself, in unprocessed form. 726 * format: The format of the wave data, including the data type, bit depth, base sampling rate 727 * 728 * Note: This function needs the audio system to be unlocked. 729 */ 730 public override int waveformDataReceive(uint id, ubyte[] rawData, WaveFormat format) nothrow { 731 int errorcode; 732 if (format.channels != 1) errorcode |= SampleLoadErrorCode.ChNumNotSupported; 733 if (format.bitsPerSample != 16) errorcode |= SampleLoadErrorCode.BitdepthNotSupported; 734 if (format.format != AudioFormat.PCM) errorcode |= SampleLoadErrorCode.FormatNotSupported; 735 if (rawData.length != 128 * 1024 * 2 && rawData.length != 1024 * 2) 736 errorcode |= SampleLoadErrorCode.SampleLenghtNotSupported; 737 if (errorcode) { 738 return errorcode; 739 } else { 740 import core.stdc.string : memcpy; 741 if (rawData.length == 128 * 1024 * 2) 742 memcpy(wavetables.ptr, rawData.ptr, 128 * 1024 * 2); 743 else 744 memcpy(wavetables[id].ptr, rawData.ptr, 1024 * 2); 745 return 0; 746 } 747 } 748 /** 749 * MIDI 2.0 data received here. 750 * 751 * data: up to 128 bits of MIDI 2.0 commands. Any packets that are shorter should be padded with zeros. 752 * offset: time offset of the command. This can reduce jitter caused by the asynchronous operation of the 753 * sequencer and the audio plugin system. 754 */ 755 public override void midiReceive(uint[4] data, uint offset) @nogc nothrow { 756 UMP firstPacket; 757 firstPacket.base = data[0]; 758 switch (firstPacket.msgType) { 759 case MessageType.SysCommMsg: //Process system common message 760 break; 761 case MessageType.MIDI1: //Process MIDI 1.0 messages 762 switch (firstPacket.status) { 763 case MIDI1_0Cmd.CtrlCh: //Process MIDI 1.0 control change messages 764 switch (firstPacket.note) { 765 case 0, 32: //Bank select 766 bankNum[firstPacket.channel] = firstPacket.value & 7; 767 break; 768 case 1: //Modulation wheel 769 chCtrls[firstPacket.channel].modwheel = cast(double)(firstPacket.value) / byte.max; 770 break; 771 case 6: //Data Entry MSB 772 paramNum[0] = firstPacket.value; 773 paramTemp = [0xFF,0xFF,0xFF,0xFF]; 774 break; 775 case 38: //Data Entry LSB 776 paramNum[1] = firstPacket.value; 777 paramTemp = [0xFF,0xFF,0xFF,0xFF]; 778 break; 779 case 98: //Non Registered Parameter Number MSB (handle through MIDI 2.0) 780 //setUnregisteredParam(firstPacket.value, paramNum, 0, firstPacket.channel); 781 paramTemp[0] = firstPacket.value; 782 setUnregisteredParam(convertM1CtrlValToM2(paramTemp[0], paramTemp[1]), paramNum, firstPacket.channel); 783 break; 784 case 99: //Non Registered Parameter Number LSB (handle through MIDI 2.0) 785 //setUnregisteredParam(firstPacket.value, paramNum, 0, firstPacket.channel); 786 paramTemp[1] = firstPacket.value; 787 if (paramTemp[0] != 0xFF) 788 setUnregisteredParam(convertM1CtrlValToM2(paramTemp[0], paramTemp[1]), paramNum, firstPacket.channel); 789 break; 790 default: 791 break; 792 } 793 break; 794 case MIDI1_0Cmd.NoteOn: //Note on command 795 const uint ch = firstPacket.channel; 796 if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch > 7) return; 797 chCtrls[ch].note = firstPacket.note; 798 chCtrls[ch].velocity = cast(double)firstPacket.velocity / cast(double)byte.max; 799 channels[ch].eeg.keyOn(); 800 operators[ch].eg.keyOn(); 801 operators[ch].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun); 802 operators[ch + 1].eg.keyOn(); 803 operators[ch + 1].setFrequency(sampleRate, firstPacket.note, chCtrls[ch + 1].pitchBend, channels[ch].preset.chnlTun); 804 if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch <= 7) { 805 channels[ch + 8].eeg.keyOn(); 806 operators[ch + 16].eg.keyOn(); 807 operators[ch + 16].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun); 808 operators[ch + 17].eg.keyOn(); 809 operators[ch + 17].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun); 810 } 811 break; 812 case MIDI1_0Cmd.NoteOff://Note off command 813 const uint ch = firstPacket.channel; 814 if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch > 7) return; 815 chCtrls[ch].velocity = cast(double)firstPacket.velocity / cast(double)byte.max; 816 channels[ch].eeg.keyOff(); 817 operators[ch].eg.keyOff(); 818 if (operators[ch].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) { 819 if (operators[ch].preset.rel) { 820 operators[ch].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch].preset.rel] * 2, sampleRate, 821 operators[ch].eg.sustainLevel); 822 } else { 823 operators[ch].eg.releaseRate = 1.0; 824 } 825 } 826 operators[ch + 1].eg.keyOff(); 827 if (operators[ch + 1].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) { 828 if (operators[ch + 1].preset.rel) { 829 operators[ch + 1].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 1].preset.rel] * 2, sampleRate, 830 operators[ch + 1].eg.sustainLevel); 831 } else { 832 operators[ch + 1].eg.releaseRate = 1.0; 833 } 834 } 835 if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch <= 7) { 836 channels[ch + 8].eeg.keyOff(); 837 operators[ch + 16].eg.keyOff(); 838 if (operators[ch + 16].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) { 839 if (operators[ch + 16].preset.rel) { 840 operators[ch + 16].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 16].preset.rel] * 2, sampleRate, 841 operators[ch + 16].eg.sustainLevel); 842 } else { 843 operators[ch + 16].eg.releaseRate = 1.0; 844 } 845 } 846 operators[ch + 17].eg.keyOff(); 847 if (operators[ch + 17].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) { 848 if (operators[ch + 17].preset.rel) { 849 operators[ch + 17].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 17].preset.rel] * 2, sampleRate, 850 operators[ch + 17].eg.sustainLevel); 851 } else { 852 operators[ch + 17].eg.releaseRate = 1.0; 853 } 854 } 855 } 856 break; 857 case MIDI1_0Cmd.ChAftrTch: 858 chCtrls[firstPacket.channel].velocity = cast(double)firstPacket.note / cast(double)byte.max; 859 break; 860 case MIDI1_0Cmd.PolyAftrTch: 861 chCtrls[firstPacket.channel].velocity = cast(double)firstPacket.velocity / cast(double)byte.max; 862 break; 863 case MIDI1_0Cmd.PrgCh: //Program change 864 const uint chOffset = firstPacket.channel; 865 const uint chCtrl = soundBank[bankNum[chOffset] & 7][presetNum[chOffset]].channel.chCtrl; 866 if (chCtrl & ChCtrlFlags.ComboModeTest) { 867 const uint chX = chOffset & 7, bankX = bankNum[chOffset] & 7 & ~1; 868 prgRecall(chX, presetNum[chX], bankX); 869 prgRecall(chX + 8, presetNum[chX], bankX + 1); 870 } else { 871 prgRecall(chOffset, presetNum[chOffset], bankNum[chOffset]); 872 } 873 break; 874 case MIDI1_0Cmd.PitchBend: 875 const uint ch = firstPacket.channel; 876 const double pitchBendSens = (channels[ch].preset.pitchBendSens>>25) + 877 (cast(double)(channels[ch].preset.pitchBendSens & 0x01_FF_FF_FF) / 0x01_FF_FF_FF); 878 chCtrls[ch].pitchBend = pitchBendSens * ((cast(double)firstPacket.bend - 0x20_00) / 0x3F_FF); 879 break; 880 default: 881 break; 882 } 883 break; 884 case MessageType.MIDI2: 885 switch (firstPacket.status) { 886 case MIDI2_0Cmd.CtrlCh: //Control change 887 setUnregisteredParam(data[1], [firstPacket.index, firstPacket.value], firstPacket.channel); 888 break; 889 case MIDI2_0Cmd.CtrlChR://Registered control change 890 //setRegisteredParam(data[1], [firstPacket.index, firstPacket.value], firstPacket.channel); 891 break; 892 case MIDI2_0Cmd.PrgCh: //Program change 893 const uint chOffset = firstPacket.channel; 894 //const uint prg = data[1]>>24, bank = data[1] & 7; 895 presetNum[chOffset] = cast(ubyte)(data[1]>>24); 896 if (firstPacket.value & 1) bankNum[chOffset] = cast(ubyte)(data[1] & 7); 897 const uint chCtrl = soundBank[bankNum[chOffset] & 7][presetNum[chOffset]].channel.chCtrl; 898 if (chCtrl & ChCtrlFlags.ComboModeTest) { 899 const uint chX = chOffset & 7, bankX = bankNum[chOffset] & 7 & ~1; 900 prgRecall(chX, presetNum[chX], bankX); 901 prgRecall(chX + 8, presetNum[chX], bankX + 1); 902 } else { 903 prgRecall(chOffset, presetNum[chOffset], bankNum[chOffset]); 904 } 905 break; 906 case MIDI2_0Cmd.NoteOn: 907 NoteVals v = *cast(NoteVals*)(&data[1]); 908 const uint ch = firstPacket.channel; 909 if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch > 7) return; 910 chCtrls[ch].note = firstPacket.note; 911 chCtrls[ch].velocity = v.velocity / cast(double)ushort.max; 912 channels[ch].eeg.keyOn(); 913 operators[ch].eg.keyOn(); 914 operators[ch].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun); 915 operators[ch + 1].eg.keyOn(); 916 operators[ch + 1].setFrequency(sampleRate, firstPacket.note, chCtrls[ch + 1].pitchBend, channels[ch].preset.chnlTun); 917 if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch <= 7) { 918 channels[ch + 8].eeg.keyOn(); 919 operators[ch + 16].eg.keyOn(); 920 operators[ch + 16].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun); 921 operators[ch + 17].eg.keyOn(); 922 operators[ch + 17].setFrequency(sampleRate, firstPacket.note, chCtrls[ch].pitchBend, channels[ch].preset.chnlTun); 923 } 924 break; 925 case MIDI2_0Cmd.NoteOff: 926 NoteVals v = *cast(NoteVals*)(&data[1]); 927 const uint ch = firstPacket.channel; 928 if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch > 7) return; 929 //chCtrls[ch].note = firstPacket.note; 930 chCtrls[ch].velocity = v.velocity / cast(double)ushort.max; 931 channels[ch].eeg.keyOff(); 932 operators[ch].eg.keyOff(); 933 if (operators[ch].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) { 934 if (operators[ch].preset.rel) { 935 operators[ch].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch].preset.rel] * 2, sampleRate, 936 operators[ch].eg.sustainLevel); 937 } else { 938 operators[ch].eg.releaseRate = 1.0; 939 } 940 } 941 operators[ch + 1].eg.keyOff(); 942 if (operators[ch + 1].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) { 943 if (operators[ch + 1].preset.rel) { 944 operators[ch + 1].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 1].preset.rel] * 2, sampleRate, 945 operators[ch + 1].eg.sustainLevel); 946 } else { 947 operators[ch + 1].eg.releaseRate = 1.0; 948 } 949 } 950 if ((channels[ch].preset.chCtrl & ChCtrlFlags.ComboModeTest) && ch <= 7) { 951 channels[ch + 8].eeg.keyOff(); 952 operators[ch + 16].eg.keyOff(); 953 if (operators[ch + 16].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) { 954 if (operators[ch + 16].preset.rel) { 955 operators[ch + 16].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 16].preset.rel] * 2, sampleRate, 956 operators[ch + 16].eg.sustainLevel); 957 } else { 958 operators[ch + 16].eg.releaseRate = 1.0; 959 } 960 } 961 operators[ch + 17].eg.keyOff(); 962 if (operators[ch + 17].preset.opCtrl & OpCtrlFlags.EGRelAdaptive) { 963 if (operators[ch + 17].preset.rel) { 964 operators[ch + 17].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[ch + 17].preset.rel] * 2, sampleRate, 965 operators[ch + 17].eg.sustainLevel); 966 } else { 967 operators[ch + 17].eg.releaseRate = 1.0; 968 } 969 } 970 } 971 break; 972 case MIDI2_0Cmd.PitchBend: 973 const uint ch = firstPacket.channel; 974 const double pitchBendSens = (channels[ch].preset.pitchBendSens>>25) + 975 (cast(double)(channels[ch].preset.pitchBendSens & 0x01_FF_FF_FF) / 0x01_FF_FF_FF); 976 chCtrls[ch].pitchBend = pitchBendSens * (cast(double)(firstPacket.bend - (uint.max / 2)) / (uint.max / 2)); 977 break; 978 default: 979 break; 980 } 981 break; 982 default: 983 break; 984 } 985 } 986 /** 987 Sets the channel delegates 988 */ 989 protected void setChDeleg(uint chCtrl, uint chNum, uint chCtrl0 = 0) @nogc @safe pure nothrow { 990 if (chCtrl & ChCtrlFlags.ComboModeTest) { //Test if channel is combined or not 991 if (chNum < 8) { 992 const uint algID = chCtrl & (ChCtrlFlags.ComboModeTest & ChCtrlFlags.Algorithm) | 993 ((chCtrl0 & ChCtrlFlags.Algorithm)<<1); 994 enum priChAlg = ChCtrlFlags.Algorithm; 995 enum secChAlg = ChCtrlFlags.Algorithm<<1; 996 switch (algID) { 997 case ChCtrlFlags.ComboMode1: 998 chDeleg[chNum] = &updateChannelM100; 999 break; 1000 case ChCtrlFlags.ComboMode1 | secChAlg: 1001 chDeleg[chNum] = &updateChannelM110; 1002 break; 1003 case ChCtrlFlags.ComboMode1 | priChAlg: 1004 chDeleg[chNum] = &updateChannelM101; 1005 break; 1006 case ChCtrlFlags.ComboMode1 | secChAlg | priChAlg: 1007 chDeleg[chNum] = &updateChannelM111; 1008 break; 1009 case ChCtrlFlags.ComboMode2: 1010 chDeleg[chNum] = &updateChannelM200; 1011 break; 1012 case ChCtrlFlags.ComboMode2 | secChAlg: 1013 chDeleg[chNum] = &updateChannelM210; 1014 break; 1015 case ChCtrlFlags.ComboMode2 | priChAlg: 1016 chDeleg[chNum] = &updateChannelM201; 1017 break; 1018 case ChCtrlFlags.ComboMode2 | secChAlg | priChAlg: 1019 chDeleg[chNum] = &updateChannelM211; 1020 break; 1021 case ChCtrlFlags.ComboMode3: 1022 chDeleg[chNum] = &updateChannelM300; 1023 break; 1024 case ChCtrlFlags.ComboMode3 | secChAlg: 1025 chDeleg[chNum] = &updateChannelM310; 1026 break; 1027 case ChCtrlFlags.ComboMode3 | priChAlg: 1028 chDeleg[chNum] = &updateChannelM301; 1029 break; 1030 case ChCtrlFlags.ComboMode3 | secChAlg | priChAlg: 1031 chDeleg[chNum] = &updateChannelM311; 1032 break; 1033 default: 1034 chDeleg[chNum] = &updateChannelMD; 1035 break; 1036 } 1037 } else { 1038 chDeleg[chNum] = &updateChannelMD; 1039 } 1040 } else { 1041 if (chCtrl & ChCtrlFlags.Algorithm) 1042 chDeleg[chNum] = &updateChannelM01; 1043 else 1044 chDeleg[chNum] = &updateChannelM00; 1045 } 1046 } 1047 /** 1048 Recalls a program 1049 */ 1050 protected void prgRecall(ubyte ch, ubyte prg, ubyte bank) @nogc @safe pure nothrow { 1051 Preset p = soundBank[bank & 7][prg]; 1052 operators[ch].preset = p.operators[0]; 1053 operators[ch].resetEG(sampleRate); 1054 operators[ch + 1].preset = p.operators[1]; 1055 operators[ch + 1].resetEG(sampleRate); 1056 channels[ch].preset = p.channel; 1057 channels[ch].resetEEG(sampleRate); 1058 } 1059 /** 1060 Sets a registered parameter 1061 1062 If type is not zero, then the MSB is being set, otherwise the LSB will be used 1063 */ 1064 protected void setRegisteredParam(T)(T val, ubyte[2] paramNum, ubyte type, ubyte chNum) @nogc @safe pure nothrow { 1065 switch (paramNum[0]) { 1066 case ChannelRegParams.PitchBendSens: 1067 static if (is(T == uint)) { 1068 channels[chNum].pitchBendSens = val; 1069 } else static if (is(T == ubyte)) { 1070 if (type) { 1071 channels[chNum].pitchBendSens &= ~(byte.max<<25); 1072 channels[chNum].pitchBendSens |= val<<25; 1073 } else { 1074 channels[chNum].pitchBendSens &= ~(byte.max<<18); 1075 channels[chNum].pitchBendSens |= val<<18; 1076 } 1077 } 1078 break; 1079 case ChannelRegParams.TuneFine: //Channel master tuning (fine) 1080 break; 1081 case ChannelRegParams.TuneCor: //Channel master tuning (coarse) 1082 break; 1083 default: break; 1084 } 1085 } 1086 /** 1087 Sets an unregistered parameter (MIDI 2.0) 1088 1089 If type is not zero, then the MSB is being set, otherwise the LSB will be used 1090 */ 1091 protected void setUnregisteredParam(uint val, ubyte[2] paramNum, ubyte chNum) @nogc @safe pure nothrow { 1092 void setOpParam(int chNum) { 1093 switch (paramNum[0]) { 1094 case OperatorParamNums.Attack: 1095 operators[chNum].preset.atk = cast(ubyte)(val >> 25); 1096 1097 if (operators[chNum].preset.atk) { 1098 operators[chNum].eg.attackRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].preset.atk], sampleRate); 1099 } else { 1100 operators[chNum].eg.attackRate = 1.0; 1101 } 1102 break; 1103 case OperatorParamNums.Decay: 1104 operators[chNum].preset.dec = cast(ubyte)(val >> 25); 1105 1106 if (operators[chNum].preset.dec) { 1107 operators[chNum].eg.decayRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].preset.dec] * 2, sampleRate, 1108 ADSREnvelopGenerator.maxOutput, operators[chNum].eg.sustainLevel); 1109 } else { 1110 operators[chNum].eg.decayRate = 1.0; 1111 } 1112 break; 1113 case OperatorParamNums.Feedback: 1114 const double valF = cast(double)val / uint.max; 1115 operators[chNum].preset.fbL = valF * valF; 1116 break; 1117 case OperatorParamNums.Level: 1118 const double valF = cast(double)val / uint.max; 1119 operators[chNum].preset.outL = valF * valF; 1120 break; 1121 case OperatorParamNums.OpCtrl: 1122 operators[chNum].preset.opCtrl = val; 1123 break; 1124 case OperatorParamNums.Release: 1125 operators[chNum].preset.rel = cast(ubyte)(val >> 25); 1126 if (operators[chNum].preset.rel) { 1127 operators[chNum].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].preset.rel] * 2, sampleRate, 1128 operators[chNum].eg.sustainLevel); 1129 } else { 1130 operators[chNum].eg.releaseRate = 1.0; 1131 } 1132 break; 1133 case OperatorParamNums.ShpA: 1134 operators[chNum].preset.shpA = cast(double)val / uint.max; 1135 break; 1136 case OperatorParamNums.ShpR: 1137 operators[chNum].preset.shpR = cast(double)val / uint.max; 1138 break; 1139 case OperatorParamNums.SusCtrl: 1140 operators[chNum].preset.susCC = cast(ubyte)(val >> 25); 1141 if (operators[chNum].preset.susCC) { 1142 operators[chNum].eg.isPercussive = false; 1143 if (operators[chNum].preset.susCC == 64) { 1144 operators[chNum].eg.sustainControl = 0.0; 1145 } else if (operators[chNum].preset.susCC < 64) { 1146 operators[chNum].eg.sustainControl = -1.0 * 1147 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[operators[chNum].preset.susCC - 1], sampleRate); 1148 } else { 1149 operators[chNum].eg.sustainControl = 1150 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[operators[chNum].preset.susCC - 64], sampleRate); 1151 } 1152 } else { 1153 operators[chNum].eg.isPercussive = true; 1154 operators[chNum].eg.sustainControl = 0.0; 1155 } 1156 break; 1157 case OperatorParamNums.SusLevel: 1158 operators[chNum].eg.sustainLevel = cast(double)val / uint.max; 1159 //Recalculate decay and release rates to new sustain levels 1160 if (operators[chNum].preset.dec) { 1161 operators[chNum].eg.decayRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].preset.dec] * 2, sampleRate, 1162 ADSREnvelopGenerator.maxOutput, operators[chNum].eg.sustainLevel); 1163 } else { 1164 operators[chNum].eg.decayRate = 1.0; 1165 } 1166 if (operators[chNum].preset.rel) { 1167 operators[chNum].eg.releaseRate = calculateRate(ADSR_TIME_TABLE[operators[chNum].preset.rel] * 2, sampleRate, 1168 operators[chNum].eg.sustainLevel); 1169 } else { 1170 operators[chNum].eg.releaseRate = 1.0; 1171 } 1172 break; 1173 case OperatorParamNums.TuneCor: 1174 operators[chNum].preset.tune = val; 1175 1176 break; 1177 case OperatorParamNums.TuneFine: 1178 operators[chNum].preset.tune &= ~uint.max>>7; 1179 operators[chNum].preset.tune |= val>>7; 1180 break; 1181 case OperatorParamNums.VelToLevel: 1182 operators[chNum].preset.outLCtrl[0] = cast(double)val / uint.max; 1183 break; 1184 case OperatorParamNums.MWToLevel: 1185 operators[chNum].preset.outLCtrl[1] = cast(double)val / uint.max; 1186 break; 1187 case OperatorParamNums.LFOToLevel: 1188 operators[chNum].preset.outLCtrl[2] = cast(double)val / uint.max; 1189 break; 1190 case OperatorParamNums.VelToFB: 1191 operators[chNum].preset.fbLCtrl[0] = cast(double)val / uint.max; 1192 break; 1193 case OperatorParamNums.MWToFB: 1194 operators[chNum].preset.fbLCtrl[1] = cast(double)val / uint.max; 1195 break; 1196 case OperatorParamNums.LFOToFB: 1197 operators[chNum].preset.fbLCtrl[2] = cast(double)val / uint.max; 1198 break; 1199 case OperatorParamNums.EEGToFB: 1200 operators[chNum].preset.fbLCtrl[3] = cast(double)val / uint.max; 1201 break; 1202 case OperatorParamNums.VelToShpA: 1203 operators[chNum].preset.shpAVel = cast(double)val / uint.max; 1204 break; 1205 case OperatorParamNums.VelToShpR: 1206 operators[chNum].preset.shpRVel = cast(double)val / uint.max; 1207 break; 1208 case OperatorParamNums.Waveform: 1209 operators[chNum].preset.opCtrl &= ~OpCtrlFlags.WavetableSelect; 1210 operators[chNum].preset.opCtrl |= cast(ubyte)(val >> 25); 1211 break; 1212 default: break; 1213 } 1214 } 1215 switch (paramNum[1]) { 1216 case 0: //Channel operator 0 1217 chNum *= 2; 1218 setOpParam(chNum); 1219 break; 1220 case 1: //Channel operator 1 1221 chNum *= 2; 1222 setOpParam(chNum + 1); 1223 break; 1224 case 2: //Channel common values 1225 switch (paramNum[0]) { 1226 //case ChannelParamNums.ALFO: break; 1227 case ChannelParamNums.Attack: 1228 channels[chNum].preset.atkX = cast(ubyte)(val >> 25); 1229 if (channels[chNum].preset.atkX) { 1230 channels[chNum].eeg.attackRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].preset.atkX], sampleRate); 1231 } else { 1232 channels[chNum].eeg.attackRate = 1.0; 1233 } 1234 break; 1235 case ChannelParamNums.AuxSLA: 1236 const double valF = cast(double)val / uint.max; 1237 channels[chNum].outLevels[2] = valF * valF; 1238 channels[chNum].preset.auxSendA = channels[chNum].outLevels[2]; 1239 break; 1240 case ChannelParamNums.AuxSLB: 1241 const double valF = cast(double)val / uint.max; 1242 channels[chNum].outLevels[2] = valF * valF; 1243 channels[chNum].preset.auxSendB = channels[chNum].outLevels[3]; 1244 break; 1245 case ChannelParamNums.Bal: 1246 channels[chNum].preset.masterBal = cast(double)val / uint.max; 1247 if (channels[chNum].preset.chCtrl & ChCtrlFlags.IndivOutChLev) { 1248 channels[chNum].outLevels[1] = channels[chNum].preset.masterBal * channels[chNum].preset.masterBal; 1249 } else { 1250 channels[chNum].outLevels[0] = channels[chNum].preset.masterVol - channels[chNum].preset.masterBal; 1251 channels[chNum].outLevels[1] = channels[chNum].preset.masterVol - (1.0 - channels[chNum].preset.masterBal); 1252 } 1253 break; 1254 case ChannelParamNums.ChCtrl: 1255 channels[chNum].preset.chCtrl = val; 1256 //mirror operator configuration parameters between paired channels 1257 if (chNum < 8) { 1258 channels[chNum + 8].preset.chCtrl &= ~ChCtrlFlags.ComboModeTest; 1259 channels[chNum + 8].preset.chCtrl |= ChCtrlFlags.ComboModeTest & channels[chNum].preset.chCtrl; 1260 } else { 1261 channels[chNum - 8].preset.chCtrl &= ~ChCtrlFlags.ComboModeTest; 1262 channels[chNum - 8].preset.chCtrl |= ChCtrlFlags.ComboModeTest & channels[chNum].preset.chCtrl; 1263 } 1264 break; 1265 //case ChannelParamNums.ChCtrlL: break; 1266 case ChannelParamNums.Decay: 1267 channels[chNum].preset.decX = cast(ubyte)(val >> 25); 1268 if (channels[chNum].preset.decX) { 1269 channels[chNum].eeg.decayRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].preset.decX] * 2, sampleRate); 1270 } else { 1271 channels[chNum].eeg.decayRate = 1.0; 1272 } 1273 break; 1274 case ChannelParamNums.EEGDetune: 1275 channels[chNum].preset.eegDetuneAm = val; 1276 break; 1277 case ChannelParamNums.MasterVol: 1278 const double valF = cast(double)val / uint.max; 1279 channels[chNum].outLevels[2] = valF * valF; 1280 if (channels[chNum].preset.chCtrl & ChCtrlFlags.IndivOutChLev) { 1281 channels[chNum].outLevels[1] = channels[chNum].preset.masterBal * channels[chNum].preset.masterBal; 1282 } else { 1283 channels[chNum].outLevels[0] = channels[chNum].preset.masterVol - channels[chNum].preset.masterBal; 1284 channels[chNum].outLevels[1] = channels[chNum].preset.masterVol - (1.0 - channels[chNum].preset.masterBal); 1285 } 1286 break; 1287 case ChannelParamNums.PLFO: 1288 channels[chNum].preset.pLFOlevel = cast(double)val / uint.max; 1289 break; 1290 case ChannelParamNums.Release: 1291 channels[chNum].preset.relX = cast(ubyte)(val >> 25); 1292 if (channels[chNum].preset.relX) { 1293 channels[chNum].eeg.releaseRate = calculateRate(ADSR_TIME_TABLE[channels[chNum].preset.relX] * 2, sampleRate); 1294 } else { 1295 channels[chNum].eeg.releaseRate = 1.0; 1296 } 1297 break; 1298 case ChannelParamNums.ShpA: 1299 channels[chNum].preset.shpAX = cast(double)val / uint.max; 1300 break; 1301 case ChannelParamNums.ShpR: 1302 channels[chNum].preset.shpRX = cast(double)val / uint.max; 1303 break; 1304 case ChannelParamNums.SusCtrl: 1305 channels[chNum].preset.susCCX = cast(ubyte)(val >> 25); 1306 if (channels[chNum].preset.susCCX) { 1307 channels[chNum].eeg.isPercussive = false; 1308 if (channels[chNum].preset.susCCX == 64) { 1309 channels[chNum].eeg.sustainControl = 0.0; 1310 } else if (channels[chNum].preset.susCCX < 64) { 1311 channels[chNum].eeg.sustainControl = -1.0 * 1312 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[channels[chNum].preset.susCCX - 1], sampleRate); 1313 } else { 1314 channels[chNum].eeg.sustainControl = 1315 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[channels[chNum].preset.susCCX - 64], sampleRate); 1316 } 1317 } else { 1318 channels[chNum].eeg.isPercussive = true; 1319 channels[chNum].eeg.sustainControl = 0.0; 1320 } 1321 break; 1322 case ChannelParamNums.SusLevel: 1323 channels[chNum].eeg.sustainLevel = cast(double)val / uint.max; 1324 channels[chNum].preset.susLevel = channels[chNum].eeg.sustainLevel; 1325 break; 1326 case ChannelParamNums.RingMod: 1327 channels[chNum].preset.rmAmount = val>>16; 1328 break; 1329 case ChannelParamNums.EEGToLeft: 1330 const double valF = cast(double)val / uint.max; 1331 channels[chNum].preset.eegLevels[0] = valF * valF; 1332 break; 1333 case ChannelParamNums.EEGToRight: 1334 const double valF = cast(double)val / uint.max; 1335 channels[chNum].preset.eegLevels[1] = valF * valF; 1336 break; 1337 case ChannelParamNums.EEGToAuxA: 1338 const double valF = cast(double)val / uint.max; 1339 channels[chNum].preset.eegLevels[2] = valF * valF; 1340 break; 1341 case ChannelParamNums.EEGToAuxB: 1342 const double valF = cast(double)val / uint.max; 1343 channels[chNum].preset.eegLevels[3] = valF * valF; 1344 break; 1345 case ChannelParamNums.LFOToLeft: 1346 const double valF = cast(double)val / uint.max; 1347 channels[chNum].preset.aLFOlevels[0] = valF * valF; 1348 1349 break; 1350 case ChannelParamNums.LFOToRight: 1351 const double valF = cast(double)val / uint.max; 1352 channels[chNum].preset.aLFOlevels[1] = valF * valF; 1353 break; 1354 case ChannelParamNums.LFOToAuxA: 1355 const double valF = cast(double)val / uint.max; 1356 channels[chNum].preset.aLFOlevels[2] = valF * valF; 1357 break; 1358 case ChannelParamNums.LFOToAuxB: 1359 const double valF = cast(double)val / uint.max; 1360 channels[chNum].preset.aLFOlevels[3] = valF * valF; 1361 break; 1362 default: 1363 break; 1364 } 1365 break; 1366 case 16: //LFO and master filter settings 1367 void setFilterFreq(int num) @nogc @safe pure nothrow { 1368 const double valF = cast(double)val / uint.max; 1369 filterCtrl[num] = valF * valF * 20_000; 1370 1371 } 1372 void setFilterQ(int num) @nogc @safe pure nothrow { 1373 const double valF = cast(double)val / uint.max; 1374 filterCtrl[num] = valF * 2; 1375 } 1376 switch (paramNum[0]) { 1377 case GlobalParamNums.PLFORate: 1378 double valF; 1379 valF = cast(double)val / uint.max; 1380 valF *= 16; 1381 const double cycleLen = sampleRate / (1.0 / valF); 1382 pLFORate = cast(int)(cycleLen * ((1<<20) / 1024.0) * bufferSize); 1383 break; 1384 case GlobalParamNums.PLFOWF: 1385 lfoWaveform[0] = cast(ubyte)(val >> 25); 1386 break; 1387 case GlobalParamNums.ALFORate: 1388 double valF; 1389 valF = cast(double)val / uint.max; 1390 valF *= 16; 1391 const double cycleLen = sampleRate / (1.0 / valF); 1392 aLFORate = cast(int)(cycleLen * ((1<<20) / 1024.0)); 1393 break; 1394 case GlobalParamNums.ALFOWF: 1395 lfoWaveform[1] = cast(ubyte)(val >> 25); 1396 break; 1397 case GlobalParamNums.FilterLCFreq: 1398 setFilterFreq(0); 1399 break; 1400 case GlobalParamNums.FilterLCQ: 1401 setFilterQ(1); 1402 break; 1403 case GlobalParamNums.FilterRCFreq: 1404 setFilterFreq(2); 1405 break; 1406 case GlobalParamNums.FilterRCQ: 1407 setFilterQ(3); 1408 break; 1409 case GlobalParamNums.FilterACFreq: 1410 setFilterFreq(4); 1411 break; 1412 case GlobalParamNums.FilterACQ: 1413 setFilterQ(5); 1414 break; 1415 case GlobalParamNums.FilterBCFreq: 1416 setFilterFreq(6); 1417 break; 1418 case GlobalParamNums.FilterBCQ: 1419 setFilterQ(7); 1420 break; 1421 default: 1422 break; 1423 } 1424 break; 1425 default: break; 1426 } 1427 } 1428 /** 1429 * Renders the current audio frame. 1430 * 1431 * input: the input buffers if any, null if none. 1432 * output: the output buffers if any, null if none. 1433 * 1434 * NOTE: Buffers must have matching sizes. 1435 */ 1436 public override void renderFrame(float*[] input, float*[] output) @nogc nothrow { 1437 //Generate aLFO table 1438 for (int i ; i < bufferSize ; i++) { 1439 aLFOBuf[i] = (wavetables[lfoWaveform[1]][(aLFOPos>>20) & 1023] - short.min) * (1 / cast(float)(ushort.max)); 1440 aLFOPos += aLFORate; 1441 } 1442 //Generate pLFO out 1443 { 1444 pLFOOut = (wavetables[lfoWaveform[0]][(pLFOPos>>20) & 1023]) * (1 / cast(float)(short.max)); 1445 pLFOPos += pLFORate; 1446 } 1447 //Render each channel 1448 foreach (size_t i, ChFun fun ; chDeleg) { 1449 fun(cast(int)i, bufferSize); 1450 } 1451 //Filter and mix outputs 1452 float*[4] outBuf; 1453 for (ubyte i, j ; i < 4 ; i++) { 1454 if (enabledOutputs.has(i)) { 1455 outBuf[i] = output[j]; 1456 j++; 1457 } else { 1458 outBuf[i] = dummyBuf.ptr; 1459 } 1460 } 1461 const __m128 b0_a0 = filterVals[3] / filterVals[0], b1_a0 = filterVals[4] / filterVals[0], 1462 b2_a0 = filterVals[5] / filterVals[0], a1_a0 = filterVals[1] / filterVals[0], a2_a0 = filterVals[2] / filterVals[0]; 1463 for (int i ; i < bufferSize ; i++) { 1464 __m128 input0 = _mm_load_ps(initBuffers.ptr + (i * 4)); 1465 input0 *= __m128(mixdownVal); 1466 input0 = _mm_max_ps(input0, __m128(-1.0)); 1467 input0 = _mm_min_ps(input0, __m128(1.0)); 1468 __m128 output0 = b0_a0 * input0 + b1_a0 * filterVals[6] + b2_a0 * filterVals[7] - a1_a0 * filterVals[8] - 1469 a2_a0 * filterVals[9]; 1470 for (int j ; j < 4 ; j++) 1471 outBuf[j][i] += output0[j]; 1472 filterVals[7] = filterVals[6]; 1473 filterVals[6] = input0; 1474 filterVals[9] = filterVals[8]; 1475 filterVals[8] = output0; 1476 } 1477 } 1478 ///Updates an operator for a cycle 1479 ///chCtrl index notation: 0: velocity, 1: modulation wheel, 2: Amplitude LFO, 3: Extra Envelop Generator 1480 pragma(inline, true) 1481 protected final void updateOperator(ref Operator op, __m128 chCtrl) @nogc @safe pure nothrow { 1482 op.output = wavetables[op.preset.opCtrl & OpCtrlFlags.WavetableSelect][(op.pos>>20 + op.input>>4 + op.feedback>>3) 1483 & 0x3_FF]; 1484 const double egOut = op.eg.shp(op.eg.position == ADSREnvelopGenerator.Stage.Attack ? op.shpA0 : op.shpR0); 1485 const double out0 = op.output; 1486 __m128 outCtrl = (op.preset.outLCtrl * chCtrl) + (__m128(1.0) - (__m128(1.0) * op.preset.outLCtrl)); 1487 __m128 fbCtrl = (op.preset.fbLCtrl * chCtrl) + (__m128(1.0) - (__m128(1.0) * op.preset.fbLCtrl)); 1488 const double out1 = out0 * egOut; 1489 //vel = op.opCtrl & OpCtrlFlags.VelNegative ? 1.0 - vel : vel; 1490 op.feedback = cast(int)((op.preset.opCtrl & OpCtrlFlags.FBMode ? out0 : out1) * op.preset.fbL * fbCtrl[0] * fbCtrl[1] * 1491 fbCtrl[2] * fbCtrl[3]); 1492 //op.feedback *= op.opCtrl & OpCtrlFlags.FBNeg ? -1 : 1; 1493 op.output_0 = cast(int)(out1 * op.preset.outL * outCtrl[0] * outCtrl[1] * outCtrl[2]); 1494 op.pos += op.step; 1495 //op.input = 0; 1496 op.eg.advance(); 1497 } 1498 ///Macro for channel update constants that need to be calculated once per frame 1499 ///Kept in at one place to make updates easier and more consistent 1500 static immutable string CHNL_UPDATE_CONSTS = 1501 q{ 1502 const int opOffset = chNum * 2; 1503 __m128 aLFOOutMW = __m128(channels[chNum].preset.chCtrl & ChCtrlFlags.MWToTrem ? 1504 chCtrls[chNum].modwheel : 1.0); 1505 const float auxSendAmMW = (channels[chNum].preset.chCtrl & ChCtrlFlags.MWToAux ? 1506 chCtrls[chNum].modwheel : 1.0); 1507 __m128 opCtrl0, opCtrl1, mwAuxCtrl; 1508 opCtrl0[0] = operators[opOffset].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 1509 chCtrls[chNum].velocity; 1510 opCtrl1[0] = operators[opOffset + 1].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 1511 chCtrls[chNum].velocity; 1512 opCtrl0[1] = operators[opOffset].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : 1513 chCtrls[chNum].modwheel; 1514 opCtrl1[1] = operators[opOffset + 1].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : 1515 chCtrls[chNum].modwheel; 1516 mwAuxCtrl[0] = 1.0; 1517 mwAuxCtrl[1] = 1.0; 1518 mwAuxCtrl[2] = auxSendAmMW; 1519 mwAuxCtrl[3] = auxSendAmMW; 1520 const float lfopan = (channels[chNum].preset.chCtrl & ChCtrlFlags.LFOPan ? 1.0 : 0); 1521 const float eegpan = (channels[chNum].preset.chCtrl & ChCtrlFlags.EEGPan ? 1.0 : 0); 1522 }; 1523 ///Macro for channel update constants that need to be calculated once per frame, for combined channels' second half 1524 ///Kept in at one place to make updates easier and more consistent 1525 static immutable string CHNL_UPDATE_CONSTS0 = 1526 q{ 1527 __m128 opCtrl2, opCtrl3; 1528 opCtrl2[0] = operators[opOffset + 16].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 1529 chCtrls[chNum].velocity; 1530 opCtrl3[0] = operators[opOffset + 17].preset.opCtrl & OpCtrlFlags.VelNeg ? 1 - chCtrls[chNum].velocity : 1531 chCtrls[chNum].velocity; 1532 opCtrl2[1] = operators[opOffset + 16].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : 1533 chCtrls[chNum].modwheel; 1534 opCtrl3[1] = operators[opOffset + 17].preset.opCtrl & OpCtrlFlags.MWNeg ? 1 - chCtrls[chNum].modwheel : 1535 chCtrls[chNum].modwheel; 1536 const float eegpan0 = (channels[chNum + 8].preset.chCtrl & ChCtrlFlags.EEGPan ? 1.0 : 0); 1537 }; 1538 ///Macro for channel update constants that need to be calculated for each cycle 1539 ///Kept in at one place to make updates easier and more consistent 1540 static immutable string CHNL_UPDATE_CONSTS_CYCL = 1541 q{ 1542 const float eegOut = channels[chNum].eeg.shp(channels[chNum].eeg.position == 1543 ADSREnvelopGenerator.Stage.Attack ? channels[chNum].preset.shpAX : channels[chNum].preset.shpRX); 1544 __m128 eegToMast = __m128(eegOut), lfoToMast = __m128(aLFOBuf[i]); 1545 eegToMast[0] = abs(eegpan - eegToMast[0]); 1546 lfoToMast[0] = abs(lfopan - lfoToMast[0]); 1547 opCtrl0[2] = aLFOBuf[i]; 1548 opCtrl1[2] = aLFOBuf[i]; 1549 opCtrl0[3] = eegOut; 1550 opCtrl1[3] = eegOut; 1551 }; 1552 1553 ///Macro for channel update constants that need to be calculated for each cycle for combined channels' second half 1554 ///Kept in at one place to make updates easier and more consistent 1555 static immutable string CHNL_UPDATE_CONSTS_CYCL0 = 1556 q{ 1557 const float eegOut0 = channels[chNum + 8].eeg.shp(channels[chNum + 8].eeg.position == 1558 ADSREnvelopGenerator.Stage.Attack ? channels[chNum + 8].preset.shpAX : 1559 channels[chNum + 8].preset.shpRX); 1560 __m128 eegToMast0 = __m128(eegOut0); 1561 eegToMast0[0] = abs(eegpan0 - eegToMast0[0]); 1562 opCtrl2[2] = aLFOBuf[i]; 1563 opCtrl3[2] = aLFOBuf[i]; 1564 opCtrl2[3] = eegOut0; 1565 opCtrl3[3] = eegOut0; 1566 }; 1567 1568 ///Macro for output mixing 1569 static immutable string CHNL_UPDATE_MIX = 1570 q{ 1571 __m128 outlevels = channels[chNum].outLevels * mwAuxCtrl; 1572 outlevels *= (channels[chNum].preset.eegLevels * eegToMast) + (__m128(1.0) - (__m128(1.0) * 1573 channels[chNum].preset.eegLevels)); 1574 outlevels *= (channels[chNum].preset.aLFOlevels * lfoToMast) + (__m128(1.0) - (__m128(1.0) * 1575 channels[chNum].preset.aLFOlevels)); 1576 _mm_store1_ps(initBuffers.ptr + (i<<2), _mm_load_ps(initBuffers.ptr + (i<<2)) + outlevels * 1577 _mm_cvtepi32_ps(outSum)); 1578 }; 1579 ///Macro for output mixing in case of combo modes 1580 static immutable string CHNL_UPDATE_MIX0 = 1581 q{ 1582 __m128 outlevels = channels[chNum].outLevels * mwAuxCtrl; 1583 outlevels *= (channels[chNum].eegLevels * eegToMast) + (__m128(1.0) - (__m128(1.0) * 1584 channels[chNum].eegLevels)); 1585 outlevels *= (channels[chNum + 8].eegLevels * eegToMast0) + (__m128(1.0) - 1586 (__m128(1.0) * channels[chNum + 8].eegLevels)); 1587 outlevels *= (channels[chNum].aLFOlevels * lfoToMast) + (__m128(1.0) - (__m128(1.0) * 1588 channels[chNum].aLFOlevels); 1589 _mm_store1_ps(initBuffers.ptr + (i<<2), _mm_load_ps(initBuffers.ptr + (i<<2)) + outlevels * 1590 _mm_cvtepi32_ps(outSum)); 1591 }; 1592 1593 1594 ///Algorithm Mode 0/0 (Serial) 1595 protected void updateChannelM00(int chNum, size_t length) @nogc pure nothrow { 1596 mixin(CHNL_UPDATE_CONSTS); 1597 for (size_t i ; i < length ; i++) { 1598 channels[chNum].eeg.advance(); 1599 mixin(CHNL_UPDATE_CONSTS_CYCL); 1600 updateOperator(operators[opOffset], opCtrl0); 1601 operators[opOffset + 1].input = operators[opOffset].output_0; 1602 updateOperator(operators[opOffset + 1], opCtrl1); 1603 //const int outSum = operators[opOffset].output_0; 1604 __m128i outSum = __m128i(operators[opOffset + 1].output_0); 1605 mixin(CHNL_UPDATE_MIX); 1606 } 1607 } 1608 ///Algorithm Mode0/1 (Parallel) 1609 protected void updateChannelM01(int chNum, size_t length) @nogc pure nothrow { 1610 mixin(CHNL_UPDATE_CONSTS); 1611 for (size_t i ; i < length ; i++) { 1612 mixin(CHNL_UPDATE_CONSTS_CYCL); 1613 updateOperator(operators[opOffset], opCtrl0); 1614 updateOperator(operators[opOffset + 1], opCtrl1); 1615 //const int outSum = operators[opOffset].output_0 + operators[opOffset + 1].output_0; 1616 __m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 1617 ((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].preset.rmAmount)>>16); 1618 mixin(CHNL_UPDATE_MIX); 1619 channels[chNum].eeg.advance(); 1620 } 1621 } 1622 ///Algorithm Mode1/00 ([S0]->[S1]->[P0]->[P1]) 1623 protected void updateChannelM100(int chNum, size_t length) @nogc pure nothrow { 1624 mixin(CHNL_UPDATE_CONSTS); 1625 mixin(CHNL_UPDATE_CONSTS0); 1626 for (size_t i ; i < length ; i++) { 1627 mixin(CHNL_UPDATE_CONSTS_CYCL); 1628 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1629 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1630 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1631 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1632 operators[opOffset].input = operators[opOffset + 17].output_0; 1633 updateOperator(operators[opOffset], opCtrl0); //P0 1634 operators[opOffset + 1].input = operators[opOffset].output_0; 1635 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1636 //const int outSum = operators[opOffset + 1].output_0; 1637 __m128i outSum = __m128i(operators[opOffset + 1].output_0); 1638 mixin(CHNL_UPDATE_MIX); 1639 channels[chNum].eeg.advance(); 1640 channels[chNum + 8].eeg.advance(); 1641 } 1642 } 1643 ///Dummy algorithm for combined channels 1644 protected void updateChannelMD(int chNum, size_t length) @nogc pure nothrow { 1645 1646 } 1647 /** 1648 Algorithm Mode1/10 1649 [S0]\ 1650 ->[P0]->[P1]-> 1651 [S1]/ 1652 */ 1653 protected void updateChannelM110(int chNum, size_t length) @nogc pure nothrow { 1654 mixin(CHNL_UPDATE_CONSTS); 1655 mixin(CHNL_UPDATE_CONSTS0); 1656 for (size_t i ; i < length ; i++) { 1657 mixin(CHNL_UPDATE_CONSTS_CYCL); 1658 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1659 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1660 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1661 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1662 operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0; 1663 updateOperator(operators[opOffset], opCtrl0); //P0 1664 operators[opOffset + 1].input = operators[opOffset].output_0; 1665 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1666 //const int outSum = operators[opOffset + 1].output_0; 1667 __m128i outSum = __m128i(operators[opOffset + 1].output_0); 1668 mixin(CHNL_UPDATE_MIX); 1669 channels[chNum].eeg.advance(); 1670 channels[chNum + 8].eeg.advance(); 1671 } 1672 } 1673 /** 1674 Algorithm Mode1/01 1675 [S0]->[S1]->[P0]-> 1676 [P1]-> 1677 */ 1678 protected void updateChannelM101(int chNum, size_t length) @nogc pure nothrow { 1679 mixin(CHNL_UPDATE_CONSTS); 1680 mixin(CHNL_UPDATE_CONSTS0); 1681 for (size_t i ; i < length ; i++) { 1682 mixin(CHNL_UPDATE_CONSTS_CYCL); 1683 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1684 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1685 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1686 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1687 operators[opOffset].input = operators[opOffset + 17].output_0; 1688 updateOperator(operators[opOffset], opCtrl0); //P0 1689 //operators[opOffset + 1].input = operators[opOffset].output_0; 1690 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1691 //const int outSum = operators[opOffset + 1].output_0; 1692 __m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 1693 ((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].preset.rmAmount)>>16); 1694 mixin(CHNL_UPDATE_MIX); 1695 channels[chNum].eeg.advance(); 1696 channels[chNum + 8].eeg.advance(); 1697 } 1698 } 1699 /** 1700 Algorithm Mode1/11 1701 [S0]\ 1702 ->[P0]-> 1703 [S1]/ [P1]-> 1704 */ 1705 protected void updateChannelM111(int chNum, size_t length) @nogc pure nothrow { 1706 mixin(CHNL_UPDATE_CONSTS); 1707 mixin(CHNL_UPDATE_CONSTS0); 1708 for (size_t i ; i < length ; i++) { 1709 mixin(CHNL_UPDATE_CONSTS_CYCL); 1710 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1711 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1712 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1713 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1714 operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0; 1715 updateOperator(operators[opOffset], opCtrl0); //P0 1716 //operators[opOffset + 1].input = operators[opOffset].output_0; 1717 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1718 //const int outSum = operators[opOffset + 1].output_0; 1719 __m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 1720 ((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].preset.rmAmount)>>16); 1721 mixin(CHNL_UPDATE_MIX); 1722 channels[chNum].eeg.advance(); 1723 channels[chNum + 8].eeg.advance(); 1724 } 1725 } 1726 /** 1727 Algorithm Mode2/00 1728 [S0]->[S1]\ 1729 ->[P1]-> 1730 [P0]/ 1731 */ 1732 protected void updateChannelM200(int chNum, size_t length) @nogc pure nothrow { 1733 mixin(CHNL_UPDATE_CONSTS); 1734 mixin(CHNL_UPDATE_CONSTS0); 1735 for (size_t i ; i < length ; i++) { 1736 mixin(CHNL_UPDATE_CONSTS_CYCL); 1737 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1738 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1739 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1740 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1741 //operators[opOffset].input = operators[opOffset + 17].output_0; 1742 updateOperator(operators[opOffset], opCtrl0); //P0 1743 operators[opOffset + 1].input = operators[opOffset].output_0 + operators[opOffset + 17].output_0; 1744 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1745 //const int outSum = operators[opOffset + 1].output_0; 1746 __m128i outSum = __m128i(operators[opOffset + 1].output_0); 1747 mixin(CHNL_UPDATE_MIX); 1748 channels[chNum].eeg.advance(); 1749 channels[chNum + 8].eeg.advance(); 1750 } 1751 } 1752 /** 1753 Algorithm Mode2/10 1754 [S0]\ 1755 [S1]-->[P1]-> 1756 [P0]/ 1757 */ 1758 protected void updateChannelM210(int chNum, size_t length) @nogc pure nothrow { 1759 mixin(CHNL_UPDATE_CONSTS); 1760 mixin(CHNL_UPDATE_CONSTS0); 1761 for (size_t i ; i < length ; i++) { 1762 mixin(CHNL_UPDATE_CONSTS_CYCL); 1763 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1764 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1765 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1766 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1767 //operators[opOffset].input = operators[opOffset + 17].output_0; 1768 updateOperator(operators[opOffset], opCtrl0); //P0 1769 operators[opOffset + 1].input = operators[opOffset].output_0 + operators[opOffset + 17].output_0 + 1770 operators[opOffset + 16].output_0; 1771 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1772 //const int outSum = operators[opOffset + 1].output_0; 1773 __m128i outSum = __m128i(operators[opOffset + 1].output_0); 1774 mixin(CHNL_UPDATE_MIX); 1775 channels[chNum].eeg.advance(); 1776 channels[chNum + 8].eeg.advance(); 1777 } 1778 } 1779 /** 1780 Algorithm Mode2/01 1781 /[P0]-> 1782 [S0]->[S1] 1783 \[P1]-> 1784 */ 1785 protected void updateChannelM201(int chNum, size_t length) @nogc pure nothrow { 1786 mixin(CHNL_UPDATE_CONSTS); 1787 mixin(CHNL_UPDATE_CONSTS0); 1788 for (size_t i ; i < length ; i++) { 1789 mixin(CHNL_UPDATE_CONSTS_CYCL); 1790 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1791 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1792 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1793 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1794 operators[opOffset].input = operators[opOffset + 17].output_0; 1795 updateOperator(operators[opOffset], opCtrl0); //P0 1796 operators[opOffset + 1].input = operators[opOffset + 17].output_0; 1797 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1798 //const int outSum = operators[opOffset + 1].output_0; 1799 __m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset].output_0 + 1800 ((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].preset.rmAmount)>>16); 1801 mixin(CHNL_UPDATE_MIX); 1802 channels[chNum].eeg.advance(); 1803 channels[chNum + 8].eeg.advance(); 1804 } 1805 } 1806 /** 1807 Algorithm Mode2/11 1808 [S0]\ /[P0]-> 1809 - 1810 [S1]/ \[P1]-> 1811 */ 1812 protected void updateChannelM211(int chNum, size_t length) @nogc pure nothrow { 1813 mixin(CHNL_UPDATE_CONSTS); 1814 mixin(CHNL_UPDATE_CONSTS0); 1815 for (size_t i ; i < length ; i++) { 1816 mixin(CHNL_UPDATE_CONSTS_CYCL); 1817 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1818 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1819 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1820 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1821 operators[opOffset].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0; 1822 updateOperator(operators[opOffset], opCtrl0); //P0 1823 operators[opOffset + 1].input = operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0; 1824 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1825 //const int outSum = operators[opOffset + 1].output_0; 1826 __m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset].output_0 + 1827 ((operators[opOffset].output_0 * operators[opOffset + 1].output)>>16 * channels[chNum].preset.rmAmount)>>16); 1828 mixin(CHNL_UPDATE_MIX); 1829 channels[chNum].eeg.advance(); 1830 channels[chNum + 8].eeg.advance(); 1831 } 1832 } 1833 /** 1834 Algorithm Mode3/00 1835 [S0]->[S1]-> 1836 [P0]->[P1]-> 1837 */ 1838 protected void updateChannelM300(int chNum, size_t length) @nogc pure nothrow { 1839 mixin(CHNL_UPDATE_CONSTS); 1840 mixin(CHNL_UPDATE_CONSTS0); 1841 for (size_t i ; i < length ; i++) { 1842 mixin(CHNL_UPDATE_CONSTS_CYCL); 1843 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1844 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1845 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1846 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1847 //operators[opOffset].input = operators[opOffset + 17].output_0; 1848 updateOperator(operators[opOffset], opCtrl0); //P0 1849 operators[opOffset + 1].input = operators[opOffset].output_0; 1850 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1851 //const int outSum = operators[opOffset + 1].output_0; 1852 __m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset + 17].output_0 + 1853 ((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].preset.rmAmount)>>16); 1854 mixin(CHNL_UPDATE_MIX); 1855 channels[chNum].eeg.advance(); 1856 channels[chNum + 8].eeg.advance(); 1857 } 1858 } 1859 /** 1860 Algorithm Mode3/10 1861 [S0]-> 1862 [S1]-> 1863 [P0]->[P1]-> 1864 */ 1865 protected void updateChannelM310(int chNum, size_t length) @nogc pure nothrow { 1866 mixin(CHNL_UPDATE_CONSTS); 1867 mixin(CHNL_UPDATE_CONSTS0); 1868 for (size_t i ; i < length ; i++) { 1869 mixin(CHNL_UPDATE_CONSTS_CYCL); 1870 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1871 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1872 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1873 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1874 //operators[opOffset].input = operators[opOffset + 17].output_0; 1875 updateOperator(operators[opOffset], opCtrl0); //P0 1876 operators[opOffset + 1].input = operators[opOffset].output_0; 1877 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1878 //const int outSum = operators[opOffset + 1].output_0; 1879 __m128i outSum = __m128i(operators[opOffset + 1].output_0 + operators[opOffset + 17].output_0 + 1880 operators[opOffset + 16].output_0 + 1881 ((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].preset.rmAmount)>>16); 1882 mixin(CHNL_UPDATE_MIX); 1883 channels[chNum].eeg.advance(); 1884 channels[chNum + 8].eeg.advance(); 1885 } 1886 } 1887 /** 1888 Algorithm Mode3/01 1889 />[S1]-> 1890 [S0]->[P0]-> 1891 \>[P1]-> 1892 */ 1893 protected void updateChannelM301(int chNum, size_t length) @nogc pure nothrow { 1894 mixin(CHNL_UPDATE_CONSTS); 1895 mixin(CHNL_UPDATE_CONSTS0); 1896 for (size_t i ; i < length ; i++) { 1897 mixin(CHNL_UPDATE_CONSTS_CYCL); 1898 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1899 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1900 operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1901 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1902 operators[opOffset].input = operators[opOffset + 16].output_0; 1903 updateOperator(operators[opOffset], opCtrl0); //P0 1904 operators[opOffset + 1].input = operators[opOffset + 16].output_0; 1905 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1906 //const int outSum = operators[opOffset + 1].output_0; 1907 __m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset + 1].output_0 + 1908 operators[opOffset + 17].output_0 + 1909 ((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].preset.rmAmount)>>16); 1910 mixin(CHNL_UPDATE_MIX); 1911 channels[chNum].eeg.advance(); 1912 channels[chNum + 8].eeg.advance(); 1913 } 1914 } 1915 /** 1916 Algorithm Mode3/11 1917 [S0]-> 1918 [S1]-> 1919 [P0]-> 1920 [P1]-> 1921 */ 1922 protected void updateChannelM311(int chNum, size_t length) @nogc pure nothrow { 1923 mixin(CHNL_UPDATE_CONSTS); 1924 mixin(CHNL_UPDATE_CONSTS0); 1925 for (size_t i ; i < length ; i++) { 1926 mixin(CHNL_UPDATE_CONSTS_CYCL); 1927 mixin(CHNL_UPDATE_CONSTS_CYCL0); 1928 updateOperator(operators[opOffset + 16], opCtrl2); //S0 1929 //operators[opOffset + 17].input = operators[opOffset + 16].output_0; 1930 updateOperator(operators[opOffset + 17], opCtrl3); //S1 1931 //operators[opOffset].input = operators[opOffset + 17].output_0; 1932 updateOperator(operators[opOffset], opCtrl0); //P0 1933 //operators[opOffset + 1].input = operators[opOffset].output_0; 1934 updateOperator(operators[opOffset + 1], opCtrl1); //P1 1935 //const int outSum = operators[opOffset + 1].output_0; 1936 __m128i outSum = __m128i(operators[opOffset].output_0 + operators[opOffset].output_0 + 1937 operators[opOffset + 17].output_0 + operators[opOffset + 16].output_0 + 1938 ((operators[opOffset + 1].output_0 * operators[opOffset + 17].output)>>16 * channels[chNum].preset.rmAmount)>>16); 1939 mixin(CHNL_UPDATE_MIX); 1940 channels[chNum].eeg.advance(); 1941 channels[chNum + 8].eeg.advance(); 1942 } 1943 } 1944 1945 /** 1946 * Restores a parameter to the given preset. 1947 * Returns an errorcode on failure. 1948 */ 1949 public override int recallParam_int(uint presetID, uint paramID, int value) @nogc nothrow { 1950 return 0; 1951 } 1952 /** 1953 * Restores a parameter to the given preset. 1954 * Returns an errorcode on failure. 1955 */ 1956 public override int recallParam_uint(uint presetID, uint paramID, uint value) @nogc nothrow { 1957 return 0; 1958 } 1959 /** 1960 * Restores a parameter to the given preset. 1961 * Returns an errorcode on failure. 1962 */ 1963 public override int recallParam_double(uint presetID, uint paramID, double value) @nogc nothrow { 1964 return 0; 1965 } 1966 /** 1967 * Restores a parameter to the given preset. 1968 * Returns an errorcode on failure. 1969 */ 1970 public override int recallParam_string(uint presetID, uint paramID, string value) @nogc nothrow { 1971 return 0; 1972 } 1973 }