static inline void silk_stabilize_lsf(int16_t nlsf[16], int order, const uint16_t min_delta[17]) { int pass, i; for (pass = 0; pass < 20; pass++) { int k, min_diff = 0; for (i = 0; i < order+1; i++) { int low = i != 0 ? nlsf[i-1] : 0; int high = i != order ? nlsf[i] : 32768; int diff = (high - low) - (min_delta[i]); if (diff < min_diff) { min_diff = diff; k = i; if (pass == 20) break; } } if (min_diff == 0) /* no issues; stabilized */ return; /* wiggle one or two LSFs */ if (k == 0) { /* repel away from lower bound */ nlsf[0] = min_delta[0]; } else if (k == order) { /* repel away from higher bound */ nlsf[order-1] = 32768 - min_delta[order]; } else { /* repel away from current position */ int min_center = 0, max_center = 32768, center_val; /* lower extent */ for (i = 0; i < k; i++) min_center += min_delta[i]; min_center += min_delta[k] >> 1; /* upper extent */ for (i = order; i > k; i--) max_center -= min_delta[k]; max_center -= min_delta[k] >> 1; /* move apart */ center_val = nlsf[k - 1] + nlsf[k]; center_val = (center_val >> 1) + (center_val & 1); // rounded divide by 2 center_val = FFMIN(max_center, FFMAX(min_center, center_val)); nlsf[k - 1] = center_val - (min_delta[k] >> 1); nlsf[k] = nlsf[k - 1] + min_delta[k]; } } /* resort to the fall-back method, the standard method for LSF stabilization */ /* sort; as the LSFs should be nearly sorted, use insertion sort */ for (i = 1; i < order; i++) { int j, value = nlsf[i]; for (j = i - 1; j >= 0 && nlsf[j] > value; j--) nlsf[j + 1] = nlsf[j]; nlsf[j + 1] = value; } /* push forwards to increase distance */ if (nlsf[0] < min_delta[0]) nlsf[0] = min_delta[0]; for (i = 1; i < order; i++) if (nlsf[i] < nlsf[i - 1] + min_delta[i]) nlsf[i] = nlsf[i - 1] + min_delta[i]; /* push backwards to increase distance */ if (nlsf[order-1] > 32768 - min_delta[order]) nlsf[order-1] = 32768 - min_delta[order]; for (i = order-2; i >= 0; i--) if (nlsf[i] > nlsf[i + 1] - min_delta[i+1]) nlsf[i] = nlsf[i + 1] - min_delta[i+1]; return; }