📄 resample.c
字号:
/* 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*/#include <math.h>#include <stdio.h>#include <stdlib.h>#include "config.h"#include "common.h"#include "instrum.h"#include "playmidi.h"#include "output.h"#include "ctrlmode.h"#include "tables.h"#include "resample.h"#ifdef LINEAR_INTERPOLATION# if defined(LOOKUP_HACK) && defined(LOOKUP_INTERPOLATION)# define RESAMPLATION \ v1=src[ofs>>FRACTION_BITS];\ v2=src[(ofs>>FRACTION_BITS)+1];\ *dest++ = (resample_t)(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++ = (resample_t)(v1 + (((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS));# endif# define INTERPVARS sample_t v1, v2#else/* Earplugs recommended for maximum listening enjoyment */# define RESAMPLATION *dest++ = src[ofs>>FRACTION_BITS];# define INTERPVARS#endif#define FINALINTERP if (ofs == le) *dest++=src[ofs>>FRACTION_BITS];/* So it isn't interpolation. At least it's final. */extern resample_t *resample_buffer;/*************** resampling with fixed increment *****************/static resample_t *rs_plain(int v, int32 *countptr){ /* Play sample until end, then free the voice. */ INTERPVARS; Voice *vp=&voice[v]; resample_t *dest=resample_buffer; sample_t *src=vp->sample->data; int32 ofs=vp->sample_offset, incr=vp->sample_increment, le=vp->sample->data_length, count=*countptr;#ifdef PRECALC_LOOPS int32 i, j; 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; for(j = 0; j < i; j++) { RESAMPLATION; ofs += incr; } if (ofs >= le) { FINALINTERP; vp->status=VOICE_FREE; ctl->note(v); *countptr-=count+1; }#else /* PRECALC_LOOPS */ while (count--) { RESAMPLATION; ofs += incr; if (ofs >= le) { FINALINTERP; vp->status=VOICE_FREE; ctl->note(v); *countptr-=count+1; break; } }#endif /* PRECALC_LOOPS */ vp->sample_offset=ofs; /* Update offset */ return resample_buffer;}static resample_t *rs_loop(Voice *vp, int32 count){ /* Play sample until end-of-loop, skip back and continue. */ INTERPVARS; int32 ofs=vp->sample_offset, incr=vp->sample_increment, le=vp->sample->loop_end, ll=le - vp->sample->loop_start; resample_t *dest=resample_buffer; sample_t *src=vp->sample->data;#ifdef PRECALC_LOOPS int32 i; if (ofs < 0 || le < 0) return resample_buffer; 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; if (i > 0) while (i--) { RESAMPLATION; ofs += incr; } }#else while (count--) { RESAMPLATION; ofs += incr; if (ofs>=le) ofs -= ll; /* Hopefully the loop is longer than an increment. */ }#endif vp->sample_offset=ofs; /* Update offset */ return resample_buffer;}static resample_t *rs_bidir(Voice *vp, int32 count){ INTERPVARS; int32 ofs=vp->sample_offset, incr=vp->sample_increment, le=vp->sample->loop_end, ls=vp->sample->loop_start; resample_t *dest=resample_buffer; sample_t *src=vp->sample->data;#ifdef PRECALC_LOOPS int32 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--) { RESAMPLATION; 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--) { RESAMPLATION; ofs += incr; } if (ofs>=le) { /* fold the overshoot back in */ ofs = le2 - ofs; incr *= -1; } else if (ofs <= ls) { ofs = ls2 - ofs; incr *= -1; } }#else /* PRECALC_LOOPS */ /* 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; } } #endif /* PRECALC_LOOPS */ 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 = FSCALE(((double)(vp->sample->sample_rate) * (double)(vp->frequency)) / ((double)(vp->sample->root_freq) * (double)(play_mode->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]=(int32) a; if (sign) a = -a; /* need to preserve the loop direction */ return (int32) a;}static resample_t *rs_vib_plain(int v, int32 *countptr){ /* Play sample until end, then free the voice. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -