Releases: OxideAV/oxideav-opus
v0.0.12
Other
- §4.3.7.1 pitch post-filter response (celt_post_filter)
- §4.3.4.2 PVQ shape read path (index read + unit-L2 normalization)
- fix clippy assertions-on-constants in celt_deemphasis test
- §4.3.7.2 de-emphasis filter (round 48)
- §4.3.7 inverse-MDCT overlap window (round 47)
- §4.1.2 public two-step range-coder symbol API (ec_decode + ec_dec_update)
- §4.3.2.1 per-LM inter-mode (alpha, beta) prediction coefficients (round 45)
- §4.3.4.3 spreading rotation (round 44)
- §4.3.4.2 PVQ index-to-vector decode (round 43)
- clean-room round 42 — §4.3.2.2 fine-energy quantization
- §4.3.4.2 PVQ codebook-size function V(N, K) (round 41)
- §4.3.3 1/64-step interpolated allocation search (round 40)
- §4.3.3 static allocation table (Table 57) (round 39)
- §4.5.3 normative + recommended-non-normative transition table (round 38)
- drop release-plz.toml — use release-plz defaults across the workspace
- RFC 6716 Appendix B self-delimiting framing (round 37)
- §4.3.3 per-band allocation-trim offsets (round 36)
- §4.3.3 per-band minimum-allocation vector (round 35)
- §4.3.3 reservation block (round 34)
- §4.3.3 band-boost decoder (round 33)
- §4.3.3 allocation-trim Table-58 PDF + signalling gate (round 32)
- §4.3.3 CACHE_CAPS50 per-band maximum-allocation parameter surface (round 31)
- §4.3.3 LOG2_FRAC_TABLE intensity-stereo reservation parameter surface (round 30)
- §4.3.2.1 CELT coarse-energy Laplace-model parameter surface (round 29)
- §4.5.1.4 redundant-CELT-frame decode parameters + cross-lap placement (round 28)
- §4.5.2 SILK + CELT state-reset policy across mode transitions (round 27)
- §4.5.1 CELT redundancy / mode-transition side information (round 26)
Added
-
Clean-room round 50 (2026-06-15): §4.3.7.1 pitch post-filter
response (celt_post_filter). The pitch comb filter the CELT decoder
applies to the inverse-MDCT / overlap-add output (§4.3.7) just before
the round-48 §4.3.7.2 de-emphasis; the post-filter parameters landed
incelt_headerat round 20, this round owns their application. RFC
6716 §4.3.7.1 (p. 121) states the five-tap symmetric comb response
y(n) = x(n) + G*(g0*y(n-T) + g1*(y(n-T+1)+y(n-T-1)) + g2*(y(n-T+2)+y(n-T-2)))— recursive over past output samples (state
= the trailingT + 2outputs, carried across frames, reset only on a
§4.5.2 CELT state reset). The ASCII equation prints each pair term with
a repeated index; the symmetricy(n-T±1)/y(n-T±2)reading is the
only one consistent with the "g0, g1, g2" symmetric-tap-set prose, and
the module documents the slip. New surface:POST_FILTER_TAPS(the
three §4.3.7.1(g0, g1, g2)tapsets) +tapset_coefficients+
post_filter_gain(G = 3*(gain_index+1)/32) + the formula constants;
PostFilterCoeffs { period, a0, a1, a2 }(gain folded into each tap)
vianew/from_header;PostFiltercarrying the output history
(new/reset/step/process_in_place/process/
process_gain_transition— the §4.3.7.1 squared-MDCT-window gain
crossfade pushing the mixed value into the shared feedback history per
"interpolated one at a time"); the standalonecrossfade_transition;
andPostFilterError::{TapsetOutOfRange, PeriodOutOfRange, GainIndexOutOfRange, OutputBufferTooSmall, TransitionLengthMismatch, Window}withFrom<MdctWindowError>. Twenty-six new unit tests (1064
lib tests, up from 1038; 20 integration unchanged): the tapset decimalsg2 = 0for tapsets 1/2, the gain formula + monotonicity, the
gain-fold, period bounds, header round-trip, fresh-history
pass-through, a hand-expanded impulse response placing each tap at its
exact lag, impulse-response symmetry aboutT, history carry across
split blocks, the buffer paths,reset, the gain-transition endpoints- old==new identity + length checks, the standalone crossfade
convexity, and every errorDisplay. Provenance: §4.3.7.1 comb
response, tapsets, gain map, and squared-window transition rule in the
stageddocs/audio/opus/rfc6716-opus.txt; the squared window reuses
the round-47celt_mdct_window; no external library source consulted.
-
Clean-room round 49 (2026-06-15): §4.3.4.2 PVQ shape read path
(celt_pvq_decode). Composes the three steps RFC 6716 §4.3.4.2
(p. 116–117) states in sequence: the up-front
i = ec_dec_uint(V(N, K))codeword-index read
(RangeDecoder::dec_uint), the round-43 five-step index-to-vector
walk, and the final normalization — "The decoded vector X is then
normalized such that its L2-norm equals one." New surface:
pvq_unit_normalize(&[i32], &mut [f64])(the unit-L2 scaling, with
theK = 0no-direction case left all-zeros);decode_pvq_shape(rd, n, k) -> Vec<f64>anddecode_pvq_shape_into(rd, n, k, &mut [f64])
(the full read path returning the unit-normf64shape the §4.3.4.3
spreading rotation operates on and §4.3.6 denormalization later
scales by the band energy); andPvqShapeError::{CodebookSize, RangeDecoder, PulseVector, OutputBufferTooSmall}withFrom<PvqVError>
/From<PvqDecodeError>. Fourteen new unit tests (1038 lib tests, up
from 1024; 20 integration unchanged): the unit-L2 norm over every
codeword of(N, K) ∈ 1..=6 × 1..=6, direction preservation,
single-pulse ±1, the zero-vector carve-out, the buffer paths;
decode_pvq_shape↔decode_pvq_vector+pvq_unit_normalize
consistency from fixed buffers, the_intoparity, theK = 0
no-bit-consumption edge,N = 1signed-unit, codebook-size error
propagation, and the error conversions/Display. -
Clean-room round 48 (2026-06-14): §4.3.7.2 de-emphasis filter
(celt_deemphasis). The final stage of the CELT decode pipeline,
applied after the inverse MDCT + overlap-add (§4.3.7) and the
§4.3.7.1 pitch post-filter. RFC 6716 §4.3.7.2 (p. 122) states it as
the inverse of the encoder's pre-emphasis filter,
1/A(z) = 1/(1 - alpha_p*z^-1)withalpha_p = 0.8500061035;
inverting the one-pole transfer function gives the time-domain
recurrencey(n) = x(n) + alpha_p*y(n-1). The single state element
carries across frame boundaries (the recurrence is continuous over
the whole stream, reset only on a §4.5.2 CELT state reset). New
surface:DEEMPHASIS_ALPHA_P = 0.8500061035constant;
DeemphasisFilterwithnew()/with_memory(mem)/memory()/
reset()/step(x)(one-sample recurrence) /
process_in_place(&mut [f64])/process(input, output); and
DeemphasisError::OutputBufferTooSmall. Fifteen new unit tests
(1024 lib tests, up from 1009; 20 integration unchanged): the
alpha_pconstant + stability bound, fresh-filter zero memory,
first-sample pass-through, hand-computed recurrence, constant-input
convergence to the DC gain1/(1 - alpha_p), the
pre-emphasis-round-trip inverse property, memory carry across split
blocks,with_memoryseeding,reset, theprocess_in_place↔
stepparity, output-buffer write + over-long acceptance +
short-buffer rejection (state unchanged on error), empty-input
no-op, and the errorDisplay. Provenance: §4.3.7.2 transfer
function +alpha_pconstant in the staged
docs/audio/opus/rfc6716-opus.txt; the recurrence is the textbook
inverse of the stated one-pole filter; no reference source
consulted. -
Clean-room round 47 (2026-06-14): §4.3.7 inverse-MDCT overlap
window (celt_mdct_window). RFC 6716 §4.3.7 (p. 121) states the
basic full-overlap 240-sample Vorbis-derived window directly:
W(n) = sin( (pi/2) * sin( (pi/2) * (n + 1/2) / L )^2 )(the2
superscript squares the inner sine — the only nesting that
satisfies the §4.3.7 power-complementarity / Princen-Bradley
requirementW(n)^2 + W(L-1-n)^2 = 1, which the module proves
algebraically and pins in tests). New surface:window_tap(n, len)
(the amplitude tap for window lengthL = len),basic_window()
(the 240-tap full-overlap window),mdct_window(overlap)(the
§4.3.7 "low-overlap" ramp for an arbitrary even overlap, built by
evaluating the same shape withL = overlap— the "zero-pad +
insert ones in the middle" construction expressed as a per-overlap
rising ramp),celt_overlap_window()(the fixed CELT 120-sample
overlap at 48 kHz — the 2.5 ms look-ahead "fixed by the decoder",
RFC 6716 §1), constantsBASIC_WINDOW_LEN = 240/
CELT_OVERLAP_48K = 120, andMdctWindowError::{PositionOutOfRange, ZeroLength, OddOverlap}. Eighteen new unit tests (1009 lib tests,
up from 991; 20 integration unchanged): the formula spot-check,
unit-interval bound, monotone-increasing ramp, power complementarity
on both the basic window and arbitrary overlaps, the half-power
centre pair, endpoint shape,mdct_window↔window_tapparity,
thecelt_overlap_window↔mdct_window(120)parity, and every
error path. The inverse MDCT itself and the weighted overlap-add
that consumes this ramp run at the §4.3.7 consumer site.
Provenance: §4.3.7 window equation + low-overlap narrative + §1
fixed-overlap statement, all in the staged
docs/audio/opus/rfc6716-opus.txt; no reference source consulted. -
Clean-room round 46 (2026-06-13): public two-step range-coder
symbol APIRangeDecoder::ec_decode(ft) -> fsand
RangeDecoder::ec_dec_update(fl, fh, ft)per RFC 6716 §4.1.2,
promoting the previously-privatedecode/dec_updatehelpers to a
validated public surface.ec_decodecomputes the §4.1.2 symbol
proxyfs = ft - min(val/(rng/ft) + 1, ft)and rejectsft == 0
(division by zero) by latching the sticky error flag;ec_dec_update
narrows the range to the chosen symbol's[fl, fh)sub-interval of
[0, ft)and rejects malformed tuples (ft == 0,fh > ft,
fl >= fh) with the same error-latch-and-no-op guard, so a corrupt
search result cannot underflowvalor zerorng. This is the
generic symbol path required when the frequency model is computed at
run time rather than baked into a...
v0.0.11
Other
- §4.3.4.5 CELT TF-resolution adjustment lookup (round 25)
Added
-
Clean-room round 25 (2026-05-30): §4.3.4.5 CELT TF-resolution
adjustment lookup — a newcelt_tf_adjustmodule owning RFC 6716
Tables 60–63 (the four(frame_size, choice) -> i8adjustment
tables keyed by(transient, tf_select)). Exposes
celt_tf_adjustment(frame_size, transient, tf_select, tf_change) -> i8(the routed lookup, return value∈ [-3, 3]),
celt_tf_select_can_affect(frame_size, transient, &[bool]) -> bool
(the §4.3.1 "tf_select is only decoded if it can have an impact on
the result knowing the value of all per-band tf_change flags"
redundancy gate that the §4.3.4.5 band loop calls AFTER decoding
every per-bandtf_change[b]),TfDirection::{Unchanged, IncreaseTime(N), IncreaseFrequency(N)}carrying the §4.3.4.5
Hadamard-transform branch and level count,TfAdjustment(=i8)
storage type, and named constantsTF_ADJUSTMENT_MAX = 3,
TF_ADJUSTMENT_ABS_MAX = 3, plus the four tables themselves
(TF_ADJ_NONTRANSIENT_SELECT0,TF_ADJ_NONTRANSIENT_SELECT1,
TF_ADJ_TRANSIENT_SELECT0,TF_ADJ_TRANSIENT_SELECT1) for direct
inspection.This is the lookup the §4.3.4.5 band loop downstream consumes once
it's wired up (gated on §4.3.2.1 coarse energy and §4.3.3 bit
allocation, both still deferred); it sits between Table 55's
per-band MDCT-bin count and the §4.3.4.2 PVQ shape decoder.Twenty-seven new module tests (428 lib tests total, up from 401 at
round-24 close; 20 integration tests unchanged, grand total 448).
Coverage: every table's4 × 2shape; every cell∈ [-3, 3]; all
32 cells across Tables 60 / 61 / 62 / 63 hand-pinned to RFC 6716
§4.3.4.5; the "non-transientchoice = 0is always 0" invariant;
the "non-transientchoice = 1is always ≤ 0" invariant; the
"positive adjustments only on transient frames" §4.3.4.5
asymmetry pinned at both the table andTfDirectionlayer; the
Table 62choice = 0monotone0, 1, 2, 3scale across frame
sizes; the universal 2.5 ms[0, -1]row across all four tables;
TF_ADJUSTMENT_MAXandTF_ADJUSTMENT_ABS_MAXmatching the
observed max over every cell;celt_tf_adjustmententry-point
routing each(transient, tf_select)corner;celt_tf_select_can_affect
returningfalseon empty band sets and on the redundant 2.5 ms
rows; returningfalseon 10 ms non-transient with all-choice 0
bands andtrueas soon as any band pickschoice = 1;
returningtrueon 20 ms transient for any non-empty band set;
TfDirection::from_adjustmentclassification +levels()value
matchingadj.unsigned_abs()over[-3, 3];
IncreaseFrequencynever reachable on non-transient frames;
IncreaseTimealways reached for non-transientchoice = 1.
v0.0.10
Other
- §4.3 Table 55 CELT MDCT-band layout (round 24)
- §4.2.7.4 SILK gain dequant tail (silk_log2lin) — round 23
- §3.4 R1..R7 malformed-input rejection audit (round 22)
- §3.1 / §4.2 framing dispatch (round 21)
- land §4.3 Table 56 CELT pre-band header symbols
- Round 19: §4.2.9 SILK resampler delay budget + sample-rate accounting
- round 18: §4.2.3 SILK header bits + §4.2.4 per-frame LBRR flags
- §4.2.8 stereo unmixing — silk_stereo_MS_to_LR (round 17)
- fix the round-16 test count phrasing
- §4.2.7.9.1 LTP synthesis filter (round 16)
- round 15 — RFC 6716 §4.2.7.9.2 LPC synthesis filter
- §4.2.7.7 LCG seed + §4.2.7.8 excitation reconstruction
- §4.2.7.6 LTP parameters (pitch lags + LTP filter + LTP scaling)
- §4.2.7.5.8 LPC prediction-gain stability limiting
- §4.2.7.5.7 LPC range-limiting bandwidth expansion
- round 10: RFC 6716 §4.2.7.5.6 SILK NLSF→LPC core conversion
- clean-room round 9 — SILK §4.2.7.5.5 NLSF interpolation
- round 8: RFC 6716 §4.2.7.5.4 SILK NLSF stabilization
- round 7: RFC 6716 §4.2.7.5.3 SILK NLSF reconstruction
- round 6: RFC 6716 §4.2.7.5.2 SILK LSF Stage-2
- round 5 fix: compare iCDF slices by value, not pointer identity
- round 5: RFC 6716 §4.2.7.4 SILK subframe gains
- round 4: RFC 6716 §4.2.7.1–§4.2.7.5.1 SILK frame header
- round 3: RFC 6716 §4.1 range decoder
- round 2: RFC 6716 §3.2 frame-packing parser
- round 1: RFC 6716 §3.1 packet TOC byte parser
- orphan rebuild: clean-room scaffold post 2026-05-20 audit
Added
-
Clean-room round 24 (2026-05-29): §4.3 CELT MDCT-band layout —
a newcelt_band_layoutmodule owning RFC 6716 Table 55 (the
21-band partition with per-band MDCT bin counts at 2.5 / 5 / 10 /
20 ms and the0..=20000 Hzband-edge frequencies) and the §4.3
"first 17 bands (up to 8 kHz) are not coded in Hybrid mode" rule.
ExposesCeltFrameSize(the four CELT frame-size variants whose
repr(u8)discriminants double as Table 55 column index0..=3,
plusfrom_frame_tenths_ms/to_frame_tenths_ms),
celt_band_bins_per_channel(band, fs) -> Option<u16>,
celt_band_start_hz(b)/celt_band_stop_hz(b)band edges,
celt_band_at_hz(hz) -> Option<usize>reverse lookup,
celt_first_coded_band(is_hybrid)/celt_end_coded_band()
iterator bounds,celt_total_bins_per_channel(fs, is_hybrid)
column-sum helper, and named constantsCELT_NUM_BANDS = 21,
HYBRID_FIRST_CODED_BAND = 17,CELT_MAX_BINS_PER_BAND = 176.
The "Custom" mode of §6.2 is explicitly out of scope.This is the layout the deferred §4.3.2 coarse-energy decoder,
§4.3.3 bit allocator, §4.3.4 PVQ shape decoder, §4.3.6
denormalisation, and §4.3.7 inverse MDCT all need before any band
loop can iterate.Twenty new module tests (401 lib tests total, up from 381 at
round-23 close; 20 integration tests unchanged) cover: full-band
start / stop pin (band 0 starts at 0 Hz, band 20 stops at 20 kHz);
adjacent bands tile without gaps (stop(b) == start(b + 1)for
everyb ∈ 0..=19); positive band widths everywhere; the
power-of-two column-scaling invariant (column(c) == 1 << c * column(0)per band); every cell∈ [1, 176]per the §4.3 prose;
hand-pinned Table 55 cells at bands 0 / 8 / 12 / 15 / 17 / 20;
band-edge spot pins at start, the §4.3 Hybrid boundary
(stop(16) = 8000=start(17)), and tail (stop(20) = 20000);
out-of-range band index returnsNone;
CeltFrameSize::from_frame_tenths_msround-trip with explicit
SILK-only rejection (400 / 600 ms); discriminant-vs-column-index
agreement; the Hybrid-vs-CELT-only first-coded-band split with the
8 kHz boundary pin;celt_total_bins_per_channelcolumn-sum
agreement against an independent iterator sum for each mode; strict
hybrid_total < celt_only_totalinvariant; pinned CELT-only column
sums (100 / 200 / 400 / 800) and Hybrid column sums (60 / 120 /
240 / 480);celt_band_at_hzround-trip against the band-edge
triple (start, midpoint,stop - 1all land on the same band);
>= 20 kHzrejection ofcelt_band_at_hz;
celt_band_at_hz(8000) == 17lining up with
HYBRID_FIRST_CODED_BAND; multiple-of-200-Hz band-width
invariant with three pinned widths (200 Hz for band 0, 400 Hz for
band 8, 4400 Hz for band 20);CELT_MAX_BINS_PER_BAND == max(every cell). -
Clean-room round 23 (2026-05-29): §4.2.7.4 SILK gain
dequantization tail — a newsilk_log2linmodule exposing
silk_log2lin(the spec's piecewise-linear approximation of
2^(inLog_Q7/128)) andsilk_gains_dequant(the composed
log_gain ∈ 0..=63 → gain_Q16pipeline
silk_log2lin((0x1D1C71*log_gain >> 16) + 2090)), plus the named
constantsSILK_LOG_GAIN_MULTIPLIER,SILK_LOG_GAIN_BIAS,
SILK_GAIN_Q16_MIN = 81_920,SILK_GAIN_Q16_MAX = 1_686_110_208.
Also adds aSubframeGains::dequant_q16convenience that maps an
entire decoded frame'slog_gain[]into the fixed-size[u32; SILK_MAX_SUBFRAMES]array consumed by the §4.2.7.9.1 LTP and
§4.2.7.9.2 LPC synthesis filters (with trailing unused slots left
at zero for two-subframe frames).This closes the §4.2.7.4 tail-end conversion that was previously
noted as deferred since round 5; the §4.2.7.9 synthesis filters
already accept again_q16input but were missing the official
RFC-spec mapping from the decodedlog_gaininteger to the linear
Q16 gain.Nineteen new module tests (381 lib tests total, up from 362 at
round-22 close, plus the 20 integration tests unchanged) cover:- The §4.2.7.4 documented endpoints —
log_gain = 0returns
81920(= 1.25 in linear scale) andlog_gain = 63returns
1_686_110_208(≈ 25 728 in linear). - Strict monotonicity:
silk_gains_dequant(g+1) > silk_gains_dequant(g)
for everyg ∈ 0..=62. - Spec-range invariant across the full
0..=63sweep. - Pure-power-of-two collapse:
silk_log2lin(128*i) == 1<<ifor
i ∈ 0..=30. silk_log2lin(0) == 1andsilk_log2lin(1) == 1(the
approximation can't resolve sub-128 Q7 belowi = 7).- Pinned
silk_log2lin(7*128 | 64) = 181— exact match of the
§4.2.7.4 approximation against the true2^7.5 ≈ 181.019…
halfway between2^7and2^8, exercising both thebowed
correction and the linear term. - Independent i64 oracle of the §4.2.7.4 formula matched bit-for-bit
by the production i32 implementation across (a) every reachable
inLog_Q7from thelog_gaindequant pipeline and (b) the full
i ∈ 0..=30 × f ∈ 0..=127Q7 domain. - Endpoint algebra pinned independently of
silk_gains_dequant:
log_gain = 0 → in_log_q7 = 2090;log_gain = 63 → in_log_q7 = 3923(=30*128 + 83),silk_log2lin(2090) = 81_920,
silk_log2lin(3923) = 1_686_110_208. SubframeGains::dequant_q16leaves trailing slots at zero for a
two-subframe frame and matches per-subframesilk_gains_dequant
calls across the four-subframe frame.
- The §4.2.7.4 documented endpoints —
-
Clean-room round 22 (2026-05-27): §3.4 R1..R7 malformed-input
rejection audit — a dedicated integration-level test file
(tests/malformed_input.rs, 20 tests) that pins every concrete
failure mode RFC 6716 §3.4 enumerates for a malformed packet, plus
property-style sweeps proving the §4.2.3 / §4.2.4 SILK header
decoder is panic-free on any truncation of a previously-valid
bitstream (§4.1.4 zero-extension contract). Covers R1 (empty
packet), R2 (frame > 1275 B for codes 0 and 1, plus the §3.2.1
boundary at 1275 B), R3 (code-1 odd body length), R4 (code-2
length-byte truncations + length > remaining + DTX boundary), R5
(M = 0+M > 48rejection), R6 (CBRR % M != 0), R7 (VBR
declared length overrun), §3.2.5 padding-chain pathologies, TOC
total-function self-consistency, §4.2.3 / §4.2.4 truncation
panic-freeness across(num_silk_frames, stereo)× prefix-length
1..=32, §4.2.4 LBRR-bitmap-never-zero invariant for 40 / 60 ms,
mono channel never emits side state, parsed-frame slice
lifetimes, and a code × body-len short-packet panic sweep. Test
totals: 362 lib + 20 integration = 382 (was 362 lib + 0
integration after round 21). -
Clean-room round 21 (2026-05-27): §3.1 / §4.2 framing dispatch —
a newframingmodule exposingOpusFrameRouting,OperatingMode,
andSilkBandwidth.OpusFrameRouting::from_tocturns the parsed
OpusTocByteinto the per-Opus-frame dispatch decision a §4 decoder
needs before it touches the range coder:operating_mode— SilkOnly / Hybrid / CeltOnly from §3.1 Table 2.silk_layer/celt_layer— which layers are present.silk_bandwidth— internal SILK bandwidth (NB / MB / WB), pinned
to WB for every Hybrid frame regardless of the TOC's SWB / FB per
RFC 6716 §4.2 first paragraph ("the LP layer itself still only runs
in WB").silk_frames_per_channel— §4.2.2 LP-layer organisation (1 for
10 / 20 ms Opus frames, 2 for 40 ms, 3 for 60 ms;Nonefor
CELT-only).total_silk_frames— channel-count × per-channel SILK frames.has_per_frame_lbrr_bits— §4.2.4 duration gate (true for SILK-
bearing frames longer than 20 ms).
Thirteen new unit tests cover the SILK-only Table 2 row-by-row
expectations (12 cells), the Hybrid WB-pin, the CELT-only frames
sweep across mono/stereo, the §4.2.4 per-frame LBRR gate against
every Table 2 cell, thetotal_silk_framesformula across all 32
configs × {mono, stereo}, a 60 ms stereo SILK-only worked example,
thec-bit independence of the routing, the channel-mapping
pass-through, and thesilk_layer ⇔ silk_bandwidth.is_some() ⇔ silk_frames_per_channel.is_some()invariants across the entire
Table 2 grid. -
Clean-room round 20 (2026-05-26): first CELT-layer fragment —
the RFC 6716 §4.3 / Table 56 pre-band header symbols behind a new
celt_headermodule (CeltHeaderPrefix/CeltPostFilter).silence—dec_icdfagainst the 2-entry{32767, 1}/32768
iCDF[1, 0]at ftb=15. When the flag fires t...