commit afd39ce67cdf54297dfbb71e3dc2c6bf8c9b7dbc
parent a229a6dcabfb83dde41b5c0cb764a1f4d777084d
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date: Wed, 5 Dec 2018 19:14:19 +0000
sample conversion/interleaving/deinterleaving
Diffstat:
5 files changed, 200 insertions(+), 5 deletions(-)
diff --git a/include/kfr/base.hpp b/include/kfr/base.hpp
@@ -31,6 +31,7 @@
#include "base/compiletime.hpp"
#include "base/complex.hpp"
#include "base/constants.hpp"
+#include "base/conversion.hpp"
#include "base/digitreverse.hpp"
#include "base/expression.hpp"
#include "base/filter.hpp"
diff --git a/include/kfr/base/conversion.hpp b/include/kfr/base/conversion.hpp
@@ -0,0 +1,125 @@
+/** @addtogroup math
+ * @{
+ */
+/*
+ Copyright (C) 2016 D Levin (https://www.kfrlib.com)
+ This file is part of KFR
+
+ KFR 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, either version 3 of the License, or
+ (at your option) any later version.
+
+ KFR 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 KFR.
+
+ If GPL is not suitable for your project, you must purchase a commercial license to use KFR.
+ Buying a commercial license is mandatory as soon as you develop commercial activities without
+ disclosing the source code of your own applications.
+ See https://www.kfrlib.com for details.
+ */
+#pragma once
+
+#include "types.hpp"
+#include "vec.hpp"
+
+namespace kfr
+{
+
+template <typename T>
+struct audio_sample_traits;
+
+template <>
+struct audio_sample_traits<i8>
+{
+ constexpr static f32 scale = 127.f;
+};
+
+template <>
+struct audio_sample_traits<i16>
+{
+ constexpr static f32 scale = 32767.f;
+};
+
+template <>
+struct audio_sample_traits<i24>
+{
+ constexpr static f32 scale = 8388607.f;
+};
+
+template <>
+struct audio_sample_traits<i32>
+{
+ constexpr static f64 scale = 2147483647.0;
+};
+
+template <>
+struct audio_sample_traits<i64>
+{
+ constexpr static f64 scale = 9223372036854775807.0;
+};
+
+template <>
+struct audio_sample_traits<f32>
+{
+ constexpr static f32 scale = 1;
+};
+
+template <>
+struct audio_sample_traits<f64>
+{
+ constexpr static f64 scale = 1;
+};
+
+template <typename Tout, typename Tin, typename Tout_traits = audio_sample_traits<Tout>,
+ typename Tin_traits = audio_sample_traits<Tin>, KFR_ENABLE_IF(is_same<Tin, Tout>::value)>
+inline Tout convert_sample(const Tin& in)
+{
+ return in;
+}
+
+template <typename Tout, typename Tin, typename Tout_traits = audio_sample_traits<Tout>,
+ typename Tin_traits = audio_sample_traits<Tin>, KFR_ENABLE_IF(!is_same<Tin, Tout>::value)>
+inline Tout convert_sample(const Tin& in)
+{
+ constexpr auto scale = Tout_traits::scale / Tin_traits::scale;
+ return cast<Tout>(in * scale);
+}
+
+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)
+{
+ for (size_t i = 0; i < size; ++i)
+ {
+ for (size_t ch = 0; ch < channels; ++ch)
+ out[ch][i] = convert_sample<Tout, Tin, Tout_traits, Tin_traits>(in[i * channels + ch]);
+ }
+}
+
+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)
+{
+ for (size_t i = 0; i < size; ++i)
+ {
+ for (size_t ch = 0; ch < channels; ++ch)
+ out[i * channels + ch] = convert_sample<Tout, Tin, Tout_traits, Tin_traits>(in[ch][i]);
+ }
+}
+
+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)
+{
+ for (size_t i = 0; i < size; ++i)
+ {
+ out[i] = convert_sample<Tout, Tin, Tout_traits, Tin_traits>(in[i]);
+ }
+}
+} // namespace kfr
diff --git a/include/kfr/base/types.hpp b/include/kfr/base/types.hpp
@@ -127,6 +127,21 @@ struct u24
struct i24
{
u8 raw[3];
+
+ i24(i32 x)
+ {
+ raw[0] = x & 0xFF;
+ raw[1] = (x >> 8) & 0xFF;
+ raw[2] = (x >> 16) & 0xFF;
+ }
+
+ i32 as_int() const
+ {
+ return static_cast<i32>(raw[0]) | static_cast<i32>(raw[1] << 8) |
+ (static_cast<i32>(raw[2] << 24) >> 8);
+ }
+
+ operator int() const { return as_int(); }
};
struct f16
@@ -232,7 +247,7 @@ using get_third = cometa::fn_get_third;
///@copybrief cometa::returns
template <typename T>
using returns = cometa::fn_returns<T>;
-}
+} // namespace fn
template <typename T>
using ftype =
@@ -269,7 +284,7 @@ struct flt_type_impl<double>
{
using type = double;
};
-}
+} // namespace internal
template <typename T>
using flt_type = typename internal::flt_type_impl<T>::type;
@@ -327,7 +342,7 @@ __attribute__((__packed__, __may_alias__)) //
;
CMT_PRAGMA_GNU(GCC diagnostic pop)
-}
+} // namespace internal
/// @brief Fills a value with zeros
template <typename T1>
@@ -351,7 +366,7 @@ CMT_INLINE void block_process_impl(size_t& i, size_t size, Fn&& fn)
for (; i < size / width * width; i += width)
fn(i, csize_t<width>());
}
-}
+} // namespace internal
template <size_t... widths, typename Fn>
CMT_INLINE void block_process(size_t size, csizes_t<widths...>, Fn&& fn)
@@ -409,6 +424,6 @@ constexpr cunaligned_t cunaligned{};
#else
#define KFR_I_CE
#endif
-}
+} // namespace kfr
CMT_PRAGMA_GNU(GCC diagnostic pop)
diff --git a/sources.cmake b/sources.cmake
@@ -24,6 +24,7 @@ set(
${PROJECT_SOURCE_DIR}/include/kfr/base/compiletime.hpp
${PROJECT_SOURCE_DIR}/include/kfr/base/complex.hpp
${PROJECT_SOURCE_DIR}/include/kfr/base/constants.hpp
+ ${PROJECT_SOURCE_DIR}/include/kfr/base/conversion.hpp
${PROJECT_SOURCE_DIR}/include/kfr/base/digitreverse.hpp
${PROJECT_SOURCE_DIR}/include/kfr/base/expression.hpp
${PROJECT_SOURCE_DIR}/include/kfr/base/filter.hpp
diff --git a/tests/base_test.cpp b/tests/base_test.cpp
@@ -377,6 +377,59 @@ TEST(test_stat)
}
}
+TEST(sample_conversion)
+{
+ CHECK(convert_sample<float>(static_cast<i8>(-127)) == -1.f);
+ CHECK(convert_sample<float>(static_cast<i8>(0)) == 0.f);
+ CHECK(convert_sample<float>(static_cast<i8>(127)) == 1.f);
+
+ CHECK(convert_sample<float>(static_cast<i16>(-32767)) == -1.f);
+ CHECK(convert_sample<float>(static_cast<i16>(0)) == 0.f);
+ CHECK(convert_sample<float>(static_cast<i16>(32767)) == 1.f);
+
+ CHECK(convert_sample<float>(static_cast<i24>(-8388607)) == -1.f);
+ CHECK(convert_sample<float>(static_cast<i24>(0)) == 0.f);
+ CHECK(convert_sample<float>(static_cast<i24>(8388607)) == 1.f);
+
+ CHECK(convert_sample<float>(static_cast<i32>(-2147483647)) == -1.f);
+ CHECK(convert_sample<float>(static_cast<i32>(0)) == 0.f);
+ CHECK(convert_sample<float>(static_cast<i32>(2147483647)) == 1.f);
+
+ CHECK(convert_sample<i8>(-1.f) == -127);
+ CHECK(convert_sample<i8>(0.f) == 0);
+ CHECK(convert_sample<i8>(1.f) == 127);
+
+ CHECK(convert_sample<i16>(-1.f) == -32767);
+ CHECK(convert_sample<i16>(0.f) == 0);
+ CHECK(convert_sample<i16>(1.f) == 32767);
+
+ CHECK(convert_sample<i24>(-1.f) == -8388607);
+ CHECK(convert_sample<i24>(0.f) == 0);
+ CHECK(convert_sample<i24>(1.f) == 8388607);
+
+ CHECK(convert_sample<i32>(-1.f) == -2147483647);
+ CHECK(convert_sample<i32>(0.f) == 0);
+ CHECK(convert_sample<i32>(1.f) == 2147483647);
+}
+
+TEST(sample_interleave_deinterleave)
+{
+ const size_t size = 50;
+ univector2d<float> in;
+ in.push_back(truncate(counter() * 3.f + 0.f, size));
+ in.push_back(truncate(counter() * 3.f + 1.f, size));
+ in.push_back(truncate(counter() * 3.f + 2.f, size));
+ univector<float> out(size * 3);
+ interleave(out.data(), (const float*[]){ in[0].data(), in[1].data(), in[2].data() }, 3, size);
+ CHECK(maxof(out - render(counter() * 1.f, out.size())) == 0);
+
+ deinterleave((float*[]){ in[0].data(), in[1].data(), in[2].data() }, out.data(), 3, size);
+
+ CHECK(maxof(in[0] - render(counter() * 3.f + 0.f, size)) == 0);
+ CHECK(maxof(in[1] - render(counter() * 3.f + 1.f, size)) == 0);
+ CHECK(maxof(in[2] - render(counter() * 3.f + 2.f, size)) == 0);
+}
+
#ifndef KFR_NO_MAIN
int main()
{