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:
anonymix007
2023-12-13 10:56:20 -08:00
committed by Antoine Soulier
parent a75f187e00
commit 149cb6537e
43 changed files with 3095 additions and 1628 deletions

View File

@@ -135,7 +135,7 @@ extern "C" {
#define LC3_MIN_FRAME_BYTES 20
#define LC3_MAX_FRAME_BYTES 400
#define LC3_MIN_FRAME_SAMPLES __LC3_NS( 7500, 8000)
#define LC3_MIN_FRAME_SAMPLES __LC3_NS( 2500, 8000)
#define LC3_MAX_FRAME_SAMPLES __LC3_NS(10000, 48000)
@@ -146,7 +146,8 @@ extern "C" {
*/
#define LC3_CHECK_DT_US(us) \
( ((us) == 7500) || ((us) == 10000) )
( ((us) == 2500) || ((us) == 5000) || \
((us) == 7500) || ((us) == 10000) )
#define LC3_CHECK_SR_HZ(sr) \
( ((sr) == 8000) || ((sr) == 16000) || ((sr) == 24000) || \
@@ -196,7 +197,7 @@ typedef LC3_DECODER_MEM_T(10000, 48000) lc3_decoder_mem_48k_t;
/**
* Return the number of PCM samples in a frame
* dt_us Frame duration in us, 7500 or 10000
* dt_us Frame duration in us, 2500, 5000, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* return Number of PCM samples, -1 on bad parameters
*/
@@ -204,7 +205,7 @@ int lc3_frame_samples(int dt_us, int sr_hz);
/**
* Return the size of frames, from bitrate
* dt_us Frame duration in us, 7500 or 10000
* dt_us Frame duration in us, 2500, 5000, 7500 or 10000
* bitrate Target bitrate in bit per second
* return The floor size in bytes of the frames, -1 on bad parameters
*/
@@ -212,7 +213,7 @@ int lc3_frame_bytes(int dt_us, int bitrate);
/**
* Resolve the bitrate, from the size of frames
* dt_us Frame duration in us, 7500 or 10000
* dt_us Frame duration in us, 2500, 5000, 7500 or 10000
* nbytes Size in bytes of the frames
* return The according bitrate in bps, -1 on bad parameters
*/
@@ -220,7 +221,7 @@ int lc3_resolve_bitrate(int dt_us, int nbytes);
/**
* Return algorithmic delay, as a number of samples
* dt_us Frame duration in us, 7500 or 10000
* dt_us Frame duration in us, 2500, 5000, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* return Number of algorithmic delay samples, -1 on bad parameters
*/
@@ -228,7 +229,7 @@ int lc3_delay_samples(int dt_us, int sr_hz);
/**
* Return size needed for an encoder
* dt_us Frame duration in us, 7500 or 10000
* dt_us Frame duration in us, 2500, 5000, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* return Size of then encoder in bytes, 0 on bad parameters
*
@@ -239,7 +240,7 @@ unsigned lc3_encoder_size(int dt_us, int sr_hz);
/**
* Setup encoder
* dt_us Frame duration in us, 7500 or 10000
* dt_us Frame duration in us, 2500, 5000, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* sr_pcm_hz Input samplerate, downsampling option of input, or 0
* mem Encoder memory space, aligned to pointer type
@@ -268,7 +269,7 @@ int lc3_encode(lc3_encoder_t encoder, enum lc3_pcm_format fmt,
/**
* Return size needed for an decoder
* dt_us Frame duration in us, 7500 or 10000
* dt_us Frame duration in us, 2500, 5000, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* return Size of then decoder in bytes, 0 on bad parameters
*
@@ -279,7 +280,7 @@ unsigned lc3_decoder_size(int dt_us, int sr_hz);
/**
* Setup decoder
* dt_us Frame duration in us, 7500 or 10000
* dt_us Frame duration in us, 2500, 5000, 7500 or 10000
* sr_hz Samplerate in Hz, 8000, 16000, 24000, 32000 or 48000
* sr_pcm_hz Output samplerate, upsampling option of output (or 0)
* mem Decoder memory space, aligned to pointer type

View File

@@ -25,46 +25,55 @@
/**
* Return number of samples, delayed samples and
* encoded spectrum coefficients within a frame
* - For encoding, keep 1.25 ms of temporal winodw
* encoded spectrum coefficients within a frame.
*
* - The number of MDCT delayed samples is the sum of half a frame and
* an ovelap of future by 1.25 ms (2.5ms, 5ms and 10ms frame durations)
* or 2 ms (7.5ms frame duration).
*
* - For encoding, keep 1.25 ms of temporal previous samples
* - For decoding, keep 18 ms of history, aligned on frames, and a frame
*/
#define __LC3_NS(dt_us, sr_hz) \
( (dt_us * sr_hz) / 1000 / 1000 )
( (dt_us) * (sr_hz) / 1000 / 1000 )
#define __LC3_ND(dt_us, sr_hz) \
( (dt_us) == 7500 ? 23 * __LC3_NS(dt_us, sr_hz) / 30 \
: 5 * __LC3_NS(dt_us, sr_hz) / 8 )
( __LC3_NS(dt_us, sr_hz) / 2 + \
__LC3_NS((dt_us) == 7500 ? 2000 : 1250, sr_hz) )
#define __LC3_NT(sr_hz) \
( (5 * sr_hz) / 4000 )
( __LC3_NS(1250, sr_hz) )
#define __LC3_NH(dt_us, sr_hz) \
( ((3 - ((dt_us) >= 10000)) + 1) * __LC3_NS(dt_us, sr_hz) )
( __LC3_NS(18000, sr_hz) + 2*__LC3_NS(dt_us, sr_hz) - \
(__LC3_NS(18000, sr_hz) % __LC3_NS(dt_us, sr_hz)) )
/**
* Frame duration 7.5ms or 10ms
* Frame duration
*/
enum lc3_dt {
LC3_DT_7M5,
LC3_DT_10M,
LC3_DT_2M5 = 0,
LC3_DT_5M = 1,
LC3_DT_7M5 = 2,
LC3_DT_10M = 3,
LC3_NUM_DT
};
/**
* Sampling frequency
*/
enum lc3_srate {
LC3_SRATE_8K,
LC3_SRATE_16K,
LC3_SRATE_24K,
LC3_SRATE_32K,
LC3_SRATE_48K,
LC3_SRATE_8K = 0,
LC3_SRATE_16K = 1,
LC3_SRATE_24K = 2,
LC3_SRATE_32K = 3,
LC3_SRATE_48K = 4,
LC3_NUM_SRATE,
};

View File

@@ -27,14 +27,14 @@ bool lc3_attdet_run(enum lc3_dt dt, enum lc3_srate sr,
{
/* --- Check enabling --- */
const int nbytes_ranges[LC3_NUM_DT][LC3_NUM_SRATE - LC3_SRATE_32K][2] = {
[LC3_DT_7M5] = { { 61, 149 }, { 75, 149 } },
[LC3_DT_10M] = { { 81, INT_MAX }, { 100, INT_MAX } },
const int nbytes_ranges[][LC3_NUM_SRATE - LC3_SRATE_32K][2] = {
[LC3_DT_7M5 - LC3_DT_7M5] = { { 61, 149 }, { 75, 149 } },
[LC3_DT_10M - LC3_DT_7M5] = { { 81, INT_MAX }, { 100, INT_MAX } },
};
if (sr < LC3_SRATE_32K ||
nbytes < nbytes_ranges[dt][sr - LC3_SRATE_32K][0] ||
nbytes > nbytes_ranges[dt][sr - LC3_SRATE_32K][1] )
if (dt < LC3_DT_7M5 || sr < LC3_SRATE_32K ||
nbytes < nbytes_ranges[dt - LC3_DT_7M5][sr - LC3_SRATE_32K][0] ||
nbytes > nbytes_ranges[dt - LC3_DT_7M5][sr - LC3_SRATE_32K][1] )
return 0;
/* --- Filtering & Energy calculation --- */

View File

@@ -16,13 +16,6 @@
*
******************************************************************************/
/**
* LC3 - Time domain attack detector
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_ATTDET_H
#define __LC3_ATTDET_H

View File

@@ -17,8 +17,6 @@
******************************************************************************/
/**
* LC3 - Bitstream management
*
* The bitstream is written by the 2 ends of the buffer :
*
* - Arthmetic coder put bits while increasing memory addresses
@@ -56,10 +54,6 @@
* - The procedure `lc3_check_bits()` returns indication that read has been
* made crossing the other bit plane.
*
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*
*/
#ifndef __LC3_BITS_H

View File

@@ -25,29 +25,54 @@
enum lc3_bandwidth lc3_bwdet_run(
enum lc3_dt dt, enum lc3_srate sr, const float *e)
{
/* Bandwidth regions (Table 3.6) */
/* Bandwidth regions */
struct region { int is : 8; int ie : 8; };
static const struct region bws_table[LC3_NUM_DT]
[LC3_NUM_BANDWIDTH-1][LC3_NUM_BANDWIDTH-1] = {
#if !LC3_NPLUS
[LC3_DT_7M5] = {
{ { 51, 63+1 } },
{ { 45, 55+1 }, { 58, 63+1 } },
{ { 42, 51+1 }, { 53, 58+1 }, { 60, 63+1 } },
{ { 40, 48+1 }, { 51, 55+1 }, { 57, 60+1 }, { 61, 63+1 } },
},
static const struct region bws_table_2m5[][LC3_NUM_BANDWIDTH-1] = {
{ { 24, 34+1 } },
{ { 24, 32+1 }, { 35, 39+1 } },
{ { 24, 31+1 }, { 33, 38+1 }, { 39, 42+1 } },
{ { 22, 29+1 }, { 31, 35+1 }, { 37, 40+1 }, { 41, 43+1 } },
};
[LC3_DT_10M] = {
{ { 53, 63+1 } },
{ { 47, 56+1 }, { 59, 63+1 } },
{ { 44, 52+1 }, { 54, 59+1 }, { 60, 63+1 } },
{ { 41, 49+1 }, { 51, 55+1 }, { 57, 60+1 }, { 61, 63+1 } },
},
static const struct region bws_table_5m[][LC3_NUM_BANDWIDTH-1] = {
{ { 39, 49+1 } },
{ { 35, 44+1 }, { 47, 51+1 } },
{ { 34, 42+1 }, { 44, 49+1 }, { 50, 53+1 } },
{ { 32, 40+1 }, { 42, 46+1 }, { 48, 51+1 }, { 52, 54+1 } },
};
#endif /* !LC3_NPLUS */
static const struct region bws_table_7m5[][LC3_NUM_BANDWIDTH-1] = {
{ { 51, 63+1 } },
{ { 45, 55+1 }, { 58, 63+1 } },
{ { 42, 51+1 }, { 53, 58+1 }, { 60, 63+1 } },
{ { 40, 48+1 }, { 51, 55+1 }, { 57, 60+1 }, { 61, 63+1 } },
};
static const struct region bws_table_10m[][LC3_NUM_BANDWIDTH-1] = {
{ { 53, 63+1 } },
{ { 47, 56+1 }, { 59, 63+1 } },
{ { 44, 52+1 }, { 54, 59+1 }, { 60, 63+1 } },
{ { 41, 49+1 }, { 51, 55+1 }, { 57, 60+1 }, { 61, 63+1 } },
};
static const struct region (*bws_table[])[LC3_NUM_BANDWIDTH-1] = {
#if !LC3_NPLUS
[LC3_DT_2M5] = bws_table_2m5,
[LC3_DT_5M ] = bws_table_5m,
#endif /* !LC3_NPLUS */
[LC3_DT_7M5] = bws_table_7m5,
[LC3_DT_10M] = bws_table_10m,
};
static const int l_table[LC3_NUM_DT][LC3_NUM_BANDWIDTH-1] = {
[LC3_DT_2M5] = { 4, 4, 3, 1 },
[LC3_DT_5M ] = { 4, 4, 3, 1 },
[LC3_DT_7M5] = { 4, 4, 3, 2 },
[LC3_DT_10M] = { 4, 4, 3, 1 },
};

View File

@@ -16,13 +16,6 @@
*
******************************************************************************/
/**
* LC3 - Bandwidth detector
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_BWDET_H
#define __LC3_BWDET_H
@@ -31,7 +24,7 @@
/**
* Bandwidth detector (cf. 3.3.5)
* Bandwidth detector
* dt, sr Duration and samplerate of the frame
* e Energy estimation per bands
* return Return detected bandwitdth

View File

@@ -16,10 +16,6 @@
*
******************************************************************************/
/**
* LC3 - Common constants and types
*/
#ifndef __LC3_COMMON_H
#define __LC3_COMMON_H
@@ -87,7 +83,7 @@
*/
#define LC3_DT_US(dt) \
( (3 + (dt)) * 2500 )
( (1 + (dt)) * 2500 )
#define LC3_SRATE_KHZ(sr) \
( (1 + (sr) + ((sr) == LC3_SRATE_48K)) * 8 )
@@ -96,19 +92,20 @@
/**
* Return number of samples, delayed samples and
* encoded spectrum coefficients within a frame
* - For encoding, keep 1.25 ms for temporal window
*
* - The number of MDCT delayed samples is the sum of half a frame and
* an ovelap of future by 1.25 ms (2.5ms, 5ms and 10ms frame durations)
* or 2 ms (7.5ms frame duration).
*
* - For encoding, keep 1.25 ms of temporal previous samples
* - For decoding, keep 18 ms of history, aligned on frames, and a frame
*/
#define LC3_NS(dt, sr) \
( 20 * (3 + (dt)) * (1 + (sr) + ((sr) == LC3_SRATE_48K)) )
#define LC3_ND(dt, sr) \
( (dt) == LC3_DT_7M5 ? 23 * LC3_NS(dt, sr) / 30 \
: 5 * LC3_NS(dt, sr) / 8 )
( 20 * (1 + (dt)) * (1 + (sr) + ((sr) == LC3_SRATE_48K)) )
#define LC3_NE(dt, sr) \
( 20 * (3 + (dt)) * (1 + (sr)) )
( 20 * (1 + (dt)) * (1 + (sr)) )
#define LC3_MAX_NS \
LC3_NS(LC3_DT_10M, LC3_SRATE_48K)
@@ -116,11 +113,17 @@
#define LC3_MAX_NE \
LC3_NE(LC3_DT_10M, LC3_SRATE_48K)
#define LC3_ND(dt, sr) \
( LC3_NS(dt, sr) / 2 + \
(5 + 3*((dt) == LC3_DT_7M5)) * LC3_SRATE_KHZ(sr) / 4 )
#define LC3_NT(sr_hz) \
( (5 * LC3_SRATE_KHZ(sr)) / 4 )
#define LC3_NH(dt, sr) \
( ((3 - dt) + 1) * LC3_NS(dt, sr) )
( ((dt == LC3_DT_2M5 ? 8 : \
dt == LC3_DT_5M ? 4 : \
dt == LC3_DT_7M5 ? 3 : 2) + 1) * LC3_NS(dt, sr) )
/**

View File

@@ -26,30 +26,17 @@
bool lc3_energy_compute(
enum lc3_dt dt, enum lc3_srate sr, const float *x, float *e)
{
static const int n1_table[LC3_NUM_DT][LC3_NUM_SRATE] = {
[LC3_DT_7M5] = { 56, 34, 27, 24, 22 },
[LC3_DT_10M] = { 49, 28, 23, 20, 18 },
};
/* Mean the square of coefficients within each band */
/* First bands are 1 coefficient width */
int nb = lc3_num_bands[dt][sr];
const uint16_t *lim = lc3_band_lim[dt][sr];
int n1 = n1_table[dt][sr];
float e_sum[2] = { 0, 0 };
int iband;
int iband_h = nb - (const int []){
[LC3_DT_2M5] = 2, [LC3_DT_5M ] = 3,
[LC3_DT_7M5] = 4, [LC3_DT_10M] = 2 }[dt];
for (iband = 0; iband < n1; iband++) {
*e = x[iband] * x[iband];
e_sum[0] += *(e++);
}
/* Mean the square of coefficients within each band,
* note that 7.5ms 8KHz frame has more bands than samples */
int nb = LC3_MIN(LC3_NUM_BANDS, LC3_NS(dt, sr));
int iband_h = nb - 2*(2 - dt);
const int *lim = lc3_band_lim[dt][sr];
for (int i = lim[iband]; iband < nb; iband++) {
for (int iband = 0, i = lim[iband]; iband < nb; iband++) {
int ie = lim[iband+1];
int n = ie - i;
@@ -61,9 +48,6 @@ bool lc3_energy_compute(
e_sum[iband >= iband_h] += *(e++);
}
for (; iband < LC3_NUM_BANDS; iband++)
*(e++) = 0;
/* Return the near nyquist flag */
return e_sum[1] > 30 * e_sum[0];

View File

@@ -16,13 +16,6 @@
*
******************************************************************************/
/**
* LC3 - Energy estimation per band
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_ENERGY_H
#define __LC3_ENERGY_H

View File

@@ -16,10 +16,6 @@
*
******************************************************************************/
/**
* LC3 - Mathematics function approximation
*/
#ifndef __LC3_FASTMATH_H
#define __LC3_FASTMATH_H

View File

@@ -57,7 +57,9 @@ struct side_data {
*/
static enum lc3_dt resolve_dt(int us)
{
return us == 7500 ? LC3_DT_7M5 :
return us == 2500 ? LC3_DT_2M5 :
us == 5000 ? LC3_DT_5M :
us == 7500 ? LC3_DT_7M5 :
us == 10000 ? LC3_DT_10M : LC3_NUM_DT;
}
@@ -269,7 +271,7 @@ static void analyze(struct lc3_encoder *encoder,
/* --- Spectral --- */
float e[LC3_NUM_BANDS];
float e[LC3_MAX_BANDS];
lc3_mdct_forward(dt, sr_pcm, sr, xs, xd, xf);
@@ -534,7 +536,8 @@ static int decode(struct lc3_decoder *decoder,
if ((ret = lc3_spec_get_side(&bits, dt, sr, &side->spec)) < 0)
return ret;
lc3_tns_get_data(&bits, dt, side->bw, nbytes, &side->tns);
if ((ret = lc3_tns_get_data(&bits, dt, side->bw, nbytes, &side->tns)) < 0)
return ret;
side->pitch_present = lc3_get_bit(&bits);

View File

@@ -457,7 +457,7 @@ LC3_HOT static int argmax_weighted(
}
/**
* Interpolate from pitch detected value (3.3.9.8)
* Interpolate from pitch detected value
* x, n [-2..-1] Previous, [0..n] Current input
* d The phase of interpolation (0 to 3)
* return The interpolated vector
@@ -492,7 +492,7 @@ LC3_HOT static void interpolate(const int16_t *x, int n, int d, int16_t *y)
}
/**
* Interpolate autocorrelation (3.3.9.7)
* Interpolate autocorrelation
* x [-4..-1] Previous, [0..4] Current input
* d The phase of interpolation (-3 to 3)
* return The interpolated value
@@ -522,7 +522,7 @@ LC3_HOT static float interpolate_corr(const float *x, int d)
}
/**
* Pitch detection algorithm (3.3.9.5-6)
* Pitch detection algorithm
* ltpf Context of analysis
* x, n [-114..-17] Previous, [0..n-1] Current 6.4KHz samples
* tc Return the pitch-lag estimation
@@ -530,8 +530,8 @@ LC3_HOT static float interpolate_corr(const float *x, int d)
*
* The `x` vector is aligned on 32 bits
*/
static bool detect_pitch(
struct lc3_ltpf_analysis *ltpf, const int16_t *x, int n, int *tc)
static bool detect_pitch(struct lc3_ltpf_analysis *ltpf,
const int16_t *x, int n, int *tc)
{
float rm1, rm2;
float r[98];
@@ -562,7 +562,7 @@ static bool detect_pitch(
}
/**
* Pitch-lag parameter (3.3.9.7)
* Pitch-lag parameter
* x, n [-232..-28] Previous, [0..n-1] Current 12.8KHz samples, Q14
* tc Pitch-lag estimation
* pitch The pitch value, in fixed .4
@@ -615,7 +615,7 @@ bool lc3_ltpf_analyse(
/* --- Resampling to 12.8 KHz --- */
int z_12k8 = sizeof(ltpf->x_12k8) / sizeof(*ltpf->x_12k8);
int n_12k8 = dt == LC3_DT_7M5 ? 96 : 128;
int n_12k8 = (1 + dt) * 32;
memmove(ltpf->x_12k8, ltpf->x_12k8 + n_12k8,
(z_12k8 - n_12k8) * sizeof(*ltpf->x_12k8));
@@ -624,7 +624,7 @@ bool lc3_ltpf_analyse(
resample_12k8[sr](&ltpf->hp50, x, x_12k8, n_12k8);
x_12k8 -= (dt == LC3_DT_7M5 ? 44 : 24);
x_12k8 -= (dt == LC3_DT_7M5 ? 44 : 24);
/* --- Resampling to 6.4 KHz --- */
@@ -638,6 +638,13 @@ bool lc3_ltpf_analyse(
resample_6k4(x_12k8, x_6k4, n_6k4);
/* --- Enlarge for small frame size --- */
if (dt == LC3_DT_2M5) {
x_12k8 -= n_12k8, x_6k4 -= n_6k4;
n_12k8 += n_12k8; n_6k4 += n_6k4;
}
/* --- Pitch detection --- */
int tc, pitch = 0;
@@ -817,6 +824,11 @@ void lc3_ltpf_synthesize(enum lc3_dt dt, enum lc3_srate sr, int nbytes,
pitch = (pitch * LC3_SRATE_KHZ(sr) * 10 + 64) / 128;
int nbits = (nbytes*8 * 10000 + (dt_us/2)) / dt_us;
if (dt == LC3_DT_2M5)
nbits = (6 * nbits + 5) / 10;
if (dt == LC3_DT_5M)
nbits -= 160;
int g_idx = LC3_MAX(nbits / 80, 3 + (int)sr) - (3 + sr);
bool active = data && data->active && g_idx < 4;
@@ -832,30 +844,31 @@ void lc3_ltpf_synthesize(enum lc3_dt dt, enum lc3_srate sr, int nbytes,
/* --- Transition handling --- */
int ns = LC3_NS(dt, sr);
int nt = ns / (3 + dt);
float x0[MAX_FILTER_WIDTH];
int nt = ns / (1 + dt);
float x0[2][MAX_FILTER_WIDTH];
memcpy(x0[0], ltpf->x, (w-1) * sizeof(float));
memcpy(ltpf->x, x + ns - (w-1), (w-1) * sizeof(float));
if (active)
memcpy(x0, x + nt-(w-1), (w-1) * sizeof(float));
memcpy(x0[1], x + nt-(w-1), (w-1) * sizeof(float));
if (!ltpf->active && active)
synthesize[sr](xh, nh, pitch/4, ltpf->x, x, nt, c, 1);
synthesize[sr](xh, nh, pitch/4, x0[0], x, nt, c, 1);
else if (ltpf->active && !active)
synthesize[sr](xh, nh, ltpf->pitch/4, ltpf->x, x, nt, ltpf->c, -1);
synthesize[sr](xh, nh, ltpf->pitch/4, x0[0], x, nt, ltpf->c, -1);
else if (ltpf->active && active && ltpf->pitch == pitch)
synthesize[sr](xh, nh, pitch/4, ltpf->x, x, nt, c, 0);
synthesize[sr](xh, nh, pitch/4, x0[0], x, nt, c, 0);
else if (ltpf->active && active) {
synthesize[sr](xh, nh, ltpf->pitch/4, ltpf->x, x, nt, ltpf->c, -1);
synthesize[sr](xh, nh, ltpf->pitch/4, x0[0], x, nt, ltpf->c, -1);
synthesize[sr](xh, nh, pitch/4,
(x <= xh ? x + nh : x) - (w-1), x, nt, c, 1);
}
/* --- Remainder --- */
memcpy(ltpf->x, x + ns - (w-1), (w-1) * sizeof(float));
if (active)
synthesize[sr](xh, nh, pitch/4, x0, x + nt, ns-nt, c, 0);
if (active && ns > nt)
synthesize[sr](xh, nh, pitch/4, x0[1], x + nt, ns-nt, c, 0);
/* --- Update state --- */

View File

@@ -16,13 +16,6 @@
*
******************************************************************************/
/**
* LC3 - Long Term Postfilter
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_LTPF_H
#define __LC3_LTPF_H

View File

@@ -175,9 +175,9 @@ static struct lc3_complex *fft(const struct lc3_complex *x, int n,
*
* n = 5^1 * 3^n3 * 2^n2
*
* for n = 40, 80, 160 n3 = 0, n2 = [3..5]
* n = 30, 60, 120, 240 n3 = 1, n2 = [1..4]
* n = 90, 180 n3 = 2, n2 = [1..2]
* for n = 10, 20, 40, 80, 160 n3 = 0, n2 = [1..5]
* n = 30, 60, 120, 240 n3 = 1, n2 = [1..4]
* n = 90, 180 n3 = 2, n2 = [1..2]
*
* Note that the expression `n & (n-1) == 0` is equivalent
* to the check that `n` is a power of 2. */

View File

@@ -16,13 +16,6 @@
*
******************************************************************************/
/**
* LC3 - Compute LD-MDCT (Low Delay Modified Discret Cosinus Transform)
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_MDCT_H
#define __LC3_MDCT_H

View File

@@ -16,13 +16,6 @@
*
******************************************************************************/
/**
* LC3 - Packet Loss Concealment
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_PLC_H
#define __LC3_PLC_H

View File

@@ -157,7 +157,7 @@ LC3_HOT static void compute_scale_factors(
/* Pre-emphasis gain table :
* Ge[b] = 10 ^ (b * g_tilt) / 630 , b = [0..63] */
static const float ge_table[LC3_NUM_SRATE][LC3_NUM_BANDS] = {
static const float ge_table[LC3_NUM_SRATE][LC3_MAX_BANDS] = {
[LC3_SRATE_8K] = { /* g_tilt = 14 */
1.00000000e+00, 1.05250029e+00, 1.10775685e+00, 1.16591440e+00,
@@ -250,17 +250,22 @@ LC3_HOT static void compute_scale_factors(
7.19685673e+02, 8.03085722e+02, 8.96150502e+02, 1.00000000e+03 },
};
float e[LC3_NUM_BANDS];
float e[LC3_MAX_BANDS];
/* --- Copy and padding --- */
int nb = LC3_MIN(lc3_band_lim[dt][sr][LC3_NUM_BANDS], LC3_NUM_BANDS);
int n2 = LC3_NUM_BANDS - nb;
int nb = lc3_num_bands[dt][sr];
int n4 = nb < 32 ? 32 % nb : 0;
int n2 = nb < 32 ? nb - n4 : LC3_MAX_BANDS - nb;
for (int i2 = 0; i2 < n2; i2++)
e[2*i2 + 0] = e[2*i2 + 1] = eb[i2];
for (int i4 = 0; i4 < n4; i4++)
e[4*i4 + 0] = e[4*i4 + 1] =
e[4*i4 + 2] = e[4*i4 + 3] = eb[i4];
memcpy(e + 2*n2, eb + n2, (nb - n2) * sizeof(float));
for (int i2 = n4; i2 < n4+n2; i2++)
e[2*(n4+i2) + 0] = e[2*(n4+i2) + 1] = eb[i2];
memcpy(e + 4*n4 + 2*n2, eb + n4 + n2, (nb - n4 - n2) * sizeof(float));
/* --- Smoothing, pre-emphasis and logarithm --- */
@@ -269,7 +274,7 @@ LC3_HOT static void compute_scale_factors(
float e0 = e[0], e1 = e[0], e2;
float e_sum = 0;
for (int i = 0; i < LC3_NUM_BANDS-1; ) {
for (int i = 0; i < LC3_MAX_BANDS-1; ) {
e[i] = (e0 * 0.25f + e1 * 0.5f + (e2 = e[i+1]) * 0.25f) * ge[i];
e_sum += e[i++];
@@ -280,12 +285,12 @@ LC3_HOT static void compute_scale_factors(
e_sum += e[i++];
}
e[LC3_NUM_BANDS-1] = (e0 * 0.25f + e1 * 0.75f) * ge[LC3_NUM_BANDS-1];
e_sum += e[LC3_NUM_BANDS-1];
e[LC3_MAX_BANDS-1] = (e0 * 0.25f + e1 * 0.75f) * ge[LC3_MAX_BANDS-1];
e_sum += e[LC3_MAX_BANDS-1];
float noise_floor = fmaxf(e_sum * (1e-4f / 64), 0x1p-32f);
for (int i = 0; i < LC3_NUM_BANDS; i++)
for (int i = 0; i < LC3_MAX_BANDS; i++)
e[i] = fast_log2f(fmaxf(e[i], noise_floor)) * 0.5f;
/* --- Grouping & scaling --- */
@@ -680,7 +685,7 @@ LC3_HOT static void spectral_shaping(enum lc3_dt dt, enum lc3_srate sr,
{
/* --- Interpolate scale factors --- */
float scf[LC3_NUM_BANDS];
float scf[LC3_MAX_BANDS];
float s0, s1 = inv ? -scf_q[0] : scf_q[0];
scf[0] = scf[1] = s1;
@@ -694,18 +699,22 @@ LC3_HOT static void spectral_shaping(enum lc3_dt dt, enum lc3_srate sr,
scf[62] = s1 + 0.125f * (s1 - s0);
scf[63] = s1 + 0.375f * (s1 - s0);
int nb = LC3_MIN(lc3_band_lim[dt][sr][LC3_NUM_BANDS], LC3_NUM_BANDS);
int n2 = LC3_NUM_BANDS - nb;
int nb = lc3_num_bands[dt][sr];
int n4 = nb < 32 ? 32 % nb : 0;
int n2 = nb < 32 ? nb - n4 : LC3_MAX_BANDS - nb;
for (int i2 = 0; i2 < n2; i2++)
scf[i2] = 0.5f * (scf[2*i2] + scf[2*i2+1]);
for (int i4 = 0; i4 < n4; i4++)
scf[i4] = 0.25f * (scf[4*i4+0] + scf[4*i4+1] +
scf[4*i4+2] + scf[4*i4+3]);
if (n2 > 0)
memmove(scf + n2, scf + 2*n2, (nb - n2) * sizeof(float));
for (int i2 = n4; i2 < n4+n2; i2++)
scf[i2] = 0.5f * (scf[2*(n4+i2)] + scf[2*(n4+i2)+1]);
memmove(scf + n4 + n2, scf + 4*n4 + 2*n2, (nb - n4 - n2) * sizeof(float));
/* --- Spectral shaping --- */
const int *lim = lc3_band_lim[dt][sr];
const uint16_t *lim = lc3_band_lim[dt][sr];
for (int i = 0, ib = 0; ib < nb; ib++) {
float g_sns = fast_exp2f(-scf[ib]);

View File

@@ -16,13 +16,6 @@
*
******************************************************************************/
/**
* LC3 - Spectral Noise Shaping
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_SNS_H
#define __LC3_SNS_H

View File

@@ -666,13 +666,13 @@ LC3_HOT static void get_lsb(lc3_bits_t *bits,
LC3_HOT static int estimate_noise(enum lc3_dt dt, enum lc3_bandwidth bw,
const uint16_t *xq, int nq, const float *x)
{
int bw_stop = (dt == LC3_DT_7M5 ? 60 : 80) * (1 + bw);
int w = 2 + dt;
int bw_stop = 20 * (1 + dt) * (1 + bw);
int w = 1 + (dt >= LC3_DT_7M5) + (dt>= LC3_DT_10M);
float sum = 0;
int i, n = 0, z = 0;
for (i = 6*(3 + dt) - w; i < LC3_MIN(nq, bw_stop); i++) {
for (i = 6 * (1 + dt) - w; i < LC3_MIN(nq, bw_stop); i++) {
z = xq[i] ? 0 : z + 1;
if (z > 2*w)
sum += fabsf(x[i - w]), n++;
@@ -682,7 +682,7 @@ LC3_HOT static int estimate_noise(enum lc3_dt dt, enum lc3_bandwidth bw,
if (++z > 2*w)
sum += fabsf(x[i - w]), n++;
int nf = n ? 8 - (int)((16 * sum) / n + 0.5f) : 0;
int nf = n ? 8 - (int)((16 * sum) / n + 0.5f) : 8;
return LC3_CLIP(nf, 0, 7);
}
@@ -697,13 +697,13 @@ LC3_HOT static int estimate_noise(enum lc3_dt dt, enum lc3_bandwidth bw,
LC3_HOT static void fill_noise(enum lc3_dt dt, enum lc3_bandwidth bw,
int nf, uint16_t nf_seed, float g, float *x, int nq)
{
int bw_stop = (dt == LC3_DT_7M5 ? 60 : 80) * (1 + bw);
int w = 2 + dt;
int bw_stop = 20 * (1 + dt) * (1 + bw);
int w = 1 + (dt >= LC3_DT_7M5) + (dt>= LC3_DT_10M);
float s = g * (float)(8 - nf) / 16;
int i, z = 0;
for (i = 6*(3 + dt) - w; i < LC3_MIN(nq, bw_stop); i++) {
for (i = 6 * (1 + dt) - w; i < LC3_MIN(nq, bw_stop); i++) {
z = x[i] ? 0 : z + 1;
if (z > 2*w) {
nf_seed = (13849 + nf_seed*31821) & 0xffff;

View File

@@ -16,13 +16,6 @@
*
******************************************************************************/
/**
* LC3 - Spectral coefficients encoding/decoding
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_SPEC_H
#define __LC3_SPEC_H

File diff suppressed because it is too large Load Diff

View File

@@ -42,9 +42,10 @@ extern const float *lc3_mdct_win[LC3_NUM_DT][LC3_NUM_SRATE];
* Limits of bands
*/
#define LC3_NUM_BANDS 64
#define LC3_MAX_BANDS 64
extern const int lc3_band_lim[LC3_NUM_DT][LC3_NUM_SRATE][LC3_NUM_BANDS+1];
extern const int lc3_num_bands[LC3_NUM_DT][LC3_NUM_SRATE];
extern const uint16_t *lc3_band_lim[LC3_NUM_DT][LC3_NUM_SRATE];
/**

148
src/tns.c
View File

@@ -31,7 +31,7 @@
*/
static bool resolve_lpc_weighting(enum lc3_dt dt, int nbytes)
{
return nbytes < (dt == LC3_DT_7M5 ? 360/8 : 480/8);
return nbytes * 8 < 120 * (int)(1 + dt);
}
/**
@@ -52,24 +52,42 @@ LC3_HOT static inline float dot(const float *a, const float *b, int n)
/**
* LPC Coefficients
* dt, bw Duration and bandwidth of the frame
* maxorder Maximum order of filter
* x Spectral coefficients
* gain, a Output the prediction gains and LPC coefficients
*/
LC3_HOT static void compute_lpc_coeffs(
enum lc3_dt dt, enum lc3_bandwidth bw,
enum lc3_dt dt, enum lc3_bandwidth bw, int maxorder,
const float *x, float *gain, float (*a)[9])
{
static const int sub_7m5_nb[] = { 9, 26, 43, 60 };
static const int sub_7m5_wb[] = { 9, 46, 83, 120 };
static const int sub_7m5_sswb[] = { 9, 66, 123, 180 };
static const int sub_7m5_swb[] = { 9, 46, 82, 120, 159, 200, 240 };
static const int sub_7m5_fb[] = { 9, 56, 103, 150, 200, 250, 300 };
static const int sub_10m_nb[] = { 12, 34, 57, 80 };
static const int sub_10m_wb[] = { 12, 61, 110, 160 };
static const int sub_10m_sswb[] = { 12, 88, 164, 240 };
static const int sub_10m_swb[] = { 12, 61, 110, 160, 213, 266, 320 };
static const int sub_10m_fb[] = { 12, 74, 137, 200, 266, 333, 400 };
#if !LC3_NPLUS
static const int sub_2m5_nb[] = { 3, 10, 20 };
static const int sub_2m5_wb[] = { 3, 20, 40 };
static const int sub_2m5_sswb[] = { 3, 30, 60 };
static const int sub_2m5_swb[] = { 3, 40, 80 };
static const int sub_2m5_fb[] = { 3, 50, 100 };
static const int sub_5m_nb[] = { 6, 23, 40 };
static const int sub_5m_wb[] = { 6, 43, 80 };
static const int sub_5m_sswb[] = { 6, 63, 120 };
static const int sub_5m_swb[] = { 6, 43, 80, 120, 160 };
static const int sub_5m_fb[] = { 6, 53, 100, 150, 200 };
#endif /* !LC3_NPLUS */
static const int sub_7m5_nb[] = { 9, 26, 43, 60 };
static const int sub_7m5_wb[] = { 9, 46, 83, 120 };
static const int sub_7m5_sswb[] = { 9, 66, 123, 180 };
static const int sub_7m5_swb[] = { 9, 46, 82, 120, 159, 200, 240 };
static const int sub_7m5_fb[] = { 9, 56, 103, 150, 200, 250, 300 };
static const int sub_10m_nb[] = { 12, 34, 57, 80 };
static const int sub_10m_wb[] = { 12, 61, 110, 160 };
static const int sub_10m_sswb[] = { 12, 88, 164, 240 };
static const int sub_10m_swb[] = { 12, 61, 110, 160, 213, 266, 320 };
static const int sub_10m_fb[] = { 12, 74, 137, 200, 266, 333, 400 };
/* --- Normalized autocorrelation --- */
@@ -79,32 +97,53 @@ LC3_HOT static void compute_lpc_coeffs(
8.81323137e-01
};
const int *sub = (const int * const [LC3_NUM_DT][LC3_NUM_SRATE]){
{ sub_7m5_nb, sub_7m5_wb, sub_7m5_sswb, sub_7m5_swb, sub_7m5_fb },
{ sub_10m_nb, sub_10m_wb, sub_10m_sswb, sub_10m_swb, sub_10m_fb },
const int *sub = (const int * const [LC3_NUM_DT][LC3_NUM_BANDWIDTH]){
#if !LC3_NPLUS
[LC3_DT_2M5] = { sub_2m5_nb, sub_2m5_wb,
sub_2m5_sswb, sub_2m5_swb, sub_2m5_fb },
[LC3_DT_5M ] = { sub_5m_nb , sub_5m_wb ,
sub_5m_sswb , sub_5m_swb , sub_5m_fb },
#endif /* !LC3_NPLUS */
[LC3_DT_7M5] = { sub_7m5_nb, sub_7m5_wb,
sub_7m5_sswb, sub_7m5_swb, sub_7m5_fb },
[LC3_DT_10M] = { sub_10m_nb, sub_10m_wb,
sub_10m_sswb, sub_10m_swb, sub_10m_fb },
}[dt][bw];
int nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB);
int nfilters = 1 + (dt >= LC3_DT_5M && bw >= LC3_BANDWIDTH_SWB);
int nsubdivisions = 2 + (dt >= LC3_DT_7M5);
const float *xs, *xe = x + *sub;
float r[2][9];
for (int f = 0; f < nfilters; f++) {
float c[9][3];
float c[9][3] = { 0 };
for (int s = 0; s < 3; s++) {
for (int s = 0; s < nsubdivisions; s++) {
xs = xe, xe = x + *(++sub);
for (int k = 0; k < 9; k++)
for (int k = 0; k <= maxorder; k++)
c[k][s] = dot(xs, xs + k, (xe - xs) - k);
}
float e0 = c[0][0], e1 = c[0][1], e2 = c[0][2];
r[f][0] = nsubdivisions;
if (nsubdivisions == 2) {
float e0 = c[0][0], e1 = c[0][1];
for (int k = 1; k <= maxorder; k++)
r[f][k] = e0 == 0 || e1 == 0 ? 0 :
(c[k][0]/e0 + c[k][1]/e1) * lag_window[k];
r[f][0] = 3;
for (int k = 1; k < 9; k++)
r[f][k] = e0 == 0 || e1 == 0 || e2 == 0 ? 0 :
(c[k][0]/e0 + c[k][1]/e1 + c[k][2]/e2) * lag_window[k];
} else {
float e0 = c[0][0], e1 = c[0][1], e2 = c[0][2];
for (int k = 1; k <= maxorder; k++)
r[f][k] = e0 == 0 || e1 == 0 || e2 == 0 ? 0 :
(c[k][0]/e0 + c[k][1]/e1 + c[k][2]/e2) * lag_window[k];
}
}
/* --- Levinson-Durbin recursion --- */
@@ -116,7 +155,7 @@ LC3_HOT static void compute_lpc_coeffs(
gain[f] = err;
a0[0] = 1;
for (int k = 1; k < 9; ) {
for (int k = 1; k <= maxorder; ) {
rc = -r[f][k];
for (int i = 1; i < k; i++)
@@ -160,21 +199,22 @@ LC3_HOT static void lpc_weighting(float pred_gain, float *a)
/**
* LPC reflection
* a LPC coefficients
* a, maxorder LPC coefficients, and maximum order (4 or 8)
* rc Output refelection coefficients
*/
LC3_HOT static void lpc_reflection(const float *a, float *rc)
LC3_HOT static void lpc_reflection(
const float *a, int maxorder, float *rc)
{
float e, b[2][7], *b0, *b1;
rc[7] = a[1+7];
e = 1 - rc[7] * rc[7];
rc[maxorder-1] = a[maxorder];
e = 1 - rc[maxorder-1] * rc[maxorder-1];
b1 = b[1];
for (int i = 0; i < 7; i++)
b1[i] = (a[1+i] - rc[7] * a[7-i]) / e;
for (int i = 0; i < maxorder-1; i++)
b1[i] = (a[1+i] - rc[maxorder-1] * a[(maxorder-1)-i]) / e;
for (int k = 6; k > 0; k--) {
for (int k = maxorder-2; k > 0; k--) {
b0 = b1, b1 = b[k & 1];
rc[k] = b0[k];
@@ -189,11 +229,11 @@ LC3_HOT static void lpc_reflection(const float *a, float *rc)
/**
* Quantization of RC coefficients
* rc Refelection coefficients
* rc_order Return order of coefficients
* rc, maxorder Refelection coefficients, and maximum order (4 or 8)
* order Return order of coefficients
* rc_i Return quantized coefficients
*/
static void quantize_rc(const float *rc, int *rc_order, int *rc_q)
static void quantize_rc(const float *rc, int maxorder, int *order, int *rc_q)
{
/* Quantization table, sin(delta * (i + 0.5)), delta = Pi / 17 */
@@ -202,9 +242,9 @@ static void quantize_rc(const float *rc, int *rc_order, int *rc_q)
7.39008917e-01, 8.50217136e-01, 9.32472229e-01, 9.82973100e-01
};
*rc_order = 8;
*order = maxorder;
for (int i = 0; i < 8; i++) {
for (int i = 0; i < maxorder; i++) {
float rc_m = fabsf(rc[i]);
rc_q[i] = 4 * (rc_m >= q_thr[4]);
@@ -213,17 +253,16 @@ static void quantize_rc(const float *rc, int *rc_order, int *rc_q)
if (rc[i] < 0)
rc_q[i] = -rc_q[i];
*rc_order = rc_q[i] != 0 ? 8 : *rc_order - 1;
*order = rc_q[i] != 0 ? maxorder : *order - 1;
}
}
/**
* Unquantization of RC coefficients
* rc_q Quantized coefficients
* rc_order Order of coefficients
* rc_q, order Quantized coefficients, and order
* rc Return refelection coefficients
*/
static void unquantize_rc(const int *rc_q, int rc_order, float rc[8])
static void unquantize_rc(const int *rc_q, int order, float rc[8])
{
/* Quantization table, sin(delta * i), delta = Pi / 17 */
@@ -235,7 +274,7 @@ static void unquantize_rc(const int *rc_q, int rc_order, float rc[8])
int i;
for (i = 0; i < rc_order; i++) {
for (i = 0; i < order; i++) {
float rc_m = q_inv[LC3_ABS(rc_q[i])];
rc[i] = rc_q[i] < 0 ? -rc_m : rc_m;
}
@@ -256,9 +295,9 @@ LC3_HOT static void forward_filtering(
enum lc3_dt dt, enum lc3_bandwidth bw,
const int rc_order[2], float (* const rc)[8], float *x)
{
int nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB);
int nfilters = 1 + (dt >= LC3_DT_5M && bw >= LC3_BANDWIDTH_SWB);
int nf = LC3_NE(dt, bw) >> (nfilters - 1);
int i0, ie = 3*(3 + dt);
int i0, ie = 3*(1 + dt);
float s[8] = { 0 };
@@ -297,9 +336,9 @@ LC3_HOT static void inverse_filtering(
enum lc3_dt dt, enum lc3_bandwidth bw,
const int rc_order[2], float (* const rc)[8], float *x)
{
int nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB);
int nfilters = 1 + (dt >= LC3_DT_5M && bw >= LC3_BANDWIDTH_SWB);
int nf = LC3_NE(dt, bw) >> (nfilters - 1);
int i0, ie = 3*(3 + dt);
int i0, ie = 3*(1 + dt);
float s[8] = { 0 };
@@ -349,10 +388,11 @@ void lc3_tns_analyze(enum lc3_dt dt, enum lc3_bandwidth bw,
float pred_gain[2], a[2][9];
float rc[2][8];
data->nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB);
data->lpc_weighting = resolve_lpc_weighting(dt, nbytes);
data->nfilters = 1 + (dt >= LC3_DT_5M && bw >= LC3_BANDWIDTH_SWB);
int maxorder = dt <= LC3_DT_5M ? 4 : 8;
compute_lpc_coeffs(dt, bw, x, pred_gain, a);
compute_lpc_coeffs(dt, bw, maxorder, x, pred_gain, a);
for (int f = 0; f < data->nfilters; f++) {
@@ -363,9 +403,9 @@ void lc3_tns_analyze(enum lc3_dt dt, enum lc3_bandwidth bw,
if (data->lpc_weighting && pred_gain[f] < 2.f)
lpc_weighting(pred_gain[f], a[f]);
lpc_reflection(a[f], rc[f]);
lpc_reflection(a[f], maxorder, rc[f]);
quantize_rc(rc[f], &data->rc_order[f], data->rc[f]);
quantize_rc(rc[f], maxorder, &data->rc_order[f], data->rc[f]);
unquantize_rc(data->rc[f], data->rc_order[f], rc[f]);
}
@@ -435,10 +475,10 @@ void lc3_tns_put_data(lc3_bits_t *bits, const struct lc3_tns_data *data)
/**
* Get bitstream data
*/
void lc3_tns_get_data(lc3_bits_t *bits,
int lc3_tns_get_data(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_bandwidth bw, int nbytes, lc3_tns_data_t *data)
{
data->nfilters = 1 + (bw >= LC3_BANDWIDTH_SWB);
data->nfilters = 1 + (dt >= LC3_DT_5M && bw >= LC3_BANDWIDTH_SWB);
data->lpc_weighting = resolve_lpc_weighting(dt, nbytes);
for (int f = 0; f < data->nfilters; f++) {
@@ -449,9 +489,13 @@ void lc3_tns_get_data(lc3_bits_t *bits,
data->rc_order[f] += lc3_get_symbol(bits,
lc3_tns_order_models + data->lpc_weighting);
if (dt <= LC3_DT_5M && data->rc_order[f] > 4)
return -1;
for (int i = 0; i < data->rc_order[f]; i++)
data->rc[f][i] = (int)lc3_get_symbol(bits,
lc3_tns_coeffs_models + i) - 8;
}
return 0;
}

View File

@@ -16,13 +16,6 @@
*
******************************************************************************/
/**
* LC3 - Temporal Noise Shaping
*
* Reference : Low Complexity Communication Codec (LC3)
* Bluetooth Specification v1.0
*/
#ifndef __LC3_TNS_H
#define __LC3_TNS_H
@@ -82,8 +75,9 @@ void lc3_tns_put_data(lc3_bits_t *bits, const lc3_tns_data_t *data);
* dt, bw Duration and bandwidth of the frame
* nbytes Size in bytes of the frame
* data Bitstream data
* return 0: Ok -1: Invalid bitstream data
*/
void lc3_tns_get_data(lc3_bits_t *bits,
int lc3_tns_get_data(lc3_bits_t *bits,
enum lc3_dt dt, enum lc3_bandwidth bw, int nbytes, lc3_tns_data_t *data);
/**

View File

@@ -120,7 +120,7 @@ def mdct_fft_twiddles():
def mdct_rot_twiddles():
for n in (120, 160, 240, 320, 360, 480, 640, 720, 960):
for n in (40, 80, 120, 160, 240, 320, 360, 480, 640, 720, 960):
print('\n--- mdct rot twiddles {:3d} ---'.format(n))

View File

@@ -54,7 +54,7 @@ class AttackDetector:
def run(self, nbytes, x):
### 3.3.6.2 Downsampling and filtering input
### Downsampling and filtering input
mf = int(16 * self.ms)
@@ -68,7 +68,7 @@ class AttackDetector:
self.xn2 = x_att[-2]
self.xn1 = x_att[-1]
### 3.3.6.3 Energy calculation
### Energy calculation
nb = int(self.ms / 2.5)
@@ -82,7 +82,7 @@ class AttackDetector:
self.en1 = e_att[-1]
self.an1 = a_att[-1]
### 3.3.6.4 Attack Detection
### Attack Detection
p_att = -1
flags = [ (e_att[i] > 8.5 * a_att[i]) for i in range(nb) ]
@@ -151,17 +151,19 @@ def check_unit(rng, dt, sr):
def check_appendix_c(dt):
i0 = dt - T.DT_7M5
sr = T.SRATE_48K
ok = True
state = initial_state()
x = np.append(np.zeros(6), C.X_PCM_ATT[dt][0])
f_att = lc3.attdet_run(dt, sr, C.NBYTES_ATT[dt], state, x)
ok = f_att == C.F_ATT[dt][0]
x = np.append(np.zeros(6), C.X_PCM_ATT[i0][0])
f_att = lc3.attdet_run(dt, sr, C.NBYTES_ATT[i0], state, x)
ok = ok and f_att == C.F_ATT[i0][0]
x = np.append(x[-6:], C.X_PCM_ATT[dt][1])
f_att = lc3.attdet_run(dt, sr, C.NBYTES_ATT[dt], state, x)
ok = f_att == C.F_ATT[dt][1]
x = np.append(x[-6:], C.X_PCM_ATT[i0][1])
f_att = lc3.attdet_run(dt, sr, C.NBYTES_ATT[i0], state, x)
ok = ok and f_att == C.F_ATT[i0][1]
return ok
@@ -173,11 +175,11 @@ def check():
for dt in range(T.NUM_DT):
ok and check_enabling(rng, dt)
for dt in range(T.NUM_DT):
for dt in range(T.DT_7M5, T.NUM_DT):
for sr in range(T.SRATE_32K, T.NUM_SRATE):
ok = ok and check_unit(rng, dt, sr)
for dt in range(T.NUM_DT):
for dt in range(T.DT_7M5, T.NUM_DT):
ok = ok and check_appendix_c(dt)
return ok

View File

@@ -21,11 +21,15 @@ import tables as T, appendix_c as C
BW_START = [
[ [], [ 24 ], [ 24, 35 ], [ 24, 33, 39 ], [ 22, 31, 37, 41 ] ],
[ [], [ 39 ], [ 35, 47 ], [ 34, 44, 50 ], [ 32, 42, 48, 52 ] ],
[ [], [ 51 ], [ 45, 58 ], [ 42, 53, 60 ], [ 40, 51, 57, 61 ] ],
[ [], [ 53 ], [ 47, 59 ], [ 44, 54, 60 ], [ 41, 51, 57, 61 ] ]
]
BW_STOP = [
[ [], [ 34 ], [ 32, 39 ], [ 31, 38, 42 ], [ 29, 35, 40, 43 ] ],
[ [], [ 49 ], [ 44, 51 ], [ 42, 49, 53 ], [ 40, 46, 51, 54 ] ],
[ [], [ 63 ], [ 55, 63 ], [ 51, 58, 63 ], [ 48, 55, 60, 63 ] ],
[ [], [ 63 ], [ 56, 63 ], [ 52, 59, 63 ], [ 49, 55, 60, 63 ] ]
]
@@ -33,8 +37,8 @@ BW_STOP = [
TQ = [ 20, 10, 10, 10 ]
TC = [ 15, 23, 20, 20 ]
L = [ [ 4, 4, 3, 2 ], [ 4, 4, 3, 1 ] ]
L = [ [ 4, 4, 3, 1 ], [ 4, 4, 3, 1 ],
[ 4, 4, 3, 2 ], [ 4, 4, 3, 1 ] ]
### ------------------------------------------------------------------------ ###
@@ -131,11 +135,13 @@ def check_unit(rng, dt, sr):
def check_appendix_c(dt):
i0 = dt - T.DT_7M5
sr = T.SRATE_16K
ok = True
E_B = C.E_B[dt]
P_BW = C.P_BW[dt]
E_B = C.E_B[i0]
P_BW = C.P_BW[i0]
bw = lc3.bwdet_run(dt, sr, E_B[0])
ok = ok and bw == P_BW[0]
@@ -154,7 +160,7 @@ def check():
for sr in range(T.NUM_SRATE):
ok = ok and check_unit(rng, dt, sr)
for dt in range(T.NUM_DT):
for dt in range(T.DT_7M5, T.NUM_DT):
ok = ok and check_appendix_c(dt)
return ok

View File

@@ -33,7 +33,7 @@ static PyObject *bwdet_run_py(PyObject *m, PyObject *args)
CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
CTYPES_CHECK("e", to_1d_ptr(e_obj, NPY_FLOAT, LC3_NUM_BANDS, &e));
CTYPES_CHECK("e", to_1d_ptr(e_obj, NPY_FLOAT, LC3_MAX_BANDS, &e));
int bw = lc3_bwdet_run(dt, sr, e);

View File

@@ -100,14 +100,15 @@ class Decoder:
def check_appendix_c(dt):
ok = True
i0 = dt - T.DT_7M5
dec_c = lc3.setup_decoder(int(T.DT_MS[dt] * 1000), 16000)
ok = True
for i in range(len(C.BYTES_AC[dt])):
for i in range(len(C.BYTES_AC[i0])):
pcm = lc3.decode(dec_c, bytes(C.BYTES_AC[dt][i]))
ok = ok and np.max(np.abs(pcm - C.X_HAT_CLIP[dt][i])) < 1
pcm = lc3.decode(dec_c, bytes(C.BYTES_AC[i0][i]))
ok = ok and np.max(np.abs(pcm - C.X_HAT_CLIP[i0][i])) < 1
return ok
@@ -115,7 +116,7 @@ def check():
ok = True
for dt in range(T.NUM_DT):
for dt in range(T.DT_7M5, T.NUM_DT):
ok = ok and check_appendix_c(dt)
return ok

View File

@@ -108,14 +108,15 @@ class Encoder:
def check_appendix_c(dt):
ok = True
i0 = dt - T.DT_7M5
enc_c = lc3.setup_encoder(int(T.DT_MS[dt] * 1000), 16000)
ok = True
for i in range(len(C.X_PCM[dt])):
for i in range(len(C.X_PCM[i0])):
data = lc3.encode(enc_c, C.X_PCM[dt][i], C.NBYTES[dt])
ok = ok and data == C.BYTES_AC[dt][i]
data = lc3.encode(enc_c, C.X_PCM[i0][i], C.NBYTES[i0])
ok = ok and data == C.BYTES_AC[i0][i]
return ok
@@ -123,7 +124,7 @@ def check():
ok = True
for dt in range(T.NUM_DT):
for dt in range(T.DT_7M5, T.NUM_DT):
ok = ok and check_appendix_c(dt)
return ok

View File

@@ -33,10 +33,10 @@ class EnergyBand:
e = [ np.mean(np.square(x[self.I[i]:self.I[i+1]]))
for i in range(len(self.I)-1) ]
e_lo = np.sum(e[:len(e) - [4, 2][self.dt]])
e_hi = np.sum(e[len(e) - [4, 2][self.dt]:])
e_lo = np.sum(e[:len(e) - [2, 3, 4, 2][self.dt]])
e_hi = np.sum(e[len(e) - [2, 3, 4, 2][self.dt]:])
return np.append(e, np.zeros(64-len(e))), (e_hi > 30*e_lo)
return e, (e_hi > 30*e_lo)
### ------------------------------------------------------------------------ ###
@@ -63,14 +63,16 @@ def check_unit(rng, dt, sr):
def check_appendix_c(dt):
i0 = dt - T.DT_7M5
sr = T.SRATE_16K
ok = True
e = lc3.energy_compute(dt, sr, C.X[dt][0])[0]
ok = ok and np.amax(np.abs(1 - e/C.E_B[dt][0])) < 1e-6
e = lc3.energy_compute(dt, sr, C.X[i0][0])[0]
ok = ok and np.amax(np.abs(1 - e/C.E_B[i0][0])) < 1e-6
e = lc3.energy_compute(dt, sr, C.X[dt][1])[0]
ok = ok and np.amax(np.abs(1 - e/C.E_B[dt][1])) < 1e-6
e = lc3.energy_compute(dt, sr, C.X[i0][1])[0]
ok = ok and np.amax(np.abs(1 - e/C.E_B[i0][1])) < 1e-6
return ok
@@ -84,7 +86,7 @@ def check():
for sr in range(T.NUM_SRATE):
ok = ok and check_unit(rng, dt, sr)
for dt in range(T.NUM_DT):
for dt in range(T.DT_7M5, T.NUM_DT):
ok = ok and check_appendix_c(dt)
return ok

View File

@@ -40,7 +40,7 @@ static PyObject *energy_compute_py(PyObject *m, PyObject *args)
int ns = LC3_NS(dt, sr);
CTYPES_CHECK("x", to_1d_ptr(x_obj, NPY_FLOAT, ns, &x));
e_obj = new_1d_ptr(NPY_FLOAT, LC3_NUM_BANDS, &e);
e_obj = new_1d_ptr(NPY_FLOAT, lc3_num_bands[dt][sr], &e);
int nn_flag = lc3_energy_compute(dt, sr, x, e);

View File

@@ -31,7 +31,7 @@ class Resampler_12k8:
self.w = 240 // self.p
self.n = ((T.DT_MS[dt] * 128) / 10).astype(int)
self.d = [ 44, 24 ][dt]
self.d = [ 24, 44 ][dt == T.DT_7M5]
self.x = np.zeros(self.w + T.NS[dt][sr])
self.u = np.zeros(self.n + 2)
@@ -59,7 +59,7 @@ class Resampler_12k8:
x = self.x
u = self.u
### 3.3.9.3 Resampling
### Resampling
h = np.zeros(240 + p)
h[-119:] = T.LTPF_H12K8[:119]
@@ -74,7 +74,7 @@ class Resampler_12k8:
if self.sr == T.SRATE_8K:
u = 0.5 * u
### 3.3.9.4 High-pass filtering
### High-pass filtering
b = [ 0.9827947082978771, -1.9655894165957540, 0.9827947082978771 ]
a = [ 1 , -1.9652933726226904, 0.9658854605688177 ]
@@ -110,7 +110,7 @@ class Resampler_6k4:
if len(self.y) > n:
self.y[-n:] = self.y[:n]
### 3.3.9.5 Downsampling to 6.4 KHz
### Downsampling to 6.4 KHz
h = [ 0.1236796411180537, 0.2353512128364889, 0.2819382920909148,
0.2353512128364889, 0.1236796411180537 ]
@@ -140,11 +140,11 @@ class LtpfAnalysis(Ltpf):
super().__init__(dt, sr)
self.resampler_12k8 = Resampler_12k8(
dt, sr, history = 232)
self.resampler_12k8 = Resampler_12k8(dt, sr,
history = 232 + (32 if dt == T.DT_2M5 else 0))
self.resampler_6k4 = Resampler_6k4(
self.resampler_12k8.n, history = 114)
self.resampler_6k4 = Resampler_6k4(self.resampler_12k8.n,
history = 114 + (16 if dt == T.DT_2M5 else 0))
self.active = False
self.tc = 0
@@ -160,30 +160,32 @@ class LtpfAnalysis(Ltpf):
return 1 + 10 * int(self.pitch_present)
def correlate(self, x, n, k0, k1):
def correlate(self, x, i0, n, k0, k1):
return [ np.dot(x[:n], np.take(x, np.arange(n) - k)) \
for k in range(k0, 1+k1) ]
return np.array([ np.dot(
np.take(x, np.arange(i0, n)),
np.take(x, np.arange(i0, n) - k)) for k in range(k0, 1+k1) ])
def norm_corr(self, x, n, k):
def norm_corr(self, x, i0, n, k):
u = x[:n]
v = np.take(x, np.arange(n) - k)
u = np.take(x, np.arange(i0, n))
v = np.take(x, np.arange(i0, n) - k)
uv = np.dot(u, v)
return uv / np.sqrt(np.dot(u, u) * np.dot(v, v)) if uv > 0 else 0
def run(self, x):
### 3.3.9.3-4 Resampling
### Resampling
x_12k8 = self.resampler_12k8.resample(x)
### 3.3.9.5-6 Pitch detection algorithm
### Pitch detection algorithm
x = self.resampler_6k4.resample(x_12k8)
n = self.resampler_6k4.n
x = self.resampler_6k4.resample(x_12k8)
i0 = [-16, 0][self.dt > T.DT_2M5]
n = self.resampler_6k4.n
r = self.correlate(x, n, 17, 114)
r = self.correlate(x, i0, n, 17, 114)
rw = r * (1 - 0.5 * np.arange(len(r)) / (len(r) - 1))
tc = self.tc
@@ -191,23 +193,24 @@ class LtpfAnalysis(Ltpf):
k1 = min(len(r)-1, tc+4)
t = [ 17 + np.argmax(rw), 17 + k0 + np.argmax(r[k0:1+k1]) ]
nc = [ self.norm_corr(x, n, t[i]) for i in range(2) ]
nc = [ self.norm_corr(x, i0, n, t[i]) for i in range(2) ]
ti = int(nc[1] > 0.85 * nc[0])
self.tc = t[ti] - 17
self.pitch_present = bool(nc[ti] > 0.6)
### 3.3.9.7 Pitch-lag parameter
### Pitch-lag parameter
if self.pitch_present:
tc = self.tc + 17
x = x_12k8
n = self.resampler_12k8.n
x = x_12k8
i0 = [-32, 0][self.dt > T.DT_2M5]
n = self.resampler_12k8.n
k0 = max( 32, 2*tc-4)
k1 = min(228, 2*tc+4)
r = self.correlate(x, n, k0-4, k1+4)
r = self.correlate(x, i0, n, k0-4, k1+4)
e = k0 + np.argmax(r[4:-4])
h = np.zeros(42)
@@ -232,17 +235,21 @@ class LtpfAnalysis(Ltpf):
e = f = 0
self.pitch_index = 0
### 3.3.9.8 Activation bit
### Activation bit
h = np.zeros(24)
h[-7:] = T.LTPF_HI[:7]
h[ :8] = T.LTPF_HI[7:]
x = x_12k8
i0 = [-32, 0][self.dt > T.DT_2M5]
n = self.resampler_12k8.n
k = np.arange(-2, 3)
u = [ np.dot( np.take(x, i-k), np.take(h, 4*k) ) \
for i in range(n) ]
for i in range(i0, n) ]
v = [ np.dot( np.take(x, i-k), np.take(h, 4*k-f) ) \
for i in range(-e, n-e) ]
for i in range(i0-e, n-e) ]
nc = max(0, np.dot(u, v)) / np.sqrt(np.dot(u, u) * np.dot(v, v)) \
if self.pitch_present else 0
@@ -327,7 +334,7 @@ class LtpfSynthesis(Ltpf):
sr = self.sr
dt = self.dt
### 3.4.9.4 Filter parameters
### Filter parameters
pitch_index = self.pitch_index
@@ -346,7 +353,12 @@ class LtpfSynthesis(Ltpf):
self.p_e[0] = int(p * 4 + 0.5) // 4
self.p_f[0] = int(p * 4 + 0.5) - 4*self.p_e[0]
nbits = round(nbytes*80 / T.DT_MS[dt])
nbits = round(nbytes*8 * 10 / T.DT_MS[dt])
if dt == T.DT_2M5:
nbits = int(nbits * (1 - 0.4))
elif dt == T.DT_5M:
nbits = nbits - 160
g_idx = max(nbits // 80, 3+sr) - (3+sr)
g = [ 0.4, 0.35, 0.3, 0.25 ][g_idx] if g_idx < 4 else 0
@@ -355,7 +367,7 @@ class LtpfSynthesis(Ltpf):
self.c_n[0] = 0.85 * g * LtpfSynthesis.C_N[sr][g_idx]
self.c_d[0] = g * LtpfSynthesis.C_D[sr][self.p_f[0]]
### 3.4.9.2 Transition handling
### Transition handling
n0 = (T.SRATE_KHZ[sr] * 1000) // 400
ns = T.NS[dt][sr]
@@ -402,8 +414,7 @@ class LtpfSynthesis(Ltpf):
np.dot(c_d[0], np.take(y , k - d[0] - np.arange(l_d)))
y[k] = yc[k] - (k/n0) * u
### 3.4.9.3 Remainder of the frame
### Remainder of the frame
for k in range(n0, ns):
@@ -466,28 +477,30 @@ def check_resampler(rng, dt, sr):
def check_resampler_appendix_c(dt):
i0 = dt - T.DT_7M5
sr = T.SRATE_16K
ok = True
nt = (5 * T.SRATE_KHZ[sr]) // 4
n = [ 96, 128 ][dt]
k = [ 44, 24 ][dt] + n
n = [ 96, 128 ][i0]
k = [ 44, 24 ][i0] + n
state = initial_hp50_state()
x = np.append(np.zeros(nt), C.X_PCM[dt][0])
x = np.append(np.zeros(nt), C.X_PCM[i0][0])
y = np.zeros(384)
y = lc3.ltpf_resample(dt, sr, state, x, y)
u = y[-k:len(C.X_TILDE_12K8D[dt][0])-k]
u = y[-k:len(C.X_TILDE_12K8D[i0][0])-k]
ok = ok and np.amax(np.abs(u - C.X_TILDE_12K8D[dt][0]/2)) < 2
ok = ok and np.amax(np.abs(u - C.X_TILDE_12K8D[i0][0]/2)) < 2
x = np.append(x[-nt:], C.X_PCM[dt][1])
x = np.append(x[-nt:], C.X_PCM[i0][1])
y[:-n] = y[n:]
y = lc3.ltpf_resample(dt, sr, state, x, y)
u = y[-k:len(C.X_TILDE_12K8D[dt][1])-k]
u = y[-k:len(C.X_TILDE_12K8D[i0][1])-k]
ok = ok and np.amax(np.abs(u - C.X_TILDE_12K8D[dt][1]/2)) < 2
ok = ok and np.amax(np.abs(u - C.X_TILDE_12K8D[i0][1]/2)) < 2
return ok
@@ -503,7 +516,7 @@ def check_analysis(rng, dt, sr):
ltpf = LtpfAnalysis(dt, sr)
t = np.arange(100 * ns) / (T.SRATE_KHZ[sr] * 1000)
s = signal.chirp(t, f0=10, f1=3e3, t1=t[-1], method='logarithmic')
s = signal.chirp(t, f0=10, f1=2500, t1=t[-1], method='logarithmic')
for i in range(20):
@@ -516,7 +529,7 @@ def check_analysis(rng, dt, sr):
(pitch_present_c, data_c) = lc3.ltpf_analyse(dt, sr, state_c, x_c)
ok = ok and (not pitch_present or state_c['tc'] == ltpf.tc)
ok = ok and np.amax(np.abs(state_c['nc'][0] - ltpf.nc[0])) < 1e-2
ok = ok and np.amax(np.abs(state_c['nc'][0] - ltpf.nc[0])) < 1e-1
ok = ok and pitch_present_c == pitch_present
ok = ok and data_c['active'] == data['active']
ok = ok and data_c['pitch_index'] == data['pitch_index']
@@ -537,6 +550,7 @@ def check_synthesis(rng, dt, sr):
x_c = np.zeros(nd+ns)
for i in range(50):
pitch_present = bool(rng.integers(0, 10) >= 1)
if not pitch_present:
synthesis.disable()
@@ -563,37 +577,40 @@ def check_synthesis(rng, dt, sr):
def check_analysis_appendix_c(dt):
i0 = dt - T.DT_7M5
sr = T.SRATE_16K
nt = (5 * T.SRATE_KHZ[sr]) // 4
ok = True
nt = (5 * T.SRATE_KHZ[sr]) // 4
state = initial_state()
x = np.append(np.zeros(nt), C.X_PCM[dt][0])
x = np.append(np.zeros(nt), C.X_PCM[i0][0])
(pitch_present, data) = lc3.ltpf_analyse(dt, sr, state, x)
ok = ok and C.T_CURR[dt][0] - state['tc'] == 17
ok = ok and np.amax(np.abs(state['nc'][0] - C.NC_LTPF[dt][0])) < 1e-5
ok = ok and pitch_present == C.PITCH_PRESENT[dt][0]
ok = ok and data['pitch_index'] == C.PITCH_INDEX[dt][0]
ok = ok and data['active'] == C.LTPF_ACTIVE[dt][0]
ok = ok and C.T_CURR[i0][0] - state['tc'] == 17
ok = ok and np.amax(np.abs(state['nc'][0] - C.NC_LTPF[i0][0])) < 1e-5
ok = ok and pitch_present == C.PITCH_PRESENT[i0][0]
ok = ok and data['pitch_index'] == C.PITCH_INDEX[i0][0]
ok = ok and data['active'] == C.LTPF_ACTIVE[i0][0]
x = np.append(x[-nt:], C.X_PCM[dt][1])
x = np.append(x[-nt:], C.X_PCM[i0][1])
(pitch_present, data) = lc3.ltpf_analyse(dt, sr, state, x)
ok = ok and C.T_CURR[dt][1] - state['tc'] == 17
ok = ok and np.amax(np.abs(state['nc'][0] - C.NC_LTPF[dt][1])) < 1e-5
ok = ok and pitch_present == C.PITCH_PRESENT[dt][1]
ok = ok and data['pitch_index'] == C.PITCH_INDEX[dt][1]
ok = ok and data['active'] == C.LTPF_ACTIVE[dt][1]
ok = ok and C.T_CURR[i0][1] - state['tc'] == 17
ok = ok and np.amax(np.abs(state['nc'][0] - C.NC_LTPF[i0][1])) < 1e-5
ok = ok and pitch_present == C.PITCH_PRESENT[i0][1]
ok = ok and data['pitch_index'] == C.PITCH_INDEX[i0][1]
ok = ok and data['active'] == C.LTPF_ACTIVE[i0][1]
return ok
def check_synthesis_appendix_c(dt):
sr = T.SRATE_16K
ok = True
ok = True
if dt != T.DT_10M:
return ok
@@ -650,7 +667,7 @@ 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):
for dt in range(T.DT_7M5, T.NUM_DT):
ok = ok and check_resampler_appendix_c(dt)
ok = ok and check_analysis_appendix_c(dt)
ok = ok and check_synthesis_appendix_c(dt)

View File

@@ -38,7 +38,7 @@ static PyObject *resample_py(PyObject *m, PyObject *args)
int ns = LC3_NS(dt, sr), nt = LC3_NT(dt);
int ny = sizeof((struct lc3_ltpf_analysis){ }.x_12k8) / sizeof(int16_t);
int n = dt == LC3_DT_7M5 ? 96 : 128;
int n = (1 + dt) * 32;
CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_INT16, ns+nt, &x));
CTYPES_CHECK("y", y_obj = to_1d_ptr(y_obj, NPY_INT16, ny, &y));

View File

@@ -24,8 +24,10 @@ import tables as T, appendix_c as C
class Mdct:
W = [ [ T.W_7M5_60, T.W_7M5_120, T.W_7M5_180, T.W_7M5_240, T.W_7M5_360 ],
[ T.W_10M_80, T.W_10M_160, T.W_10M_240, T.W_10M_320, T.W_10M_480 ] ]
W = [ [ T.W_2M5_8K, T.W_2M5_16K, T.W_2M5_24K, T.W_2M5_32K, T.W_2M5_48K ],
[ T.W_5M_8K , T.W_5M_16K , T.W_5M_24K , T.W_5M_32K , T.W_5M_48K ],
[ T.W_7M5_8K, T.W_7M5_16K, T.W_7M5_24K, T.W_7M5_32K, T.W_7M5_48K ],
[ T.W_10M_8K, T.W_10M_16K, T.W_10M_24K, T.W_10M_32K, T.W_10M_48K ] ]
def __init__(self, dt, sr):
@@ -117,16 +119,19 @@ def check_forward_unit(rng, dt, sr):
def check_forward_appendix_c(dt):
i0 = dt - T.DT_7M5
sr = T.SRATE_16K
ns = T.NS[dt][sr]
nd = T.ND[dt][sr]
ok = True
(y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[dt][0], np.zeros(nd))
ok = ok and np.amax(np.abs(y - C.X[dt][0])) < 1e-1
ns = T.NS[dt][sr]
nd = T.ND[dt][sr]
(y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[dt][1], d)
ok = ok and np.amax(np.abs(y - C.X[dt][1])) < 1e-1
(y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[i0][0], np.zeros(nd))
ok = ok and np.amax(np.abs(y - C.X[i0][0])) < 1e-1
(y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[i0][1], d)
ok = ok and np.amax(np.abs(y - C.X[i0][1])) < 1e-1
return ok
@@ -134,7 +139,7 @@ def check_forward_appendix_c(dt):
def check_inverse_unit(rng, dt, sr):
ns = T.NS[dt][sr]
nd = [ (23 * ns) // 30, (5 * ns) // 8 ][dt]
nd = T.ND[dt][sr]
ok = True
x = (2 * rng.random(ns)) - 1
@@ -157,22 +162,25 @@ def check_inverse_unit(rng, dt, sr):
def check_inverse_appendix_c(dt):
i0 = dt - T.DT_7M5
sr = T.SRATE_16K
ns = T.NS[dt][sr]
nd = [ (23 * ns) // 30, (5 * ns) // 8 ][dt]
ok = True
(y, d0) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[dt][0], np.zeros(nd))
yr = C.T_HAT_MDCT[dt][0][ns-nd:2*ns-nd]
dr = C.T_HAT_MDCT[dt][0][2*ns-nd:]
ns = T.NS[dt][sr]
nd = T.ND[dt][sr]
(y, d0) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[i0][0], np.zeros(nd))
yr = C.T_HAT_MDCT[i0][0][ns-nd:2*ns-nd]
dr = C.T_HAT_MDCT[i0][0][2*ns-nd:]
ok = ok and np.amax(np.abs(yr - y )) < 1e-1
ok = ok and np.amax(np.abs(dr - d0)) < 1e-1
(y, d1) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[dt][1], d0)
yr[ :nd] = C.T_HAT_MDCT[dt][1][ns-nd:ns] + d0
yr[nd:ns] = C.T_HAT_MDCT[dt][1][ns:2*ns-nd]
dr = C.T_HAT_MDCT[dt][1][2*ns-nd:]
(y, d1) = lc3.mdct_inverse(dt, sr, C.X_HAT_SNS[i0][1], d0)
yr[ :nd] = C.T_HAT_MDCT[i0][1][ns-nd:ns] + d0
yr[nd:ns] = C.T_HAT_MDCT[i0][1][ns:2*ns-nd]
dr = C.T_HAT_MDCT[i0][1][2*ns-nd:]
ok = ok and np.amax(np.abs(yr - y )) < 1e-1
ok = ok and np.amax(np.abs(dr - d1)) < 1e-1
@@ -191,7 +199,7 @@ def check():
ok = ok and check_forward_unit(rng, dt, sr)
ok = ok and check_inverse_unit(rng, dt, sr)
for dt in range(T.NUM_DT):
for dt in range(T.DT_7M5, T.NUM_DT):
ok = ok and check_forward_appendix_c(dt)
ok = ok and check_inverse_appendix_c(dt)

View File

@@ -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

View File

@@ -36,7 +36,7 @@ static PyObject *compute_scale_factors_py(PyObject *m, PyObject *args)
CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
int nb = LC3_MIN(lc3_band_lim[dt][sr][LC3_NUM_BANDS], LC3_NUM_BANDS);
int nb = lc3_num_bands[dt][sr];
CTYPES_CHECK("eb", to_1d_ptr(eb_obj, NPY_FLOAT, nb, &eb));
scf_obj = new_1d_ptr(NPY_FLOAT, 16, &scf);
@@ -150,7 +150,7 @@ static PyObject *analyze_py(PyObject *m, PyObject *args)
CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
int ne = LC3_NE(dt, sr);
int nb = LC3_MIN(ne, LC3_NUM_BANDS);
int nb = lc3_num_bands[dt][sr];
CTYPES_CHECK("eb", to_1d_ptr(eb_obj, NPY_FLOAT, nb, &eb));
CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));

View File

@@ -42,18 +42,17 @@ class SpectrumQuantization:
def get_noise_indices(self, bw, xq, lastnz):
nf_start = [ 18, 24 ][self.dt]
nf_width = [ 2, 3 ][self.dt]
nf_start = [ 6, 12, 18, 24 ][self.dt]
nf_width = [ 1, 1, 2, 3 ][self.dt]
bw_stop = int([ 80, 160, 240, 320, 400 ][bw] * (T.DT_MS[self.dt] / 10))
xq = np.append(xq[:lastnz], np.zeros(len(xq) - lastnz))
xq[:nf_start-nf_width] = 1
xq[min(bw_stop+nf_width+1,bw_stop):] = 1
i_nf = [ np.all(xq[k-nf_width:min(bw_stop, k+nf_width+1)] == 0)
for k in range(nf_start, bw_stop) ]
return (i_nf, nf_start, bw_stop)
return [ np.all(xq[max(k-nf_width, 0):min(k+nf_width+1, bw_stop)] == 0)
for k in range(len(xq)) ]
class SpectrumAnalysis(SpectrumQuantization):
@@ -118,7 +117,7 @@ class SpectrumAnalysis(SpectrumQuantization):
if reset_off:
g_idx = g_min
return (g_idx + g_off, reset_off)
return (g_min, g_idx + g_off, reset_off)
def quantize(self, g_int, x):
@@ -222,7 +221,7 @@ class SpectrumAnalysis(SpectrumQuantization):
(g_idx > 0 and nbits < nbits_spec - (delta + 2)):
if nbits < nbits_spec - (delta + 2):
return - 1
return -1
if g_idx == 254 or nbits < nbits_spec + delta:
return 1
@@ -234,12 +233,10 @@ class SpectrumAnalysis(SpectrumQuantization):
def estimate_noise(self, bw, xq, lastnz, x):
(i_nf, nf_start, nf_stop) = self.get_noise_indices(bw, xq, lastnz)
i_nf = self.get_noise_indices(bw, xq, lastnz)
l_nf = sum(abs(x * i_nf)) / sum(i_nf) if sum(i_nf) > 0 else 0
nf = 8 - 16 * sum(abs(x[nf_start:nf_stop] * i_nf)) / sum(i_nf) \
if sum(i_nf) > 0 else 0
return min(max(np.rint(nf).astype(int), 0), 7)
return min(max(np.rint(8 - 16 * l_nf).astype(int), 0), 7)
def run(self,
bw, nbytes, nbits_bw, nbits_ltpf, nbits_sns, nbits_tns, x):
@@ -268,7 +265,7 @@ class SpectrumAnalysis(SpectrumQuantization):
g_off = self.get_gain_offset(nbytes)
(g_int, self.reset_off) = \
(g_min, g_int, self.reset_off) = \
self.estimate_gain(x, nbits_spec, nbits_off, g_off)
self.nbits_off = nbits_off
self.nbits_spec = nbits_spec
@@ -285,6 +282,7 @@ class SpectrumAnalysis(SpectrumQuantization):
### Adjust gain and requantize
g_adj = self.adjust_gain(g_int - g_off, nbits_est, nbits_spec)
g_adj = max(g_int + g_adj, g_min + g_off) - g_int
(xg, xq, lastnz) = self.quantize(g_adj, xg)
@@ -410,9 +408,9 @@ class SpectrumSynthesis(SpectrumQuantization):
def fill_noise(self, bw, x, lastnz, f_nf, nf_seed):
(i_nf, nf_start, nf_stop) = self.get_noise_indices(bw, x, lastnz)
i_nf = self.get_noise_indices(bw, x, lastnz)
k_nf = nf_start + np.argwhere(i_nf)
k_nf = np.argwhere(i_nf)
l_nf = (8 - f_nf)/16
for k in k_nf:
@@ -578,6 +576,7 @@ def check_estimate_gain(rng, dt, sr):
analysis = SpectrumAnalysis(dt, sr)
mismatch_count = 0
for i in range(10):
x = rng.random(ne) * i * 1e2
@@ -586,14 +585,17 @@ def check_estimate_gain(rng, dt, sr):
nbits_off = rng.random() * 10
g_off = 10 - int(rng.random() * 20)
(g_int, reset_off) = \
(_, g_int, reset_off) = \
analysis.estimate_gain(x, nbits_budget, nbits_off, g_off)
(g_int_c, reset_off_c, _) = lc3.spec_estimate_gain(
dt, sr, x, nbits_budget, nbits_off, -g_off)
ok = ok and g_int_c == g_int
ok = ok and reset_off_c == reset_off
if g_int_c != g_int:
mismatch_count += 1
ok = ok and (g_int_c == g_int or mismatch_count <= 1)
ok = ok and (reset_off_c == reset_off or mismatch_count <= 1)
return ok
@@ -730,69 +732,71 @@ def check_noise(rng, dt, bw):
def check_appendix_c(dt):
i0 = dt - T.DT_7M5
sr = T.SRATE_16K
ne = T.NE[dt][sr]
ok = True
state_c = initial_state()
for i in range(len(C.X_F[dt])):
for i in range(len(C.X_F[i0])):
g_int = lc3.spec_estimate_gain(dt, sr, C.X_F[dt][i],
C.NBITS_SPEC[dt][i], C.NBITS_OFFSET[dt][i], -C.GG_OFF[dt][i])[0]
ok = ok and g_int == C.GG_IND[dt][i] + C.GG_OFF[dt][i]
g_int = lc3.spec_estimate_gain(dt, sr, C.X_F[i0][i],
C.NBITS_SPEC[i0][i], C.NBITS_OFFSET[i0][i], -C.GG_OFF[i0][i])[0]
ok = ok and g_int == C.GG_IND[i0][i] + C.GG_OFF[i0][i]
(_, xq, nq) = lc3.spec_quantize(dt, sr,
C.GG_IND[dt][i] + C.GG_OFF[dt][i], C.X_F[dt][i])
ok = ok and np.any((xq - C.X_Q[dt][i]) == 0)
ok = ok and nq == C.LASTNZ[dt][i]
C.GG_IND[i0][i] + C.GG_OFF[i0][i], C.X_F[i0][i])
ok = ok and np.any((xq - C.X_Q[i0][i]) == 0)
ok = ok and nq == C.LASTNZ[i0][i]
nbits = lc3.spec_compute_nbits(dt, sr,
C.NBYTES[dt], C.X_Q[dt][i], C.LASTNZ[dt][i], 0)[0]
ok = ok and nbits == C.NBITS_EST[dt][i]
C.NBYTES[i0], C.X_Q[i0][i], C.LASTNZ[i0][i], 0)[0]
ok = ok and nbits == C.NBITS_EST[i0][i]
g_adj = lc3.spec_adjust_gain(sr,
C.GG_IND[dt][i], C.NBITS_EST[dt][i], C.NBITS_SPEC[dt][i], 0)
ok = ok and g_adj == C.GG_IND_ADJ[dt][i] - C.GG_IND[dt][i]
C.GG_IND[i0][i], C.NBITS_EST[i0][i], C.NBITS_SPEC[i0][i], 0)
ok = ok and g_adj == C.GG_IND_ADJ[i0][i] - C.GG_IND[i0][i]
if C.GG_IND_ADJ[dt][i] != C.GG_IND[dt][i]:
if C.GG_IND_ADJ[i0][i] != C.GG_IND[i0][i]:
(_, xq, nq) = lc3.spec_quantize(dt, sr,
C.GG_IND_ADJ[dt][i] + C.GG_OFF[dt][i], C.X_F[dt][i])
lastnz = C.LASTNZ_REQ[dt][i]
ok = ok and np.any(((xq - C.X_Q_REQ[dt][i])[:lastnz]) == 0)
C.GG_IND_ADJ[i0][i] + C.GG_OFF[i0][i], C.X_F[i0][i])
lastnz = C.LASTNZ_REQ[i0][i]
ok = ok and np.any(((xq - C.X_Q_REQ[i0][i])[:lastnz]) == 0)
tns_data = {
'nfilters' : C.NUM_TNS_FILTERS[dt][i],
'nfilters' : C.NUM_TNS_FILTERS[i0][i],
'lpc_weighting' : [ True, True ],
'rc_order' : [ C.RC_ORDER[dt][i][0], 0 ],
'rc' : [ C.RC_I_1[dt][i] - 8, np.zeros(8, dtype = np.intc) ]
'rc_order' : [ C.RC_ORDER[i0][i][0], 0 ],
'rc' : [ C.RC_I_1[i0][i] - 8, np.zeros(8, dtype = np.intc) ]
}
(x, xq, side) = lc3.spec_analyze(dt, sr, C.NBYTES[dt],
C.PITCH_PRESENT[dt][i], tns_data, state_c, C.X_F[dt][i])
(x, xq, side) = lc3.spec_analyze(dt, sr, C.NBYTES[i0],
C.PITCH_PRESENT[i0][i], tns_data, state_c, C.X_F[i0][i])
ok = ok and np.abs(state_c['nbits_off'] - C.NBITS_OFFSET[dt][i]) < 1e-5
if C.GG_IND_ADJ[dt][i] != C.GG_IND[dt][i]:
xq = C.X_Q_REQ[dt][i]
nq = C.LASTNZ_REQ[dt][i]
ok = ok and side['g_idx'] == C.GG_IND_ADJ[dt][i]
ok = ok and np.abs(state_c['nbits_off'] - C.NBITS_OFFSET[i0][i]) < 1e-5
if C.GG_IND_ADJ[i0][i] != C.GG_IND[i0][i]:
xq = C.X_Q_REQ[i0][i]
nq = C.LASTNZ_REQ[i0][i]
ok = ok and side['g_idx'] == C.GG_IND_ADJ[i0][i]
ok = ok and side['nq'] == nq
ok = ok and np.any(((xq[:nq] - xq[:nq])) == 0)
else:
xq = C.X_Q[dt][i]
nq = C.LASTNZ[dt][i]
ok = ok and side['g_idx'] == C.GG_IND[dt][i]
xq = C.X_Q[i0][i]
nq = C.LASTNZ[i0][i]
ok = ok and side['g_idx'] == C.GG_IND[i0][i]
ok = ok and side['nq'] == nq
ok = ok and np.any((xq[:nq] - C.X_Q[dt][i][:nq]) == 0)
ok = ok and side['lsb_mode'] == C.LSB_MODE[dt][i]
ok = ok and np.any((xq[:nq] - C.X_Q[i0][i][:nq]) == 0)
ok = ok and side['lsb_mode'] == C.LSB_MODE[i0][i]
gg = C.GG[dt][i] if C.GG_IND_ADJ[dt][i] == C.GG_IND[dt][i] \
else C.GG_ADJ[dt][i]
gg = C.GG[i0][i] if C.GG_IND_ADJ[i0][i] == C.GG_IND[i0][i] \
else C.GG_ADJ[i0][i]
nf = lc3.spec_estimate_noise(dt, C.P_BW[dt][i],
xq, nq, C.X_F[dt][i] / gg)
ok = ok and nf == C.F_NF[dt][i]
nf = lc3.spec_estimate_noise(dt, C.P_BW[i0][i],
xq, nq, C.X_F[i0][i] / gg)
ok = ok and nf == C.F_NF[i0][i]
return ok
@@ -810,7 +814,7 @@ def check():
ok = ok and check_unit(rng, dt, sr)
ok = ok and check_noise(rng, dt, sr)
for dt in range(T.NUM_DT):
for dt in range(T.DT_7M5, T.NUM_DT):
ok = ok and check_appendix_c(dt)
return ok

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -36,13 +36,14 @@ static PyObject *compute_lpc_coeffs_py(PyObject *m, PyObject *args)
CTYPES_CHECK("sr", (unsigned)bw < LC3_NUM_BANDWIDTH);
int ne = LC3_NE(dt, bw);
int maxorder = dt <= LC3_DT_5M ? 4 : 8;
CTYPES_CHECK("x", to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
g_obj = new_1d_ptr(NPY_FLOAT, 2, &g);
a_obj = new_2d_ptr(NPY_FLOAT, 2, 9, &a);
compute_lpc_coeffs(dt, bw, x, g, a);
compute_lpc_coeffs(dt, bw, maxorder, x, g, a);
return Py_BuildValue("NN", g_obj, a_obj);
}
@@ -50,15 +51,20 @@ static PyObject *compute_lpc_coeffs_py(PyObject *m, PyObject *args)
static PyObject *lpc_reflection_py(PyObject *m, PyObject *args)
{
PyObject *a_obj, *rc_obj;
unsigned dt;
float *a, *rc;
if (!PyArg_ParseTuple(args, "O", &a_obj))
if (!PyArg_ParseTuple(args, "IO", &dt, &a_obj))
return NULL;
CTYPES_CHECK("a", to_1d_ptr(a_obj, NPY_FLOAT, 9, &a));
rc_obj = new_1d_ptr(NPY_FLOAT, 8, &rc);
CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
lpc_reflection(a, rc);
int maxorder = dt <= LC3_DT_5M ? 4 : 8;
CTYPES_CHECK("a", to_1d_ptr(a_obj, NPY_FLOAT, 9, &a));
rc_obj = new_1d_ptr(NPY_FLOAT, maxorder, &rc);
lpc_reflection(a, maxorder, rc);
return Py_BuildValue("N", rc_obj);
}
@@ -66,17 +72,21 @@ static PyObject *lpc_reflection_py(PyObject *m, PyObject *args)
static PyObject *quantize_rc_py(PyObject *m, PyObject *args)
{
PyObject *rc_obj, *rc_q_obj;
unsigned dt;
float *rc;
int rc_order, *rc_q;
if (!PyArg_ParseTuple(args, "O", &rc_obj))
if (!PyArg_ParseTuple(args, "IO", &dt, &rc_obj))
return NULL;
CTYPES_CHECK("rc", to_1d_ptr(rc_obj, NPY_FLOAT, 8, &rc));
CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
int maxorder = dt <= LC3_DT_5M ? 4 : 8;
CTYPES_CHECK("rc", to_1d_ptr(rc_obj, NPY_FLOAT, 8, &rc));
rc_q_obj = new_1d_ptr(NPY_INT, 8, &rc_q);
quantize_rc(rc, &rc_order, rc_q);
quantize_rc(rc, maxorder, &rc_order, rc_q);
return Py_BuildValue("iN", rc_order, rc_q_obj);
}

View File

@@ -33,7 +33,7 @@ struct lc3bin_header {
uint16_t bitrate_100bps;
uint16_t channels;
uint16_t frame_10us;
uint16_t rfu;
uint16_t epmode;
uint16_t nsamples_low;
uint16_t nsamples_high;
};
@@ -46,17 +46,26 @@ int lc3bin_read_header(FILE *fp,
int *frame_us, int *srate_hz, int *nchannels, int *nsamples)
{
struct lc3bin_header hdr;
uint16_t hrmode = 0;
if (fread(&hdr, sizeof(hdr), 1, fp) != 1
|| hdr.file_id != LC3_FILE_ID
|| hdr.header_size < sizeof(hdr))
return -1;
int num_extended_params = (hdr.header_size - sizeof(hdr)) / sizeof(uint16_t);
if (num_extended_params >= 1 &&
fread(&hrmode, sizeof(hrmode), 1, fp) != 1)
return -1;
*nchannels = hdr.channels;
*frame_us = hdr.frame_10us * 10;
*srate_hz = hdr.srate_100hz * 100;
*nsamples = hdr.nsamples_low | (hdr.nsamples_high << 16);
if (hdr.epmode || hrmode)
return -1;
fseek(fp, hdr.header_size, SEEK_SET);
return 0;