mirror of
https://github.com/google/liblc3.git
synced 2026-05-01 11:08:00 +00:00
feature: Add 2.5 ms and 5 ms LC3 plus frame durations
fix: Check TNS bitstream data fix: LTPF Activation with 2.5 ms frame sizes
This commit is contained in:
committed by
Antoine Soulier
parent
a75f187e00
commit
149cb6537e
138
test/tns.py
138
test/tns.py
@@ -41,7 +41,25 @@ class Tns:
|
||||
SUB_LIM_7M5 = [ SUB_LIM_7M5_NB, SUB_LIM_7M5_WB,
|
||||
SUB_LIM_7M5_SSWB, SUB_LIM_7M5_SWB, SUB_LIM_7M5_FB ]
|
||||
|
||||
SUB_LIM = [ SUB_LIM_7M5, SUB_LIM_10M ]
|
||||
SUB_LIM_5M_NB = [ [ 6, 23, 40 ] ]
|
||||
SUB_LIM_5M_WB = [ [ 6, 43, 80 ] ]
|
||||
SUB_LIM_5M_SSWB = [ [ 6, 63, 120 ] ]
|
||||
SUB_LIM_5M_SWB = [ [ 6, 43, 80 ], [ 80, 120, 160 ] ]
|
||||
SUB_LIM_5M_FB = [ [ 6, 53, 100 ], [ 100, 150, 200 ] ]
|
||||
|
||||
SUB_LIM_5M = [ SUB_LIM_5M_NB, SUB_LIM_5M_WB,
|
||||
SUB_LIM_5M_SSWB, SUB_LIM_5M_SWB, SUB_LIM_5M_FB ]
|
||||
|
||||
SUB_LIM_2M5_NB = [ [ 3, 10, 20 ] ]
|
||||
SUB_LIM_2M5_WB = [ [ 3, 20, 40 ] ]
|
||||
SUB_LIM_2M5_SSWB = [ [ 3, 30, 60 ] ]
|
||||
SUB_LIM_2M5_SWB = [ [ 3, 40, 80 ] ]
|
||||
SUB_LIM_2M5_FB = [ [ 3, 50, 100 ] ]
|
||||
|
||||
SUB_LIM_2M5 = [ SUB_LIM_2M5_NB, SUB_LIM_2M5_WB,
|
||||
SUB_LIM_2M5_SSWB, SUB_LIM_2M5_SWB, SUB_LIM_2M5_FB ]
|
||||
|
||||
SUB_LIM = [ SUB_LIM_2M5, SUB_LIM_5M, SUB_LIM_7M5, SUB_LIM_10M ]
|
||||
|
||||
FREQ_LIM_10M_NB = [ 12, 80 ]
|
||||
FREQ_LIM_10M_WB = [ 12, 160 ]
|
||||
@@ -61,7 +79,25 @@ class Tns:
|
||||
FREQ_LIM_7M5 = [ FREQ_LIM_7M5_NB, FREQ_LIM_7M5_WB,
|
||||
FREQ_LIM_7M5_SSWB, FREQ_LIM_7M5_SWB, FREQ_LIM_7M5_FB ]
|
||||
|
||||
FREQ_LIM = [ FREQ_LIM_7M5, FREQ_LIM_10M ]
|
||||
FREQ_LIM_5M_NB = [ 6, 40 ]
|
||||
FREQ_LIM_5M_WB = [ 6, 80 ]
|
||||
FREQ_LIM_5M_SSWB = [ 6, 120 ]
|
||||
FREQ_LIM_5M_SWB = [ 6, 80, 160 ]
|
||||
FREQ_LIM_5M_FB = [ 6, 100, 200 ]
|
||||
|
||||
FREQ_LIM_5M = [ FREQ_LIM_5M_NB, FREQ_LIM_5M_WB,
|
||||
FREQ_LIM_5M_SSWB, FREQ_LIM_5M_SWB, FREQ_LIM_5M_FB ]
|
||||
|
||||
FREQ_LIM_2M5_NB = [ 3, 20 ]
|
||||
FREQ_LIM_2M5_WB = [ 3, 40 ]
|
||||
FREQ_LIM_2M5_SSWB = [ 3, 60 ]
|
||||
FREQ_LIM_2M5_SWB = [ 3, 80 ]
|
||||
FREQ_LIM_2M5_FB = [ 3, 100 ]
|
||||
|
||||
FREQ_LIM_2M5 = [ FREQ_LIM_2M5_NB, FREQ_LIM_2M5_WB,
|
||||
FREQ_LIM_2M5_SSWB, FREQ_LIM_2M5_SWB, FREQ_LIM_2M5_FB ]
|
||||
|
||||
FREQ_LIM = [ FREQ_LIM_2M5, FREQ_LIM_5M, FREQ_LIM_7M5, FREQ_LIM_10M ]
|
||||
|
||||
def __init__(self, dt):
|
||||
|
||||
@@ -72,9 +108,11 @@ class Tns:
|
||||
|
||||
def get_data(self):
|
||||
|
||||
rc = np.append(self.rc - 8, np.zeros((2, 8 - len(self.rc[0]))), axis=1)
|
||||
|
||||
return { 'nfilters' : self.nfilters,
|
||||
'lpc_weighting' : self.lpc_weighting,
|
||||
'rc_order' : self.rc_order, 'rc' : self.rc - 8 }
|
||||
'rc_order' : self.rc_order, 'rc' : rc }
|
||||
|
||||
def get_nbits(self):
|
||||
|
||||
@@ -105,17 +143,18 @@ class TnsAnalysis(Tns):
|
||||
### Normalized autocorrelation function
|
||||
|
||||
S = Tns.SUB_LIM[self.dt][bw][f]
|
||||
maxorder = [ 4, 8 ][self.dt > T.DT_5M]
|
||||
|
||||
r = np.append([ 3 ], np.zeros(8))
|
||||
e = [ sum(x[S[s]:S[s+1]] ** 2) for s in range(3) ]
|
||||
r = np.append([ 3 ], np.zeros(maxorder))
|
||||
e = [ sum(x[S[s]:S[s+1]] ** 2) for s in range(len(S)-1) ]
|
||||
|
||||
for k in range(len(r) if sum(e) > 0 else 0):
|
||||
c = [ np.dot(x[S[s]:S[s+1]-k], x[S[s]+k:S[s+1]])
|
||||
for s in range(3) ]
|
||||
for s in range(len(S)-1) ]
|
||||
|
||||
r[k] = np.sum( np.array(c) / np.array(e) )
|
||||
|
||||
r *= np.exp(-0.5 * (0.02 * np.pi * np.arange(9)) ** 2)
|
||||
r *= np.exp(-0.5 * (0.02 * np.pi * np.arange(1+maxorder)) ** 2)
|
||||
|
||||
### Levinson-Durbin recursion
|
||||
|
||||
@@ -140,10 +179,10 @@ class TnsAnalysis(Tns):
|
||||
|
||||
def coeffs_reflexion(self, a):
|
||||
|
||||
rc = np.zeros(8)
|
||||
rc = np.zeros(len(a)-1)
|
||||
b = a.copy()
|
||||
|
||||
for k in range(8, 0, -1):
|
||||
for k in range(len(rc), 0, -1):
|
||||
rc[k-1] = b[k]
|
||||
e = 1 - rc[k-1] ** 2
|
||||
b[1:k] = (b[1:k] - rc[k-1] * b[k-1:0:-1]) / e
|
||||
@@ -186,9 +225,12 @@ class TnsAnalysis(Tns):
|
||||
y = x.copy()
|
||||
|
||||
self.nfilters = len(Tns.SUB_LIM[self.dt][bw])
|
||||
self.lpc_weighting = nbytes * 8 < 48 * T.DT_MS[self.dt]
|
||||
maxorder = [ 4, 8 ][self.dt > T.DT_5M]
|
||||
|
||||
self.lpc_weighting = nbytes < 120 * (1 + self.dt) / 8
|
||||
|
||||
self.rc_order = np.zeros(2, dtype=np.intc)
|
||||
self.rc = np.zeros((2, 8), dtype=np.intc)
|
||||
self.rc = np.zeros((2, maxorder), dtype=np.intc)
|
||||
|
||||
for f in range(self.nfilters):
|
||||
|
||||
@@ -258,7 +300,7 @@ class TnsSynthesis(Tns):
|
||||
def load(self, b, bw, nbytes):
|
||||
|
||||
self.nfilters = len(Tns.SUB_LIM[self.dt][bw])
|
||||
self.lpc_weighting = nbytes * 8 < 48 * T.DT_MS[self.dt]
|
||||
self.lpc_weighting = nbytes < 120 * (1 + self.dt) / 8
|
||||
self.rc_order = np.zeros(2, dtype=np.intc)
|
||||
self.rc = 8 * np.ones((2, 8), dtype=np.intc)
|
||||
|
||||
@@ -316,14 +358,14 @@ def check_analysis(rng, dt, bw):
|
||||
y = analysis.run(x, bw, nn_flag, nbytes)
|
||||
(y_c, data_c) = lc3.tns_analyze(dt, bw, nn_flag, nbytes, x)
|
||||
|
||||
ok = ok and data_c['nfilters'] == analysis.nfilters
|
||||
ok = ok and data_c['lpc_weighting'] == analysis.lpc_weighting
|
||||
ok = ok and data_c['nfilters'] == analysis.nfilters
|
||||
for f in range(analysis.nfilters):
|
||||
rc_order = analysis.rc_order[f]
|
||||
rc_order_c = data_c['rc_order'][f]
|
||||
rc_c = 8 + data_c['rc'][f]
|
||||
ok = ok and rc_order_c == rc_order
|
||||
ok = ok and not np.any((rc_c - analysis.rc[f])[:rc_order])
|
||||
ok = ok and not np.any(rc_c[:rc_order] - analysis.rc[f][:rc_order])
|
||||
|
||||
ok = ok and lc3.tns_get_nbits(data_c) == analysis.get_nbits()
|
||||
ok = ok and np.amax(np.abs(y_c - y)) < 1e-2
|
||||
@@ -339,74 +381,78 @@ def check_synthesis(rng, dt, bw):
|
||||
|
||||
x = rng.random(T.NE[dt][bw]) * 1e2
|
||||
|
||||
synthesis.nfilters = 1 + int(bw >= T.SRATE_32K)
|
||||
synthesis.rc_order = rng.integers(0, 9, 2)
|
||||
maxorder = [ 4, 8 ][dt > T.DT_5M]
|
||||
synthesis.nfilters = 1 + int(dt >= T.DT_5M and bw >= T.SRATE_32K)
|
||||
synthesis.rc_order = rng.integers(0, 1+maxorder, 2)
|
||||
synthesis.rc = rng.integers(0, 17, 16).reshape(2, 8)
|
||||
|
||||
y = synthesis.run(x, bw)
|
||||
y_c = lc3.tns_synthesize(dt, bw, synthesis.get_data(), x)
|
||||
|
||||
ok = ok and np.amax(np.abs(y_c - y) < 1e-6)
|
||||
ok = ok and np.amax(np.abs(y_c - y) < 1e-4)
|
||||
|
||||
return ok
|
||||
|
||||
def check_analysis_appendix_c(dt):
|
||||
|
||||
i0 = dt - T.DT_7M5
|
||||
sr = T.SRATE_16K
|
||||
|
||||
ok = True
|
||||
|
||||
fs = Tns.FREQ_LIM[dt][sr][0]
|
||||
fe = Tns.FREQ_LIM[dt][sr][1]
|
||||
fs = Tns.FREQ_LIM[i0][sr][0]
|
||||
fe = Tns.FREQ_LIM[i0][sr][1]
|
||||
st = np.zeros(8)
|
||||
|
||||
for i in range(len(C.X_S[dt])):
|
||||
for i in range(len(C.X_S[i0])):
|
||||
|
||||
(_, a) = lc3.tns_compute_lpc_coeffs(dt, sr, C.X_S[dt][i])
|
||||
ok = ok and np.amax(np.abs(a[0] - C.TNS_LEV_A[dt][i])) < 1e-5
|
||||
(_, a) = lc3.tns_compute_lpc_coeffs(dt, sr, C.X_S[i0][i])
|
||||
ok = ok and np.amax(np.abs(a[0] - C.TNS_LEV_A[i0][i])) < 1e-5
|
||||
|
||||
rc = lc3.tns_lpc_reflection(a[0])
|
||||
ok = ok and np.amax(np.abs(rc - C.TNS_LEV_RC[dt][i])) < 1e-5
|
||||
rc = lc3.tns_lpc_reflection(dt, a[0])
|
||||
ok = ok and np.amax(np.abs(rc - C.TNS_LEV_RC[i0][i])) < 1e-5
|
||||
|
||||
(rc_order, rc_i) = lc3.tns_quantize_rc(C.TNS_LEV_RC[dt][i])
|
||||
ok = ok and rc_order == C.RC_ORDER[dt][i][0]
|
||||
ok = ok and np.any((rc_i + 8) - C.RC_I_1[dt][i] == 0)
|
||||
(rc_order, rc_i) = lc3.tns_quantize_rc(dt, C.TNS_LEV_RC[i0][i])
|
||||
ok = ok and rc_order == C.RC_ORDER[i0][i][0]
|
||||
ok = ok and np.any((rc_i + 8) - C.RC_I_1[i0][i] == 0)
|
||||
|
||||
rc_q = lc3.tns_unquantize_rc(rc_i, rc_order)
|
||||
ok = ok and np.amax(np.abs(rc_q - C.RC_Q_1[dt][i])) < 1e-6
|
||||
ok = ok and np.amax(np.abs(rc_q - C.RC_Q_1[i0][i])) < 1e-6
|
||||
|
||||
(x, side) = lc3.tns_analyze(dt, sr, False, C.NBYTES[dt], C.X_S[dt][i])
|
||||
(x, side) = lc3.tns_analyze(dt, sr, False, C.NBYTES[i0], C.X_S[i0][i])
|
||||
ok = ok and side['nfilters'] == 1
|
||||
ok = ok and side['rc_order'][0] == C.RC_ORDER[dt][i][0]
|
||||
ok = ok and not np.any((side['rc'][0] + 8) - C.RC_I_1[dt][i])
|
||||
ok = ok and lc3.tns_get_nbits(side) == C.NBITS_TNS[dt][i]
|
||||
ok = ok and np.amax(np.abs(x - C.X_F[dt][i])) < 1e-3
|
||||
ok = ok and side['rc_order'][0] == C.RC_ORDER[i0][i][0]
|
||||
ok = ok and not np.any((side['rc'][0] + 8) - C.RC_I_1[i0][i])
|
||||
ok = ok and lc3.tns_get_nbits(side) == C.NBITS_TNS[i0][i]
|
||||
ok = ok and np.amax(np.abs(x - C.X_F[i0][i])) < 1e-3
|
||||
|
||||
return ok
|
||||
|
||||
def check_synthesis_appendix_c(dt):
|
||||
|
||||
i0 = dt - T.DT_7M5
|
||||
sr = T.SRATE_16K
|
||||
|
||||
ok = True
|
||||
|
||||
for i in range(len(C.X_HAT_Q[dt])):
|
||||
for i in range(len(C.X_HAT_Q[i0])):
|
||||
|
||||
side = {
|
||||
'nfilters' : 1,
|
||||
'lpc_weighting' : C.NBYTES[dt] * 8 < 48 * T.DT_MS[dt],
|
||||
'rc_order': C.RC_ORDER[dt][i],
|
||||
'rc': [ C.RC_I_1[dt][i] - 8, C.RC_I_2[dt][i] - 8 ]
|
||||
'lpc_weighting' : C.NBYTES[i0] < 120 * (1 + dt) / 8,
|
||||
'rc_order': C.RC_ORDER[i0][i],
|
||||
'rc': [ C.RC_I_1[i0][i] - 8, C.RC_I_2[i0][i] - 8 ]
|
||||
}
|
||||
|
||||
g_int = C.GG_IND_ADJ[dt][i] + C.GG_OFF[dt][i]
|
||||
x = C.X_HAT_Q[dt][i] * (10 ** (g_int / 28))
|
||||
g_int = C.GG_IND_ADJ[i0][i] + C.GG_OFF[i0][i]
|
||||
x = C.X_HAT_Q[i0][i] * (10 ** (g_int / 28))
|
||||
|
||||
x = lc3.tns_synthesize(dt, sr, side, x)
|
||||
ok = ok and np.amax(np.abs(x - C.X_HAT_TNS[dt][i])) < 1e-3
|
||||
|
||||
if dt != T.DT_10M:
|
||||
return ok
|
||||
ok = ok and np.amax(np.abs(x - C.X_HAT_TNS[i0][i])) < 1e-3
|
||||
|
||||
sr = T.SRATE_48K
|
||||
if dt != T.DT_10M:
|
||||
return ok
|
||||
|
||||
side = {
|
||||
'nfilters' : 2,
|
||||
@@ -431,9 +477,9 @@ def check():
|
||||
ok = ok and check_analysis(rng, dt, sr)
|
||||
ok = ok and check_synthesis(rng, dt, sr)
|
||||
|
||||
for dt in range(T.NUM_DT):
|
||||
ok = ok and check_analysis_appendix_c(dt)
|
||||
ok = ok and check_synthesis_appendix_c(dt)
|
||||
for dt in range(T.DT_7M5, T.NUM_DT):
|
||||
check_analysis_appendix_c(dt)
|
||||
check_synthesis_appendix_c(dt)
|
||||
|
||||
return ok
|
||||
|
||||
|
||||
Reference in New Issue
Block a user