I have created this Envelope with only SSE code, but I wonder if there is a way to organize it better. As it does get confusing to read as things piles up. Another thing is about loop unrolling. Is there a cross-platform way to do that or some other way to handle it? Or I shouldn’t really bother about it?

Here’s the current project’s code.

https://www.wusik.com/download/Wusik_ZR_002.zip

You can check my videos where I explain this live on twitch.

Here’s a snip of the ADSR envelope SSE processing code.

```
const static __m128 xNum0 = _mm_setzero_ps();
const static __m128 xNum1 = _mm_set1_ps(1.0f);
const static __m128 xNum2 = _mm_set1_ps(2.0f);
const static __m128 xNum10 = _mm_set1_ps(10.0f);
for (int xvoice = 0; xvoice < MAX_INTERNAL_VOICES; xvoice += 4)
{
__m128 xValue = _mm_load_ps(ADSREnvelope.value + xvoice);
__m128 xPositon = _mm_load_ps(ADSREnvelope.position + xvoice);
__m128 xCurve = _mm_set1_ps(valuesList[kADSR_Curve]);
//
__m128 xAllRates = _mm_and_ps(_mm_cmpeq_ps(xPositon, ADSR_ATTACK_SSE), _mm_load_ps(ADSREnvelope.rate[WusikADSREnvelope::kRate_Attack] + xvoice));
xAllRates = _mm_add_ps(xAllRates, _mm_and_ps(_mm_cmpeq_ps(xPositon, ADSR_DECAY_RELEASE_SSE), _mm_load_ps(ADSREnvelope.rate[WusikADSREnvelope::kRate_DecayRelease] + xvoice)));
xValue = _mm_add_ps(xValue, xAllRates);
xPositon = _mm_add_ps(xPositon, _mm_and_ps(_mm_cmpgt_ps(xValue, xNum1), xNum1));
xValue = _mm_min_ps(xNum1, _mm_max_ps(xValue, _mm_and_ps(_mm_cmpeq_ps(xPositon, xNum1), _mm_load_ps(ADSREnvelope.sustain + xvoice))));
//
_mm_store_ps(ADSREnvelope.value + xvoice, xValue);
_mm_store_ps(ADSREnvelope.position + xvoice, xPositon);
//
xValue = _mm_mul_ps(_mm_load_ps(ADSREnvelope.velocity + xvoice),
_mm_min_ps(xNum1, _mm_mul_ps(
xValue,
_mm_add_ps(_mm_mul_ps(_mm_set1_ps(valuesList[kADSR_Clip]), xNum10), xNum1))));
//
_mm_store_ps(ADSREnvelope.output + xvoice,
_mm_add_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(xValue, xValue), _mm_mul_ps(xValue, xValue)), xCurve), _mm_mul_ps(xValue, _mm_sub_ps(xNum1, xCurve))));
}
```

Cheers, WilliamK