import config, image, filter     

def cdf_9x7_filter_nosubsample(V const *indata, int n, instep,
    V *outlow, int lowstep, V *outhigh, int highstep, int scale):
    V lowpass9[] = {0.026748757411, -0.016864118443, -0.078223266529,
        0.266864118443, 0.602949018236, 0.266864118443,
        -0.078223266529, -0.016864118443, 0.026748757411}
    V highpass7[] = {0.091271763114, -0.057543526229, -0.591271763114,
        1.11508705, -0.591271763114, -0.057543526229, 0.091271763114}

    double q = sqrt(2.0)
    for int i = 0; i < 9; i++: lowpass9[i] *= q
    for int i = 0; i < 7; i++: highpass7[i] *= q

    filter(indata, n, instep, lowpass9, 9, outlow, lowstep, 1 << scale)
    filter(indata, n, instep, highpass7, 7, outhigh, highstep, 1 << scale)

def cdf_9x7_filter_nosubsample_param(V const *indata, int n, instep,
    V *outlow, int lowstep, V *outhigh, int highstep, int scale, V alpha):
    V lowpass9[9]
    V highpass7[7]

    V ALPHA = alpha
    V BETA = -1 / (4 * pow(1 + 2 * ALPHA, 2))
    V GAMMA = (-1 - 4 * ALPHA - 4 * pow(ALPHA, 2)) / (1 + 4 * ALPHA)
    V DELTA = (4 - ((2 + 4 * ALPHA) / pow(1 + 2 * ALPHA, 4)) + ((1 - 8 * ALPHA) / pow(1 + 2 * ALPHA, 2))) / 16
    V KL = 2 * (1 + 2 * ALPHA) / (1 + 4 * ALPHA)
    V KH = 1 / KL
    KL *= sqrt(2)
    KH *= sqrt(2)

    lowpass9[0] = KL * ALPHA * BETA * GAMMA * DELTA
    lowpass9[1] = KL * BETA * GAMMA * DELTA
    lowpass9[2] = KL * (ALPHA * BETA + ALPHA * DELTA + GAMMA * DELTA + 4 * ALPHA * BETA * GAMMA * DELTA)
    lowpass9[3] = KL * (3 * BETA * GAMMA * DELTA + BETA + DELTA)
    lowpass9[4] = KL * (1 + 2 * ALPHA * BETA + 2* ALPHA * DELTA + 2 * GAMMA * DELTA + 6 * ALPHA * BETA * GAMMA * DELTA)
    lowpass9[5] = lowpass9[3]
    lowpass9[6] = lowpass9[2]
    lowpass9[7] = lowpass9[1]
    lowpass9[8] = lowpass9[0]

    highpass7[0] = -KH * -1 * ALPHA * BETA * GAMMA
    highpass7[1] = KH * BETA * GAMMA
    highpass7[2] = -KH * -(3 * ALPHA * BETA * GAMMA + ALPHA + GAMMA)
    highpass7[3] = KH * (2 * BETA * GAMMA + 1)
    highpass7[4] = highpass7[2]
    highpass7[5] = highpass7[1]
    highpass7[6] = highpass7[0]

    filter(indata, n, instep, lowpass9, 9, outlow, lowstep, 1 << scale)
    filter(indata, n, instep, highpass7, 7, outhigh, highstep, 1 << scale)

static V def getkeyval(char const *key):
    int i = (key[0] - '0') * 10 + (key[1] - '0')
    V v = i * 9.2 / 100.0
    if v < 4.6: return v - 6
    else: return v - 3.2
    return v

V **def cdf97(V const *s, int n, char const *key):
    """
    This expects a signal of n samples, and will return (full-length, not
    downsampled) low and high pass results for each subdivision level.

    0 2 4.../log2(n)\ * 2 - 2 are the low pass results
    1 3 5.../log2(n)\ * 2 - 1 the high pass results
    """
    int l = ceil(log2(n));
    V **r = ALLOCATE(l * 2 * sizeof(V *))

    if key:
        V param = getkeyval(key)
        # printf("CDF 9x7 alpha used: %f\n", param)
        V const *p = s
        for int i = 0; i < l; i++:
            r[i * 2] = ALLOCATE(n * sizeof(V))
            r[i * 2 + 1] = ALLOCATE(n * sizeof(V))
            cdf_9x7_filter_nosubsample_param(p, n, 1, r[i * 2], 1, r[i * 2 + 1],
                1, i, param)
            # right now, we always use the lowband for further analysis.
            p = r[i * 2]
    else:
        V const *p = s
        for int i = 0; i < l; i++:
            r[i * 2] = ALLOCATE(n * sizeof(V))
            r[i * 2 + 1] = ALLOCATE(n * sizeof(V))
            cdf_9x7_filter_nosubsample(p, n, 1, r[i * 2], 1, r[i * 2 + 1], 1, i)

            # right now, we always use the lowband for further analysis.
            p = r[i * 2]
    return r
