nx_fidelity.nx source
↩ module page · 86 lines · 3159 B
1// nx_fidelity.nx -- Calculates segmental SNR as a deci-dB fidelity metric for audio reconstruction quality.
2const FID_MAGIC_131072: i64 = 131072
3const FID_MAGIC_65536: i64 = 65536
4const FID_MAGIC_32768: i64 = 32768
5// nx_fidelity.nx -- AUDIO arc R6: a sovereign FIDELITY metric. Grades how
6// faithfully a reconstruction (a clone, a codec output, an LPC resynthesis)
7// matches a reference, so clone/codec quality is MEASURED, not asserted.
8//
9// Segmental SNR: per frame, 10*log10( sum(ref^2) / sum((ref-test)^2) ), averaged.
10// Higher dB = closer. Uses a sovereign integer log2 (normalize + 16-iteration
11// mantissa squaring, the classic fixed-point log) converted to dB via the
12// constant 10/log2(10). Returned in DECI-decibels (dB*10) for resolution; an
13// exact reconstruction (zero error) caps at 99.0 dB.
14//
15// Pure integer, NO floats, NO imports (caller owns the buffers).
16// nx_segsnr(ref, test, n, frame) -> deci-dB (dB*10)
17//
18// license_tier: ORIGINAL
19// module: nishi-core.audio.fidelity
20// capability: AUDIO_FIDELITY_METRIC
21
22const FID_LOG10_K: i64 = 197336 // 10/log2(10) = 3.0103 in Q16.16
23const FID_CAP_DDB: i64 = 990 // 99.0 dB cap (deci-dB) for near-zero error
24
25// log2(x) for a Q16.16 value x (65536 = 1.0); returns Q16.16.
26func _fid_log2_q16(x: i64) -> i64 {
27 if x <= 0 { return 0 }
28 var v: i64 = x
29 var ip: i64 = 0
30 while v >= FID_MAGIC_131072 { v = v >> 1; ip = ip + 1 } // bring into [1,2)
31 while v < FID_MAGIC_65536 { v = v << 1; ip = ip - 1 }
32 var result: i64 = ip << 16
33 var b: i64 = FID_MAGIC_32768 // mantissa bit weight (Q16 .5)
34 var i: i64 = 0
35 while i < 16 {
36 v = (v * v) >> 16
37 if v >= FID_MAGIC_131072 { v = v >> 1; result = result + b }
38 b = b >> 1
39 i = i + 1
40 }
41 return result
42}
43
44func _fid_i16(p: *u8, i: i64) -> i64 {
45 let lo: i64 = p[i * 2]
46 let hi: i64 = p[i * 2 + 1]
47 var v: i64 = lo | (hi << 8)
48 if v >= 0x8000 { v = v - 0x10000 }
49 return v
50}
51
52func nx_segsnr(ref: *u8, test: *u8, n: i64, frame: i64) -> i64 {
53 var nf: i64 = 0
54 var acc: i64 = 0
55 var f: i64 = 0
56 while (f + 1) * frame <= n {
57 let st: i64 = f * frame
58 var sig: i64 = 0
59 var err: i64 = 0
60 var j: i64 = 0
61 while j < frame {
62 let r: i64 = _fid_i16(ref, st + j)
63 let t: i64 = _fid_i16(test, st + j)
64 sig = sig + r * r
65 let d: i64 = r - t
66 err = err + d * d
67 j = j + 1
68 }
69 var ddb: i64 = FID_CAP_DDB // default = error ~0 -> cap
70 if sig == 0 { ddb = 0 }
71 if err > 0 {
72 if sig > 0 {
73 let ratio_q16: i64 = (sig << 16) / err
74 let l2: i64 = _fid_log2_q16(ratio_q16)
75 let db_q16: i64 = (l2 * FID_LOG10_K) >> 16 // 10*log10(ratio), Q16
76 ddb = (db_q16 * 10) >> 16 // deci-dB (can be <0)
77 if ddb > FID_CAP_DDB { ddb = FID_CAP_DDB }
78 }
79 }
80 acc = acc + ddb
81 nf = nf + 1
82 f = f + 1
83 }
84 if nf < 1 { return 0 }
85 return acc / nf
86}