1 /* 2 This software is part of pffft/pfdsp, a set of simple DSP routines. 3 4 Copyright (c) 2014, Andras Retzler <randras@sdr.hu> 5 Copyright (c) 2020 Hayati Ayguen <h_ayguen@web.de> 6 All rights reserved. 7 8 Redistribution and use in source and binary forms, with or without 9 modification, are permitted provided that the following conditions are met: 10 * Redistributions of source code must retain the above copyright 11 notice, this list of conditions and the following disclaimer. 12 * Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions and the following disclaimer in the 14 documentation and/or other materials provided with the distribution. 15 * Neither the name of the copyright holder nor the 16 names of its contributors may be used to endorse or promote products 17 derived from this software without specific prior written permission. 18 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY 23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #pragma once 32 33 #include <stdio.h> 34 #include <stdint.h> 35 36 #include "pf_cplx.h" 37 38 #ifdef __cplusplus 39 extern "C" { 40 #endif 41 42 43 // ================================================================================= 44 45 int have_sse_shift_mixer_impl(); 46 47 48 /*********************************************************************/ 49 50 /**************/ 51 /*** ALGO A ***/ 52 /**************/ 53 54 float shift_math_cc(const complexf *input, complexf* output, int input_size, float rate, float starting_phase); 55 56 57 /*********************************************************************/ 58 59 /**************/ 60 /*** ALGO B ***/ 61 /**************/ 62 63 typedef struct shift_table_data_s 64 { 65 float* table; 66 int table_size; 67 } shift_table_data_t; 68 69 void shift_table_deinit(shift_table_data_t table_data); 70 shift_table_data_t shift_table_init(int table_size); 71 float shift_table_cc(complexf* input, complexf* output, int input_size, float rate, shift_table_data_t table_data, float starting_phase); 72 73 /*********************************************************************/ 74 75 /**************/ 76 /*** ALGO C ***/ 77 /**************/ 78 79 typedef struct shift_addfast_data_s 80 { 81 float dsin[4]; 82 float dcos[4]; 83 float phase_increment; 84 } shift_addfast_data_t; 85 86 shift_addfast_data_t shift_addfast_init(float rate); 87 float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_addfast_data_t* d, float starting_phase); 88 float shift_addfast_inp_c(complexf *in_out, int N_cplx, shift_addfast_data_t* d, float starting_phase); 89 90 91 /*********************************************************************/ 92 93 /**************/ 94 /*** ALGO D ***/ 95 /**************/ 96 97 typedef struct shift_unroll_data_s 98 { 99 float* dsin; 100 float* dcos; 101 float phase_increment; 102 int size; 103 } shift_unroll_data_t; 104 105 shift_unroll_data_t shift_unroll_init(float rate, int size); 106 void shift_unroll_deinit(shift_unroll_data_t* d); 107 float shift_unroll_cc(complexf *input, complexf* output, int size, shift_unroll_data_t* d, float starting_phase); 108 float shift_unroll_inp_c(complexf* in_out, int size, shift_unroll_data_t* d, float starting_phase); 109 110 111 /*********************************************************************/ 112 113 /**************/ 114 /*** ALGO E ***/ 115 /**************/ 116 117 /* similar to shift_unroll_cc() - but, have fixed and limited precalc size 118 * idea: smaller cache usage by table 119 * size must be multiple of CSDR_SHIFT_LIMITED_SIMD (= 4) 120 */ 121 #define PF_SHIFT_LIMITED_UNROLL_SIZE 128 122 #define PF_SHIFT_LIMITED_SIMD_SZ 4 123 124 typedef struct shift_limited_unroll_data_s 125 { 126 float dcos[PF_SHIFT_LIMITED_UNROLL_SIZE]; 127 float dsin[PF_SHIFT_LIMITED_UNROLL_SIZE]; 128 complexf complex_phase; 129 float phase_increment; 130 } shift_limited_unroll_data_t; 131 132 shift_limited_unroll_data_t shift_limited_unroll_init(float rate); 133 /* size must be multiple of PF_SHIFT_LIMITED_SIMD_SZ */ 134 /* starting_phase for next call is kept internal in state */ 135 void shift_limited_unroll_cc(const complexf *input, complexf* output, int size, shift_limited_unroll_data_t* d); 136 void shift_limited_unroll_inp_c(complexf* in_out, int size, shift_limited_unroll_data_t* d); 137 138 139 /*********************************************************************/ 140 141 /**************/ 142 /*** ALGO F ***/ 143 /**************/ 144 145 typedef struct shift_limited_unroll_A_sse_data_s 146 { 147 /* small/limited trig table */ 148 float dcos[PF_SHIFT_LIMITED_UNROLL_SIZE+PF_SHIFT_LIMITED_SIMD_SZ]; 149 float dsin[PF_SHIFT_LIMITED_UNROLL_SIZE+PF_SHIFT_LIMITED_SIMD_SZ]; 150 /* 4 times complex phase */ 151 float phase_state_i[PF_SHIFT_LIMITED_SIMD_SZ]; 152 float phase_state_q[PF_SHIFT_LIMITED_SIMD_SZ]; 153 /* N_cplx_per_block times increment - for future parallel variants */ 154 float dcos_blk; 155 float dsin_blk; 156 /* */ 157 float phase_increment; 158 } shift_limited_unroll_A_sse_data_t; 159 160 shift_limited_unroll_A_sse_data_t shift_limited_unroll_A_sse_init(float relative_freq, float phase_start_rad); 161 void shift_limited_unroll_A_sse_inp_c(complexf* in_out, int N_cplx, shift_limited_unroll_A_sse_data_t* d); 162 163 164 /*********************************************************************/ 165 166 /**************/ 167 /*** ALGO G ***/ 168 /**************/ 169 170 typedef struct shift_limited_unroll_B_sse_data_s 171 { 172 /* small/limited trig table */ 173 float dtrig[PF_SHIFT_LIMITED_UNROLL_SIZE+PF_SHIFT_LIMITED_SIMD_SZ]; 174 /* 4 times complex phase */ 175 float phase_state_i[PF_SHIFT_LIMITED_SIMD_SZ]; 176 float phase_state_q[PF_SHIFT_LIMITED_SIMD_SZ]; 177 /* N_cplx_per_block times increment - for future parallel variants */ 178 float dcos_blk; 179 float dsin_blk; 180 /* */ 181 float phase_increment; 182 } shift_limited_unroll_B_sse_data_t; 183 184 shift_limited_unroll_B_sse_data_t shift_limited_unroll_B_sse_init(float relative_freq, float phase_start_rad); 185 void shift_limited_unroll_B_sse_inp_c(complexf* in_out, int N_cplx, shift_limited_unroll_B_sse_data_t* d); 186 187 /*********************************************************************/ 188 189 /**************/ 190 /*** ALGO H ***/ 191 /**************/ 192 193 typedef struct shift_limited_unroll_C_sse_data_s 194 { 195 /* small/limited trig table - interleaved: 4 cos, 4 sin, 4 cos, .. */ 196 float dinterl_trig[2*(PF_SHIFT_LIMITED_UNROLL_SIZE+PF_SHIFT_LIMITED_SIMD_SZ)]; 197 /* 4 times complex phase */ 198 float phase_state_i[PF_SHIFT_LIMITED_SIMD_SZ]; 199 float phase_state_q[PF_SHIFT_LIMITED_SIMD_SZ]; 200 /* N_cplx_per_block times increment - for future parallel variants */ 201 float dcos_blk; 202 float dsin_blk; 203 /* */ 204 float phase_increment; 205 } shift_limited_unroll_C_sse_data_t; 206 207 shift_limited_unroll_C_sse_data_t shift_limited_unroll_C_sse_init(float relative_freq, float phase_start_rad); 208 void shift_limited_unroll_C_sse_inp_c(complexf* in_out, int N_cplx, shift_limited_unroll_C_sse_data_t* d); 209 210 211 212 /*********************************************************************/ 213 214 /**************/ 215 /*** ALGO I ***/ 216 /**************/ 217 218 /* Recursive Quadrature Oscillator functions "recursive_osc" 219 * see https://www.vicanek.de/articles/QuadOsc.pdf 220 */ 221 #define PF_SHIFT_RECURSIVE_SIMD_SZ 8 222 typedef struct shift_recursive_osc_s 223 { 224 float u_cos[PF_SHIFT_RECURSIVE_SIMD_SZ]; 225 float v_sin[PF_SHIFT_RECURSIVE_SIMD_SZ]; 226 } shift_recursive_osc_t; 227 228 typedef struct shift_recursive_osc_conf_s 229 { 230 float k1; 231 float k2; 232 } shift_recursive_osc_conf_t; 233 234 void shift_recursive_osc_init(float rate, float starting_phase, shift_recursive_osc_conf_t *conf, shift_recursive_osc_t *state); 235 void shift_recursive_osc_update_rate(float rate, shift_recursive_osc_conf_t *conf, shift_recursive_osc_t* state); 236 237 /* size must be multiple of PF_SHIFT_LIMITED_SIMD_SZ */ 238 /* starting_phase for next call is kept internal in state */ 239 void shift_recursive_osc_cc(const complexf *input, complexf* output, int size, const shift_recursive_osc_conf_t *conf, shift_recursive_osc_t* state); 240 void shift_recursive_osc_inp_c(complexf* output, int size, const shift_recursive_osc_conf_t *conf, shift_recursive_osc_t* state); 241 void gen_recursive_osc_c(complexf* output, int size, const shift_recursive_osc_conf_t *conf, shift_recursive_osc_t* state); 242 243 /*********************************************************************/ 244 245 /**************/ 246 /*** ALGO J ***/ 247 /**************/ 248 249 #define PF_SHIFT_RECURSIVE_SIMD_SSE_SZ 4 250 typedef struct shift_recursive_osc_sse_s 251 { 252 float u_cos[PF_SHIFT_RECURSIVE_SIMD_SSE_SZ]; 253 float v_sin[PF_SHIFT_RECURSIVE_SIMD_SSE_SZ]; 254 } shift_recursive_osc_sse_t; 255 256 typedef struct shift_recursive_osc_sse_conf_s 257 { 258 float k1; 259 float k2; 260 } shift_recursive_osc_sse_conf_t; 261 262 void shift_recursive_osc_sse_init(float rate, float starting_phase, shift_recursive_osc_sse_conf_t *conf, shift_recursive_osc_sse_t *state); 263 void shift_recursive_osc_sse_update_rate(float rate, shift_recursive_osc_sse_conf_t *conf, shift_recursive_osc_sse_t* state); 264 void shift_recursive_osc_sse_inp_c(complexf* in_out, int N_cplx, const shift_recursive_osc_sse_conf_t *conf, shift_recursive_osc_sse_t* state_ext); 265 266 267 #ifdef __cplusplus 268 } 269 #endif 270 271