/*

    TiMidity -- Experimental MIDI to WAVE converter
    Copyright (C) 1995 Tuukka Toivonen <titoivon@snakemail.hut.fi>

    This program is free software; you can 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 a 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.

    resample.c
*/

#include <stdio.h>
#include <malloc.h>

#include "config.h"
#include "common.h"
#include "instruments.h"
#include "playmidi.h"
#include "output.h"
#include "controls.h"
#include "tables.h"
#include "resample.h"

#ifdef LOOKUP_HACK
# ifdef LINEAR_INTERPOLATION
    /* Addition, division, interpolation. Resamplation. */
#   ifdef LOOKUP_INTERPOLATION
#     define RESAMPLATION \
	v1=src[ofs>>FRACTION_BITS];\
	v2=src[(ofs>>FRACTION_BITS)+1];\
	*dest++ = v1 + (iplookup[(((v2-v1)<<5) & 0x03FE0) | \
	     ((ofs & FRACTION_MASK) >> (FRACTION_BITS-5))]);
#   else
#     define RESAMPLATION \
	v1=src[ofs>>FRACTION_BITS];\
	v2=src[(ofs>>FRACTION_BITS)+1];\
        *dest++ = v1 + (((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
#   endif
# else
#   define RESAMPLATION \
	*dest++=src[ofs>>FRACTION_BITS];
        /* Earplugs recommended for maximum listening enjoyment */
# endif
#else
# ifdef LINEAR_INTERPOLATION
#   define RESAMPLATION \
	v1=src[ofs>>FRACTION_BITS];\
	v2=src[(ofs>>FRACTION_BITS)+1];\
	*dest++ = v1 + (((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
# else
#   define RESAMPLATION \
	*dest++=src[ofs>>FRACTION_BITS]; /* Sounds terrible */
# endif
#endif

static sample_t resample_buffer[AUDIO_BUFFER_SIZE];

/*************** resampling with fixed increment *****************/

static sample_t *rs_plain(int v, int32 *countptr)
{
#ifdef LINEAR_INTERPOLATION
  sample_t v1, v2;
#endif
  int32 ofs, incr, le;
  int32 count;
  sample_t *dest,*src;
  Voice *vp=&voice[v];

  count=*countptr;
  src=vp->sample->data;
  ofs=vp->sample_offset;
  dest=resample_buffer;
  incr=vp->sample_increment;

  /* Play sample until end, then free the voice. */
  
  le=vp->sample->loop_end-(1<<FRACTION_BITS);
/* 
   Still not sure which one should be used.
   Using data_length causes clicks with some patches (fretnoyz.pat).
   le=vp->sample->data_length-(1<<FRACTION_BITS); */

  while (count--)
    {
      RESAMPLATION;
      ofs += incr;
      if (ofs >= le)
	{
	  if ((ofs & FRACTION_MASK)==0)
	    {
	      *dest++ = src[ofs>>FRACTION_BITS];
	    }
	  else
	    {
	      RESAMPLATION;
	    }
	  vp->status=VOICE_FREE;
 	  ctl->note(v);
	  *countptr-=count+1;
	  break;
	}
    }
  vp->sample_offset=ofs; /* Update offset */
  return resample_buffer;
}

static sample_t *rs_loop(Voice *vp, int32 count)
{
#ifdef LINEAR_INTERPOLATION
  sample_t v1, v2;
#endif
  int32 ofs, incr, le, ll;
  sample_t *dest,*src;

  src=vp->sample->data;
  ofs=vp->sample_offset;
  dest=resample_buffer;
  incr=vp->sample_increment;

  /* Play sample until end-of-loop, skip back and continue. */
  
  le=vp->sample->loop_end;
  ll=le - vp->sample->loop_start;

  while (count--)
    {
      RESAMPLATION;
      ofs += incr;
      if (ofs>=le)
	ofs -= ll; /* Hopefully the loop is longer than an increment. */
    }
  vp->sample_offset=ofs; /* Update offset */
  return resample_buffer;
}

static sample_t *rs_bidir(Voice *vp, int32 count)
{
#ifdef LINEAR_INTERPOLATION
  sample_t v1, v2;
#endif
  int32 ofs, incr, le, ls;
  sample_t *dest,*src;

  src=vp->sample->data;
  ofs=vp->sample_offset;
  dest=resample_buffer;
  incr=vp->sample_increment;

  ls=vp->sample->loop_start;
  le=vp->sample->loop_end;

  /* Play normally until inside the loop region */

  if (ofs < ls)
    {
      while (count--)
	{
	  RESAMPLATION;
	  ofs += incr;
	  if (ofs>=ls)
	    break;
	}
    }

  /* Then do the bidirectional looping */

  if (count>0)
    while (count--)
      {
	RESAMPLATION;
	ofs += incr;
	if (ofs>=le)
	  {
	    /* fold the overshoot back in */
	    ofs = le - (ofs - le);
	    incr = -incr;
	  }
	else if (ofs <= ls)
	  {
	    ofs = ls + (ls - ofs);
	    incr = -incr;
	  }
      }
  vp->sample_increment=incr;
  vp->sample_offset=ofs; /* Update offset */
  return resample_buffer;
}

/*********************** vibrato versions ***************************/

/* We only need to compute one half of the vibrato sine cycle */
static int vib_phase_to_inc_ptr(int phase)
{
  if (phase < VIBRATO_SAMPLE_INCREMENTS/2)
    return VIBRATO_SAMPLE_INCREMENTS/2-1-phase;
  else if (phase >= 3*VIBRATO_SAMPLE_INCREMENTS/2)
    return 5*VIBRATO_SAMPLE_INCREMENTS/2-1-phase;
  else
    return phase-VIBRATO_SAMPLE_INCREMENTS/2;
}

static int32 update_vibrato(Voice *vp, int sign)
{
  int32 depth;
  int phase, pb;
  double a;

  if (vp->vibrato_phase++ >= 2*VIBRATO_SAMPLE_INCREMENTS-1)
    vp->vibrato_phase=0;
  phase=vib_phase_to_inc_ptr(vp->vibrato_phase);
  
  if (vp->vibrato_sample_increment[phase])
    {
      if (sign)
	return -vp->vibrato_sample_increment[phase];
      else
	return vp->vibrato_sample_increment[phase];
    }

  /* Need to compute this sample increment. */
    
  depth=vp->sample->vibrato_depth<<7;

  if (vp->vibrato_sweep)
    {
      /* Need to update sweep */
      vp->vibrato_sweep_position += vp->vibrato_sweep;
      if (vp->vibrato_sweep_position >= (1<<SWEEP_SHIFT))
	vp->vibrato_sweep=0;
      else
	{
	  /* Adjust depth */
	  depth *= vp->vibrato_sweep_position;
	  depth >>= SWEEP_SHIFT;
	}
    }
  
  a = ((double)(1<<FRACTION_BITS) * 
       ((double)(vp->sample->sample_rate) *
	(double)(vp->frequency)) /
       ((double)(vp->sample->root_freq) *
	(double)(play_mode->rate)));
 
  pb=(int)((sine(vp->vibrato_phase * 
		 (SINE_CYCLE_LENGTH/(2*VIBRATO_SAMPLE_INCREMENTS)))
	    * (double)(depth) * VIBRATO_AMPLITUDE_TUNING));

  if (pb<0)
    {
      pb=-pb;
      a /= bend_fine[(pb>>5) & 0xFF] * bend_coarse[pb>>13];
    }
  else
    a *= bend_fine[(pb>>5) & 0xFF] * bend_coarse[pb>>13];
  
  /* If the sweep's over, we can store the newly computed sample_increment */
  if (!vp->vibrato_sweep)
    vp->vibrato_sample_increment[phase]=(int32) a;

  if (sign)
    a = -a; /* need to preserve the loop direction */

  return (int32) a;
}

static sample_t *rs_vib_plain(int v, int32 *countptr)
{
#ifdef LINEAR_INTERPOLATION
  sample_t v1, v2;
#endif
  int32 ofs, incr, le;
  int32 count;
  sample_t *dest,*src;
  Voice *vp=&voice[v];
  int cc;

  count=*countptr;
  src=vp->sample->data;
  ofs=vp->sample_offset;
  dest=resample_buffer;
  incr=vp->sample_increment;
  cc=vp->vibrato_control_counter;

  /* Play sample until end, then free the voice. */
  
  le=vp->sample->loop_end-(1<<FRACTION_BITS);
/*  le=vp->sample->data_length-(1<<FRACTION_BITS); */
  
  while (count--)
    {
      if (!cc--)
	{
	  cc=vp->vibrato_control_ratio;
	  incr=update_vibrato(vp, 0);
	}
      RESAMPLATION;
      ofs += incr;
      if (ofs >= le)
	{
	  if ((ofs & FRACTION_MASK)==0)
	    {
	      *dest++ = src[ofs>>FRACTION_BITS];
	    }
	  else
	    {
	      RESAMPLATION;
	    }
	  vp->status=VOICE_FREE;
 	  ctl->note(v);
	  *countptr-=count+1;
	  break;
	}
    }
  vp->vibrato_control_counter=cc;
  vp->sample_increment=incr;
  vp->sample_offset=ofs; /* Update offset */
  return resample_buffer;
}

static sample_t *rs_vib_loop(Voice *vp, int32 count)
{
#ifdef LINEAR_INTERPOLATION
  sample_t v1, v2;
#endif
  int32 ofs, incr, le, ll;
  sample_t *dest,*src;
  int cc;

  src=vp->sample->data;
  ofs=vp->sample_offset;
  dest=resample_buffer;
  incr=vp->sample_increment;
  cc=vp->vibrato_control_counter;

  /* Play sample until end-of-loop, skip back and continue. */
  
  le=vp->sample->loop_end;
  ll=le - vp->sample->loop_start;

  while (count--)
    {
      if (!cc--)
	{
	  cc=vp->vibrato_control_ratio;
	  incr=update_vibrato(vp, 0);
	}
      RESAMPLATION;
      ofs += incr;
      if (ofs>=le)
	ofs -= ll; /* Hopefully the loop is longer than an increment. */
    }
  vp->vibrato_control_counter=cc;
  vp->sample_increment=incr;
  vp->sample_offset=ofs; /* Update offset */
  return resample_buffer;
}

static sample_t *rs_vib_bidir(Voice *vp, int32 count)
{
#ifdef LINEAR_INTERPOLATION
  sample_t v1, v2;
#endif
  int32 ofs, incr, le, ls;
  sample_t *dest,*src;
  int cc;

  src=vp->sample->data;
  ofs=vp->sample_offset;
  dest=resample_buffer;
  incr=vp->sample_increment;
  cc=vp->vibrato_control_counter;

  ls=vp->sample->loop_start;
  le=vp->sample->loop_end;

  /* Play normally until inside the loop region */

  if (ofs < ls)
    {
      while (count--)
	{
	  if (!cc--)
	    {
	      cc=vp->vibrato_control_ratio;
	      incr=update_vibrato(vp, 0);
	    }
	  RESAMPLATION;
	  ofs += incr;
	  if (ofs>=ls)
	    break;
	}
    }

  /* Then do the bidirectional looping */

  if (count>0)
    while (count--)
      {
	if (!cc--)
	  {
	    cc=vp->vibrato_control_ratio;
	    incr=update_vibrato(vp, (incr < 0));
	  }
	RESAMPLATION;
	ofs += incr;
	if (ofs>=le)
	  {
	    /* fold the overshoot back in */
	    ofs = le - (ofs - le);
	    incr = -incr;
	  }
	else if (ofs <= ls)
	  {
	    ofs = ls + (ls - ofs);
	    incr = -incr;
	  }
      }
  vp->vibrato_control_counter=cc;
  vp->sample_increment=incr;
  vp->sample_offset=ofs; /* Update offset */
  return resample_buffer;
}

static sample_t *resample_voice(int v, int32 *countptr)
{
  int32 ofs;
  uint8 modes;
  Voice *vp=&voice[v];
  
  if (!(vp->sample->sample_rate))
    {
      /* Pre-resampled data -- just update the offset and check if
         we're out of data. */
      ofs=vp->sample_offset >> FRACTION_BITS; /* Kind of silly to use
						 FRACTION_BITS here... */
      if (*countptr >= (vp->sample->loop_end>>FRACTION_BITS) - ofs)
	{
	  /* Note finished. Free the voice. */
	  vp->status = VOICE_FREE;
	  ctl->note(v);
	  
	  /* Let the caller know how much data we had left */
	  *countptr = (vp->sample->loop_end>>FRACTION_BITS) - ofs;
	}
      else
	vp->sample_offset += *countptr << FRACTION_BITS;
      
      return vp->sample->data+ofs;
    }

  /* Need to resample. Use the proper function. */
  modes=vp->sample->modes;

  if (vp->vibrato_control_ratio)
    {
      if (modes & MODES_LOOPING)
	{
	  if (modes & MODES_PINGPONG)
	    return rs_vib_bidir(vp, *countptr);
	  else
	    return rs_vib_loop(vp, *countptr);
	}
      else
	return rs_vib_plain(v, countptr);
    }
  else
    {
      if (modes & MODES_LOOPING)
	{
	  if (modes & MODES_PINGPONG)
	    return rs_bidir(vp, *countptr);
	  else
	    return rs_loop(vp, *countptr);
	}
      else
	return rs_plain(v, countptr);
    }
}

/********************* mixing functions ***********************/

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

  stage = voice[v].envelope_stage;

  if (stage>5)
    {
      /* Envelope ran out. */
      int tmp=(voice[v].status == VOICE_DIE); /* Already displayed as dead */
      voice[v].status = VOICE_FREE;
      if(!tmp)
	ctl->note(v);
      return 1;
    }

  if (voice[v].sample->modes & MODES_ENVELOPE)
    {
      if (voice[v].status==VOICE_ON || voice[v].status==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 (voice[v].envelope_volume==voice[v].sample->envelope_offset[stage])
    return recompute_envelope(v);
  voice[v].envelope_target=voice[v].sample->envelope_offset[stage];
  voice[v].envelope_increment = voice[v].sample->envelope_rate[stage];
  if (voice[v].envelope_target<voice[v].envelope_volume)
    voice[v].envelope_increment = -voice[v].envelope_increment;
  return 0;
}

void apply_envelope_to_amp(int v)
{
  float lamp=voice[v].left_amp, ramp;
  int32 la,ra;
  if (voice[v].panned == PANNED_MYSTERY)
    {
      ramp=voice[v].right_amp;
      if (voice[v].tremolo_phase_increment)
	{
	  lamp *= voice[v].tremolo_volume;
	  ramp *= voice[v].tremolo_volume;
	}
      if (voice[v].sample->modes & MODES_ENVELOPE)
	{
	  lamp *= vol_table[voice[v].envelope_volume>>23];
	  ramp *= vol_table[voice[v].envelope_volume>>23];
	}

      la=lamp * (double)(1<<AMP_BITS); /* TODO: use fscale */
      if (la>MAX_AMP_VALUE)
	la=MAX_AMP_VALUE;

      ra=ramp * (double)(1<<AMP_BITS); /* TODO: use fscale */
      if (ra>MAX_AMP_VALUE)
	ra=MAX_AMP_VALUE;

#ifdef LOOKUP_HACK
      voice[v].left_mix=~_l2u[la];
      voice[v].right_mix=~_l2u[ra];
#else
      voice[v].left_mix=la;
      voice[v].right_mix=ra;
#endif
    }
  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=lamp * (double)(1<<AMP_BITS); /* TODO: use fscale */
      if (la>MAX_AMP_VALUE)
	la=MAX_AMP_VALUE;

#ifdef LOOKUP_HACK
      voice[v].left_mix=~_l2u[la];
#else
      voice[v].left_mix=la;
#endif
    }
}

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

static void update_tremolo(int v)
{
  int32 depth=voice[v].sample->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 -
    ((sine(voice[v].tremolo_phase>>RATE_SHIFT)+1.0)*(double)(depth)) *
      (TREMOLO_AMPLITUDE_TUNING/(double)(1<<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);

  apply_envelope_to_amp(v);
  return 0;
}

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

static void mix_data(sample_t *sp, int32 *lp, int v, int count)
{
#ifdef LOOKUP_HACK
  uint8 left,right;
#else
  int32 left,right;
#endif
  int cc;
  sample_t s=0; /* silly warning about uninitialized s */

  left=voice[v].left_mix;
  if (!(play_mode->encoding & PE_MONO))
    {
      right=voice[v].right_mix;
      if (voice[v].panned==PANNED_MYSTERY)
	{
	  if (voice[v].envelope_increment||voice[v].tremolo_phase_increment)
	    {
	      cc=voice[v].control_counter;
	      while (count--)
		{
		  if (!cc--)
		    {
		      cc=control_ratio;
		      if (update_signal(v))
			return; /* Envelope ran out */
		      left=voice[v].left_mix;
		      right=voice[v].right_mix;
		    }
		  s=*sp++;
		  MIXATION(left);
		  MIXATION(right);
		}
	      voice[v].control_counter=cc;
	    }
	  else /* No envelope! This is too easy... */
	    {
	      while (count--)
		{
		  s=*sp++;
		  MIXATION(left);
		  MIXATION(right);
		}	  
	    }
	}
      else if (voice[v].panned==PANNED_CENTER)
	{
	  if (voice[v].envelope_increment||voice[v].tremolo_phase_increment)
	    {
	      cc=voice[v].control_counter;
	      while (count--)
		{
		  if (!cc--)
		    {
		      cc=control_ratio;
		      if (update_signal(v))
			return; /* Envelope ran out */
		      left=voice[v].left_mix;
		    }
		  s=*sp++;
		  MIXATION(left);
		  MIXATION(left);
		}
	      voice[v].control_counter=cc;
	    }
	  else /* No envelope! This is too easy... */
	    {
	      while (count--)
		{
		  s=*sp++;
		  MIXATION(left);
		  MIXATION(left);
		}	  
	    }
	}
      else if (voice[v].panned==PANNED_LEFT)
	{
	  if (voice[v].envelope_increment||voice[v].tremolo_phase_increment)
	    {
	      cc=voice[v].control_counter;
	      while (count--)
		{
		  if (!cc--)
		    {
		      cc=control_ratio;
		      if (update_signal(v))
			return; /* Envelope ran out */
		      left=voice[v].left_mix;
		    }
		  s=*sp++;
		  MIXATION(left);
		  lp++;
		}
	      voice[v].control_counter=cc;
	    }
	  else /* No envelope! This is too easy... */
	    {
	      while (count--)
		{
		  s=*sp++;
		  MIXATION(left);
		  lp++;
		}	  
	    }
	}
      else if (voice[v].panned==PANNED_RIGHT)
	{
	  if (voice[v].envelope_increment||voice[v].tremolo_phase_increment)
	    {
	      cc=voice[v].control_counter;
	      while (count--)
		{
		  if (!cc--)
		    {
		      cc=control_ratio;
		      if (update_signal(v))
			return; /* Envelope ran out */
		      left=voice[v].left_mix;
		    }
		  s=*sp++;
		  lp++;
		  MIXATION(left);
		}
	      voice[v].control_counter=cc;
	    }
	  else /* No envelope! This is too easy... */
	    {
	      while (count--)
		{
		  s=*sp++;
		  lp++;
		  MIXATION(left);
		}	  
	    }
	}
    }
  else
    {
      /* Mono output. */
      if (voice[v].envelope_increment||voice[v].tremolo_phase_increment)
	{
	  cc=voice[v].control_counter;
	  while (count--)
	    {
	      if (!cc--)
		{
		  cc=control_ratio;
		  if (update_signal(v))
		    return; /* Envelope ran out */
		  left=voice[v].left_mix;
		}
	      s=*sp++;
	      MIXATION(left);
	    }
	  voice[v].control_counter=cc;
	}
      else /* No envelope! This is too easy... */
	{
	  while (count--)
	    {
	      s=*sp++;
	      MIXATION(left);
	    }	  
	}
    }
}

/* Ramp a note out in c samples */
static void ramp_out(sample_t *sp, int32 *lp, int v, int32 c)
{
#ifdef LOOP_HACK
  int8 left, right, li, ri;
#else
  int32 left, right, li, ri;
#endif
  sample_t s=0; /* silly warning about uninitialized s */

  left=voice[v].left_mix;
  li=-(left/c);
  if (!li) li=-1;

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

  if (!(play_mode->encoding & PE_MONO))
    {
      if (voice[v].panned==PANNED_MYSTERY)
	{
	  right=voice[v].right_mix;
	  ri=-(right/c);
	  while (c--)
	    {
	      left += li;
	      if (left<0)
		left=0;
	      right += ri;
	      if (right<0)
		right=0;
	      s=*sp++;
	      MIXATION(left);
	      MIXATION(right);
	    }
	}
      else if (voice[v].panned==PANNED_CENTER)
	{
	  while (c--)
	    {
	      left += li;
	      if (left<0)
		return;
	      s=*sp++;	
	      MIXATION(left);
	      MIXATION(left);
	    }
	}
      else if (voice[v].panned==PANNED_LEFT)
	{
	  while (c--)
	    {
	      left += li;
	      if (left<0)
		return;
	      s=*sp++;
	      MIXATION(left);
	      lp++;
	    }
	}
      else if (voice[v].panned==PANNED_RIGHT)
	{
	  while (c--)
	    {
	      left += li;
	      if (left<0)
		return;
	      s=*sp++;
	      lp++;
	      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, int32 c)
{
  sample_t *sp;
  if (voice[v].status==VOICE_DIE)
    {
      if (c>=MAX_DIE_TIME)
	c=MAX_DIE_TIME;
      sp=resample_voice(v, &c);
      ramp_out(sp, buf, v, c);
      voice[v].status=VOICE_FREE;
    }
  else
    {
      sp=resample_voice(v, &c);
      mix_data(sp, buf, v, c);
    }
}

#ifdef LOOKUP_HACK
  /* We'll always use 16-bit interpolation in pre-resampling */
# undef RESAMPLATION
# define RESAMPLATION \
	v1=src[ofs>>FRACTION_BITS];\
	v2=src[(ofs>>FRACTION_BITS)+1];\
	*dest++ = v1 + (((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
#endif

void pre_resample(Sample *sp)
{
  double a;
  int32 incr, ofs, newlen, count;
  int16 *newdata, *dest, *src;
  int16 v1, v2;

  ctl->cmsg(CMSG_INFO, VERB_NOISY, " * pre-resampling for note %d", 
	    sp->note_to_use);
  a = 
    ((double)(sp->sample_rate) * (double)(freq_table[(int)(sp->note_to_use)]))
      / 
    ((double)(sp->root_freq) * (double)(play_mode->rate))
      ;

  newlen=(int32)((double)(sp->data_length) / a);
  newdata=safe_malloc(2*(newlen>>FRACTION_BITS));

  src=(int16 *)sp->data;
  dest=newdata;
  count=newlen>>FRACTION_BITS;
  ofs=0;
  incr = (sp->data_length-(1<<FRACTION_BITS))/count;

  while (--count)
    {
      RESAMPLATION;
      ofs += incr;
    }
  if ((ofs & FRACTION_MASK)==0)
    {
      *dest++ = src[ofs>>FRACTION_BITS];
    }
  else
    {
      RESAMPLATION;
    }
  sp->data_length=newlen;
  sp->loop_start=(int32)((double)(sp->loop_start) / a);
  sp->loop_end=(int32)((double)(sp->loop_end) / a);
  free(sp->data);
  sp->data=(sample_t *)newdata;
  sp->sample_rate=0;
}
