/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "crossover.h"
#include "biquad.h"
static void lr4_set(struct lr4 *lr4, enum biquad_type type, float freq)
{
struct biquad q;
biquad_set(&q, type, freq, 0, 0);
lr4->b0 = q.b0;
lr4->b1 = q.b1;
lr4->b2 = q.b2;
lr4->a1 = q.a1;
lr4->a2 = q.a2;
lr4->x1 = 0;
lr4->x2 = 0;
lr4->y1 = 0;
lr4->y2 = 0;
lr4->z1 = 0;
lr4->z2 = 0;
}
/* Split input data using two LR4 filters, put the result into the input array
* and another array.
*
* data0 --+-- lp --> data0
* |
* \-- hp --> data1
*/
static void lr4_split(struct lr4 *lp, struct lr4 *hp, int count, float *data0,
float *data1)
{
float lx1 = lp->x1;
float lx2 = lp->x2;
float ly1 = lp->y1;
float ly2 = lp->y2;
float lz1 = lp->z1;
float lz2 = lp->z2;
float lb0 = lp->b0;
float lb1 = lp->b1;
float lb2 = lp->b2;
float la1 = lp->a1;
float la2 = lp->a2;
float hx1 = hp->x1;
float hx2 = hp->x2;
float hy1 = hp->y1;
float hy2 = hp->y2;
float hz1 = hp->z1;
float hz2 = hp->z2;
float hb0 = hp->b0;
float hb1 = hp->b1;
float hb2 = hp->b2;
float ha1 = hp->a1;
float ha2 = hp->a2;
int i;
for (i = 0; i < count; i++) {
float x, y, z;
x = data0[i];
y = lb0*x + lb1*lx1 + lb2*lx2 - la1*ly1 - la2*ly2;
z = lb0*y + lb1*ly1 + lb2*ly2 - la1*lz1 - la2*lz2;
lx2 = lx1;
lx1 = x;
ly2 = ly1;
ly1 = y;
lz2 = lz1;
lz1 = z;
data0[i] = z;
y = hb0*x + hb1*hx1 + hb2*hx2 - ha1*hy1 - ha2*hy2;
z = hb0*y + hb1*hy1 + hb2*hy2 - ha1*hz1 - ha2*hz2;
hx2 = hx1;
hx1 = x;
hy2 = hy1;
hy1 = y;
hz2 = hz1;
hz1 = z;
data1[i] = z;
}
lp->x1 = lx1;
lp->x2 = lx2;
lp->y1 = ly1;
lp->y2 = ly2;
lp->z1 = lz1;
lp->z2 = lz2;
hp->x1 = hx1;
hp->x2 = hx2;
hp->y1 = hy1;
hp->y2 = hy2;
hp->z1 = hz1;
hp->z2 = hz2;
}
/* Split input data using two LR4 filters and sum them back to the original
* data array.
*
* data --+-- lp --+--> data
* | |
* \-- hp --/
*/
static void lr4_merge(struct lr4 *lp, struct lr4 *hp, int count, float *data)
{
float lx1 = lp->x1;
float lx2 = lp->x2;
float ly1 = lp->y1;
float ly2 = lp->y2;
float lz1 = lp->z1;
float lz2 = lp->z2;
float lb0 = lp->b0;
float lb1 = lp->b1;
float lb2 = lp->b2;
float la1 = lp->a1;
float la2 = lp->a2;
float hx1 = hp->x1;
float hx2 = hp->x2;
float hy1 = hp->y1;
float hy2 = hp->y2;
float hz1 = hp->z1;
float hz2 = hp->z2;
float hb0 = hp->b0;
float hb1 = hp->b1;
float hb2 = hp->b2;
float ha1 = hp->a1;
float ha2 = hp->a2;
int i;
for (i = 0; i < count; i++) {
float x, y, z;
x = data[i];
y = lb0*x + lb1*lx1 + lb2*lx2 - la1*ly1 - la2*ly2;
z = lb0*y + lb1*ly1 + lb2*ly2 - la1*lz1 - la2*lz2;
lx2 = lx1;
lx1 = x;
ly2 = ly1;
ly1 = y;
lz2 = lz1;
lz1 = z;
y = hb0*x + hb1*hx1 + hb2*hx2 - ha1*hy1 - ha2*hy2;
z = hb0*y + hb1*hy1 + hb2*hy2 - ha1*hz1 - ha2*hz2;
hx2 = hx1;
hx1 = x;
hy2 = hy1;
hy1 = y;
hz2 = hz1;
hz1 = z;
data[i] = z + lz1;
}
lp->x1 = lx1;
lp->x2 = lx2;
lp->y1 = ly1;
lp->y2 = ly2;
lp->z1 = lz1;
lp->z2 = lz2;
hp->x1 = hx1;
hp->x2 = hx2;
hp->y1 = hy1;
hp->y2 = hy2;
hp->z1 = hz1;
hp->z2 = hz2;
}
void crossover_init(struct crossover *xo, float freq1, float freq2)
{
int i;
for (i = 0; i < 3; i++) {
float f = (i == 0) ? freq1 : freq2;
lr4_set(&xo->lp[i], BQ_LOWPASS, f);
lr4_set(&xo->hp[i], BQ_HIGHPASS, f);
}
}
void crossover_process(struct crossover *xo, int count, float *data0,
float *data1, float *data2)
{
lr4_split(&xo->lp[0], &xo->hp[0], count, data0, data1);
lr4_merge(&xo->lp[1], &xo->hp[1], count, data0);
lr4_split(&xo->lp[2], &xo->hp[2], count, data1, data2);
}