#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 bits_per_sample, block_size, predicted;
OUTPUT residual;
VAR bits_per_sample "bits-per-sample";
VAR block_size "block size";
VAR predicted "predicted";
VAR shift "shift";
VAR round "round";
VAR qm "qm";
VAR dx "dx";
VAR dl "dl";
VAR sum_ "sum";
VAR residual "residual";

switch bits_per_sample {
    case 8 {
       shift <- 10;
    }
    case 16 {
       shift <- 9;
    }
    case 24 {
       shift <- 10;
    }
}
round <- 2 ^ {shift - 1};
qm,dx,dl <- [0, 0, 0, 0, 0, 0, 0, 0];
for i <- 0 to block_size {
    if i == 0 {
        residual[0] <- predicted[0] + floor(round / 2 ^ shift);
    } else {
        for j <- 0 to 8 {
            if residual[i - 1] > 0 {
                qm[j] <- qm[j] + dx[j];
            } elif residual[i - 1] < 0 {
                qm[j] <- qm[j] - dx[j];
            }
        }
        sum_ <- round + sum j <- 0 to 7 {dl[j] * qm[j]};
        /*sum is stored in a signed 32-bit value and may wrap in rare instances*/;
        while sum_ >= 2 ^ 31 {
            sum_ <- sum_ - 2 ^ 32;
        }
        while sum_ < -2 ^ 31 {
            sum_ <- sum_ + 2 ^ 32;
        }
        residual[i] <- predicted[i] - floor(sum_ / 2 ^ shift);
    }
    dx[0] <- dx[1];
    dx[1] <- dx[2];
    dx[2] <- dx[3];
    dx[3] <- dx[4];
    dx[4] <- 1 if dl[4] >= 0 else -1;
    dx[5] <- 2 if dl[5] >= 0 else -2;
    dx[6] <- 2 if dl[6] >= 0 else -2;
    dx[7] <- 4 if dl[7] >= 0 else -4;
    dl[0] <- dl[1];
    dl[1] <- dl[2];
    dl[2] <- dl[3];
    dl[3] <- dl[4];
    dl[4] <- -dl[5] + (-dl[6] + (predicted[i] - dl[7]));
    dl[5] <- -dl[6] + (predicted[i] - dl[7]);
    dl[6] <- predicted[i] - dl[7];
    dl[7] <- predicted[i];
}
return residual;
