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 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 bufferHalf = 1<<3, 146 } 147 /** 148 Defines a single channel's statuses. 149 */ 150 protected struct Channel { 151 //int[256] decoderBuffer; 152 int[256] decoderBuffer; ///Stores decoded samples. 153 Preset presetCopy; ///The copy of the preset. 154 DecoderWorkpad decoderWorkpad; ///Stores the current state of the decoder. 155 DecoderWorkpad savedDWState; ///The state of the decoder when the beginning of the looppoint has been reached. 156 WavemodWorkpad waveModWorkpad; ///Stores the current state of the wave modulator. 157 double freqRatio; ///Sampling-to-playback frequency ratio, with pitch bend, LFO, and envGen applied. 158 ulong outPos; ///Position in decoded amount, including fractions 159 ulong samplesHave; ///Amount of decoded samples with fractions offsetted 160 //uint decodeAm; ///Decoded amount, mainly used to determine output buffer half 161 uint jumpAm; ///Jump amount for current sample, calculated from freqRatio. 162 //WavemodWorkpad savedWMWState; ///The state of the wave modulator when the beginning of the looppoint has been reached. 163 ADSREnvelopGenerator envGen; ///Channel envelop generator. 164 165 ubyte currNote = 255; ///The currently played note + Bit 8 indicates suspension. 166 ubyte presetNum; ///Selected preset. 167 ushort bankNum; ///Bank select number. 168 uint status; ///Channel status flags. Bit 1: Note on, Bit 2: Sample run out approaching, Bit 3: In loop, Bit 4: Bufferhalf 169 170 float pitchBend = 0; ///Current amount of pitch bend. 171 172 float velocity = 0; ///Velocity normalized between 0 and 1 173 float modWheel = 0; ///Modulation wheel normalized between 0 and 1 174 175 float currShpA; ///The current attack shape 176 float currShpR; ///The current release shape 177 /** 178 Decodes one more block worth of samples, depending on internal state. 179 Params: 180 * sa = The sample's assigned data. 181 * slmp = The sample to be decoded. 182 Bugs: 183 * Upon pitchbend and when looping, it can cause buffer alignment issues, which in turn will cause audio glitches. FIXED! 184 */ 185 void decodeMore(ref SampleAssignment sa, ref Sample slmp) @nogc nothrow pure { 186 //Check if sample runout have happened already, stop decoding if yes. 187 if (status & ChannelStatusFlags.sampleRunout) { 188 currNote = 255; 189 } 190 if (currNote == 255) { 191 return; 192 } 193 //Determine how much samples we will need. 194 sizediff_t samplesNeeded = 128; 195 //Determine offset based on which cycle we will need 196 const size_t offset = status & ChannelStatusFlags.bufferHalf ? 128 : 0; 197 //Determine if note is on. 198 const bool keyOn = (status & 1) == 1; 199 //Determine if sample is looping 200 const bool isLooping = (sa.loopBegin != -1 && sa.loopEnd != -1) && ((sa.loopEnd - sa.loopBegin) > 0) && keyOn; 201 202 //Special Case 1: sample is running out, and there are no looppoints or note isn't on. 203 if (!isLooping && (decoderWorkpad.pos + samplesNeeded >= slmp.samplesLength())) { 204 samplesNeeded -= decoderWorkpad.pos + samplesNeeded - slmp.samplesLength(); 205 status |= ChannelStatusFlags.sampleRunout; 206 for (size_t i = samplesNeeded ; i < 128 ; i++) 207 decoderBuffer[offset + i] = 0; 208 } 209 size_t dPos = offset; //Decoder position 210 while (samplesNeeded > 0) { 211 //Special Case 2: sample might enter the beginning or the end of the loop. 212 //If loop is short enough, it can happen multiple times 213 const bool loopBegin = isLooping && (decoderWorkpad.pos + samplesNeeded >= sa.loopBegin) && 214 !(status & ChannelStatusFlags.inLoop); 215 const bool loopEnd = isLooping && (decoderWorkpad.pos + samplesNeeded >= sa.loopEnd); 216 const size_t samplesToDecode = loopBegin ? samplesNeeded - (sa.loopBegin - decoderWorkpad.pos) : (loopEnd ? 217 samplesNeeded - (sa.loopEnd - decoderWorkpad.pos) : samplesNeeded);//Determine how much saples will we need 218 slmp.decode(slmp.sampleData, decoderBuffer[dPos..dPos + samplesToDecode], decoderWorkpad);//Decode some amount of samples 219 if (loopBegin) {//Save decoder workpad state on the beginning of the loop (important for ADPCM!) 220 status |= ChannelStatusFlags.inLoop; 221 savedDWState = decoderWorkpad; 222 } else if (loopEnd) {//Restore decoder and other necessary statuses. 223 decoderWorkpad = savedDWState; 224 } 225 samplesNeeded -= samplesToDecode; 226 dPos += samplesToDecode; 227 samplesHave += (samplesToDecode<<24); 228 } 229 status ^= ChannelStatusFlags.bufferHalf; 230 //decodeAm++; //Flip decode buffer 231 } 232 ///Calculates jump amount for the sample. 233 void calculateJumpAm(int sampleRate, float lfoOut) @nogc @safe pure nothrow { 234 freqRatio = sampleRate / bendFreq(presetCopy.sampleMapping[currNote & 127].baseFreq, pitchBend + 235 (presetCopy.vibrAm * lfoOut * (presetCopy.flags & PresetFlags.modwheelToLFO ? modWheel : 1.0)) + 236 (presetCopy.adsrToDetune * 237 envGen.shp(envGen.position == ADSREnvelopGenerator.Stage.Attack ? currShpA : currShpR))); 238 jumpAm = cast(uint)((1<<24) / freqRatio); 239 } 240 ///Resets all internal states. 241 void reset() @nogc @safe pure nothrow { 242 outPos = 0; 243 status = 0; 244 status &= ~ChannelStatusFlags.bufferHalf; 245 //decodeAm = 0; 246 samplesHave = 0; 247 decoderWorkpad = DecoderWorkpad.init; 248 savedDWState = DecoderWorkpad.init; 249 waveModWorkpad = WavemodWorkpad.init; 250 } 251 ///Recalculates shape params. 252 void setShpVals(float vel = 1.0) @nogc @safe pure nothrow { 253 currShpA = presetCopy.eAtkShp - (presetCopy.velToAtkShp * presetCopy.eAtkShp) + 254 (presetCopy.velToAtkShp * presetCopy.eAtkShp * vel); 255 currShpR = presetCopy.eRelShp - (presetCopy.velToRelShp * presetCopy.eRelShp) + 256 (presetCopy.velToRelShp * presetCopy.eRelShp * vel); 257 } 258 void setADSR(int sampleRate) @nogc @safe pure nothrow { 259 envGen.sustainLevel = presetCopy.eSusLev; 260 if (presetCopy.eAtk) { 261 envGen.attackRate = calculateRate(ADSR_TIME_TABLE[presetCopy.eAtk], sampleRate); 262 } else { 263 envGen.attackRate = 1.0; 264 } 265 if (presetCopy.eDec) { 266 envGen.decayRate = calculateRate(ADSR_TIME_TABLE[presetCopy.eDec] * 2, sampleRate, 267 ADSREnvelopGenerator.maxOutput, envGen.sustainLevel); 268 } else { 269 envGen.decayRate = 1.0; 270 } 271 if (presetCopy.eSusC) { 272 envGen.isPercussive = false; 273 if (presetCopy.eSusC == 64) { 274 envGen.sustainControl = 0.0; 275 } else if (presetCopy.eSusC < 64) { 276 envGen.sustainControl = 277 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[62 - (presetCopy.eSusC - 1)], sampleRate); 278 } else { 279 envGen.sustainControl = -1.0 * 280 calculateRate(SUSTAIN_CONTROL_TIME_TABLE[presetCopy.eSusC - 64], sampleRate); 281 } 282 } else { 283 envGen.isPercussive = true; 284 envGen.sustainControl = 0.0; 285 } 286 //Set release phase 287 if (presetCopy.eRel) { 288 envGen.releaseRate = calculateRate(ADSR_TIME_TABLE[presetCopy.eRel] * 2, sampleRate, envGen.sustainLevel); 289 } else { 290 envGen.releaseRate = 1.0; 291 } 292 } 293 } 294 alias SampleMap = TreeMap!(uint, Sample); 295 alias PresetMap = TreeMap!(uint, Preset); 296 protected SampleMap sampleBank; ///Stores all current samples. 297 protected PresetMap presetBank; ///Stores all current presets. (bits: 0-6: preset number, 7-13: bank lsb, 14-20: bank msb) 298 protected Channel[8] channels; ///Channel status data. 299 protected MultiTapOsc lfo; ///Low frequency oscillator to modify values in real-time 300 protected float[] lfoOut; ///LFO output buffer 301 protected uint lfoFlags = LFOFlags.triangle;///LFO state flags containing info about current waveform data 302 protected float lfoFreq = 6.0; ///LFO frequency 303 protected float lfoPWM = 0.5; ///LFO pulse width modulation 304 protected float[] dummyBuf; ///Dummy buffer if one or more output aren't used 305 protected int[] iBuf; ///Integer output buffers 306 protected __m128[] lBuf; ///Local output buffer 307 ///Stores output filter values. 308 ///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] 309 protected __m128[10] filterVals; 310 ///Stores control values of the output values. 311 ///Layout: [LF, LQ, RF, RQ, AF, AQ, BF, BQ] 312 protected float[8] filterCtrl = [16_000, 0.707, 16_000, 0.707, 16_000, 0.707, 16_000, 0.707]; 313 protected float mixdownVal = short.max + 1; 314 protected ubyte[32] sysExBuf; ///SysEx command buffer [0-30] + length [31] 315 protected ubyte[68][9] chCtrlLower; ///Lower parts of the channel controllers (0-31 / 32-63) + (Un)registered parameter select (64-65) 316 public this() @safe nothrow { 317 info.nOfAudioInput = 0; 318 info.nOfAudioOutput = 4; 319 info.outputChNames = ["mainL", "mainR", "auxSendA", "auxSendB"]; 320 info.isInstrument = true; 321 info.hasMidiIn = true; 322 info.hasMidiOut = true; 323 info.midiSendback = true; 324 lfo = MultiTapOsc.init; 325 } 326 /** 327 * Sets the module up. 328 * 329 * Can be overridden in child classes to allow resets. 330 */ 331 public override void moduleSetup(ubyte[] inputs, ubyte[] outputs, int sampleRate, size_t bufferSize, 332 ModuleManager handler) @safe nothrow { 333 enabledInputs = StreamIDSet(inputs); 334 enabledOutputs = StreamIDSet(outputs); 335 this.sampleRate = sampleRate; 336 this.bufferSize = bufferSize; 337 /+for (int i ; i < 8 ; i++) { 338 channels[i].decoderBuffer.length = bufferSize * 2; 339 }+/ 340 dummyBuf.length = bufferSize; 341 iBuf.length = bufferSize; 342 lBuf.length = bufferSize; 343 lfoOut.length = bufferSize; 344 this.handler = handler; 345 //Reset filters 346 for (int i ; i < 4 ; i++) { 347 resetLPF(i); 348 filterVals[6][i] = 0; 349 filterVals[7][i] = 0; 350 filterVals[8][i] = 0; 351 filterVals[9][i] = 0; 352 } 353 resetLFO(); 354 } 355 ///Recalculates the low pass filter vlues for the given output channel. 356 protected void resetLPF(int i) @nogc @safe pure nothrow { 357 BiquadFilterValues vals = createLPF(sampleRate, filterCtrl[i * 2], filterCtrl[(i * 2) + 1]); 358 filterVals[0][i] = vals.a0; 359 filterVals[1][i] = vals.a1; 360 filterVals[2][i] = vals.a2; 361 filterVals[3][i] = vals.b0; 362 filterVals[4][i] = vals.b1; 363 filterVals[5][i] = vals.b2; 364 } 365 /** 366 * MIDI 2.0 data received here. 367 * 368 * data0: Header of the up to 128 bit MIDI 2.0 data. 369 * data1-3: Other packets if needed. 370 */ 371 public override void midiReceive(UMP data0, uint data1 = 0, uint data2 = 0, uint data3 = 0) @nogc nothrow { 372 switch (data0.msgType) { 373 case MessageType.MIDI1: 374 if (data0.channel < 8) { 375 switch (data0.status) { 376 case MIDI1_0Cmd.PitchBend: 377 channels[data0.channel].pitchBend = channels[data0.channel].presetCopy.pitchBendAm * 378 ((cast(double)data0.bend - 0x20_00) / 0x3F_FF); 379 //channels[data0.channel].calculateJumpAm(sampleRate); 380 break; 381 case MIDI1_0Cmd.NoteOn: 382 keyOn(data0.note, data0.channel, data0.value/127.0); 383 break; 384 case MIDI1_0Cmd.NoteOff: 385 keyOff(data0.note, data0.channel, data0.value/127.0); 386 break; 387 case MIDI1_0Cmd.CtrlCh: 388 uint val; 389 if (data0.note < 64) { 390 chCtrlLower[data0.channel][data0.note] = data0.value; 391 val = convertM1CtrlValToM2(chCtrlLower[data0.channel][data0.note & 0x1F], 392 chCtrlLower[data0.channel][data0.note | 0x20]); 393 } else if (data0.note >= 70 && data0.note <= 73) { 394 val = data0.value<<25; 395 } else { 396 val = convertM1CtrlValToM2(data0.value, data0.value); 397 } 398 if (data0.note == 0 || data0.note == 32) 399 channels[data0.channel].bankNum = (chCtrlLower[data0.channel][0]<<7) | chCtrlLower[data0.channel][32]; 400 else 401 ctrlCh (data0.channel, data0.note, val); 402 break; 403 case MIDI1_0Cmd.PrgCh: 404 channels[data0.channel].presetCopy = presetBank[(channels[data0.channel].bankNum<<7) | data0.note]; 405 channels[data0.channel].presetNum = data0.note; 406 break; 407 default: 408 break; 409 } 410 } 411 break; 412 case MessageType.MIDI2: 413 if (data0.channel < 8) { 414 switch (data0.status) { 415 case MIDI2_0Cmd.PitchBend: 416 channels[data0.channel].pitchBend = channels[data0.channel].presetCopy.pitchBendAm * 417 ((cast(double)data1 - int.max) / (int.max)); 418 //channels[data0.channel].calculateJumpAm(sampleRate); 419 break; 420 case MIDI2_0Cmd.NoteOn: 421 NoteVals nv = *cast(NoteVals*)&data1; 422 keyOn(data0.note, data0.channel, nv.velocity / ushort.max); 423 break; 424 case MIDI2_0Cmd.NoteOff: 425 NoteVals nv = *cast(NoteVals*)&data1; 426 keyOff(data0.note, data0.channel, nv.velocity / ushort.max); 427 break; 428 case MIDI2_0Cmd.CtrlChOld, MIDI2_0Cmd.CtrlCh: 429 ctrlCh(data0.channel, data0.note, data1); 430 break; 431 case MIDI2_0Cmd.PrgCh: 432 channels[data0.channel].bankNum = data1 & ushort.max; 433 channels[data0.channel].presetNum = data1>>24; 434 presetRecall(data0.channel); 435 break; 436 default: 437 break; 438 } 439 } 440 break; 441 case MessageType.Data64: 442 if (data0.status == SysExSt.Start || data0.status == SysExSt.Complete) 443 sysExBuf[31] = 0; 444 ubyte[4] packet1 = [cast(ubyte)(data1>>24), cast(ubyte)(data1>>16), cast(ubyte)(data1>>8), cast(ubyte)data1]; 445 int length = data0.channel; 446 for (int i ; i < 2 && length - 4 > 0 ; i++, length--) { 447 sysExBuf[sysExBuf[31]] = data0.bytes[i]; 448 sysExBuf[31]++; 449 if (sysExBuf[31] > 30) { 450 length = 0; 451 sysExBuf[31] = 0; 452 } 453 } 454 for (int i ; i < 4 && length > 0 ; i++, length--) { 455 sysExBuf[sysExBuf[31]] = packet1[i]; 456 sysExBuf[31]++; 457 if (sysExBuf[31] > 30) { 458 length = 0; 459 sysExBuf[31] = 0; 460 } 461 } 462 if (data0.status == SysExSt.Complete || data0.status == SysExSt.End) 463 sysExCmd(sysExBuf[0..sysExBuf[31]]); 464 break; 465 case MessageType.Data128: 466 if (data0.status == SysExSt.Start || data0.status == SysExSt.Complete) 467 sysExBuf[31] = 0; 468 ubyte[13] data = [data0.value, 469 cast(ubyte)(data1>>24), cast(ubyte)(data1>>16), cast(ubyte)(data1>>8), cast(ubyte)data1, 470 cast(ubyte)(data2>>24), cast(ubyte)(data2>>16), cast(ubyte)(data2>>8), cast(ubyte)data2, 471 cast(ubyte)(data3>>24), cast(ubyte)(data3>>16), cast(ubyte)(data3>>8), cast(ubyte)data3]; 472 for (int i ; i < data0.channel ; i++, sysExBuf[31]++) { 473 sysExBuf[sysExBuf[31]] = data[i]; 474 if (sysExBuf[31] > 30) 475 sysExBuf[31] = 0; 476 } 477 if (data0.status == SysExSt.Complete || data0.status == SysExSt.End) 478 sysExCmd(sysExBuf[0..sysExBuf[31]]); 479 break; 480 default: 481 break; 482 } 483 } 484 protected void keyOn(ubyte note, ubyte ch, float vel) @nogc pure nothrow { 485 channels[ch].currNote = note; 486 channels[ch].velocity = vel; 487 channels[ch].calculateJumpAm(sampleRate, lfoOut[0]); 488 channels[ch].setShpVals(vel); 489 channels[ch].setADSR(sampleRate); 490 channels[ch].envGen.keyOn(); 491 //reset all on channel 492 channels[ch].reset(); 493 //set noteOn status flag 494 channels[ch].status |= ChannelStatusFlags.noteOn; 495 } 496 protected void keyOff(ubyte note, ubyte ch, float vel) @nogc pure nothrow { 497 if (!(channels[ch].currNote & 128)) 498 channels[ch].currNote = note; 499 channels[ch].velocity = vel; 500 channels[ch].calculateJumpAm(sampleRate, lfoOut[0]); 501 channels[ch].setShpVals(vel); 502 channels[ch].envGen.keyOff(); 503 channels[ch].status &= ~ChannelStatusFlags.noteOn; 504 } 505 protected void ctrlCh(ubyte ch, ubyte param, uint val) @nogc pure nothrow { 506 if (param >= 32 && param < 64) param &= 0x1F; 507 if (ch <= 7) { //Channel locals 508 switch (param) { 509 case 7: 510 channels[ch].presetCopy.masterVol = (1.0 / uint.max) * val; 511 break; 512 case 8: 513 channels[ch].presetCopy.balance = (1.0 / uint.max) * val; 514 break; 515 case 91: 516 channels[ch].presetCopy.auxSendA = (1.0 / uint.max) * val; 517 break; 518 case 92: 519 channels[ch].presetCopy.auxSendB = (1.0 / uint.max) * val; 520 break; 521 case 73: 522 channels[ch].presetCopy.eAtk = cast(ubyte)(val>>25); 523 break; 524 case 14: 525 channels[ch].presetCopy.eAtkShp = (1.0 / uint.max) * val; 526 break; 527 case 70: 528 channels[ch].presetCopy.eDec = cast(ubyte)(val>>25); 529 break; 530 case 71: 531 channels[ch].presetCopy.eSusC = cast(ubyte)(val>>25); 532 break; 533 case 9: 534 channels[ch].presetCopy.eSusLev = (1.0 / uint.max) * val; 535 break; 536 case 72: 537 channels[ch].presetCopy.eRel = cast(ubyte)(val>>25); 538 break; 539 case 15: 540 channels[ch].presetCopy.eRelShp = (1.0 / uint.max) * val; 541 break; 542 case 20: 543 channels[ch].presetCopy.velToLevelAm = (1.0 / uint.max) * val; 544 break; 545 case 21: 546 channels[ch].presetCopy.velToAuxSendAm = (1.0 / uint.max) * val; 547 break; 548 case 22: 549 channels[ch].presetCopy.velToAtkShp = (1.0 / uint.max) * val; 550 break; 551 case 23: 552 channels[ch].presetCopy.velToRelShp = (1.0 / uint.max) * val; 553 break; 554 case 24: 555 channels[ch].presetCopy.lfoToVol = (1.0 / uint.max) * val; 556 break; 557 case 25: 558 channels[ch].presetCopy.adsrToVol = (1.0 / uint.max) * val; 559 break; 560 case 26: 561 channels[ch].presetCopy.adsrToDetune = (1.0 / uint.max) * val * 24; 562 break; 563 case 27: 564 channels[ch].presetCopy.vibrAm = (1.0 / uint.max) * val * 12; 565 break; 566 case 102: 567 if (val) 568 channels[ch].presetCopy.flags |= PresetFlags.cutoffOnKeyOff; 569 else 570 channels[ch].presetCopy.flags &= ~PresetFlags.cutoffOnKeyOff; 571 break; 572 case 103: 573 if (val) 574 channels[ch].presetCopy.flags |= PresetFlags.modwheelToLFO; 575 else 576 channels[ch].presetCopy.flags &= ~PresetFlags.modwheelToLFO; 577 break; 578 case 104: 579 if (val) 580 channels[ch].presetCopy.flags |= PresetFlags.panningLFO; 581 else 582 channels[ch].presetCopy.flags &= ~PresetFlags.panningLFO; 583 break; 584 default: 585 break; 586 } 587 } else if (ch == 8) { //Module globals 588 switch (param) { 589 case 2: 590 filterCtrl[0] = (1.0 / uint.max) * val * 16_000; 591 resetLPF(0); 592 break; 593 case 3: 594 filterCtrl[1] = (1.0 / uint.max) * val * 40; 595 resetLPF(0); 596 break; 597 case 4: 598 filterCtrl[2] = (1.0 / uint.max) * val * 16_000; 599 resetLPF(1); 600 break; 601 case 5: 602 filterCtrl[3] = (1.0 / uint.max) * val * 40; 603 resetLPF(1); 604 break; 605 case 6: 606 filterCtrl[4] = (1.0 / uint.max) * val * 16_000; 607 resetLPF(2); 608 break; 609 case 7: 610 filterCtrl[5] = (1.0 / uint.max) * val * 40; 611 resetLPF(2); 612 break; 613 case 8: 614 filterCtrl[6] = (1.0 / uint.max) * val * 16_000; 615 resetLPF(3); 616 break; 617 case 9: 618 filterCtrl[7] = (1.0 / uint.max) * val * 40; 619 resetLPF(3); 620 break; 621 case 10: 622 if (lfoFlags & LFOFlags.ringmod) 623 lfoFreq = noteToFreq((1.0 / uint.max) * val * 127); 624 else 625 lfoFreq = (1.0 / uint.max) * val * 20; 626 resetLFO(); 627 break; 628 case 11: 629 lfoPWM = (1.0 / uint.max) * val; 630 resetLFO(); 631 break; 632 case 102: 633 if (val) 634 lfoFlags |= LFOFlags.saw; 635 else 636 lfoFlags &= ~LFOFlags.saw; 637 resetLFO(); 638 break; 639 case 103: 640 if (val) 641 lfoFlags |= LFOFlags.triangle; 642 else 643 lfoFlags &= ~LFOFlags.triangle; 644 resetLFO(); 645 break; 646 case 104: 647 if (val) 648 lfoFlags |= LFOFlags.pulse; 649 else 650 lfoFlags &= ~LFOFlags.pulse; 651 resetLFO(); 652 break; 653 case 105: 654 if (val) 655 lfoFlags |= LFOFlags.sawpulse; 656 else 657 lfoFlags &= ~LFOFlags.sawpulse; 658 resetLFO(); 659 break; 660 case 106: 661 if (val) 662 lfoFlags |= LFOFlags.invert; 663 else 664 lfoFlags &= ~LFOFlags.invert; 665 resetLFO(); 666 break; 667 case 107: 668 if (val) 669 lfoFlags |= LFOFlags.ringmod; 670 else 671 lfoFlags &= ~LFOFlags.ringmod; 672 resetLFO(); 673 break; 674 default: 675 break; 676 } 677 } 678 } 679 protected void sysExCmd(ubyte[] msg) @nogc nothrow { 680 //Check manufacturer ID (7D: internal use) 681 if (msg[0] == 0x7D || msg[1] == 0x7D) { 682 const int msgPos = msg[0] ? 1 : 2; 683 switch (msg[msgPos]) { 684 case 0x01: //Suspend channel 685 if (msg[msgPos + 1] >= 8) return; 686 if (!(channels[msg[msgPos + 1]].status & ChannelStatusFlags.sampleRunout)) { 687 channels[msg[msgPos + 1]].currNote |= 0x80; 688 } 689 break; 690 case 0x02: //Resume channel 691 if (msg[msgPos + 1] >= 8) return; 692 if (!(channels[msg[msgPos + 1]].status & ChannelStatusFlags.sampleRunout)) { 693 channels[msg[msgPos + 1]].currNote &= 0x7F; 694 } 695 break; 696 case 0x03: //Overwrite preset 697 if (msg[msgPos + 1] >= 8) return; 698 if (msg.length == msgPos + 5) { 699 channels[msg[msgPos + 1]].presetNum = msg[msgPos + 2]; 700 channels[msg[msgPos + 1]].bankNum = (msg[msgPos + 3]>>1) | msg[msgPos + 4]; 701 } 702 *(presetBank.ptrOf((channels[msg[msgPos + 1]].bankNum<<7) | channels[msg[msgPos + 1]].presetNum)) = 703 channels[msg[msgPos + 1]].presetCopy; 704 break; 705 case 0x20: //Jump to sample position by restoring codec data 706 if (msg[msgPos + 1] >= 8) return; 707 channels[msg[msgPos + 1]].decoderWorkpad.pos = (msg[msgPos + 2] << 21) | (msg[msgPos + 3] << 14) | 708 (msg[msgPos + 4] << 7) | msg[msgPos + 5]; 709 channels[msg[msgPos + 1]].waveModWorkpad.lookupVal = 0; 710 if (msg.length == msgPos + 10) { 711 channels[msg[msgPos + 1]].decoderWorkpad.pred = msg[msgPos + 6]; 712 channels[msg[msgPos + 1]].decoderWorkpad.outn1 = (msg[msgPos + 7]<<30) | (msg[msgPos + 8]<<23) | 713 (msg[msgPos + 9]<<16); 714 channels[msg[msgPos + 1]].decoderWorkpad.outn1>>=16; 715 } 716 //decode the sample 717 if (channels[msg[msgPos + 1]].currNote & 128) return; 718 //get the data for the sample 719 SampleAssignment sa = channels[msg[msgPos + 1]].presetCopy.sampleMapping[channels[msg[msgPos + 1]].currNote]; 720 Sample slmp = sampleBank[sa.sampleNum]; 721 channels[msg[msgPos + 1]].decodeMore(sa, slmp); 722 break; 723 case 0x21: //Dump codec data 724 if (msg[msgPos + 1] >= 8) return; 725 uint[2] dump; 726 const int delta = channels[msg[msgPos + 1]].decoderWorkpad.outn1; 727 dump[0] = cast(uint)channels[msg[msgPos + 1]].decoderWorkpad.pos; 728 dump[0] = ((dump[0] & 0xF_E0_00_00)<<3) | ((dump[0] & 0x1F_C0_00)<<2) | ((dump[0] & 0x3F_80)<<1) | 729 (dump[0] & 0x7F); 730 dump[1] = channels[msg[msgPos + 1]].decoderWorkpad.pred<<24; 731 dump[1] |= ((delta & 0xC0_00)<<2) | ((delta & 0x3F_80)<<1) | (delta & 0x7F); 732 if (midiOut !is null) midiOut(UMP(MessageType.Data128, 0x0, SysExSt.Complete, 9, 0x0, 0x7D), dump[0], 733 dump[1]); 734 break; 735 case 0xA0: //Jump to sample position by restoring codec data (8bit) 736 if (msg[msgPos + 1] >= 8) return; 737 channels[msg[msgPos + 1]].decoderWorkpad.pos = (msg[msgPos + 2] << 24) | (msg[msgPos + 3] << 16) | 738 (msg[msgPos + 4] << 8) | msg[msgPos + 5]; 739 channels[msg[msgPos + 1]].waveModWorkpad.lookupVal = 0; 740 if (msg.length == msgPos + 9) { 741 channels[msg[msgPos + 1]].decoderWorkpad.pred = msg[msgPos + 6]; 742 channels[msg[msgPos + 1]].decoderWorkpad.outn1 = (msg[msgPos + 7]<<24) | (msg[msgPos + 8]<<16); 743 channels[msg[msgPos + 1]].decoderWorkpad.outn1>>=16; 744 } 745 //decode the sample 746 if (channels[msg[msgPos + 1]].currNote & 128) return; 747 //get the data for the sample 748 SampleAssignment sa = channels[msg[msgPos + 1]].presetCopy.sampleMapping[channels[msg[msgPos + 1]].currNote]; 749 Sample slmp = sampleBank[sa.sampleNum]; 750 channels[msg[msgPos + 1]].decodeMore(sa, slmp); 751 break; 752 case 0xA1: //Dump codec data (8bit) 753 if (msg[msgPos + 1] >= 8) return; 754 uint[2] dump; 755 dump[0] = cast(uint)channels[msg[msgPos + 1]].decoderWorkpad.pos; 756 dump[1] = channels[msg[msgPos + 1]].decoderWorkpad.pred<<24; 757 dump[1] |= (channels[msg[msgPos + 1]].decoderWorkpad.outn1 & ushort.max)<<8; 758 if (midiOut !is null) midiOut(UMP(MessageType.Data128, 0x0, SysExSt.Complete, 8, 0x0, 0x7D), dump[0], 759 dump[1]); 760 break; 761 default: 762 break; 763 } 764 } 765 } 766 protected void resetLFO() @nogc @safe pure nothrow { 767 const int divident = ((lfoFlags>>3) & 1) + ((lfoFlags>>2) & 1) + ((lfoFlags>>1) & 1) + (lfoFlags & 1); 768 const short value = cast(short)(short.max / divident * (lfoFlags & LFOFlags.invert ? -1 : 1)); 769 if (lfoFlags & LFOFlags.pulse) 770 lfo.pulseAm = value; 771 if (lfoFlags & LFOFlags.saw) 772 lfo.sawAm = value; 773 if (lfoFlags & LFOFlags.sawpulse) 774 lfo.sawPulseAm = value; 775 if (lfoFlags & LFOFlags.triangle) 776 lfo.triAm = value; 777 lfo.pulseWidth = cast(uint)(lfoPWM * uint.max); 778 lfo.setRate(sampleRate, lfoFreq); 779 } 780 protected void presetRecall(ubyte ch) @nogc pure nothrow { 781 channels[ch].presetCopy = presetBank[channels[ch].presetNum | (channels[ch].bankNum<<7)]; 782 } 783 /** 784 * Creates a decoder function. 785 * Params: 786 * fmt = the format of the sample. 787 * Returns: The decoder function, or null if format not supported. 788 */ 789 protected DecodeFunc getDecoderFunction(WaveFormat fmt) @nogc pure nothrow { 790 switch (fmt.format) { //Hope this branching won't impact performance too much 791 case AudioFormat.PCM: 792 if (fmt.bitsPerSample == 8) 793 return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) {decode8bitPCM(cast(const(ubyte)[])src, dest, wp);}; 794 else if (fmt.bitsPerSample == 16) 795 return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) {decode16bitPCM(cast(const(short)[])src, dest, wp);}; 796 return null; 797 case AudioFormat.ADPCM, AudioFormat.IMA_ADPCM: 798 return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) 799 {decode4bitIMAADPCM(ADPCMStream(src, src.length*2), dest, wp);}; 800 801 case AudioFormat.DIALOGIC_OKI_ADPCM, AudioFormat.OKI_ADPCM: 802 return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) 803 {decode4bitDialogicADPCM(ADPCMStream(src, src.length*2), dest, wp);}; 804 805 case AudioFormat.MULAW: 806 return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) {decodeMuLawStream(cast(const(ubyte)[])src, dest, wp);}; 807 808 case AudioFormat.ALAW: 809 return (ubyte[] src, int[] dest, ref DecoderWorkpad wp) {decodeALawStream(cast(const(ubyte)[])src, dest, wp);}; 810 811 default: 812 return null; 813 } 814 } 815 /** 816 * Renders the current audio frame. 817 * 818 * input: the input buffers if any, null if none. 819 * output: the output buffers if any, null if none. 820 * 821 * NOTE: Buffers must have matching sizes. 822 */ 823 public override void renderFrame(float*[] input, float*[] output) @nogc nothrow { 824 for (int i ; i < bufferSize ; i++) { 825 lfoOut[i] = lfo.outputF(0.5, 1.0 / ushort.max); 826 } 827 for (int i ; i < 8 ; i++) { 828 if (!(channels[i].currNote & 128) && channels[i].jumpAm) { 829 channels[i].calculateJumpAm(sampleRate, lfoOut[0]); 830 //get the data for the sample 831 SampleAssignment sa = channels[i].presetCopy.sampleMapping[channels[i].currNote]; //get sample assignment data 832 Sample slmp = sampleBank[sa.sampleNum]; //get sample 833 if (!slmp.sampleData.length) continue; //break if no sample found 834 size_t samplesNeeded = bufferSize; //determine the amount of needed samples for this frame, initially it's equals with the frame buffer size 835 size_t outpos; //position in output buffer 836 while (samplesNeeded && !(channels[i].currNote & 128)) { 837 //Calculate the amount of samples that are needed for this block 838 ulong samplesToAdvance = channels[i].jumpAm * samplesNeeded; 839 //Determine if there's enough decoded samples in the output buffer. 840 //If not, decode more. 841 if ((channels[i].outPos + samplesToAdvance) > (channels[i].samplesHave)) 842 channels[i].decodeMore(sa, slmp); 843 //Get the amount of unused samples in the decoder buffer with fractions 844 const ulong decoderBufPos = channels[i].samplesHave - channels[i].outPos; 845 //Determine if there's enough decoded samples, if not then reduce the amount of samplesToAdvance 846 if ((128<<24L) - decoderBufPos < samplesToAdvance){ 847 samplesToAdvance = (128<<24L) - decoderBufPos; 848 } 849 debug assert(samplesToAdvance, "Lockup event in PCM8!"); //Test for lockups, crash thread if anything goes wrong 850 //Calculate how many samples will be outputted 851 const size_t samplesOutputted = cast(size_t)(samplesToAdvance / channels[i].jumpAm); 852 stretchAudioNoIterpol(channels[i].decoderBuffer, iBuf[outpos..outpos + samplesOutputted], 853 channels[i].waveModWorkpad, channels[i].jumpAm); //Output the audio to the intermediary buffer 854 samplesNeeded -= samplesOutputted; //substract the number of outputted samples from the needed samples 855 channels[i].outPos += samplesToAdvance; //add the samples needed to advance to the output position 856 outpos += samplesOutputted; //shift the output position by the amount of the outputted samples 857 } 858 //apply envelop (if needed) and volume, then mix it to the local buffer 859 __m128 levels; 860 levels[0] = channels[i].presetCopy.masterVol * channels[i].presetCopy.balance; 861 levels[1] = channels[i].presetCopy.masterVol * (1 - channels[i].presetCopy.balance); 862 levels[2] = channels[i].presetCopy.auxSendA; 863 levels[3] = channels[i].presetCopy.auxSendB; 864 for (int j ; j < bufferSize ; j++) { 865 __m128 sample = _mm_cvtepi32_ps(__m128i(iBuf[j])); 866 const float adsrEnv = channels[i].envGen.shp(channels[i].envGen.position == ADSREnvelopGenerator.Stage.Attack ? 867 channels[i].currShpA : channels[i].currShpR) * channels[i].presetCopy.adsrToVol; 868 channels[i].envGen.advance(); 869 sample *= __m128((1 - channels[i].presetCopy.adsrToVol) + adsrEnv) * __m128((1 - channels[i].presetCopy.lfoToVol) + 870 (lfoOut[j] * channels[i].presetCopy.lfoToVol)) * levels; 871 lBuf[j] += sample; 872 } 873 resetBuffer(iBuf); 874 } 875 } 876 float*[4] outBuf; 877 for (ubyte i, j ; i < 4 ; i++) { 878 if (enabledOutputs.has(i)) { 879 outBuf[i] = output[j]; 880 j++; 881 } else { 882 outBuf[i] = dummyBuf.ptr; 883 } 884 } 885 //apply filtering and mix to destination 886 const __m128 b0_a0 = filterVals[3] / filterVals[0], b1_a0 = filterVals[4] / filterVals[0], 887 b2_a0 = filterVals[5] / filterVals[0], a1_a0 = filterVals[1] / filterVals[0], a2_a0 = filterVals[2] / filterVals[0]; 888 for (int i ; i < bufferSize ; i++) { 889 __m128 input0 = lBuf[i]; 890 input0 /= __m128(mixdownVal); 891 input0 = _mm_max_ps(input0, __m128(-1.0)); 892 input0 = _mm_min_ps(input0, __m128(1.0)); 893 __m128 output0 = b0_a0 * input0 + b1_a0 * filterVals[6] + b2_a0 * filterVals[7] - a1_a0 * filterVals[8] - 894 a2_a0 * filterVals[9]; 895 for (int j ; j < 4 ; j++) 896 outBuf[j][i] += output0[j]; 897 filterVals[7] = filterVals[6]; 898 filterVals[6] = input0; 899 filterVals[9] = filterVals[8]; 900 filterVals[8] = output0; 901 } 902 resetBuffer(lBuf); 903 } 904 /** 905 * Receives waveform data that has been loaded from disk for reading. Returns zero if successful, or a specific 906 * errorcode. 907 * 908 * id: The ID of the waveform. 909 * rawData: The data itself, in unprocessed form. 910 * format: The format of the wave data, including the data type, bit depth, base sampling rate 911 */ 912 public override int waveformDataReceive(uint id, ubyte[] rawData, WaveFormat format) nothrow { 913 int result; 914 if (!(format.format == AudioFormat.PCM || format.format == AudioFormat.MULAW || format.format == AudioFormat.ALAW || 915 format.format == AudioFormat.ADPCM || format.format == AudioFormat.IMA_ADPCM || 916 format.format == AudioFormat.DIALOGIC_OKI_ADPCM || format.format == AudioFormat.OKI_ADPCM)) 917 result |= SampleLoadErrorCode.FormatNotSupported; 918 result |= format.channels == 1 ? 0 : SampleLoadErrorCode.ChNumNotSupported; 919 if (result) { 920 return result; 921 } else { 922 sampleBank[id] = Sample(rawData, format, getDecoderFunction(format)); 923 return 0; 924 } 925 } 926 /** 927 * Creates a new waveform from an existing one using slicing. 928 * Params: 929 * id = The ID of the new sample. 930 * src = The ID of the original sample. 931 * pos = The position where the slice begins. 932 * length = The length of the slice. 933 * Returns: 0 on success, -1 if module don't support this feature, -2 if slice is out of bounds (longer than the 934 * sample, etc.), -3 if sample is not slicable (ADPCM, etc.). 935 */ 936 public override int waveformSlice(uint id, uint src, uint pos, uint length) nothrow { 937 Sample srcSlmp = sampleBank[src]; 938 switch (srcSlmp.format.format) { 939 case AudioFormat.UNKNOWN: 940 return -4; 941 case AudioFormat.ADPCM, AudioFormat.IMA_ADPCM, AudioFormat.OKI_ADPCM, AudioFormat.DIALOGIC_OKI_ADPCM: 942 return -3; 943 default: 944 break; 945 } 946 const size_t samplelen = srcSlmp.samplesLength(); 947 if (pos > samplelen || pos + length > samplelen) { 948 return -2; 949 } 950 const size_t begin = (pos * 8) / srcSlmp.format.bitsPerSample, 951 end = ((pos + length) * 8) / srcSlmp.format.bitsPerSample; 952 sampleBank[id] = Sample(srcSlmp.sampleData[begin..end], srcSlmp.format, srcSlmp.decode); 953 return 0; 954 } 955 /** 956 * Returns the waveform data from the 957 * Params: 958 * id = The ID of the waveform. 959 * Returns: The raw waveform data, or null on error (unsupported feature, waveform not found, etc.) 960 */ 961 public override const(ubyte)[] getWaveformData(uint id) nothrow { 962 return cast(const(ubyte)[])sampleBank[id].sampleData; 963 } 964 /** 965 * Returns the format of the selected waveform 966 * Params: 967 * id = The ID of the waveform. 968 * Returns: The format of the waveform data, or WaveFormat.init if not available. 969 */ 970 public override WaveFormat getWaveformDataFormat(uint id) nothrow { 971 return sampleBank[id].format; 972 } 973 ///Returns the available waveform ID list 974 public override uint[] getWaveformIDList() nothrow { 975 uint[] result; 976 foreach (uint key, Sample elem; sampleBank) { 977 result ~= key; 978 } 979 return result; 980 } 981 /** 982 * Restores a parameter to the given preset. 983 * Returns an errorcode on failure. 984 */ 985 public override int writeParam_int(uint presetID, uint paramID, int value) nothrow { 986 Preset* presetPtr = presetBank.ptrOf(presetID); 987 if (presetPtr is null) { 988 presetBank[presetID] = Preset.init; 989 presetPtr = presetBank.ptrOf(presetID); 990 } 991 if (paramID & 0x10_00) { 992 switch (paramID & 0x0F_00) { 993 case 0x00_00: 994 presetPtr.sampleMapping[paramID & 0x7F].sampleNum = value; 995 return 0; 996 case 0x02_00: 997 presetPtr.sampleMapping[paramID & 0x7F].loopBegin = value; 998 return 0; 999 case 0x03_00: 1000 presetPtr.sampleMapping[paramID & 0x7F].loopEnd = value; 1001 return 0; 1002 default: 1003 break; 1004 } 1005 } else if (paramID & 0x80_00) { 1006 switch (paramID) { 1007 case 0x80_09: 1008 if (value) 1009 lfoFlags |= LFOFlags.saw; 1010 else 1011 lfoFlags &= ~LFOFlags.saw; 1012 resetLFO(); 1013 return 0; 1014 case 0x80_0a: 1015 if (value) 1016 lfoFlags |= LFOFlags.triangle; 1017 else 1018 lfoFlags &= ~LFOFlags.triangle; 1019 resetLFO(); 1020 return 0; 1021 case 0x80_0b: 1022 if (value) 1023 lfoFlags |= LFOFlags.pulse; 1024 else 1025 lfoFlags &= ~LFOFlags.pulse; 1026 resetLFO(); 1027 return 0; 1028 case 0x80_0c: 1029 if (value) 1030 lfoFlags |= LFOFlags.sawpulse; 1031 else 1032 lfoFlags &= ~LFOFlags.sawpulse; 1033 resetLFO(); 1034 return 0; 1035 case 0x80_0d: 1036 if (value) 1037 lfoFlags |= LFOFlags.invert; 1038 else 1039 lfoFlags &= ~LFOFlags.invert; 1040 resetLFO(); 1041 return 0; 1042 case 0x80_0f: 1043 if (value) 1044 lfoFlags |= LFOFlags.ringmod; 1045 else 1046 lfoFlags &= ~LFOFlags.ringmod; 1047 resetLFO(); 1048 return 0; 1049 default: 1050 break; 1051 } 1052 } else { 1053 switch (paramID) { 1054 case 0x00: 1055 presetPtr.eAtk = cast(ubyte)(value & 0x7F); 1056 return 0; 1057 case 0x01: 1058 presetPtr.eDec = cast(ubyte)(value & 0x7F); 1059 return 0; 1060 case 0x02: 1061 presetPtr.eSusC = cast(ubyte)(value & 0x7F); 1062 return 0; 1063 case 0x03: 1064 presetPtr.eRel = cast(ubyte)(value & 0x7F); 1065 return 0; 1066 case 0x10: 1067 presetPtr.flags = value; 1068 return 0; 1069 case 0x00_11: 1070 if (value) 1071 presetPtr.flags |= PresetFlags.cutoffOnKeyOff; 1072 else 1073 presetPtr.flags &= ~PresetFlags.cutoffOnKeyOff; 1074 return 0; 1075 case 0x00_12: 1076 if (value) 1077 presetPtr.flags |= PresetFlags.modwheelToLFO; 1078 else 1079 presetPtr.flags &= ~PresetFlags.modwheelToLFO; 1080 return 0; 1081 case 0x00_13: 1082 if (value) 1083 presetPtr.flags |= PresetFlags.panningLFO; 1084 else 1085 presetPtr.flags &= ~PresetFlags.panningLFO; 1086 return 0; 1087 /* case 0x00_14: 1088 if (value) 1089 presetPtr.flags |= PresetFlags.ADSRtoVol; 1090 else 1091 presetPtr.flags &= ~PresetFlags.ADSRtoVol; 1092 return 0; */ 1093 default: 1094 break; 1095 } 1096 } 1097 return 1; 1098 } 1099 /** 1100 * Restores a parameter to the given preset. 1101 * Returns an errorcode on failure. 1102 */ 1103 public override int writeParam_long(uint presetID, uint paramID, long value) nothrow { 1104 return 0; 1105 } 1106 /** 1107 * Restores a parameter to the given preset. 1108 * Returns an errorcode on failure. 1109 */ 1110 public override int writeParam_double(uint presetID, uint paramID, double value) nothrow { 1111 Preset* presetPtr = presetBank.ptrOf(presetID); 1112 if (presetPtr is null) { 1113 presetBank[presetID] = Preset.init; 1114 presetPtr = presetBank.ptrOf(presetID); 1115 } 1116 if (paramID & 0x10_00) { 1117 switch (paramID & 0x0F_00) { 1118 case 0x01_00: 1119 presetPtr.sampleMapping[paramID & 0x7F].baseFreq = value; 1120 return 0; 1121 default: 1122 break; 1123 } 1124 } else if (paramID & 0x80_00) { 1125 switch (paramID) { 1126 case 0x80_00: 1127 filterCtrl[0] = value; 1128 resetLPF(0); 1129 return 0; 1130 case 0x80_01: 1131 filterCtrl[1] = value; 1132 resetLPF(0); 1133 return 0; 1134 case 0x80_02: 1135 filterCtrl[2] = value; 1136 resetLPF(1); 1137 return 0; 1138 case 0x80_03: 1139 filterCtrl[3] = value; 1140 resetLPF(1); 1141 return 0; 1142 case 0x80_04: 1143 filterCtrl[4] = value; 1144 resetLPF(2); 1145 return 0; 1146 case 0x80_05: 1147 filterCtrl[5] = value; 1148 resetLPF(2); 1149 return 0; 1150 case 0x80_06: 1151 filterCtrl[6] = value; 1152 resetLPF(3); 1153 return 0; 1154 case 0x80_07: 1155 filterCtrl[7] = value; 1156 resetLPF(3); 1157 return 0; 1158 case 0x80_08: 1159 lfoFreq = value; 1160 resetLFO(); 1161 return 0; 1162 case 0x80_0e: 1163 lfoPWM = value; 1164 resetLFO(); 1165 return 0; 1166 default: 1167 break; 1168 } 1169 } else { 1170 switch (paramID) { 1171 case 0x00_14: 1172 presetPtr.adsrToDetune = value; 1173 return 0; 1174 case 0x00_15: 1175 presetPtr.vibrAm = value; 1176 return 0; 1177 case 0x00_20: 1178 presetPtr.pitchBendAm = value; 1179 return 0; 1180 default: break; 1181 } 1182 if (value < 0 || value > 1) return 2; 1183 switch (paramID) { 1184 case 0x00_04: 1185 presetPtr.eAtkShp = value; 1186 return 0; 1187 case 0x00_05: 1188 presetPtr.eRelShp = value; 1189 return 0; 1190 case 0x00_06: 1191 presetPtr.eSusLev = value; 1192 return 0; 1193 case 0x00_07: 1194 presetPtr.masterVol = value; 1195 return 0; 1196 case 0x00_08: 1197 presetPtr.balance = value; 1198 return 0; 1199 case 0x00_09: 1200 presetPtr.auxSendA = value; 1201 return 0; 1202 case 0x00_0A: 1203 presetPtr.auxSendB = value; 1204 return 0; 1205 case 0x00_0B: 1206 presetPtr.velToLevelAm = value; 1207 return 0; 1208 case 0x00_0C: 1209 presetPtr.velToAuxSendAm = value; 1210 return 0; 1211 case 0x00_0D: 1212 presetPtr.velToAtkShp = value; 1213 return 0; 1214 case 0x00_0E: 1215 presetPtr.velToRelShp = value; 1216 return 0; 1217 case 0x00_0F: 1218 presetPtr.adsrToVol = value; 1219 return 0; 1220 1221 default: 1222 break; 1223 } 1224 } 1225 return 1; 1226 } 1227 /** 1228 * Restores a parameter to the given preset. 1229 * Returns an errorcode on failure. 1230 */ 1231 public override int writeParam_string(uint presetID, uint paramID, string value) nothrow { 1232 return 0; 1233 } 1234 /** 1235 * Returns all the possible parameters this module has. 1236 */ 1237 public override MValue[] getParameters() nothrow { 1238 return [ 1239 MValue(MValueType.Int32, 0x00_00, "envGenAtk"), MValue(MValueType.Int32, 0x00_01, "envGenDec"), 1240 MValue(MValueType.Int32, 0x00_02, "envGenSusC"), MValue(MValueType.Int32, 0x00_03, "envGenRel"), 1241 MValue(MValueType.Float, 0x00_04, "envGenAtkShp"), MValue(MValueType.Float, 0x00_05, "envGenDecShp"), 1242 MValue(MValueType.Float, 0x00_06, "envGenSusLevel"), MValue(MValueType.Float, 0x00_07, "masterVol"), 1243 MValue(MValueType.Float, 0x00_08, "balance"), MValue(MValueType.Float, 0x00_09, "auxSendA"), 1244 MValue(MValueType.Float, 0x00_0A, "auxSendB"), MValue(MValueType.Float, 0x00_0B, "velToLevelAm"), 1245 MValue(MValueType.Float, 0x00_0C, "velToAuxSendAm"), MValue(MValueType.Float, 0x00_0D, "velToAtkShp"), 1246 MValue(MValueType.Float, 0x00_0E, "velToRelShp"), MValue(MValueType.Float, 0x00_0F, "adsrToVol"), 1247 MValue(MValueType.Float, 0x00_14, "adsrToDetune"), MValue(MValueType.Float, 0x00_15, "vibrAm"), 1248 MValue(MValueType.Int32, 0x00_10, "flags"), 1249 MValue(MValueType.Boolean, 0x00_11, "f_cutoffOnKeyOff"), 1250 MValue(MValueType.Boolean, 0x00_12, "f_modwheelToLFO"), 1251 MValue(MValueType.Boolean, 0x00_13, "f_panningLFO"), 1252 MValue(MValueType.Float, 0x00_20, "pitchBendRange"), 1253 /* MValue(MValueType.Boolean, 0x00_13, "f_ADSRtoVol"), */ 1254 ] ~ SAMPLE_SET_VALS.dup ~ [ 1255 MValue(MValueType.Float, 0x80_00, `_FilterLCFreq`), MValue(MValueType.Float, 0x80_01, `_FilterLCQ`), 1256 MValue(MValueType.Float, 0x80_02, `_FilterRCFreq`), MValue(MValueType.Float, 0x80_03, `_FilterRCQ`), 1257 MValue(MValueType.Float, 0x80_04, `_FilterACFreq`), MValue(MValueType.Float, 0x80_05, `_FilterACQ`), 1258 MValue(MValueType.Float, 0x80_06, `_FilterBCFreq`), MValue(MValueType.Float, 0x80_07, `_FilterBCQ`), 1259 MValue(MValueType.Float, 0x80_08, "_LFOFreq"), MValue(MValueType.Boolean, 0x80_09, "_LFOSaw"), 1260 MValue(MValueType.Boolean, 0x80_0a, "_LFOTri"), MValue(MValueType.Boolean, 0x80_0b, "_LFOPul"), 1261 MValue(MValueType.Boolean, 0x80_0c, "_LFOSawPul"), MValue(MValueType.Boolean, 0x80_0d, "_LFOInv"), 1262 MValue(MValueType.Float, 0x80_0e, "_LFOPWM"), MValue(MValueType.Boolean, 0x80_0f, "_LFORingmod") 1263 ]; 1264 } 1265 /** 1266 * Reads the given value (int). 1267 * Params: 1268 * presetID = The preset ID, or uint.max for global module values. 1269 * paramID = The parameter ID. 1270 * Returns: The value of the given preset and parameter 1271 */ 1272 public override int readParam_int(uint presetID, uint paramID) nothrow { 1273 Preset* presetPtr = presetBank.ptrOf(presetID); 1274 if (presetPtr is null) return 0; 1275 if (paramID & 0x10_00) { 1276 switch (paramID & 0x0F_00) { 1277 case 0x00_00: 1278 return presetPtr.sampleMapping[paramID & 0x7F].sampleNum; 1279 case 0x02_00: 1280 return presetPtr.sampleMapping[paramID & 0x7F].loopBegin; 1281 case 0x03_00: 1282 return presetPtr.sampleMapping[paramID & 0x7F].loopEnd; 1283 default: 1284 break; 1285 } 1286 } else if (paramID & 0x80_00) { 1287 switch (paramID) { 1288 case 0x80_09: 1289 return lfoFlags & LFOFlags.saw ? 1 : 0; 1290 case 0x80_0a: 1291 return lfoFlags & LFOFlags.triangle ? 1 : 0; 1292 case 0x80_0b: 1293 return lfoFlags & LFOFlags.pulse ? 1 : 0; 1294 case 0x80_0c: 1295 return lfoFlags & LFOFlags.sawpulse ? 1 : 0; 1296 case 0x80_0d: 1297 return lfoFlags & LFOFlags.invert ? 1 : 0; 1298 case 0x80_0f: 1299 return lfoFlags & LFOFlags.ringmod ? 1 : 0; 1300 default: 1301 break; 1302 } 1303 } else { 1304 switch (paramID) { 1305 case 0x00: 1306 return presetPtr.eAtk; 1307 case 0x01: 1308 return presetPtr.eDec; 1309 case 0x02: 1310 return presetPtr.eSusC; 1311 case 0x03: 1312 return presetPtr.eRel; 1313 case 0x10: 1314 return presetPtr.flags; 1315 case 0x00_11: 1316 return presetPtr.flags & PresetFlags.cutoffOnKeyOff ? 1 : 0; 1317 case 0x00_12: 1318 return presetPtr.flags & PresetFlags.modwheelToLFO ? 1 : 0; 1319 case 0x00_13: 1320 return presetPtr.flags & PresetFlags.panningLFO ? 1 : 0; 1321 /* case 0x00_14: 1322 return presetPtr.flags |= PresetFlags.ADSRtoVol ? 1 : 0; */ 1323 default: 1324 break; 1325 } 1326 } 1327 return 0; 1328 } 1329 /** 1330 * Reads the given value (int). 1331 * Params: 1332 * presetID = The preset ID, or uint.max for global module values. 1333 * paramID = The parameter ID. 1334 * Returns: The value of the given preset and parameter 1335 */ 1336 public override long readParam_long(uint presetID, uint paramID) nothrow { 1337 return 0; 1338 } 1339 /** 1340 * Reads the given value (int). 1341 * Params: 1342 * presetID = The preset ID, or uint.max for global module values. 1343 * paramID = The parameter ID. 1344 * Returns: The value of the given preset and parameter 1345 */ 1346 public override double readParam_double(uint presetID, uint paramID) nothrow { 1347 Preset* presetPtr = presetBank.ptrOf(presetID); 1348 if (presetPtr is null) return double.nan; 1349 if (paramID & 0x10_00) { 1350 switch (paramID & 0x0F_00) { 1351 case 0x01_00: 1352 return presetPtr.sampleMapping[paramID & 0x7F].baseFreq; 1353 default: 1354 break; 1355 } 1356 } else if (paramID & 0x80_00) { 1357 switch (paramID) { 1358 case 0x80_00: 1359 return filterCtrl[0]; 1360 case 0x80_01: 1361 return filterCtrl[1]; 1362 case 0x80_02: 1363 return filterCtrl[2]; 1364 case 0x80_03: 1365 return filterCtrl[3]; 1366 case 0x80_04: 1367 return filterCtrl[4]; 1368 case 0x80_05: 1369 return filterCtrl[5]; 1370 case 0x80_06: 1371 return filterCtrl[6]; 1372 case 0x80_07: 1373 return filterCtrl[7]; 1374 case 0x80_08: 1375 return lfoFreq; 1376 case 0x80_0e: 1377 return lfoPWM; 1378 default: 1379 break; 1380 } 1381 } else { 1382 switch (paramID) { 1383 case 0x00_04: 1384 return presetPtr.eAtkShp; 1385 case 0x00_05: 1386 return presetPtr.eRelShp; 1387 case 0x00_06: 1388 return presetPtr.eSusLev; 1389 case 0x00_07: 1390 return presetPtr.masterVol; 1391 case 0x00_08: 1392 return presetPtr.balance; 1393 case 0x00_09: 1394 return presetPtr.auxSendA; 1395 case 0x00_0A: 1396 return presetPtr.auxSendB; 1397 case 0x00_0B: 1398 return presetPtr.velToLevelAm; 1399 case 0x00_0C: 1400 return presetPtr.velToAuxSendAm; 1401 case 0x00_0D: 1402 return presetPtr.velToAtkShp; 1403 case 0x00_0E: 1404 return presetPtr.velToRelShp; 1405 case 0x00_0F: 1406 return presetPtr.adsrToVol; 1407 case 0x00_14: 1408 return presetPtr.adsrToDetune; 1409 case 0x00_15: 1410 return presetPtr.vibrAm; 1411 case 0x0020: 1412 return presetPtr.pitchBendAm; 1413 default: 1414 break; 1415 } 1416 } 1417 return double.nan; 1418 } 1419 /** 1420 * Reads the given value (int). 1421 * Params: 1422 * presetID = The preset ID, or uint.max for global module values. 1423 * paramID = The parameter ID. 1424 * Returns: The value of the given preset and parameter 1425 */ 1426 public override string readParam_string(uint presetID, uint paramID) nothrow { 1427 return null; 1428 } 1429 }