aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/mdct
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2024-06-17 20:12:45 +0000
committerDaniil Cherednik <dan.cherednik@gmail.com>2024-06-17 22:21:52 +0200
commit23a4e5f1dd7ce24f65a2af0598d1f92af4b5c424 (patch)
tree8a259ca8363c5b15fd3605b760518cb37e6ac63c /src/lib/mdct
parent73dbd1609445a0142e1e138b6b44ec6d1925cbb8 (diff)
downloadatracdenc-23a4e5f1dd7ce24f65a2af0598d1f92af4b5c424.tar.gz
[refactoring] move some libraries in to library directory
Diffstat (limited to 'src/lib/mdct')
-rw-r--r--src/lib/mdct/common.h47
-rw-r--r--src/lib/mdct/dct.h31
-rw-r--r--src/lib/mdct/mdct.cpp82
-rw-r--r--src/lib/mdct/mdct.h182
-rw-r--r--src/lib/mdct/mdct_ut.cpp200
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);
+ }
+}