/*---------------------------------------------------------------------------*/
/*
  File: resample.cpp

  HD audio resampling.
*/
/*---------------------------------------------------------------------------*/

#include "platform.h"
#include "resample.h"
#include "sdsputil.h"

#define FILE_ "resample.cpp"

/*---------------------------------------------------------------------------*/
#ifdef RESAMPLE_LIGHTWEIGHT

static const word resample_down2_filter_coefs[2 * RESAMPLE_FILTER_TAPS_HALF + 1] =
{
  0xFFDF, 0x0029, 0x0048, 0xFFCD, 0xFF4D, 0x001E, 0x017A, 0x0065,
  0xFD6B, 0xFE3F, 0x03DB, 0x04AD, 0xFAF1, 0xF4C6, 0x05EB, 0x27E7,
  0x39C1
};


static const word resample_down32_filter_coefs0[(3 * RESAMPLE_FILTER_TAPS) / 2] =
{
/*0xFFD4,*/0x0054, 0x0008, 0xFF12, 0x00DE, 0x0181, 0xFC91, 0xFFDB,
  0x077B, 0xF945, 0xF4A3, 0x25F4, 0x4CC7, 0x25F4, 0xF4A3, 0xF945,
  0x077B, 0xFFDB, 0xFC91, 0x0181, 0x00DE, 0xFF12, 0x0008, 0x0054,
/*0xFFD4*/0x0000
};

static const word resample_down32_filter_coefs1[(3 * RESAMPLE_FILTER_TAPS_HALF) / 2] =
{
  0x0013, 0x005F, 0xFF6C, 0xFF90, 0x01F7, 0xFF2D, 0xFC58, 0x0521,
  0x031C, 0xF14E, 0x07E0, 0x4196
};


static const word resample_down3_filter_coefs[3 * RESAMPLE_FILTER_TAPS_HALF + 1] =
{
  0xFFEA, 0x0009, 0x002A, 0x0030, 0x0004, 0xFFB6, 0xFF88, 0xFFC8,
  0x006F, 0x00FC, 0x00C1, 0xFF96, 0xFE48, 0xFE2B, 0xFFEE, 0x0292,
  0x03C0, 0x018F, 0xFCA1, 0xF8A2, 0xFA4E, 0x03F2, 0x1306, 0x20DF,
  0x267B
};


static const word resample_down43_filter_coefs0[(4 * RESAMPLE_FILTER_TAPS3) / 3] =
{
/*0x001A,*/0xFFA7, 0x0062, 0x0046, 0xFE7B, 0x01CB, 0x00B3, 0xFAFB,
  0x063D, 0x0121, 0xEEDA, 0x221C, 0x56BB, 0x221C, 0xEEDA, 0x0121,
  0x063D, 0xFAFB, 0x00B3, 0x01CB, 0xFE7B, 0x0046, 0x0062, 0xFFA7,
/*0x001A*/0x0000
};

static const word resample_down43_filter_coefs1[(4 * RESAMPLE_FILTER_TAPS3) / 3] =
{
  0xFFBC, 0x0002, 0x00AF, 0xFEC8, 0x003E, 0x0285, 0xFB8C, 0x0171,
  0x075D, 0xF079, 0x08F8, 0x4F82, 0x3C0A, 0xF6D5, 0xF827, 0x08EC,
  0xFD17, 0xFDF1, 0x02CE, 0xFEF9, 0xFF88, 0x00AE, 0xFFBD, 0xFFE9
};

static const word resample_down43_filter_coefs2[(4 * RESAMPLE_FILTER_TAPS3) / 3] =
{
  0xFFE9, 0xFFBD, 0x00AE, 0xFF88, 0xFEF9, 0x02CE, 0xFDF1, 0xFD17,
  0x08EC, 0xF827, 0xF6D5, 0x3C0A, 0x4F82, 0x08F8, 0xF079, 0x075D,
  0x0171, 0xFB8C, 0x0285, 0x003E, 0xFEC8, 0x00AF, 0x0002, 0xFFBC
};


static const word resample_down83_filter_coefs0[(8 * RESAMPLE_FILTER_TAPS3) / 3] =
{
/*0x000D,*/0xFFE8, 0xFFD4, 0xFFED, 0x0031, 0x005D, 0x0023, 0xFF91,
  0xFF3D, 0xFFC4, 0x00E5, 0x016E, 0x005A, 0xFE4D, 0xFD7D, 0xFF88,
  0x031E, 0x0461, 0x0091, 0xF9ED, 0xF76C, 0xFF5E, 0x110E, 0x2383,
  0x2B61, 0x2383, 0x110E, 0xFF5E, 0xF76C, 0xF9ED, 0x0091, 0x0461,
  0x031E, 0xFF88, 0xFD7D, 0xFE4D, 0x005A, 0x016E, 0x00E5, 0xFFC4,
  0xFF3D, 0xFF91, 0x0023, 0x005D, 0x0031, 0xFFED, 0xFFD4, 0xFFE8,
/*0x000D*/0x0000
};

static const word resample_down83_filter_coefs1[(8 * RESAMPLE_FILTER_TAPS3) / 3] =
{
  0xFFF5, 0xFFD7, 0xFFDF, 0x0018, 0x0057, 0x0044, 0xFFC4, 0xFF46,
  0xFF7C, 0x0083, 0x0167, 0x00E5, 0xFEF9, 0xFD7B, 0xFE8B, 0x01F7,
  0x0476, 0x0263, 0xFC14, 0xF750, 0xFB69, 0x0A7F, 0x1E07, 0x2A75,
  0x27C4, 0x17B8, 0x047B, 0xF8C2, 0xF83D, 0xFE63, 0x03B0, 0x0400,
  0x00B8, 0xFDD8, 0xFDC6, 0xFFB0, 0x0143, 0x0136, 0x001F, 0xFF4F,
  0xFF64, 0xFFF7, 0x0058, 0x0047, 0x0001, 0xFFD6, 0xFFDE, 0x0001
};

static const word resample_down83_filter_coefs2[(8 * RESAMPLE_FILTER_TAPS3) / 3] =
{
  0x0001, 0xFFDE, 0xFFD6, 0x0001, 0x0047, 0x0058, 0xFFF7, 0xFF64,
  0xFF4F, 0x001F, 0x0136, 0x0143, 0xFFB0, 0xFDC6, 0xFDD8, 0x00B8,
  0x0400, 0x03B0, 0xFE63, 0xF83D, 0xF8C2, 0x047B, 0x17B8, 0x27C4,
  0x2A75, 0x1E07, 0x0A7F, 0xFB69, 0xF750, 0xFC14, 0x0263, 0x0476,
  0x01F7, 0xFE8B, 0xFD7B, 0xFEF9, 0x00E5, 0x0167, 0x0083, 0xFF7C,
  0xFF46, 0xFFC4, 0x0044, 0x0057, 0x0018, 0xFFDF, 0xFFD7, 0xFFF5
};


static const word resample_down4_filter_coefs[4 * RESAMPLE_FILTER_TAPS_HALF + 1] =
{
  0xFFEF, 0x0000, 0x0014, 0x0023, 0x0024, 0x000F, 0xFFE6, 0xFFBB,
  0xFFA6, 0xFFC1, 0x000F, 0x0075, 0x00BD, 0x00AF, 0x0032, 0xFF6B,
  0xFEB6, 0xFE84, 0xFF20, 0x0070, 0x01EE, 0x02CB, 0x0256, 0x005D,
  0xFD79, 0xFAF5, 0xFA64, 0xFCFC, 0x02F5, 0x0B4C, 0x13F0, 0x1A70,
  0x1CDB
};


static const word resample_down6_filter_coefs[6 * RESAMPLE_FILTER_TAPS_HALF + 1] =
{
  0xFFF5, 0xFFFC, 0x0005, 0x000E, 0x0015, 0x0019, 0x0018, 0x0010,
  0x0002, 0xFFEF, 0xFFDB, 0xFFCB, 0xFFC4, 0xFFCC, 0xFFE4, 0x000B,
  0x0038, 0x0063, 0x007E, 0x007F, 0x0060, 0x0020, 0xFFCA, 0xFF6E,
  0xFF23, 0xFF00, 0xFF16, 0xFF6C, 0xFFF8, 0x00A4, 0x014A, 0x01C0,
  0x01DF, 0x018D, 0x00C6, 0xFFA0, 0xFE4F, 0xFD1A, 0xFC52, 0xFC44,
  0xFD29, 0xFF17, 0x01FB, 0x0595, 0x0982, 0x0D49, 0x106C, 0x1280,
  0x1339
};


static const word resample_up24_filter_coefs0[RESAMPLE_FILTER_TAPS] =
{
/*0xFFBE,*/0x008F, 0xFE9A, 0x02F4, 0xFAD7, 0x07B7, 0xF5E1, 0x0BD8,
  0x7347, 0x0BD8, 0xF5E1, 0x07B7, 0xFAD7, 0x02F4, 0xFE9A, 0x008F,
/*0xFFBE*/0x0000
};

static const word resample_up24_filter_coefs3[RESAMPLE_FILTER_TAPS] =
{
  0x0098, 0xFEB0, 0x0283, 0xFC1A, 0x04D8, 0xFBD8, 0xFE5A, 0x70D2,
  0x1BC3, 0xF046, 0x09F5, 0xFA1B, 0x030C, 0xFEB5, 0x0070, 0xFFDD
};

static const word resample_up24_filter_coefs4[RESAMPLE_FILTER_TAPS] =
{
  0x0096, 0xFEC0, 0x024E, 0xFC99, 0x03D2, 0xFDC8, 0xFA85, 0x6EED,
  0x2173, 0xEE9F, 0x0A7E, 0xFA03, 0x02FC, 0xFEC9, 0x0060, 0xFFE9
};

static const word resample_up24_filter_coefs6[RESAMPLE_FILTER_TAPS] =
{
  0x008D, 0xFEEB, 0x01D5, 0xFDA9, 0x01C4, 0x016F, 0xF3F6, 0x69A2,
  0x2D27, 0xEBD6, 0x0B2A, 0xFA14, 0x02B8, 0xFF06, 0x003A, 0x0002
};

static const word resample_up24_filter_coefs8[RESAMPLE_FILTER_TAPS] =
{
  0x007E, 0xFF20, 0x014F, 0xFEC0, 0xFFCD, 0x04A7, 0xEEF3, 0x627B,
  0x3901, 0xE9EE, 0x0B3B, 0xFA84, 0x0241, 0xFF5A, 0x000B, 0x001D
};

static const word resample_up24_filter_coefs9[RESAMPLE_FILTER_TAPS] =
{
  0x0074, 0xFF3E, 0x010A, 0xFF49, 0xFEE1, 0x060F, 0xED09, 0x5E49,
  0x3EDF, 0xE960, 0x0B04, 0xFAE1, 0x01F3, 0xFF8C, 0xFFF1, 0x002A
};

static const word resample_up24_filter_coefs12[RESAMPLE_FILTER_TAPS_HALF] =
{
  0x0052, 0xFF99, 0x003E, 0x00C5, 0xFC83, 0x0951, 0xE999, 0x4FA9
};

static const word resample_up24_filter_coefs15[RESAMPLE_FILTER_TAPS] =
{
  0x002A, 0xFFF1, 0xFF8C, 0x01F3, 0xFAE1, 0x0B04, 0xE960, 0x3EDF,
  0x5E49, 0xED09, 0x060F, 0xFEE1, 0xFF49, 0x010A, 0xFF3E, 0x0074
};

static const word resample_up24_filter_coefs16[RESAMPLE_FILTER_TAPS] =
{
  0x001D, 0x000B, 0xFF5A, 0x0241, 0xFA84, 0x0B3B, 0xE9EE, 0x3901,
  0x627B, 0xEEF3, 0x04A7, 0xFFCD, 0xFEC0, 0x014F, 0xFF20, 0x007E
};

static const word resample_up24_filter_coefs18[RESAMPLE_FILTER_TAPS] =
{
  0x0002, 0x003A, 0xFF06, 0x02B8, 0xFA14, 0x0B2A, 0xEBD6, 0x2D27,
  0x69A2, 0xF3F6, 0x016F, 0x01C4, 0xFDA9, 0x01D5, 0xFEEB, 0x008D
};

static const word resample_up24_filter_coefs20[RESAMPLE_FILTER_TAPS] =
{
  0xFFE9, 0x0060, 0xFEC9, 0x02FC, 0xFA03, 0x0A7E, 0xEE9F, 0x2173,
  0x6EED, 0xFA85, 0xFDC8, 0x03D2, 0xFC99, 0x024E, 0xFEC0, 0x0096
};

static const word resample_up24_filter_coefs21[RESAMPLE_FILTER_TAPS] =
{
  0xFFDD, 0x0070, 0xFEB5, 0x030C, 0xFA1B, 0x09F5, 0xF046, 0x1BC3,
  0x70D2, 0xFE5A, 0xFBD8, 0x04D8, 0xFC1A, 0x0283, 0xFEB0, 0x0098
};

#else

static const word resample_down2_filter_coefs[2 * RESAMPLE_FILTER_TAPS_HALF + 1] =
{
  0x000C, 0xFFF6, 0xFFF0, 0x0008, 0x0015, 0xFFFC, 0xFFE5, 0xFFFF,
  0x0023, 0x000B, 0xFFD5, 0xFFE7, 0x0031, 0x002E, 0xFFCC, 0xFFB8,
  0x0030, 0x0066, 0xFFDE, 0xFF78, 0x0007, 0x00AB, 0x0022, 0xFF37,
  0xFFA4, 0x00DD, 0x00A7, 0xFF1D, 0xFEFD, 0x00D1, 0x016D, 0xFF5E,
  0xFE1D, 0x004C, 0x0260, 0x003D, 0xFD22, 0xFEFA, 0x0357, 0x022A,
  0xFC3B, 0xFC22, 0x0422, 0x06B1, 0xFB97, 0xF352, 0x0495, 0x2871,
  0x3B5C
};


static const word resample_down32_filter_coefs0[(3 * RESAMPLE_FILTER_TAPS) / 2] =
{
/*0x0010,*/0xFFEB, 0xFFFE, 0x001B, 0xFFEB, 0xFFEC, 0x002F, 0xFFF3,
  0xFFC8, 0x0042, 0x0016, 0xFF91, 0x0040, 0x0061, 0xFF58, 0x000B,
  0x00D6, 0xFF3F, 0xFF88, 0x015F, 0xFF7A, 0xFEAA, 0x01C6, 0x0043,
  0xFD7E, 0x01BC, 0x01D5, 0xFC2F, 0x00C5, 0x048D, 0xFAF9, 0xFDCF,
  0x09D7, 0xFA1E, 0xF25A, 0x25D1, 0x4EF5, 0x25D1, 0xF25A, 0xFA1E,
  0x09D7, 0xFDCF, 0xFAF9, 0x048D, 0x00C5, 0xFC2F, 0x01D5, 0x01BC,
  0xFD7E, 0x0043, 0x01C6, 0xFEAA, 0xFF7A, 0x015F, 0xFF88, 0xFF3F,
  0x00D6, 0x000B, 0xFF58, 0x0061, 0x0040, 0xFF91, 0x0016, 0x0042,
  0xFFC8, 0xFFF3, 0x002F, 0xFFEC, 0xFFEB, 0x001B, 0xFFFE, 0xFFEB,
/*0x0010*/0x0000
};

static const word resample_down32_filter_coefs1[(3 * RESAMPLE_FILTER_TAPS_HALF) / 2] =
{
  0xFFFC, 0xFFEB, 0x0015, 0x0009, 0xFFDC, 0x0013, 0x0023, 0xFFC7,
  0x0000, 0x0051, 0xFFBA, 0xFFCA, 0x008D, 0xFFD2, 0xFF69, 0x00BC,
  0x002B, 0xFEE5, 0x00B1, 0x00DC, 0xFE65, 0x0037, 0x01E5, 0xFE2A,
  0xFF12, 0x0329, 0xFE97, 0xFCFE, 0x0473, 0x0055, 0xF958, 0x0583,
  0x0597, 0xF015, 0x061D, 0x4317
};


static const word resample_down3_filter_coefs[3 * RESAMPLE_FILTER_TAPS_HALF + 1] =
{
  0x0008, 0xFFFE, 0xFFF6, 0xFFF6, 0xFFFF, 0x000B, 0x000E, 0x0004,
  0xFFF5, 0xFFEE, 0xFFF6, 0x000A, 0x0017, 0x0012, 0xFFFA, 0xFFE3,
  0xFFE4, 0x0000, 0x0021, 0x0029, 0x000B, 0xFFDD, 0xFFC8, 0xFFE5,
  0x0020, 0x0047, 0x0031, 0xFFE9, 0xFFAC, 0xFFB4, 0x0006, 0x005E,
  0x006B, 0x0016, 0xFF9F, 0xFF72, 0xFFC4, 0x0059, 0x00B0, 0x006E,
  0xFFBD, 0xFF32, 0xFF54, 0x001B, 0x00E4, 0x00F3, 0x0022, 0xFF14,
  0xFEBE, 0xFF89, 0x00DF, 0x0195, 0x00EB, 0xFF4B, 0xFE16, 0xFE7E,
  0x0063, 0x023B, 0x0248, 0x002B, 0xFD7B, 0xFCAA, 0xFEE7, 0x02C3,
  0x04EE, 0x02CD, 0xFD0D, 0xF806, 0xF929, 0x0310, 0x12F4, 0x21A0,
  0x2793
};


static const word resample_down43_filter_coefs0[(4 * RESAMPLE_FILTER_TAPS3) / 3] =
{
/*0x0012,*/0xFFE6, 0x000C, 0x0012, 0xFFD7, 0x001F, 0x0010, 0xFFBA,
  0x004A, 0x0000, 0xFF95, 0x0094, 0xFFCE, 0xFF76, 0x0100, 0xFF65,
  0xFF76, 0x0189, 0xFEAD, 0xFFB7, 0x0224, 0xFD87, 0x0071, 0x02BD,
  0xFBB3, 0x0213, 0x033F, 0xF853, 0x0633, 0x0396, 0xECFB, 0x2136,
  0x590A, 0x2136, 0xECFB, 0x0396, 0x0633, 0xF853, 0x033F, 0x0213,
  0xFBB3, 0x02BD, 0x0071, 0xFD87, 0x0224, 0xFFB7, 0xFEAD, 0x0189,
  0xFF76, 0xFF65, 0x0100, 0xFF76, 0xFFCE, 0x0094, 0xFF95, 0x0000,
  0x004A, 0xFFBA, 0x0010, 0x001F, 0xFFD7, 0x0012, 0x000C, 0xFFE6,
/*0x0012*/0x0000
};

static const word resample_down43_filter_coefs1[(4 * RESAMPLE_FILTER_TAPS3) / 3] =
{
  0xFFF1, 0xFFF7, 0x001F, 0xFFE2, 0xFFFE, 0x0030, 0xFFC0, 0x0013,
  0x0044, 0xFF85, 0x0047, 0x004D, 0xFF33, 0x00AA, 0x0033, 0xFED4,
  0x014C, 0xFFD7, 0xFE7C, 0x023B, 0xFF0E, 0xFE4A, 0x0390, 0xFD86,
  0xFE77, 0x059C, 0xFA58, 0xFF98, 0x0A0A, 0xF007, 0x06DF, 0x515A,
  0x3CA8, 0xF457, 0xF963, 0x0AA4, 0xFA32, 0xFECA, 0x0503, 0xFBFC,
  0x005B, 0x0294, 0xFD2B, 0x00E6, 0x013A, 0xFE19, 0x00FB, 0x0072,
  0xFED3, 0x00D5, 0x000B, 0xFF5B, 0x009A, 0xFFE1, 0xFFB3, 0x0060,
  0xFFDA, 0xFFE3, 0x0035, 0xFFE1, 0xFFF9, 0x001C, 0xFFE9, 0x0002
};

static const word resample_down43_filter_coefs2[(4 * RESAMPLE_FILTER_TAPS3) / 3] =
{
  0x0002, 0xFFE9, 0x001C, 0xFFF9, 0xFFE1, 0x0035, 0xFFE3, 0xFFDA,
  0x0060, 0xFFB3, 0xFFE1, 0x009A, 0xFF5B, 0x000B, 0x00D5, 0xFED3,
  0x0072, 0x00FB, 0xFE19, 0x013A, 0x00E6, 0xFD2B, 0x0294, 0x005B,
  0xFBFC, 0x0503, 0xFECA, 0xFA32, 0x0AA4, 0xF963, 0xF457, 0x3CA8,
  0x515A, 0x06DF, 0xF007, 0x0A0A, 0xFF98, 0xFA58, 0x059C, 0xFE77,
  0xFD86, 0x0390, 0xFE4A, 0xFF0E, 0x023B, 0xFE7C, 0xFFD7, 0x014C,
  0xFED4, 0x0033, 0x00AA, 0xFF33, 0x004D, 0x0047, 0xFF85, 0x0044,
  0x0013, 0xFFC0, 0x0030, 0xFFFE, 0xFFE2, 0x001F, 0xFFF7, 0xFFF1
};


static const word resample_down83_filter_coefs0[(8 * RESAMPLE_FILTER_TAPS3) / 3] =
{
/*0x000A,*/0xFFFE, 0xFFF3, 0xFFF7, 0x0005, 0x0010, 0x000A, 0xFFF7,
  0xFFEB, 0xFFF6, 0x000E, 0x001B, 0x000A, 0xFFE9, 0xFFDC, 0xFFF8,
  0x0023, 0x002D, 0x0003, 0xFFCC, 0xFFC8, 0x0006, 0x0048, 0x0041,
  0xFFEB, 0xFF9E, 0xFFB7, 0x002A, 0x007F, 0x004D, 0xFFB8, 0xFF5F,
  0xFFB5, 0x0070, 0x00C6, 0x0041, 0xFF5C, 0xFF13, 0xFFD3, 0x00E6,
  0x0116, 0x0009, 0xFEC8, 0xFEC1, 0x002E, 0x019F, 0x0166, 0xFF7E,
  0xFDDC, 0xFE76, 0x00FF, 0x02D5, 0x01AA, 0xFE3E, 0xFC28, 0xFE3C,
  0x0310, 0x058D, 0x01D7, 0xFA29, 0xF679, 0xFE1D, 0x1094, 0x242E,
  0x2C93, 0x242E, 0x1094, 0xFE1D, 0xF679, 0xFA29, 0x01D7, 0x058D,
  0x0310, 0xFE3C, 0xFC28, 0xFE3E, 0x01AA, 0x02D5, 0x00FF, 0xFE76,
  0xFDDC, 0xFF7E, 0x0166, 0x019F, 0x002E, 0xFEC1, 0xFEC8, 0x0009,
  0x0116, 0x00E6, 0xFFD3, 0xFF13, 0xFF5C, 0x0041, 0x00C6, 0x0070,
  0xFFB5, 0xFF5F, 0xFFB8, 0x004D, 0x007F, 0x002A, 0xFFB7, 0xFF9E,
  0xFFEB, 0x0041, 0x0048, 0x0006, 0xFFC8, 0xFFCC, 0x0003, 0x002D,
  0x0023, 0xFFF8, 0xFFDC, 0xFFE9, 0x000A, 0x001B, 0x000E, 0xFFF6,
  0xFFEB, 0xFFF7, 0x000A, 0x0010, 0x0005, 0xFFF7, 0xFFF3, 0xFFFE,
/*0x000A*/0x0000
};

static const word resample_down83_filter_coefs1[(8 * RESAMPLE_FILTER_TAPS3) / 3] =
{
  0x0002, 0xFFF6, 0xFFF4, 0x0000, 0x000D, 0x000E, 0xFFFE, 0xFFED,
  0xFFF0, 0x0006, 0x001A, 0x0013, 0xFFF4, 0xFFDC, 0xFFEB, 0x0016,
  0x0030, 0x0016, 0xFFDC, 0xFFC2, 0xFFED, 0x0037, 0x004E, 0x000D,
  0xFFB0, 0xFFA1, 0x0000, 0x006F, 0x006E, 0xFFEC, 0xFF6C, 0xFF85,
  0x0033, 0x00C0, 0x0083, 0xFFA3, 0xFF0D, 0xFF7B, 0x0095, 0x012C,
  0x007C, 0xFF1F, 0xFE93, 0xFF9C, 0x0143, 0x01B5, 0x0038, 0xFE39,
  0xFDF8, 0x0012, 0x027C, 0x026B, 0xFF71, 0xFC77, 0xFD10, 0x016E,
  0x0550, 0x03C8, 0xFCBD, 0xF6B3, 0xFA20, 0x09AC, 0x1E56, 0x2B97,
  0x28B7, 0x17A3, 0x0363, 0xF793, 0xF808, 0xFF68, 0x050C, 0x046D,
  0xFFC0, 0xFC5A, 0xFD34, 0x00A1, 0x02D2, 0x01D7, 0xFF31, 0xFDC4,
  0xFECC, 0x00E2, 0x01C8, 0x00C2, 0xFF1D, 0xFE96, 0xFF90, 0x00D9,
  0x011B, 0x0036, 0xFF38, 0xFF27, 0xFFF4, 0x00B1, 0x00A2, 0xFFF1,
  0xFF67, 0xFF8B, 0x0020, 0x007F, 0x0051, 0xFFD8, 0xFF99, 0xFFCB,
  0x002A, 0x0051, 0x0020, 0xFFD7, 0xFFC3, 0xFFEF, 0x0024, 0x002C,
  0x0007, 0xFFE1, 0xFFE1, 0xFFFF, 0x0019, 0x0015, 0xFFFD, 0xFFEC,
  0xFFF2, 0x0004, 0x0010, 0x000A, 0xFFFB, 0xFFF3, 0xFFF9, 0x0006
};

static const word resample_down83_filter_coefs2[(8 * RESAMPLE_FILTER_TAPS3) / 3] =
{
  0x0006, 0xFFF9, 0xFFF3, 0xFFFB, 0x000A, 0x0010, 0x0004, 0xFFF2,
  0xFFEC, 0xFFFD, 0x0015, 0x0019, 0xFFFF, 0xFFE1, 0xFFE1, 0x0007,
  0x002C, 0x0024, 0xFFEF, 0xFFC3, 0xFFD7, 0x0020, 0x0051, 0x002A,
  0xFFCB, 0xFF99, 0xFFD8, 0x0051, 0x007F, 0x0020, 0xFF8B, 0xFF67,
  0xFFF1, 0x00A2, 0x00B1, 0xFFF4, 0xFF27, 0xFF38, 0x0036, 0x011B,
  0x00D9, 0xFF90, 0xFE96, 0xFF1D, 0x00C2, 0x01C8, 0x00E2, 0xFECC,
  0xFDC4, 0xFF31, 0x01D7, 0x02D2, 0x00A1, 0xFD34, 0xFC5A, 0xFFC0,
  0x046D, 0x050C, 0xFF68, 0xF808, 0xF793, 0x0363, 0x17A3, 0x28B7,
  0x2B97, 0x1E56, 0x09AC, 0xFA20, 0xF6B3, 0xFCBD, 0x03C8, 0x0550,
  0x016E, 0xFD10, 0xFC77, 0xFF71, 0x026B, 0x027C, 0x0012, 0xFDF8,
  0xFE39, 0x0038, 0x01B5, 0x0143, 0xFF9C, 0xFE93, 0xFF1F, 0x007C,
  0x012C, 0x0095, 0xFF7B, 0xFF0D, 0xFFA3, 0x0083, 0x00C0, 0x0033,
  0xFF85, 0xFF6C, 0xFFEC, 0x006E, 0x006F, 0x0000, 0xFFA1, 0xFFB0,
  0x000D, 0x004E, 0x0037, 0xFFED, 0xFFC2, 0xFFDC, 0x0016, 0x0030,
  0x0016, 0xFFEB, 0xFFDC, 0xFFF4, 0x0013, 0x001A, 0x0006, 0xFFF0,
  0xFFED, 0xFFFE, 0x000E, 0x000D, 0x0000, 0xFFF4, 0xFFF6, 0x0002
};


static const word resample_down4_filter_coefs[4 * RESAMPLE_FILTER_TAPS_HALF + 1] =
{
  0x0006, 0x0001, 0xFFFB, 0xFFF7, 0xFFF8, 0xFFFD, 0x0004, 0x0009,
  0x000A, 0x0006, 0xFFFE, 0xFFF6, 0xFFF2, 0xFFF6, 0xFFFF, 0x000A,
  0x0012, 0x0010, 0x0005, 0xFFF6, 0xFFEB, 0xFFE9, 0xFFF3, 0x0006,
  0x0019, 0x0020, 0x0017, 0x0000, 0xFFE6, 0xFFD7, 0xFFDC, 0xFFF6,
  0x0018, 0x0031, 0x0033, 0x001A, 0xFFEF, 0xFFC9, 0xFFBC, 0xFFD2,
  0x0004, 0x0039, 0x0055, 0x0047, 0x0011, 0xFFCC, 0xFF9C, 0xFF9C,
  0xFFD2, 0x0026, 0x006F, 0x0083, 0x0054, 0xFFF2, 0xFF8F, 0xFF5E,
  0xFF7E, 0xFFE8, 0x0069, 0x00BE, 0x00B7, 0x004D, 0xFFAF, 0xFF2D,
  0xFF0E, 0xFF6E, 0x0026, 0x00DC, 0x0130, 0x00EA, 0x001E, 0xFF2C,
  0xFE91, 0xFEA9, 0xFF7D, 0x00B1, 0x01AC, 0x01DF, 0x0115, 0xFF99,
  0xFE1D, 0xFD71, 0xFE11, 0xFFDD, 0x0211, 0x038C, 0x0359, 0x0132,
  0xFDCC, 0xFAAD, 0xF9A8, 0xFC1D, 0x024A, 0x0B13, 0x143A, 0x1B20,
  0x1DB0
};


static const word resample_down6_filter_coefs[6 * RESAMPLE_FILTER_TAPS_HALF + 1] =
{
  0x0004, 0x0002, 0xFFFF, 0xFFFD, 0xFFFB, 0xFFFA, 0xFFFB, 0xFFFD,
  0xFFFF, 0x0002, 0x0005, 0x0007, 0x0007, 0x0005, 0x0003, 0xFFFF,
  0xFFFB, 0xFFF8, 0xFFF7, 0xFFF8, 0xFFFB, 0xFFFF, 0x0004, 0x0009,
  0x000C, 0x000C, 0x0009, 0x0004, 0xFFFD, 0xFFF7, 0xFFF2, 0xFFF0,
  0xFFF2, 0xFFF7, 0xFFFF, 0x0008, 0x0010, 0x0015, 0x0015, 0x0010,
  0x0006, 0xFFFB, 0xFFEF, 0xFFE7, 0xFFE4, 0xFFE8, 0xFFF2, 0x0000,
  0x000F, 0x001C, 0x0023, 0x0022, 0x0019, 0x0009, 0xFFF6, 0xFFE3,
  0xFFD6, 0xFFD2, 0xFFD9, 0xFFEA, 0x0001, 0x001A, 0x002E, 0x0039,
  0x0036, 0x0027, 0x000D, 0xFFEE, 0xFFD1, 0xFFBE, 0xFFB9, 0xFFC5,
  0xFFE0, 0x0005, 0x002B, 0x0049, 0x0058, 0x0053, 0x0039, 0x0010,
  0xFFE1, 0xFFB6, 0xFF9A, 0xFF94, 0xFFA8, 0xFFD3, 0x000B, 0x0044,
  0x0071, 0x0085, 0x007B, 0x0052, 0x0014, 0xFFCC, 0xFF8C, 0xFF64,
  0xFF5E, 0xFF7F, 0xFFC1, 0x0017, 0x006D, 0x00AE, 0x00CB, 0x00B8,
  0x0078, 0x0017, 0xFFA9, 0xFF48, 0xFF0C, 0xFF06, 0xFF3D, 0xFFA6,
  0x002E, 0x00B5, 0x011C, 0x0147, 0x0126, 0x00BB, 0x0019, 0xFF62,
  0xFEC0, 0xFE5C, 0xFE54, 0xFEB4, 0xFF70, 0x0065, 0x015F, 0x0222,
  0x0278, 0x023D, 0x016A, 0x001B, 0xFE8A, 0xFD0D, 0xFC03, 0xFBC5,
  0xFC91, 0xFE83, 0x0184, 0x0550, 0x0979, 0x0D7C, 0x10D3, 0x1308,
  0x13CE
};


static const word resample_up24_filter_coefs0[RESAMPLE_FILTER_TAPS] =
{
/*0x0016,*/0xFFE2, 0x0028, 0xFFCA, 0x0047, 0xFFA8, 0x0066, 0xFF93,
  0x0067, 0xFFB2, 0x001C, 0x0035, 0xFF58, 0x013F, 0xFE08, 0x02D0,
  0xFC40, 0x04BF, 0xFA3F, 0x06BA, 0xF863, 0x085C, 0xF712, 0x0949,
  0x7698, 0x0949, 0xF712, 0x085C, 0xF863, 0x06BA, 0xFA3F, 0x04BF,
  0xFC40, 0x02D0, 0xFE08, 0x013F, 0xFF58, 0x0035, 0x001C, 0xFFB2,
  0x0067, 0xFF93, 0x0066, 0xFFA8, 0x0047, 0xFFCA, 0x0028, 0xFFE2,
/*0x0016*/0x0000
};

static const word resample_up24_filter_coefs3[RESAMPLE_FILTER_TAPS] =
{
  0xFFDD, 0x002A, 0xFFCC, 0x003E, 0xFFBB, 0x0047, 0xFFC3, 0x0024,
  0x000A, 0xFFAF, 0x00B3, 0xFED1, 0x01C4, 0xFD95, 0x031C, 0xFC36,
  0x0466, 0xFB24, 0x0513, 0xFB1C, 0x040C, 0xFE29, 0xFB39, 0x73FD,
  0x1A02, 0xF042, 0x0BEE, 0xF681, 0x0793, 0xFA14, 0x0479, 0xFCCC,
  0x021F, 0xFEC5, 0x0088, 0xFFFC, 0xFFAA, 0x008A, 0xFF5F, 0x00A1,
  0xFF6E, 0x007A, 0xFFA0, 0x0047, 0xFFCE, 0x0021, 0xFFEB, 0x000C
};

static const word resample_up24_filter_coefs4[RESAMPLE_FILTER_TAPS] =
{
  0xFFDD, 0x0029, 0xFFCF, 0x0039, 0xFFC3, 0x003A, 0xFFD4, 0x000D,
  0x0027, 0xFF8E, 0x00D7, 0xFEAE, 0x01E2, 0xFD81, 0x031D, 0xFC4F,
  0x0428, 0xFB93, 0x0463, 0xFC22, 0x028B, 0x006F, 0xF743, 0x71FC,
  0x2000, 0xEE35, 0x0CDC, 0xF61F, 0x07A5, 0xFA33, 0x043D, 0xFD16,
  0x01D1, 0xFF10, 0x0044, 0x0036, 0xFF7C, 0x00AD, 0xFF47, 0x00B0,
  0xFF66, 0x007E, 0xFFA0, 0x0045, 0xFFD1, 0x001E, 0xFFEF, 0x0009
};

static const word resample_up24_filter_coefs6[RESAMPLE_FILTER_TAPS] =
{
  0xFFDD, 0x0026, 0xFFD5, 0x002D, 0xFFD5, 0x0020, 0xFFF8, 0xFFDF,
  0x005D, 0xFF52, 0x0113, 0xFE78, 0x0208, 0xFD77, 0x02FE, 0xFCA9,
  0x0381, 0xFC9C, 0x02DE, 0xFE45, 0xFF94, 0x04AA, 0xF090, 0x6C60,
  0x2C5B, 0xEAA8, 0x0E35, 0xF5C6, 0x0772, 0xFAB3, 0x0394, 0xFDCD,
  0x011D, 0xFFB5, 0xFFB6, 0x00A9, 0xFF23, 0x00ED, 0xFF1D, 0x00C8,
  0xFF5B, 0x007F, 0xFFA5, 0x003D, 0xFFDA, 0x0015, 0xFFF7, 0x0001
};

static const word resample_up24_filter_coefs8[RESAMPLE_FILTER_TAPS] =
{
  0xFFE0, 0x0021, 0xFFDE, 0x001F, 0xFFE9, 0x0005, 0x001B, 0xFFB6,
  0x008B, 0xFF23, 0x013D, 0xFE5A, 0x020F, 0xFD92, 0x02B3, 0xFD31,
  0x02AC, 0xFDCE, 0x013E, 0x0068, 0xFCCC, 0x0851, 0xEB8E, 0x64CC,
  0x38E2, 0xE80F, 0x0EC8, 0xF606, 0x06CB, 0xFB8A, 0x02AE, 0xFEAC,
  0x0052, 0x0063, 0xFF28, 0x0116, 0xFED5, 0x0120, 0xFF00, 0x00D5,
  0xFF5B, 0x0078, 0xFFAF, 0x0032, 0xFFE5, 0x000B, 0x0000, 0xFFF9
};

static const word resample_up24_filter_coefs9[RESAMPLE_FILTER_TAPS] =
{
  0xFFE2, 0x001E, 0xFFE3, 0x0018, 0xFFF3, 0xFFF7, 0x002B, 0xFFA3,
  0x009F, 0xFF11, 0x014B, 0xFE55, 0x0207, 0xFDAD, 0x027F, 0xFD84,
  0x0235, 0xFE70, 0x006C, 0x0171, 0xFB86, 0x09E0, 0xE9B4, 0x605A,
  0x3F17, 0xE732, 0x0EC0, 0xF661, 0x064D, 0xFC13, 0x0228, 0xFF27,
  0xFFE8, 0x00BB, 0xFEE4, 0x0148, 0xFEB3, 0x0134, 0xFEF6, 0x00D6,
  0xFF5E, 0x0072, 0xFFB6, 0x002B, 0xFFEC, 0x0005, 0x0004, 0xFFF5
};

static const word resample_up24_filter_coefs12[RESAMPLE_FILTER_TAPS_HALF] =
{
  0xFFEA, 0x0012, 0xFFF4, 0x0001, 0x0011, 0xFFD3, 0x0055, 0xFF76,
  0x00C9, 0xFEF1, 0x0156, 0xFE6B, 0x01C3, 0xFE2E, 0x01B4, 0xFEA6,
  0x00B0, 0x005F, 0xFE0F, 0x043A, 0xF859, 0x0D51, 0xE6AE, 0x50DD,
};

static const word resample_up24_filter_coefs15[RESAMPLE_FILTER_TAPS] =
{
  0xFFF5, 0x0004, 0x0005, 0xFFEC, 0x002B, 0xFFB6, 0x0072, 0xFF5E,
  0x00D6, 0xFEF6, 0x0134, 0xFEB3, 0x0148, 0xFEE4, 0x00BB, 0xFFE8,
  0xFF27, 0x0228, 0xFC13, 0x064D, 0xF661, 0x0EC0, 0xE732, 0x3F17,
  0x605A, 0xE9B4, 0x09E0, 0xFB86, 0x0171, 0x006C, 0xFE70, 0x0235,
  0xFD84, 0x027F, 0xFDAD, 0x0207, 0xFE55, 0x014B, 0xFF11, 0x009F,
  0xFFA3, 0x002B, 0xFFF7, 0xFFF3, 0x0018, 0xFFE3, 0x001E, 0xFFE2
};

static const word resample_up24_filter_coefs16[RESAMPLE_FILTER_TAPS] =
{
  0xFFF9, 0x0000, 0x000B, 0xFFE5, 0x0032, 0xFFAF, 0x0078, 0xFF5B,
  0x00D5, 0xFF00, 0x0120, 0xFED5, 0x0116, 0xFF28, 0x0063, 0x0052,
  0xFEAC, 0x02AE, 0xFB8A, 0x06CB, 0xF606, 0x0EC8, 0xE80F, 0x38E2,
  0x64CC, 0xEB8E, 0x0851, 0xFCCC, 0x0068, 0x013E, 0xFDCE, 0x02AC,
  0xFD31, 0x02B3, 0xFD92, 0x020F, 0xFE5A, 0x013D, 0xFF23, 0x008B,
  0xFFB6, 0x001B, 0x0005, 0xFFE9, 0x001F, 0xFFDE, 0x0021, 0xFFE0
};

static const word resample_up24_filter_coefs18[RESAMPLE_FILTER_TAPS] =
{
  0x0001, 0xFFF7, 0x0015, 0xFFDA, 0x003D, 0xFFA5, 0x007F, 0xFF5B,
  0x00C8, 0xFF1D, 0x00ED, 0xFF23, 0x00A9, 0xFFB6, 0xFFB5, 0x011D,
  0xFDCD, 0x0394, 0xFAB3, 0x0772, 0xF5C6, 0x0E35, 0xEAA8, 0x2C5B,
  0x6C60, 0xF090, 0x04AA, 0xFF94, 0xFE45, 0x02DE, 0xFC9C, 0x0381,
  0xFCA9, 0x02FE, 0xFD77, 0x0208, 0xFE78, 0x0113, 0xFF52, 0x005D,
  0xFFDF, 0xFFF8, 0x0020, 0xFFD5, 0x002D, 0xFFD5, 0x0026, 0xFFDD
};

static const word resample_up24_filter_coefs20[RESAMPLE_FILTER_TAPS] =
{
  0x0009, 0xFFEF, 0x001E, 0xFFD1, 0x0045, 0xFFA0, 0x007E, 0xFF66,
  0x00B0, 0xFF47, 0x00AD, 0xFF7C, 0x0036, 0x0044, 0xFF10, 0x01D1,
  0xFD16, 0x043D, 0xFA33, 0x07A5, 0xF61F, 0x0CDC, 0xEE35, 0x2000,
  0x71FC, 0xF743, 0x006F, 0x028B, 0xFC22, 0x0463, 0xFB93, 0x0428,
  0xFC4F, 0x031D, 0xFD81, 0x01E2, 0xFEAE, 0x00D7, 0xFF8E, 0x0027,
  0x000D, 0xFFD4, 0x003A, 0xFFC3, 0x0039, 0xFFCF, 0x0029, 0xFFDD
};

static const word resample_up24_filter_coefs21[RESAMPLE_FILTER_TAPS] =
{
  0x000C, 0xFFEB, 0x0021, 0xFFCE, 0x0047, 0xFFA0, 0x007A, 0xFF6E,
  0x00A1, 0xFF5F, 0x008A, 0xFFAA, 0xFFFC, 0x0088, 0xFEC5, 0x021F,
  0xFCCC, 0x0479, 0xFA14, 0x0793, 0xF681, 0x0BEE, 0xF042, 0x1A02,
  0x73FD, 0xFB39, 0xFE29, 0x040C, 0xFB1C, 0x0513, 0xFB24, 0x0466,
  0xFC36, 0x031C, 0xFD95, 0x01C4, 0xFED1, 0x00B3, 0xFFAF, 0x000A,
  0x0024, 0xFFC3, 0x0047, 0xFFBB, 0x003E, 0xFFCC, 0x002A, 0xFFDD
};

#endif
/*---------------------------------------------------------------------------*/

void resample_down_init (t_resample_down *p_resample, word mode)
{
  p_resample->mode = mode;
  p_resample->filter_pos = 0;
  switch (p_resample->mode)
  {
  case RESAMPLE_MODE_2:
    memset (p_resample->filter_buffer, 0, (2 * RESAMPLE_FILTER_TAPS + 1) * sizeof(short));
    break;
  case RESAMPLE_MODE_3:
    memset (p_resample->filter_buffer, 0, (3 * RESAMPLE_FILTER_TAPS + 1) * sizeof(short));
    break;
  case RESAMPLE_MODE_4:
    memset (p_resample->filter_buffer, 0, (4 * RESAMPLE_FILTER_TAPS + 1) * sizeof(short));
    break;
  case RESAMPLE_MODE_6:
    memset (p_resample->filter_buffer, 0, (6 * RESAMPLE_FILTER_TAPS + 1) * sizeof(short));
    break;
  case RESAMPLE_MODE_3_2:
    memset (p_resample->filter_buffer, 0, ((3 * RESAMPLE_FILTER_TAPS) / 2) * sizeof(short));
    break;
  case RESAMPLE_MODE_4_3:
    memset (p_resample->filter_buffer, 0, ((4 * RESAMPLE_FILTER_TAPS3) / 3) * sizeof(short));
    break;
  case RESAMPLE_MODE_8_3:
    memset (p_resample->filter_buffer, 0, ((8 * RESAMPLE_FILTER_TAPS3) / 3) * sizeof(short));
    break;
  }
}

void resample_down (t_resample_down *p_resample,
  const short *in_sample_buffer, word out_sample_count, short *out_sample_buffer)
{
  word i;

  switch (p_resample->mode)
  {
  case RESAMPLE_MODE_2:
    for (i = 0; i < out_sample_count; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[2*i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 2 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
      out_sample_buffer[i] = sdsp_fir_half_plus1_coefs ((const short *) resample_down2_filter_coefs,
        p_resample->filter_buffer, p_resample->filter_pos, 2 * RESAMPLE_FILTER_TAPS + 1);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[2*i + 1];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 2 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
    }
    break;
  case RESAMPLE_MODE_3:
    for (i = 0; i < out_sample_count; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 3 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
      out_sample_buffer[i] = sdsp_fir_half_plus1_coefs ((const short *) resample_down3_filter_coefs,
        p_resample->filter_buffer, p_resample->filter_pos, 3 * RESAMPLE_FILTER_TAPS + 1);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i + 1];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 3 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i + 2];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 3 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
    }
    break;
  case RESAMPLE_MODE_4:
    for (i = 0; i < out_sample_count; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[4*i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 4 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
      out_sample_buffer[i] = sdsp_fir_half_plus1_coefs ((const short *) resample_down4_filter_coefs,
        p_resample->filter_buffer, p_resample->filter_pos, 4 * RESAMPLE_FILTER_TAPS + 1);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[4*i + 1];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 4 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[4*i + 2];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 4 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[4*i + 3];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 4 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
    }
    break;
  case RESAMPLE_MODE_6:
    for (i = 0; i < out_sample_count; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[6*i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 6 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
      out_sample_buffer[i] = sdsp_fir_half_plus1_coefs ((const short *) resample_down6_filter_coefs,
        p_resample->filter_buffer, p_resample->filter_pos, 6 * RESAMPLE_FILTER_TAPS + 1);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[6*i + 1];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 6 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[6*i + 2];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 6 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[6*i + 3];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 6 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[6*i + 4];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 6 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[6*i + 5];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= 6 * RESAMPLE_FILTER_TAPS + 1)
        p_resample->filter_pos = 0;
    }
    break;
  case RESAMPLE_MODE_3_2:
    for (i = 0; i < out_sample_count / 2; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (3 * RESAMPLE_FILTER_TAPS) / 2)
        p_resample->filter_pos = 0;
      out_sample_buffer[2*i] = sdsp_fir ((const short *) resample_down32_filter_coefs0,
        p_resample->filter_buffer, p_resample->filter_pos, (3 * RESAMPLE_FILTER_TAPS) / 2);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i + 1];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (3 * RESAMPLE_FILTER_TAPS) / 2)
        p_resample->filter_pos = 0;
      out_sample_buffer[2*i + 1] = sdsp_fir_half_coefs ((const short *) resample_down32_filter_coefs1,
        p_resample->filter_buffer, p_resample->filter_pos, (3 * RESAMPLE_FILTER_TAPS) / 2);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i + 2];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (3 * RESAMPLE_FILTER_TAPS) / 2)
        p_resample->filter_pos = 0;
    }
    break;
  case RESAMPLE_MODE_4_3:
    for (i = 0; i < out_sample_count / 3; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[4*i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (4 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
      out_sample_buffer[3*i] = sdsp_fir ((const short *) resample_down43_filter_coefs0,
        p_resample->filter_buffer, p_resample->filter_pos, (4 * RESAMPLE_FILTER_TAPS3) / 3);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[4*i + 1];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (4 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
      out_sample_buffer[3*i + 1] = sdsp_fir ((const short *) resample_down43_filter_coefs1,
        p_resample->filter_buffer, p_resample->filter_pos, (4 * RESAMPLE_FILTER_TAPS3) / 3);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[4*i + 2];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (4 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
      out_sample_buffer[3*i + 2] = sdsp_fir ((const short *) resample_down43_filter_coefs2,
        p_resample->filter_buffer, p_resample->filter_pos, (4 * RESAMPLE_FILTER_TAPS3) / 3);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[4*i + 3];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (4 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
    }
    break;
  case RESAMPLE_MODE_8_3:
    for (i = 0; i < out_sample_count / 3; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[8*i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (8 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
      out_sample_buffer[3*i] = sdsp_fir ((const short *) resample_down83_filter_coefs0,
        p_resample->filter_buffer, p_resample->filter_pos, (8 * RESAMPLE_FILTER_TAPS3) / 3);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[8*i + 1];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (8 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[8*i + 2];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (8 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
      out_sample_buffer[3*i + 1] = sdsp_fir ((const short *) resample_down83_filter_coefs2,
        p_resample->filter_buffer, p_resample->filter_pos, (8 * RESAMPLE_FILTER_TAPS3) / 3);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[8*i + 3];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (8 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[8*i + 4];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (8 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[8*i + 5];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (8 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
      out_sample_buffer[3*i + 2] = sdsp_fir ((const short *) resample_down83_filter_coefs1,
        p_resample->filter_buffer, p_resample->filter_pos, (8 * RESAMPLE_FILTER_TAPS3) / 3);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[8*i + 6];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (8 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[8*i + 7];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= (8 * RESAMPLE_FILTER_TAPS3) / 3)
        p_resample->filter_pos = 0;
    }
    break;
  }
}

void resample_up_init (t_resample_up *p_resample, word mode)
{
  p_resample->mode = mode;
  p_resample->filter_pos = 0;
  memset (p_resample->filter_buffer, 0, RESAMPLE_FILTER_TAPS * sizeof(short));
}

void resample_up (t_resample_up *p_resample,
  const short *in_sample_buffer, word in_sample_count, short *out_sample_buffer)
{
  word i;

  switch (p_resample->mode)
  {
  case RESAMPLE_MODE_2:
    for (i = 0; i < in_sample_count; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[2*i] = sdsp_fir ((const short *) resample_up24_filter_coefs0,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[2*i + 1] = sdsp_fir_half_coefs ((const short *) resample_up24_filter_coefs12,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
    }
    break;
  case RESAMPLE_MODE_3:
    for (i = 0; i < in_sample_count; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[3*i] = sdsp_fir ((const short *) resample_up24_filter_coefs0,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[3*i + 1] = sdsp_fir ((const short *) resample_up24_filter_coefs8,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[3*i + 2] = sdsp_fir ((const short *) resample_up24_filter_coefs16,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
    }
    break;
  case RESAMPLE_MODE_4:
    for (i = 0; i < in_sample_count; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[4*i] = sdsp_fir ((const short *) resample_up24_filter_coefs0,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[4*i + 1] = sdsp_fir ((const short *) resample_up24_filter_coefs6,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[4*i + 2] = sdsp_fir_half_coefs ((const short *) resample_up24_filter_coefs12,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[4*i + 3] = sdsp_fir ((const short *) resample_up24_filter_coefs18,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
    }
    break;
  case RESAMPLE_MODE_6:
    for (i = 0; i < in_sample_count; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[6*i] = sdsp_fir ((const short *) resample_up24_filter_coefs0,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[6*i + 1] = sdsp_fir ((const short *) resample_up24_filter_coefs4,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[6*i + 2] = sdsp_fir ((const short *) resample_up24_filter_coefs8,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[6*i + 3] = sdsp_fir_half_coefs ((const short *) resample_up24_filter_coefs12,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[6*i + 4] = sdsp_fir ((const short *) resample_up24_filter_coefs16,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[6*i + 5] = sdsp_fir ((const short *) resample_up24_filter_coefs20,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
    }
    break;
  case RESAMPLE_MODE_3_2:
    for (i = 0; i < in_sample_count / 2; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[2*i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[3*i] = sdsp_fir ((const short *) resample_up24_filter_coefs0,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[3*i + 1] = sdsp_fir ((const short *) resample_up24_filter_coefs16,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[2*i + 1];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[3*i + 2] = sdsp_fir ((const short *) resample_up24_filter_coefs8,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
    }
    break;
  case RESAMPLE_MODE_4_3:
    for (i = 0; i < in_sample_count / 3; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[4*i] = sdsp_fir ((const short *) resample_up24_filter_coefs0,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[4*i + 1] = sdsp_fir ((const short *) resample_up24_filter_coefs18,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i + 1];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[4*i + 2] = sdsp_fir_half_coefs ((const short *) resample_up24_filter_coefs12,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i + 2];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[4*i + 3] = sdsp_fir ((const short *) resample_up24_filter_coefs6,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
    }
    break;
  case RESAMPLE_MODE_8_3:
    for (i = 0; i < in_sample_count / 3; i++)
    {
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[8*i] = sdsp_fir ((const short *) resample_up24_filter_coefs0,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[8*i + 1] = sdsp_fir ((const short *) resample_up24_filter_coefs9,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[8*i + 2] = sdsp_fir ((const short *) resample_up24_filter_coefs18,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i + 1];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[8*i + 3] = sdsp_fir ((const short *) resample_up24_filter_coefs3,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[8*i + 4] = sdsp_fir_half_coefs ((const short *) resample_up24_filter_coefs12,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[8*i + 5] = sdsp_fir ((const short *) resample_up24_filter_coefs21,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      p_resample->filter_buffer[p_resample->filter_pos] = in_sample_buffer[3*i + 2];
      (p_resample->filter_pos)++;
      if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
        p_resample->filter_pos = 0;
      out_sample_buffer[8*i + 6] = sdsp_fir ((const short *) resample_up24_filter_coefs6,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
      out_sample_buffer[8*i + 7] = sdsp_fir ((const short *) resample_up24_filter_coefs15,
        p_resample->filter_buffer, p_resample->filter_pos, RESAMPLE_FILTER_TAPS);
    }
    break;
  }
}


void resample_up_put_sample (t_resample_up *p_resample, short in_sample)
{
  p_resample->filter_buffer[p_resample->filter_pos] = in_sample;
  (p_resample->filter_pos)++;
  if (p_resample->filter_pos >= RESAMPLE_FILTER_TAPS)
    p_resample->filter_pos = 0;
}


/*---------------------------------------------------------------------------*/
