<feed xmlns='http://www.w3.org/2005/Atom'>
<title>atracdenc, branch new_psy</title>
<subtitle>OpenSource ATRAC1 ATRAC3 Encoder</subtitle>
<id>https://code.mastervirt.ru/atracdenc/atom?h=new_psy</id>
<link rel='self' href='https://code.mastervirt.ru/atracdenc/atom?h=new_psy'/>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/'/>
<updated>2026-04-19T22:27:45Z</updated>
<entry>
<title>atrac3: reimplement tonal encoding. Use flatness-based tonal extraction</title>
<updated>2026-04-19T22:27:45Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-04-18T14:51:23Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=e784b79cfef682059cf5cc8cf9bed635e714c439'/>
<id>urn:sha1:e784b79cfef682059cf5cc8cf9bed635e714c439</id>
<content type='text'>
- Add shared CalcSpectralFlatnessPerBfu helper in atrac_psy_common
  with BFU-table mapping.
- Implement ATRAC3 tonal extraction: compute MDCT energy, estimate
  per-BFU flatness, extract up to 5-bin strongest tonal run in
  low-flatness BFUs, and zero extracted bins in residual.
- Map extracted tonal bins into TTonalBlocks and integrate them into
  bitstream coding.
- Update ATRAC3 bit allocation - reduce residual bits for BFUs with tonal
  blocks, and increase tonal quantizer selection.
- Restore --notonal CLI option in main.cpp for A/B comparison.
</content>
</entry>
<entry>
<title>[AT3] refactor bitstream allocation loop to bs_encode</title>
<updated>2026-04-11T21:20:06Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-04-11T21:18:36Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=a958b27a43f0a436406dc51b942ca2f3a417e7a7'/>
<id>urn:sha1:a958b27a43f0a436406dc51b942ca2f3a417e7a7</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Remove dead transient hooks, hack override, and unused RMS helper</title>
<updated>2026-04-09T19:39:52Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-04-09T19:36:07Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=3efb188ade161e9c01cb7550aca95aa8e5c78875'/>
<id>urn:sha1:3efb188ade161e9c01cb7550aca95aa8e5c78875</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Merge new_psy -&gt; master</title>
<updated>2026-04-08T22:24:50Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-04-08T22:24:50Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=26e8a2a5bcb52395dd1cc03bd946c0989ed01793'/>
<id>urn:sha1:26e8a2a5bcb52395dd1cc03bd946c0989ed01793</id>
<content type='text'>
New experimental gain control code for atrac3</content>
</entry>
<entry>
<title>Fix Windows C++17 build and MSVC flag warnings</title>
<updated>2026-04-08T22:12:05Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-04-08T22:12:05Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=73e432a3ed6b122ae1fb9d0daf20169c303e2f94'/>
<id>urn:sha1:73e432a3ed6b122ae1fb9d0daf20169c303e2f94</id>
<content type='text'>
</content>
</entry>
<entry>
<title>atrac3: add boundary transient thresholding to prune low-value gain transitions</title>
<updated>2026-04-08T21:33:40Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-04-06T21:10:51Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=2c285429d27ae2d15f6b5538f0591a15dfc6490b'/>
<id>urn:sha1:2c285429d27ae2d15f6b5538f0591a15dfc6490b</id>
<content type='text'>
Problem
Gain curve generation emitted many +/-1 level transitions that do not correspond
to strong local transients. These points consume gain-info bits and can create
low-level modulation artifacts without improving transient handling.

Solution
Introduce explicit transient evidence gating at transition boundaries in
CalcCurve(), and wire it to the existing dynamic min-score path.

What changed
- Added BoundaryTransientScore(env, loc, win):
  - computes local ratio around each subframe boundary
  - R = max(max_right/max_left, max_left/max_right)
  - short symmetric window (win=3 subframes)
- Re-enabled minScore usage in CalcCurve() (previously ignored).
- For each level transition candidate at loc=sf+1:
  - keep unconditionally if loc==targetSf (tail neutral anchor)
  - keep unconditionally if |deltaLevel| &gt;= 2 (strong step)
  - otherwise keep only if BoundaryTransientScore(loc) &gt;= minScore
- Added YAML telemetry:
  - transient_min_score
  - transient_window
  - transition_pruned {loc, delta, score}

Why this is safe
- Strong transitions are preserved.
- Rightmost transition is preserved to keep proper return-to-neutral anchoring.
- Only low-confidence small toggles are removed.

Measured impact (current branch comparison)
Baseline: ea4d33b38 (before this change)
Tracks: show_me_your_spine.wav, 13.wav

Gain-info bits / points:
- spine: 191,697 -&gt; 150,297 bits  (delta -41,400; -21.6%)
         15,593 -&gt; 10,993 points (delta -4,600)
- 13.wav: 1,299,035 -&gt; 979,931 bits  (delta -319,104; -24.6%)
          97,035 -&gt; 61,579 points   (delta -35,456)

Subjective note
User listening reports improved sound and fixes for some low-level artifacts.
</content>
</entry>
<entry>
<title>atrac3: remove band3 transient boost redirection to band0</title>
<updated>2026-04-08T21:33:40Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-04-06T19:37:44Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=44fd0465b87e6648a647cf868ab4026d28ff60a7'/>
<id>urn:sha1:44fd0465b87e6648a647cf868ab4026d28ff60a7</id>
<content type='text'>
</content>
</entry>
<entry>
<title>atrac3: make sticky gain quantization conditional and tune thresholds</title>
<updated>2026-04-08T21:33:40Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-04-06T18:55:17Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=f2c699fae52cf298aabc9b73d91c5bee28cd64dd'/>
<id>urn:sha1:f2c699fae52cf298aabc9b73d91c5bee28cd64dd</id>
<content type='text'>
Problem
The distribution-aware sticky quantizer reduced gain-curve bitrate, but in some
release/transient frames it over-merged nearby transitions. On spine around
17.657s (ch1/band2), this collapsed the curve shape and could produce an
audible spike.

What changed
- Added frame-level sticky eligibility gating in CalcCurve().
- Sticky is now enabled only when both conditions hold:
  - intra-frame ratio is limited: max_gain / target &lt;= kStickyMaxIntraFrameRatio
  - inter-frame target jump is limited: prev_target / target (symmetric) &lt;= kStickyMaxInterFrameRatio
- Added local uncertainty guard for sticky hold:
  - require idx span from [subframeLow, subframeHigh] quantization to be narrow
    (idxSpan &lt;= 1) before allowing prev-level hold.
- Added YAML diagnostics per band/frame to make gating decisions auditable:
  - sticky_frame_eligible
  - sticky_intra_ratio
  - sticky_inter_ratio

Threshold tuning
Swept candidate pairs on both tracks:
- show_me_your_spine.wav
- 13.wav
Pairs tested:
(5,6), (5,8), (6,8), (6,10), (7,8), (7,10), (8,12)

Selected:
- kStickyMaxIntraFrameRatio = 7.0
- kStickyMaxInterFrameRatio = 10.0

Reason for selection
- Keeps safety behavior on known failure site:
  frame 760, ch1, band2 remains sticky_frame_eligible=false
  and retains non-collapsed curve shape (loc 1,2,5,7).
- Improves gain-modulation bitrate vs previous 6/8 tuning while avoiding fully
  open behavior.

Measured gain-modulation bits (spine + 13.wav)
- 6/8:  1,493,639 bits
- 7/10: 1,490,732 bits  (selected, -2,907 bits vs 6/8)
- 8/12: 1,488,824 bits  (lowest in sweep; not selected to keep extra margin)
</content>
</entry>
<entry>
<title>atrac3: add distribution-aware sticky gain quantization</title>
<updated>2026-04-08T21:33:40Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-04-06T17:14:32Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=90ae01a4fbc62d1e839d749bf2ead6b0c67e29ff'/>
<id>urn:sha1:90ae01a4fbc62d1e839d749bf2ead6b0c67e29ff</id>
<content type='text'>
Problem
Gain curve construction still produced many +/-1 level toggles across long runs
(e.g. 7&lt;-&gt;8 chatter). These transitions are usually quantization noise from
subframe-level RMS rounding, not real envelope changes, and they consume gain
bit budget without improving transient protection.

Feature
Introduce distribution-aware sticky quantization for subframe gain levels.
Instead of quantizing only the subframe centre estimate, we also track a robust
within-subframe range and suppress one-step toggles when the previous level is
still consistent with that range.

Implementation
1) AnalyzeGain now optionally returns per-subframe low/high energy estimates
   (robust inter-quantile bounds from micro-chunk analysis inside each subframe).
2) CalcCurve now accepts optional subframe low/high vectors.
3) During sfLevel quantization:
   - compute centre level via RelationToIdx(filtered/target)
   - if new level differs from previous by exactly 1, and previous level is still
     inside [idx(low), idx(high)], keep previous level (sticky hold)
4) CreateSubbandInfo wires the new AnalyzeGain outputs into CalcCurve.
5) Existing point0 guard/boundary logic remains intact; this feature operates
   earlier at sfLevel formation.

Why this is safe
- Only suppresses +/-1 oscillation when previous level is still supported by
  observed subframe distribution.
- Does not clamp large transitions or remove structurally important points.
- Keeps curve scan/priority flow unchanged after sfLevel is formed.

Measured impact on current HEAD (gain-info bits)
Bit accounting uses ATRAC3 gain syntax: per channel header + per band point-count
fields + 9 bits per gain point.

show_me_your_spine.wav:
- base: 219,552 bits (18,688 points)
- with sticky: 172,158 bits (13,422 points)
- saved: 47,394 bits, 5,266 points (-21.59% gain-info bits)

13.wav:
- base: 1,537,724 bits (123,556 points)
- with sticky: 1,146,746 bits (80,114 points)
- saved: 390,978 bits, 43,442 points (-25.43% gain-info bits)
</content>
</entry>
<entry>
<title>atrac3: make point0 guard boundary-aware to avoid overlap artifacts</title>
<updated>2026-04-08T21:33:40Z</updated>
<author>
<name>Daniil Cherednik</name>
<email>dan.cherednik@gmail.com</email>
</author>
<published>2026-04-05T21:59:39Z</published>
<link rel='alternate' type='text/html' href='https://code.mastervirt.ru/atracdenc/commit/?id=7ee080508593c7e83080fdca2acfa20e10d1db81'/>
<id>urn:sha1:7ee080508593c7e83080fdca2acfa20e10d1db81</id>
<content type='text'>
Problem
The current point0 guard decides keep/revert only from an early-frame mismatch score.
That can revert a newly inserted point0 even when it is needed for frame-boundary
continuity. In ATRAC3 demodulation, the next frame's first gain level is reused as a
scale term for the overlap region, so removing point0 can change boundary scale by
multiple quantization steps and create audible artifacts.

Root cause
For frames like 13.wav around 45.1s, point0_guard reverted point0 in key bands,
which changed first-point scale and increased boundary mismatch despite a locally
better early-fit score.

Change
- Keep existing early mismatch metric (fit + leakage proxy).
- Add boundary-aware keep criterion inside point0_guard:
  * compute desired boundary scale in the same HPF domain:
      desiredScale = LimitRel(prevTarget / hpfRmsNextMod)
  * compare log2 distance of first-level scale before/after point0 insertion
  * if point0 reduces boundary error by a material margin (0.2 bits), force keep
    even when early-fit score slightly worsens
- Apply guard only when point0 actually changes the curve.
- Add YAML telemetry for boundary error before/after to support analysis.

Implementation details
- Added helper utilities to reconstruct subframe-average divisors from curve points
  and score early mismatch consistently.
- Updated point0 insertion/update flow to track whether point0 changed.
- Extended guard decision to combine:
  * early mismatch tolerance (existing behavior), and
  * boundary continuity improvement (new behavior).

Observed effect (focused check)
- On 13 clip (~45.1s), exact bad subframe (t=45.103129s, frame256=7769, sf32=23):
  ratio vs no-gain reduced from 9.30x to 1.51x after this change.
- Frame 1942 YAML now shows point0 kept in bands where boundary error drops
  substantially.

Notes
- No full regression run in this commit (intentional for fast iteration).
</content>
</entry>
</feed>
