aboutsummaryrefslogtreecommitdiffstats
path: root/src/atrac3denc.cpp
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2024-12-24 22:59:03 +0100
committerDaniil Cherednik <dan.cherednik@gmail.com>2024-12-24 22:59:03 +0100
commitbddbeb98b3db8d435de6b2d10269640121475538 (patch)
tree1a791f5dd49b94ead503b9b77c6b9277f2701a89 /src/atrac3denc.cpp
parentc73a0e24a0d5c510a65efbe5c2fbc7fd39a3c003 (diff)
parent74d6e04c21bddd435bd74c34dbe027b883772a76 (diff)
downloadatracdenc-bddbeb98b3db8d435de6b2d10269640121475538.tar.gz
Merge branch 'master' into at3plus-dev
Diffstat (limited to 'src/atrac3denc.cpp')
-rw-r--r--src/atrac3denc.cpp130
1 files changed, 79 insertions, 51 deletions
diff --git a/src/atrac3denc.cpp b/src/atrac3denc.cpp
index b1f81d1..56e6517 100644
--- a/src/atrac3denc.cpp
+++ b/src/atrac3denc.cpp
@@ -18,6 +18,7 @@
#include "atrac3denc.h"
#include "transient_detector.h"
+#include "atrac/atrac_psy_common.h"
#include <assert.h>
#include <algorithm>
#include <iostream>
@@ -28,26 +29,26 @@ using namespace NMDCT;
using namespace NAtrac3;
using std::vector;
-void TAtrac3MDCT::Mdct(TFloat specs[1024], TFloat* bands[4], TFloat maxLevels[4], TGainModulatorArray gainModulators)
+void TAtrac3MDCT::Mdct(float specs[1024], float* bands[4], float maxLevels[4], TGainModulatorArray gainModulators)
{
for (int band = 0; band < 4; ++band) {
- TFloat* srcBuff = bands[band];
- TFloat* const curSpec = &specs[band*256];
+ float* srcBuff = bands[band];
+ float* const curSpec = &specs[band*256];
TGainModulator modFn = gainModulators[band];
- TFloat tmp[512];
- memcpy(&tmp[0], srcBuff, 256 * sizeof(TFloat));
+ float tmp[512];
+ memcpy(&tmp[0], srcBuff, 256 * sizeof(float));
if (modFn) {
modFn(&tmp[0], &srcBuff[256]);
}
- TFloat max = 0.0;
+ float max = 0.0;
for (int i = 0; i < 256; i++) {
max = std::max(max, std::abs(srcBuff[256+i]));
srcBuff[i] = TAtrac3Data::EncodeWindow[i] * srcBuff[256+i];
tmp[256+i] = TAtrac3Data::EncodeWindow[255-i] * srcBuff[256+i];
}
- const vector<TFloat>& sp = Mdct512(&tmp[0]);
+ const vector<float>& sp = Mdct512(&tmp[0]);
assert(sp.size() == 256);
- memcpy(curSpec, sp.data(), 256 * sizeof(TFloat));
+ memcpy(curSpec, sp.data(), 256 * sizeof(float));
if (band & 1) {
SwapArray(curSpec, 256);
}
@@ -55,27 +56,27 @@ void TAtrac3MDCT::Mdct(TFloat specs[1024], TFloat* bands[4], TFloat maxLevels[4]
}
}
-void TAtrac3MDCT::Mdct(TFloat specs[1024], TFloat* bands[4], TGainModulatorArray gainModulators)
+void TAtrac3MDCT::Mdct(float specs[1024], float* bands[4], TGainModulatorArray gainModulators)
{
- static TFloat dummy[4];
+ static float dummy[4];
Mdct(specs, bands, dummy, gainModulators);
}
-void TAtrac3MDCT::Midct(TFloat specs[1024], TFloat* bands[4], TGainDemodulatorArray gainDemodulators)
+void TAtrac3MDCT::Midct(float specs[1024], float* bands[4], TGainDemodulatorArray gainDemodulators)
{
for (int band = 0; band < 4; ++band) {
- TFloat* dstBuff = bands[band];
- TFloat* curSpec = &specs[band*256];
- TFloat* prevBuff = dstBuff + 256;
+ float* dstBuff = bands[band];
+ float* curSpec = &specs[band*256];
+ float* prevBuff = dstBuff + 256;
TAtrac3GainProcessor::TGainDemodulator demodFn = gainDemodulators[band];
if (band & 1) {
SwapArray(curSpec, 256);
}
- vector<TFloat> inv = Midct512(curSpec);
+ vector<float> inv = Midct512(curSpec);
assert(inv.size()/2 == 256);
for (int j = 0; j < 256; ++j) {
- inv[j] *= /*2 */ DecodeWindow[j];
- inv[511 - j] *= /*2*/ DecodeWindow[j];
+ inv[j] *= /*2 */ TAtrac3Data::DecodeWindow[j];
+ inv[511 - j] *= /*2*/ TAtrac3Data::DecodeWindow[j];
}
if (demodFn) {
demodFn(dstBuff, inv.data(), prevBuff);
@@ -84,13 +85,14 @@ void TAtrac3MDCT::Midct(TFloat specs[1024], TFloat* bands[4], TGainDemodulatorAr
dstBuff[j] = inv[j] + prevBuff[j];
}
}
- memcpy(prevBuff, &inv[256], sizeof(TFloat)*256);
+ memcpy(prevBuff, &inv[256], sizeof(float)*256);
}
}
TAtrac3Encoder::TAtrac3Encoder(TCompressedOutputPtr&& oma, TAtrac3EncoderSettings&& encoderSettings)
: Oma(std::move(oma))
, Params(std::move(encoderSettings))
+ , LoudnessCurve(CreateLoudnessCurve(TAtrac3Data::NumSamples))
, SingleChannelElements(Params.SourceChannels)
, TransientParamsHistory(Params.SourceChannels, std::vector<TTransientParam>(4))
{}
@@ -128,9 +130,9 @@ TAtrac3MDCT::TGainModulatorArray TAtrac3MDCT::MakeGainModulatorArray(const TAtra
}
}
-TFloat TAtrac3Encoder::LimitRel(TFloat x)
+float TAtrac3Encoder::LimitRel(float x)
{
- return std::min(std::max((double)x, GainLevel[15]), GainLevel[0]);
+ return std::min(std::max(x, TAtrac3Data::GainLevel[15]), TAtrac3Data::GainLevel[0]);
}
void TAtrac3Encoder::ResetTransientParamsHistory(int channel, int band)
@@ -148,18 +150,18 @@ const TAtrac3Encoder::TTransientParam& TAtrac3Encoder::GetTransientParamsHistory
return TransientParamsHistory[channel][band];
}
-TAtrac3Encoder::TTransientParam TAtrac3Encoder::CalcTransientParam(const std::vector<TFloat>& gain, const TFloat lastMax)
+TAtrac3Encoder::TTransientParam TAtrac3Encoder::CalcTransientParam(const std::vector<float>& gain, const float lastMax)
{
int32_t attack0Location = -1; // position where gain is risen up, -1 - no attack
- TFloat attack0Relation = 1;
+ float attack0Relation = 1;
- const TFloat attackThreshold = 2;
+ const float attackThreshold = 2;
{
// pre-echo searching
// relative to previous half frame
for (uint32_t i = 0; i < gain.size(); i++) {
- const TFloat tmp = gain[i] / lastMax;
+ const float tmp = gain[i] / lastMax;
if (tmp > attackThreshold) {
attack0Relation = tmp;
attack0Location = i;
@@ -169,13 +171,13 @@ TAtrac3Encoder::TTransientParam TAtrac3Encoder::CalcTransientParam(const std::ve
}
int32_t attack1Location = -1;
- TFloat attack1Relation = 1;
+ float attack1Relation = 1;
{
// pre-echo searching
// relative to previous subsamples block
- TFloat q = gain[0];
+ float q = gain[0];
for (uint32_t i = 1; i < gain.size(); i++) {
- const TFloat tmp = gain[i] / q;
+ const float tmp = gain[i] / q;
if (tmp > attackThreshold) {
attack1Relation = tmp;
attack1Location = i;
@@ -185,15 +187,15 @@ TAtrac3Encoder::TTransientParam TAtrac3Encoder::CalcTransientParam(const std::ve
}
int32_t releaseLocation = -1; // position where gain is fallen down, -1 - no release
- TFloat releaseRelation = 1;
+ float releaseRelation = 1;
- const TFloat releaseTreshold = 2;
+ const float releaseTreshold = 2;
{
// post-echo searching
// relative to current frame
- TFloat q = gain.back();
+ float q = gain.back();
for (uint32_t i = gain.size() - 2; i > 0; --i) {
- const TFloat tmp = gain[i] / q;
+ const float tmp = gain[i] / q;
if (tmp > releaseTreshold) {
releaseRelation = tmp;
releaseLocation = i;
@@ -206,24 +208,24 @@ TAtrac3Encoder::TTransientParam TAtrac3Encoder::CalcTransientParam(const std::ve
return {attack0Location, attack0Relation, attack1Location, attack1Relation, releaseLocation, releaseRelation};
}
-void TAtrac3Encoder::CreateSubbandInfo(TFloat* in[4],
+void TAtrac3Encoder::CreateSubbandInfo(float* in[4],
uint32_t channel,
TAtrac3Data::SubbandInfo* subbandInfo)
{
- auto relToIdx = [](TFloat rel) {
+ auto relToIdx = [](float rel) {
rel = 1.0/rel;
return (uint32_t)(RelationToIdx(rel));
};
for (int band = 0; band < 4; ++band) {
- const TFloat* srcBuff = in[band];
+ const float* srcBuff = in[band];
- const TFloat* const lastMax = &PrevPeak[channel][band];
+ const float* const lastMax = &PrevPeak[channel][band];
std::vector<TAtrac3Data::SubbandInfo::TGainPoint> curve;
- const std::vector<TFloat> gain = AnalyzeGain(srcBuff, 256, 32, false);
+ const std::vector<float> gain = AnalyzeGain(srcBuff, 256, 32, false);
auto transientParam = CalcTransientParam(gain, *lastMax);
bool hasTransient = false;
@@ -275,8 +277,8 @@ void TAtrac3Encoder::CreateSubbandInfo(TFloat* in[4],
void TAtrac3Encoder::Matrixing()
{
for (uint32_t subband = 0; subband < 4; subband++) {
- TFloat* pair[2] = {PcmBuffer.GetSecond(subband * 2), PcmBuffer.GetSecond(subband * 2 + 1)};
- TFloat tmp[2];
+ float* pair[2] = {PcmBuffer.GetSecond(subband * 2), PcmBuffer.GetSecond(subband * 2 + 1)};
+ float tmp[2];
for (uint32_t sample = 0; sample < 256; sample++) {
tmp[0] = pair[0][sample];
tmp[1] = pair[1][sample];
@@ -286,21 +288,33 @@ void TAtrac3Encoder::Matrixing()
}
}
-TPCMEngine<TFloat>::TProcessLambda TAtrac3Encoder::GetLambda()
+TPCMEngine::TProcessLambda TAtrac3Encoder::GetLambda()
{
std::shared_ptr<TAtrac3BitStreamWriter> bitStreamWriter(new TAtrac3BitStreamWriter(Oma.get(), *Params.ConteinerParams, Params.BfuIdxConst));
- return [this, bitStreamWriter](TFloat* data, const TPCMEngine<TFloat>::ProcessMeta& meta) {
+
+ struct TChannelData {
+ TChannelData()
+ : Specs(TAtrac3Data::NumSamples)
+ {}
+
+ vector<float> Specs;
+ };
+
+ using TData = vector<TChannelData>;
+ auto buf = std::make_shared<TData>(2);
+
+ return [this, bitStreamWriter, buf](float* data, const TPCMEngine::ProcessMeta& meta) {
using TSce = TAtrac3BitStreamWriter::TSingleChannelElement;
for (uint32_t channel = 0; channel < meta.Channels; channel++) {
- TFloat src[NumSamples];
+ float src[TAtrac3Data::NumSamples];
- for (size_t i = 0; i < NumSamples; ++i) {
+ for (size_t i = 0; i < TAtrac3Data::NumSamples; ++i) {
src[i] = data[i * meta.Channels + channel] / 4.0;
}
{
- TFloat* p[4] = {PcmBuffer.GetSecond(channel), PcmBuffer.GetSecond(channel+2), PcmBuffer.GetSecond(channel+4), PcmBuffer.GetSecond(channel+6)};
+ float* p[4] = {PcmBuffer.GetSecond(channel), PcmBuffer.GetSecond(channel+2), PcmBuffer.GetSecond(channel+4), PcmBuffer.GetSecond(channel+6)};
AnalysisFilterBank[channel].Analysis(&src[0], p);
}
}
@@ -310,27 +324,42 @@ TPCMEngine<TFloat>::TProcessLambda TAtrac3Encoder::GetLambda()
}
for (uint32_t channel = 0; channel < meta.Channels; channel++) {
- vector<TFloat> specs(1024);
+ auto& specs = (*buf)[channel].Specs;
TSce* sce = &SingleChannelElements[channel];
sce->SubbandInfo.Reset();
if (!Params.NoGainControll) {
- TFloat* p[4] = {PcmBuffer.GetSecond(channel), PcmBuffer.GetSecond(channel+2), PcmBuffer.GetSecond(channel+4), PcmBuffer.GetSecond(channel+6)};
+ float* p[4] = {PcmBuffer.GetSecond(channel), PcmBuffer.GetSecond(channel+2), PcmBuffer.GetSecond(channel+4), PcmBuffer.GetSecond(channel+6)};
CreateSubbandInfo(p, channel, &sce->SubbandInfo); //4 detectors per band
}
- TFloat* maxOverlapLevels = PrevPeak[channel];
+ float* maxOverlapLevels = PrevPeak[channel];
{
- TFloat* p[4] = {PcmBuffer.GetFirst(channel), PcmBuffer.GetFirst(channel+2), PcmBuffer.GetFirst(channel+4), PcmBuffer.GetFirst(channel+6)};
+ float* p[4] = {PcmBuffer.GetFirst(channel), PcmBuffer.GetFirst(channel+2), PcmBuffer.GetFirst(channel+4), PcmBuffer.GetFirst(channel+6)};
Mdct(specs.data(), p, maxOverlapLevels, MakeGainModulatorArray(sce->SubbandInfo));
}
- sce->Energy = CalcEnergy(specs);
+ float l = 0;
+ for (size_t i = 0; i < specs.size(); i++) {
+ float e = specs[i] * specs[i];
+ l += e * LoudnessCurve[i];
+ }
+
+ sce->Loudness = l;
//TBlockSize for ATRAC3 - 4 subband, all are long (no short window)
sce->ScaledBlocks = Scaler.ScaleFrame(specs, TBlockSize());
+ }
+ if (meta.Channels == 2 && !Params.ConteinerParams->Js) {
+ const TSce& sce0 = SingleChannelElements[0];
+ const TSce& sce1 = SingleChannelElements[1];
+ Loudness = TrackLoudness(Loudness, sce0.Loudness, sce1.Loudness);
+ } else {
+ // 1 channel or Js. In case of Js we do not use side channel to adjust loudness
+ const TSce& sce0 = SingleChannelElements[0];
+ Loudness = TrackLoudness(Loudness, sce0.Loudness);
}
if (Params.ConteinerParams->Js && meta.Channels == 1) {
@@ -341,9 +370,8 @@ TPCMEngine<TFloat>::TProcessLambda TAtrac3Encoder::GetLambda()
SingleChannelElements[1].SubbandInfo.Info.resize(1);
}
- bitStreamWriter->WriteSoundUnit(SingleChannelElements);
-
- return TPCMEngine<TFloat>::EProcessResult::PROCESSED;
+ bitStreamWriter->WriteSoundUnit(SingleChannelElements, Loudness);
+ return TPCMEngine::EProcessResult::PROCESSED;
};
}