/* * Brickworks * * Copyright (C) 2023, 2024 Orastron Srl unipersonale * * Brickworks is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * Brickworks is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Brickworks. If not, see . * * File author: Stefano D'Angelo */ /*! * module_type {{{ utility }}} * version {{{ 1.1.1 }}} * requires {{{ bw_common }}} * description {{{ * Common operations on buffers. * }}} * changelog {{{ * * }}} */ #ifndef BW_BUF_H #define BW_BUF_H #include #ifdef __cplusplus extern "C" { #endif /*** Public API ***/ /*! api {{{ * #### bw_buf_fill() * ```>>> */ static inline void bw_buf_fill( float k, float * BW_RESTRICT dest, size_t n_elems); /*! <<<``` * Sets the first `n_elems` in `dest` to `k`. * * #### bw_buf_neg() * ```>>> */ static inline void bw_buf_neg( const float * src, float * dest, size_t n_elems); /*! <<<``` * Inverts the sign of the first `n_elems` in `src` and stores the results in * the first `n_elems` of `dest`. * * #### bw_buf_add() * ```>>> */ static inline void bw_buf_add( const float * src, float k, float * dest, size_t n_elems); /*! <<<``` * Adds `k` to the first `n_elems` in `src` and stores the results in the * first `n_elems` of `dest`. * * #### bw_buf_scale() * ```>>> */ static inline void bw_buf_scale( const float * src, float k, float * dest, size_t n_elems); /*! <<<``` * Multiplies the first `n_elems` in `src` by `k` and stores the results in * the first `n_elems` of `dest`. * * #### bw_buf_mix() * ```>>> */ static inline void bw_buf_mix( const float * src1, const float * src2, float * dest, size_t n_elems); /*! <<<``` * Adds the first `n_elems` of `src1` and `src2` and stores the results in * the first `n_elems` of `dest`. * * #### bw_buf_mul() * ```>>> */ static inline void bw_buf_mul( const float * src1, const float * src2, float * dest, size_t n_elems); /*! <<<``` * Multiplies the first `n_elems` of `src1` and `src2` and stores the results * in the first `n_elems` of `dest`. * * #### bw_buf_fill_multi() * ```>>> */ static inline void bw_buf_fill_multi( float k, float * BW_RESTRICT const * BW_RESTRICT dest, size_t n_channels, size_t n_elems); /*! <<<``` * Sets the first `n_elems` in each of the `n_channels` buffers `dest` to * `k`. * * #### bw_buf_neg_multi() * ```>>> */ static inline void bw_buf_neg_multi( const float * const * src, float * const * dest, size_t n_channels, size_t n_elems); /*! <<<``` * Inverts the sign of the first `n_elems` in each of the `n_channels` * buffers `src` and stores the results in the first `n_elems` in each of the * `n_channels` buffers `dest`. * * #### bw_buf_add_multi() * ```>>> */ static inline void bw_buf_add_multi( const float * const * src, float k, float * const * dest, size_t n_channels, size_t n_elems); /*! <<<``` * Adds `k` to the first `n_elems` in each of the `n_channels` buffers `src` * and stores the results in the first `n_elems` in each of the `n_channels` * buffers `dest`. * * #### bw_buf_scale_multi() * ```>>> */ static inline void bw_buf_scale_multi( const float * const * src, float k, float * const * dest, size_t n_channels, size_t n_elems); /*! <<<``` * Multiplies the first `n_elems` in each of the `n_channels` buffers `src` * by `k` and stores the results in the first `n_elems` in each of the * `n_channels` buffers `dest`. * * #### bw_buf_mix_multi() * ```>>> */ static inline void bw_buf_mix_multi( const float * const * src1, const float * const * src2, float * const * dest, size_t n_channels, size_t n_elems); /*! <<<``` * Adds the first `n_elems` in each of the `n_channels` buffers `src1` and * `src2` and stores the results in the first `n_elems` in each of the * `n_channels` buffers `dest`. * * #### bw_buf_mul_multi() * ```>>> */ static inline void bw_buf_mul_multi( const float * const * src1, const float * const * src2, float * const * dest, size_t n_channels, size_t n_elems); /*! <<<``` * Multiplies the first `n_elems` in each of the `n_channels` buffers `src1` * and `src2` and stores the results in the first `n_elems` in each of the * `n_channels` buffers `dest`. * }}} */ #ifdef __cplusplus } #endif /*** Implementation ***/ /* WARNING: This part of the file is not part of the public API. Its content may * change at any time in future versions. Please, do not use it directly. */ #ifdef __cplusplus extern "C" { #endif static inline void bw_buf_fill( float k, float * BW_RESTRICT dest, size_t n_elems) { BW_ASSERT(!bw_is_nan(k)); BW_ASSERT(dest != BW_NULL); for (size_t i = 0; i < n_elems; i++) dest[i] = k; BW_ASSERT_DEEP(!bw_has_nan(dest, n_elems)); } static inline void bw_buf_neg( const float * src, float * dest, size_t n_elems) { BW_ASSERT(src != BW_NULL); BW_ASSERT_DEEP(!bw_has_nan(src, n_elems)); BW_ASSERT(dest != BW_NULL); for (size_t i = 0; i < n_elems; i++) dest[i] = -src[i]; BW_ASSERT_DEEP(!bw_has_nan(dest, n_elems)); } static inline void bw_buf_add( const float * src, float k, float * dest, size_t n_elems) { BW_ASSERT(src != BW_NULL); BW_ASSERT_DEEP(!bw_has_nan(src, n_elems)); BW_ASSERT(!bw_is_nan(k)); BW_ASSERT(dest != BW_NULL); for (size_t i = 0; i < n_elems; i++) dest[i] = k + src[i]; BW_ASSERT_DEEP(!bw_has_nan(dest, n_elems)); } static inline void bw_buf_scale( const float * src, float k, float * dest, size_t n_elems) { BW_ASSERT(src != BW_NULL); BW_ASSERT_DEEP(!bw_has_nan(src, n_elems)); BW_ASSERT(!bw_is_nan(k)); BW_ASSERT(dest != BW_NULL); for (size_t i = 0; i < n_elems; i++) dest[i] = k * src[i]; BW_ASSERT_DEEP(!bw_has_nan(dest, n_elems)); } static inline void bw_buf_mix( const float * src1, const float * src2, float * dest, size_t n_elems) { BW_ASSERT(src1 != BW_NULL); BW_ASSERT_DEEP(!bw_has_nan(src1, n_elems)); BW_ASSERT(src2 != BW_NULL); BW_ASSERT_DEEP(!bw_has_nan(src2, n_elems)); BW_ASSERT(dest != BW_NULL); for (size_t i = 0; i < n_elems; i++) dest[i] = src1[i] + src2[i]; BW_ASSERT_DEEP(!bw_has_nan(dest, n_elems)); } static inline void bw_buf_mul( const float * src1, const float * src2, float * dest, size_t n_elems) { BW_ASSERT(src1 != BW_NULL); BW_ASSERT_DEEP(!bw_has_nan(src1, n_elems)); BW_ASSERT(src2 != BW_NULL); BW_ASSERT_DEEP(!bw_has_nan(src2, n_elems)); BW_ASSERT(dest != BW_NULL); for (size_t i = 0; i < n_elems; i++) dest[i] = src1[i] * src2[i]; BW_ASSERT_DEEP(!bw_has_nan(dest, n_elems)); } static inline void bw_buf_fill_multi( float k, float * BW_RESTRICT const * BW_RESTRICT dest, size_t n_channels, size_t n_elems) { BW_ASSERT(!bw_is_nan(k)); BW_ASSERT(dest != BW_NULL); #ifndef BW_NO_DEBUG for (size_t i = 0; i < n_channels; i++) for (size_t j = i + 1; j < n_channels; j++) BW_ASSERT(dest[i] != dest[j]); #endif for (size_t i = 0; i < n_channels; i++) bw_buf_fill(k, dest[i], n_elems); } static inline void bw_buf_neg_multi( const float * const * src, float * const * dest, size_t n_channels, size_t n_elems) { BW_ASSERT(src != BW_NULL); BW_ASSERT(dest != BW_NULL); #ifndef BW_NO_DEBUG for (size_t i = 0; i < n_channels; i++) for (size_t j = i + 1; j < n_channels; j++) BW_ASSERT(dest[i] != dest[j]); for (size_t i = 0; i < n_channels; i++) for (size_t j = 0; j < n_channels; j++) BW_ASSERT(i == j || src[i] != dest[j]); #endif for (size_t i = 0; i < n_channels; i++) bw_buf_neg(src[i], dest[i], n_elems); } static inline void bw_buf_add_multi( const float * const * src, float k, float * const * dest, size_t n_channels, size_t n_elems) { BW_ASSERT(src != BW_NULL); BW_ASSERT(!bw_is_nan(k)); BW_ASSERT(dest != BW_NULL); #ifndef BW_NO_DEBUG for (size_t i = 0; i < n_channels; i++) for (size_t j = i + 1; j < n_channels; j++) BW_ASSERT(dest[i] != dest[j]); for (size_t i = 0; i < n_channels; i++) for (size_t j = 0; j < n_channels; j++) BW_ASSERT(i == j || src[i] != dest[j]); #endif for (size_t i = 0; i < n_channels; i++) bw_buf_add(src[i], k, dest[i], n_elems); } static inline void bw_buf_scale_multi( const float * const * src, float k, float * const * dest, size_t n_channels, size_t n_elems) { BW_ASSERT(src != BW_NULL); BW_ASSERT(!bw_is_nan(k)); BW_ASSERT(dest != BW_NULL); #ifndef BW_NO_DEBUG for (size_t i = 0; i < n_channels; i++) for (size_t j = i + 1; j < n_channels; j++) BW_ASSERT(dest[i] != dest[j]); for (size_t i = 0; i < n_channels; i++) for (size_t j = 0; j < n_channels; j++) BW_ASSERT(i == j || src[i] != dest[j]); #endif for (size_t i = 0; i < n_channels; i++) bw_buf_scale(src[i], k, dest[i], n_elems); } static inline void bw_buf_mix_multi( const float * const * src1, const float * const * src2, float * const * dest, size_t n_channels, size_t n_elems) { BW_ASSERT(src1 != BW_NULL); BW_ASSERT(src2 != BW_NULL); BW_ASSERT(dest != BW_NULL); #ifndef BW_NO_DEBUG for (size_t i = 0; i < n_channels; i++) for (size_t j = i + 1; j < n_channels; j++) BW_ASSERT(dest[i] != dest[j]); for (size_t i = 0; i < n_channels; i++) for (size_t j = 0; j < n_channels; j++) { BW_ASSERT(i == j || src1[i] != dest[j]); BW_ASSERT(i == j || src2[i] != dest[j]); } #endif for (size_t i = 0; i < n_channels; i++) bw_buf_mix(src1[i], src2[i], dest[i], n_elems); } static inline void bw_buf_mul_multi( const float * const * src1, const float * const * src2, float * const * dest, size_t n_channels, size_t n_elems) { BW_ASSERT(src1 != BW_NULL); BW_ASSERT(src2 != BW_NULL); BW_ASSERT(dest != BW_NULL); #ifndef BW_NO_DEBUG for (size_t i = 0; i < n_channels; i++) for (size_t j = i + 1; j < n_channels; j++) BW_ASSERT(dest[i] != dest[j]); for (size_t i = 0; i < n_channels; i++) for (size_t j = 0; j < n_channels; j++) { BW_ASSERT(i == j || src1[i] != dest[j]); BW_ASSERT(i == j || src2[i] != dest[j]); } #endif for (size_t i = 0; i < n_channels; i++) bw_buf_mul(src1[i], src2[i], dest[i], n_elems); } #ifdef __cplusplus } #ifndef BW_CXX_NO_ARRAY # include #endif namespace Brickworks { /*** Public C++ API ***/ /*! api_cpp {{{ * ##### Brickworks::bufFill * ```>>> */ template inline void bufFill( float k, float * BW_RESTRICT const * BW_RESTRICT dest, size_t nSamples); #ifndef BW_CXX_NO_ARRAY template inline void bufFill( float k, std::array dest, size_t nSamples); #endif /*! <<<``` * * ##### Brickworks::bufNeg * ```>>> */ template inline void bufNeg( const float * const * src, float * const * dest, size_t nSamples); #ifndef BW_CXX_NO_ARRAY template inline void bufNeg( const std::array src, const std::array dest, size_t nSamples); #endif /*! <<<``` * * ##### Brickworks::bufAdd * ```>>> */ template inline void bufAdd( const float * const * src, float k, float * const * dest, size_t nSamples); #ifndef BW_CXX_NO_ARRAY template inline void bufAdd( const std::array src, float k, const std::array dest, size_t nSamples); #endif /*! <<<``` * * ##### Brickworks::bufScale * ```>>> */ template inline void bufScale( const float * const * src, float k, float * const * dest, size_t nSamples); #ifndef BW_CXX_NO_ARRAY template inline void bufScale( const std::array src, float k, const std::array dest, size_t nSamples); #endif /*! <<<``` * * ##### Brickworks::bufMix * ```>>> */ template inline void bufMix( const float * const * src1, const float * const * src2, float * const * dest, size_t nSamples); #ifndef BW_CXX_NO_ARRAY template inline void bufMix( const std::array src1, const std::array src2, const std::array dest, size_t nSamples); #endif /*! <<<``` * * ##### Brickworks::bufMul * ```>>> */ template inline void bufMul( const float * const * src1, const float * const * src2, float * const * dest, size_t nSamples); #ifndef BW_CXX_NO_ARRAY template inline void bufMul( const std::array src1, const std::array src2, const std::array dest, size_t nSamples); #endif /*! <<<``` * }}} */ /*** Implementation ***/ /* WARNING: This part of the file is not part of the public API. Its content may * change at any time in future versions. Please, do not use it directly. */ template inline void bufFill( float k, float * BW_RESTRICT const * BW_RESTRICT dest, size_t nSamples) { bw_buf_fill_multi(k, dest, N_CHANNELS, nSamples); } #ifndef BW_CXX_NO_ARRAY template inline void bufFill( float k, const std::array dest, size_t nSamples) { bufFill(k, dest.data(), nSamples); } #endif template inline void bufNeg( const float * const * src, float * const * dest, size_t nSamples) { bw_buf_neg_multi(src, dest, N_CHANNELS, nSamples); } #ifndef BW_CXX_NO_ARRAY template inline void bufNeg( const std::array src, const std::array dest, size_t nSamples) { bufNeg(src.data(), dest.data(), nSamples); } #endif template inline void bufAdd( const float * const * src, float k, float * const * dest, size_t nSamples) { bw_buf_add_multi(src, k, dest, N_CHANNELS, nSamples); } #ifndef BW_CXX_NO_ARRAY template inline void bufAdd( const std::array src, float k, const std::array dest, size_t nSamples) { bufAdd(src.data(), k, dest.data(), nSamples); } #endif template inline void bufScale( const float * const * src, float k, float * const * dest, size_t nSamples) { bw_buf_scale_multi(src, k, dest, N_CHANNELS, nSamples); } #ifndef BW_CXX_NO_ARRAY template inline void bufScale( const std::array src, float k, const std::array dest, size_t nSamples) { bufScale(src.data(), k, dest.data(), nSamples); } #endif template inline void bufMix( const float * const * src1, const float * const * src2, float * const * dest, size_t nSamples) { bw_buf_mix_multi(src1, src2, dest, N_CHANNELS, nSamples); } #ifndef BW_CXX_NO_ARRAY template inline void bufMix( const std::array src1, const std::array src2, const std::array dest, size_t nSamples) { bufMix(src1.data(), src2.data(), dest.data(), nSamples); } #endif template inline void bufMul( const float * const * src1, const float * const * src2, float * const * dest, size_t nSamples) { bw_buf_mul_multi(src1, src2, dest, N_CHANNELS, nSamples); } #ifndef BW_CXX_NO_ARRAY template inline void bufMul( const std::array src1, const std::array src2, const std::array dest, size_t nSamples) { bufMul(src1.data(), src2.data(), dest.data(), nSamples); } #endif } #endif #endif