diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2024-06-17 20:12:45 +0000 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2024-06-17 22:21:52 +0200 |
commit | 23a4e5f1dd7ce24f65a2af0598d1f92af4b5c424 (patch) | |
tree | 8a259ca8363c5b15fd3605b760518cb37e6ac63c /src/lib/mdct | |
parent | 73dbd1609445a0142e1e138b6b44ec6d1925cbb8 (diff) | |
download | atracdenc-23a4e5f1dd7ce24f65a2af0598d1f92af4b5c424.tar.gz |
[refactoring] move some libraries in to library directory
Diffstat (limited to 'src/lib/mdct')
-rw-r--r-- | src/lib/mdct/common.h | 47 | ||||
-rw-r--r-- | src/lib/mdct/dct.h | 31 | ||||
-rw-r--r-- | src/lib/mdct/mdct.cpp | 82 | ||||
-rw-r--r-- | src/lib/mdct/mdct.h | 182 | ||||
-rw-r--r-- | src/lib/mdct/mdct_ut.cpp | 200 |
5 files changed, 542 insertions, 0 deletions
diff --git a/src/lib/mdct/common.h b/src/lib/mdct/common.h new file mode 100644 index 0000000..9b3c893 --- /dev/null +++ b/src/lib/mdct/common.h @@ -0,0 +1,47 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once +#include "../config.h" + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#ifdef CONFIG_DOUBLE +typedef double FLOAT; +#define FCONST(X) (X) +#define AFT_COS cos +#define AFT_SIN sin +#define AFT_TAN tan +#define AFT_LOG10 log10 +#define AFT_EXP exp +#define AFT_FABS fabs +#define AFT_SQRT sqrt +#define AFT_EXP exp +#else +typedef float FLOAT; +#define FCONST(X) (X##f) +#define AFT_COS cosf +#define AFT_SIN sinf +#define AFT_TAN tanf +#define AFT_LOG10 log10f +#define AFT_FABS fabsf +#define AFT_SQRT sqrtf +#define AFT_EXP expf +#endif diff --git a/src/lib/mdct/dct.h b/src/lib/mdct/dct.h new file mode 100644 index 0000000..55b81a9 --- /dev/null +++ b/src/lib/mdct/dct.h @@ -0,0 +1,31 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct atde_dct_ctx *atde_dct_ctx_t; + +atde_dct_ctx_t atde_create_dct4_16(float scale); +void atde_free_dct_ctx(atde_dct_ctx_t ctx); +void atde_do_dct4_16(atde_dct_ctx_t ctx, const float* in, float* out); + +#ifdef __cplusplus +} +#endif diff --git a/src/lib/mdct/mdct.cpp b/src/lib/mdct/mdct.cpp new file mode 100644 index 0000000..74b6d91 --- /dev/null +++ b/src/lib/mdct/mdct.cpp @@ -0,0 +1,82 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "mdct.h" +#include "dct.h" +#include <iostream> + +namespace NMDCT { + +static std::vector<TFloat> CalcSinCos(size_t n, TFloat scale) +{ + std::vector<TFloat> tmp(n >> 1); + const TFloat alpha = 2.0 * M_PI / (8.0 * n); + const TFloat omiga = 2.0 * M_PI / n; + scale = sqrt(scale/n); + for (size_t i = 0; i < (n >> 2); ++i) { + tmp[2 * i + 0] = scale * cos(omiga * i + alpha); + tmp[2 * i + 1] = scale * sin(omiga * i + alpha); + } + return tmp; +} + +TMDCTBase::TMDCTBase(size_t n, TFloat scale) + : N(n) + , SinCos(CalcSinCos(n, scale)) +{ + FFTIn = (kiss_fft_cpx*) malloc(sizeof(kiss_fft_cpx) * N >> 2); + FFTOut = (kiss_fft_cpx*) malloc(sizeof(kiss_fft_cpx) * N >> 2); + FFTPlan = kiss_fft_alloc(N >> 2, false, nullptr, nullptr); +} + +TMDCTBase::~TMDCTBase() +{ + kiss_fft_free(FFTPlan); + free(FFTOut); + free(FFTIn); +} + +} // namespace NMDCT + +struct atde_dct_ctx { + atde_dct_ctx(float scale) + : mdct(scale) + {} + NMDCT::TMIDCT<32, float> mdct; +}; + +atde_dct_ctx_t atde_create_dct4_16(float scale) +{ + return new atde_dct_ctx(32.0 * scale); +} + +void atde_free_dct_ctx(atde_dct_ctx_t ctx) +{ + delete ctx; +} + +void atde_do_dct4_16(atde_dct_ctx_t ctx, const float* in, float* out) +{ + //TODO: rewrire more optimal + const auto& x = ctx->mdct(in); + + for (int i = 0; i < 16; i++) { + out[i] = x[i + 8] * -1.0; + } +} + diff --git a/src/lib/mdct/mdct.h b/src/lib/mdct/mdct.h new file mode 100644 index 0000000..59b9af7 --- /dev/null +++ b/src/lib/mdct/mdct.h @@ -0,0 +1,182 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "config.h" +#include "fft/kissfft_impl/kiss_fft.h" +#include <vector> +#include <type_traits> + +namespace NMDCT { + +static_assert(sizeof(kiss_fft_scalar) == sizeof(TFloat), "size of fft_scalar is not equal to size of TFloat"); + +class TMDCTBase { +protected: + const size_t N; + const std::vector<TFloat> SinCos; + kiss_fft_cpx* FFTIn; + kiss_fft_cpx* FFTOut; + kiss_fft_cfg FFTPlan; + TMDCTBase(size_t n, TFloat scale); + virtual ~TMDCTBase(); +}; + + +template<size_t TN, typename TIO = TFloat> +class TMDCT : public TMDCTBase { + std::vector<TIO> Buf; +public: + TMDCT(float scale = 1.0) + : TMDCTBase(TN, scale) + , Buf(TN/2) + { + } + const std::vector<TIO>& operator()(const TIO* in) { + + const size_t n2 = N >> 1; + const size_t n4 = N >> 2; + const size_t n34 = 3 * n4; + const size_t n54 = 5 * n4; + const TFloat* cos = &SinCos[0]; + const TFloat* sin = &SinCos[1]; + + TFloat *xr, *xi, r0, i0; + TFloat c, s; + size_t n; + + xr = (TFloat*)FFTIn; + xi = (TFloat*)FFTIn + 1; + for (n = 0; n < n4; n += 2) { + r0 = in[n34 - 1 - n] + in[n34 + n]; + i0 = in[n4 + n] - in[n4 - 1 - n]; + + c = cos[n]; + s = sin[n]; + + xr[n] = r0 * c + i0 * s; + xi[n] = i0 * c - r0 * s; + } + + for (; n < n2; n += 2) { + r0 = in[n34 - 1 - n] - in[n - n4]; + i0 = in[n4 + n] + in[n54 - 1 - n]; + + c = cos[n]; + s = sin[n]; + + xr[n] = r0 * c + i0 * s; + xi[n] = i0 * c - r0 * s; + } + + kiss_fft(FFTPlan, FFTIn, FFTOut); + + xr = (TFloat*)FFTOut; + xi = (TFloat*)FFTOut + 1; + for (n = 0; n < n2; n += 2) { + r0 = xr[n]; + i0 = xi[n]; + + c = cos[n]; + s = sin[n]; + + Buf[n] = - r0 * c - i0 * s; + Buf[n2 - 1 -n] = - r0 * s + i0 * c; + } + + return Buf; + } +}; + +template<size_t TN, typename TIO = TFloat> +class TMIDCT : public TMDCTBase { + std::vector<TIO> Buf; +public: + TMIDCT(float scale = TN) + : TMDCTBase(TN, scale/2) + , Buf(TN) + {} + const std::vector<TIO>& operator()(const TIO* in) { + + const size_t n2 = N >> 1; + const size_t n4 = N >> 2; + const size_t n34 = 3 * n4; + const size_t n54 = 5 * n4; + const TFloat* cos = &SinCos[0]; + const TFloat* sin = &SinCos[1]; + + TFloat *xr, *xi, r0, i0, r1, i1; + TFloat c, s; + size_t n; + + xr = (TFloat*)FFTIn; + xi = (TFloat*)FFTIn + 1; + + for (n = 0; n < n2; n += 2) { + r0 = in[n]; + i0 = in[n2 - 1 - n]; + + c = cos[n]; + s = sin[n]; + + xr[n] = -2.0 * (i0 * s + r0 * c); + xi[n] = -2.0 * (i0 * c - r0 * s); + } + + kiss_fft(FFTPlan, FFTIn, FFTOut); + + xr = (TFloat*)FFTOut; + xi = (TFloat*)FFTOut + 1; + + for (n = 0; n < n4; n += 2) { + r0 = xr[n]; + i0 = xi[n]; + + c = cos[n]; + s = sin[n]; + + r1 = r0 * c + i0 * s; + i1 = r0 * s - i0 * c; + + Buf[n34 - 1 - n] = r1; + Buf[n34 + n] = r1; + Buf[n4 + n] = i1; + Buf[n4 - 1 - n] = -i1; + } + + for (; n < n2; n += 2) { + r0 = xr[n]; + i0 = xi[n]; + + c = cos[n]; + s = sin[n]; + + r1 = r0 * c + i0 * s; + i1 = r0 * s - i0 * c; + + Buf[n34 - 1 - n] = r1; + Buf[n - n4] = -r1; + Buf[n4 + n] = i1; + Buf[n54 - 1 - n] = i1; + } + return Buf; + } +}; + +} //namespace NMDCT diff --git a/src/lib/mdct/mdct_ut.cpp b/src/lib/mdct/mdct_ut.cpp new file mode 100644 index 0000000..31f6f81 --- /dev/null +++ b/src/lib/mdct/mdct_ut.cpp @@ -0,0 +1,200 @@ +/* + * This file is part of AtracDEnc. + * + * AtracDEnc is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * AtracDEnc 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with AtracDEnc; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "mdct.h" +#include <gtest/gtest.h> + +#include <vector> +#include <cstdlib> + +using std::vector; +using namespace NMDCT; + +static vector<TFloat> mdct(TFloat* x, int N) { + vector<TFloat> res; + for (int k = 0; k < N; k++) { + TFloat sum = 0; + for (int n = 0; n < 2 * N; n++) + sum += x[n]* cos((M_PI/N) * ((TFloat)n + 0.5 + N/2) * ((TFloat)k + 0.5)); + + res.push_back(sum); + } + return res; +} + +static vector<TFloat> midct(TFloat* x, int N) { + vector<TFloat> res; + for (int n = 0; n < 2 * N; n++) { + TFloat sum = 0; + for (int k = 0; k < N; k++) + sum += (x[k] * cos((M_PI/N) * ((TFloat)n + 0.5 + N/2) * ((TFloat)k + 0.5))); + + res.push_back(sum); + } + return res; +} + +TEST(TMdctTest, MDCT32) { + const int N = 32; + TMDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N; i++) { + src[i] = i; + } + const vector<TFloat> res1 = mdct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < res1.size(); i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MDCT64) { + const int N = 64; + TMDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N; i++) { + src[i] = i; + } + const vector<TFloat> res1 = mdct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < res1.size(); i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MDCT128) { + const int N = 128; + TMDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N; i++) { + src[i] = i; + } + const vector<TFloat> res1 = mdct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < res1.size(); i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MDCT256) { + const int N = 256; + TMDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N; i++) { + src[i] = i; + } + const vector<TFloat> res1 = mdct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < res1.size(); i++) { + EXPECT_NEAR(res1[i], res2[i], 0.00000001); + } +} + +TEST(TMdctTest, MDCT256_RAND) { + const int N = 256; + TMDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N; i++) { + src[i] = rand(); + } + const vector<TFloat> res1 = mdct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < res1.size(); i++) { + EXPECT_NEAR(res1[i], res2[i], 0.01); + } +} + +TEST(TMdctTest, MIDCT32) { + const int N = 32; + TMIDCT<N> transform; + vector<TFloat> src(N); + for (int i = 0; i < N/2; i++) { + src[i] = i; + } + const vector<TFloat> res1 = midct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < N; i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MIDCT64) { + const int N = 64; + TMIDCT<N> transform; + vector<TFloat> src(N); + for (int i = 0; i < N/2; i++) { + src[i] = i; + } + const vector<TFloat> res1 = midct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < N; i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MIDCT128) { + const int N = 128; + TMIDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N/2; i++) { + src[i] = i; + } + const vector<TFloat> res1 = midct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < N; i++) { + EXPECT_NEAR(res1[i], res2[i], 0.0000000001); + } +} + +TEST(TMdctTest, MIDCT256) { + const int N = 256; + TMIDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N/2; i++) { + src[i] = i; + } + const vector<TFloat> res1 = midct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < N; i++) { + EXPECT_NEAR(res1[i], res2[i], 0.000000001); + } +} + +TEST(TMdctTest, MIDCT256_RAND) { + const int N = 256; + TMIDCT<N> transform(N); + vector<TFloat> src(N); + for (int i = 0; i < N/2; i++) { + src[i] = rand(); + } + const vector<TFloat> res1 = midct(&src[0], N/2); + const vector<TFloat> res2 = transform(&src[0]); + EXPECT_EQ(res1.size(), res2.size()); + for (int i = 0; i < N; i++) { + EXPECT_NEAR(res1[i], res2[i], 0.01); + } +} |