// // VecAmalgam.cpp // BitCombiner // // Created by Dale Johnson on 26/11/2018. // Copyright © 2018 Dale Johnson. All rights reserved. // #include "VecAmalgam.hpp" VecAmalgam::VecAmalgam() { __zeros = _mm_set1_ps(0.f); __ones = _mm_set1_ps(1.f); __negOnes = _mm_set1_ps(-1.f); __halfs = _mm_set1_ps(0.5f); __ffTarget = __zeros; __high = _mm_castsi128_ps(_mm_set1_epi32(0xFFFFFFFF)); __x = __zeros; __y = __zeros; __z = __zeros; __xFolded = __zeros; __yFolded = __zeros; __zero16 = Dmm_set1_pi16(0); __one16 = Dmm_set1_pi16(1); __a = __zero16; __b = __zero16; __c = __zero16; __aPrev = __zero16; __bPrev = __zero16; __aREdge = __zero16; __bREdge = __zero16; __count = Dmm_set1_pi16(0xFFFF); _step = 1.f; __xDS = __zeros; __yDS = __zeros; __zDS = __zeros; p[RING_MOD_1_MODE] = &VecAmalgam::ringMod1; p[RING_MOD_2_MODE] = &VecAmalgam::ringMod2; p[RING_MOD_3_MODE] = &VecAmalgam::ringMod3; p[DIODE_RING_MOD_MODE] = &VecAmalgam::diodeRingMod; p[MIN_MAX_MODE] = &VecAmalgam::minMax; p[SIGN_SWITCH_1_MODE] = &VecAmalgam::signSwitch1; p[SIGN_SWITCH_2_MODE] = &VecAmalgam::signSwitch2; p[X_FADE_MODE] = &VecAmalgam::xFade; p[FLIP_FLOP_MODE] = &VecAmalgam::flipFlop; p[ALPHA_PWM_MODE] = &VecAmalgam::alphaPWM; p[BIT_AND_MODE] = &VecAmalgam::bitAND; p[BIT_XOR_MODE] = &VecAmalgam::bitXOR; p[BIT_INTERLEAVE_MODE] = &VecAmalgam::bitInterleave; p[BIT_HACK_MODE] = &VecAmalgam::bitHack; p[BIT_AND_FLOAT_MODE] = &VecAmalgam::bitANDFloat; p[BIT_INTERLEAVE_FLOAT_MODE] = &VecAmalgam::bitInterleaveFloat; p[BIT_HACK_FLOAT_MODE] = &VecAmalgam::bitHackFloat; _mode = RING_MOD_1_MODE; std::srand(std::time(NULL)); for(auto i = 0; i < 4; ++i) { _z[i] = std::rand(); _w[i] = std::rand(); _k[i] = 0; } setSampleRate(44100.f); } void VecAmalgam::setMode(int mode) { _mode = mode; if(_mode < 0) { _mode = 0; } else if(_mode >= NUM_MODES) { _mode = NUM_MODES - 1; } } void VecAmalgam::setSampleRate(float sampleRate) { _engineSampleRate = sampleRate; _quarterNyquist = _engineSampleRate / 32.f; calcStepSize(); } void VecAmalgam::calcStepSize() { _internalSampleRate = _quarterNyquist * powf(2.f, (_updateRate * 5.f)); _stepSize = _internalSampleRate / _engineSampleRate; } __m128 VecAmalgam::ringMod1(const __m128& x, const __m128& y, float paramA, float paramB) { __z = _mm_or_ps(_mm_cmpgt_ps(y, _mm_set1_ps(paramB * 1.066f)), _mm_cmplt_ps(y, _mm_set1_ps(paramB * -1.066f))); __z = _mm_and_ps(y, __z); return _mm_mul_ps(_mm_add_ps(_mm_mul_ps(x, _mm_set1_ps(1.f - 0.5f * paramA)), _mm_set1_ps(paramA * 0.5f)), __z); } __m128 VecAmalgam::ringMod2(const __m128& x, const __m128& y, float paramA, float paramB) { __xFolded = _mm_add_ps(_mm_mul_ps(x, __halfs), __halfs); __yFolded = _mm_add_ps(_mm_mul_ps(y, __halfs), __halfs); __xFolded = _mm_mirror_ps(__xFolded, _mm_set1_ps(paramA + 0.00001f)); __yFolded = _mm_mirror_ps(__yFolded, _mm_set1_ps(paramB + 0.00001f)); __xFolded = _mm_mul_ps(_mm_add_ps(__xFolded, _mm_set1_ps(-0.5f)),_mm_set1_ps(2.f)); __yFolded = _mm_mul_ps(_mm_add_ps(__yFolded, _mm_set1_ps(-0.5f)),_mm_set1_ps(2.f)); return _mm_mul_ps(__xFolded, __yFolded); } __m128 VecAmalgam::ringMod3(const __m128& x, const __m128& y, float paramA, float paramB) { __xFolded = _mm_add_ps(_mm_mul_ps(x, __halfs), __halfs); __yFolded = _mm_add_ps(_mm_mul_ps(y, __halfs), __halfs); __xFolded = _mm_mirror_ps(__xFolded, _mm_set1_ps(paramA + 0.00001f)); __yFolded = _mm_mirror_ps(__yFolded, _mm_set1_ps(paramA + 0.00001f)); __xFolded = _mm_mul_ps(_mm_add_ps(__xFolded, _mm_set1_ps(-0.5f)),_mm_set1_ps(2.f)); __yFolded = _mm_mul_ps(_mm_add_ps(__yFolded, _mm_set1_ps(-0.5f)),_mm_set1_ps(-2.f)); __xLogic = _mm_cmpgt_ps(__xFolded, __zeros); __yLogic = _mm_cmpgt_ps(__yFolded, __zeros); __zLogic = _mm_xor_ps(__xLogic, __yLogic); __z = _mm_and_ps(__zLogic, __ones); __z = _mm_add_ps(_mm_mul_ps(__z, _mm_set1_ps(-2.f)), __ones); return _mm_linterp_ps(_mm_mul_ps(__xFolded, __yFolded), __z, _mm_set1_ps(paramB)); } __m128 VecAmalgam::diodeRingMod(const __m128& x, const __m128& y, float paramA, float paramB) { return _d.process(x, y, paramA, paramB); } __m128 VecAmalgam::minMax(const __m128& x, const __m128& y, float paramA, float paramB) { __m128 select = _mm_cmpgt_ps(x, y); __m128 max = _mm_switch_ps(y, x, select); __m128 min = _mm_switch_ps(x, y, select); __m128 delta = _mm_sub_ps(max, min); __z = _mm_linterp_ps(min, max, _mm_set1_ps(paramA)); return _mm_linterp_ps(__z, _mm_mul_ps(__z, delta), _mm_set1_ps(paramB)); } __m128 VecAmalgam::signSwitch1(const __m128& x, const __m128& y, float paramA, float paramB) { __m128 midPoint = _mm_set1_ps(paramA * 2.f - 1.f); __m128 thresh = _mm_set1_ps(paramB); return _mm_add_ps(_mm_and_ps(x, _mm_cmpge_ps(x, _mm_add_ps(midPoint, thresh))), _mm_and_ps(y, _mm_cmplt_ps(y,_mm_sub_ps(midPoint, thresh)))); } __m128 VecAmalgam::signSwitch2(const __m128& x, const __m128& y, float paramA, float paramB) { __m128 midPoint = _mm_set1_ps(paramA * 2.f - 1.f); __m128 thresh = _mm_set1_ps(paramB); __z = _mm_switch_ps(__zeros, x, _mm_cmpgt_ps(x, _mm_add_ps(midPoint, thresh))); return _mm_switch_ps(__z, y, _mm_cmplt_ps(y, _mm_sub_ps(midPoint, thresh))); } __m128 VecAmalgam::xFade(const __m128& x, const __m128& y, float paramA, float paramB) { __m128 xScaled = _mm_add_ps(_mm_mul_ps(x, __halfs), __halfs); xScaled = _mm_mul_ps(xScaled, _mm_set1_ps(paramB)); return _mm_linterp_ps(x,y, _mm_clamp_ps(_mm_add_ps(_mm_set1_ps(paramA), xScaled), __zeros, __ones)); } __m128 VecAmalgam::flipFlop(const __m128& x, const __m128& y, float paramA, float paramB) { __m128 thresh = _mm_set1_ps(paramB); for(auto i = 0; i < 4; ++i) { _k[i] = (float)mwcRand(_z[i], _w[i]) / (float)UINT32_MAX; } __chanceX = _mm_loadu_ps(_k); __chanceX = _mm_and_ps(_mm_cmpgt_ps(__chanceX, _mm_set1_ps(paramA)), __high); for(auto i = 0; i < 4; ++i) { _k[i] = (float)mwcRand(_z[i], _w[i]) / (float)UINT32_MAX; } __chanceY = _mm_loadu_ps(_k); __chanceY = _mm_and_ps(_mm_cmpgt_ps(__chanceY, _mm_set1_ps(1.f - paramA)), __high); __xREdge = _mm_and_ps(_mm_cmpgt_ps(x, thresh), _mm_cmple_ps(__xPrev, thresh)); __yREdge = _mm_and_ps(_mm_cmpgt_ps(y, thresh), _mm_cmple_ps(__yPrev, thresh)); __xREdge = _mm_and_ps(__xREdge, __chanceX); __yREdge = _mm_and_ps(__yREdge, __chanceY); __ffTarget = _mm_switch_ps(__ffTarget, __zeros, __xREdge); __ffTarget = _mm_switch_ps(__ffTarget, __high, __yREdge); __xPrev = x; __yPrev = y; return _mm_switch_ps(x, y, __ffTarget); } __m128 VecAmalgam::alphaPWM(const __m128& x, const __m128& y, float paramA, float paramB) { __z = _mm_mul_ps(_mm_abs_ps(x), __halfs); __z = _mm_mul_ps(__z, _mm_add_ps(_mm_mul_ps(_mm_set1_ps(paramA), _mm_set1_ps(16.f)), __ones)); __m128i xInt = _mm_cvttps_epi32(__z); __m128 xIntF = _mm_cvtepi32_ps(xInt); __z = _mm_sub_ps(__z, xIntF); return _mm_mul_ps(_mm_switch_ps(x, _mm_set1_ps(0.f), _mm_cmpgt_ps(__z, _mm_set1_ps(1.f - paramB))), y); } __m128 VecAmalgam::bitAND(const __m128& x, const __m128& y, float paramA, float paramB) { paramA = 1.f - paramA * 0.8f; paramA *= paramA; downSample(_mm_varStep_ps(x, _mm_set1_ps(1.f - paramA)),_mm_varStep_ps(y, _mm_set1_ps(1.f - paramA))); __a32 = _mm_cvttps_epi32(_mm_mul_ps(__xDS, _mm_set1_ps(0x7FFFFFFF))); __b32 = _mm_cvttps_epi32(_mm_mul_ps(__yDS, _mm_set1_ps(0x7FFFFFFF))); __c32 = _mm_and_si128(__a32, __b32); return _mm_div_ps(_mm_cvtepi32_ps(__c32), _mm_set1_ps(0x7FFFFFFF)); } __m128 VecAmalgam::bitXOR(const __m128& x, const __m128& y, float paramA, float paramB) { paramA = 1.f - paramA * 0.8f; paramA *= paramA; downSample(_mm_varStep_ps(x, _mm_set1_ps(1.f - paramA)),_mm_varStep_ps(y, _mm_set1_ps(1.f - paramA))); __a32 = _mm_cvttps_epi32(_mm_mul_ps(__xDS, _mm_set1_ps(0x7FFFFFFF))); __b32 = _mm_cvttps_epi32(_mm_mul_ps(__yDS, _mm_set1_ps(0x7FFFFFFF))); __c32 = _mm_xor_si128(__a32, __b32); return _mm_div_ps(_mm_cvtepi32_ps(__c32), _mm_set1_ps(0x7FFFFFFF)); } __m128 VecAmalgam::bitInterleave(const __m128& x, const __m128& y, float paramA, float paramB) { paramA = 1.f - paramA * 0.8f; paramA *= paramA; downSample(_mm_varStep_ps(x, _mm_set1_ps(1.f - paramA)),_mm_varStep_ps(y, _mm_set1_ps(1.f - paramA))); __a32 = _mm_cvttps_epi32(_mm_mul_ps(__xDS, _mm_set1_ps(0x7FFFFFFF))); __b32 = _mm_cvttps_epi32(_mm_mul_ps(__yDS, _mm_set1_ps(0x7FFFFFFF))); __c32 = _mm_xor_si128(__a32, __b32); __c32 = _mm_or_si128(_mm_and_si128(__a32, _mm_set1_epi32(0x55555555)), _mm_and_si128(__b32, _mm_set1_epi32(0xAAAAAAAA))); return _mm_div_ps(_mm_cvtepi32_ps(__c32), _mm_set1_ps(0x7FFFFFFF)); } __m128 VecAmalgam::bitHack(const __m128& x, const __m128& y, float paramA, float paramB) { __chance32 = __high; int random = 0; for(auto i = 0; i < 4; ++i) { random = mwcRand(_z[i], _w[i]); _k32[i] = (float)random / (float)UINT32_MAX > (0.5f - paramA * paramA * 0.5f) ? random : 0xFFFFFFFF; } __chance32 = _mm_castsi128_ps(_mm_set_epi32(_k32[3], _k32[2], _k32[1], _k32[0])); downSample(x,y); __a32 = _mm_cvttps_epi32(_mm_mul_ps(__xDS, _mm_set1_ps(0x7FFFFFFF))); __b32 = _mm_cvttps_epi32(_mm_mul_ps(__yDS, _mm_set1_ps(0x7FFFFFFF))); __c32 = _mm_and_si128(_mm_or_si128(__c32, _mm_and_si128(__a32, __b32)), _mm_castps_si128(__chance32)); // Make 1 if a == 1 AND b == 1 #ifdef _MSC_VER { // workaround for MSVC "error C2675: unary '~': '__m128i' does not define this operator or a conversion to a type acceptable to the predefined operator" __m128i a32inv; a32inv.m128i_u64[0] = ~__a32.m128i_u64[0]; a32inv.m128i_u64[1] = ~__a32.m128i_u64[1]; __m128i b32inv; b32inv.m128i_u64[0] = ~__b32.m128i_u64[0]; b32inv.m128i_u64[1] = ~__b32.m128i_u64[1]; __m128i tinv = _mm_and_si128(_mm_and_si128(a32inv, b32inv), _mm_castps_si128(__chance32)); tinv.m128i_u64[0] = ~tinv.m128i_u64[0]; tinv.m128i_u64[1] = ~tinv.m128i_u64[1]; __c32 = _mm_and_si128(__c32, tinv); // Make 0 if a == 0 AND b == 0 } #else __c32 = _mm_and_si128(__c32, ~_mm_and_si128(_mm_and_si128(~__a32, ~__b32), _mm_castps_si128(__chance32))); // Make 0 if a == 0 AND b == 0 #endif __z = _mm_div_ps(_mm_cvtepi32_ps(__c32), _mm_set1_ps(0x7FFFFFFF)); __zDS = _mm_switch_ps(__zDS, __z, __sample); return __zDS; } __m128 VecAmalgam::bitANDFloat(const __m128& x, const __m128& y, float paramA, float paramB) { __chance32 = __high; int random = 0; for(auto i = 0; i < 4; ++i) { random = mwcRand(_z[i], _w[i]); _k32[i] = (float)random / (float)UINT32_MAX > (0.5f - paramA * paramA * 0.5f) ? random : 0xFFFFFFFF; } __chance32 = _mm_castsi128_ps(_mm_set_epi32(_k32[3], _k32[2], _k32[1], _k32[0])); downSample(x,y); __z = _mm_and_ps(_mm_and_ps(__xDS,__yDS), __chance32); __zDS = _mm_switch_ps(__zDS, __z, __sample); return __zDS; } __m128 VecAmalgam::bitInterleaveFloat(const __m128& x, const __m128& y, float paramA, float paramB) { paramA = 1.f - paramA * 0.8f; paramA *= paramA; downSample(_mm_varStep_ps(x, _mm_set1_ps(1.f - paramA)),_mm_varStep_ps(y, _mm_set1_ps(1.f - paramA))); return _mm_or_ps(_mm_and_ps(__xDS, _mm_castsi128_ps(_mm_set1_epi32(0x55555555))), _mm_and_ps(__yDS, _mm_castsi128_ps(_mm_set1_epi32(0xAAAAAAAA)))); } __m128 VecAmalgam::bitHackFloat(const __m128& x, const __m128& y, float paramA, float paramB) { __chance32 = __high; int random = 0; for(auto i = 0; i < 4; ++i) { random = mwcRand(_z[i], _w[i]); _k32[i] = (float)random / (float)UINT32_MAX > (0.5f - paramA * paramA * 0.5f) ? random : 0xFFFFFFFF; } __chance32 = _mm_castsi128_ps(_mm_set_epi32(_k32[3], _k32[2], _k32[1], _k32[0])); downSample(x,y); __z = _mm_and_ps(_mm_or_ps(__z, _mm_and_ps(__xDS,__yDS)), __chance32); __z = _mm_andnot_ps(_mm_and_ps(_mm_and_ps(_mm_xor_ps(__xDS, __high), _mm_xor_ps(__yDS, __high)),__chance32), __z); __zDS = _mm_switch_ps(__zDS, __z, __sample); return __zDS; }