/*
* 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 {{{
*
* - Version 1.1.1:
*
* - Added debugging check in
*
bw_buf_{neg,add,scale,mix,mul}_multi()
to ensure
* that buffers used for both input and output appear at the same
* channel indices.
*
*
* - Version 1.1.0:
*
* - Now using
BW_NULL
and
* BW_CXX_NO_ARRAY
.
*
*
* - Version 1.0.0:
*
* - Now using
size_t
instead of
* BW_SIZE_T
.
* - C++ API now uses
size_t
to count samples.
* - Changed order of arguments to improve consistency.
* - Added more
const
and BW_RESTRICT
* specifiers to input arguments.
* - Moved C++ code to C header.
* - Added overloaded C++ functions taking C-style arrays as
* arguments.
* - Removed usage of reserved identifiers.
* - Now checking that buffers are never
NULL
and that
* output buffers are different in debugging code.
*
*
* - Version 0.6.0:
*
* - Added debugging code.
* - Removed dependency on bw_config.
*
*
* - Version 0.5.0:
*
* - Added
bw_buf_*_multi()
.
* - Added
bw_buf_neg()
.
* - Added C++ wrapper.
*
*
* - Version 0.4.0:
*
* - Added
bw_buf_fill()
and
* bw_buf_add()
.
*
*
* - Version 0.3.0:
*
*
*
* }}}
*/
#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