#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 "list of QLP coefficients, QLP coefficient count, list of PCM samples, sample count, sample size";
INPUT QLP_coeff,QLP_coeff_count,sample,sample_count,sample_size;
OUTPUT "list of residual values as signed integers";
VAR QLP_coeff "QLP coefficient";
VAR QLP_coeff_count "QLP coefficient count";
VAR QLP_sum "QLP sum";
VAR sample "sample";
VAR sample_count "sample count";
VAR sample_size "sample size";
VAR residual "residual";
VAR base_sample "base sample";
VAR diff "diff";
VAR sign "sign";
VAR error "error";
residual[0] <- sample[i] /*first sample always copied verbatim*/;
for i <- 1 to (QLP_coeff_count + 1) {
    residual[i] <- truncate(sample[i] - sample[i - 1], sample_size);
}
for i <- (QLP_coeff_count + 1) to sample_count {
    base_sample[i] <- sample[i - QLP_coeff_count - 1];
    QLP_sum[i] <- sum j <- 0 to QLP_coeff_count - 1
                  {QLP_coeff[j] * (sample[i - j - 1] - base_sample[i])};
    error <- truncate(sample[i] -
                      base_sample[i] -
                      floor(frac(QLP_sum[i] + 2 ^ 8, 2 ^ 9)),
                      sample_size);
    residual[i] <- error;
    if residual[i] > 0 {
        for j <- QLP_coeff_count downto 0 {
            diff <- base_sample[i] - sample[i - j - 1];
            sign <- sign(diff);
            QLP_coeff[j] <- QLP_coeff[j] - sign;
            error <- error - floor(frac(diff * sign, 2 ^ 9)) *
                             (QLP_coeff_count - j);
            if error <= 0 {
                break;
            }
        }
    } elif residual[i] < 0 {
        for j <- QLP_coeff_count downto 0 {
            diff <- base_sample[i] - sample[i - j - 1];
            sign <- sign(diff);
            QLP_coeff[j] <- QLP_coeff[j] + sign;
            error <- error - floor(frac(diff * -sign, 2 ^ 9)) *
                             (QLP_coeff_count - j);
            if error >= 0 {
                break;
            }
        }
    }
}
return residual;
