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.cpp (21807B)


      1 /** @addtogroup dft
      2  *  @{
      3  */
      4 /*
      5   Copyright (C) 2016-2023 Dan Cazarin (https://www.kfrlib.com)
      6   This file is part of KFR
      7 
      8   KFR is free software: you can redistribute it and/or modify
      9   it under the terms of the GNU General Public License as published by
     10   the Free Software Foundation, either version 2 of the License, or
     11   (at your option) any later version.
     12 
     13   KFR is distributed in the hope that it will be useful,
     14   but WITHOUT ANY WARRANTY; without even the implied warranty of
     15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16   GNU General Public License for more details.
     17 
     18   You should have received a copy of the GNU General Public License
     19   along with KFR.
     20 
     21   If GPL is not suitable for your project, you must purchase a commercial license to use KFR.
     22   Buying a commercial license is mandatory as soon as you develop commercial activities without
     23   disclosing the source code of your own applications.
     24   See https://www.kfrlib.com for details.
     25  */
     26 #include <variant>
     27 #define KFR_NO_C_COMPLEX_TYPES 1
     28 
     29 #include <kfr/capi.h>
     30 #include <kfr/dft.hpp>
     31 #include <kfr/dsp.hpp>
     32 #include <kfr/multiarch.h>
     33 
     34 namespace kfr
     35 {
     36 static thread_local std::array<char, 256> error;
     37 
     38 void reset_error() { std::fill(error.begin(), error.end(), 0); }
     39 void set_error(std::string_view s)
     40 {
     41     size_t n = std::min(s.size(), error.size() - 1);
     42     auto end = std::copy_n(s.begin(), n, error.begin());
     43     std::fill(end, error.end(), 0);
     44 }
     45 
     46 template <typename Fn, typename R = std::invoke_result_t<Fn>, typename T>
     47 static R try_fn(Fn&& fn, T fallback)
     48 {
     49     try
     50     {
     51         auto result = fn();
     52         reset_error();
     53         return result;
     54     }
     55     catch (std::exception& e)
     56     {
     57         set_error(e.what());
     58         return fallback;
     59     }
     60     catch (...)
     61     {
     62         set_error("(unknown exception)");
     63         return fallback;
     64     }
     65 }
     66 
     67 template <typename Fn>
     68 static void try_fn(Fn&& fn)
     69 {
     70     try
     71     {
     72         fn();
     73         reset_error();
     74     }
     75     catch (std::exception& e)
     76     {
     77         set_error(e.what());
     78     }
     79     catch (...)
     80     {
     81         set_error("(unknown exception)");
     82     }
     83 }
     84 
     85 template <typename T>
     86 class var_dft_plan
     87 {
     88 public:
     89     virtual ~var_dft_plan() {}
     90     virtual void dump()                             = 0;
     91     virtual size_t size()                           = 0;
     92     virtual size_t temp_size()                      = 0;
     93     virtual void execute(T*, const T*, u8*)         = 0;
     94     virtual void execute_inverse(T*, const T*, u8*) = 0;
     95 };
     96 
     97 static shape<dynamic_shape> init_shape(size_t dims, const unsigned* shape_)
     98 {
     99     shape<dynamic_shape> sh(dims);
    100     for (size_t i = 0; i < dims; ++i)
    101     {
    102         sh[i] = shape_[i];
    103     }
    104     return sh;
    105 }
    106 
    107 template <typename T, size_t Dims>
    108 struct var_dft_plan_select
    109 {
    110     using complex = dft_plan_md<T, dynamic_shape>;
    111     using real    = dft_plan_md_real<T, dynamic_shape>;
    112 
    113     static size_t size(const complex& plan) { return plan.size.product(); }
    114     static size_t size(const real& plan) { return plan.size.product(); }
    115 };
    116 template <typename T>
    117 struct var_dft_plan_select<T, 1>
    118 {
    119     using complex = dft_plan<T>;
    120     using real    = dft_plan_real<T>;
    121 
    122     static size_t size(const complex& plan) { return plan.size; }
    123     static size_t size(const real& plan) { return plan.size; }
    124 };
    125 
    126 template <typename T, size_t Dims>
    127 class var_dft_plan_impl final : public var_dft_plan<T>
    128 {
    129 public:
    130     template <typename... Args>
    131     CMT_ALWAYS_INLINE var_dft_plan_impl(Args&&... args) : plan(std::forward<Args>(args)...)
    132     {
    133     }
    134     typename var_dft_plan_select<T, Dims>::complex plan;
    135     void dump() { plan.dump(); }
    136     size_t size() { return var_dft_plan_select<T, Dims>::size(plan); }
    137     size_t temp_size() { return plan.temp_size; }
    138     void execute(T* out, const T* in, u8* temp)
    139     {
    140         plan.execute(reinterpret_cast<complex<T>*>(out), reinterpret_cast<const complex<T>*>(in), temp,
    141                      cfalse);
    142     }
    143     void execute_inverse(T* out, const T* in, u8* temp)
    144     {
    145         plan.execute(reinterpret_cast<complex<T>*>(out), reinterpret_cast<const complex<T>*>(in), temp,
    146                      ctrue);
    147     }
    148 };
    149 
    150 template <typename T, size_t Dims>
    151 class var_dft_plan_real_impl final : public var_dft_plan<T>
    152 {
    153 public:
    154     template <typename... Args>
    155     CMT_ALWAYS_INLINE var_dft_plan_real_impl(Args&&... args) : plan(std::forward<Args>(args)...)
    156     {
    157     }
    158     typename var_dft_plan_select<T, Dims>::real plan;
    159     void dump() { plan.dump(); }
    160     size_t size() { return var_dft_plan_select<T, Dims>::size(plan); }
    161     size_t temp_size() { return plan.temp_size; }
    162     void execute(T* out, const T* in, u8* temp)
    163     {
    164         plan.execute(reinterpret_cast<complex<T>*>(out), reinterpret_cast<const T*>(in), temp, cfalse);
    165     }
    166     void execute_inverse(T* out, const T* in, u8* temp)
    167     {
    168         plan.execute(reinterpret_cast<T*>(out), reinterpret_cast<const complex<T>*>(in), temp, ctrue);
    169     }
    170 };
    171 
    172 extern "C"
    173 {
    174 KFR_API_SPEC const char* kfr_version_string()
    175 {
    176     return "KFR " KFR_VERSION_STRING KFR_DEBUG_STR " " KFR_ENABLED_ARCHS_LIST " " CMT_ARCH_BITNESS_NAME
    177            " (" CMT_COMPILER_FULL_NAME "/" CMT_OS_NAME ")" KFR_BUILD_DETAILS_1 KFR_BUILD_DETAILS_2;
    178 }
    179 KFR_API_SPEC uint32_t kfr_version() { return KFR_VERSION; }
    180 KFR_API_SPEC const char* kfr_enabled_archs() { return KFR_ENABLED_ARCHS_LIST; }
    181 KFR_API_SPEC int kfr_current_arch() { return static_cast<int>(get_cpu()); }
    182 
    183 KFR_API_SPEC const char* kfr_last_error() { return error.data(); }
    184 
    185 KFR_API_SPEC void* kfr_allocate(size_t size) { return details::aligned_malloc(size, KFR_DEFAULT_ALIGNMENT); }
    186 KFR_API_SPEC void* kfr_allocate_aligned(size_t size, size_t alignment)
    187 {
    188     return details::aligned_malloc(size, alignment);
    189 }
    190 KFR_API_SPEC void kfr_deallocate(void* ptr) { return details::aligned_free(ptr); }
    191 KFR_API_SPEC size_t kfr_allocated_size(void* ptr) { return details::aligned_size(ptr); }
    192 
    193 KFR_API_SPEC void* kfr_add_ref(void* ptr)
    194 {
    195     details::aligned_add_ref(ptr);
    196     return ptr;
    197 }
    198 KFR_API_SPEC void kfr_release(void* ptr) { details::aligned_release(ptr); }
    199 
    200 KFR_API_SPEC void* kfr_reallocate(void* ptr, size_t new_size)
    201 {
    202     return details::aligned_reallocate(ptr, new_size, KFR_DEFAULT_ALIGNMENT);
    203 }
    204 KFR_API_SPEC void* kfr_reallocate_aligned(void* ptr, size_t new_size, size_t alignment)
    205 {
    206     return details::aligned_reallocate(ptr, new_size, alignment);
    207 }
    208 
    209 KFR_API_SPEC KFR_DFT_PLAN_F32* kfr_dft_create_plan_f32(size_t size)
    210 {
    211     return try_fn([&]()
    212                   { return reinterpret_cast<KFR_DFT_PLAN_F32*>(new var_dft_plan_impl<float, 1>(size)); },
    213                   nullptr);
    214 }
    215 
    216 KFR_API_SPEC KFR_DFT_PLAN_F32* kfr_dft_create_2d_plan_f32(size_t size1, size_t size2)
    217 {
    218     return try_fn(
    219         [&]() {
    220             return reinterpret_cast<KFR_DFT_PLAN_F32*>(
    221                 new var_dft_plan_impl<float, 2>(shape{ size1, size2 }));
    222         },
    223         nullptr);
    224 }
    225 KFR_API_SPEC KFR_DFT_PLAN_F32* kfr_dft_create_3d_plan_f32(size_t size1, size_t size2, size_t size3)
    226 {
    227     return try_fn(
    228         [&]()
    229         {
    230             return reinterpret_cast<KFR_DFT_PLAN_F32*>(
    231                 new var_dft_plan_impl<float, 3>(shape{ size1, size2, size3 }));
    232         },
    233         nullptr);
    234 }
    235 KFR_API_SPEC KFR_DFT_PLAN_F32* kfr_dft_create_md_plan_f32(size_t dims, const unsigned* shape)
    236 {
    237     return try_fn(
    238         [&]()
    239         {
    240             return reinterpret_cast<KFR_DFT_PLAN_F32*>(
    241                 new var_dft_plan_impl<float, dynamic_shape>(init_shape(dims, shape)));
    242         },
    243         nullptr);
    244 }
    245 KFR_API_SPEC KFR_DFT_PLAN_F64* kfr_dft_create_plan_f64(size_t size)
    246 {
    247     return try_fn([&]()
    248                   { return reinterpret_cast<KFR_DFT_PLAN_F64*>(new var_dft_plan_impl<double, 1>(size)); },
    249                   nullptr);
    250 }
    251 KFR_API_SPEC KFR_DFT_PLAN_F64* kfr_dft_create_2d_plan_f64(size_t size1, size_t size2)
    252 {
    253     return try_fn(
    254         [&]() {
    255             return reinterpret_cast<KFR_DFT_PLAN_F64*>(
    256                 new var_dft_plan_impl<double, 2>(shape{ size1, size2 }));
    257         },
    258         nullptr);
    259 }
    260 KFR_API_SPEC KFR_DFT_PLAN_F64* kfr_dft_create_3d_plan_f64(size_t size1, size_t size2, size_t size3)
    261 {
    262     return try_fn(
    263         [&]()
    264         {
    265             return reinterpret_cast<KFR_DFT_PLAN_F64*>(
    266                 new var_dft_plan_impl<double, 3>(shape{ size1, size2, size3 }));
    267         },
    268         nullptr);
    269 }
    270 KFR_API_SPEC KFR_DFT_PLAN_F64* kfr_dft_create_md_plan_f64(size_t dims, const unsigned* shape)
    271 {
    272     return try_fn(
    273         [&]()
    274         {
    275             return reinterpret_cast<KFR_DFT_PLAN_F64*>(
    276                 new var_dft_plan_impl<double, dynamic_shape>(init_shape(dims, shape)));
    277         },
    278         nullptr);
    279 }
    280 
    281 KFR_API_SPEC void kfr_dft_dump_f32(KFR_DFT_PLAN_F32* plan)
    282 {
    283     try_fn([&] { reinterpret_cast<var_dft_plan<float>*>(plan)->dump(); });
    284 }
    285 KFR_API_SPEC void kfr_dft_dump_f64(KFR_DFT_PLAN_F64* plan)
    286 {
    287     try_fn([&] { reinterpret_cast<var_dft_plan<double>*>(plan)->dump(); });
    288 }
    289 
    290 KFR_API_SPEC size_t kfr_dft_get_size_f32(KFR_DFT_PLAN_F32* plan)
    291 {
    292     return try_fn([&]() { return reinterpret_cast<var_dft_plan<float>*>(plan)->size(); }, 0);
    293 }
    294 KFR_API_SPEC size_t kfr_dft_get_size_f64(KFR_DFT_PLAN_F64* plan)
    295 {
    296     return try_fn([&]() { return reinterpret_cast<var_dft_plan<double>*>(plan)->size(); }, 0);
    297 }
    298 
    299 KFR_API_SPEC size_t kfr_dft_get_temp_size_f32(KFR_DFT_PLAN_F32* plan)
    300 {
    301     return try_fn([&]() { return reinterpret_cast<var_dft_plan<float>*>(plan)->temp_size(); }, 0);
    302 }
    303 KFR_API_SPEC size_t kfr_dft_get_temp_size_f64(KFR_DFT_PLAN_F64* plan)
    304 {
    305     return try_fn([&]() { return reinterpret_cast<var_dft_plan<double>*>(plan)->temp_size(); }, 0);
    306 }
    307 
    308 KFR_API_SPEC void kfr_dft_execute_f32(KFR_DFT_PLAN_F32* plan, kfr_c32* out, const kfr_c32* in, uint8_t* temp)
    309 {
    310     try_fn(
    311         [&]()
    312         {
    313             reinterpret_cast<var_dft_plan<float>*>(plan)->execute(reinterpret_cast<float*>(out),
    314                                                                   reinterpret_cast<const float*>(in), temp);
    315         });
    316 }
    317 KFR_API_SPEC void kfr_dft_execute_f64(KFR_DFT_PLAN_F64* plan, kfr_c64* out, const kfr_c64* in, uint8_t* temp)
    318 {
    319     try_fn(
    320         [&]()
    321         {
    322             reinterpret_cast<var_dft_plan<double>*>(plan)->execute(reinterpret_cast<double*>(out),
    323                                                                    reinterpret_cast<const double*>(in), temp);
    324         });
    325 }
    326 KFR_API_SPEC void kfr_dft_execute_inverse_f32(KFR_DFT_PLAN_F32* plan, kfr_c32* out, const kfr_c32* in,
    327                                               uint8_t* temp)
    328 {
    329     try_fn(
    330         [&]()
    331         {
    332             reinterpret_cast<var_dft_plan<float>*>(plan)->execute_inverse(
    333                 reinterpret_cast<float*>(out), reinterpret_cast<const float*>(in), temp);
    334         });
    335 }
    336 KFR_API_SPEC void kfr_dft_execute_inverse_f64(KFR_DFT_PLAN_F64* plan, kfr_c64* out, const kfr_c64* in,
    337                                               uint8_t* temp)
    338 {
    339     try_fn(
    340         [&]()
    341         {
    342             reinterpret_cast<var_dft_plan<double>*>(plan)->execute_inverse(
    343                 reinterpret_cast<double*>(out), reinterpret_cast<const double*>(in), temp);
    344         });
    345 }
    346 
    347 KFR_API_SPEC void kfr_dft_delete_plan_f32(KFR_DFT_PLAN_F32* plan)
    348 {
    349     try_fn([&]() { delete reinterpret_cast<var_dft_plan<float>*>(plan); });
    350 }
    351 KFR_API_SPEC void kfr_dft_delete_plan_f64(KFR_DFT_PLAN_F64* plan)
    352 {
    353     try_fn([&]() { delete reinterpret_cast<var_dft_plan<double>*>(plan); });
    354 }
    355 
    356 // Real DFT plans
    357 
    358 KFR_API_SPEC KFR_DFT_REAL_PLAN_F32* kfr_dft_real_create_plan_f32(size_t size, KFR_DFT_PACK_FORMAT pack_format)
    359 {
    360     return try_fn(
    361         [&]()
    362         {
    363             return reinterpret_cast<KFR_DFT_REAL_PLAN_F32*>(
    364                 new var_dft_plan_real_impl<float, 1>(size, static_cast<dft_pack_format>(pack_format)));
    365         },
    366         nullptr);
    367 }
    368 
    369 KFR_API_SPEC KFR_DFT_REAL_PLAN_F32* kfr_dft_real_create_2d_plan_f32(size_t size1, size_t size2,
    370                                                                     bool real_out_is_enough)
    371 {
    372     return try_fn(
    373         [&]()
    374         {
    375             return reinterpret_cast<KFR_DFT_REAL_PLAN_F32*>(
    376                 new var_dft_plan_real_impl<float, 2>(shape{ size1, size2 }, real_out_is_enough));
    377         },
    378         nullptr);
    379 }
    380 KFR_API_SPEC KFR_DFT_REAL_PLAN_F32* kfr_dft_real_create_3d_plan_f32(size_t size1, size_t size2, size_t size3,
    381                                                                     bool real_out_is_enough)
    382 {
    383     return try_fn(
    384         [&]()
    385         {
    386             return reinterpret_cast<KFR_DFT_REAL_PLAN_F32*>(
    387                 new var_dft_plan_real_impl<float, 3>(shape{ size1, size2, size3 }, real_out_is_enough));
    388         },
    389         nullptr);
    390 }
    391 KFR_API_SPEC KFR_DFT_REAL_PLAN_F32* kfr_dft_real_create_md_plan_f32(size_t dims, const unsigned* shape,
    392                                                                     bool real_out_is_enough)
    393 {
    394     return try_fn(
    395         [&]()
    396         {
    397             return reinterpret_cast<KFR_DFT_REAL_PLAN_F32*>(
    398                 new var_dft_plan_real_impl<float, dynamic_shape>(init_shape(dims, shape), real_out_is_enough));
    399         },
    400         nullptr);
    401 }
    402 
    403 KFR_API_SPEC KFR_DFT_REAL_PLAN_F64* kfr_dft_real_create_plan_f64(size_t size, KFR_DFT_PACK_FORMAT pack_format)
    404 {
    405     return try_fn(
    406         [&]()
    407         {
    408             return reinterpret_cast<KFR_DFT_REAL_PLAN_F64*>(
    409                 new var_dft_plan_real_impl<double, 1>(size, static_cast<dft_pack_format>(pack_format)));
    410         },
    411         nullptr);
    412 }
    413 
    414 KFR_API_SPEC void kfr_dft_real_dump_f32(KFR_DFT_REAL_PLAN_F32* plan)
    415 {
    416     try_fn([&]() { reinterpret_cast<var_dft_plan<float>*>(plan)->dump(); });
    417 }
    418 KFR_API_SPEC void kfr_dft_real_dump_f64(KFR_DFT_REAL_PLAN_F64* plan)
    419 {
    420     try_fn([&]() { reinterpret_cast<var_dft_plan<double>*>(plan)->dump(); });
    421 }
    422 
    423 KFR_API_SPEC size_t kfr_dft_real_get_size_f32(KFR_DFT_REAL_PLAN_F32* plan)
    424 {
    425     return try_fn([&]() { return reinterpret_cast<var_dft_plan<float>*>(plan)->size(); }, 0);
    426 }
    427 KFR_API_SPEC size_t kfr_dft_real_get_size_f64(KFR_DFT_REAL_PLAN_F64* plan)
    428 {
    429     return try_fn([&]() { return reinterpret_cast<var_dft_plan<double>*>(plan)->size(); }, 0);
    430 }
    431 
    432 KFR_API_SPEC size_t kfr_dft_real_get_temp_size_f32(KFR_DFT_REAL_PLAN_F32* plan)
    433 {
    434     return try_fn([&]() { return reinterpret_cast<var_dft_plan<float>*>(plan)->temp_size(); }, 0);
    435 }
    436 KFR_API_SPEC size_t kfr_dft_real_get_temp_size_f64(KFR_DFT_REAL_PLAN_F64* plan)
    437 {
    438     return try_fn([&]() { return reinterpret_cast<var_dft_plan<double>*>(plan)->temp_size(); }, 0);
    439 }
    440 
    441 KFR_API_SPEC void kfr_dft_real_execute_f32(KFR_DFT_REAL_PLAN_F32* plan, kfr_c32* out, const float* in,
    442                                            uint8_t* temp)
    443 {
    444     try_fn(
    445         [&]()
    446         { reinterpret_cast<var_dft_plan<float>*>(plan)->execute(reinterpret_cast<float*>(out), in, temp); });
    447 }
    448 KFR_API_SPEC void kfr_dft_real_execute_f64(KFR_DFT_REAL_PLAN_F64* plan, kfr_c64* out, const double* in,
    449                                            uint8_t* temp)
    450 {
    451     try_fn(
    452         [&]() {
    453             reinterpret_cast<var_dft_plan<double>*>(plan)->execute(reinterpret_cast<double*>(out), in, temp);
    454         });
    455 }
    456 KFR_API_SPEC void kfr_dft_real_execute_inverse_f32(KFR_DFT_REAL_PLAN_F32* plan, float* out, const kfr_c32* in,
    457                                                    uint8_t* temp)
    458 {
    459     try_fn(
    460         [&]()
    461         {
    462             reinterpret_cast<var_dft_plan<float>*>(plan)->execute_inverse(
    463                 out, reinterpret_cast<const float*>(in), temp);
    464         });
    465 }
    466 KFR_API_SPEC void kfr_dft_real_execute_inverse_f64(KFR_DFT_REAL_PLAN_F64* plan, double* out,
    467                                                    const kfr_c64* in, uint8_t* temp)
    468 {
    469     try_fn(
    470         [&]()
    471         {
    472             reinterpret_cast<var_dft_plan<double>*>(plan)->execute_inverse(
    473                 out, reinterpret_cast<const double*>(in), temp);
    474         });
    475 }
    476 
    477 KFR_API_SPEC void kfr_dft_real_delete_plan_f32(KFR_DFT_REAL_PLAN_F32* plan)
    478 {
    479     try_fn([&]() { delete reinterpret_cast<var_dft_plan<float>*>(plan); });
    480 }
    481 KFR_API_SPEC void kfr_dft_real_delete_plan_f64(KFR_DFT_REAL_PLAN_F64* plan)
    482 {
    483     try_fn([&]() { delete reinterpret_cast<var_dft_plan<double>*>(plan); });
    484 }
    485 
    486 // Discrete Cosine Transform
    487 
    488 KFR_API_SPEC KFR_DCT_PLAN_F32* kfr_dct_create_plan_f32(size_t size)
    489 {
    490     return try_fn([&]() { return reinterpret_cast<KFR_DCT_PLAN_F32*>(new dct_plan<float>(size)); }, nullptr);
    491 }
    492 KFR_API_SPEC KFR_DCT_PLAN_F64* kfr_dct_create_plan_f64(size_t size)
    493 {
    494     return try_fn([&]() { return reinterpret_cast<KFR_DCT_PLAN_F64*>(new dct_plan<double>(size)); }, nullptr);
    495 }
    496 
    497 KFR_API_SPEC void kfr_dct_dump_f32(KFR_DCT_PLAN_F32* plan)
    498 {
    499     try_fn([&]() { reinterpret_cast<dct_plan<float>*>(plan)->dump(); });
    500 }
    501 KFR_API_SPEC void kfr_dct_dump_f64(KFR_DCT_PLAN_F64* plan)
    502 {
    503     try_fn([&]() { reinterpret_cast<dct_plan<double>*>(plan)->dump(); });
    504 }
    505 
    506 KFR_API_SPEC size_t kfr_dct_get_size_f32(KFR_DCT_PLAN_F32* plan)
    507 {
    508     return try_fn([&]() { return reinterpret_cast<dft_plan<float>*>(plan)->size; }, 0);
    509 }
    510 KFR_API_SPEC size_t kfr_dct_get_size_f64(KFR_DCT_PLAN_F64* plan)
    511 {
    512     return try_fn([&]() { return reinterpret_cast<dft_plan<double>*>(plan)->size; }, 0);
    513 }
    514 
    515 KFR_API_SPEC size_t kfr_dct_get_temp_size_f32(KFR_DCT_PLAN_F32* plan)
    516 {
    517     return try_fn([&]() { return reinterpret_cast<dft_plan<float>*>(plan)->temp_size; }, 0);
    518 }
    519 KFR_API_SPEC size_t kfr_dct_get_temp_size_f64(KFR_DCT_PLAN_F64* plan)
    520 {
    521     return try_fn([&]() { return reinterpret_cast<dft_plan<double>*>(plan)->temp_size; }, 0);
    522 }
    523 
    524 KFR_API_SPEC void kfr_dct_execute_f32(KFR_DCT_PLAN_F32* plan, float* out, const float* in, uint8_t* temp)
    525 {
    526     try_fn([&]() { reinterpret_cast<dct_plan<float>*>(plan)->execute(out, in, temp, cfalse); });
    527 }
    528 KFR_API_SPEC void kfr_dct_execute_f64(KFR_DCT_PLAN_F64* plan, double* out, const double* in, uint8_t* temp)
    529 {
    530     try_fn([&]() { reinterpret_cast<dct_plan<double>*>(plan)->execute(out, in, temp, cfalse); });
    531 }
    532 KFR_API_SPEC void kfr_dct_execute_inverse_f32(KFR_DCT_PLAN_F32* plan, float* out, const float* in,
    533                                               uint8_t* temp)
    534 {
    535     try_fn([&]() { reinterpret_cast<dct_plan<float>*>(plan)->execute(out, in, temp, ctrue); });
    536 }
    537 KFR_API_SPEC void kfr_dct_execute_inverse_f64(KFR_DCT_PLAN_F64* plan, double* out, const double* in,
    538                                               uint8_t* temp)
    539 {
    540     try_fn([&]() { reinterpret_cast<dct_plan<double>*>(plan)->execute(out, in, temp, ctrue); });
    541 }
    542 
    543 KFR_API_SPEC void kfr_dct_delete_plan_f32(KFR_DCT_PLAN_F32* plan)
    544 {
    545     try_fn([&]() { delete reinterpret_cast<dct_plan<float>*>(plan); });
    546 }
    547 KFR_API_SPEC void kfr_dct_delete_plan_f64(KFR_DCT_PLAN_F64* plan)
    548 {
    549     try_fn([&]() { delete reinterpret_cast<dct_plan<double>*>(plan); });
    550 }
    551 
    552 // Filters
    553 
    554 KFR_API_SPEC KFR_FILTER_F32* kfr_filter_create_fir_plan_f32(const kfr_f32* taps, size_t size)
    555 {
    556     return try_fn(
    557         [&]()
    558         { return reinterpret_cast<KFR_FILTER_F32*>(new fir_filter<float>(make_univector(taps, size))); },
    559         nullptr);
    560 }
    561 KFR_API_SPEC KFR_FILTER_F64* kfr_filter_create_fir_plan_f64(const kfr_f64* taps, size_t size)
    562 {
    563     return try_fn(
    564         [&]()
    565         { return reinterpret_cast<KFR_FILTER_F64*>(new fir_filter<double>(make_univector(taps, size))); },
    566         nullptr);
    567 }
    568 
    569 KFR_API_SPEC KFR_FILTER_F32* kfr_filter_create_convolution_plan_f32(const kfr_f32* taps, size_t size,
    570                                                                     size_t block_size)
    571 {
    572     return try_fn(
    573         [&]()
    574         {
    575             return reinterpret_cast<KFR_FILTER_F32*>(
    576                 new convolve_filter<float>(make_univector(taps, size), block_size ? block_size : 1024));
    577         },
    578         nullptr);
    579 }
    580 KFR_API_SPEC KFR_FILTER_F64* kfr_filter_create_convolution_plan_f64(const kfr_f64* taps, size_t size,
    581                                                                     size_t block_size)
    582 {
    583     return try_fn(
    584         [&]()
    585         {
    586             return reinterpret_cast<KFR_FILTER_F64*>(
    587                 new convolve_filter<double>(make_univector(taps, size), block_size ? block_size : 1024));
    588         },
    589         nullptr);
    590 }
    591 
    592 KFR_API_SPEC KFR_FILTER_F32* kfr_filter_create_iir_plan_f32(const kfr_f32* sos, size_t sos_count)
    593 {
    594     return try_fn(
    595         [&]()
    596         {
    597             return reinterpret_cast<KFR_FILTER_F32*>(new iir_filter<float>(
    598                 iir_params{ reinterpret_cast<const biquad_section<float>*>(sos), sos_count }));
    599         },
    600         nullptr);
    601 }
    602 KFR_API_SPEC KFR_FILTER_F64* kfr_filter_create_iir_plan_f64(const kfr_f64* sos, size_t sos_count)
    603 {
    604     return try_fn(
    605         [&]()
    606         {
    607             return reinterpret_cast<KFR_FILTER_F64*>(new iir_filter<double>(
    608                 iir_params{ reinterpret_cast<const biquad_section<double>*>(sos), sos_count }));
    609         },
    610         nullptr);
    611 }
    612 
    613 KFR_API_SPEC void kfr_filter_process_f32(KFR_FILTER_F32* plan, kfr_f32* output, const kfr_f32* input,
    614                                          size_t size)
    615 {
    616     try_fn([&]() { reinterpret_cast<filter<float>*>(plan)->apply(output, input, size); });
    617 }
    618 KFR_API_SPEC void kfr_filter_process_f64(KFR_FILTER_F64* plan, kfr_f64* output, const kfr_f64* input,
    619                                          size_t size)
    620 {
    621     try_fn([&]() { reinterpret_cast<filter<double>*>(plan)->apply(output, input, size); });
    622 }
    623 
    624 KFR_API_SPEC void kfr_filter_reset_f32(KFR_FILTER_F32* plan)
    625 {
    626     try_fn([&]() { reinterpret_cast<filter<float>*>(plan)->reset(); });
    627 }
    628 KFR_API_SPEC void kfr_filter_reset_f64(KFR_FILTER_F64* plan)
    629 {
    630     try_fn([&]() { reinterpret_cast<filter<double>*>(plan)->reset(); });
    631 }
    632 
    633 KFR_API_SPEC void kfr_filter_delete_plan_f32(KFR_FILTER_F32* plan)
    634 {
    635     try_fn([&]() { delete reinterpret_cast<filter<f32>*>(plan); });
    636 }
    637 KFR_API_SPEC void kfr_filter_delete_plan_f64(KFR_FILTER_F64* plan)
    638 {
    639     try_fn([&]() { delete reinterpret_cast<filter<f64>*>(plan); });
    640 }
    641 }
    642 
    643 } // namespace kfr