axvpb.pb.biquad

Syntax

#define AX_PB_BIQUAD_OFF        0x0000  // Biquad IIR filter switch
#define AX_PB_BIQUAD_ON         0x0002

typedef struct _AXPBBIQUAD
{
    
    u16     on;   // Filter switch. Valid when AX_PB_BIQUAD_ON(2).  Invalid when AX_PB_BIQUAD_OFF(0).
    u16     xn1;  //  History data. Must be initialized to zero.
    u16     xn2;  // History data. Must be initialized to zero.
    u16     yn1;  // History data. Must be initialized to zero.
    u16     yn2;  // History data. Must be initialized to zero.
    u16     b0;   // Filter coefficient
    u16     b1;   // Filter coefficient
    u16     b2;   // Filter coefficient
    u16     a1;   // Filter coefficient
    u16     a2;   // Filter coefficient

} AXPBBIQUAD;

Description

With AX, a Biquad filter can be applied to each voice independently. Moreover, the Biquad filter can be used with a conventional LPF filter. The biquad value controls these Biquad filters.

The on value is the Biquad filter switch. Biquad filters are enabled when AX_PB_BIQUAD_ON(2) is set to on; the filters are invalid when AX_PB_BIQUAD_OFF(0) is set.

The xn1, xn2, yn1, and yn2 values are history data used by Biquad filters. These values must be initialized to zero when Biquad filters are enabled. Once Biquad filters become valid, the AX library manages these values. After the data have been initialized, the application must not make any changes to them.

In the diagram below, the b0, b1, b2, a1, and a2 values are coefficients of the Biquad filter. The application must set the coefficients in these members to correspond to the filter type and cutoff frequency. Note that these values can be changed at any time.


    y(n) = b0 * x(n) + b1 * x(n-1) + b2 * x(n-2) + a1 * y(n-1) + a2 * y(n-2)
    
    IN--->[+]-------------->+--->[ x b0 ]-->[+]--->OUT
           |                |                |
           |             [ Z^-1 ]            |
           |                |                |
           +<---[ x a1 ]<---+--->[ x b1 ]--->+
           |                |                |
           |             [ Z^-1 ]            |
           |                |                |
           +<---[ x a2 ]<---+--->[ x b2 ]--->+


                    b0 + b1(Z^-1) + b2(Z^-2)
           H(z) = ----------------------------
                    1  - a1(Z^-1) - a2(Z^-2)

Each filter coefficient is a 16-bit fixed-point value with a 2-bit integer part and a 14-bit decimal fraction (-2.0 <= coef < 2.0). Using a general-purpose filter design tool, convert the requested filter coefficients to fixed-point values, and set them for b0 - a2.

For the /build/demos/axdemo/include/lpfdemo.h sample, the following coefficient table has been prepared:


typedef struct
{
    u16  b0; 
    u16  b1; 
    u16  b2; 
    u16  a1; 
    u16  a2; 
    char *text;

} __BIQUAD_COEF;

// low-pass
static __BIQUAD_COEF __biquad_lpf_coefs[] =
{
    { 0x36fa, 0x6df4, 0x36fa, 0x8c47, 0xcaca, "16000 Hz"}, // actually 15000 Hz
    { 0x2bf0, 0x57e0, 0x2bf0, 0xa967, 0xdc70, "12800 Hz"},
    { 0x2071, 0x40e3, 0x2071, 0xcd87, 0xe904, "10240 Hz"},
    { 0x173d, 0x2e7b, 0x173d, 0xef3d, 0xee4c, " 8000 Hz"},
    { 0x110d, 0x221a, 0x110d, 0x0903, 0xeec0, " 6400 Hz"},
    { 0x0c59, 0x18b3, 0x0c59, 0x1eee, 0xecbf, " 5120 Hz"},
    { 0x087e, 0x10fc, 0x087e, 0x332c, 0xe8d8, " 4000 Hz"},
    { 0x05f5, 0x0bea, 0x05f5, 0x423b, 0xe487, " 3200 Hz"},
    { 0x041f, 0x083d, 0x041f, 0x4e96, 0xdff6, " 2560 Hz"},
    { 0x02b3, 0x0565, 0x02b3, 0x598e, 0xdb05, " 2000 Hz"},
    { 0x01d1, 0x03a3, 0x01d1, 0x616d, 0xd6df, " 1600 Hz"},
    { 0x0137, 0x026e, 0x0137, 0x67b7, 0xd325, " 1280 Hz"},
    { 0x00c5, 0x018a, 0x00c5, 0x6d2e, 0xcf90, " 1000 Hz"},
    { 0x0082, 0x0103, 0x0082, 0x710d, 0xccce, "  800 Hz"},
    { 0x0055, 0x00a9, 0x0055, 0x741f, 0xca7b, "  640 Hz"},
    { 0x0035, 0x0069, 0x0035, 0x76c7, 0xc85a, "  500 Hz"},
    { 0x0022, 0x0044, 0x0022, 0x78a9, 0xc6c7, "  400 Hz"},
    { 0x0016, 0x002c, 0x0016, 0x7a27, 0xc57c, "  320 Hz"},
    { 0x000e, 0x001d, 0x000e, 0x7b57, 0xc46d, "  256 Hz"},
    { 0x0009, 0x0012, 0x0009, 0x7c5f, 0xc37c, "  200 Hz"},
    { 0x0006, 0x000b, 0x0006, 0x7d1b, 0xc2ce, "  160 Hz"},
    { 0x0004, 0x0007, 0x0004, 0x7db0, 0xc241, "  128 Hz"},
    { 0x0002, 0x0004, 0x0002, 0x7e32, 0xc1c5, "  100 Hz"},
    { 0x0001, 0x0003, 0x0001, 0x7e8f, 0xc16b, "   80 Hz"}
};

// high-pass
static __BIQUAD_COEF __biquad_hpf_coefs[] =
{
    { 0x3bf9, 0x880e, 0x3bf9, 0x7f0d, 0xc0f1, "   80 Hz"},
    { 0x3bdd, 0x8846, 0x3bdd, 0x7ed0, 0xc12c, "  100 Hz"},
    { 0x3bb5, 0x8896, 0x3bb5, 0x7e7b, 0xc17f, "  128 Hz"},
    { 0x3b88, 0x88f1, 0x3b88, 0x7e19, 0xc1dd, "  160 Hz"},
    { 0x3b4f, 0x8962, 0x3b4f, 0x7d9e, 0xc252, "  200 Hz"},
    { 0x3b00, 0x8a00, 0x3b00, 0x7cf1, 0xc2f5, "  256 Hz"},
    { 0x3aa6, 0x8ab4, 0x3aa6, 0x7c2b, 0xc3ac, "  320 Hz"},
    { 0x3a36, 0x8b95, 0x3a36, 0x7b31, 0xc48f, "  400 Hz"},
    { 0x39aa, 0x8cac, 0x39aa, 0x79f8, 0xc5a5, "  500 Hz"},
    { 0x38e8, 0x8e31, 0x38e8, 0x783d, 0xc722, "  640 Hz"},
    { 0x380b, 0x8fea, 0x380b, 0x763e, 0xc8ca, "  800 Hz"},
    { 0x36fa, 0x920c, 0x36fa, 0x73b9, 0xcaca, " 1000 Hz"},
    { 0x3580, 0x9500, 0x3580, 0x7027, 0xcd77, " 1280 Hz"},
    { 0x33d7, 0x9852, 0x33d7, 0x6c03, 0xd05c, " 1600 Hz"},
    { 0x31ce, 0x9c64, 0x31ce, 0x66c2, 0xd3bc, " 2000 Hz"},
    { 0x2f06, 0xa1f5, 0x2f06, 0x5f4a, 0xd80d, " 2560 Hz"},
    { 0x2bf0, 0xa821, 0x2bf0, 0x569a, 0xdc70, " 3200 Hz"},
    { 0x2836, 0xaf95, 0x2836, 0x4b8b, 0xe12e, " 4000 Hz"},
    { 0x2334, 0xb998, 0x2334, 0x3bb7, 0xe68e, " 5120 Hz"},
    { 0x1dbf, 0xc483, 0x1dbf, 0x2913, 0xeb0d, " 6400 Hz"},
    { 0x173d, 0xd186, 0x173d, 0x10c3, 0xee4c, " 8000 Hz"},
    { 0x0eab, 0xe2ab, 0x0eab, 0xec30, 0xee0b, "10240 Hz"},
    { 0x05f5, 0xf416, 0x05f5, 0xbdc5, 0xe487, "12800 Hz"},
    { 0x00c5, 0xfe77, 0x00c5, 0x92d2, 0xcf90, "16000 Hz"}  // actually 15000 Hz
};

// band-pass
static __BIQUAD_COEF __biquad_bpf_coefs[] =
{
    { 0x3ff5, 0x0000, 0xc00c, 0x0000, 0x3fea, "   0 - 16000 Hz"},
    { 0x3c9d, 0x0000, 0xc364, 0x061c, 0x393a, "  80 - 14464 Hz"},
    { 0x398b, 0x0000, 0xc676, 0x0c2a, 0x3315, "  95 - 12928 Hz"},
    { 0x36c4, 0x0000, 0xc93d, 0x11b5, 0x2d88, " 101 - 11520 Hz"},
    { 0x3427, 0x0000, 0xcbd9, 0x16e1, 0x284e, " 113 - 10240 Hz"},
    { 0x31cc, 0x0000, 0xce35, 0x1b88, 0x2398, " 127 -  9152 Hz"},
    { 0x2f65, 0x0000, 0xd09b, 0x2044, 0x1eca, " 143 -  8128 Hz"},
    { 0x2d16, 0x0000, 0xd2eb, 0x24d3, 0x1a2b, " 160 -  7232 Hz"},
    { 0x2ae2, 0x0000, 0xd51f, 0x2927, 0x15c3, " 180 -  6464 Hz"},
    { 0x28a0, 0x0000, 0xd760, 0x2d96, 0x1141, " 202 -  5760 Hz"},
    { 0x2652, 0x0000, 0xd9af, 0x3220, 0x0ca3, " 226 -  5120 Hz"},
    { 0x2418, 0x0000, 0xdbe9, 0x367d, 0x082f, " 254 -  4576 Hz"},
    { 0x21b7, 0x0000, 0xde49, 0x3b26, 0x036f, " 286 -  4064 Hz"},
    { 0x1f59, 0x0000, 0xe0a7, 0x3fcd, 0xfeb3, " 320 -  3616 Hz"},
    { 0x1d03, 0x0000, 0xe2fd, 0x445e, 0xfa07, " 360 -  3232 Hz"},
    { 0x1a92, 0x0000, 0xe56e, 0x4927, 0xf525, " 404 -  2880 Hz"},
    { 0x1807, 0x0000, 0xe7fa, 0x4e25, 0xf00e, " 452 -  2560 Hz"},
    { 0x157d, 0x0000, 0xea84, 0x531c, 0xeafa, " 508 -  2288 Hz"},
    { 0x12b6, 0x0000, 0xed4a, 0x588a, 0xe56d, " 572 -  2032 Hz"},
    { 0x0fdf, 0x0000, 0xf022, 0x5e1d, 0xdfbe, " 640 -  1808 Hz"},
    { 0x0ce7, 0x0000, 0xf31a, 0x63e8, 0xd9ce, " 720 -  1616 Hz"},
    { 0x09aa, 0x0000, 0xf657, 0x6a3e, 0xd354, " 808 -  1440 Hz"},
    { 0x061f, 0x0000, 0xf9e2, 0x7130, 0xcc3e, " 904 -  1280 Hz"},
    { 0x0239, 0x0000, 0xfdc8, 0x78cc, 0xc472, "1016 -  1144 Hz"}
};

To reflect changes to the filter coefficients b0 - a2 in DSP, the application must assert the AX_SYNC_USER_BIAQUAD_COEF bit in the axvpb.sync member. If the Biquad filter switch on value is changed and the overall AXPBBIQUAD structure needs to be reflected in the DSP, the application must assert the AX_SYNC_USER_BIQUAD bit.

If an extremely small value is set for a filter coefficient (__biquad_lpf_coefs[] of 80Hz in the above sample), some sounds may exhibit noticeable pop.

The load placed on DSP by Biquad filters is three times greater than by conventional LPF filters. The load is about the same as for a mixer with one AUX bus.

See Also

axvpb.sync, AXSetVoiceBiquad, AXSetVoiceBiquadCoefs

Revision History

2006/11/14 Initial version.


CONFIDENTIAL