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