static void filter_channel(MLPDecodeContext *m, unsigned int substr,
                           unsigned int channel)
{
    SubStream *s = &m->substream[substr];
    int32_t firbuf[MAX_BLOCKSIZE + MAX_FIR_ORDER];
    int32_t iirbuf[MAX_BLOCKSIZE + MAX_IIR_ORDER];
    FilterParams *fir = &m->channel_params[channel].filter_params[FIR];
    FilterParams *iir = &m->channel_params[channel].filter_params[IIR];
    unsigned int filter_shift = fir->shift;
    int32_t mask = MSB_MASK(s->quant_step_size[channel]);
    int index = MAX_BLOCKSIZE;
    int i;

    memcpy(&firbuf[index], fir->state,
            MAX_FIR_ORDER * sizeof(int32_t));
    memcpy(&iirbuf[index], iir->state,
            MAX_IIR_ORDER * sizeof(int32_t));

    for (i = 0; i < s->blocksize; i++) {
        int32_t residual = m->sample_buffer[i + s->blockpos][channel];
        unsigned int order;
        int64_t accum = 0;
        int32_t result;

        /* TODO: Move this code to DSPContext? */

        for (order = 0; order < fir->order; order++)
            accum += (int64_t)firbuf[index + order] *
                                fir->coeff[order];
        for (order = 0; order < iir->order; order++)
            accum += (int64_t)iirbuf[index + order] *
                                iir->coeff[order];

        accum  = accum >> filter_shift;
        result = (accum + residual) & mask;

        --index;

        firbuf[index] = result;
        iirbuf[index] = result - accum;

        m->sample_buffer[i + s->blockpos][channel] = result;
    }

    memcpy(fir->state, &firbuf[index],
            MAX_FIR_ORDER * sizeof(int32_t));
    memcpy(iir->state, &iirbuf[index],
            MAX_IIR_ORDER * sizeof(int32_t));
}