/* Extended Module Player
 * Copyright (C) 1996-2001 Claudio Matsuoka and Hipolito Carraro Jr.
 *
 * This file is part of the Extended Module Player and is distributed
 * under the terms of the GNU General Public License. See docs/COPYING
 * for more information.
 *
 * $Id: mix_all.c,v 1.7 2001/01/03 10:57:37 claudio Exp $
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "xmpi.h"
#include "driver.h"
#include "mixer.h"
#include "synth.h"


/* Mixers
 *
 * To increase performance eight mixers are defined, one for each
 * combination of the following parameters: interpolation, resolution
 * and number of channels.
 */
#define INTERPOLATE() do { \
    if (itpt >> SMIX_SFT_FT) { \
	cur_bk += itpt >> SMIX_SFT_FT; \
	smp_x1 = in_bk[cur_bk]; \
	smp_dt = in_bk[cur_bk + 1] - smp_x1; \
	itpt &= SMIX_AND_FT; \
    } \
    smp_in = smp_x1 + ((itpt * smp_dt) >> SMIX_SFT_FT); \
} while (0)

#define DONT_INTERPOLATE() do { \
    smp_in = in_bk[itpt >> SMIX_SFT_FT]; \
} while (0)

#define DO_FILTER() do { \
    smp_in = (smp_in * vi->flt_B0 + fx1 * vi->flt_B1 + fx2 * vi->flt_B2) / FILTER_PRECISION; \
    fx2 = fx1; fx1 = smp_in; \
} while (0)

#define SAVE_FILTER() do { \
    vi->flt_X1 = fx1; \
    vi->flt_X2 = fx2; \
} while (0)

#define MIX_STEREO() do { \
    *(tmp_bk++) += smp_in * vr; \
    *(tmp_bk++) += smp_in * vl; \
    itpt += itpt_inc; \
} while (0)

#define MIX_MONO() do { \
    *(tmp_bk++) += smp_in * vl; \
    itpt += itpt_inc; \
} while (0)

#define MIX_LOOP(x) do { \
    while (count--) { x } \
} while (0)

#define VAR_NORM(x) \
    register int smp_in; \
    x *in_bk = vi->sptr; \
    int cur_bk = vi->pos - 1; \
    int itpt = vi->itpt + (1 << SMIX_SFT_FT)
#define VAR_ITPT(x) \
    VAR_NORM(x); \
    int smp_x1 = 0, smp_dt = 0
#define VAR_FILT \
    int fx1 = vi->flt_X1, fx2 = vi->flt_X2

#define SMIX_MIXER(f) void f(struct voice_info *vi, int* tmp_bk, \
    int count, int vl, int vr, int itpt_inc)

/* Handler for 8 bit samples, interpolated stereo output
 */
SMIX_MIXER(smix_st8itpt)
{
    VAR_ITPT(int8);

    vl <<= 8;
    vr <<= 8;
    while (count--) { INTERPOLATE (); MIX_STEREO (); }
}


/* Handler for 16 bit samples, interpolated stereo output
 */
SMIX_MIXER(smix_st16itpt)
{
    VAR_ITPT(int16);
    while (count--) { INTERPOLATE (); MIX_STEREO (); }
}


/* Handler for 8 bit samples, non-interpolated stereo output
 */
SMIX_MIXER(smix_st8norm)
{
    VAR_NORM(int8);

    vl <<= 8;
    vr <<= 8;
    in_bk += cur_bk;
    while (count--) { DONT_INTERPOLATE (); MIX_STEREO (); }
}


/* Handler for 16 bit samples, non-interpolated stereo output
 */
SMIX_MIXER(smix_st16norm)
{
    VAR_NORM(int16);

    in_bk += cur_bk;
    while (count--) { DONT_INTERPOLATE (); MIX_STEREO (); }
}


/* Handler for 8 bit samples, interpolated mono output
 */
SMIX_MIXER(smix_mn8itpt)
{
    VAR_ITPT(int8);

    vl <<= 9;
    while (count--) { INTERPOLATE (); MIX_MONO (); }
}


/* Handler for 16 bit samples, interpolated mono output
 */
SMIX_MIXER(smix_mn16itpt)
{
    VAR_ITPT(int16);

    vl <<= 1;
    while (count--) { INTERPOLATE (); MIX_MONO (); }
}


/* Handler for 8 bit samples, non-interpolated mono output
 */
SMIX_MIXER(smix_mn8norm)
{
    VAR_NORM(int8);

    vl <<= 9;
    in_bk += cur_bk;
    while (count--) { DONT_INTERPOLATE (); MIX_MONO (); }
}


/* Handler for 16 bit samples, non-interpolated mono output
 */
SMIX_MIXER(smix_mn16norm)
{
    VAR_NORM(int16);

    vl <<= 1;
    in_bk += cur_bk;
    while (count--) { DONT_INTERPOLATE (); MIX_MONO (); }
}

/*
 * Filtering mixers
 */

/* Handler for 8 bit samples, interpolated stereo output
 */
SMIX_MIXER(smix_st8itpt_flt)
{
    VAR_ITPT(int8);
    VAR_FILT;

    vl <<= 8;
    vr <<= 8;
    while (count--) { INTERPOLATE (); DO_FILTER (); MIX_STEREO (); }
    SAVE_FILTER();
}


/* Handler for 16 bit samples, interpolated stereo output
 */
SMIX_MIXER(smix_st16itpt_flt)
{
    VAR_ITPT(int16);
    VAR_FILT;

    while (count--) { INTERPOLATE (); DO_FILTER (); MIX_STEREO (); }
    SAVE_FILTER();
}


/* Handler for 8 bit samples, interpolated mono output
 */
SMIX_MIXER(smix_mn8itpt_flt)
{
    VAR_ITPT(int8);
    VAR_FILT;

    vl <<= 9;
    while (count--) { INTERPOLATE (); DO_FILTER (); MIX_MONO (); }
    SAVE_FILTER();
}


/* Handler for 16 bit samples, interpolated mono output
 */
SMIX_MIXER(smix_mn16itpt_flt)
{
    VAR_ITPT(int16);
    VAR_FILT;

    vl <<= 1;
    while (count--) { INTERPOLATE (); DO_FILTER (); MIX_MONO (); }
    SAVE_FILTER();
}


/* Handler for synthesized sounds
 */
SMIX_MIXER(smix_synth)
{
    synth_mixer (tmp_bk, count, itpt_inc, vl, vr);
}

