diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2017-08-06 00:28:18 +0300 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2017-10-17 01:08:53 +0300 |
commit | 43e508b0b607054d2a720e8d9c3a11947d6f798d (patch) | |
tree | c9d70e031a21ec9dcf45ab1d18727f267724c30f /src/atrac3denc.cpp | |
parent | fcb5986d9d21d923db2480be5089168fc1d1fcd2 (diff) | |
download | atracdenc-43e508b0b607054d2a720e8d9c3a11947d6f798d.tar.gz |
Simplest gain control - scale first part of frame if the attack transient was detected
Diffstat (limited to 'src/atrac3denc.cpp')
-rw-r--r-- | src/atrac3denc.cpp | 191 |
1 files changed, 104 insertions, 87 deletions
diff --git a/src/atrac3denc.cpp b/src/atrac3denc.cpp index b5b838b..893733a 100644 --- a/src/atrac3denc.cpp +++ b/src/atrac3denc.cpp @@ -18,7 +18,6 @@ #include "atrac3denc.h" #include "transient_detector.h" -#include "util.h" #include <assert.h> #include <algorithm> #include <iostream> @@ -94,6 +93,7 @@ TAtrac3Processor::TAtrac3Processor(TCompressedIOPtr&& oma, TAtrac3EncoderSetting , Params(std::move(encoderSettings)) , TransientDetectors(2 * 4, TTransientDetector(8, 256)) //2 - channels, 4 - bands , SingleChannelElements(Params.SourceChannels) + , TransientParamsHistory(Params.SourceChannels, std::vector<TTransientParam>(4)) {} TAtrac3Processor::~TAtrac3Processor() @@ -188,54 +188,77 @@ TFloat TAtrac3Processor::LimitRel(TFloat x) return std::min(std::max(x, GainLevel[15]), GainLevel[0]); } +void TAtrac3Processor::ResetTransientParamsHistory(int channel, int band) +{ + TransientParamsHistory[channel][band] = {-1 , 1, -1, 1, -1, 1}; +} + +void TAtrac3Processor::SetTransientParamsHistory(int channel, int band, const TTransientParam& params) +{ + TransientParamsHistory[channel][band] = params; +} + +const TAtrac3Processor::TTransientParam& TAtrac3Processor::GetTransientParamsHistory(int channel, int band) const +{ + return TransientParamsHistory[channel][band]; +} + TAtrac3Processor::TTransientParam TAtrac3Processor::CalcTransientParam(const std::vector<TFloat>& gain, const TFloat lastMax) { - int32_t attackLocation = 0; - TFloat attackRelation = 1; - - const TFloat attackThreshold = 4; - //pre-echo searching - TFloat tmp; - TFloat q = lastMax; //std::max(lastMax, gain[0]); - tmp = gain[0] / q; - if (tmp > attackThreshold) { - attackRelation = tmp; - } else { - for (uint32_t i = 0; i < gain.size() -1; ++i) { - q = std::max(q, gain[i]); - tmp = gain[i+1] / q; + int32_t attack0Location = -1; // position where gain is risen up, -1 - no attack + TFloat attack0Relation = 1; + + const TFloat 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; if (tmp > attackThreshold) { - attackRelation = tmp; - attackLocation = i; + attack0Relation = tmp; + attack0Location = i; break; } + } + } + + int32_t attack1Location = -1; + TFloat attack1Relation = 1; + { + // pre-echo searching + // relative to previous subsamples block + TFloat q = gain[0]; + for (uint32_t i = 1; i < gain.size(); i++) { + const TFloat tmp = gain[i] / q; + if (tmp > attackThreshold) { + attack1Relation = tmp; + attack1Location = i; + } + q = std::max(q, gain[i]); } } - int32_t releaseLocation = 0; + int32_t releaseLocation = -1; // position where gain is fallen down, -1 - no release TFloat releaseRelation = 1; - const TFloat releaseTreshold = 4; - //post-echo searching - q = 0; - for (uint32_t i = gain.size() - 1; i > 0; --i) { - q = std::max(q, gain[i]); - tmp = gain[i-1] / q; - if (tmp > releaseTreshold) { - releaseRelation = tmp; - releaseLocation = i; - break; - } - } - if (releaseLocation == 0) { - q = std::max(q, gain[0]); - tmp = lastMax / q; - if (tmp > releaseTreshold) { - releaseRelation = tmp; + const TFloat releaseTreshold = 2; + { + // post-echo searching + // relative to current frame + TFloat q = gain.back(); + for (uint32_t i = gain.size() - 2; i > 0; --i) { + const TFloat tmp = gain[i] / q; + if (tmp > releaseTreshold) { + releaseRelation = tmp; + releaseLocation = i; + break; + } + q = std::max(q, gain[i]); } } - return {attackLocation, attackRelation, releaseLocation, releaseRelation}; + return {attack0Location, attack0Relation, attack1Location, attack1Relation, releaseLocation, releaseRelation}; } void TAtrac3Processor::CreateSubbandInfo(TFloat* in[4], @@ -243,72 +266,65 @@ void TAtrac3Processor::CreateSubbandInfo(TFloat* in[4], TTransientDetector* transientDetector, TAtrac3Data::SubbandInfo* subbandInfo) { + + auto relToIdx = [this](TFloat rel) { + rel = 1.0/rel; + return (uint32_t)(RelationToIdx(rel)); + }; + for (int band = 0; band < 4; ++band) { - TFloat invBuf[256]; - if (band & 1) { - memcpy(invBuf, in[band], 256*sizeof(TFloat)); - InvertSpectrInPlase<256>(invBuf); - } - const TFloat* srcBuff = (band & 1) ? invBuf : in[band]; + const TFloat* srcBuff = in[band]; const TFloat* const lastMax = &PrevPeak[channel][band]; std::vector<TAtrac3Data::SubbandInfo::TGainPoint> curve; - std::vector<TFloat> gain = AnalyzeGain(srcBuff, 256, 32, false); + const std::vector<TFloat> gain = AnalyzeGain(srcBuff, 256, 32, false); auto transientParam = CalcTransientParam(gain, *lastMax); - bool hasTransient = (transientParam.AttackRelation != 1.0 || transientParam.ReleaseRelation != 1.0); - - //combine attack and release - TFloat relA = 1; - TFloat relB = 1; - TFloat relC = 1; - uint32_t loc1 = 0; - uint32_t loc2 = 0; - if (transientParam.AttackLocation < transientParam.ReleaseLocation) { - //Peak like transient - relA = transientParam.AttackRelation; - loc1 = transientParam.AttackLocation; - relB = 1; - loc2 = transientParam.ReleaseLocation; - relC = transientParam.ReleaseRelation; - } else if (transientParam.AttackLocation > transientParam.ReleaseLocation) { - //Hole like transient - relA = transientParam.AttackRelation; - loc1 = transientParam.ReleaseLocation; - relB = transientParam.AttackRelation * transientParam.ReleaseRelation; - loc2 = transientParam.AttackLocation; - relC = transientParam.ReleaseRelation; - } else { - //??? - //relA = relB = relC = transientParam.AttackRelation * transientParam.ReleaseRelation; - //loc1 = loc2 = transientParam.ReleaseLocation; - hasTransient = false; - } - //std::cout << "loc: " << loc1 << " " << loc2 << " rel: " << relA << " " << relB << " " << relC << std::endl; + bool hasTransient = false; - if (relC != 1) { - relA /= relC; - relB /= relC; - relC = 1.0; + if (transientParam.Attack0Location == -1 && transientParam.Attack1Location == -1 && transientParam.ReleaseLocation == -1) { + // No transient + ResetTransientParamsHistory(channel, band); + continue; } - auto relToIdx = [this](TFloat rel) { - rel = LimitRel(1/rel); - return (uint32_t)(15 - Log2FloatToIdx(rel, 2048)); - }; - curve.push_back({relToIdx(relA), loc1}); - if (loc1 != loc2) { - curve.push_back({relToIdx(relB), loc2}); + if (transientParam.Attack0Location == -1 && transientParam.Attack1Location == -1) { + // Release only in current frame - PostEcho. Not implemented yet. + // Note: "Hole like" transient also possible (if value is grather in next frame), + // but we keep peak value of this frame, so in next frame we will use this peak value + // for searching attack. + // Handling "Hole like" transients also not implemented. But it should be masked + SetTransientParamsHistory(channel, band, transientParam); + continue; } - if (loc2 != 31) { - curve.push_back({relToIdx(relC), 31}); + + auto transientParamHistory = GetTransientParamsHistory(channel, band); + + if (transientParamHistory.Attack0Location == -1 && transientParamHistory.Attack1Location == -1 && transientParamHistory.ReleaseLocation == -1 && + transientParam.Attack0Location != -1 /*&& transientParam.Attack1Location == -1 && transientParam.ReleaseLocation == -1*/) { + // No transient at previous frame, but transient (attack) at border of first and second half - simplest way, just scale the first half. + + //std::cout << "CASE 1: " << transientParam.Attack0Location << " " << transientParam.Attack0Relation << std::endl; + auto idx = relToIdx(transientParam.Attack0Relation); + //std::cout << "PREV PEAK: " << *lastMax << " " << idx << std::endl; + curve.push_back({idx, (uint32_t)transientParam.Attack0Location}); + hasTransient = true; } + //std::cout << "transient params band: " << band << " atack0loc: " << transientParam.Attack0Location << " atack0rel: " << transientParam.Attack0Relation << + // " atack1loc: " << transientParam.Attack1Location << " atack1rel: " << transientParam.Attack1Relation << + // " releaseloc: " << transientParam.ReleaseLocation << " releaserel: "<< transientParam.ReleaseRelation << std::endl; + + //for (int i = 0; i < 256; i++) { + // std::cout << i << " " << srcBuff[i] << " | " << srcBuff[i-256] << std::endl; + //} + + + SetTransientParamsHistory(channel, band, transientParam); if (hasTransient) { subbandInfo->AddSubbandCurve(band, std::move(curve)); } - } } @@ -347,7 +363,8 @@ TPCMEngine<TFloat>::TProcessLambda TAtrac3Processor::GetEncodeLambda() sce->SubbandInfo.Reset(); if (!Params.NoGainControll) { - //CreateSubbandInfo(p, channel, &TransientDetectors[channel*4], &sce->SubbandInfo); //4 detectors per band + TFloat* p[4] = {PcmBuffer.GetSecond(channel), PcmBuffer.GetSecond(channel+2), PcmBuffer.GetSecond(channel+4), PcmBuffer.GetSecond(channel+6)}; + CreateSubbandInfo(p, channel, &TransientDetectors[channel*4], &sce->SubbandInfo); //4 detectors per band } TFloat* maxOverlapLevels = PrevPeak[channel]; |