#This work is licensed under the
#Creative Commons Attribution-Share Alike 3.0 United States License.
#To view a copy of this license, visit
#http://creativecommons.org/licenses/by-sa/3.0/us/ or send a letter to
#Creative Commons,
#171 Second Street, Suite 300,
#San Francisco, California, 94105, USA.

INPUT block_size[s],quant_step_size[s][c],residual[s][c],
fir_order[s][c],fir_shift[s][c],fir_coeff[s][c],fir_state[s][c],
iir_order[s][c],iir_shift[s][c],iir_coeff[s][c],iir_state[s][c];
OUTPUT filtered[s][c],fir_state[s][c],iir_state[s][c];
VAR fir_order "FIR order";
VAR fir_shift "FIR shift";
VAR fir_coeff "FIR coefficient";
VAR fir_state "FIR state";
VAR iir_order "IIR order";
VAR iir_shift "IIR shift";
VAR iir_coeff "IIR coefficient";
VAR iir_state "IIR state";
VAR quant_step_size "quant_step_size";
VAR shift "shift";
VAR filtered "filtered";
VAR fir_sum "FIR sum";
VAR iir_sum "IIR sum";
VAR residual "residual";
VAR block_size "block size";
VAR sum_ "sum";
VAR value "value";
assert (fir_order[s][c] + iir_order[s][c]) <= 8;
if (fir_order[s][c] > 0) and (iir_order[s][c] > 0) {
    assert fir_shift[s][c] == iir_shift[s][c];
    shift <- fir_shift[s][c];
} elif fir_order[s][c] > 0 {
    shift <- fir_shift[s][c];
} else {
    shift <- iir_shift[s][c];
}
for i <- 0 to block_size[s] {
    fir_sum <- sum j <- 0 to fir_order[s][c]
               {fir_coeff[s][c][j] *
                fir_state[s][c][(fir_order[s][c] - j - 1)]};
    iir_sum <- sum k <- 0 to iir_order[s][c]
               {iir_coeff[s][c][k] *
                iir_state[s][c][(iir_order[s][c] - k - 1)]};
    sum_ <- floor((fir_sum + iir_sum) / 2 ^ shift);
    if quant_step_size[s][c] == 0 {
        value <- sum_ + residual[s][c][i];
    } else {
        value <- floor(sum_ / 2 ^ quant_step_size[s][c]) * 2 ^ quant_step_size[s][c] + residual[s][c][i];
    }
    filtered[s][c][i] <- value;
    if fir_order[s][c] > 0 {
        for j <- 0 to (fir_order[s][c] - 1)
            /*shift FIR state values down by 1*/ {
            fir_state[s][c][j] <- fir_state[s][c][(j + 1)];
        }
        fir_state[s][c][(fir_order[s][c])] <- value
            /*append new FIR state value*/;
    }
    if iir_order[s][c] > 0 {
        for k <- 0 to (iir_order[s][c] - 1)
            /*shift IIR state values down by 1*/ {
            iir_state[s][c][k] <- iir_state[s][c][(k + 1)];
        }
        iir_state[s][c][(iir_order[s][c])] <- value - sum_
            /*append new IIR state value*/;
    }
}
return filtered[s][c],fir_state[s][c],iir_state[s][c];
