kfr

Fast, modern C++ DSP framework, FFT, Sample Rate Conversion, FIR/IIR/Biquad Filters (SSE, AVX, AVX-512, ARM NEON)
Log | Files | Refs | README

capi_test.cpp (9982B)


      1 #define KFR_NO_C_COMPLEX_TYPES 1
      2 
      3 #include <kfr/capi.h>
      4 #include <math.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 
      8 static int failures = 0;
      9 
     10 #ifdef _MSC_VER
     11 #define CHECK(condition, message, ...)                                                                       \
     12     if (!(condition))                                                                                        \
     13     {                                                                                                        \
     14         ++failures;                                                                                          \
     15         fprintf(stderr, "[FAILED] " message "\n", __VA_ARGS__);                                              \
     16     }
     17 #else
     18 #define CHECK(condition, message, ...)                                                                       \
     19     if (!(condition))                                                                                        \
     20     {                                                                                                        \
     21         ++failures;                                                                                          \
     22         fprintf(stderr, "[FAILED] " message "\n", ##__VA_ARGS__);                                            \
     23     }
     24 #endif
     25 
     26 void test_memory()
     27 {
     28     printf("[TEST] Memory allocation\n");
     29     uint8_t* d = (uint8_t*)(kfr_allocate(256));
     30     for (size_t i = 0; i < 256; i++)
     31         d[i] = i;
     32     CHECK(kfr_allocated_size(d) == 256, "kfr_allocated_size: wrong size: %zu", kfr_allocated_size(d));
     33     d = (uint8_t*)(kfr_reallocate(d, 512));
     34     CHECK(kfr_allocated_size(d) == 512, "kfr_allocated_size: wrong size: %zu", kfr_allocated_size(d));
     35     for (size_t i = 0; i < 256; i++)
     36     {
     37         CHECK(d[i] == i, "kfr_reallocate: data lost after reallocation\n");
     38     }
     39     kfr_deallocate(d);
     40 
     41     void* page = kfr_allocate_aligned(4096, 4096);
     42     CHECK(((uintptr_t)page & 0xFFF) == 0, "kfr_allocate_aligned: wrong alignment: 0x%zx",
     43           ((uintptr_t)page & 0xFFF));
     44 
     45     kfr_deallocate(page);
     46 }
     47 
     48 #define DFT_SIZE 32
     49 
     50 static void init_data_f32(kfr_f32* buf)
     51 {
     52     for (int i = 0; i < DFT_SIZE; i++)
     53     {
     54         buf[i * 2 + 0] = (float)(i) / DFT_SIZE;
     55         buf[i * 2 + 1] = (float)(-i) / DFT_SIZE;
     56     }
     57 }
     58 static void init_data_f64(kfr_f64* buf)
     59 {
     60     for (int i = 0; i < DFT_SIZE; i++)
     61     {
     62         buf[i * 2 + 0] = (double)(i) / DFT_SIZE;
     63         buf[i * 2 + 1] = (double)(-i) / DFT_SIZE;
     64     }
     65 }
     66 
     67 static void test_data_f32(kfr_f32* buf)
     68 {
     69     const float eps = 0.00001f;
     70     for (int i = 0; i < DFT_SIZE; i++)
     71     {
     72         CHECK(fabsf(buf[i * 2 + 0] - (float)(i)) < eps, "DFT: wrong result at %d: re = %f", i,
     73               buf[i * 2 + 0]);
     74         CHECK(fabsf(buf[i * 2 + 1] - (float)(-i)) < eps, "DFT: wrong result at %d: im = %f", i,
     75               buf[i * 2 + 1]);
     76     }
     77 }
     78 static void test_data_f64(kfr_f64* buf)
     79 {
     80     const double eps = 0.00001;
     81     for (int i = 0; i < DFT_SIZE; i++)
     82     {
     83         CHECK(fabs(buf[i * 2 + 0] - (double)(i)) < eps, "DFT: wrong result at %d: re = %f", i,
     84               buf[i * 2 + 0]);
     85         CHECK(fabs(buf[i * 2 + 1] - (double)(-i)) < eps, "DFT: wrong result at %d: im = %f", i,
     86               buf[i * 2 + 1]);
     87     }
     88 }
     89 
     90 void test_dft_f32()
     91 {
     92     printf("[TEST] DFT f32\n");
     93     // kfr_dft_dump_f32(plan);
     94     kfr_f32 buf[DFT_SIZE * 2];
     95     KFR_DFT_PLAN_F32* plan;
     96     uint8_t* tmp;
     97 
     98     init_data_f32(buf);
     99     plan = kfr_dft_create_plan_f32(DFT_SIZE);
    100     tmp  = (uint8_t*)kfr_allocate(kfr_dft_get_temp_size_f32(plan));
    101     kfr_dft_execute_f32(plan, buf, buf, tmp);
    102     kfr_dft_execute_inverse_f32(plan, buf, buf, tmp);
    103     kfr_deallocate(tmp);
    104     kfr_dft_delete_plan_f32(plan);
    105     test_data_f32(buf);
    106 
    107     init_data_f32(buf);
    108     plan = kfr_dft_create_2d_plan_f32(8, 4);
    109     tmp  = (uint8_t*)kfr_allocate(kfr_dft_get_temp_size_f32(plan));
    110     kfr_dft_execute_f32(plan, buf, buf, tmp);
    111     kfr_dft_execute_inverse_f32(plan, buf, buf, tmp);
    112     kfr_deallocate(tmp);
    113     kfr_dft_delete_plan_f32(plan);
    114     test_data_f32(buf);
    115 
    116     init_data_f32(buf);
    117     plan = kfr_dft_create_3d_plan_f32(4, 4, 2);
    118     tmp  = (uint8_t*)kfr_allocate(kfr_dft_get_temp_size_f32(plan));
    119     kfr_dft_execute_f32(plan, buf, buf, tmp);
    120     kfr_dft_execute_inverse_f32(plan, buf, buf, tmp);
    121     kfr_deallocate(tmp);
    122     kfr_dft_delete_plan_f32(plan);
    123     test_data_f32(buf);
    124 
    125     unsigned sizes[4] = { 2, 2, 2, 4 };
    126     init_data_f32(buf);
    127     plan = kfr_dft_create_md_plan_f32(4, sizes);
    128     tmp  = (uint8_t*)kfr_allocate(kfr_dft_get_temp_size_f32(plan));
    129     kfr_dft_execute_f32(plan, buf, buf, tmp);
    130     kfr_dft_execute_inverse_f32(plan, buf, buf, tmp);
    131     kfr_deallocate(tmp);
    132     kfr_dft_delete_plan_f32(plan);
    133     test_data_f32(buf);
    134 }
    135 
    136 void test_dft_f64()
    137 {
    138     printf("[TEST] DFT f64\n");
    139     // kfr_dft_dump_f64(plan);
    140     kfr_f64 buf[DFT_SIZE * 2];
    141     KFR_DFT_PLAN_F64* plan;
    142     uint8_t* tmp;
    143 
    144     init_data_f64(buf);
    145     plan = kfr_dft_create_plan_f64(DFT_SIZE);
    146     tmp  = (uint8_t*)kfr_allocate(kfr_dft_get_temp_size_f64(plan));
    147     kfr_dft_execute_f64(plan, buf, buf, tmp);
    148     kfr_dft_execute_inverse_f64(plan, buf, buf, tmp);
    149     kfr_deallocate(tmp);
    150     kfr_dft_delete_plan_f64(plan);
    151     test_data_f64(buf);
    152 
    153     init_data_f64(buf);
    154     plan = kfr_dft_create_2d_plan_f64(8, 4);
    155     tmp  = (uint8_t*)kfr_allocate(kfr_dft_get_temp_size_f64(plan));
    156     kfr_dft_execute_f64(plan, buf, buf, tmp);
    157     kfr_dft_execute_inverse_f64(plan, buf, buf, tmp);
    158     kfr_deallocate(tmp);
    159     kfr_dft_delete_plan_f64(plan);
    160     test_data_f64(buf);
    161 
    162     init_data_f64(buf);
    163     plan = kfr_dft_create_3d_plan_f64(4, 4, 2);
    164     tmp  = (uint8_t*)kfr_allocate(kfr_dft_get_temp_size_f64(plan));
    165     kfr_dft_execute_f64(plan, buf, buf, tmp);
    166     kfr_dft_execute_inverse_f64(plan, buf, buf, tmp);
    167     kfr_deallocate(tmp);
    168     kfr_dft_delete_plan_f64(plan);
    169     test_data_f64(buf);
    170 
    171     unsigned sizes[4] = { 2, 2, 2, 4 };
    172     init_data_f64(buf);
    173     plan = kfr_dft_create_md_plan_f64(4, sizes);
    174     tmp  = (uint8_t*)kfr_allocate(kfr_dft_get_temp_size_f64(plan));
    175     kfr_dft_execute_f64(plan, buf, buf, tmp);
    176     kfr_dft_execute_inverse_f64(plan, buf, buf, tmp);
    177     kfr_deallocate(tmp);
    178     kfr_dft_delete_plan_f64(plan);
    179     test_data_f64(buf);
    180 }
    181 
    182 #define FILTER_SIZE 256
    183 
    184 void test_fir_f32()
    185 {
    186     printf("[TEST] FIR f32\n");
    187     kfr_f32 taps[]         = { 1.f, 2.f, -2.f, -1.f };
    188     KFR_FILTER_F32* filter = kfr_filter_create_fir_plan_f32(taps, sizeof(taps) / sizeof(kfr_f32));
    189 
    190     kfr_f32 buf[FILTER_SIZE];
    191     for (int i = 0; i < FILTER_SIZE; i++)
    192         buf[i] = i;
    193 
    194     kfr_filter_process_f32(filter, buf, buf, FILTER_SIZE);
    195     CHECK(buf[0] == 0, "FIR: wrong result at %d: %g", 0, buf[0]);
    196     CHECK(buf[1] == 1, "FIR: wrong result at %d: %g", 1, buf[1]);
    197     CHECK(buf[2] == 4, "FIR: wrong result at %d: %g", 2, buf[2]);
    198     CHECK(buf[3] == 5, "FIR: wrong result at %d: %g", 3, buf[3]);
    199     CHECK(buf[FILTER_SIZE - 1] == 5, "FIR: wrong result at %d: %g", FILTER_SIZE - 1, buf[FILTER_SIZE - 1]);
    200 
    201     kfr_filter_delete_plan_f32(filter);
    202 }
    203 
    204 void test_fir_f64()
    205 {
    206     printf("[TEST] FIR f64\n");
    207     kfr_f64 taps[]         = { 1.f, 2.f, -2.f, -1.f };
    208     KFR_FILTER_F64* filter = kfr_filter_create_fir_plan_f64(taps, sizeof(taps) / sizeof(kfr_f64));
    209 
    210     kfr_f64 buf[FILTER_SIZE];
    211     for (int i = 0; i < FILTER_SIZE; i++)
    212         buf[i] = i;
    213 
    214     kfr_filter_process_f64(filter, buf, buf, FILTER_SIZE);
    215     CHECK(buf[0] == 0, "FIR: wrong result at %d: %g", 0, buf[0]);
    216     CHECK(buf[1] == 1, "FIR: wrong result at %d: %g", 1, buf[1]);
    217     CHECK(buf[2] == 4, "FIR: wrong result at %d: %g", 2, buf[2]);
    218     CHECK(buf[3] == 5, "FIR: wrong result at %d: %g", 3, buf[3]);
    219     CHECK(buf[FILTER_SIZE - 1] == 5, "FIR: wrong result at %d: %g", FILTER_SIZE - 1, buf[FILTER_SIZE - 1]);
    220 
    221     kfr_filter_delete_plan_f64(filter);
    222 }
    223 
    224 void test_iir_f32()
    225 {
    226     const float eps = 0.00001f;
    227     printf("[TEST] IIR f32\n");
    228     float sos[6] = {
    229         1.,
    230         -1.872871474946867,
    231         0.8809814578599688,
    232         0.002027495728275458,
    233         0.004054991456550916,
    234         0.002027495728275458,
    235     };
    236     KFR_FILTER_F32* filter = kfr_filter_create_iir_plan_f32(sos, 1);
    237 
    238     kfr_f32 buf[FILTER_SIZE];
    239     kfr_f32 src[4] = { 0, 1, 0, -1 };
    240     for (int i = 0; i < FILTER_SIZE; i++)
    241         buf[i] = src[i % 4];
    242 
    243     kfr_filter_process_f32(filter, buf, buf, FILTER_SIZE);
    244 
    245     CHECK(fabsf(buf[0] - 0.f) < eps, "IIR: wrong result at %d: %f", 0, buf[0]);
    246     CHECK(fabsf(buf[1] - 0.002027496f) < eps, "IIR: wrong result at %d: %f", 1, buf[1]);
    247     CHECK(fabsf(buf[60] - -0.001285130f) < eps, "IIR: wrong result at %d: %f", 60, buf[60]);
    248 
    249     kfr_filter_delete_plan_f32(filter);
    250 }
    251 
    252 void test_iir_f64()
    253 {
    254     const double eps = 0.0000001;
    255     printf("[TEST] IIR f64\n");
    256     double sos[6] = {
    257         1.,
    258         -1.872871474946867,
    259         0.8809814578599688,
    260         0.002027495728275458,
    261         0.004054991456550916,
    262         0.002027495728275458,
    263     };
    264     KFR_FILTER_F64* filter = kfr_filter_create_iir_plan_f64(sos, 1);
    265 
    266     kfr_f64 buf[FILTER_SIZE];
    267     kfr_f64 src[4] = { 0, 1, 0, -1 };
    268     for (int i = 0; i < FILTER_SIZE; i++)
    269         buf[i] = src[i % 4];
    270 
    271     kfr_filter_process_f64(filter, buf, buf, FILTER_SIZE);
    272 
    273     CHECK(fabs(buf[0] - 0.) < eps, "IIR: wrong result at %d: %f", 0, buf[0]);
    274     CHECK(fabs(buf[1] - 0.002027496) < eps, "IIR: wrong result at %d: %f", 1, buf[1]);
    275     CHECK(fabs(buf[60] - -0.001285130) < eps, "IIR: wrong result at %d: %f", 60, buf[60]);
    276 
    277     kfr_filter_delete_plan_f64(filter);
    278 }
    279 
    280 int main()
    281 {
    282     CHECK(KFR_HEADERS_VERSION <= kfr_version(), "Dynamic library is too old. At least %d required",
    283           KFR_HEADERS_VERSION);
    284 
    285     printf("[INFO] %s\n", kfr_version_string());
    286 
    287     test_memory();
    288     test_dft_f32();
    289     test_dft_f64();
    290     test_fir_f32();
    291     test_fir_f64();
    292     test_iir_f32();
    293     test_iir_f64();
    294 
    295     if (failures == 0)
    296         printf("[PASSED]\n");
    297     else
    298         printf("[FAILED] %d check(s)\n", failures);
    299     return failures;
    300 }