/*

    TiMidity -- Experimental MIDI to WAVE converter
    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>

    Suddenly, you realize that this program is free software; you get
    an overwhelming urge to redistribute it and/or modify it under the
    terms of the GNU General Public License as published by the Free
    Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received another copy of the GNU General Public
    License along with this program; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    I bet they'll be amazed.

    mix.c */

#include <math.h>
#include <stdio.h>
#ifdef __FreeBSD__
#    include <stdlib.h>
#else
#    include <malloc.h>
#endif
#include "gtim.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "output.h"
#include "controls.h"
#include "tables.h"
#include "resample.h"
#include "mix.h"

/* Returns 1 if envelope runs out */
int
recompute_envelope (int v)
{
    int     stage;

    stage = voice[v].envelope_stage;

#if 0
    if (voice[v].envelope_offset[stage] >> 23 > 127)
	fprintf (stderr, "offset %d\n",
		 voice[v].envelope_offset[stage] >> 23);
#endif

    if (stage > 5) {
	/* Envelope ran out. */
	if (!(voice[v].status & VOICE_FREE)) {
	    voice[v].status = VOICE_FREE;
	    ctl->note (v);
	}
	return 1;
    }

  /**if (voice[v].sample->modes & MODES_ENVELOPE)**/
    if ((voice[v].sample->modes & MODES_ENVELOPE)
	&& (voice[v].sample->modes & MODES_SUSTAIN)) {
	if (voice[v].status & (VOICE_ON | VOICE_SUSTAINED)) {
	    if (stage > 2) {
		/* Freeze envelope until note turns off. Trumpets want this. */
		voice[v].envelope_increment = 0;
		return 0;
	    }
	}
    }
    voice[v].envelope_stage = stage + 1;

#if 0
    fprintf (stderr,
	     "v=%d stage %d, inc %ld[%ld], vol %ld[%ld], offset %ld[%ld]\n",
	     v, stage, voice[v].envelope_increment,
	     voice[v].envelope_increment >> 23, voice[v].envelope_volume,
	     voice[v].envelope_volume >> 23, voice[v].envelope_offset[stage],
	     voice[v].envelope_offset[stage] >> 23);
#endif


#ifdef tplus
    if (voice[v].envelope_volume == (int) voice[v].envelope_offset[stage] ||
	(stage > 2
	 && voice[v].envelope_volume < (int) voice[v].envelope_offset[stage]))
#else
    if (voice[v].envelope_volume == voice[v].envelope_offset[stage])
#endif

#if 0
	if ((voice[v].envelope_increment >= 0
	     && voice[v].envelope_volume >= voice[v].envelope_offset[stage])
	    || (voice[v].envelope_increment < 0
		&& voice[v].envelope_volume <=
		voice[v].envelope_offset[stage]))
#endif
	    return recompute_envelope (v);
    voice[v].envelope_target = voice[v].envelope_offset[stage];
    voice[v].envelope_increment = voice[v].envelope_rate[stage];
    if ((int) voice[v].envelope_target < voice[v].envelope_volume)
	voice[v].envelope_increment = -voice[v].envelope_increment;

#if 0
    fprintf (stderr,
	     "	cont:v=%d, stage %d, inc %ld[%ld], vol %ld[%ld], offset %ld[%ld]\n",
	     v, stage, voice[v].envelope_increment,
	     voice[v].envelope_increment >> 23, voice[v].envelope_volume,
	     voice[v].envelope_volume >> 23, voice[v].envelope_offset[stage],
	     voice[v].envelope_offset[stage] >> 23);
#endif




    return 0;
}

#ifdef tplus
int
apply_envelope_to_amp (int v)
#else
void
apply_envelope_to_amp (int v)
#endif
{
    FLOAT_T lamp = voice[v].left_amp, ramp, lramp, rramp, ceamp, lfeamp;
    int32   la, ra, lra, rra, cea, lfea;
    if (voice[v].panned == PANNED_MYSTERY) {
	lramp = voice[v].lr_amp;
	ramp = voice[v].right_amp;
	ceamp = voice[v].ce_amp;
	rramp = voice[v].rr_amp;
	lfeamp = voice[v].lfe_amp;

	if (voice[v].tremolo_phase_increment) {
	    FLOAT_T tv = voice[v].tremolo_volume;
	    lramp *= tv;
	    lamp *= tv;
	    ceamp *= tv;
	    ramp *= tv;
	    rramp *= tv;
	    lfeamp *= tv;
	}
	if (voice[v].sample->modes & MODES_ENVELOPE) {
	    FLOAT_T ev = (FLOAT_T) vol_table[voice[v].envelope_volume >> 23];
	    lramp *= ev;
	    lamp *= ev;
	    ceamp *= ev;
	    ramp *= ev;
	    rramp *= ev;
	    lfeamp *= ev;
#if 0
	    if (voice[v].envelope_volume >> 23 > 127)
		fprintf (stderr, "env vol %d >>23 = %d\n",
			 voice[v].envelope_volume,
			 voice[v].envelope_volume >> 23);
#endif
	}

	la = (int32) FRSCALE (lamp, AMP_BITS);
	ra = (int32) FRSCALE (ramp, AMP_BITS);
	lra = (int32) FRSCALE (lramp, AMP_BITS);
	rra = (int32) FRSCALE (rramp, AMP_BITS);
	cea = (int32) FRSCALE (ceamp, AMP_BITS);
	lfea = (int32) FRSCALE (lfeamp, AMP_BITS);

#ifdef WATCH_AMPS_MAXING
if (la > MAX_AMP_VALUE)
	fprintf(stderr,"la maxed\n");
if (ra > MAX_AMP_VALUE)
	fprintf(stderr,"ra maxed\n");
if (lra > MAX_AMP_VALUE)
	fprintf(stderr,"lra maxed\n");
if (rra > MAX_AMP_VALUE)
	fprintf(stderr,"rra maxed\n");
if (cea > MAX_AMP_VALUE)
	fprintf(stderr,"cea maxed\n");
if (lfea > MAX_AMP_VALUE)
	fprintf(stderr,"lfea maxed\n");
#endif

	if (la > MAX_AMP_VALUE)
	    la = MAX_AMP_VALUE;
	if (ra > MAX_AMP_VALUE)
	    ra = MAX_AMP_VALUE;
	if (lra > MAX_AMP_VALUE)
	    lra = MAX_AMP_VALUE;
	if (rra > MAX_AMP_VALUE)
	    rra = MAX_AMP_VALUE;
	if (cea > MAX_AMP_VALUE)
	    cea = MAX_AMP_VALUE;
	if (lfea > MAX_AMP_VALUE)
	    lfea = MAX_AMP_VALUE;

#ifdef tplus
	if ((voice[v].
	     status & (VOICE_OFF | VOICE_DIE | VOICE_FREE | VOICE_SUSTAINED))
	    && (la | ra) <= MIN_AMP_VALUE) {
	    if (!(voice[v].status & VOICE_FREE)) {
		voice[v].status = VOICE_FREE;
		ctl->note (v);
	    }
	    return 1;
	}
#endif

	voice[v].lr_mix = FINAL_VOLUME (lra);
	voice[v].left_mix = FINAL_VOLUME (la);
	voice[v].ce_mix = FINAL_VOLUME (cea);
	voice[v].right_mix = FINAL_VOLUME (ra);
	voice[v].rr_mix = FINAL_VOLUME (rra);
	voice[v].lfe_mix = FINAL_VOLUME (lfea);

    }
    else {
	if (voice[v].tremolo_phase_increment)
	    lamp *= voice[v].tremolo_volume;
	if (voice[v].sample->modes & MODES_ENVELOPE)
	    lamp *= vol_table[voice[v].envelope_volume >> 23];

	la = (int32) FRSCALE (lamp, AMP_BITS);

	if (la > MAX_AMP_VALUE)
	    la = MAX_AMP_VALUE;

#ifdef tplus
	if ((voice[v].
	     status & (VOICE_OFF | VOICE_DIE | VOICE_FREE | VOICE_SUSTAINED))
	    && la <= MIN_AMP_VALUE) {
	    if (!(voice[v].status & VOICE_FREE)) {
		voice[v].status = VOICE_FREE;
		ctl->note (v);
	    }
	    return 1;
	}
#endif

	voice[v].left_mix = FINAL_VOLUME (la);
    }
#ifdef tplus
    return 0;
#endif
}

static int
update_envelope (int v)
{
    voice[v].envelope_volume += voice[v].envelope_increment;
    if (voice[v].envelope_volume < 0)
	voice[v].envelope_volume = 0;
    /* Why is there no ^^ operator?? */
    if (((voice[v].envelope_increment < 0) &&
	 (voice[v].envelope_volume <= (int) voice[v].envelope_target)) ||
	((voice[v].envelope_increment > 0) &&
	 (voice[v].envelope_volume >= (int) voice[v].envelope_target))) {
	voice[v].envelope_volume = voice[v].envelope_target;
	if (recompute_envelope (v))
	    return 1;
    }
    return 0;
}

void
update_tremolo (int v)
{
    int32   depth = voice[v].tremolo_depth << 7;

    if (voice[v].tremolo_sweep) {
	/* Update sweep position */

	voice[v].tremolo_sweep_position += voice[v].tremolo_sweep;
	if (voice[v].tremolo_sweep_position >= (1 << SWEEP_SHIFT))
	    voice[v].tremolo_sweep = 0;	/* Swept to max amplitude */
	else {
	    /* Need to adjust depth */
	    depth *= voice[v].tremolo_sweep_position;
	    depth >>= SWEEP_SHIFT;
	}
    }

    voice[v].tremolo_phase += voice[v].tremolo_phase_increment;

    /* if (voice[v].tremolo_phase >= (SINE_CYCLE_LENGTH<<RATE_SHIFT))
       voice[v].tremolo_phase -= SINE_CYCLE_LENGTH<<RATE_SHIFT;  */

    voice[v].tremolo_volume =
	1.0 - FRSCALENEG ((sine (voice[v].tremolo_phase >> RATE_SHIFT) + 1.0)
			  * depth * TREMOLO_AMPLITUDE_TUNING, 17);

    /* I'm not sure about the +1.0 there -- it makes tremoloed voices'
       volumes on average the lower the higher the tremolo amplitude. */
}

/* Returns 1 if the note died */
static int
update_signal (int v)
{
    if (voice[v].envelope_increment && update_envelope (v))
	return 1;

    if (voice[v].tremolo_phase_increment)
	update_tremolo (v);

#ifdef tplus
    return apply_envelope_to_amp (v);
#else
    apply_envelope_to_amp (v);
    return 0;
#endif
}

#ifdef LOOKUP_HACK
#    define MIXATION(a)	*lp++ += mixup[(a<<8) | (uint8)s];
#else
#    define MIXATION(a)	*lp++ += (a)*s;
#endif

#define MIXSKIP lp++
#define MIXHALF(a)	*lp++ += (a>>1)*s;

#ifdef NEW_PANNER
#define MIXFRONT(a)	*lp++ += (a>>1)*s;
#define MIXREAR(a)	*lp++ += (a>>1)*s;
#else
#define MIXFRONT(a)	*lp++ += (a>>1)*s;
#define MIXREAR(a)	*lp++ += (a)*s;
#endif

static void
mix_mystery_signal (resample_t *sp, int32 *lp, int v, uint32 count)
{
    Voice  *vp = voice + v;
    final_volume_t
	left_rear = vp->lr_mix,
	left = vp->left_mix,
	center = vp->ce_mix,
	right = vp->right_mix, right_rear = vp->rr_mix, lfe = vp->lfe_mix;
    uint32  cc;
    resample_t s;

    if (!(cc = vp->control_counter)) {
	cc = control_ratio;
	if (update_signal (v))
	    return;		/* Envelope ran out */

	left_rear = vp->lr_mix;
	left = vp->left_mix;
	center = vp->ce_mix;
	right = vp->right_mix;
	right_rear = vp->rr_mix;
	lfe = vp->lfe_mix;
    }

    while (count)
	if (cc < count) {
	    count -= cc;
	    while (cc--) {
		s = *sp++;
		MIXATION (left);
		MIXATION (right);
		if (num_ochannels >= 4) {
		    MIXATION (left_rear);
		    MIXATION (right_rear);
		}
		if (num_ochannels == 6) {
		    MIXATION (center);
		    MIXATION (lfe);
		}
	    }
	    cc = control_ratio;
	    if (update_signal (v))
		return;		/* Envelope ran out */

	    left_rear = vp->lr_mix;
	    left = vp->left_mix;
	    center = vp->ce_mix;
	    right = vp->right_mix;
	    right_rear = vp->rr_mix;
	    lfe = vp->lfe_mix;
	}
	else {
	    vp->control_counter = cc - count;
	    while (count--) {
		s = *sp++;
		MIXATION (left);
		MIXATION (right);
		if (num_ochannels >= 4) {
		    MIXATION (left_rear);
		    MIXATION (right_rear);
		}
		if (num_ochannels == 6) {
		    MIXATION (center);
		    MIXATION (lfe);
		}
	    }
	    return;
	}
}

static void
mix_center_signal (resample_t *sp, int32 *lp, int v, uint32 count)
{
    Voice  *vp = voice + v;
    final_volume_t
            left = vp->left_mix;
    uint32  cc;
    resample_t s;

    if (!(cc = vp->control_counter)) {
	cc = control_ratio;
	if (update_signal (v))
	    return;		/* Envelope ran out */
	left = vp->left_mix;
    }

    while (count)
	if (cc < count) {
	    count -= cc;
	    while (cc--) {
		s = *sp++;
		if (num_ochannels == 2) {
		    MIXATION (left);
		    MIXATION (left);
		}
		else if (num_ochannels == 4) {
		    MIXATION (left);
		    MIXSKIP;
		    MIXATION (left);
		    MIXSKIP;
		}
		else if (num_ochannels == 6) {
		    MIXSKIP;
		    MIXSKIP;
		    MIXSKIP;
		    MIXSKIP;
		    MIXATION (left);
		    MIXATION (left);
		}
	    }
	    cc = control_ratio;
	    if (update_signal (v))
		return;		/* Envelope ran out */
	    left = vp->left_mix;
	}
	else {
	    vp->control_counter = cc - count;
	    while (count--) {
		s = *sp++;
		if (num_ochannels == 2) {
		    MIXATION (left);
		    MIXATION (left);
		}
		else if (num_ochannels == 4) {
		    MIXATION (left);
		    MIXSKIP;
		    MIXATION (left);
		    MIXSKIP;
		}
		else if (num_ochannels == 6) {
		    MIXSKIP;
		    MIXSKIP;
		    MIXSKIP;
		    MIXSKIP;
		    MIXATION (left);
		    MIXATION (left);
		}
	    }
	    return;
	}
}


static void
mix_single_left_signal (resample_t *sp, int32 *lp, int v, uint32 count)
{
    Voice  *vp = voice + v;
    final_volume_t
            left = vp->left_mix;
    uint32     cc;
    resample_t s;

    if (!(cc = vp->control_counter)) {
	cc = control_ratio;
	if (update_signal (v))
	    return;		/* Envelope ran out */
	left = vp->left_mix;
    }

    while (count)
	if (cc < count) {
	    count -= cc;
	    while (cc--) {
		s = *sp++;
		if (num_ochannels == 2) {
		    MIXATION (left);
		    MIXSKIP;
		}
		if (num_ochannels >= 4) {
		    MIXFRONT (left);
		    MIXSKIP;
		    MIXREAR (left);
		    MIXSKIP;
		}
		if (num_ochannels == 6) {
		    MIXSKIP;
		    MIXATION (left);
		}
	    }
	    cc = control_ratio;
	    if (update_signal (v))
		return;		/* Envelope ran out */
	    left = vp->left_mix;
	}
	else {
	    vp->control_counter = cc - count;
	    while (count--) {
		s = *sp++;
		if (num_ochannels == 2) {
		    MIXATION (left);
		    MIXSKIP;
		}
		if (num_ochannels >= 4) {
		    MIXFRONT (left);
		    MIXSKIP;
		    MIXREAR (left);
		    MIXSKIP;
		}
		if (num_ochannels == 6) {
		    MIXSKIP;
		    MIXATION (left);
		}
	    }
	    return;
	}
}

static void
mix_single_right_signal (resample_t *sp, int32 *lp, int v, uint32 count)
{
    Voice  *vp = voice + v;
    final_volume_t
            left = vp->left_mix;
    uint32     cc;
    resample_t s;

    if (!(cc = vp->control_counter)) {
	cc = control_ratio;
	if (update_signal (v))
	    return;		/* Envelope ran out */
	left = vp->left_mix;
    }

    while (count)
	if (cc < count) {
	    count -= cc;
	    while (cc--) {
		s = *sp++;
		if (num_ochannels == 2) {
		    MIXSKIP;
		    MIXATION (left);
		}
		if (num_ochannels >= 4) {
		    MIXSKIP;
		    MIXFRONT (left);
		    MIXSKIP;
		    MIXREAR (left);
		}
		if (num_ochannels == 6) {
		    MIXSKIP;
		    MIXATION (left);
		}
	    }
	    cc = control_ratio;
	    if (update_signal (v))
		return;		/* Envelope ran out */
	    left = vp->left_mix;
	}
	else {
	    vp->control_counter = cc - count;
	    while (count--) {
		s = *sp++;
		if (num_ochannels == 2) {
		    MIXSKIP;
		    MIXATION (left);
		}
		if (num_ochannels >= 4) {
		    MIXSKIP;
		    MIXFRONT (left);
		    MIXSKIP;
		    MIXREAR (left);
		}
		if (num_ochannels == 6) {
		    MIXSKIP;
		    MIXATION (left);
		}
	    }
	    return;
	}
}

static void
mix_mono_signal (resample_t *sp, int32 *lp, int v, uint32 count)
{
    Voice  *vp = voice + v;
    final_volume_t
            left = vp->left_mix;
    uint32  cc;
    resample_t s;

    if (!(cc = vp->control_counter)) {
	cc = control_ratio;
	if (update_signal (v))
	    return;		/* Envelope ran out */
	left = vp->left_mix;
    }

    while (count)
	if (cc < count) {
	    count -= cc;
	    while (cc--) {
		s = *sp++;
		MIXATION (left);
	    }
	    cc = control_ratio;
	    if (update_signal (v))
		return;		/* Envelope ran out */
	    left = vp->left_mix;
	}
	else {
	    vp->control_counter = cc - count;
	    while (count--) {
		s = *sp++;
		MIXATION (left);
	    }
	    return;
	}
}

static void
mix_mystery (resample_t *sp, int32 *lp, int v, uint32 count)
{
    final_volume_t
	left_rear = voice[v].lr_mix,
	left = voice[v].left_mix,
	center = voice[v].ce_mix,
	right = voice[v].right_mix,
	right_rear = voice[v].rr_mix, lfe = voice[v].lfe_mix;

    resample_t s;

    while (count--) {
	s = *sp++;
	MIXATION (left);
	MIXATION (right);
	if (num_ochannels >= 4) {
	    MIXATION (left_rear);
	    MIXATION (right_rear);
	}
	if (num_ochannels == 6) {
	    MIXATION (center);
	    MIXATION (lfe);
	}
    }
}

static void
mix_center (resample_t *sp, int32 *lp, int v, uint32 count)
{
    final_volume_t
            left = voice[v].left_mix;
    resample_t s;

    while (count--) {
	s = *sp++;
	if (num_ochannels == 2) {
	    MIXATION (left);
	    MIXATION (left);
	}
	else if (num_ochannels == 4) {
	    MIXATION (left);
	    MIXATION (left);
	    MIXSKIP;
	    MIXSKIP;
	}
	else if (num_ochannels == 6) {
	    MIXSKIP;
	    MIXSKIP;
	    MIXSKIP;
	    MIXSKIP;
	    MIXATION (left);
	    MIXATION (left);
	}

    }
}

static void
mix_single_left (resample_t *sp, int32 *lp, int v, uint32 count)
{
    final_volume_t
            left = voice[v].left_mix;
    resample_t s;

    while (count--) {
	s = *sp++;
	if (num_ochannels == 2) {
	    MIXATION (left);
	    MIXSKIP;
	}
	if (num_ochannels >= 4) {
	    MIXFRONT (left);
	    MIXSKIP;
	    MIXREAR (left);
	    MIXSKIP;
	}
	if (num_ochannels == 6) {
	    MIXSKIP;
	    MIXATION (left);
	}
    }
}
static void
mix_single_right (resample_t *sp, int32 *lp, int v, uint32 count)
{
    final_volume_t
            left = voice[v].left_mix;
    resample_t s;

    while (count--) {
	s = *sp++;
	if (num_ochannels == 2) {
	    MIXSKIP;
	    MIXATION (left);
	}
	if (num_ochannels >= 4) {
	    MIXSKIP;
	    MIXFRONT (left);
	    MIXSKIP;
	    MIXREAR (left);
	}
	if (num_ochannels == 6) {
	    MIXSKIP;
	    MIXATION (left);
	}
    }
}

static void
mix_mono (resample_t *sp, int32 *lp, int v, uint32 count)
{
    final_volume_t
            left = voice[v].left_mix;
    resample_t s;

    while (count--) {
	s = *sp++;
	MIXATION (left);
    }
}

/* Ramp a note out in c samples */
static void
ramp_out (resample_t *sp, int32 *lp, int v, uint32 c)
{

    /* should be final_volume_t, but uint8 gives trouble. */
    int32   left_rear, left, center, right, right_rear, lfe, li, ri;

    resample_t s = 0;		/* silly warning about uninitialized s */
    left = voice[v].left_mix;
    if (c < 1)
	return;
    li = -(left / c);		/*NB: c can be 0 here */
    if (!li)
	li = -1;

    /* printf("Ramping out: left=%d, c=%d, li=%d\n", left, c, li); */

    if (num_ochannels > 1) {
	if (voice[v].panned == PANNED_MYSTERY) {
	    left_rear = voice[v].lr_mix;
	    center = voice[v].ce_mix;
	    right = voice[v].right_mix;
	    right_rear = voice[v].rr_mix;
	    lfe = voice[v].lfe_mix;

	    ri = -(right / c);
	    while (c--) {
		left_rear += li;
		if (left_rear < 0)
		    left_rear = 0;
		left += li;
		if (left < 0)
		    left = 0;
		center += li;
		if (center < 0)
		    center = 0;
		right += ri;
		if (right < 0)
		    right = 0;
		right_rear += ri;
		if (right_rear < 0)
		    right_rear = 0;
		lfe += li;
		if (lfe < 0)
		    lfe = 0;

		s = *sp++;
		MIXATION (left);
		MIXATION (right);
		if (num_ochannels >= 4) {
		    MIXATION (left_rear);
		    MIXATION (right_rear);
		}
		if (num_ochannels == 6) {
		    MIXATION (center);
		    MIXATION (lfe);
		}
	    }
	}
	else if (voice[v].panned == PANNED_CENTER) {
	    while (c--) {
		left += li;
		if (left < 0)
		    return;
		s = *sp++;
		if (num_ochannels == 2) {
		    MIXATION (left);
		    MIXATION (left);
		}
		else if (num_ochannels == 4) {
		    MIXATION (left);
		    MIXATION (left);
		    MIXSKIP;
		    MIXSKIP;
		}
		else if (num_ochannels == 6) {
		    MIXSKIP;
		    MIXSKIP;
		    MIXSKIP;
		    MIXSKIP;
		    MIXATION (left);
		    MIXATION (left);
		}
	    }
	}
	else if (voice[v].panned == PANNED_LEFT) {
	    while (c--) {
		left += li;
		if (left < 0)
		    return;
		s = *sp++;
		MIXATION (left);
		MIXSKIP;
		if (num_ochannels >= 4) {
		    MIXATION (left);
		    MIXSKIP;
		}
		if (num_ochannels == 6) {
		    MIXATION (left);
		    MIXATION (left);
		}
	    }
	}
	else if (voice[v].panned == PANNED_RIGHT) {
	    while (c--) {
		left += li;
		if (left < 0)
		    return;
		s = *sp++;
		MIXSKIP;
		MIXATION (left);
		if (num_ochannels >= 4) {
		    MIXSKIP;
		    MIXATION (left);
		}
		if (num_ochannels == 6) {
		    MIXATION (left);
		    MIXATION (left);
		}

	    }
	}
    }
    else {
	/* Mono output.  */
	while (c--) {
	    left += li;
	    if (left < 0)
		return;
	    s = *sp++;
	    MIXATION (left);
	}
    }
}

/**************** interface function ******************/

void
mix_voice (int32 *buf, int v, uint32 c)
{
    Voice  *vp = voice + v;
    resample_t *sp;
    uint32  count = c;

    if (!vp->sample_offset) vp->sample_offset = vp->initial_offset;

    if (vp->status & VOICE_DIE) {
/* this seems no longer useful: resample kill voices
   before they get here
*/
	if (count >= MAX_DIE_TIME)
	    count = MAX_DIE_TIME;
	sp = resample_voice (v, &count);
	ramp_out (sp, buf, v, count);
	vp->status = VOICE_FREE;
    }
    else {
	sp = resample_voice (v, &count);
	if (count < 1) {
	    vp->status = VOICE_FREE;
	    return;
	}
	if (play_mode->encoding & PE_MONO) {
	    /* Mono output. */
	    if (vp->envelope_increment || vp->tremolo_phase_increment)
		mix_mono_signal (sp, buf, v, count);
	    else
		mix_mono (sp, buf, v, count);
	}
	else {
	    if (vp->panned == PANNED_MYSTERY) {
		if (vp->envelope_increment || vp->tremolo_phase_increment)
		    mix_mystery_signal (sp, buf, v, count);
		else
		    mix_mystery (sp, buf, v, count);
	    }
	    else if (vp->panned == PANNED_CENTER) {
		if (vp->envelope_increment || vp->tremolo_phase_increment)
		    mix_center_signal (sp, buf, v, count);
		else
		    mix_center (sp, buf, v, count);
	    }
	    else {
		/* It's either full left or full right. In either case,
		   every other sample is 0. Just get the offset right: */
		/* if (vp->panned == PANNED_RIGHT) buf++; */

		if (vp->envelope_increment || vp->tremolo_phase_increment) {
		    if (vp->panned == PANNED_RIGHT)
			mix_single_right_signal (sp, buf, v, count);
		    else
			mix_single_left_signal (sp, buf, v, count);
		}
		else {
		    if (vp->panned == PANNED_RIGHT)
			mix_single_right (sp, buf, v, count);
		    else
			mix_single_left (sp, buf, v, count);
		}
	    }
	}
    }
}
