Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ccb12700 authored by Antoine Soulier's avatar Antoine Soulier Committed by Jakub Pawlowski
Browse files

Merge LC3 fixes and improvements

This patch is a copy-paste of lastest LC3 encoder/decoder version.
Folowing patches were added:
Add downsampling / upsampling options for encoder / decoder
src: fix dereference of encoder before check of nullity
test: fix parenthisis typo
fix: Improper buffer initialization, when resampling disabled
fix: parameter of setup_encoder() sadly inverted

Bug: 150670922
Test: compile
Change-Id: If91239d18d7a6c05cc68b11dcebbfd063fe8da02
parent 2aca920b
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -205,6 +205,9 @@ int lc3_delay_samples(int dt_us, int sr_hz);
 * dt_us           Frame duration in us, 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
 *
 * The `sr_hz` parameter is the samplerate of the PCM input stream,
 * and will match `sr_pcm_hz` of `lc3_setup_encoder()`.
 */
unsigned lc3_encoder_size(int dt_us, int sr_hz);

@@ -212,10 +215,18 @@ unsigned lc3_encoder_size(int dt_us, int sr_hz);
 * Setup encoder
 * dt_us           Frame duration in us, 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
 * return          Encoder as an handle, NULL on bad parameters
 *
 * The `sr_pcm_hz` parameter is a downsampling option of PCM input,
 * the value `0` fallback to the samplerate of the encoded stream `sr_hz`.
 * When used, `sr_pcm_hz` is intended to be higher or equal to the encoder
 * samplerate `sr_hz`. The size of the context needed, given by
 * `lc3_encoder_size()` will be set accordingly to `sr_pcm_hz`.
 */
lc3_encoder_t lc3_setup_encoder(int dt_us, int sr_hz, void *mem);
lc3_encoder_t lc3_setup_encoder(
    int dt_us, int sr_hz, int sr_pcm_hz, void *mem);

/**
 * Encode a frame
@@ -233,6 +244,9 @@ int lc3_encode(lc3_encoder_t encoder,
 * dt_us           Frame duration in us, 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
 *
 * The `sr_hz` parameter is the samplerate of the PCM output stream,
 * and will match `sr_pcm_hz` of `lc3_setup_decoder()`.
 */
unsigned lc3_decoder_size(int dt_us, int sr_hz);

@@ -240,10 +254,18 @@ unsigned lc3_decoder_size(int dt_us, int sr_hz);
 * Setup decoder
 * dt_us           Frame duration in us, 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
 * return          Decoder as an handle, NULL on bad parameters
 *
 * The `sr_pcm_hz` parameter is an upsampling option of PCM output,
 * the value `0` fallback to the samplerate of the decoded stream `sr_hz`.
 * When used, `sr_pcm_hz` is intended to be higher or equal to the decoder
 * samplerate `sr_hz`. The size of the context needed, given by
 * `lc3_decoder_size()` will be set accordingly to `sr_pcm_hz`.
 */
lc3_decoder_t lc3_setup_decoder(int dt_us, int sr_hz, void *mem);
lc3_decoder_t lc3_setup_decoder(
    int dt_us, int sr_hz, int sr_pcm_hz, void *mem);

/**
 * Decode a frame
+2 −2
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@ typedef struct lc3_spec_analysis {

struct lc3_encoder {
    enum lc3_dt dt;
    enum lc3_srate sr;
    enum lc3_srate sr, sr_pcm;

    lc3_attdet_analysis_t attdet;
    lc3_ltpf_analysis_t ltpf;
@@ -134,7 +134,7 @@ typedef struct lc3_plc_state {

struct lc3_decoder {
    enum lc3_dt dt;
    enum lc3_srate sr;
    enum lc3_srate sr, sr_pcm;

    lc3_ltpf_synthesis_t ltpf;
    lc3_plc_state_t plc;
+40 −25
Original line number Diff line number Diff line
@@ -153,7 +153,7 @@ static void load_s16(
    struct lc3_encoder *encoder, const int16_t *pcm, int pitch)
{
    enum lc3_dt dt = encoder->dt;
    enum lc3_srate sr = encoder->sr;
    enum lc3_srate sr = encoder->sr_pcm;
    float *xs = encoder->xs;
    int ns = LC3_NS(dt, sr);

@@ -172,23 +172,25 @@ static void analyze(struct lc3_encoder *encoder,
{
    enum lc3_dt dt = encoder->dt;
    enum lc3_srate sr = encoder->sr;
    enum lc3_srate sr_pcm = encoder->sr_pcm;
    int ns = LC3_NS(dt, sr_pcm);
    int nd = LC3_ND(dt, sr_pcm);

    float *xs = encoder->xs;
    float *xf = encoder->xf;
    int ns = LC3_NS(dt, sr);
    int nd = LC3_ND(dt, sr);

    /* --- Temporal --- */

    bool att = lc3_attdet_run(dt, sr, nbytes, &encoder->attdet, xs);
    bool att = lc3_attdet_run(dt, sr_pcm, nbytes, &encoder->attdet, xs);

    side->pitch_present =
        lc3_ltpf_analyse(dt, sr, &encoder->ltpf, xs, &side->ltpf);
        lc3_ltpf_analyse(dt, sr_pcm, &encoder->ltpf, xs, &side->ltpf);

    /* --- Spectral --- */

    float e[LC3_NUM_BANDS];

    lc3_mdct_forward(dt, sr, xs, xf);
    lc3_mdct_forward(dt, sr_pcm, sr, xs, xf);
    memmove(xs - nd, xs + ns-nd, nd * sizeof(float));

    bool nn_flag = lc3_energy_compute(dt, sr, xf, e);
@@ -260,26 +262,32 @@ unsigned lc3_encoder_size(int dt_us, int sr_hz)
/**
 * Setup encoder
 */
struct lc3_encoder *lc3_setup_encoder(int dt_us, int sr_hz, void *mem)
struct lc3_encoder *lc3_setup_encoder(
    int dt_us, int sr_hz, int sr_pcm_hz, void *mem)
{
    if (sr_pcm_hz <= 0)
        sr_pcm_hz = sr_hz;

    enum lc3_dt dt = resolve_dt(dt_us);
    enum lc3_srate sr = resolve_sr(sr_hz);
    enum lc3_srate sr_pcm = resolve_sr(sr_pcm_hz);

    if (dt >= LC3_NUM_DT || sr >= LC3_NUM_SRATE || !mem)
    if (dt >= LC3_NUM_DT || sr_pcm >= LC3_NUM_SRATE || sr > sr_pcm || !mem)
        return NULL;

    struct lc3_encoder *encoder = mem;
    int ns = LC3_NS(dt, sr);
    int nd = LC3_ND(dt, sr);
    int ns = LC3_NS(dt, sr_pcm);
    int nd = LC3_ND(dt, sr_pcm);

    *encoder = (struct lc3_encoder){
        .dt = dt, .sr = sr,
        .sr_pcm = sr_pcm,
        .xs = encoder->s + nd,
        .xf = encoder->s + nd+ns,
    };

    memset(encoder->s, 0,
        LC3_ENCODER_BUFFER_COUNT(dt_us, sr_hz) * sizeof(float));
        LC3_ENCODER_BUFFER_COUNT(dt_us, sr_pcm_hz) * sizeof(float));

    return encoder;
}
@@ -324,7 +332,7 @@ static void store_s16(
    struct lc3_decoder *decoder, int16_t *pcm, int pitch)
{
    enum lc3_dt dt = decoder->dt;
    enum lc3_srate sr = decoder->sr;
    enum lc3_srate sr = decoder->sr_pcm;
    float *xs = decoder->xs;
    int ns = LC3_NS(dt, sr);

@@ -391,8 +399,9 @@ static void synthesize(struct lc3_decoder *decoder,
{
    enum lc3_dt dt = decoder->dt;
    enum lc3_srate sr = decoder->sr;
    int ns = LC3_NS(dt, sr);
    int nh = LC3_NH(sr);
    enum lc3_srate sr_pcm = decoder->sr_pcm;
    int ns = LC3_NS(dt, sr_pcm);
    int nh = LC3_NH(sr_pcm);

    float *xf = decoder->xs;
    float *xg = decoder->xg;
@@ -408,15 +417,15 @@ static void synthesize(struct lc3_decoder *decoder,

        lc3_sns_synthesize(dt, sr, &side->sns, xf, xg);

        lc3_mdct_inverse(dt, sr, xg, xd, xs);
        lc3_mdct_inverse(dt, sr_pcm, sr, xg, xd, xs);

    } else {
        lc3_plc_synthesize(dt, sr, &decoder->plc, xg, xf);

        lc3_mdct_inverse(dt, sr, xf, xd, xs);
        lc3_mdct_inverse(dt, sr_pcm, sr, xf, xd, xs);
    }

    lc3_ltpf_synthesize(dt, sr, nbytes, &decoder->ltpf,
    lc3_ltpf_synthesize(dt, sr_pcm, nbytes, &decoder->ltpf,
        side && side->pitch_present ? &side->ltpf : NULL, xs);

    memmove(xs - nh, xs - nh+ns, nh * sizeof(*xs));
@@ -438,21 +447,27 @@ unsigned lc3_decoder_size(int dt_us, int sr_hz)
/**
 * Setup decoder
 */
struct lc3_decoder *lc3_setup_decoder(int dt_us, int sr_hz, void *mem)
struct lc3_decoder *lc3_setup_decoder(
    int dt_us, int sr_hz, int sr_pcm_hz, void *mem)
{
    if (sr_pcm_hz <= 0)
        sr_pcm_hz = sr_hz;

    enum lc3_dt dt = resolve_dt(dt_us);
    enum lc3_srate sr = resolve_sr(sr_hz);
    enum lc3_srate sr_pcm = resolve_sr(sr_pcm_hz);

    if (dt >= LC3_NUM_DT || sr >= LC3_NUM_SRATE || !mem)
    if (dt >= LC3_NUM_DT || sr_pcm >= LC3_NUM_SRATE || sr > sr_pcm || !mem)
        return NULL;

    struct lc3_decoder *decoder = mem;
    int nh = LC3_NH(sr);
    int ns = LC3_NS(dt, sr);
    int nd = LC3_ND(dt, sr);
    int nh = LC3_NH(sr_pcm);
    int ns = LC3_NS(dt, sr_pcm);
    int nd = LC3_ND(dt, sr_pcm);

    *decoder = (struct lc3_decoder){
        .dt = dt, .sr = sr,
        .sr_pcm = sr_pcm,
        .xs = decoder->s + nh,
        .xd = decoder->s + nh+ns,
        .xg = decoder->s + nh+ns+nd,
@@ -461,7 +476,7 @@ struct lc3_decoder *lc3_setup_decoder(int dt_us, int sr_hz, void *mem)
    lc3_plc_reset(&decoder->plc);

    memset(decoder->s, 0,
        LC3_DECODER_BUFFER_COUNT(dt_us, sr_hz) * sizeof(float));
        LC3_DECODER_BUFFER_COUNT(dt_us, sr_pcm_hz) * sizeof(float));

    return decoder;
}
@@ -472,8 +487,6 @@ struct lc3_decoder *lc3_setup_decoder(int dt_us, int sr_hz, void *mem)
int lc3_decode(struct lc3_decoder *decoder,
    const void *in, int nbytes, int16_t *pcm, int pitch)
{
    struct side_data side;

    /* --- Check parameters --- */

    if (!decoder)
@@ -485,6 +498,8 @@ int lc3_decode(struct lc3_decoder *decoder,

    /* --- Processing --- */

    struct side_data side;

    int ret = !in || (decode(decoder, in, nbytes, &side) < 0);

    synthesize(decoder, ret ? NULL : &side, nbytes);
+6 −4
Original line number Diff line number Diff line
@@ -464,9 +464,10 @@ static void imdct_window(enum lc3_dt dt, enum lc3_srate sr,
 * Forward MDCT transformation
 */
void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr,
    const float *x, float *y)
    enum lc3_srate sr_dst, const float *x, float *y)
{
    const struct lc3_mdct_rot_def *rot = lc3_mdct_rot[dt][sr];
    int nf = LC3_NS(dt, sr_dst);
    int ns = LC3_NS(dt, sr);

    union { float *f; struct lc3_complex *z; } u = { .f = y };
@@ -476,16 +477,17 @@ void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr,

    mdct_pre_fft(rot, u.f, u.z);
    u.z = fft(false, u.z, ns/2, u.z, z);
    mdct_post_fft(rot, u.z, y, sqrtf(2.f / ns));
    mdct_post_fft(rot, u.z, y, sqrtf( (2.f*nf) / (ns*ns) ));
}

/**
 * Inverse MDCT transformation
 */
void lc3_mdct_inverse(enum lc3_dt dt, enum lc3_srate sr,
    const float *x, float *d, float *y)
    enum lc3_srate sr_src, const float *x, float *d, float *y)
{
    const struct lc3_mdct_rot_def *rot = lc3_mdct_rot[dt][sr];
    int nf = LC3_NS(dt, sr_src);
    int ns = LC3_NS(dt, sr);

    struct lc3_complex buffer[ns/2];
@@ -494,7 +496,7 @@ void lc3_mdct_inverse(enum lc3_dt dt, enum lc3_srate sr,

    imdct_pre_fft(rot, x, z);
    z = fft(true, z, ns/2, z, u.z);
    imdct_post_fft(rot, z, u.f, sqrtf(2.f / ns));
    imdct_post_fft(rot, z, u.f, sqrtf(2.f / nf));

    imdct_window(dt, sr, u.f, d, y);
}
+4 −2
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
/**
 * Forward MDCT transformation
 * dt, sr          Duration and samplerate (size of the transform)
 * sr_dst          Samplerate destination, scale transforam accordingly
 * x               [-nd..-1] Previous, [0..ns-1] Current samples
 * y               Output `ns` frequency coefficients
 *
@@ -40,18 +41,19 @@
 *   nd: `ns` *  5/ 8 for  10ms frame duration
 */
void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr,
    const float *x, float *y);
    enum lc3_srate sr_dst, const float *x, float *y);

/**
 * Inverse MDCT transformation
 * dt, sr          Duration and samplerate (size of the transform)
 * sr_src          Samplerate source, scale transforam accordingly
 * x, d            Frequency coefficients and delayed buffer
 * y, d            Output `ns` samples and `nd` delayed ones
 *
 * `x` and `y` can be the same buffer
 */
void lc3_mdct_inverse(enum lc3_dt dt, enum lc3_srate sr,
    const float *x, float *d, float *y);
    enum lc3_srate sr_src, const float *x, float *d, float *y);


#endif /* __LC3_MDCT_H */