annotate projects/heavy/envelopeTrigger/SignalPhasor.h @ 162:c3e8226a5651 heavy-updated

- added additional flags to C rules (-DNDEBUG, -mfpu=neon) - sample-accurate envelope triggering pd/heavy example
author chnrx <chris.heinrichs@gmail.com>
date Thu, 12 Nov 2015 14:59:46 +0000
parents
children
rev   line source
chris@162 1 /**
chris@162 2 * Copyright (c) 2014, 2015, Enzien Audio Ltd.
chris@162 3 *
chris@162 4 * Permission to use, copy, modify, and/or distribute this software for any
chris@162 5 * purpose with or without fee is hereby granted, provided that the above
chris@162 6 * copyright notice and this permission notice appear in all copies.
chris@162 7 *
chris@162 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
chris@162 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
chris@162 10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
chris@162 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
chris@162 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
chris@162 13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
chris@162 14 * PERFORMANCE OF THIS SOFTWARE.
chris@162 15 */
chris@162 16
chris@162 17 #ifndef _HEAVY_SIGNAL_PHASOR_H_
chris@162 18 #define _HEAVY_SIGNAL_PHASOR_H_
chris@162 19
chris@162 20 #include "HvBase.h"
chris@162 21
chris@162 22 typedef struct SignalPhasor {
chris@162 23 #if HV_SIMD_AVX
chris@162 24 __m256 phase; // current phase
chris@162 25 __m256 inc; // phase increment
chris@162 26 #elif HV_SIMD_SSE
chris@162 27 __m128i phase;
chris@162 28 __m128i inc;
chris@162 29 #elif HV_SIMD_NEON
chris@162 30 uint32x4_t phase;
chris@162 31 int32x4_t inc;
chris@162 32 #else // HV_SIMD_NONE
chris@162 33 hv_uint32_t phase;
chris@162 34 hv_int32_t inc;
chris@162 35 #endif
chris@162 36 union {
chris@162 37 float f2sc; // float to step conversion (used for __phasor~f)
chris@162 38 hv_int32_t s; // step value (used for __phasor_k~f)
chris@162 39 } step;
chris@162 40 } SignalPhasor;
chris@162 41
chris@162 42 hv_size_t sPhasor_init(SignalPhasor *o, double samplerate);
chris@162 43
chris@162 44 hv_size_t sPhasor_k_init(SignalPhasor *o, float frequency, double samplerate);
chris@162 45
chris@162 46 void sPhasor_k_onMessage(HvBase *_c, SignalPhasor *o, int letIn, const HvMessage *m);
chris@162 47
chris@162 48 void sPhasor_onMessage(HvBase *_c, SignalPhasor *o, int letIn, const HvMessage *m);
chris@162 49
chris@162 50 static inline void __hv_phasor_f(SignalPhasor *o, hv_bInf_t bIn, hv_bOutf_t bOut) {
chris@162 51 #if HV_SIMD_AVX
chris@162 52 __m256 p = _mm256_mul_ps(bIn, _mm256_set1_ps(o->step.f2sc)); // a b c d e f g h
chris@162 53
chris@162 54 __m256 z = _mm256_setzero_ps();
chris@162 55
chris@162 56 // http://stackoverflow.com/questions/11906814/how-to-rotate-an-sse-avx-vector
chris@162 57 __m256 a = _mm256_permute_ps(p, _MM_SHUFFLE(2,1,0,3)); // d a b c h e f g
chris@162 58 __m256 b = _mm256_permute2f128_ps(a, a, 0x01); // h e f g d a b c
chris@162 59 __m256 c = _mm256_blend_ps(a, b, 0x10); // d a b c d e f g
chris@162 60 __m256 d = _mm256_blend_ps(c, z, 0x01); // 0 a b c d e f g
chris@162 61 __m256 e = _mm256_add_ps(p, d); // a (a+b) (b+c) (c+d) (d+e) (e+f) (f+g) (g+h)
chris@162 62
chris@162 63 __m256 f = _mm256_permute_ps(e, _MM_SHUFFLE(1,0,3,2)); // (b+c) (c+d) a (a+b) (f+g) (g+h) (d+e) (e+f)
chris@162 64 __m256 g = _mm256_permute2f128_ps(f, f, 0x01); // (f+g) (g+h) (d+e) (e+f) (b+c) (c+d) a (a+b)
chris@162 65 __m256 h = _mm256_blend_ps(f, g, 0x33); // (b+c) (c+d) a (a+b) (b+c) (c+d) (d+e) (e+f)
chris@162 66 __m256 i = _mm256_blend_ps(h, z, 0x03); // 0 0 a (a+b) (b+c) (c+d) (d+e) (e+f)
chris@162 67 __m256 j = _mm256_add_ps(e, i); // a (a+b) (a+b+c) (a+b+c+d) (b+c+d+e) (c+d+e+f) (d+e+f+g) (e+f+g+h)
chris@162 68
chris@162 69 __m256 k = _mm256_permute2f128_ps(j, z, 0x02); // 0 0 0 0 a (a+b) (a+b+c) (a+b+c+d) (b+c+d+e)
chris@162 70 __m256 m = _mm256_add_ps(j, k); // a (a+b) (a+b+c) (a+b+c+d) (a+b+c+d+e) (a+b+c+d+e+f) (a+b+c+d+e+f+g) (a+b+c+d+e+f+g+h)
chris@162 71
chris@162 72 __m256 n = _mm256_or_ps(_mm256_andnot_ps(
chris@162 73 _mm256_set1_ps(-INFINITY),
chris@162 74 _mm256_add_ps(o->phase, m)),
chris@162 75 _mm256_set1_ps(1.0f));
chris@162 76
chris@162 77 *bOut = _mm256_sub_ps(n, _mm256_set1_ps(1.0f));
chris@162 78
chris@162 79 __m256 x = _mm256_permute_ps(n, _MM_SHUFFLE(3,3,3,3));
chris@162 80 o->phase = _mm256_permute2f128_ps(x, x, 0x11);
chris@162 81 #elif HV_SIMD_SSE
chris@162 82 __m128i p = _mm_cvtps_epi32(_mm_mul_ps(bIn, _mm_set1_ps(o->step.f2sc))); // convert frequency to step
chris@162 83 p = _mm_add_epi32(p, _mm_slli_si128(p, 4)); // add incremental steps to phase (prefix sum)
chris@162 84 p = _mm_add_epi32(p, _mm_slli_si128(p, 8)); // http://stackoverflow.com/questions/10587598/simd-prefix-sum-on-intel-cpu?rq=1
chris@162 85 p = _mm_add_epi32(o->phase, p);
chris@162 86 *bOut = _mm_sub_ps(_mm_castsi128_ps(
chris@162 87 _mm_or_si128(_mm_srli_epi32(p, 9),
chris@162 88 (__m128i) {0x3F8000003F800000L, 0x3F8000003F800000L})),
chris@162 89 _mm_set1_ps(1.0f));
chris@162 90 o->phase = _mm_shuffle_epi32(p, _MM_SHUFFLE(3,3,3,3));
chris@162 91 #elif HV_SIMD_NEON
chris@162 92 int32x4_t p = vcvtq_s32_f32(vmulq_n_f32(bIn, o->step.f2sc));
chris@162 93 p = vaddq_s32(p, vextq_s32(vdupq_n_s32(0), p, 3)); // http://stackoverflow.com/questions/11259596/arm-neon-intrinsics-rotation
chris@162 94 p = vaddq_s32(p, vextq_s32(vdupq_n_s32(0), p, 2));
chris@162 95 uint32x4_t pp = vaddq_u32(o->phase, vreinterpretq_u32_s32(p));
chris@162 96 *bOut = vsubq_f32(vreinterpretq_f32_u32(vorrq_u32(vshrq_n_u32(pp, 9), vdupq_n_u32(0x3F800000))), vdupq_n_f32(1.0f));
chris@162 97 o->phase = vdupq_n_u32(pp[3]);
chris@162 98 #else // HV_SIMD_NONE
chris@162 99 const hv_uint32_t p = (o->phase >> 9) | 0x3F800000;
chris@162 100 *bOut = *((float *) (&p)) - 1.0f;
chris@162 101 o->phase += ((int) (bIn * o->step.f2sc));
chris@162 102 #endif
chris@162 103 }
chris@162 104
chris@162 105 static inline void __hv_phasor_k_f(SignalPhasor *o, hv_bOutf_t bOut) {
chris@162 106 #if HV_SIMD_AVX
chris@162 107 *bOut = _mm256_sub_ps(o->phase, _mm256_set1_ps(1.0f));
chris@162 108 o->phase = _mm256_or_ps(_mm256_andnot_ps(
chris@162 109 _mm256_set1_ps(-INFINITY),
chris@162 110 _mm256_add_ps(o->phase, o->inc)),
chris@162 111 _mm256_set1_ps(1.0f));
chris@162 112 #elif HV_SIMD_SSE
chris@162 113 *bOut = _mm_sub_ps(_mm_castsi128_ps(
chris@162 114 _mm_or_si128(_mm_srli_epi32(o->phase, 9),
chris@162 115 (__m128i) {0x3F8000003F800000L, 0x3F8000003F800000L})),
chris@162 116 _mm_set1_ps(1.0f));
chris@162 117 o->phase = _mm_add_epi32(o->phase, o->inc);
chris@162 118 #elif HV_SIMD_NEON
chris@162 119 *bOut = vsubq_f32(vreinterpretq_f32_u32(
chris@162 120 vorrq_u32(vshrq_n_u32(o->phase, 9),
chris@162 121 vdupq_n_u32(0x3F800000))),
chris@162 122 vdupq_n_f32(1.0f));
chris@162 123 o->phase = vaddq_u32(o->phase, vreinterpretq_u32_s32(o->inc));
chris@162 124 #else // HV_SIMD_NONE
chris@162 125 const hv_uint32_t p = (o->phase >> 9) | 0x3F800000;
chris@162 126 *bOut = *((float *) (&p)) - 1.0f;
chris@162 127 o->phase += o->inc;
chris@162 128 #endif
chris@162 129 }
chris@162 130
chris@162 131 #endif // _HEAVY_SIGNAL_PHASOR_H_