commit 4b9a56369a644cf1465d095d9ee323daccadbbbe parent ba2d0fd68f433b6029994eda7426a7fd27263c7e Author: d.levin256@gmail.com <d.levin256@gmail.com> Date: Wed, 12 Dec 2018 12:56:45 +0000 Documentation Diffstat:
26 files changed, 295 insertions(+), 114 deletions(-)
diff --git a/include/kfr/base/basic_expressions.hpp b/include/kfr/base/basic_expressions.hpp @@ -25,9 +25,9 @@ */ #pragma once +#include "operators.hpp" #include "univector.hpp" #include "vec.hpp" -#include "operators.hpp" #include <algorithm> namespace kfr @@ -367,18 +367,24 @@ struct expression_adjacent : expression_base<E> }; } // namespace internal +/** @brief Returns the subrange of the given expression + */ template <typename E1> CMT_INLINE internal::expression_slice<E1> slice(E1&& e1, size_t start, size_t size = infinite_size) { return internal::expression_slice<E1>(std::forward<E1>(e1), start, size); } +/** @brief Returns the expression truncated to the given size + */ template <typename E1> CMT_INLINE internal::expression_slice<E1> truncate(E1&& e1, size_t size) { return internal::expression_slice<E1>(std::forward<E1>(e1), 0, size); } +/** @brief Returns reversed expression + */ template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> CMT_INLINE internal::expression_reverse<E1> reverse(E1&& e1) { @@ -386,6 +392,14 @@ CMT_INLINE internal::expression_reverse<E1> reverse(E1&& e1) return internal::expression_reverse<E1>(std::forward<E1>(e1)); } +/** @brief Returns evenly spaced numbers over a specified interval. + * + * @param start The starting value of the sequence + * @param stop The end value of the sequence. if ``endpoint`` is ``false``, the last value is excluded + * @param size Number of samples to generate + * @param endpoint If ``true``, ``stop`` is the last sample. Otherwise, it is not included + * @param truncate If ``true``, linspace returns exactly size elements, otherwise, returns infinite sequence + */ template <typename T1, typename T2, bool precise = false, typename TF = ftype<common_type<T1, T2>>> CMT_INLINE internal::expression_linspace<TF, precise> linspace(T1 start, T2 stop, size_t size, bool endpoint = false, bool truncate = false) diff --git a/include/kfr/base/complex.hpp b/include/kfr/base/complex.hpp @@ -178,8 +178,13 @@ struct compound_type_traits<kfr::complex<T>> namespace kfr { -using c32 = complex<f32>; -using c64 = complex<f64>; +/// @brief Alias for complex<f32> +using c32 = complex<f32>; + +/// @brief Alias for complex<f64> +using c64 = complex<f64>; + +/// @brief Alias for complex<fbase> using cbase = complex<fbase>; namespace internal @@ -191,6 +196,7 @@ constexpr inline vec<T, 2> vcomplex(const complex<T>& v) } } // namespace internal +/// @brief vec<> specialization for complex numbers. Implements all operators template <typename T, size_t N> struct vec<complex<T>, N> : private vec<T, 2 * N> { @@ -379,6 +385,7 @@ struct vec<complex<T>, N> : private vec<T, 2 * N> simd_type& operator*() noexcept { return base::operator*(); } }; +/// @brief Returns vector of complex values with real part duplicated template <typename T, size_t N> CMT_INLINE vec<complex<T>, N> cdupreal(const vec<complex<T>, N>& x) { @@ -386,6 +393,7 @@ CMT_INLINE vec<complex<T>, N> cdupreal(const vec<complex<T>, N>& x) } KFR_FN(cdupreal) +/// @brief Returns vector of complex values with imaginary part duplicated template <typename T, size_t N> CMT_INLINE vec<complex<T>, N> cdupimag(const vec<complex<T>, N>& x) { @@ -393,6 +401,7 @@ CMT_INLINE vec<complex<T>, N> cdupimag(const vec<complex<T>, N>& x) } KFR_FN(cdupimag) +/// @brief Returns vector of complex values with real and imaginary parts swapped template <typename T, size_t N> CMT_INLINE vec<complex<T>, N> cswapreim(const vec<complex<T>, N>& x) { @@ -400,12 +409,15 @@ CMT_INLINE vec<complex<T>, N> cswapreim(const vec<complex<T>, N>& x) } KFR_FN(cswapreim) +/// @brief Returns vector of complex values with real part negated template <typename T, size_t N> CMT_INLINE vec<complex<T>, N> cnegreal(const vec<complex<T>, N>& x) { return x ^ complex<T>(-T(), T()); } KFR_FN(cnegreal) + +/// @brief Returns vector of complex values with imaginary part negated template <typename T, size_t N> CMT_INLINE vec<complex<T>, N> cnegimag(const vec<complex<T>, N>& x) { @@ -413,7 +425,6 @@ CMT_INLINE vec<complex<T>, N> cnegimag(const vec<complex<T>, N>& x) } KFR_FN(cnegimag) - namespace internal { template <typename T> @@ -464,16 +475,21 @@ constexpr CMT_INLINE vec<T, N * 2> cdecom(const vec<complex<T>, N>& x) return compcast<T>(x); } +/// @brief Returns the real part of the complex value template <typename T, KFR_ENABLE_IF(is_numeric<T>::value)> constexpr CMT_INLINE T real(const T& value) { return value; } + +/// @brief Returns the real part of the complex value template <typename T> constexpr CMT_INLINE T real(const complex<T>& value) { return value.real(); } + +/// @brief Returns the real part of the complex value template <typename T, size_t N> constexpr CMT_INLINE vec<T, N> real(const vec<complex<T>, N>& value) { @@ -486,35 +502,44 @@ template <typename T> using realftype = ftype<decltype(kfr::real(std::declval<T>()))>; KFR_FN(real) + +/// @brief Returns the real part of the complex value template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> CMT_INLINE internal::expression_function<fn::real, E1> real(E1&& x) { return { {}, std::forward<E1>(x) }; } +/// @brief Returns the imaginary part of the complex value template <typename T> constexpr CMT_INLINE T imag(const complex<T>& value) { return value.imag(); } + +/// @brief Returns the imaginary part of the complex value template <typename T, size_t N> constexpr CMT_INLINE vec<T, N> imag(const vec<complex<T>, N>& value) { return odd(compcast<T>(value)); } KFR_FN(imag) + +/// @brief Returns the imaginary part of the complex value template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> CMT_INLINE internal::expression_function<fn::imag, E1> imag(E1&& x) { return { {}, std::forward<E1>(x) }; } +/// @brief Constructs complex value from real and imaginary parts template <typename T1, typename T2 = T1, size_t N, typename T = common_type<T1, T2>> constexpr CMT_INLINE vec<complex<T>, N> make_complex(const vec<T1, N>& real, const vec<T2, N>& imag = T2(0)) { return compcast<complex<T>>(interleave(cast<T>(real), cast<T>(imag))); } +/// @brief Constructs complex value from real and imaginary parts template <typename T1, typename T2 = T1, typename T = common_type<T1, T2>> constexpr CMT_INLINE complex<T> make_complex(T1 real, T2 imag = T2(0)) { @@ -675,161 +700,224 @@ KFR_I_FN(polar) KFR_I_FN(cartesian) KFR_I_FN(csqrt) +/// @brief Returns the sine of the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 csin(const T1& x) { return intrinsics::csin(x); } + +/// @brief Returns template expression that returns the sine of the the complex value x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::csin, E1> csin(E1&& x) { return { fn::csin(), std::forward<E1>(x) }; } + +/// @brief Returns the hyperbolic sine of the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 csinh(const T1& x) { return intrinsics::csinh(x); } + +/// @brief Returns template expression that returns the hyperbolic sine of the complex number x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::csinh, E1> csinh(E1&& x) { return { fn::csinh(), std::forward<E1>(x) }; } + +/// @brief Returns the cosine of the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 ccos(const T1& x) { return intrinsics::ccos(x); } + +/// @brief Returns template expression that returns the cosine of the the complex value x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::ccos, E1> ccos(E1&& x) { return { fn::ccos(), std::forward<E1>(x) }; } + +/// @brief Returns the hyperbolic cosine of the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 ccosh(const T1& x) { return intrinsics::ccosh(x); } + +/// @brief Returns template expression that returns the hyperbolic cosine of the the complex value x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::ccosh, E1> ccosh(E1&& x) { return { fn::ccosh(), std::forward<E1>(x) }; } + +/// @brief Returns the absolute value (magnitude) of the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC realtype<T1> cabs(const T1& x) { return intrinsics::cabs(x); } + +/// @brief Returns template expression that returns the absolute value (magnitude) of the complex number x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::cabs, E1> cabs(E1&& x) { return { fn::cabs(), std::forward<E1>(x) }; } + +/// @brief Returns the phase angle (argument) of the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC realtype<T1> carg(const T1& x) { return intrinsics::carg(x); } + +/// @brief Returns template expression that returns the phase angle (argument) of the complex number x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::carg, E1> carg(E1&& x) { return { fn::carg(), std::forward<E1>(x) }; } + +/// @brief Returns the complex conjugate of the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 cconj(const T1& x) { return intrinsics::cconj(x); } + +/// @brief Returns template expression that returns the complex conjugate of the complex number x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::cconj, E1> cconj(E1&& x) { return { fn::cconj(), std::forward<E1>(x) }; } + +/// @brief Returns the natural logarithm of the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 clog(const T1& x) { return intrinsics::clog(x); } + +/// @brief Returns template expression that returns the natural logarithm of the complex number x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::clog, E1> clog(E1&& x) { return { fn::clog(), std::forward<E1>(x) }; } + +/// @brief Returns the binary (base-2) logarithm of the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 clog2(const T1& x) { return intrinsics::clog2(x); } + +/// @brief Returns template expression that returns the binary (base-2) logarithm of the complex number x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::clog2, E1> clog2(E1&& x) { return { fn::clog2(), std::forward<E1>(x) }; } + +/// @brief Returns the common (base-10) logarithm of the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 clog10(const T1& x) { return intrinsics::clog10(x); } + +/// @brief Returns template expression that returns the common (base-10) logarithm of the complex number x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::clog10, E1> clog10(E1&& x) { return { fn::clog10(), std::forward<E1>(x) }; } + +/// @brief Returns \f$e\f$ raised to the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 cexp(const T1& x) { return intrinsics::cexp(x); } + +/// @brief Returns template expression that returns \f$e\f$ raised to the complex number x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::cexp, E1> cexp(E1&& x) { return { fn::cexp(), std::forward<E1>(x) }; } + +/// @brief Returns 2 raised to the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 cexp2(const T1& x) { return intrinsics::cexp2(x); } + +/// @brief Returns template expression that returns 2 raised to the complex number x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::cexp2, E1> cexp2(E1&& x) { return { fn::cexp2(), std::forward<E1>(x) }; } + +/// @brief Returns 10 raised to the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 cexp10(const T1& x) { return intrinsics::cexp10(x); } + +/// @brief Returns template expression that returns 10 raised to the complex number x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::cexp10, E1> cexp10(E1&& x) { return { fn::cexp10(), std::forward<E1>(x) }; } + +/// @brief Converts complex number to polar template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 polar(const T1& x) { return intrinsics::polar(x); } + +/// @brief Returns template expression that converts complex number to polar template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::polar, E1> polar(E1&& x) { return { fn::polar(), std::forward<E1>(x) }; } + +/// @brief Converts complex number to cartesian template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 cartesian(const T1& x) { return intrinsics::cartesian(x); } + +/// @brief Returns template expression that converts complex number to cartesian template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::cartesian, E1> cartesian(E1&& x) { return { fn::cartesian(), std::forward<E1>(x) }; } + +/// @brief Returns square root of the complex number x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC T1 csqrt(const T1& x) { return intrinsics::csqrt(x); } + +/// @brief Returns template expression that returns square root of the complex number x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::csqrt, E1> csqrt(E1&& x) { diff --git a/include/kfr/base/constants.hpp b/include/kfr/base/constants.hpp @@ -229,33 +229,33 @@ constexpr subtype<T> constants<T>::neginfinity; template <typename T> constexpr subtype<T> constants<T>::qnan; -// π (pi) -// c_pi<f64, 4> = 4pi -// c_pi<f64, 3, 4> = 3/4pi +/// π (pi) +/// c_pi<f64, 4> = 4pi +/// c_pi<f64, 3, 4> = 3/4pi template <typename T, int m = 1, int d = 1> constexpr subtype<T> c_pi = subtype<T>(3.1415926535897932384626433832795 * m / d); -// π² (pi²) -// c_sqr_pi<f64, 4> = 4pi² -// c_sqr_pi<f64, 3, 4> = 3/4pi² +/// π² (pi²) +/// c_sqr_pi<f64, 4> = 4pi² +/// c_sqr_pi<f64, 3, 4> = 3/4pi² template <typename T, int m = 1, int d = 1> constexpr subtype<T> c_sqr_pi = subtype<T>(9.8696044010893586188344909998762 * m / d); -// 1/π (1/pi) -// c_recip_pi<f64> 1/pi -// c_recip_pi<f64, 4> 4/pi +/// 1/π (1/pi) +/// c_recip_pi<f64> 1/pi +/// c_recip_pi<f64, 4> 4/pi template <typename T, int m = 1, int d = 1> constexpr subtype<T> c_recip_pi = subtype<T>(0.31830988618379067153776752674503 * m / d); -// degree to radian conversion factor +/// degree to radian conversion factor template <typename T> constexpr subtype<T> c_degtorad = c_pi<T, 1, 180>; -// radian to degree conversion factor +/// radian to degree conversion factor template <typename T> constexpr subtype<T> c_radtodeg = c_recip_pi<T, 180>; -// e, Euler's number +/// e, Euler's number template <typename T, int m = 1, int d = 1> constexpr subtype<T> c_e = subtype<T>(2.718281828459045235360287471352662 * m / d); @@ -268,12 +268,15 @@ constexpr subtype<T> c_mantissa_mask = (subtype<T>(1) << c_mantissa_bits<T>)-1; template <typename T> constexpr subtype<T> c_epsilon = (std::numeric_limits<subtype<T>>::epsilon()); +/// infinity template <typename T> constexpr subtype<T> c_infinity = std::numeric_limits<subtype<T>>::infinity(); +/// -infinity template <typename T> constexpr subtype<T> c_neginfinity = -std::numeric_limits<subtype<T>>::infinity(); +/// Quiet NaN template <typename T> constexpr subtype<T> c_qnan = std::numeric_limits<subtype<T>>::quiet_NaN(); diff --git a/include/kfr/base/conversion.hpp b/include/kfr/base/conversion.hpp @@ -179,6 +179,7 @@ inline Tout convert_sample(const Tin& in) return cast<Tout>(in * scale); } +/// @brief Deinterleaves and converts audio samples template <typename Tout, typename Tin, typename Tout_traits = audio_sample_traits<Tout>, typename Tin_traits = audio_sample_traits<Tin>> void deinterleave(Tout* out[], const Tin* in, size_t channels, size_t size) @@ -190,6 +191,7 @@ void deinterleave(Tout* out[], const Tin* in, size_t channels, size_t size) } } +/// @brief Deinterleaves and converts audio samples template <typename Tout, size_t Tag1, size_t Tag2, typename Tin, size_t Tag3> void deinterleave(univector2d<Tout, Tag1, Tag2>& out, const univector<Tin, Tag3>& in) { @@ -203,6 +205,7 @@ void deinterleave(univector2d<Tout, Tag1, Tag2>& out, const univector<Tin, Tag3> return deinterleave(ptrs.data(), in.data(), out.size(), in.size() / out.size()); } +/// @brief Interleaves and converts audio samples template <typename Tout, typename Tin, typename Tout_traits = audio_sample_traits<Tout>, typename Tin_traits = audio_sample_traits<Tin>> void interleave(Tout* out, const Tin* in[], size_t channels, size_t size) @@ -214,6 +217,7 @@ void interleave(Tout* out, const Tin* in[], size_t channels, size_t size) } } +/// @brief Interleaves and converts audio samples template <typename Tout, size_t Tag1, typename Tin, size_t Tag2, size_t Tag3> void interleave(univector<Tout, Tag1>& out, const univector2d<Tin, Tag2, Tag3>& in) { @@ -227,6 +231,7 @@ void interleave(univector<Tout, Tag1>& out, const univector2d<Tin, Tag2, Tag3>& return interleave(out.data(), ptrs.data(), in.size(), out.size() / in.size()); } +/// @brief Interleaves and converts audio samples template <typename Tin, size_t Tag1, size_t Tag2> univector<Tin> interleave(const univector2d<Tin, Tag1, Tag2>& in) { @@ -237,6 +242,7 @@ univector<Tin> interleave(const univector2d<Tin, Tag1, Tag2>& in) return result; } +/// @brief Converts audio samples (both formats are known at compile time) template <typename Tout, typename Tin, typename Tout_traits = audio_sample_traits<Tout>, typename Tin_traits = audio_sample_traits<Tin>> void convert(Tout* out, const Tin* in, size_t size) @@ -247,6 +253,7 @@ void convert(Tout* out, const Tin* in, size_t size) } } +/// @brief Converts audio samples (input format is known at runtime) template <typename Tout, typename Tout_traits = audio_sample_traits<Tout>> void convert(Tout* out, const void* in, audio_sample_type in_type, size_t size) { @@ -256,6 +263,7 @@ void convert(Tout* out, const void* in, audio_sample_type in_type, size_t size) }); } +/// @brief Converts audio samples (output format is known at runtime) template <typename Tin, typename Tin_traits = audio_sample_traits<Tin>> void convert(void* out, audio_sample_type out_type, const Tin* in, size_t size) { diff --git a/include/kfr/base/hyperbolic.hpp b/include/kfr/base/hyperbolic.hpp @@ -30,75 +30,91 @@ namespace kfr { +/// @brief Returns the hyperbolic sine of the x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> sinh(const T1& x) { return intrinsics::sinh(x); } +/// @brief Returns template expression that returns the hyperbolic sine of the x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::sinh, E1> sinh(E1&& x) { return { fn::sinh(), std::forward<E1>(x) }; } +/// @brief Returns the hyperbolic cosine of the x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> cosh(const T1& x) { return intrinsics::cosh(x); } +/// @brief Returns template expression that returns the hyperbolic cosine of the x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::cosh, E1> cosh(E1&& x) { return { fn::cosh(), std::forward<E1>(x) }; } +/// @brief Returns the hyperbolic tangent of the x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> tanh(const T1& x) { return intrinsics::tanh(x); } +/// @brief Returns template expression that returns the hyperbolic tangent of the x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::tanh, E1> tanh(E1&& x) { return { fn::tanh(), std::forward<E1>(x) }; } +/// @brief Returns the hyperbolic cotangent of the x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> coth(const T1& x) { return intrinsics::coth(x); } +/// @brief Returns template expression that returns the hyperbolic cotangent of the x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::coth, E1> coth(E1&& x) { return { fn::coth(), std::forward<E1>(x) }; } +/// @brief Returns the hyperbolic sine of the even elements of the x and the hyperbolic cosine of the odd +/// elements of the x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> sinhcosh(const T1& x) { return intrinsics::sinhcosh(x); } +/// @brief Returns template expression that returns the hyperbolic sine of the even elements of the x and the +/// hyperbolic cosine of the odd elements of the x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::sinhcosh, E1> sinhcosh(E1&& x) { return { fn::sinhcosh(), std::forward<E1>(x) }; } +/// @brief Returns the hyperbolic cosine of the even elements of the x and the hyperbolic sine of the odd +/// elements of the x template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> coshsinh(const T1& x) { return intrinsics::coshsinh(x); } +/// @brief Returns template expression that returns the hyperbolic cosine of the even elements of the x and +/// the hyperbolic sine of the odd elements of the x template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::coshsinh, E1> coshsinh(E1&& x) { return { fn::coshsinh(), std::forward<E1>(x) }; } -} +} // namespace kfr diff --git a/include/kfr/base/kfr.h b/include/kfr/base/kfr.h @@ -27,11 +27,15 @@ #ifdef __cplusplus namespace kfr { +/// @brief KFR version string constexpr const char version_string[] = KFR_VERSION_STRING; + constexpr int version_major = KFR_VERSION_MAJOR; constexpr int version_minor = KFR_VERSION_MINOR; constexpr int version_build = KFR_VERSION_BUILD; constexpr int version = KFR_VERSION; + +/// @brief KFR version string including architecture and compiler name constexpr const char version_full[] = KFR_VERSION_FULL; } #endif diff --git a/include/kfr/base/log_exp.hpp b/include/kfr/base/log_exp.hpp @@ -30,168 +30,196 @@ namespace kfr { +/// @brief Returns e raised to the given power x. template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> exp(const T1& x) { return intrinsics::exp(x); } +/// @brief Returns e raised to the given power x. Version that accepts and returns expressions. template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::exp, E1> exp(E1&& x) { return { fn::exp(), std::forward<E1>(x) }; } +/// @brief Returns 2 raised to the given power x. template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> exp2(const T1& x) { return intrinsics::exp2(x); } +/// @brief Returns 2 raised to the given power x. Version that accepts and returns expressions. template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::exp2, E1> exp2(E1&& x) { return { fn::exp2(), std::forward<E1>(x) }; } +/// @brief Returns 10 raised to the given power x. template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> exp10(const T1& x) { return intrinsics::exp10(x); } +/// @brief Returns 10 raised to the given power x. Version that accepts and returns expressions. template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::exp10, E1> exp10(E1&& x) { return { fn::exp10(), std::forward<E1>(x) }; } +/// @brief Returns the natural logarithm of the x. template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> log(const T1& x) { return intrinsics::log(x); } +/// @brief Returns the natural logarithm of the x. Version that accepts and returns expressions. template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::log, E1> log(E1&& x) { return { fn::log(), std::forward<E1>(x) }; } +/// @brief Returns the binary (base-2) logarithm of the x. template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> log2(const T1& x) { return intrinsics::log2(x); } +/// @brief Returns the binary (base-2) logarithm of the x. Version that accepts and returns expressions. template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::log2, E1> log2(E1&& x) { return { fn::log2(), std::forward<E1>(x) }; } +/// @brief Returns the common (base-10) logarithm of the x. template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> log10(const T1& x) { return intrinsics::log10(x); } +/// @brief Returns the common (base-10) logarithm of the x. Version that accepts and returns expressions. template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::log10, E1> log10(E1&& x) { return { fn::log10(), std::forward<E1>(x) }; } +/// @brief Returns the rounded binary (base-2) logarithm of the x. template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> logb(const T1& x) { return intrinsics::logb(x); } +/// @brief Returns the rounded binary (base-2) logarithm of the x. Version that accepts and returns expressions. template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::logb, E1> logb(E1&& x) { return { fn::logb(), std::forward<E1>(x) }; } +/// @brief Returns the logarithm of the x with base y. template <typename T1, typename T2, KFR_ENABLE_IF(is_numeric_args<T1, T2>::value)> KFR_FUNC flt_type<common_type<T1, T2>> logn(const T1& x, const T2& y) { return intrinsics::logn(x, y); } +/// @brief Returns the logarithm of the x with base y. Version that accepts and returns expressions. template <typename E1, typename E2, KFR_ENABLE_IF(is_input_expressions<E1, E2>::value)> KFR_FUNC internal::expression_function<fn::logn, E1, E2> logn(E1&& x, E2&& y) { return { fn::logn(), std::forward<E1>(x), std::forward<E2>(y) }; } +/// @brief Returns log(x) * y. template <typename T1, typename T2, KFR_ENABLE_IF(is_numeric_args<T1, T2>::value)> KFR_FUNC flt_type<common_type<T1, T2>> logm(const T1& x, const T2& y) { return intrinsics::logm(x, y); } +/// @brief Returns log(x) * y. Version that accepts and returns expressions. template <typename E1, typename E2, KFR_ENABLE_IF(is_input_expressions<E1, E2>::value)> KFR_FUNC internal::expression_function<fn::logm, E1, E2> logm(E1&& x, E2&& y) { return { fn::logm(), std::forward<E1>(x), std::forward<E2>(y) }; } +/// @brief Returns exp(x * m + a). template <typename T1, typename T2, typename T3, KFR_ENABLE_IF(is_numeric_args<T1, T2, T3>::value)> KFR_FUNC flt_type<common_type<T1, T2, T3>> exp_fmadd(const T1& x, const T2& y, const T3& z) { return intrinsics::exp_fmadd(x, y, z); } +/// @brief Returns exp(x * m + a). Version that accepts and returns expressions. template <typename E1, typename E2, typename E3, KFR_ENABLE_IF(is_input_expressions<E1, E2, E3>::value)> KFR_FUNC internal::expression_function<fn::exp_fmadd, E1, E2, E3> exp_fmadd(E1&& x, E2&& y, E3&& z) { return { fn::exp_fmadd(), std::forward<E1>(x), std::forward<E2>(y), std::forward<E3>(z) }; } +/// @brief Returns log(x) * m + a. template <typename T1, typename T2, typename T3, KFR_ENABLE_IF(is_numeric_args<T1, T2, T3>::value)> KFR_FUNC flt_type<common_type<T1, T2, T3>> log_fmadd(const T1& x, const T2& y, const T3& z) { return intrinsics::log_fmadd(x, y, z); } +/// @brief Returns log(x) * m + a. Version that accepts and returns expressions. template <typename E1, typename E2, typename E3, KFR_ENABLE_IF(is_input_expressions<E1, E2, E3>::value)> KFR_FUNC internal::expression_function<fn::log_fmadd, E1, E2, E3> log_fmadd(E1&& x, E2&& y, E3&& z) { return { fn::log_fmadd(), std::forward<E1>(x), std::forward<E2>(y), std::forward<E3>(z) }; } +/// @brief Returns the x raised to the given power y. template <typename T1, typename T2, KFR_ENABLE_IF(is_numeric_args<T1, T2>::value)> KFR_FUNC flt_type<common_type<T1, T2>> pow(const T1& x, const T2& y) { return intrinsics::pow(x, y); } +/// @brief Returns the x raised to the given power y. Version that accepts and returns expressions. template <typename E1, typename E2, KFR_ENABLE_IF(is_input_expressions<E1, E2>::value)> KFR_FUNC internal::expression_function<fn::pow, E1, E2> pow(E1&& x, E2&& y) { return { fn::pow(), std::forward<E1>(x), std::forward<E2>(y) }; } +/// @brief Returns the real nth root of the x. template <typename T1, typename T2, KFR_ENABLE_IF(is_numeric_args<T1, T2>::value)> KFR_FUNC flt_type<common_type<T1, T2>> root(const T1& x, const T2& y) { return intrinsics::root(x, y); } +/// @brief Returns the real nth root of the x. Version that accepts and returns expressions. template <typename E1, typename E2, KFR_ENABLE_IF(is_input_expressions<E1, E2>::value)> KFR_FUNC internal::expression_function<fn::root, E1, E2> root(E1&& x, E2&& y) { return { fn::root(), std::forward<E1>(x), std::forward<E2>(y) }; } +/// @brief Returns the cube root of the x. template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> KFR_FUNC flt_type<T1> cbrt(const T1& x) { return intrinsics::cbrt(x); } +/// @brief Returns the cube root of the x. Version that accepts and returns expressions. template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> KFR_FUNC internal::expression_function<fn::cbrt, E1> cbrt(E1&& x) { diff --git a/include/kfr/base/memory.hpp b/include/kfr/base/memory.hpp @@ -104,6 +104,7 @@ inline void aligned_free(void* ptr) inline void aligned_release(void* ptr) { aligned_free(ptr); } } +/// @brief Allocates aligned memory template <typename T = void, size_t alignment = platform<>::native_cache_alignment> CMT_INLINE T* aligned_allocate(size_t size = 1) { @@ -113,6 +114,7 @@ CMT_INLINE T* aligned_allocate(size_t size = 1) return ptr; } +/// @brief Deallocates aligned memory template <typename T = void> CMT_INLINE void aligned_deallocate(T* ptr) { @@ -154,6 +156,7 @@ struct autofree std::unique_ptr<T[], internal::aligned_deleter<T>> ptr; }; +/// @brief Aligned allocator template <typename T> struct allocator { diff --git a/include/kfr/base/operators.hpp b/include/kfr/base/operators.hpp @@ -227,9 +227,9 @@ CMT_INLINE internal::expression_function<fn::ipow, E1, E2> ipow(E1&& x, E2&& b) } /// Return square of the sum of all arguments -/// *Example*:: -/// +/// @code /// CHECK(sqrsum(1,2,3) == 36); +/// @endcode template <typename T1, typename... Ts> constexpr inline common_type<T1, Ts...> sqrsum(const T1& x, const Ts&... rest) { diff --git a/include/kfr/base/random.hpp b/include/kfr/base/random.hpp @@ -167,24 +167,28 @@ struct expression_random_range : input_expression }; } // namespace internal +/// @brief Returns expression that returns pseudo random values template <typename T> inline internal::expression_random_uniform<T> gen_random_uniform(const random_bit_generator& gen) { return internal::expression_random_uniform<T>(gen); } +/// @brief Returns expression that returns pseudo random values template <typename T> -inline internal::expression_random_range<T> gen_random_range(const random_bit_generator& gen, T min, T max) +inline internal::expression_random_uniform<T> gen_random_uniform() { - return internal::expression_random_range<T>(gen, min, max); + return internal::expression_random_uniform<T>(random_bit_generator(seed_from_rdtsc)); } +/// @brief Returns expression that returns pseudo random values of the given range template <typename T> -inline internal::expression_random_uniform<T> gen_random_uniform() +inline internal::expression_random_range<T> gen_random_range(const random_bit_generator& gen, T min, T max) { - return internal::expression_random_uniform<T>(random_bit_generator(seed_from_rdtsc)); + return internal::expression_random_range<T>(gen, min, max); } +/// @brief Returns expression that returns pseudo random values of the given range template <typename T> inline internal::expression_random_range<T> gen_random_range(T min, T max) { diff --git a/include/kfr/base/sort.hpp b/include/kfr/base/sort.hpp @@ -32,7 +32,7 @@ namespace kfr { /** - * Sort the elements in the vector in ascending order + * @brief Sort the elements in the vector in ascending order * @param x input vector * @return sorted vector * @code @@ -65,7 +65,7 @@ CMT_INLINE vec<T, N> sort(const vec<T, N>& x) } /** - * Sort the elements in the vector in descending order + * @brief Sort the elements in the vector in descending order * @param x input vector * @return sorted vector * @code diff --git a/include/kfr/base/univector.hpp b/include/kfr/base/univector.hpp @@ -61,6 +61,7 @@ constexpr size_t tag_dynamic_vector = max_size_t; template <typename T, size_t Size = tag_dynamic_vector> struct univector; +/// @brief Base class for all univector specializations. template <typename T, typename Class> struct univector_base : input_expression, output_expression { @@ -88,24 +89,38 @@ struct univector_base : input_expression, output_expression assign_expr(std::forward<Input>(input)); return *derived_cast<Class>(this); } + + /// @brief Returns subrange of the vector. + /// If start is greater or equal to this->size, returns empty univector + /// If requested size is greater than this->size, returns only available elements univector<T, 0> slice(size_t start = 0, size_t size = max_size_t) { T* data = derived_cast<Class>(this)->data(); const size_t this_size = derived_cast<Class>(this)->size(); return array_ref<T>(data + start, std::min(size, start < this_size ? this_size - start : 0)); } + + /// @brief Returns subrange of the vector. + /// If start is greater or equal to this->size, returns empty univector + /// If requested size is greater than this->size, returns only available elements univector<const T, 0> slice(size_t start = 0, size_t size = max_size_t) const { const T* data = derived_cast<Class>(this)->data(); const size_t this_size = derived_cast<Class>(this)->size(); return array_ref<const T>(data + start, std::min(size, start < this_size ? this_size - start : 0)); } + + /// @brief Returns subrange of the vector starting from 0. + /// If requested size is greater than this->size, returns only available elements univector<T, 0> truncate(size_t size = max_size_t) { T* data = derived_cast<Class>(this)->data(); const size_t this_size = derived_cast<Class>(this)->size(); return array_ref<T>(data, std::min(size, this_size)); } + + /// @brief Returns subrange of the vector starting from 0. + /// If requested size is greater than this->size, returns only available elements univector<const T, 0> truncate(size_t size = max_size_t) const { const T* data = derived_cast<Class>(this)->data(); @@ -344,9 +359,11 @@ struct univector<T, tag_dynamic_vector> : std::vector<T, allocator<T>>, } }; +/// @brief Alias for ``univector<T, tag_array_ref>``; template <typename T> using univector_ref = univector<T, tag_array_ref>; +/// @brief Alias for ``univector<T, tag_dynamic_vector>``; template <typename T> using univector_dyn = univector<T, tag_dynamic_vector>; diff --git a/include/kfr/base/vec.hpp b/include/kfr/base/vec.hpp @@ -604,7 +604,7 @@ CMT_GNU_CONSTEXPR CMT_INLINE vec<T, N> make_vector_impl(csizes_t<indices...>, co /// Create vector from scalar values /// @code /// CHECK( make_vector( 1, 2, 3, 4 ) == i32x4{1, 2, 3, 4} ); -/// @encode +/// @endcode template <typename Type = void, typename Arg, typename... Args, size_t N = (sizeof...(Args) + 1), typename SubType = conditional<is_void<Type>::value, common_type<Arg, Args...>, Type>> constexpr CMT_INLINE vec<SubType, N> make_vector(const Arg& x, const Args&... rest) diff --git a/include/kfr/cometa.hpp b/include/kfr/cometa.hpp @@ -819,36 +819,42 @@ constexpr inline bool is_divisible(T x, T divisor) return x % divisor == 0; } +/// @brief Greatest common divisor template <typename T> constexpr inline T gcd(T a) { return a; } +/// @brief Greatest common divisor template <typename T> constexpr inline T gcd(T a, T b) { return a < b ? gcd(b, a) : ((a % b == 0) ? b : gcd(b, a % b)); } +/// @brief Greatest common divisor template <typename T, typename... Ts> constexpr inline T gcd(T a, T b, T c, Ts... rest) { return gcd(a, gcd(b, c, rest...)); } +/// @brief Least common multiple template <typename T> constexpr inline T lcm(T a) { return a; } +/// @brief Least common multiple template <typename T> constexpr inline T lcm(T a, T b) { return a * b / gcd(a, b); } +/// @brief Least common multiple template <typename T, typename... Ts> constexpr inline T lcm(T a, T b, T c, Ts... rest) { diff --git a/include/kfr/cometa/array.hpp b/include/kfr/cometa/array.hpp @@ -11,6 +11,7 @@ namespace cometa { +/// @brief Reference to array template <typename T> struct array_ref { diff --git a/include/kfr/cometa/function.hpp b/include/kfr/cometa/function.hpp @@ -66,7 +66,7 @@ struct function; * @code * function<int( float )> f = []( float x ){ return static_cast<int>( x ); }; * CHECK( f( 3.4f ) == 3 ) - * @encode + * @endcode */ template <typename Result, typename... Args> struct function<Result(Args...)> diff --git a/include/kfr/cometa/range.hpp b/include/kfr/cometa/range.hpp @@ -7,6 +7,8 @@ namespace cometa { + +/// @brief Iterable range template <typename T> struct range { @@ -51,12 +53,14 @@ struct range iterator end() const { return iterator{ value_end, step }; } }; +/// @brief Make iterable range object template <typename T> range<T> make_range(T begin, T end) { return range<T>(begin, end, end > begin ? 1 : -1); } +/// @brief Make iterable range object with step template <typename T, typename diff_type = decltype(std::declval<T>() - std::declval<T>())> range<T> make_range(T begin, T end, diff_type step) { diff --git a/include/kfr/dft/cache.hpp b/include/kfr/dft/cache.hpp @@ -123,6 +123,7 @@ private: using dft_cache = dft_cache_impl<>; +/// @brief Performs Direct DFT using cached plan template <typename T, size_t Tag> univector<complex<T>> dft(const univector<complex<T>, Tag>& input) { @@ -133,6 +134,7 @@ univector<complex<T>> dft(const univector<complex<T>, Tag>& input) return output; } +/// @brief Performs Inverse DFT using cached plan template <typename T, size_t Tag> univector<complex<T>> idft(const univector<complex<T>, Tag>& input) { @@ -143,6 +145,7 @@ univector<complex<T>> idft(const univector<complex<T>, Tag>& input) return output; } +/// @brief Performs Real Direct DFT using cached plan template <typename T, size_t Tag> univector<complex<T>> realdft(const univector<T, Tag>& input) { @@ -153,6 +156,7 @@ univector<complex<T>> realdft(const univector<T, Tag>& input) return output; } +/// @brief Permorms Real Inverse DFT using cached plan template <typename T, size_t Tag> univector<T> irealdft(const univector<complex<T>, Tag>& input) { diff --git a/include/kfr/dft/convolution.hpp b/include/kfr/dft/convolution.hpp @@ -53,24 +53,28 @@ template <typename T> univector<T> autocorrelate(const univector_ref<const T>& src1); } // namespace internal +/// @brief Convolution template <typename T, size_t Tag1, size_t Tag2> univector<T> convolve(const univector<T, Tag1>& src1, const univector<T, Tag2>& src2) { return internal::convolve(src1.slice(), src2.slice()); } +/// @brief Correlation template <typename T, size_t Tag1, size_t Tag2> univector<T> correlate(const univector<T, Tag1>& src1, const univector<T, Tag2>& src2) { return internal::correlate(src1.slice(), src2.slice()); } +/// @brief Auto-correlation template <typename T, size_t Tag1> univector<T> autocorrelate(const univector<T, Tag1>& src) { return internal::autocorrelate(src.slice()); } +/// @brief Convolution using Filter API template <typename T> class convolve_filter : public filter<T> { diff --git a/include/kfr/dft/fft.hpp b/include/kfr/dft/fft.hpp @@ -63,6 +63,7 @@ enum class dft_order template <typename T> struct dft_stage; +/// @brief Class for performing DFT/FFT template <typename T> struct dft_plan { diff --git a/include/kfr/dft/reference_dft.hpp b/include/kfr/dft/reference_dft.hpp @@ -77,6 +77,7 @@ void reference_fft_pass(Tnumber pi2, size_t N, size_t offset, size_t delta, int } } +/// @brief Performs Complex FFT using reference implementation (slow, used for testing) template <typename Tnumber = double, typename T> void reference_fft(complex<T>* out, const complex<T>* in, size_t size, bool inversion = false) { @@ -93,6 +94,7 @@ void reference_fft(complex<T>* out, const complex<T>* in, size_t size, bool inve std::copy(dataout.begin(), dataout.end(), out); } +/// @brief Performs Direct Real FFT using reference implementation (slow, used for testing) template <typename Tnumber = double, typename T> void reference_fft(complex<T>* out, const T* in, size_t size) { @@ -110,6 +112,7 @@ void reference_fft(complex<T>* out, const T* in, size_t size) std::copy(dataout.begin(), dataout.end(), out); } +/// @brief Performs Inverse Real FFT using reference implementation (slow, used for testing) template <typename Tnumber = double, typename T> void reference_fft(T* out, const complex<T>* in, size_t size) { @@ -128,6 +131,7 @@ void reference_fft(T* out, const complex<T>* in, size_t size) out[i] = dataout[i].real(); } +/// @brief Performs Complex DFT using reference implementation (slow, used for testing) template <typename Tnumber = double, typename T> void reference_dft(complex<T>* out, const complex<T>* in, size_t size, bool inversion = false) { @@ -177,6 +181,7 @@ void reference_dft(complex<T>* out, const complex<T>* in, size_t size, bool inve } } +/// @brief Performs DFT using reference implementation (slow, used for testing) template <typename Tnumber = double, typename T> inline univector<complex<T>> reference_dft(const univector<complex<T>>& in, bool inversion = false) { diff --git a/include/kfr/dsp/fir.hpp b/include/kfr/dsp/fir.hpp @@ -192,6 +192,7 @@ public: void set_taps(const array_ref<const T>& taps) { state = fir_state<T, U>(taps); } + /// Reset internal filter state void reset() final { state.delayline.fill(0); diff --git a/include/kfr/dsp/sample_rate_conversion.hpp b/include/kfr/dsp/sample_rate_conversion.hpp @@ -55,6 +55,7 @@ KFR_SINTRIN T1 sample_rate_converter_blackman(T1 n, T2 a) return a0 - a1 * cos(n) + a2 * cos(2 * n); } +/// @brief Sample Rate converter template <typename T, size_t quality, KFR_ARCH_DEP> struct sample_rate_converter { diff --git a/include/kfr/io/audiofile.hpp b/include/kfr/io/audiofile.hpp @@ -109,9 +109,11 @@ static drflac_bool32 drflac_reader_seek_proc(abstract_reader<void>* file, int of } // namespace internal #if KFR_ENABLE_WAV +/// @brief WAV format writer template <typename T> struct audio_writer_wav : audio_writer<T> { + /// @brief Constructs WAV writer using target writer and format audio_writer_wav(std::shared_ptr<abstract_writer<>>&& writer, const audio_format& fmt) : writer(std::move(writer)), f(nullptr), fmt(fmt) { @@ -127,6 +129,7 @@ struct audio_writer_wav : audio_writer<T> } ~audio_writer_wav() { close(); } + /// @brief Write data to underlying binary writer size_t write(const T* data, size_t size) { if (!f) @@ -148,14 +151,21 @@ struct audio_writer_wav : audio_writer<T> return sz; } } + + /// @brief Finishes writing and closes underlying writer void close() { drwav_close(f); f = nullptr; writer.reset(); } + + /// @brief Returns format description const audio_format_and_length& format() const { return fmt; } + + /// @brief Returns current position imax tell() const { return fmt.length; } + bool seek(imax position, seek_origin origin) { return false; } private: @@ -164,9 +174,11 @@ private: audio_format_and_length fmt; }; +/// @brief WAV format reader template <typename T> struct audio_reader_wav : audio_reader<T> { + /// @brief Constructs WAV reader audio_reader_wav(std::shared_ptr<abstract_reader<>>&& reader) : reader(std::move(reader)) { f = drwav_open((drwav_read_proc)&internal::drwav_reader_read_proc, @@ -217,8 +229,10 @@ struct audio_reader_wav : audio_reader<T> } ~audio_reader_wav() { drwav_close(f); } + /// @brief Returns audio format description const audio_format_and_length& format() const { return fmt; } + /// @brief Reads and decodes audio data size_t read(T* data, size_t size) { if (fmt.type == audio_sample_type::unknown) @@ -235,7 +249,11 @@ struct audio_reader_wav : audio_reader<T> return sz; } } + + /// @brief Returns current position imax tell() const { return position; } + + /// @brief Seeks to specific sample bool seek(imax offset, seek_origin origin) { switch (origin) @@ -260,9 +278,12 @@ private: #endif #if KFR_ENABLE_FLAC + +/// @brief FLAC format reader template <typename T> struct audio_reader_flac : audio_reader<T> { + /// @brief Constructs FLAC reader audio_reader_flac(std::shared_ptr<abstract_reader<>>&& reader) : reader(std::move(reader)) { f = drflac_open((drflac_read_proc)&internal::drflac_reader_read_proc, @@ -274,8 +295,10 @@ struct audio_reader_flac : audio_reader<T> } ~audio_reader_flac() { drflac_close(f); } + /// @brief Returns audio format description const audio_format_and_length& format() const { return fmt; } + /// @brief Reads and decodes audio data size_t read(T* data, size_t size) { if (fmt.type == audio_sample_type::unknown) @@ -292,7 +315,11 @@ struct audio_reader_flac : audio_reader<T> return sz; } } + + /// @brief Returns current position imax tell() const { return position; } + + /// @brief Seeks to specific sample bool seek(imax offset, seek_origin origin) { switch (origin) diff --git a/include/kfr/io/file.hpp b/include/kfr/io/file.hpp @@ -56,6 +56,7 @@ using filepath = std::basic_string<filepath_char>; #define IO_TELL_64 ftello #endif +/// @brief Opens file using portable path (char* on posix, wchar_t* on windows) inline FILE* fopen_portable(const filepath_char* path, const filepath_char* mode) { #ifdef CMT_OS_WIN @@ -78,13 +79,15 @@ constexpr inline size_t element_size<void>() return 1; } +/// @brief Seek origin enum class seek_origin : int { - current = SEEK_CUR, - begin = SEEK_SET, - end = SEEK_END, + current = SEEK_CUR, ///< From the current position + begin = SEEK_SET, ///< From the beginning + end = SEEK_END, ///< From the end }; +/// @brief Base class for all typed readers and writer template <typename T = void> struct abstract_stream { @@ -94,12 +97,14 @@ struct abstract_stream bool seek(imax offset, int origin) { return seek(offset, static_cast<seek_origin>(origin)); } }; +/// @brief Base class for all typed readers template <typename T = void> struct abstract_reader : abstract_stream<T> { virtual size_t read(T* data, size_t size) = 0; }; +/// @brief Base class for all typed writers template <typename T = void> struct abstract_writer : abstract_stream<T> { @@ -137,11 +142,22 @@ struct writer_adapter : abstract_writer<To> std::shared_ptr<abstract_writer<From>> writer; }; +/// @brief Binary reader using binary_reader = abstract_reader<>; + +/// @brief Binary writer using binary_writer = abstract_writer<>; + +/// @brief Byte reader using byte_reader = abstract_reader<u8>; + +/// @brief Byte writer using byte_writer = abstract_writer<u8>; + +/// @brief float reader using f32_reader = abstract_reader<f32>; + +/// @brief float writer using f32_writer = abstract_writer<f32>; struct file_handle @@ -161,6 +177,7 @@ struct file_handle void swap(file_handle& handle) { std::swap(file, handle.file); } }; +/// @brief Typed file reader template <typename T = void> struct file_reader : abstract_reader<T> { @@ -176,6 +193,7 @@ struct file_reader : abstract_reader<T> file_handle handle; }; +/// @brief Typed file writer template <typename T = void> struct file_writer : abstract_writer<T> { @@ -193,18 +211,21 @@ struct file_writer : abstract_writer<T> file_handle handle; }; +/// @brief Opens typed file for reading template <typename T = void> inline std::shared_ptr<file_reader<T>> open_file_for_reading(const filepath& path) { return std::make_shared<file_reader<T>>(fopen_portable(path.c_str(), KFR_FILEPATH("rb"))); } +/// @brief Opens typed file for writing template <typename T = void> inline std::shared_ptr<file_writer<T>> open_file_for_writing(const filepath& path) { return std::make_shared<file_writer<T>>(fopen_portable(path.c_str(), KFR_FILEPATH("wb"))); } +/// @brief Opens typed file for appending template <typename T = void> inline std::shared_ptr<file_writer<T>> open_file_for_appending(const filepath& path) { @@ -212,18 +233,21 @@ inline std::shared_ptr<file_writer<T>> open_file_for_appending(const filepath& p } #ifdef CMT_OS_WIN +/// @brief Opens typed file for reading template <typename T = void> inline std::shared_ptr<file_reader<T>> open_file_for_reading(const std::string& path) { return std::make_shared<file_reader<T>>(fopen(path.c_str(), "rb")); } +/// @brief Opens typed file for writing template <typename T = void> inline std::shared_ptr<file_writer<T>> open_file_for_writing(const std::string& path) { return std::make_shared<file_writer<T>>(fopen(path.c_str(), "wb")); } +/// @brief Opens typed file for appending template <typename T = void> inline std::shared_ptr<file_writer<T>> open_file_for_appending(const std::string& path) { @@ -231,88 +255,4 @@ inline std::shared_ptr<file_writer<T>> open_file_for_appending(const std::string } #endif -namespace internal -{ -struct expression_file_base -{ - expression_file_base() = delete; - expression_file_base(const expression_file_base&) = delete; - expression_file_base(expression_file_base&&) = default; - expression_file_base(FILE* file) : file(file) {} - ~expression_file_base() { fclose(file); } - bool ok() const { return file != nullptr; } - FILE* file; -}; - -struct expression_sequential_file_writer : expression_file_base, output_expression -{ - using expression_file_base::expression_file_base; - template <typename U, size_t N> - void operator()(coutput_t, size_t, const vec<U, N>& value) - { - write(value); - } - template <typename U> - void write(const U& value) - { - write(&value, 1); - } - template <typename U> - void write(const U* value, size_t size) - { - fwrite(value, 1, sizeof(U) * size, file); - } -}; - -struct expression_sequential_file_reader : expression_file_base, input_expression -{ - using expression_file_base::expression_file_base; - template <typename U, size_t N> - vec<U, N> operator()(cinput_t, size_t, vec_t<U, N>) const - { - vec<U, N> input = qnan; - read(input); - return input; - } - template <typename U> - void read(U& value) const - { - fread(std::addressof(value), 1, sizeof(U), file); - } -}; - -template <typename T> -struct expression_file_writer : expression_file_base, output_expression -{ - using expression_file_base::expression_file_base; - template <size_t N> - void operator()(coutput_t, size_t index, const vec<T, N>& value) - { - if (position != index) - fseeko(file, static_cast<off_t>(index * sizeof(T)), SEEK_SET); - const vec<T, N> output = value; - fwrite(output.data(), sizeof(T), output.size(), file); - position = index + N; - } - size_t position = 0; -}; - -template <typename T> -struct expression_file_reader : expression_file_base, input_expression -{ - using expression_file_base::expression_file_base; - template <size_t N> - vec<T, N> operator()(cinput_t, size_t index, vec_t<T, N>) const - { - if (position != index) - fseeko(file, static_cast<off_t>(index * sizeof(T)), SEEK_SET); - vec<T, N> input = qnan; - fread(input.data(), sizeof(T), input.size(), file); - position = index + N; - return input; - } - mutable size_t position = 0; -}; -} // namespace internal - } // namespace kfr diff --git a/include/kfr/io/python_plot.hpp b/include/kfr/io/python_plot.hpp @@ -116,6 +116,7 @@ void plot_show(const std::string& name, const char* x, const std::string& option plot_show(name, std::string(x), options); } +/// @brief Plot data using python template <typename T> void plot_show(const std::string& name, T&& x, const std::string& options = "") { @@ -133,6 +134,7 @@ void plot_show(const std::string& name, T&& x, const std::string& options = "") print("done\n"); } +/// @brief Plot data using python and save to file template <typename T> void plot_save(const std::string& name, T&& x, const std::string& options = "") {