static int combine_residual_frame(DCAXllDecoder *s, DCAXllChSet *c)

{

    DCAContext *dca = s->avctx->priv_data;

    int ch, nsamples = s->nframesamples;

    DCAXllChSet *o;



    // Verify that core is compatible

    if (!(dca->packet & DCA_PACKET_CORE)) {

        av_log(s->avctx, AV_LOG_ERROR, "Residual encoded channels are present without core\n");

        return AVERROR(EINVAL);

    }



    if (c->freq != dca->core.output_rate) {

        av_log(s->avctx, AV_LOG_WARNING, "Sample rate mismatch between core (%d Hz) and XLL (%d Hz)\n", dca->core.output_rate, c->freq);

        return AVERROR_INVALIDDATA;

    }



    if (nsamples != dca->core.npcmsamples) {

        av_log(s->avctx, AV_LOG_WARNING, "Number of samples per frame mismatch between core (%d) and XLL (%d)\n", dca->core.npcmsamples, nsamples);

        return AVERROR_INVALIDDATA;

    }



    // See if this channel set is downmixed and find the next channel set in

    // hierarchy. If downmixed, undo core pre-scaling before combining with

    // residual (residual is not scaled).

    o = find_next_hier_dmix_chset(s, c);



    // Reduce core bit width and combine with residual

    for (ch = 0; ch < c->nchannels; ch++) {

        int n, spkr, shift, round;

        int32_t *src, *dst;



        if (c->residual_encode & (1 << ch))

            continue;



        // Map this channel to core speaker

        spkr = ff_dca_core_map_spkr(&dca->core, c->ch_remap[ch]);

        if (spkr < 0) {

            av_log(s->avctx, AV_LOG_WARNING, "Residual encoded channel (%d) references unavailable core channel\n", c->ch_remap[ch]);

            return AVERROR_INVALIDDATA;

        }



        // Account for LSB width

        shift = 24 - c->pcm_bit_res + chs_get_lsb_width(s, c, 0, ch);

        if (shift > 24) {

            av_log(s->avctx, AV_LOG_WARNING, "Invalid core shift (%d bits)\n", shift);

            return AVERROR_INVALIDDATA;

        }



        round = shift > 0 ? 1 << (shift - 1) : 0;



        src = dca->core.output_samples[spkr];

        dst = c->bands[0].msb_sample_buffer[ch];

        if (o) {

            // Undo embedded core downmix pre-scaling

            int scale_inv = o->dmix_scale_inv[c->hier_ofs + ch];

            for (n = 0; n < nsamples; n++)

                dst[n] += (SUINT)clip23((mul16(src[n], scale_inv) + round) >> shift);

        } else {

            // No downmix scaling

            for (n = 0; n < nsamples; n++)

                dst[n] += (src[n] + round) >> shift;

        }

    }



    return 0;

}
