/*
	$Id:$

    TiMidity++ -- MIDI to WAVE converter and player
    Copyright (C) 1999 Masanao Izumo <mo@goice.co.jp>
    Copyright (C) 1995 Tuukka Toivonen <tt@cgs.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.

*/

#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"


#define LINEAR_INTERPOLATION
#define LAGRANGE_INTERPOLATION
#define ENVELOPE_PITCH_MODULATION


#ifdef LOOKUP_HACK
#define MAX_DATAVAL 127
#define MIN_DATAVAL -128
#else
#define MAX_DATAVAL 32767
#define MIN_DATAVAL -32768
#endif

#define OVERSHOOT_STEP 50


static resample_t *vib_resample_voice(int, uint32 *, int);
static resample_t *normal_resample_voice(int, uint32 *, int);

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

static resample_t *rs_plain(int v, uint32 *countptr)
{
  /* Play sample until end, then free the voice. */
  Voice
    *vp=&voice[v];
   int32   ofsd, v0, v1, v2, v3, overshoot;
   int32 offset;
  uint32 cc_count=vp->modulation_counter;
  resample_t
    *dest=resample_buffer+resample_buffer_offset;
#ifdef SL32
  samplel_t
    *src=vp->sample->ldata;
#else
  sample_t
    *src=vp->sample->data;
#endif
  int32
    incr=vp->sample_increment;
  splen_t
    ofs=vp->sample_offset;
#if defined(LAGRANGE_INTERPOLATION) || defined(CSPLINE_INTERPOLATION)
  splen_t
    ls=0,
    le=vp->sample->data_length;
#endif /* LAGRANGE_INTERPOLATION */
  splen_t
    se=vp->sample->data_length;
  uint32
    count=*countptr;

  if (!incr) return resample_buffer+resample_buffer_offset; /* --gl */

  overshoot = src[(se>>FRACTION_BITS)-1] / OVERSHOOT_STEP;
  if (overshoot < 0) overshoot = -overshoot;

    while (count--)
    {

	offset = ofs >> FRACTION_BITS;

	if (ofs >= se) {
		int32 delta = (ofs - se)>>FRACTION_BITS ;
        	v1 = (int32)src[(int32)(se>>FRACTION_BITS)-1];
		if (overshoot) v1 -=  (delta+1) * v1 / overshoot;
        }
	else  v1 = (int32)src[offset];

	if (ofs + (1L<<FRACTION_BITS) >= se) {
		v2 = v1;
        }
	else  v2 = (int32)src[offset+1];

	if ( (vp->algorithm & INTERPOLATION_LINEAR) || dont_cspline ||
	   ( (ofs-(1L<<FRACTION_BITS)) < ls) ||
	     ((ofs+(2L<<FRACTION_BITS)) > le) ) {
                *dest++ = (resample_t)(v1 + ((int32)((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS));
	}
	else {
                v0 = (int32)src[offset-1];
                v3 = (int32)src[offset+2];
                ofsd = (int32)(ofs & FRACTION_MASK) + (1L << FRACTION_BITS);
                v1 = v1*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v1 = v1*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd;
                ofsd -= (1L << FRACTION_BITS);
                v0 = (v3 - v0*ofsd)/(6L << FRACTION_BITS);
                v1 = (v1 - v2)*ofsd>>(FRACTION_BITS+1);
		v1 += v0;
		*dest++ = (resample_t)v1;
	}

		if (!cc_count--) {
		    cc_count = control_ratio - 1;
		    if (!update_modulation_signal(vp))
		        incr = calc_mod_freq(vp, incr);
		}
      ofs += incr;
      if (ofs >= se + (overshoot << FRACTION_BITS))
	{
	  if (!(vp->status&VOICE_FREE))
	    {
	      vp->status=VOICE_FREE;
 	      ctl->note(v);
	    }
	  *countptr-=count+1;
	  break;
	}
    }

  vp->sample_offset=ofs; /* Update offset */
  vp->modulation_counter=cc_count;
  return resample_buffer+resample_buffer_offset;
}

static resample_t *rs_loop(int v, Voice *vp, uint32 *countptr)
{
  /* Play sample until end-of-loop, skip back and continue. */
   int32   ofsd, v0, v1, v2, v3, overshoot;
   int32 offset;
  uint32 cc_count=vp->modulation_counter;
  int32
    incr=vp->sample_increment;
  splen_t
    ofs=vp->sample_offset,
    le=vp->loop_end,
#if defined(LAGRANGE_INTERPOLATION) || defined(CSPLINE_INTERPOLATION)
    ls=vp->loop_start,
#endif /* LAGRANGE_INTERPOLATION */
    ll=le - vp->loop_start;
  resample_t
    *dest=resample_buffer+resample_buffer_offset;
#ifdef SL32
  samplel_t
    *src=vp->sample->ldata;
#else
  sample_t
    *src=vp->sample->data;
#endif
  splen_t
    se=vp->sample->data_length;
  uint32
    count = *countptr;
  int
    flag_exit_loop;


  flag_exit_loop =
	(vp->status & (VOICE_FREE | VOICE_DIE)) ||
	((vp->status & VOICE_OFF) && (vp->sample->modes & MODES_FAST_RELEASE) ) ||
	((vp->status & VOICE_OFF) && dont_keep_looping ) ;

  overshoot = src[(se>>FRACTION_BITS)-1] / OVERSHOOT_STEP;
  if (overshoot < 0) overshoot = -overshoot;

  while (count--)
    {

	offset = ofs >> FRACTION_BITS;

	if (ofs >= se) {
		int32 delta = (ofs - se)>>FRACTION_BITS ;
        	v1 = (int32)src[(int32)(se>>FRACTION_BITS)-1];
		if (overshoot) v1 -=  (delta+1) * v1 / overshoot;
        }
	else  v1 = (int32)src[offset];

	if (ofs + (1L<<FRACTION_BITS) >= se) {
		v2 = v1;
        }
	else  v2 = (int32)src[offset+1];

	if ( (vp->algorithm & INTERPOLATION_LINEAR) || dont_cspline ||
	   ( (ofs-(1L<<FRACTION_BITS)) < ls) ||
	     ((ofs+(2L<<FRACTION_BITS)) > le) ) {
                *dest++ = (resample_t)(v1 + ((int32)((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS));
	}
	else {
                v0 = (int32)src[offset-1];
                v3 = (int32)src[offset+2];
                ofsd = (int32)(ofs & FRACTION_MASK) + (1L << FRACTION_BITS);
                v1 = v1*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v1 = v1*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd;
                ofsd -= (1L << FRACTION_BITS);
                v0 = (v3 - v0*ofsd)/(6L << FRACTION_BITS);
                v1 = (v1 - v2)*ofsd>>(FRACTION_BITS+1);
		v1 += v0;
		*dest++ = (resample_t)v1;
	}

		if (!cc_count--) {
		    cc_count = control_ratio - 1;
		    if (!update_modulation_signal(vp))
		        incr = calc_mod_freq(vp, incr);
		}
      ofs += incr;
      if (ofs>=le)
	{
	  if (flag_exit_loop)
	    {
	    	vp->reverb_time -= ll >> FRACTION_BITS;
	  	if (vp->reverb_time >= 0) ofs -= ll;
	    }
	  else ofs -= ll; /* Hopefully the loop is longer than an increment. */
	}
      if (ofs >= se + (overshoot << FRACTION_BITS))
	{
	  if (!(vp->status&VOICE_FREE))
	    {
	      vp->status=VOICE_FREE;
 	      ctl->note(v);
	    }
	  *countptr-=count+1;
	  break;
	}
    }

  vp->sample_offset=ofs; /* Update offset */
  vp->modulation_counter=cc_count;
  return resample_buffer+resample_buffer_offset;
}

static resample_t *rs_bidir(Voice *vp, uint32 count)
{
   int32   ofsd, v0, v1, v2, v3, overshoot;
   int32 offset;
  int32
    incr=vp->sample_increment;
  splen_t
    le=vp->loop_end,
    ls=vp->loop_start,
    ofs=vp->sample_offset,
    se=vp->sample->data_length;
  resample_t
    *dest=resample_buffer+resample_buffer_offset;
#ifdef SL32
  samplel_t
    *src=vp->sample->ldata;
#else
  sample_t
    *src=vp->sample->data;
#endif


#ifdef USE_BIDIR_OVERSHOOT
  int32
    le2 = le<<1,
    ls2 = ls<<1;
#endif
  uint32
    i, j;
  /* Play normally until inside the loop region */

  overshoot = src[(se>>FRACTION_BITS)-1] / OVERSHOOT_STEP;
  if (overshoot < 0) overshoot = -overshoot;

  if (ofs <= ls)
    {
      /* NOTE: Assumes that incr > 0, which is NOT always the case
	 when doing bidirectional looping.  I have yet to see a case
	 where both ofs <= ls AND incr < 0, however. */
      if (incr < 0) i = ls - ofs;
	else
      i = (ls - ofs) / incr + 1;
      if (i > count)
	{
	  i = count;
	  count = 0;
	}
      else count -= i;
      for(j = 0; j < i; j++)
	{

	offset = ofs >> FRACTION_BITS;

	if (ofs >= se) {
		int32 delta = (ofs - se)>>FRACTION_BITS ;
        	v1 = (int32)src[(int32)(se>>FRACTION_BITS)-1];
		if (overshoot) v1 -=  (delta+1) * v1 / overshoot;
        }
	else  v1 = (int32)src[offset];

	if (ofs + (1L<<FRACTION_BITS) >= se) {
		v2 = v1;
        }
	else  v2 = (int32)src[offset+1];

	if ( (vp->algorithm & INTERPOLATION_LINEAR) || dont_cspline ||
	   ( (ofs-(1L<<FRACTION_BITS)) < ls) ||
	     ((ofs+(2L<<FRACTION_BITS)) > le) ) {
                *dest++ = (resample_t)(v1 + ((int32)((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS));
	}
	else {
                v0 = (int32)src[offset-1];
                v3 = (int32)src[offset+2];
                ofsd = (int32)(ofs & FRACTION_MASK) + (1L << FRACTION_BITS);
                v1 = v1*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v1 = v1*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd;
                ofsd -= (1L << FRACTION_BITS);
                v0 = (v3 - v0*ofsd)/(6L << FRACTION_BITS);
                v1 = (v1 - v2)*ofsd>>(FRACTION_BITS+1);
		v1 += v0;
		*dest++ = (resample_t)v1;
	}

	  ofs += incr;
	}
    }

  /* Then do the bidirectional looping */

  while(count)
    {
      /* Precalc how many times we should go through the loop */
#if 1
      i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
#else
/* fix from M. Izumo */
      i = ((incr > 0 ? le : ls) - ofs + incr - 1) / incr;
#endif
      if (i > count)
	{
	  i = count;
	  count = 0;
	}
      else count -= i;
      for(j = 0; j < i && ofs < se; j++)
	{

	offset = ofs >> FRACTION_BITS;

	if (ofs >= se) {
		int32 delta = (ofs - se)>>FRACTION_BITS ;
        	v1 = (int32)src[(int32)(se>>FRACTION_BITS)-1];
		if (overshoot) v1 -=  (delta+1) * v1 / overshoot;
        }
	else  v1 = (int32)src[offset];

	if (ofs + (1L<<FRACTION_BITS) >= se) {
		v2 = v1;
        }
	else  v2 = (int32)src[offset+1];

	if ( (vp->algorithm & INTERPOLATION_LINEAR) || dont_cspline ||
	   ( (ofs-(1L<<FRACTION_BITS)) < ls) ||
	     ((ofs+(2L<<FRACTION_BITS)) > le) ) {
                *dest++ = (resample_t)(v1 + ((int32)((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS));
	}
	else {
                v0 = (int32)src[offset-1];
                v3 = (int32)src[offset+2];
                ofsd = (int32)(ofs & FRACTION_MASK) + (1L << FRACTION_BITS);
                v1 = v1*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v1 = v1*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd;
                ofsd -= (1L << FRACTION_BITS);
                v0 = (v3 - v0*ofsd)/(6L << FRACTION_BITS);
                v1 = (v1 - v2)*ofsd>>(FRACTION_BITS+1);
		v1 += v0;
		*dest++ = (resample_t)v1;
	}

	  ofs += incr;
	}
#ifdef USE_BIDIR_OVERSHOOT
      if (ofs>=le)
	{
	  /* fold the overshoot back in */
	  ofs = le2 - ofs;
	  incr *= -1;
	}
      else if (ofs <= ls)
	{
	  ofs = ls2 - ofs;
	  incr *= -1;
	}
#else
	  incr *= -1;
#endif
    }

  vp->sample_increment=incr;
  vp->sample_offset=ofs; /* Update offset */
  return resample_buffer+resample_buffer_offset;
}

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

/* We only need to compute one half of the vibrato sine cycle */
static uint32 vib_phase_to_inc_ptr(uint32 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)
{
  uint32 depth, freq=vp->frequency;
#ifdef ENVELOPE_PITCH_MODULATION
  FLOAT_T mod_amount=vp->modEnvToPitch;
#endif
  uint32 phase;
  int pb;
  double a;

  if(vp->vibrato_delay > 0)
  {
      vp->vibrato_delay -= vp->vibrato_control_ratio;
      if(vp->vibrato_delay > 0)
	  return vp->sample_increment;
  }

  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->vibrato_depth;
  if(depth < vp->modulation_wheel)
      depth = vp->modulation_wheel;
  depth <<= 7;

  if (vp->vibrato_sweep && !vp->modulation_wheel)
    {
      /* 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;
	}
    }

#ifdef ENVELOPE_PITCH_MODULATION
#ifndef FILTER_INTERPOLATION
  if (update_modulation_signal(vp)) mod_amount = 0;
  else
#endif
  if (mod_amount>0.5)
   freq = (int32)( (double)freq*(1.0 + (mod_amount - 1.0) * (vp->modulation_volume>>22) / 255.0) );
#endif

  pb=(int)((sine(vp->vibrato_phase *
			(SINE_CYCLE_LENGTH/(2*VIBRATO_SAMPLE_INCREMENTS)))
	    * (double)(depth) * VIBRATO_AMPLITUDE_TUNING));

  a = FRSCALE(((double)(vp->sample->sample_rate) *
		  (double)(freq)) /
		 ((double)(vp->sample->root_freq) *
		  (double)(play_mode->rate)),
		 FRACTION_BITS);
  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];
  a += 0.5;

  /* If the sweep's over, we can store the newly computed sample_increment */
  if (!vp->vibrato_sweep || vp->modulation_wheel)
    vp->vibrato_sample_increment[phase]=(int32) a;

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

  return (int32) a;
}

static resample_t *rs_vib_plain(int v, uint32 *countptr)
{

  /* Play sample until end, then free the voice. */

  Voice *vp=&voice[v];
   int32   ofsd, v0, v1, v2, v3, overshoot;
   int32 offset;
  resample_t
    *dest=resample_buffer+resample_buffer_offset;
#ifdef SL32
  samplel_t
    *src=vp->sample->ldata;
#else
  sample_t
    *src=vp->sample->data;
#endif
  int32
    incr=vp->sample_increment;
#if defined(LAGRANGE_INTERPOLATION) || defined(CSPLINE_INTERPOLATION)
  splen_t
    ls=0,
    le=vp->sample->data_length;
#endif /* LAGRANGE_INTERPOLATION */
  splen_t
    ofs=vp->sample_offset,
    se=vp->sample->data_length,
    count=*countptr;
  uint32
    cc=vp->vibrato_control_counter;

  /* This has never been tested */

  if (incr<0) incr = -incr; /* In case we're coming out of a bidir loop */

  overshoot = src[(se>>FRACTION_BITS)-1] / OVERSHOOT_STEP;
  if (overshoot < 0) overshoot = -overshoot;
  while (count--)
    {
      if (!cc--)
	{
	  cc=vp->vibrato_control_ratio;
	  incr=update_vibrato(vp, 0);
	}

	offset = ofs >> FRACTION_BITS;

	if (ofs >= se) {
		int32 delta = (ofs - se)>>FRACTION_BITS ;
        	v1 = (int32)src[(int32)(se>>FRACTION_BITS)-1];
		if (overshoot) v1 -=  (delta+1) * v1 / overshoot;
        }
	else  v1 = (int32)src[offset];

	if (ofs + (1L<<FRACTION_BITS) >= se) {
		v2 = v1;
        }
	else  v2 = (int32)src[offset+1];

	if ( (vp->algorithm & INTERPOLATION_LINEAR) || dont_cspline ||
	   ( (ofs-(1L<<FRACTION_BITS)) < ls) ||
	     ((ofs+(2L<<FRACTION_BITS)) > le) ) {
                *dest++ = (resample_t)(v1 + ((int32)((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS));
	}
	else {
                v0 = (int32)src[offset-1];
                v3 = (int32)src[offset+2];
                ofsd = (int32)(ofs & FRACTION_MASK) + (1L << FRACTION_BITS);
                v1 = v1*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v1 = v1*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd;
                ofsd -= (1L << FRACTION_BITS);
                v0 = (v3 - v0*ofsd)/(6L << FRACTION_BITS);
                v1 = (v1 - v2)*ofsd>>(FRACTION_BITS+1);
		v1 += v0;
		*dest++ = (resample_t)v1;
	}

      ofs += incr;
      if (ofs >= se + (overshoot << FRACTION_BITS))
	{
	  if (!(vp->status&VOICE_FREE))
	    {
	      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+resample_buffer_offset;
}

static resample_t *rs_vib_loop(int v, Voice *vp, uint32 *countptr)
{
  /* Play sample until end-of-loop, skip back and continue. */
   int32   ofsd, v0, v1, v2, v3, overshoot;
   int32 offset;
  int32
    incr=vp->sample_increment;
  splen_t
#if defined(LAGRANGE_INTERPOLATION) || defined(CSPLINE_INTERPOLATION)
    ls=vp->loop_start,
#endif /* LAGRANGE_INTERPOLATION */
    le=vp->loop_end,
    ll=le - vp->loop_start;
  resample_t
    *dest=resample_buffer+resample_buffer_offset;
#ifdef SL32
  samplel_t
    *src=vp->sample->ldata;
#else
  sample_t
    *src=vp->sample->data;
#endif
  splen_t
    ofs=vp->sample_offset,
    se=vp->sample->data_length,
    count = *countptr;
  uint32
    cc=vp->vibrato_control_counter;
  int
    flag_exit_loop;


  flag_exit_loop =
	(vp->status & (VOICE_FREE | VOICE_DIE)) ||
	((vp->status & VOICE_OFF) && (vp->sample->modes & MODES_FAST_RELEASE) ) ||
	((vp->status & VOICE_OFF) && dont_keep_looping ) ;

  overshoot = src[(se>>FRACTION_BITS)-1] / OVERSHOOT_STEP;
  if (overshoot < 0) overshoot = -overshoot;
  while (count--)
    {
      if (!cc--)
	{
	  cc=vp->vibrato_control_ratio;
	  incr=update_vibrato(vp, 0);
	}

	offset = ofs >> FRACTION_BITS;

	if (ofs >= se) {
		int32 delta = (ofs - se)>>FRACTION_BITS ;
        	v1 = (int32)src[(int32)(se>>FRACTION_BITS)-1];
		if (overshoot) v1 -=  (delta+1) * v1 / overshoot;
        }
	else  v1 = (int32)src[offset];

	if (ofs + (1L<<FRACTION_BITS) >= se) {
		v2 = v1;
        }
	else  v2 = (int32)src[offset+1];

	if ( (vp->algorithm & INTERPOLATION_LINEAR) || dont_cspline ||
	   ( (ofs-(1L<<FRACTION_BITS)) < ls) ||
	     ((ofs+(2L<<FRACTION_BITS)) > le) ) {
                *dest++ = (resample_t)(v1 + ((int32)((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS));
	}
	else {
                v0 = (int32)src[offset-1];
                v3 = (int32)src[offset+2];
                ofsd = (int32)(ofs & FRACTION_MASK) + (1L << FRACTION_BITS);
                v1 = v1*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v1 = v1*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd;
                ofsd -= (1L << FRACTION_BITS);
                v0 = (v3 - v0*ofsd)/(6L << FRACTION_BITS);
                v1 = (v1 - v2)*ofsd>>(FRACTION_BITS+1);
		v1 += v0;
		*dest++ = (resample_t)v1;
	}

      ofs += incr;
      if (ofs>=le)
	{
	  if (flag_exit_loop)
	    {
	    	vp->reverb_time -= ll >> FRACTION_BITS;
	  	if (vp->reverb_time >= 0) ofs -= ll;
	    }
	  else ofs -= ll; /* Hopefully the loop is longer than an increment. */
	}
      if (ofs >= se + (overshoot << FRACTION_BITS))
	{
	  if (!(vp->status&VOICE_FREE))
	    {
	      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+resample_buffer_offset;
}

static resample_t *rs_vib_bidir(Voice *vp, uint32 count)
{
   int32   ofsd, v0, v1, v2, v3, overshoot;
   int32 offset;
  int32
    incr=vp->sample_increment;
  splen_t
    le=vp->loop_end,
    ls=vp->loop_start,
    ofs=vp->sample_offset,
    se=vp->sample->data_length;
  resample_t
    *dest=resample_buffer+resample_buffer_offset;
#ifdef SL32
  samplel_t
    *src=vp->sample->ldata;
#else
  sample_t
    *src=vp->sample->data;
#endif
  uint32
    cc=vp->vibrato_control_counter;


#ifdef USE_BIDIR_OVERSHOOT
  splen_t
    le2=le<<1,
    ls2=ls<<1;
#endif
  uint32
    i, j;
  int
    vibflag = 0;


  overshoot = src[(se>>FRACTION_BITS)-1] / OVERSHOOT_STEP;
  if (overshoot < 0) overshoot = -overshoot;
  /* Play normally until inside the loop region */
  while (count && (ofs <= ls))
    {
      i = (ls - ofs) / incr + 1;
      if (i > count) i = count;
      if (i > cc)
	{
	  i = cc;
	  vibflag = 1;
	}
      else cc -= i;
      count -= i;
      for(j = 0; j < i; j++)
	{

	offset = ofs >> FRACTION_BITS;

	if (ofs >= se) {
		int32 delta = (ofs - se)>>FRACTION_BITS ;
        	v1 = (int32)src[(int32)(se>>FRACTION_BITS)-1];
		if (overshoot) v1 -=  (delta+1) * v1 / overshoot;
        }
	else  v1 = (int32)src[offset];

	if (ofs + (1L<<FRACTION_BITS) >= se) {
		v2 = v1;
        }
	else  v2 = (int32)src[offset+1];

	if ( (vp->algorithm & INTERPOLATION_LINEAR) || dont_cspline ||
	   ( (ofs-(1L<<FRACTION_BITS)) < ls) ||
	     ((ofs+(2L<<FRACTION_BITS)) > le) ) {
                *dest++ = (resample_t)(v1 + ((int32)((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS));
	}
	else {
                v0 = (int32)src[offset-1];
                v3 = (int32)src[offset+2];
                ofsd = (int32)(ofs & FRACTION_MASK) + (1L << FRACTION_BITS);
                v1 = v1*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v1 = v1*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd;
                ofsd -= (1L << FRACTION_BITS);
                v0 = (v3 - v0*ofsd)/(6L << FRACTION_BITS);
                v1 = (v1 - v2)*ofsd>>(FRACTION_BITS+1);
		v1 += v0;
		*dest++ = (resample_t)v1;
	}

	  ofs += incr;
	}
      if (vibflag)
	{
	  cc = vp->vibrato_control_ratio;
	  incr = update_vibrato(vp, 0);
	  vibflag = 0;
	}
    }

  /* Then do the bidirectional looping */

  while (count)
    {
      /* Precalc how many times we should go through the loop */
#if 1
      i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
#else
/* fix from M. Izumo */
      i = ((incr > 0 ? le : ls) - ofs + incr - 1) / incr;
#endif
      if(i > count) i = count;
      if(i > cc)
	{
	  i = cc;
	  vibflag = 1;
	}
      else cc -= i;
      count -= i;
      while (i-- && ofs < se)
	{

	offset = ofs >> FRACTION_BITS;

	if (ofs >= se) {
		int32 delta = (ofs - se)>>FRACTION_BITS ;
        	v1 = (int32)src[(int32)(se>>FRACTION_BITS)-1];
		if (overshoot) v1 -=  (delta+1) * v1 / overshoot;
        }
	else  v1 = (int32)src[offset];

	if (ofs + (1L<<FRACTION_BITS) >= se) {
		v2 = v1;
        }
	else  v2 = (int32)src[offset+1];

	if ( (vp->algorithm & INTERPOLATION_LINEAR) || dont_cspline ||
	   ( (ofs-(1L<<FRACTION_BITS)) < ls) ||
	     ((ofs+(2L<<FRACTION_BITS)) > le) ) {
                *dest++ = (resample_t)(v1 + ((int32)((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS));
	}
	else {
                v0 = (int32)src[offset-1];
                v3 = (int32)src[offset+2];
                ofsd = (int32)(ofs & FRACTION_MASK) + (1L << FRACTION_BITS);
                v1 = v1*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v2 = v2*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd>>FRACTION_BITS;
                ofsd -= (1L << FRACTION_BITS);
                v0 = v0*ofsd>>FRACTION_BITS;
                v1 = v1*ofsd>>FRACTION_BITS;
                v3 = v3*ofsd;
                ofsd -= (1L << FRACTION_BITS);
                v0 = (v3 - v0*ofsd)/(6L << FRACTION_BITS);
                v1 = (v1 - v2)*ofsd>>(FRACTION_BITS+1);
		v1 += v0;
		*dest++ = (resample_t)v1;
	}

	  ofs += incr;
	}
      if (vibflag)
	{
	  cc = vp->vibrato_control_ratio;
	  incr = update_vibrato(vp, (incr < 0));
	  vibflag = 0;
	}
      if (ofs >= le)
	{
#ifdef USE_BIDIR_OVERSHOOT
	  /* fold the overshoot back in */
	  ofs = le2 - ofs;
#endif
	  incr *= -1;
	}
      else if (ofs <= ls)
	{
#ifdef USE_BIDIR_OVERSHOOT
	  ofs = ls2 - ofs;
#endif
	  incr *= -1;
	}
    }


  vp->vibrato_control_counter=cc;
  vp->sample_increment=incr;
  vp->sample_offset=ofs; /* Update offset */
  return resample_buffer+resample_buffer_offset;
}

static int rs_update_porta(int v)
{
    Voice *vp=&voice[v];
    int32 d;

    d = vp->porta_dpb;
    if(vp->porta_pb < 0)
    {
	if(d > -vp->porta_pb)
	    d = -vp->porta_pb;
    }
    else
    {
	if(d > vp->porta_pb)
	    d = -vp->porta_pb;
	else
	    d = -d;
    }

    vp->porta_pb += d;
    if(vp->porta_pb == 0)
    {
	vp->porta_control_ratio = 0;
	vp->porta_pb = 0;
    }
    recompute_freq(v);
    return vp->porta_control_ratio;
}

static resample_t *porta_resample_voice(int v, uint32 *countptr, int mode)
{
    Voice *vp=&voice[v];
    uint32 n = *countptr;
    uint32 i;
    resample_t *(* resampler)(int, uint32 *, int);
    int cc = vp->porta_control_counter;
    int loop;

    if(vp->vibrato_control_ratio)
	resampler = vib_resample_voice;
    else
	resampler = normal_resample_voice;
    if(mode != 1)
	loop = 1;
    else
	loop = 0;

    /* vp->cache = NULL; */
    resample_buffer_offset = 0;
    while(resample_buffer_offset < n)
    {
	if(cc == 0)
	{
	    if((cc = rs_update_porta(v)) == 0)
	    {
		i = n - resample_buffer_offset;
		resampler(v, &i, mode);
		resample_buffer_offset += i;
		break;
	    }
	}

	i = n - resample_buffer_offset;
	if(i > (uint32)cc)
	    i = (uint32)cc;
	resampler(v, &i, mode);
	resample_buffer_offset += i;

	/* if(!loop && vp->status == VOICE_FREE) */
	if(vp->status == VOICE_FREE)
	    break;
	cc -= (int)i;
    }
    *countptr = resample_buffer_offset;
    resample_buffer_offset = 0;
    vp->porta_control_counter = cc;
    return resample_buffer;
}

static resample_t *vib_resample_voice(int v, uint32 *countptr, int mode)
{
    Voice *vp = &voice[v];

    /* vp->cache = NULL; */
    if(mode == 0)
	return rs_vib_loop(v, vp, countptr);
    if(mode == 1)
	return rs_vib_plain(v, countptr);
    return rs_vib_bidir(vp, *countptr);
}

static resample_t *normal_resample_voice(int v, uint32 *countptr, int mode)
{
    Voice *vp = &voice[v];
    if(mode == 0)
	return rs_loop(v, vp, countptr);
    if(mode == 1)
	return rs_plain(v, countptr);
    return rs_bidir(vp, *countptr);
}

resample_t *resample_voice_lagrange(int v, uint32 *countptr)
{
    Voice *vp=&voice[v];
    int mode;

    mode = vp->sample->modes;
    if((mode & MODES_LOOPING) &&
       ((mode & MODES_ENVELOPE) ||
	(vp->status & (VOICE_ON | VOICE_SUSTAINED))))
    {
	if(mode & MODES_PINGPONG)
	{
	    /* vp->cache = NULL; */
	    mode = 2;
	}
	else
	    mode = 0;
    }
    else
	mode = 1;

    if(vp->porta_control_ratio)
	return porta_resample_voice(v, countptr, mode);

    if(vp->vibrato_control_ratio)
	return vib_resample_voice(v, countptr, mode);

    return normal_resample_voice(v, countptr, mode);
}

