<feed xmlns='http://www.w3.org/2005/Atom'>
<title>atracdenc/src/gain_processor_ut.cpp, branch fix_input_file_path</title>
<subtitle>OpenSource ATRAC1 ATRAC3 Encoder</subtitle>
<id>https://code.mastervirt.ru/atracdenc/atom?h=fix_input_file_path</id>
<link rel='self' href='https://code.mastervirt.ru/atracdenc/atom?h=fix_input_file_path'/>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/'/>
<updated>2026-03-15T20:13:24Z</updated>
<entry>
<title>atrac3: ratio-scored transients, per-band gain boost, pre-echo reduction</title>
<updated>2026-03-15T20:13:24Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-03-15T20:13:24Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=34aee45f701cd49824a83cc3781b0c12976eca2f'/>
<id>urn:sha1:34aee45f701cd49824a83cc3781b0c12976eca2f</id>
<content type='text'>
Rewrites the ATRAC3 gain control pipeline to eliminate noise flashes
and substantially reduce pre-echo artifacts:

Transient detection &amp; curve building (transient_detector.cpp/h):
- Replace legacy heuristic detector with ratio-scored DetectTransients:
  score = peak/floor for rising (c/a) or falling (a/c) triplets, scored
  and ranked, top-N kept, sorted by location
- Add explicit point0 derived from windowed-RMS match between bufCur and
  the curve-modulated bufNext (CalcWindowedRmsAfterCurve)
- Replace RegionMax with RegionRMS for smoother region amplitude estimate
- Add per-band detection thresholds kMinScorePerBand[4] = {1.9,1.9,2.1,2.2}
- Dynamic minScore: scale threshold by min(1.5, max(1.0, overlapRatio)) to
  suppress false-positive curves when previous frame dominates
- Scale constraint: curve[0].Level &gt;= 3 to cap cross-frame amplification at 2x

Bit allocation (atrac3_bitstream.cpp/h):
- Add GainBoostPerBand[NumQMF] to TSingleChannelElement, computed in
  CreateSubbandInfo and applied in CalcBitsAllocation
- levelBoost: compensate for Demodulate's GainLevel[minLevel] attenuation
- scaleBoost: compensate for next-frame cross-frame scale via lookahead
- Both capped (kLevelBoostCap=1, kScaleBoostCap=2) to avoid bit starvation

Upsampler (atrac3denc.cpp):
- Raise cutoff from 600 Hz to 800 Hz for tighter band separation

Tests (gain_processor_ut.cpp):
- Relax fixed curve shape assertions to ExpectCurveReasonable (bounds checks)
- Relax quantization error bound for dense-event spacing (&lt;=128 samples)

Results (branch new_psy vs original baseline):
  riddler: pre-echo worse 43-&gt;15/479 frames, 0 flashes
  spine:   pre-echo worse 192-&gt;107/1804 frames, 0 flashes

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Integrate TSpectralUpsampler into ATRAC3 gain control and fix CalcCurve ctx tracking</title>
<updated>2026-03-08T17:46:05Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-03-08T17:46:05Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=d41f56fb67e84d949bd8757287e7b9dfe8008ef1'/>
<id>urn:sha1:d41f56fb67e84d949bd8757287e7b9dfe8008ef1</id>
<content type='text'>
Encoder (atrac3denc.cpp / atrac3denc.h):
- Replace old TTransientParam / TransientParamsHistory with TSpectralUpsampler-
  based CreateSubbandInfo(): analyses the upsampled QMF band, computes gain[]
  and nextLevel from the contiguous look-ahead buffer, and calls CalcCurve to
  build ATRAC3 gain-curve points.
- highFreqRatio guard: skip CalcCurve for sub-bass bands where the HPF signal
  is too weak to produce meaningful gain control.

CalcCurve (transient_detector.cpp):
- Fix Issue 1 (FFT-window context mismatch at frame boundary):
  Store ctx.LastLevel = in.back() instead of target (nextLevel).
  in.back() and the next call's gain[0] are both analysis-domain estimates of
  adjacent 8-sample blocks — no cross-domain FFT-window divergence that produced
  false boundary transients.
- Guard against zero savedLastLevel (first frame or post-reset): return empty
  curve rather than emitting scaleLevel=15 (GainLevel=1/2048) which would cause
  extreme amplification in the gain modulator.
- Tighten gain-point budget to 7 (&lt; MaxGainPointsNum=8) to match the 3-bit
  count field in the ATRAC3 bitstream.

Tests (gain_processor_ut.cpp):
- Add BoundaryLevelMismatch suite: Issue1_FalseTransientOnConstantTone_AfterOnset,
  Issue1_MdctRoundtrip_NoGain, Issue1_MdctRoundtrip_WithGain,
  Issue1_RoundtripWithGainAndQuantization.
- Quantization test threshold set to 400× kQuantStep: correct two-point gain
  curves for a 9:1 amplitude-ratio signal produce at most ~323× peak error
  (scale×level=16 × ~8× IMDCT base noise); pathological false transients would
  cause signal-level reconstruction errors well above this bound.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Add CalcCurve and TSpectralUpsampler for transient detection</title>
<updated>2026-03-05T22:44:12Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-03-05T22:44:12Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=7607e6c47490e3d5c74949e7f7d90ef6f9c0b5f0'/>
<id>urn:sha1:7607e6c47490e3d5c74949e7f7d90ef6f9c0b5f0</id>
<content type='text'>
CalcCurve (transient_detector.cpp/h):
- Recursive divide-and-conquer FindTransients scans the gain vector for
  monotonic 3-subframe windows (rising or falling); kMinScore=2.0 filters
  out oscillations smaller than a factor of 2 (no-op at Level 4).
- RelationToIdx maps an amplitude ratio to an ATRAC3 gain Level index.
- TCurveBuilderCtx carries LastLevel across frames; CalcCurve prepends it
  as a virtual boundary element to detect Location=0 attacks.
- budget=8 matches ATRAC3 SubbandInfo::MaxGainPointsNum.

TSpectralUpsampler (transient_spectral_upsampler.cpp/h):
- Applies a Planck-taper window (ε=0.15) to a 512-sample context window,
  forward-FFTs, applies a 3-bin raised-cosine HPF, zero-pads to 4096 bins,
  and inverse-FFTs to give an 8× upsampled output.
- Returns highFreqRatio = Σ|X[k]·H[k]|²/Σ|X[k]|²; callers skip CalcCurve
  when this is below kHighFreqThreshold=0.05, preventing false transients
  from Planck noise-floor variation in sub-cutoff frames.

Tests:
- gain_processor_ut: upsampled-path blocks added to all FreqDomain tests;
  CalcCurve negative tests (NegativeTests suite).
- transient_spectral_upsampler_ut: OutputSize, DCIsRemovedByLowCutFilter,
  HighFreqSinePreservesRMS (parametrised), ChirpNoTransient (0→5510 Hz
  sweep at 689 Hz low-cut, Len1024/16384/262144).

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Add AttackAndRelease_LevelRise gain modulation test</title>
<updated>2026-02-26T22:47:06Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-02-26T22:47:06Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=fe59f80d61062aa4197aa88f6471d6809388ea14'/>
<id>urn:sha1:fe59f80d61062aa4197aa88f6471d6809388ea14</id>
<content type='text'>
Demonstrates handling a burst where the post-burst quiet level (A_after=2)
differs from the pre-burst quiet level (A_before=1).

Strategy: normalise to A_after using {{5,4},{2,12}}:
  - scale = GainLevel[5] = 0.5 → amplifies quiet prefix ×2 to A_after
  - Level=2 (GainLevel=4) attenuates burst ÷4 to A_after
  - Remainder [104..255] already at A_after → untouched

Modulated bufNext is uniform A_after throughout → near-zero HF leakage
in both frame 1 and frame 2. No compensating gain needed. Release ramp
uses gainInc = 2^(-2/8) (GainLevel 4.0→1.0, 2-octave span to neutral).

Includes full TDAC round-trip verification.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Refactor AttackAndRelease and add ReleaseAndAttack gain modulation tests</title>
<updated>2026-02-26T22:00:59Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-02-26T22:00:59Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=7adbf958c0d6ec500f05efb24ef1eca68d4b98e2'/>
<id>urn:sha1:7adbf958c0d6ec500f05efb24ef1eca68d4b98e2</id>
<content type='text'>
Both tests now normalise to the dominant amplitude using the minimum
number of gain points, with no compensating gain needed in frame 2:

- AttackAndRelease (QUIET→LOUD→QUIET burst): switch from 3-point
  {{7,4},{4,12},{7,31}} (normalise to A_loud, needed {{1,1}} frame 2
  compensation) to 2-point {{4,4},{1,12}} (scale=1.0 leaves quiet
  bufCur unchanged, loud burst attenuated ÷8 to A_quiet, quiet tail
  falls in untouched remainder). Strengthen frame 2 assertion to ×10.

- ReleaseAndAttack (LOUD→QUIET→LOUD dip): new test with 2-point
  {{4,4},{7,12}} (scale=1.0 leaves loud bufCur unchanged, quiet dip
  amplified ×8 to A_loud, loud tail falls in untouched remainder).
  Frame 2 is plain A_loud with no compensating gain.

Both include full TDAC round-trip verification.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Add GainModulation_ReducesSpectralEnergy_QuietToLoudTransient test</title>
<updated>2026-02-25T23:45:43Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-02-25T23:45:43Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=5e2d85448f67582d4530bebff76c6a74d1d7148d'/>
<id>urn:sha1:5e2d85448f67582d4530bebff76c6a74d1d7148d</id>
<content type='text'>
Demonstrates that a QUIET-&gt;LOUD transient inside bufNext can be handled
in the current frame by amplifying the quiet prefix to match the loud
suffix, rather than deferring to the next frame.

Signal (3 frames):
  frame 0: quiet (A=1) -- primes overlap
  frame 1: quiet[0..55] + attack ramp[56..63] + loud[64..255]
  frame 2: all loud (A=8) -- continuation

Gain: {{7, 7}} on frame 1
  Level=7 -&gt; GainLevel[7]=0.125 -&gt; scale=0.125 (amplify x8)
  Location=7 -&gt; lastPos=56; constant [0..55] amplified x8 to A_loud
  Transition [56..63]: level 0.125-&gt;1.0 at gainInc_atk=2^(3/8) rate;
  signal pre-shaped with matching ramp so Modulate divides it out
  exactly -&gt; uniform A_loud*sin across the entire MDCT window.
  Remainder [64..255]: loud signal untouched (already at A_loud). No
  compensating gain needed on frame 2 -- loud bufCur and loud bufNext
  are already matched.

Assertions:
  EXPECT_LT(hf1_mod * 10, hf1_nomod)  -- frame 1: HF leakage reduced &gt;10x
  EXPECT_LE(hf2_mod * 10, hf2_nomod)  -- frame 2: no regression

Round-trip: Mdct(Modulate) -&gt; Midct(Demodulate) recovers signal.
  frame 1 Midct: Demodulate(siCur=empty, siNext={{7,7}})
  frame 2 Midct: Demodulate(siCur={{7,7}}, siNext=empty)
  Verified with EXPECT_NEAR(..., 1e-5) over frames 1 and 2.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Add TGainProcessor and frequency-domain gain modulation unit tests</title>
<updated>2026-02-23T21:15:20Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-02-23T21:08:26Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=836ce334b101182ec8ceea35e9349f1d507e27c5'/>
<id>urn:sha1:836ce334b101182ec8ceea35e9349f1d507e27c5</id>
<content type='text'>
gain_processor_ut.cpp covers three test suites:

TGainProcessor_Modulate (5 tests):
  - Empty gain returns null op
  - Single-point constant/transition/remainder regions
  - Two-point and three-point envelopes

TGainProcessor_Demodulate (5 tests):
  - Empty gain returns null op
  - Single-point constant/transition/remainder regions
  - Two-point envelope

TGainProcessor_Mirror (6 tests):
  - Round-trip Modulate-&gt;Demodulate algebraic identity
  - Constant, transition, remainder, and asymmetric-scale cases

TGainProcessor_FreqDomain (6 tests):
  Each test builds a 3-frame signal, runs MDCT with Modulate, checks
  HF energy reduction vs unmodulated, and verifies perfect signal
  reconstruction via MDCT(Modulate)-&gt;MIDCT(Demodulate) with 1e-5 tolerance.

  Test signals and gain envelopes (mirroring atrac3denc_ut.cpp reference tests):

  | Test name                                             | Frame 1 gain          | Frame 2 comp gain |
  |-------------------------------------------------------|-----------------------|-------------------|
  | GainModulation_ReducesSpectralEnergy                  | {{7,0}}               | none              |
  | GainModulation_ReducesSpectralEnergy_TransientInFrame | {{4,8},{7,31}}        | {{1,1}}           |
  | GainModulation_ReducesSpectralEnergy_AttackAndRelease | {{7,4},{4,12},{7,31}} | {{1,1}}           |
  | GainModulation_ReducesSpectralEnergy_DcSignal         | {{7,1}}               | {{1,1}}           |
  | GainModulation_ReducesSpectralEnergy_DcSignal2        | {{7,1}}               | {{1,0}}           |
  | GainModulation_ReducesSpectralEnergy_2PointsWithoutScaleDc2 | {{4,0},{1,31}} | none              |

  Round-trip Demodulate mapping (siCur -&gt; siNext at frame 2 MIDCT):

  | Test name                                             | siCur                 | siNext  |
  |-------------------------------------------------------|-----------------------|---------|
  | GainModulation_ReducesSpectralEnergy                  | {{7,0}}               | empty   |
  | GainModulation_ReducesSpectralEnergy_TransientInFrame | {{4,8},{7,31}}        | {{1,1}} |
  | GainModulation_ReducesSpectralEnergy_AttackAndRelease | {{7,4},{4,12},{7,31}} | {{1,1}} |
  | GainModulation_ReducesSpectralEnergy_DcSignal         | {{7,1}}               | {{1,1}} |
  | GainModulation_ReducesSpectralEnergy_DcSignal2        | {{7,1}}               | {{1,0}} |
  | GainModulation_ReducesSpectralEnergy_2PointsWithoutScaleDc2 | {{4,0},{1,31}} | empty   |

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
