mirror of
https://github.com/google/liblc3.git
synced 2026-04-21 23:24:50 +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
198
test/sns.py
198
test/sns.py
@@ -52,7 +52,7 @@ class Sns:
|
||||
|
||||
def spectral_shaping(self, scf, inv, x):
|
||||
|
||||
## 3.3.7.4 Scale factors interpolation
|
||||
## Scale factors interpolation
|
||||
|
||||
scf_i = np.empty(4*len(scf))
|
||||
scf_i[0 ] = scf[0]
|
||||
@@ -64,20 +64,35 @@ class Sns:
|
||||
scf_i[62 ] = scf[15 ] + 1/8 * (scf[15] - scf[14 ])
|
||||
scf_i[63 ] = scf[15 ] + 3/8 * (scf[15] - scf[14 ])
|
||||
|
||||
n2 = 64 - min(len(x), 64)
|
||||
nb = len(T.I[self.dt][self.sr]) - 1
|
||||
|
||||
for i in range(n2):
|
||||
scf_i[i] = 0.5 * (scf_i[2*i] + scf_i[2*i+1])
|
||||
scf_i = np.append(scf_i[:n2], scf_i[2*n2:])
|
||||
if nb < 32:
|
||||
n4 = round(abs(1-32/nb)*nb)
|
||||
n2 = nb - n4
|
||||
|
||||
for i in range(n4):
|
||||
scf_i[i] = np.mean(scf_i[4*i:4*i+4])
|
||||
|
||||
for i in range(n4, n4+n2):
|
||||
scf_i[i] = np.mean(scf_i[2*n4+2*i:2*n4+2*i+2])
|
||||
|
||||
scf_i = scf_i[:n4+n2]
|
||||
|
||||
elif nb < 64:
|
||||
n2 = 64 - nb
|
||||
|
||||
for i in range(n2):
|
||||
scf_i[i] = np.mean(scf_i[2*i:2*i+2])
|
||||
scf_i = np.append(scf_i[:n2], scf_i[2*n2:])
|
||||
|
||||
g_sns = np.power(2, [ -scf_i, scf_i ][inv])
|
||||
|
||||
## 3.3.7.4 Spectral shaping
|
||||
## Spectral shaping
|
||||
|
||||
y = np.empty(len(x))
|
||||
I = T.I[self.dt][self.sr]
|
||||
|
||||
for b in range(len(g_sns)):
|
||||
for b in range(nb):
|
||||
y[I[b]:I[b+1]] = x[I[b]:I[b+1]] * g_sns[b]
|
||||
|
||||
return y
|
||||
@@ -93,36 +108,49 @@ class SnsAnalysis(Sns):
|
||||
|
||||
dt = self.dt
|
||||
|
||||
## 3.3.7.2.1 Padding
|
||||
## Padding
|
||||
|
||||
n2 = 64 - len(e)
|
||||
if len(e) < 32:
|
||||
n4 = round(abs(1-32/len(e))*len(e))
|
||||
n2 = len(e) - n4
|
||||
|
||||
e = np.append(np.empty(n2), e)
|
||||
for i in range(n2):
|
||||
e[2*i+0] = e[2*i+1] = e[n2+i]
|
||||
e = np.append(np.zeros(3*n4+n2), e)
|
||||
for i in range(n4):
|
||||
e[4*i+0] = e[4*i+1] = \
|
||||
e[4*i+2] = e[4*i+3] = e[3*n4+n2+i]
|
||||
|
||||
## 3.3.7.2.2 Smoothing
|
||||
for i in range(2*n4, 2*n4+n2):
|
||||
e[2*i+0] = e[2*i+1] = e[2*n4+n2+i]
|
||||
|
||||
elif len(e) < 64:
|
||||
n2 = 64 - len(e)
|
||||
|
||||
e = np.append(np.empty(n2), e)
|
||||
for i in range(n2):
|
||||
e[2*i+0] = e[2*i+1] = e[n2+i]
|
||||
|
||||
## Smoothing
|
||||
|
||||
e_s = np.zeros(len(e))
|
||||
e_s[0 ] = 0.75 * e[0 ] + 0.25 * e[1 ]
|
||||
e_s[1:63] = 0.25 * e[0:62] + 0.5 * e[1:63] + 0.25 * e[2:64]
|
||||
e_s[ 63] = 0.25 * e[ 62] + 0.75 * e[ 63]
|
||||
|
||||
## 3.3.7.2.3 Pre-emphasis
|
||||
## Pre-emphasis
|
||||
|
||||
g_tilt = [ 14, 18, 22, 26, 30 ][self.sr]
|
||||
e_p = e_s * (10 ** ((np.arange(64) * g_tilt) / 630))
|
||||
|
||||
## 3.3.7.2.4 Noise floor
|
||||
## Noise floor
|
||||
|
||||
noise_floor = max(np.average(e_p) * (10 ** (-40/10)), 2 ** -32)
|
||||
e_p = np.fmax(e_p, noise_floor * np.ones(len(e)))
|
||||
|
||||
## 3.3.7.2.5 Logarithm
|
||||
## Logarithm
|
||||
|
||||
e_l = np.log2(10 ** -31 + e_p) / 2
|
||||
|
||||
## 3.3.7.2.6 Band energy grouping
|
||||
## Band energy grouping
|
||||
|
||||
w = [ 1/12, 2/12, 3/12, 3/12, 2/12, 1/12 ]
|
||||
|
||||
@@ -131,18 +159,18 @@ class SnsAnalysis(Sns):
|
||||
e_4[1:15] = [ np.sum(w * e_l[4*i-1:4*i+5]) for i in range(1, 15) ]
|
||||
e_4[ 15] = np.sum(w[:5] * e_l[59:64]) + w[5] * e_l[63]
|
||||
|
||||
## 3.3.7.2.7 Mean removal and scaling, attack handling
|
||||
## Mean removal and scaling, attack handling
|
||||
|
||||
scf = 0.85 * (e_4 - np.average(e_4))
|
||||
|
||||
scf_a = np.zeros(len(scf))
|
||||
scf_a[0 ] = np.average(scf[:3])
|
||||
scf_a[1 ] = np.average(scf[:4])
|
||||
scf_a[2:14] = [ np.average(scf[i:i+5]) for i in range(12) ]
|
||||
scf_a[ 14] = np.average(scf[12:])
|
||||
scf_a[ 15] = np.average(scf[13:])
|
||||
scf_a[0 ] = np.mean(scf[:3])
|
||||
scf_a[1 ] = np.mean(scf[:4])
|
||||
scf_a[2:14] = [ np.mean(scf[i:i+5]) for i in range(12) ]
|
||||
scf_a[ 14] = np.mean(scf[12:])
|
||||
scf_a[ 15] = np.mean(scf[13:])
|
||||
|
||||
scf_a = (0.5 if self.dt == T.DT_10M else 0.3) * \
|
||||
scf_a = (0.5 if self.dt != T.DT_7M5 else 0.3) * \
|
||||
(scf_a - np.average(scf_a))
|
||||
|
||||
return scf_a if att else scf
|
||||
@@ -167,7 +195,7 @@ class SnsAnalysis(Sns):
|
||||
|
||||
def quantize(self, scf):
|
||||
|
||||
## 3.3.7.3.2 Stage 1
|
||||
## Stage 1
|
||||
|
||||
dmse_lf = [ np.sum((scf[:8] - T.SNS_LFCB[i]) ** 2) for i in range(32) ]
|
||||
dmse_hf = [ np.sum((scf[8:] - T.SNS_HFCB[i]) ** 2) for i in range(32) ]
|
||||
@@ -178,19 +206,19 @@ class SnsAnalysis(Sns):
|
||||
st1 = np.append(T.SNS_LFCB[self.ind_lf], T.SNS_HFCB[self.ind_hf])
|
||||
r1 = scf - st1
|
||||
|
||||
## 3.3.7.3.3 Stage 2
|
||||
## Stage 2
|
||||
|
||||
t2_rot = fftpack.dct(r1, norm = 'ortho')
|
||||
x = np.abs(t2_rot)
|
||||
|
||||
## 3.3.7.3.3 Stage 2 Shape search, step 1
|
||||
## Stage 2 Shape search, step 1
|
||||
|
||||
K = 6
|
||||
|
||||
proj_fac = (K - 1) / sum(np.abs(t2_rot))
|
||||
y3 = np.floor(x * proj_fac).astype(int)
|
||||
|
||||
## 3.3.7.3.3 Stage 2 Shape search, step 2
|
||||
## Stage 2 Shape search, step 2
|
||||
|
||||
corr_xy = np.sum(y3 * x)
|
||||
energy_y = np.sum(y3 * y3)
|
||||
@@ -204,7 +232,7 @@ class SnsAnalysis(Sns):
|
||||
energy_y += 2*y3[n_best] + 1
|
||||
y3[n_best] += 1
|
||||
|
||||
## 3.3.7.3.3 Stage 2 Shape search, step 3
|
||||
## Stage 2 Shape search, step 3
|
||||
|
||||
K = 8
|
||||
|
||||
@@ -219,16 +247,16 @@ class SnsAnalysis(Sns):
|
||||
y2[n_best] += 1
|
||||
|
||||
|
||||
## 3.3.7.3.3 Stage 2 Shape search, step 4
|
||||
## Stage 2 Shape search, step 4
|
||||
|
||||
y1 = np.append(y2[:10], [0] * 6)
|
||||
|
||||
## 3.3.7.3.3 Stage 2 Shape search, step 5
|
||||
## Stage 2 Shape search, step 5
|
||||
|
||||
corr_xy -= sum(y2[10:] * x[10:])
|
||||
energy_y -= sum(y2[10:] * y2[10:])
|
||||
|
||||
## 3.3.7.3.3 Stage 2 Shape search, step 6
|
||||
## Stage 2 Shape search, step 6
|
||||
|
||||
K = 10
|
||||
|
||||
@@ -240,7 +268,7 @@ class SnsAnalysis(Sns):
|
||||
energy_y += 2*y1[n_best] + 1
|
||||
y1[n_best] += 1
|
||||
|
||||
## 3.3.7.3.3 Stage 2 Shape search, step 7
|
||||
## Stage 2 Shape search, step 7
|
||||
|
||||
y0 = np.append(y1[:10], [ 0 ] * 6)
|
||||
|
||||
@@ -249,18 +277,18 @@ class SnsAnalysis(Sns):
|
||||
|
||||
y0[n_best] += 1
|
||||
|
||||
## 3.3.7.3.3 Stage 2 Shape search, step 8
|
||||
## Stage 2 Shape search, step 8
|
||||
|
||||
y0 *= np.sign(t2_rot).astype(int)
|
||||
y1 *= np.sign(t2_rot).astype(int)
|
||||
y2 *= np.sign(t2_rot).astype(int)
|
||||
y3 *= np.sign(t2_rot).astype(int)
|
||||
|
||||
## 3.3.7.3.3 Stage 2 Shape search, step 9
|
||||
## Stage 2 Shape search, step 9
|
||||
|
||||
xq = [ y / np.sqrt(sum(y ** 2)) for y in (y0, y1, y2, y3) ]
|
||||
|
||||
## 3.3.7.3.3 Shape and gain combination determination
|
||||
## Shape and gain combination determination
|
||||
|
||||
G = [ T.SNS_VQ_REG_ADJ_GAINS, T.SNS_VQ_REG_LF_ADJ_GAINS,
|
||||
T.SNS_VQ_NEAR_ADJ_GAINS, T.SNS_VQ_FAR_ADJ_GAINS ]
|
||||
@@ -273,7 +301,7 @@ class SnsAnalysis(Sns):
|
||||
|
||||
gain = G[self.shape][self.gain]
|
||||
|
||||
## 3.3.7.3.3 Enumeration of the selected PVQ pulse configurations
|
||||
## Enumeration of the selected PVQ pulse configurations
|
||||
|
||||
if self.shape == 0:
|
||||
(self.idx_a, self.ls_a) = self.enum_mpvq(y0[:10])
|
||||
@@ -288,7 +316,7 @@ class SnsAnalysis(Sns):
|
||||
(self.idx_a, self.ls_a) = self.enum_mpvq(y3)
|
||||
(self.idx_b, self.ls_b) = (None, None)
|
||||
|
||||
## 3.3.7.3.4 Synthesis of the Quantized scale factor
|
||||
## Synthesis of the Quantized scale factor
|
||||
|
||||
scf_q = st1 + gain * fftpack.idct(xq[self.shape], norm = 'ortho')
|
||||
|
||||
@@ -372,7 +400,7 @@ class SnsSynthesis(Sns):
|
||||
|
||||
def unquantize(self):
|
||||
|
||||
## 3.7.4.2.1-2 SNS VQ Decoding
|
||||
## SNS VQ Decoding
|
||||
|
||||
y = np.empty(16, dtype=np.intc)
|
||||
|
||||
@@ -387,11 +415,11 @@ class SnsSynthesis(Sns):
|
||||
elif self.shape == 3:
|
||||
y = self.deenum_mpvq(self.idx_a, self.ls_a, 6, 16)
|
||||
|
||||
## 3.7.4.2.3 Unit energy normalization
|
||||
## Unit energy normalization
|
||||
|
||||
y = y / np.sqrt(sum(y ** 2))
|
||||
|
||||
## 3.7.4.2.4 Reconstruction of the quantized scale factors
|
||||
## Reconstruction of the quantized scale factors
|
||||
|
||||
G = [ T.SNS_VQ_REG_ADJ_GAINS, T.SNS_VQ_REG_LF_ADJ_GAINS,
|
||||
T.SNS_VQ_NEAR_ADJ_GAINS, T.SNS_VQ_FAR_ADJ_GAINS ]
|
||||
@@ -465,7 +493,7 @@ def check_analysis(rng, dt, sr):
|
||||
|
||||
for i in range(10):
|
||||
x = rng.random(T.NE[dt][sr]) * 1e4
|
||||
e = rng.random(min(len(x), 64)) * 1e10
|
||||
e = rng.random(len(T.I[dt][sr]) - 1) * 1e10
|
||||
|
||||
for att in (0, 1):
|
||||
y = analysis.run(e, att, x)
|
||||
@@ -506,72 +534,78 @@ def check_synthesis(rng, dt, sr):
|
||||
|
||||
y = synthesis.run(x)
|
||||
y_c = lc3.sns_synthesize(dt, sr, synthesis.get_data(), x)
|
||||
ok = ok and np.amax(np.abs(y - y_c)) < 2e0
|
||||
ok = ok and np.amax(np.abs(1 - y/y_c)) < 1e-5
|
||||
|
||||
return ok
|
||||
|
||||
def check_analysis_appendix_c(dt):
|
||||
|
||||
i0 = dt - T.DT_7M5
|
||||
sr = T.SRATE_16K
|
||||
|
||||
ok = True
|
||||
|
||||
for i in range(len(C.E_B[dt])):
|
||||
for i in range(len(C.E_B[i0])):
|
||||
|
||||
scf = lc3.sns_compute_scale_factors(dt, sr, C.E_B[dt][i], False)
|
||||
ok = ok and np.amax(np.abs(scf - C.SCF[dt][i])) < 1e-4
|
||||
scf = lc3.sns_compute_scale_factors(dt, sr, C.E_B[i0][i], False)
|
||||
ok = ok and np.amax(np.abs(scf - C.SCF[i0][i])) < 1e-4
|
||||
|
||||
(lf, hf) = lc3.sns_resolve_codebooks(scf)
|
||||
ok = ok and lf == C.IND_LF[dt][i] and hf == C.IND_HF[dt][i]
|
||||
ok = ok and lf == C.IND_LF[i0][i] and hf == C.IND_HF[i0][i]
|
||||
|
||||
(y, yn, shape, gain) = lc3.sns_quantize(scf, lf, hf)
|
||||
ok = ok and np.any(y[0][:16] - C.SNS_Y0[dt][i] == 0)
|
||||
ok = ok and np.any(y[1][:10] - C.SNS_Y1[dt][i] == 0)
|
||||
ok = ok and np.any(y[2][:16] - C.SNS_Y2[dt][i] == 0)
|
||||
ok = ok and np.any(y[3][:16] - C.SNS_Y3[dt][i] == 0)
|
||||
ok = ok and shape == 2*C.SUBMODE_MSB[dt][i] + C.SUBMODE_LSB[dt][i]
|
||||
ok = ok and gain == C.G_IND[dt][i]
|
||||
ok = ok and np.any(y[0][:16] - C.SNS_Y0[i0][i] == 0)
|
||||
ok = ok and np.any(y[1][:10] - C.SNS_Y1[i0][i] == 0)
|
||||
ok = ok and np.any(y[2][:16] - C.SNS_Y2[i0][i] == 0)
|
||||
ok = ok and np.any(y[3][:16] - C.SNS_Y3[i0][i] == 0)
|
||||
ok = ok and shape == 2*C.SUBMODE_MSB[i0][i] + C.SUBMODE_LSB[i0][i]
|
||||
ok = ok and gain == C.G_IND[i0][i]
|
||||
|
||||
scf_q = lc3.sns_unquantize(lf, hf, yn[shape], shape, gain)
|
||||
ok = ok and np.amax(np.abs(scf_q - C.SCF_Q[dt][i])) < 1e-5
|
||||
ok = ok and np.amax(np.abs(scf_q - C.SCF_Q[i0][i])) < 1e-5
|
||||
|
||||
x = lc3.sns_spectral_shaping(dt, sr, C.SCF_Q[dt][i], False, C.X[dt][i])
|
||||
ok = ok and np.amax(np.abs(1 - x/C.X_S[dt][i])) < 1e-5
|
||||
x = lc3.sns_spectral_shaping(
|
||||
dt, sr, C.SCF_Q[i0][i], False, C.X[i0][i])
|
||||
ok = ok and np.amax(np.abs(1 - x/C.X_S[i0][i])) < 1e-5
|
||||
|
||||
(x, data) = lc3.sns_analyze(dt, sr, C.E_B[dt][i], False, C.X[dt][i])
|
||||
ok = ok and data['lfcb'] == C.IND_LF[dt][i]
|
||||
ok = ok and data['hfcb'] == C.IND_HF[dt][i]
|
||||
ok = ok and data['shape'] == \
|
||||
2*C.SUBMODE_MSB[dt][i] + C.SUBMODE_LSB[dt][i]
|
||||
ok = ok and data['gain'] == C.G_IND[dt][i]
|
||||
ok = ok and data['idx_a'] == C.IDX_A[dt][i]
|
||||
ok = ok and data['ls_a'] == C.LS_IND_A[dt][i]
|
||||
ok = ok and (C.IDX_B[dt][i] is None or
|
||||
data['idx_b'] == C.IDX_B[dt][i])
|
||||
ok = ok and (C.LS_IND_B[dt][i] is None or
|
||||
data['ls_b'] == C.LS_IND_B[dt][i])
|
||||
ok = ok and np.amax(np.abs(1 - x/C.X_S[dt][i])) < 1e-5
|
||||
(x, data) = lc3.sns_analyze(
|
||||
dt, sr, C.E_B[i0][i], False, C.X[i0][i])
|
||||
ok = ok and data['lfcb'] == C.IND_LF[i0][i]
|
||||
ok = ok and data['hfcb'] == C.IND_HF[i0][i]
|
||||
ok = ok and data['shape'] == 2*C.SUBMODE_MSB[i0][i] + \
|
||||
C.SUBMODE_LSB[i0][i]
|
||||
ok = ok and data['gain'] == C.G_IND[i0][i]
|
||||
ok = ok and data['idx_a'] == C.IDX_A[i0][i]
|
||||
ok = ok and data['ls_a'] == C.LS_IND_A[i0][i]
|
||||
ok = ok and (C.IDX_B[i0][i] is None or
|
||||
data['idx_b'] == C.IDX_B[i0][i])
|
||||
ok = ok and (C.LS_IND_B[i0][i] is None or
|
||||
data['ls_b'] == C.LS_IND_B[i0][i])
|
||||
ok = ok and np.amax(np.abs(1 - x/C.X_S[i0][i])) < 1e-5
|
||||
|
||||
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_TNS[dt])):
|
||||
for i in range(len(C.X_HAT_TNS[i0])):
|
||||
|
||||
data = {
|
||||
'lfcb' : C.IND_LF[dt][i], 'hfcb' : C.IND_HF[dt][i],
|
||||
'shape' : 2*C.SUBMODE_MSB[dt][i] + C.SUBMODE_LSB[dt][i],
|
||||
'gain' : C.G_IND[dt][i],
|
||||
'idx_a' : C.IDX_A[dt][i],
|
||||
'ls_a' : C.LS_IND_A[dt][i],
|
||||
'idx_b' : C.IDX_B[dt][i] if C.IDX_B[dt][i] is not None else 0,
|
||||
'ls_b' : C.LS_IND_B[dt][i] if C.LS_IND_B[dt][i] is not None else 0,
|
||||
'lfcb' : C.IND_LF[i0][i], 'hfcb' : C.IND_HF[i0][i],
|
||||
'shape' : 2*C.SUBMODE_MSB[i0][i] + C.SUBMODE_LSB[i0][i],
|
||||
'gain' : C.G_IND[i0][i],
|
||||
'idx_a' : C.IDX_A[i0][i],
|
||||
'ls_a' : C.LS_IND_A[i0][i],
|
||||
'idx_b' : C.IDX_B[i0][i] if C.IDX_B[i0][i] is not None else 0,
|
||||
'ls_b' : C.LS_IND_B[i0][i] if C.LS_IND_B[i0][i] is not None else 0,
|
||||
}
|
||||
|
||||
x = lc3.sns_synthesize(dt, sr, data, C.X_HAT_TNS[dt][i])
|
||||
ok = ok and np.amax(np.abs(x - C.X_HAT_SNS[dt][i])) < 1e0
|
||||
x = lc3.sns_synthesize(dt, sr, data, C.X_HAT_TNS[i0][i])
|
||||
ok = ok and np.amax(np.abs(x - C.X_HAT_SNS[i0][i])) < 1e0
|
||||
|
||||
return ok
|
||||
|
||||
@@ -585,9 +619,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