aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2025-06-09 23:19:20 +0200
committerDaniil Cherednik <dan.cherednik@gmail.com>2025-06-13 22:49:47 +0200
commit8b399993d5d6a9b7ef682027c8c15538ab88a156 (patch)
treeaab3fccefd78a66953d96447f2fc8b19bb86e9cf
parent42aa1bfdd430ac39c8fdb76363d2868238d40853 (diff)
downloadatracdenc-master.tar.gz
[AT3P] MDCT window shape configuration code.HEADmaster
And pass window shape in to the bitstream.
-rw-r--r--src/atrac/at3p/at3p.cpp11
-rw-r--r--src/atrac/at3p/at3p_bitstream.cpp25
-rw-r--r--src/atrac/at3p/at3p_bitstream.h10
-rw-r--r--src/atrac/at3p/at3p_bitstream_impl.h11
-rw-r--r--src/atrac/at3p/at3p_bitstream_ut.cpp6
-rw-r--r--src/atrac/at3p/at3p_mdct.cpp82
-rw-r--r--src/atrac/at3p/at3p_mdct.h50
-rw-r--r--src/atrac/at3p/at3p_mdct_ut.cpp30
8 files changed, 178 insertions, 47 deletions
diff --git a/src/atrac/at3p/at3p.cpp b/src/atrac/at3p/at3p.cpp
index c48c21c..0cdcdd3 100644
--- a/src/atrac/at3p/at3p.cpp
+++ b/src/atrac/at3p/at3p.cpp
@@ -117,7 +117,8 @@ EncodeFrame(const float* data, int channels)
const TAt3PGhaData* tonalBlock = GhaProcessor->DoAnalize({b1Cur, b1Next}, {b2Cur, b2Next}, b1Prev, b2Prev);
- std::vector<std::vector<TScaledBlock>> scaledBlocks;
+ std::vector<TAt3PBitStream::TSingleChannelElement> sces;
+ sces.resize(channels);
for (int ch = 0; ch < channels; ch++) {
float* x = (ch == 0) ? b1Prev : b2Prev;
auto& c = ChannelCtx[ch];
@@ -137,13 +138,13 @@ EncodeFrame(const float* data, int channels)
for (size_t b = 0; b < 16; b++) {
p[b] = tmp + b * 128;
}
- Mdct.Do(c.Specs.data(), p, c.MdctBuf);
- const auto& block = Scaler.ScaleFrame(c.Specs, NAt3p::TScaleTable::TBlockSizeMod());
- scaledBlocks.push_back(block);
+ Mdct.Do(c.Specs.data(), p, c.MdctBuf, sces[ch].SubbandInfo.Win);
+
+ sces[ch].ScaledBlocks = Scaler.ScaleFrame(c.Specs, NAt3p::TScaleTable::TBlockSizeMod());
}
- BitStream.WriteFrame(channels, p, scaledBlocks);
+ BitStream.WriteFrame(channels, p, sces);
for (int ch = 0; ch < channels; ch++) {
if (Settings.UseGha & TSettings::GHA_PASS_INPUT) {
diff --git a/src/atrac/at3p/at3p_bitstream.cpp b/src/atrac/at3p/at3p_bitstream.cpp
index 40e860f..2d48729 100644
--- a/src/atrac/at3p/at3p_bitstream.cpp
+++ b/src/atrac/at3p/at3p_bitstream.cpp
@@ -118,9 +118,9 @@ IBitStreamPartEncoder::EStatus TConfigure::Encode(void* frameData, TBitAllocHand
frame->SfIdx.resize(frame->NumQuantUnits);
for (size_t i = 0; i < frame->SfIdx.size(); i++) {
- frame->SfIdx[i].first = frame->Chs[0].ScaledBlocks.at(i).ScaleFactorIndex;
+ frame->SfIdx[i].first = frame->Chs[0].Sce.ScaledBlocks.at(i).ScaleFactorIndex;
if (frame->Chs.size() > 1)
- frame->SfIdx[i].second = frame->Chs[1].ScaledBlocks.at(i).ScaleFactorIndex;
+ frame->SfIdx[i].second = frame->Chs[1].Sce.ScaledBlocks.at(i).ScaleFactorIndex;
}
frame->SpecTabIdx.resize(frame->NumQuantUnits);
@@ -407,7 +407,7 @@ IBitStreamPartEncoder::EStatus TQuantUnitsEncoder::Encode(void* frameData, TBitA
std::vector<std::pair<uint16_t, uint8_t>>> data;
for (size_t ch = 0; ch < specFrame->Chs.size(); ch++) {
auto& chData = specFrame->Chs.at(ch);
- auto scaledBlocks = chData.ScaledBlocks;
+ auto scaledBlocks = chData.Sce.ScaledBlocks;
for (size_t qu = 0; qu < specFrame->NumQuantUnits; qu++) {
size_t len = (ch == 0) ?
@@ -664,7 +664,20 @@ IBitStreamPartEncoder::EStatus TTonalComponentEncoder::Encode(void* frameData, T
}
for (size_t ch = 0; ch < chNum; ch++) {
- Insert(0, 1); // window shape
+ TAt3pMDCTWin winType = specFrame->Chs[ch].Sce.SubbandInfo.Win;
+ uint8_t sbNum = atrac3p_qu_to_subband[specFrame->NumQuantUnits - 1] + 1;
+ if (winType.IsAllSine()) {
+ Insert(0, 1);
+ } else if (winType.IsAllSteep(sbNum)) {
+ Insert(1, 1);
+ Insert(0, 1);
+ } else {
+ Insert(1, 1);
+ Insert(1, 1);
+ for (size_t i = 0; i < sbNum; i++) {
+ Insert(winType.IsSbSteep(i), 1);
+ }
+ }
}
for (size_t ch = 0; ch < chNum; ch++) {
@@ -687,7 +700,7 @@ IBitStreamPartEncoder::EStatus TTonalComponentEncoder::Encode(void* frameData, T
return CheckFrameDone(specFrame, ba);
}
-void TAt3PBitStream::WriteFrame(int channels, const TAt3PGhaData* tonalBlock, const std::vector<std::vector<TScaledBlock>>& scaledBlocks)
+void TAt3PBitStream::WriteFrame(int channels, const TAt3PGhaData* tonalBlock, const std::vector<TSingleChannelElement>& sces)
{
NBitStream::TBitStream bitStream;
// First bit must be zero
@@ -700,7 +713,7 @@ void TAt3PBitStream::WriteFrame(int channels, const TAt3PGhaData* tonalBlock, co
const uint32_t initialNumQuantUnits = 32;
- TSpecFrame frame(FrameSzToAllocBits, initialNumQuantUnits, channels, tonalBlock, scaledBlocks);
+ TSpecFrame frame(FrameSzToAllocBits, initialNumQuantUnits, channels, tonalBlock, sces);
Encoder.Do(&frame, bitStream);
diff --git a/src/atrac/at3p/at3p_bitstream.h b/src/atrac/at3p/at3p_bitstream.h
index 25edd1e..5f3ae46 100644
--- a/src/atrac/at3p/at3p_bitstream.h
+++ b/src/atrac/at3p/at3p_bitstream.h
@@ -20,6 +20,7 @@
#include "compressed_io.h"
#include "at3p_gha.h"
+#include "at3p_mdct.h"
#include <lib/bs_encode/encode.h>
namespace NAtracDEnc {
@@ -47,8 +48,15 @@ TTonePackResult CreateFreqBitPack(const TAt3PGhaData::TWaveParam* param, int len
class TAt3PBitStream {
public:
+ struct TSubbandInfos {
+ TAt3pMDCTWin Win;
+ };
+ struct TSingleChannelElement {
+ TSubbandInfos SubbandInfo;
+ std::vector<TScaledBlock> ScaledBlocks;
+ };
TAt3PBitStream(ICompressedOutput* container, uint16_t frameSz);
- void WriteFrame(int channels, const TAt3PGhaData* tonalData, const std::vector<std::vector<TScaledBlock>>& scaledBlocks);
+ void WriteFrame(int channels, const TAt3PGhaData* tonalData, const std::vector<TSingleChannelElement>& scaledBlocks);
private:
ICompressedOutput* Container;
TBitStreamEncoder Encoder;
diff --git a/src/atrac/at3p/at3p_bitstream_impl.h b/src/atrac/at3p/at3p_bitstream_impl.h
index 32316f2..5e0fded 100644
--- a/src/atrac/at3p/at3p_bitstream_impl.h
+++ b/src/atrac/at3p/at3p_bitstream_impl.h
@@ -19,6 +19,7 @@
*/
#include "atrac/at3p/at3p_gha.h"
+#include "at3p_bitstream.h"
#include <lib/bitstream/bitstream.h>
#include <lib/bs_encode/encode.h>
#include <atrac/atrac_scale.h>
@@ -33,7 +34,7 @@ struct TVlcElement;
struct TSpecFrame {
TSpecFrame(uint32_t sz, uint32_t numQuantUnits, size_t channels,
const TAt3PGhaData* tonalBlock,
- const std::vector<std::vector<TScaledBlock>>& scaledBlocks)
+ const std::vector<TAt3PBitStream::TSingleChannelElement>& sces)
: SizeBits(sz)
, NumQuantUnits(numQuantUnits)
, TonalBlock(tonalBlock)
@@ -41,7 +42,7 @@ struct TSpecFrame {
{
Chs.reserve(channels);
for (size_t i = 0; i < channels; i++) {
- Chs.emplace_back(TChannel(scaledBlocks[i]));
+ Chs.emplace_back(TChannel(sces[i]));
}
}
@@ -53,10 +54,10 @@ struct TSpecFrame {
std::vector<std::pair<uint8_t, uint8_t>> SpecTabIdx;
struct TChannel {
- TChannel(const std::vector<TScaledBlock>& scaledBlock)
- : ScaledBlocks(scaledBlock)
+ TChannel(const TAt3PBitStream::TSingleChannelElement& sce)
+ : Sce(sce)
{}
- const std::vector<TScaledBlock>& ScaledBlocks;
+ const TAt3PBitStream::TSingleChannelElement& Sce;
};
std::vector<TChannel> Chs;
diff --git a/src/atrac/at3p/at3p_bitstream_ut.cpp b/src/atrac/at3p/at3p_bitstream_ut.cpp
index 92feb17..0b70297 100644
--- a/src/atrac/at3p/at3p_bitstream_ut.cpp
+++ b/src/atrac/at3p/at3p_bitstream_ut.cpp
@@ -125,10 +125,10 @@ TEST(AT3PBitstream, Wordlen) {
NBitStream::TBitStream bs;
TBitStreamEncoder encoder(std::move(encoders));
- std::vector<std::vector<TScaledBlock>> scaledBlocks;
- scaledBlocks.resize(2);
+ std::vector<TAt3PBitStream::TSingleChannelElement> sce;
+ sce.resize(2);
- TSpecFrame frame(444, 28, 2, nullptr, scaledBlocks);
+ TSpecFrame frame(444, 28, 2, nullptr, sce);
FillFrameData(frame);
diff --git a/src/atrac/at3p/at3p_mdct.cpp b/src/atrac/at3p/at3p_mdct.cpp
index b92e87b..0836463 100644
--- a/src/atrac/at3p/at3p_mdct.cpp
+++ b/src/atrac/at3p/at3p_mdct.cpp
@@ -28,12 +28,18 @@ using std::vector;
namespace NAtracDEnc {
-static std::array<float, 128> SineWin;
+static std::array<float, 128> SineWin128;
+static std::array<float, 64> SineWin64;
static void InitSineWin() {
- if (SineWin[SineWin.size() - 1] == 0.0) {
- for (size_t i = 0; i < SineWin.size(); i++) {
- SineWin[i] = 2.0 * sinf((i + 0.5) * (M_PI / (2.0 * SineWin.size())));
+ if (SineWin128[SineWin128.size() - 1] == 0.0) {
+ for (size_t i = 0; i < SineWin128.size(); i++) {
+ SineWin128[i] = 2.0 * sinf((i + 0.5) * (M_PI / (2.0 * SineWin128.size())));
+ }
+ }
+ if (SineWin64[SineWin64.size() - 1] == 0.0) {
+ for (size_t i = 0; i < SineWin64.size(); i++) {
+ SineWin64[i] = 2.0 * sinf((i + 0.5) * (M_PI / (2.0 * SineWin64.size())));
}
}
}
@@ -43,16 +49,26 @@ TAt3pMDCT::TAt3pMDCT()
InitSineWin();
}
-void TAt3pMDCT::Do(float specs[2048], const TPcmBandsData& bands, THistBuf& work)
+void TAt3pMDCT::Do(float specs[2048], const TPcmBandsData& bands, THistBuf& work, TAt3pMDCTWin winType)
{
- for (size_t b = 0; b < 16; b++) {
+ for (size_t b = 0, flag = 1; b < 16; b++, flag <<= 1) {
const float* srcBuff = bands[b];
float* const curSpec = &specs[b*128];
std::array<float, 256>& tmp = work[b];
- for (size_t i = 0; i < 128; i++) {
- tmp[128 + i] = SineWin[127 - i] * srcBuff[i];
+ if (winType.Flags & flag) {
+ for (size_t i = 0; i < 64; i++) {
+ tmp[128 + i] = srcBuff[i] * 2.0;
+ }
+ for (size_t i = 0; i < 64; i++) {
+ tmp[160 + i] = SineWin64[63 - i] * srcBuff[32 + i];
+ }
+ memset(&tmp[224], 0, sizeof(float) * 32);
+ } else {
+ for (size_t i = 0; i < 128; i++) {
+ tmp[128 + i] = SineWin128[127 - i] * srcBuff[i];
+ }
}
const vector<float>& sp = Mdct(tmp.data());
@@ -63,8 +79,18 @@ void TAt3pMDCT::Do(float specs[2048], const TPcmBandsData& bands, THistBuf& work
SwapArray(curSpec, 128);
}
- for (size_t i = 0; i < 128; i++) {
- tmp[i] = SineWin[i] * srcBuff[i];
+ if (winType.Flags & flag) {
+ memset(&tmp[0], 0, sizeof(float) * 32);
+ for (size_t i = 0; i < 64; i++) {
+ tmp[i + 32] = SineWin64[i] * srcBuff[i + 32];
+ }
+ for (size_t i = 0; i < 32; i++) {
+ tmp[i + 96] = srcBuff[i + 96] * 2.0;
+ }
+ } else {
+ for (size_t i = 0; i < 128; i++) {
+ tmp[i] = SineWin128[i] * srcBuff[i];
+ }
}
}
}
@@ -74,13 +100,13 @@ TAt3pMIDCT::TAt3pMIDCT()
InitSineWin();
}
-void TAt3pMIDCT::Do(float specs[2048], TPcmBandsData& bands, THistBuf& work)
+void TAt3pMIDCT::Do(float specs[2048], TPcmBandsData& bands, THistBuf& work, TAt3pMDCTWin winType)
{
- for (size_t b = 0; b < 16; b++) {
+ for (size_t b = 0, flag = 1; b < 16; b++, flag <<= 1) {
float* dstBuff = bands[b];
float* const curSpec = &specs[b*128];
- std::array<float, 128>& tmp = work[b];
+ std::array<float, 128>& tmp = work.Buf[b];
if (b & 1) {
SwapArray(curSpec, 128);
@@ -88,9 +114,32 @@ void TAt3pMIDCT::Do(float specs[2048], TPcmBandsData& bands, THistBuf& work)
vector<float> inv = Midct(curSpec);
- for (int j = 0; j < 128; ++j) {
- inv[j] *= SineWin[j];
- inv[255 - j] *= SineWin[j];
+ if (work.Win.Flags & flag) {
+ memset(&inv[0], 0, sizeof(float) * 32);
+ for (size_t j = 0; j < 64; ++j) {
+ inv[j + 32] *= SineWin64[j];
+ }
+ for (size_t j = 96; j < 128; j++) {
+ inv[j] *= 2.0;
+ }
+ } else {
+ for (size_t j = 0; j < 128; ++j) {
+ inv[j] *= SineWin128[j];
+ }
+ }
+
+ if (winType.Flags & flag) {
+ for (size_t j = 128; j < 160; ++j) {
+ inv[j] *= 2.0;
+ }
+ for (size_t j = 0; j < 64; ++j) {
+ inv[223 - j] *= SineWin64[j];
+ }
+ memset(&inv[224], 0, sizeof(float) * 32);
+ } else {
+ for (size_t j = 0; j < 128; ++j) {
+ inv[255 - j] *= SineWin128[j];
+ }
}
for (uint32_t j = 0; j < 128; ++j) {
@@ -99,6 +148,7 @@ void TAt3pMIDCT::Do(float specs[2048], TPcmBandsData& bands, THistBuf& work)
memcpy(tmp.data(), &inv[128], sizeof(float)*128);
}
+ work.Win = winType;
}
};
diff --git a/src/atrac/at3p/at3p_mdct.h b/src/atrac/at3p/at3p_mdct.h
index de67245..c547fec 100644
--- a/src/atrac/at3p/at3p_mdct.h
+++ b/src/atrac/at3p/at3p_mdct.h
@@ -19,19 +19,60 @@
#pragma once
#include <array>
+#include <cstdint>
#include <config.h>
#include "lib/mdct/mdct.h"
namespace NAtracDEnc {
+class TAt3pMDCT;
+class TAt3pMIDCT;
+
+class TAt3pMDCTWin {
+ friend class TAt3pMDCT;
+ friend class TAt3pMIDCT;
+public:
+ enum EWinType {
+ SINE = 0,
+ STEEP = 1,
+ };
+
+ TAt3pMDCTWin() noexcept
+ : Flags(0)
+ {}
+
+ TAt3pMDCTWin(EWinType win) noexcept
+ : Flags(win == STEEP ? (uint16_t)-1 : 0)
+ {}
+
+ void SetSteepWin(size_t sb) noexcept {
+ Flags |= (1 << sb);
+ }
+
+ bool IsAllSine() const noexcept {
+ return Flags == 0;
+ }
+
+ bool IsAllSteep(uint8_t sbNum) const noexcept {
+ uint8_t mask = (1 << sbNum) - 1;
+ return (Flags & mask) == mask;
+ }
+
+ bool IsSbSteep(uint8_t sb) const noexcept {
+ return Flags & (1 << sb);
+ }
+private:
+ uint16_t Flags;
+};
+
class TAt3pMDCT {
public:
TAt3pMDCT();
using THistBuf = std::array<std::array<float, 256>, 16>;
using TPcmBandsData = std::array<const float*, 16>;
- void Do(float specs[2048], const TPcmBandsData& bands, THistBuf& work);
+ void Do(float specs[2048], const TPcmBandsData& bands, THistBuf& work, TAt3pMDCTWin winType);
private:
NMDCT::TMDCT<256> Mdct;
};
@@ -39,10 +80,13 @@ private:
class TAt3pMIDCT {
public:
TAt3pMIDCT();
- using THistBuf = std::array<std::array<float, 128>, 16>;
+ struct THistBuf {
+ std::array<std::array<float, 128>, 16> Buf;
+ TAt3pMDCTWin Win;
+ };
using TPcmBandsData = std::array<float*, 16>;
- void Do(float specs[2048], TPcmBandsData& bands, THistBuf& work);
+ void Do(float specs[2048], TPcmBandsData& bands, THistBuf& work, TAt3pMDCTWin winType);
private:
NMDCT::TMIDCT<256> Midct;
};
diff --git a/src/atrac/at3p/at3p_mdct_ut.cpp b/src/atrac/at3p/at3p_mdct_ut.cpp
index c74eb47..a405927 100644
--- a/src/atrac/at3p/at3p_mdct_ut.cpp
+++ b/src/atrac/at3p/at3p_mdct_ut.cpp
@@ -38,7 +38,7 @@ TEST(TAtpMDCT, ZeroOneBlock) {
pcm[i] = &zero[i * 128];
}
- mdct.Do(specs.data(), pcm, buff);
+ mdct.Do(specs.data(), pcm, buff, TAt3pMDCTWin::SINE);
for(auto s: specs)
EXPECT_NEAR(s, 0.0, 0.0000000001);
@@ -53,15 +53,14 @@ TEST(TAtpMDCT, ZeroOneBlock) {
pcm[i] = &zero[i * 128];
}
- midct.Do(specs.data(), pcm, buff);
+ midct.Do(specs.data(), pcm, buff, TAt3pMDCTWin::SINE);
for(size_t i = 0; i < zero.size(); ++i)
EXPECT_NEAR(zero[i], 0.0, 0.0000000001);
}
}
-
-TEST(TAtpMDCT, DC) {
+static void DoAt3pMDCTDcTest(TAt3pMDCTWin first, TAt3pMDCTWin second) {
std::array<float, 4096> specs;
std::array<float, 2048> dc;
@@ -79,8 +78,8 @@ TEST(TAtpMDCT, DC) {
pcm[i] = &dc[i * 128];
}
- mdct.Do(specs.data(), pcm, buff);
- mdct.Do(specs.data() + 2048, pcm, buff);
+ mdct.Do(specs.data(), pcm, buff, first);
+ mdct.Do(specs.data() + 2048, pcm, buff, second);
}
{
@@ -96,11 +95,26 @@ TEST(TAtpMDCT, DC) {
pcm[i] = &result[i * 128];
}
- midct.Do(specs.data(), pcm, buff);
- midct.Do(specs.data() + 2048, pcm, buff);
+ midct.Do(specs.data(), pcm, buff, first);
+ midct.Do(specs.data() + 2048, pcm, buff, second);
for(size_t i = 0; i < result.size(); ++i) {
EXPECT_NEAR(result[i], dc[i], 0.000001);
}
}
}
+TEST(TAtpMDCT, DCSineWin) {
+ DoAt3pMDCTDcTest(TAt3pMDCTWin::SINE, TAt3pMDCTWin::SINE);
+}
+
+TEST(TAtpMDCT, DCSteepWin) {
+ DoAt3pMDCTDcTest(TAt3pMDCTWin::STEEP, TAt3pMDCTWin::STEEP);
+}
+
+TEST(TAtpMDCT, DCSineSteepWin) {
+ DoAt3pMDCTDcTest(TAt3pMDCTWin::SINE, TAt3pMDCTWin::STEEP);
+}
+
+TEST(TAtpMDCT, DCSteepSineWin) {
+ DoAt3pMDCTDcTest(TAt3pMDCTWin::STEEP, TAt3pMDCTWin::SINE);
+}