auto DSP::envelopeRun(Voice& v) -> void { int envelope = v.envelope; if(v.envelopeMode == EnvelopeRelease) { //60% envelope -= 0x8; if(envelope < 0) envelope = 0; v.envelope = envelope; return; } int rate; int envelopeData = VREG(ADSR1); if(state._adsr0 & 0x80) { //99% ADSR if(v.envelopeMode >= EnvelopeDecay) { //99% envelope--; envelope -= envelope >> 8; rate = envelopeData & 0x1f; if(v.envelopeMode == EnvelopeDecay) { //1% rate = ((state._adsr0 >> 3) & 0x0e) + 0x10; } } else { //env_attack rate = ((state._adsr0 & 0x0f) << 1) + 1; envelope += rate < 31 ? 0x20 : 0x400; } } else { //GAIN envelopeData = VREG(GAIN); int mode = envelopeData >> 5; if(mode < 4) { //direct envelope = envelopeData << 4; rate = 31; } else { rate = envelopeData & 0x1f; if(mode == 4) { //4: linear decrease envelope -= 0x20; } else if(mode < 6) { //5: exponential decrease envelope--; envelope -= envelope >> 8; } else { //6, 7: linear increase envelope += 0x20; if(mode > 6 && (uint)v.hiddenEnvelope >= 0x600) { envelope += 0x8 - 0x20; //7: two-slope linear increase } } } } //sustain level if((envelope >> 8) == (envelopeData >> 5) && v.envelopeMode == EnvelopeDecay) v.envelopeMode = EnvelopeSustain; v.hiddenEnvelope = envelope; //uint cast because linear decrease underflowing also triggers this if((uint)envelope > 0x7ff) { envelope = (envelope < 0 ? 0 : 0x7ff); if(v.envelopeMode == EnvelopeAttack) v.envelopeMode = EnvelopeDecay; } if(counterPoll(rate)) v.envelope = envelope; }