diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2016-03-13 09:49:33 +0300 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2016-09-02 21:21:28 +0300 |
commit | cfaa2cd39b7256a868a4f5cd83aac207df6bd1b3 (patch) | |
tree | 75efff26584e046566d17cd308d45b6b0fd5abfc /src/atrac3denc_ut.cpp | |
parent | b4df8a7c2dd12eea27c8cc52bd52a1bb8c00943f (diff) | |
download | atracdenc-cfaa2cd39b7256a868a4f5cd83aac207df6bd1b3.tar.gz |
Dirty implementation of atrac3 encoder:
- no JS mode
- constant quantiser for tonal components
- gain controll implemented but produces some artifacts with real signals.
- etc...
Diffstat (limited to 'src/atrac3denc_ut.cpp')
-rw-r--r-- | src/atrac3denc_ut.cpp | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/src/atrac3denc_ut.cpp b/src/atrac3denc_ut.cpp new file mode 100644 index 0000000..e0602a2 --- /dev/null +++ b/src/atrac3denc_ut.cpp @@ -0,0 +1,335 @@ +#define ATRAC_UT_PUBLIC + +#include "atrac3denc.h" +#include <gtest/gtest.h> + +#include <vector> +#include <cmath> +using std::vector; +using namespace NAtracDEnc; +using namespace NAtrac3; + +static void GenerateSignal(TFloat* buf, size_t n, TFloat f, TFloat a) { + for (size_t i = 0; i < n; ++i) { + buf[i] = a * sin((M_PI/2) * i * f); + } +} + +static void GenerateSignalWithTransient(TFloat* buf, size_t n, TFloat f, TFloat a, + size_t transientPos, size_t transientLen, TFloat transientLev) { + assert(transientPos + transientLen < n); + GenerateSignal(buf, n, f, a); + GenerateSignal(buf+transientPos, transientLen, f, transientLev); +// for (size_t i = transientPos; i < transientPos + transientLen; ++i) { +// buf[i] += (i & 1) ? transientLev : - transientLev; +// } +} + +class TWindowTest : public TAtrac3Data { +public: + void RunTest() { + for (size_t i = 0; i < 256; i++) { + const TFloat ha1 = EncodeWindow[i] / 2.0; //compensation + const TFloat hs1 = DecodeWindow[i]; + const TFloat hs2 = DecodeWindow[255-i]; + const TFloat res = hs1 / (hs1 * hs1 + hs2 * hs2); + EXPECT_NEAR(ha1, res, 0.000000001); + } + } +}; + +template<class T> +class TAtrac3MDCTWorkBuff { + T* Buffer; +public: + static const size_t BandBuffSz = 256; + static const size_t BandBuffAndOverlapSz = BandBuffSz * 2; + static const size_t BuffSz = BandBuffAndOverlapSz * (4 + 4); + T* const Band0; + T* const Band1; + T* const Band2; + T* const Band3; + T* const Band0Res; + T* const Band1Res; + T* const Band2Res; + T* const Band3Res; + TAtrac3MDCTWorkBuff() + : Buffer(new T[BuffSz]) + , Band0(Buffer) + , Band1(Band0 + BandBuffAndOverlapSz) + , Band2(Band1 + BandBuffAndOverlapSz) + , Band3(Band2 + BandBuffAndOverlapSz) + , Band0Res(Band3 + BandBuffAndOverlapSz) + , Band1Res(Band0Res + BandBuffAndOverlapSz) + , Band2Res(Band1Res + BandBuffAndOverlapSz) + , Band3Res(Band2Res + BandBuffAndOverlapSz) + { + memset(Buffer, 0, sizeof(T)*BuffSz); + } + ~TAtrac3MDCTWorkBuff() + { + delete[] Buffer; + } +}; + + +TEST(TAtrac3MDCT, TAtrac3MDCTZeroOneBlock) { + TAtrac3MDCT mdct; + TAtrac3MDCTWorkBuff<TFloat> buff; + size_t workSz = TAtrac3MDCTWorkBuff<TFloat>::BandBuffSz; + + vector<TFloat> specs(1024); + + TFloat* p[4] = { buff.Band0, buff.Band1, buff.Band2, buff.Band3 }; + + mdct.Mdct(specs.data(), p); + for(auto s: specs) + EXPECT_NEAR(s, 0.0, 0.0000000001); + + TFloat* t[4] = { buff.Band0Res, buff.Band1Res, buff.Band2Res, buff.Band3Res }; + mdct.Midct(specs.data(), p); + + for(size_t i = 0; i < workSz; ++i) + EXPECT_NEAR(buff.Band0Res[i], 0.0, 0.0000000001); + + for(size_t i = 0; i < workSz; ++i) + EXPECT_NEAR(buff.Band1Res[i], 0.0, 0.0000000001); + + for(size_t i = 0; i < workSz; ++i) + EXPECT_NEAR(buff.Band2Res[i], 0.0, 0.0000000001); + + for(size_t i = 0; i < workSz; ++i) + EXPECT_NEAR(buff.Band3Res[i], 0.0, 0.0000000001); + + +} + +TEST(TAtrac3MDCT, TAtrac3MDCTSignal) { + TAtrac3MDCT mdct; + TAtrac3MDCTWorkBuff<TFloat> buff; + size_t workSz = TAtrac3MDCTWorkBuff<TFloat>::BandBuffSz; + + const size_t len = 1024; + vector<TFloat> signal(len); + vector<TFloat> signalRes(len); + GenerateSignal(signal.data(), signal.size(), 0.25, 32768); + + for (size_t pos = 0; pos < len; pos += workSz) { + vector<TFloat> specs(1024); + memcpy(buff.Band0, signal.data() + pos, workSz * sizeof(TFloat)); + + TFloat* p[4] = { buff.Band0, buff.Band1, buff.Band2, buff.Band3 }; + mdct.Mdct(specs.data(), p); + + TFloat* t[4] = { buff.Band0Res, buff.Band1Res, buff.Band2Res, buff.Band3Res }; + mdct.Midct(specs.data(), t); + + memcpy(signalRes.data() + pos, buff.Band0Res, workSz * sizeof(TFloat)); + } + + for (int i = workSz; i < len; ++i) + EXPECT_NEAR(signal[i - workSz], signalRes[i], 0.00000001); +} + +TEST(TAtrac3MDCT, TAtrac3MDCTSignalWithGainCompensation) { + TAtrac3MDCT mdct; + TAtrac3MDCTWorkBuff<TFloat> buff; + size_t workSz = TAtrac3MDCTWorkBuff<TFloat>::BandBuffSz; + + const size_t len = 4096; + vector<TFloat> signal(len, 8000); + vector<TFloat> signalRes(len); + GenerateSignal(signal.data() + 1024, signal.size()-1024, 0.25, 32768); + + for (size_t pos = 0; pos < len; pos += workSz) { + vector<TFloat> specs(1024); + memcpy(buff.Band0, signal.data() + pos, workSz * sizeof(TFloat)); + + TFloat* p[4] = { buff.Band0, buff.Band1, buff.Band2, buff.Band3 }; + + if (pos == 256) { //apply gain modulation + TAtrac3Data::SubbandInfo siCur; + siCur.AddSubbandCurve(0, {{3, 2}}); + + mdct.Mdct(specs.data(), p, { mdct.GainProcessor.Modulate(siCur.GetGainPoints(0)), + TAtrac3MDCT::TGainModulator(), TAtrac3MDCT::TGainModulator(), TAtrac3MDCT::TGainModulator()}); + } else if (pos == 1024) { + TAtrac3Data::SubbandInfo siCur; + std::vector<TAtrac3Data::SubbandInfo::TGainPoint> curve = {{3, 2}, {2, 5}}; + siCur.AddSubbandCurve(0, std::move(curve)); + + mdct.Mdct(specs.data(), p, { mdct.GainProcessor.Modulate(siCur.GetGainPoints(0)), + TAtrac3MDCT::TGainModulator(), TAtrac3MDCT::TGainModulator(), TAtrac3MDCT::TGainModulator()}); + } else if (pos == 1024 + 256) { + TAtrac3Data::SubbandInfo siCur; + siCur.AddSubbandCurve(0, {{1, 0}}); + + mdct.Mdct(specs.data(), p, { mdct.GainProcessor.Modulate(siCur.GetGainPoints(0)), + TAtrac3MDCT::TGainModulator(), TAtrac3MDCT::TGainModulator(), TAtrac3MDCT::TGainModulator()}); + } else if (pos == 2048) { + TAtrac3Data::SubbandInfo siCur; + std::vector<TAtrac3Data::SubbandInfo::TGainPoint> curve = {{4, 2}, {1, 5}}; + siCur.AddSubbandCurve(0, std::move(curve)); + + mdct.Mdct(specs.data(), p, { mdct.GainProcessor.Modulate(siCur.GetGainPoints(0)), + TAtrac3MDCT::TGainModulator(), TAtrac3MDCT::TGainModulator(), TAtrac3MDCT::TGainModulator()}); + } else { + mdct.Mdct(specs.data(), p); + } + + TFloat* t[4] = { buff.Band0Res, buff.Band1Res, buff.Band2Res, buff.Band3Res }; + + if (pos == 256) { //restore gain modulation + TAtrac3Data::SubbandInfo siCur; + TAtrac3Data::SubbandInfo siNext; + siNext.AddSubbandCurve(0, {{3, 2}}); + + mdct.Midct(specs.data(), t, {mdct.GainProcessor.Demodulate(siCur.GetGainPoints(0), siNext.GetGainPoints(0)), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator()}); + } else if (pos == 512) { + TAtrac3Data::SubbandInfo siNext; + TAtrac3Data::SubbandInfo siCur; + siCur.AddSubbandCurve(0, {{3, 2}}); + + mdct.Midct(specs.data(), t, {mdct.GainProcessor.Demodulate(siCur.GetGainPoints(0), siNext.GetGainPoints(0)), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator()}); + } else if (pos == 1024) { + TAtrac3Data::SubbandInfo siCur; + TAtrac3Data::SubbandInfo siNext; + std::vector<TAtrac3Data::SubbandInfo::TGainPoint> curve = {{3, 2}, {2, 5}}; + siNext.AddSubbandCurve(0, std::move(curve)); + + mdct.Midct(specs.data(), t, {mdct.GainProcessor.Demodulate(siCur.GetGainPoints(0), siNext.GetGainPoints(0)), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator()}); + } else if (pos == 1024 + 256) { + TAtrac3Data::SubbandInfo siNext; + TAtrac3Data::SubbandInfo siCur; + siNext.AddSubbandCurve(0, {{1, 0}}); + std::vector<TAtrac3Data::SubbandInfo::TGainPoint> curve = {{3, 2}, {2, 5}}; + siCur.AddSubbandCurve(0, std::move(curve)); + + mdct.Midct(specs.data(), t, {mdct.GainProcessor.Demodulate(siCur.GetGainPoints(0), siNext.GetGainPoints(0)), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator()}); + } else if (pos == 1024 + 256 + 256) { + TAtrac3Data::SubbandInfo siNext; + TAtrac3Data::SubbandInfo siCur; + siCur.AddSubbandCurve(0, {{1, 0}}); + + mdct.Midct(specs.data(), t, {mdct.GainProcessor.Demodulate(siCur.GetGainPoints(0), siNext.GetGainPoints(0)), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator()}); + } else if (pos == 2048) { + TAtrac3Data::SubbandInfo siCur; + TAtrac3Data::SubbandInfo siNext; + std::vector<TAtrac3Data::SubbandInfo::TGainPoint> curve = {{4, 2}, {1, 5}}; + siNext.AddSubbandCurve(0, std::move(curve)); + + mdct.Midct(specs.data(), t, {mdct.GainProcessor.Demodulate(siCur.GetGainPoints(0), siNext.GetGainPoints(0)), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator()}); + } else if (pos == 2048 + 256) { + TAtrac3Data::SubbandInfo siNext; + TAtrac3Data::SubbandInfo siCur; + std::vector<TAtrac3Data::SubbandInfo::TGainPoint> curve = {{4, 2}, {1, 5}}; + siCur.AddSubbandCurve(0, std::move(curve)); + + mdct.Midct(specs.data(), t, {mdct.GainProcessor.Demodulate(siCur.GetGainPoints(0), siNext.GetGainPoints(0)), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator()}); + } else { + mdct.Midct(specs.data(), t); + } + memcpy(signalRes.data() + pos, buff.Band0Res, workSz * sizeof(TFloat)); + } + for (int i = workSz; i < len; ++i) { + //std::cout << "res: " << i << " " << signalRes[i] << std::endl; + EXPECT_NEAR(signal[i - workSz], signalRes[i], 0.00000001); + } +} + +TEST(TAtrac3MDCT, TAtrac3MDCTSignalWithGainCompensationAndManualTransient) { + TAtrac3MDCT mdct; + TAtrac3MDCTWorkBuff<TFloat> buff; + size_t workSz = TAtrac3MDCTWorkBuff<TFloat>::BandBuffSz; + + const size_t len = 1024; + vector<TFloat> signal(len); + vector<TFloat> signalRes(len); + GenerateSignalWithTransient(signal.data(), signal.size(), 0.03125, 512.0, + 640, 64, 32768.0); + const std::vector<TAtrac3Data::SubbandInfo::TGainPoint> curve1 = {{6, 13}, {4, 14}}; + + for (size_t pos = 0; pos < len; pos += workSz) { + vector<TFloat> specs(1024); + memcpy(buff.Band0, signal.data() + pos, workSz * sizeof(TFloat)); + + TFloat* p[4] = { buff.Band0, buff.Band1, buff.Band2, buff.Band3 }; + //for (int i = 0; i < 256; i++) { + // std::cout << i + pos << " " << buff.Band0[i] << std::endl; + //} + + if (pos == 512) { //apply gain modulation + TAtrac3Data::SubbandInfo siCur; + siCur.AddSubbandCurve(0, std::vector<TAtrac3Data::SubbandInfo::TGainPoint>(curve1)); + + for (int i = 0; i < 256; i++) { + std::cout << i << " " << buff.Band0[i] << std::endl; + } + + mdct.Mdct(specs.data(), p, { mdct.GainProcessor.Modulate(siCur.GetGainPoints(0)), + TAtrac3MDCT::TGainModulator(), TAtrac3MDCT::TGainModulator(), TAtrac3MDCT::TGainModulator()}); + } else { + mdct.Mdct(specs.data(), p); + } + + for (int i = 0; i < specs.size(); ++i) { + if (i > 240 && i < 256) + specs[i] /= 1.9; + } + TFloat* t[4] = { buff.Band0Res, buff.Band1Res, buff.Band2Res, buff.Band3Res }; + if (pos == 512) { //restore gain modulation + TAtrac3Data::SubbandInfo siCur; + TAtrac3Data::SubbandInfo siNext; + siNext.AddSubbandCurve(0, std::vector<TAtrac3Data::SubbandInfo::TGainPoint>(curve1)); + mdct.Midct(specs.data(), t, {mdct.GainProcessor.Demodulate(siCur.GetGainPoints(0), siNext.GetGainPoints(0)), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator()}); + } else if (pos == 768) { + TAtrac3Data::SubbandInfo siNext; + TAtrac3Data::SubbandInfo siCur; + siCur.AddSubbandCurve(0, std::vector<TAtrac3Data::SubbandInfo::TGainPoint>(curve1)); + + mdct.Midct(specs.data(), t, {mdct.GainProcessor.Demodulate(siCur.GetGainPoints(0), siNext.GetGainPoints(0)), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator(), + TAtrac3MDCT::TAtrac3GainProcessor::TGainDemodulator()}); + } else { + mdct.Midct(specs.data(), t); + } + + memcpy(signalRes.data() + pos, buff.Band0Res, workSz * sizeof(TFloat)); + } + for (int i = workSz; i < len; ++i) { + //std::cout << "res: " << i << " " << signalRes[i] << std::endl; + EXPECT_NEAR(signal[i - workSz], signalRes[i], 10); + } +} + +TEST(TAtrac3MDCT, TAtrac3MDCTWindow) { + TWindowTest test; + test.RunTest(); +} + + |