#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 LPC_order,LP_coeff,QLP_precision;
OUTPUT QLP_coeff,QLP_shift;
VAR LPC_order "LPC order";
VAR LP_coeff "LP coefficient";
VAR QLP_shift "QLP shift needed";
VAR QLP_precision "QLP precision";
VAR QLP_max "QLP maximum";
VAR QLP_min "QLP minimum";
VAR QLP_coeff "QLP coefficient";
VAR error "error";
FUNC excessive_negative_shift "excessive negative shift error";
l <- 0;
for i <- 0 to LPC_order /*find largest LP coefficient*/ {
    c <- LP_coeff[(LPC_order - 1)][i];
    if |c| > l {
        l <- |c|;
    }
}
QLP_shift <- (QLP_precision - 1) - (floor(log 2 {l}) - 1) - 1;
if QLP_shift > 2 ^ 4 - 1 /*must fit into signed, 5-bit field*/ {
   QLP_shift <- 2 ^ 4 - 1;
} elif (QLP_shift < -(2 ^ 4)) {
    excessive_negative_shift();
}
;
QLP_max <- 2 ^ {QLP_precision - 1} - 1;
QLP_min <- -(2 ^ {QLP_precision - 1});
error <- 0.0;
for i <- 0 to LPC_order {
    if QLP_shift >= 0 {
        error <- error + LP_coeff[(LPC_order - 1)][i] * 2 ^ QLP_shift;
    } else /*shrink negative coefficients*/ {
        error <- error + LP_coeff[(LPC_order - 1)][i] / 2 ^ QLP_shift;
    }
    c[i] <- round(error);
    if c[i] > QLP_max {
        QLP_coeff[i] <- QLP_max;
    } elif c[i] < QLP_min {
        QLP_coeff[i] <- QLP_min;
    } else {
        QLP_coeff[i] <- c[i];
    }
    error <- error - QLP_coeff[i];
}
if QLP_shift >= 0 {
    return QLP_coeff,QLP_shift;
} else {
    return QLP_coeff,0;
}
