diff decoders/timidity/resample.c @ 199:2d887640d300

Initial add.
author Ryan C. Gordon <icculus@icculus.org>
date Fri, 04 Jan 2002 06:49:49 +0000
parents
children a73c51c12452
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoders/timidity/resample.c	Fri Jan 04 06:49:49 2002 +0000
@@ -0,0 +1,607 @@
+/*
+
+    TiMidity -- Experimental MIDI to WAVE converter
+    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.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
+*/
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "timidity.h"
+#include "options.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "tables.h"
+#include "resample.h"
+
+/*************** resampling with fixed increment *****************/
+
+static sample_t *rs_plain(MidiSong *song, int v, Sint32 *countptr)
+{
+
+  /* Play sample until end, then free the voice. */
+
+  sample_t v1, v2;
+  Voice 
+    *vp=&(song->voice[v]);
+  sample_t 
+    *dest=song->resample_buffer,
+    *src=vp->sample->data;
+  Sint32 
+    ofs=vp->sample_offset,
+    incr=vp->sample_increment,
+    le=vp->sample->data_length,
+    count=*countptr;
+  Sint32 i;
+
+  if (incr<0) incr = -incr; /* In case we're coming out of a bidir loop */
+
+  /* Precalc how many times we should go through the loop.
+     NOTE: Assumes that incr > 0 and that ofs <= le */
+  i = (le - ofs) / incr + 1;
+
+  if (i > count)
+    {
+      i = count;
+      count = 0;
+    } 
+  else count -= i;
+
+  while (i--) 
+    {
+      v1 = src[ofs >> FRACTION_BITS];
+      v2 = src[(ofs >> FRACTION_BITS)+1];
+      *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+      ofs += incr;
+    }
+
+  if (ofs >= le) 
+    {
+      if (ofs == le)
+	*dest++ = src[ofs >> FRACTION_BITS];
+      vp->status=VOICE_FREE;
+      *countptr-=count+1;
+    }
+  
+  vp->sample_offset=ofs; /* Update offset */
+  return song->resample_buffer;
+}
+
+static sample_t *rs_loop(MidiSong *song, Voice *vp, Sint32 count)
+{
+
+  /* Play sample until end-of-loop, skip back and continue. */
+
+  sample_t v1, v2;
+  Sint32 
+    ofs=vp->sample_offset, 
+    incr=vp->sample_increment,
+    le=vp->sample->loop_end, 
+    ll=le - vp->sample->loop_start;
+  sample_t
+    *dest=song->resample_buffer,
+    *src=vp->sample->data;
+  Sint32 i;
+  
+  while (count) 
+    {
+      if (ofs >= le)
+	/* NOTE: Assumes that ll > incr and that incr > 0. */
+	ofs -= ll;
+      /* Precalc how many times we should go through the loop */
+      i = (le - ofs) / incr + 1;
+      if (i > count) 
+	{
+	  i = count;
+	  count = 0;
+	} 
+      else count -= i;
+      while (i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+    }
+
+  vp->sample_offset=ofs; /* Update offset */
+  return song->resample_buffer;
+}
+
+static sample_t *rs_bidir(MidiSong *song, Voice *vp, Sint32 count)
+{
+  sample_t v1, v2;
+  Sint32 
+    ofs=vp->sample_offset,
+    incr=vp->sample_increment,
+    le=vp->sample->loop_end,
+    ls=vp->sample->loop_start;
+  sample_t 
+    *dest=song->resample_buffer, 
+    *src=vp->sample->data;
+  Sint32
+    le2 = le<<1, 
+    ls2 = ls<<1,
+    i;
+  /* Play normally until inside the loop region */
+
+  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. */
+      i = (ls - ofs) / incr + 1;
+      if (i > count) 
+	{
+	  i = count;
+	  count = 0;
+	} 
+      else count -= i;
+      while (i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+    }
+
+  /* Then do the bidirectional looping */
+  
+  while(count) 
+    {
+      /* Precalc how many times we should go through the loop */
+      i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
+      if (i > count) 
+	{
+	  i = count;
+	  count = 0;
+	} 
+      else count -= i;
+      while (i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+      if (ofs>=le) 
+	{
+	  /* fold the overshoot back in */
+	  ofs = le2 - ofs;
+	  incr *= -1;
+	} 
+      else if (ofs <= ls) 
+	{
+	  ofs = ls2 - ofs;
+	  incr *= -1;
+	}
+    }
+
+  vp->sample_increment=incr;
+  vp->sample_offset=ofs; /* Update offset */
+  return song->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 Sint32 update_vibrato(MidiSong *song, Voice *vp, int sign)
+{
+  Sint32 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 = FSCALE(((double)(vp->sample->sample_rate) *
+	      (double)(vp->frequency)) /
+	     ((double)(vp->sample->root_freq) *
+	      (double)(song->rate)),
+	     FRACTION_BITS);
+
+  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]=(Sint32) a;
+
+  if (sign)
+    a = -a; /* need to preserve the loop direction */
+
+  return (Sint32) a;
+}
+
+static sample_t *rs_vib_plain(MidiSong *song, int v, Sint32 *countptr)
+{
+
+  /* Play sample until end, then free the voice. */
+
+  sample_t v1, v2;
+  Voice *vp=&(song->voice[v]);
+  sample_t 
+    *dest=song->resample_buffer, 
+    *src=vp->sample->data;
+  Sint32 
+    le=vp->sample->data_length,
+    ofs=vp->sample_offset, 
+    incr=vp->sample_increment, 
+    count=*countptr;
+  int 
+    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 */
+
+  while (count--)
+    {
+      if (!cc--)
+	{
+	  cc=vp->vibrato_control_ratio;
+	  incr=update_vibrato(song, vp, 0);
+	}
+      v1 = src[ofs >> FRACTION_BITS];
+      v2 = src[(ofs >> FRACTION_BITS)+1];
+      *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+      ofs += incr;
+      if (ofs >= le)
+	{
+	  if (ofs == le)
+	    *dest++ = src[ofs >> FRACTION_BITS];
+	  vp->status=VOICE_FREE;
+	  *countptr-=count+1;
+	  break;
+	}
+    }
+  
+  vp->vibrato_control_counter=cc;
+  vp->sample_increment=incr;
+  vp->sample_offset=ofs; /* Update offset */
+  return song->resample_buffer;
+}
+
+static sample_t *rs_vib_loop(MidiSong *song, Voice *vp, Sint32 count)
+{
+
+  /* Play sample until end-of-loop, skip back and continue. */
+  
+  sample_t v1, v2;
+  Sint32 
+    ofs=vp->sample_offset, 
+    incr=vp->sample_increment, 
+    le=vp->sample->loop_end,
+    ll=le - vp->sample->loop_start;
+  sample_t 
+    *dest=song->resample_buffer, 
+    *src=vp->sample->data;
+  int 
+    cc=vp->vibrato_control_counter;
+  Sint32 i;
+  int
+    vibflag=0;
+
+  while (count) 
+    {
+      /* Hopefully the loop is longer than an increment */
+      if(ofs >= le)
+	ofs -= ll;
+      /* Precalc how many times to go through the loop, taking
+	 the vibrato control ratio into account this time. */
+      i = (le - ofs) / incr + 1;
+      if(i > count) i = count;
+      if(i > cc)
+	{
+	  i = cc;
+	  vibflag = 1;
+	} 
+      else cc -= i;
+      count -= i;
+      while(i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+      if(vibflag) 
+	{
+	  cc = vp->vibrato_control_ratio;
+	  incr = update_vibrato(song, vp, 0);
+	  vibflag = 0;
+	}
+    }
+
+  vp->vibrato_control_counter=cc;
+  vp->sample_increment=incr;
+  vp->sample_offset=ofs; /* Update offset */
+  return song->resample_buffer;
+}
+
+static sample_t *rs_vib_bidir(MidiSong *song, Voice *vp, Sint32 count)
+{
+  sample_t v1, v2;
+  Sint32 
+    ofs=vp->sample_offset, 
+    incr=vp->sample_increment,
+    le=vp->sample->loop_end, 
+    ls=vp->sample->loop_start;
+  sample_t 
+    *dest=song->resample_buffer, 
+    *src=vp->sample->data;
+  int 
+    cc=vp->vibrato_control_counter;
+  Sint32
+    le2=le<<1,
+    ls2=ls<<1,
+    i;
+  int
+    vibflag = 0;
+
+  /* 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;
+      while (i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+      if (vibflag) 
+	{
+	  cc = vp->vibrato_control_ratio;
+	  incr = update_vibrato(song, vp, 0);
+	  vibflag = 0;
+	}
+    }
+  
+  /* Then do the bidirectional looping */
+
+  while (count) 
+    {
+      /* Precalc how many times we should go through the loop */
+      i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
+      if(i > count) i = count;
+      if(i > cc) 
+	{
+	  i = cc;
+	  vibflag = 1;
+	} 
+      else cc -= i;
+      count -= i;
+      while (i--) 
+	{
+          v1 = src[ofs >> FRACTION_BITS];
+          v2 = src[(ofs >> FRACTION_BITS)+1];
+          *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+	  ofs += incr;
+	}
+      if (vibflag) 
+	{
+	  cc = vp->vibrato_control_ratio;
+	  incr = update_vibrato(song, vp, (incr < 0));
+	  vibflag = 0;
+	}
+      if (ofs >= le) 
+	{
+	  /* fold the overshoot back in */
+	  ofs = le2 - ofs;
+	  incr *= -1;
+	} 
+      else if (ofs <= ls) 
+	{
+	  ofs = ls2 - ofs;
+	  incr *= -1;
+	}
+    }
+
+  vp->vibrato_control_counter=cc;
+  vp->sample_increment=incr;
+  vp->sample_offset=ofs; /* Update offset */
+  return song->resample_buffer;
+}
+
+sample_t *resample_voice(MidiSong *song, int v, Sint32 *countptr)
+{
+  Sint32 ofs;
+  Uint8 modes;
+  Voice *vp=&(song->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->data_length>>FRACTION_BITS) - ofs)
+	{
+	  /* Note finished. Free the voice. */
+	  vp->status = VOICE_FREE;
+	  
+	  /* Let the caller know how much data we had left */
+	  *countptr = (vp->sample->data_length>>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) &&
+	  ((modes & MODES_ENVELOPE) ||
+	   (vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED)))
+	{
+	  if (modes & MODES_PINGPONG)
+	    return rs_vib_bidir(song, vp, *countptr);
+	  else
+	    return rs_vib_loop(song, vp, *countptr);
+	}
+      else
+	return rs_vib_plain(song, v, countptr);
+    }
+  else
+    {
+      if ((modes & MODES_LOOPING) &&
+	  ((modes & MODES_ENVELOPE) ||
+	   (vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED)))
+	{
+	  if (modes & MODES_PINGPONG)
+	    return rs_bidir(song, vp, *countptr);
+	  else
+	    return rs_loop(song, vp, *countptr);
+	}
+      else
+	return rs_plain(song, v, countptr);
+    }
+}
+
+void pre_resample(MidiSong *song, Sample *sp)
+{
+  double a, xdiff;
+  Sint32 incr, ofs, newlen, count;
+  Sint16 *newdata, *dest, *src = (Sint16 *) sp->data;
+  Sint16 v1, v2, v3, v4, *vptr;
+#ifdef DEBUG_CHATTER
+  static const char note_name[12][3] =
+  {
+    "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
+  };
+#endif
+
+  SNDDBG((" * pre-resampling for note %d (%s%d)\n",
+	  sp->note_to_use,
+	  note_name[sp->note_to_use % 12], (sp->note_to_use & 0x7F) / 12));
+
+  a = ((double) (sp->sample_rate) * freq_table[(int) (sp->note_to_use)]) /
+    ((double) (sp->root_freq) * song->rate);
+  newlen = (Sint32)(sp->data_length / a);
+  dest = newdata = safe_malloc(newlen >> (FRACTION_BITS - 1));
+
+  count = (newlen >> FRACTION_BITS) - 1;
+  ofs = incr = (sp->data_length - (1 << FRACTION_BITS)) / count;
+
+  if (--count)
+    *dest++ = src[0];
+
+  /* Since we're pre-processing and this doesn't have to be done in
+     real-time, we go ahead and do the full sliding cubic interpolation. */
+  while (--count)
+    {
+      vptr = src + (ofs >> FRACTION_BITS);
+      v1 = *(vptr - 1);
+      v2 = *vptr;
+      v3 = *(vptr + 1);
+      v4 = *(vptr + 2);
+      xdiff = FSCALENEG(ofs & FRACTION_MASK, FRACTION_BITS);
+      *dest++ = (Sint16)(v2 + (xdiff / 6.0) * (-2 * v1 - 3 * v2 + 6 * v3 - v4 +
+      xdiff * (3 * (v1 - 2 * v2 + v3) + xdiff * (-v1 + 3 * (v2 - v3) + v4))));
+      ofs += incr;
+    }
+
+  if (ofs & FRACTION_MASK)
+    {
+      v1 = src[ofs >> FRACTION_BITS];
+      v2 = src[(ofs >> FRACTION_BITS) + 1];
+      *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+    }
+  else
+    *dest++ = src[ofs >> FRACTION_BITS];
+
+  sp->data_length = newlen;
+  sp->loop_start = (Sint32)(sp->loop_start / a);
+  sp->loop_end = (Sint32)(sp->loop_end / a);
+  free(sp->data);
+  sp->data = (sample_t *) newdata;
+  sp->sample_rate = 0;
+}