1 #pragma once
2 #include "vt_dsp.h"
3 #include "shared.h"
4 
5 /*
6 ** lipol_ps is a small utility class for generating small line segments
7 ** between values
8 **
9 ** usage would be
10 **
11 ** ```
12 ** lipol_ps mypol;
13 **
14 ** ...
15 **
16 ** mypol.set_target(13.23);
17 ** if( init )
18 **   mypol.instantize();
19 ** ```
20 **
21 ** then later in the code
22 **
23 ** ```
24 ** float values alignas(16)[SIZE]
25 ** mypol.store_block(values, SIZE_OVER_FOUR);
26 ** ```
27 **
28 ** and block would contain the linear interpolation between the
29 ** last queried value and the target.
30 */
31 class lipol_ps
32 {
33   public:
34     __m128 target, currentval, coef, coef_m1;
35     __m128 lipol_BLOCK_SIZE;
36     __m128 m128_lipolstarter;
37     __m128 m128_bs4_inv;
38 
39     lipol_ps();
40 
set_target(float t)41     inline void set_target(float t)
42     {
43         currentval = target;
44         target = _mm_set_ss(t);
45     }
46 
set_target(__m128 t)47     inline void set_target(__m128 t)
48     {
49         currentval = target;
50         target = t;
51     }
set_target_instantize(float t)52     inline void set_target_instantize(float t)
53     {
54         target = _mm_set_ss(t);
55         currentval = target;
56     }
set_target_smoothed(float t)57     inline void set_target_smoothed(float t)
58     {
59         currentval = target;
60         __m128 p1 = _mm_mul_ss(coef, _mm_set_ss(t));
61         __m128 p2 = _mm_mul_ss(coef_m1, target);
62         target = _mm_add_ss(p1, p2);
63     }
64     void set_blocksize(int bs);
65 
66     // inline void set_target(__m128 t) { currentval = target; target = t; }
instantize()67     inline void instantize() { currentval = target; }
get_target()68     float get_target()
69     {
70         float f;
71         _mm_store_ss(&f, target);
72         return f;
73     }
74     void store_block(float *dst, unsigned int nquads);
75     void multiply_block(float *src, unsigned int nquads);
76     void multiply_block_sat1(
77         float *src,
78         unsigned int nquads); // saturates the interpolator each step (for amp envelopes)
79     void add_block(float *src, unsigned int nquads);
80     void fade_block_to(float *src1, float *src2, float *dst, unsigned int nquads);
81     void fade_2_blocks_to(float *src11, float *src12, float *src21, float *src22, float *dst1,
82                           float *dst2, unsigned int nquads);
83     void subtract_block(float *src, unsigned int nquads);
84     void trixpan_blocks(float *L, float *R, float *dL, float *dR,
85                         unsigned int nquads); // panning that always lets both channels through
86                                               // unattenuated (seperate hard-panning)
87     void multiply_block_to(float *src, float *dst, unsigned int nquads);
88     void multiply_2_blocks(float *src1, float *src2, unsigned int nquads);
89     void multiply_2_blocks_to(float *src1, float *src2, float *dst1, float *dst2,
90                               unsigned int nquads);
91     void MAC_block_to(float *src, float *dst, unsigned int nquads);
92     void MAC_2_blocks_to(float *src1, float *src2, float *dst1, float *dst2, unsigned int nquads);
93 
94   private:
initblock(__m128 & y,__m128 & dy)95     inline void initblock(__m128 &y, __m128 &dy)
96     {
97         dy = _mm_sub_ss(target, currentval);
98         dy = _mm_mul_ss(dy, m128_bs4_inv);
99         dy = _mm_shuffle_ps(dy, dy, _MM_SHUFFLE(0, 0, 0, 0));
100         y = _mm_shuffle_ps(currentval, currentval, _MM_SHUFFLE(0, 0, 0, 0));
101         y = _mm_add_ps(y, _mm_mul_ps(dy, m128_lipolstarter));
102     }
103 };
104