/* TiMidity -- Experimental MIDI to WAVE converter Copyright (C) 1995 Tuukka Toivonen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA resample.c */ #include #include #include #include "timidity.h" #include "c_cvars.h" EXTERN_CVAR(Bool, midi_timiditylike) namespace Timidity { #define RESAMPLATION {\ int o = ofs >> FRACTION_BITS, m = ofs & FRACTION_MASK; \ *dest++ = src[o] + (src[o + 1] - src[o]) * m / (1 << FRACTION_BITS);\ } #define FINALINTERP if (ofs == le) *dest++ = src[ofs >> FRACTION_BITS]; /* So it isn't interpolation. At least it's final. */ /*************** resampling with fixed increment *****************/ static sample_t *rs_plain(sample_t *resample_buffer, Voice *v, int *countptr) { /* Play sample until end, then free the voice. */ const sample_t *src = v->sample->data; sample_t *dest = resample_buffer; int ofs = v->sample_offset, incr = v->sample_increment, le = v->sample->data_length, count = *countptr; int 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--) { RESAMPLATION; ofs += incr; } if (ofs >= le) { FINALINTERP; v->status = 0; *countptr -= count + 1; } v->sample_offset = ofs; /* Update offset */ return resample_buffer; } static sample_t *rs_loop(sample_t *resample_buffer, Voice *vp, int count) { /* Play sample until end-of-loop, skip back and continue. */ int ofs = vp->sample_offset, incr = vp->sample_increment, le = vp->sample->loop_end, ll = le - vp->sample->loop_start; sample_t *dest = resample_buffer; const sample_t *src = vp->sample->data; int 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--) { RESAMPLATION; ofs += incr; } } vp->sample_offset=ofs; /* Update offset */ return resample_buffer; } static sample_t *rs_bidir(sample_t *resample_buffer, Voice *vp, int count) { int ofs = vp->sample_offset, incr = vp->sample_increment, le = vp->sample->loop_end, ls = vp->sample->loop_start; sample_t *dest = resample_buffer; const sample_t *src = vp->sample->data; int 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; } } 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 >= VIBRATO_SAMPLE_INCREMENTS * 3 / 2) return VIBRATO_SAMPLE_INCREMENTS * 5 / 2 - 1 - phase; else return phase - VIBRATO_SAMPLE_INCREMENTS / 2; } static int update_vibrato(float output_rate, Voice *vp, int sign) { int depth; int phase; double a, pb; 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 != 0) { /* Need to update sweep */ vp->vibrato_sweep_position += vp->vibrato_sweep; if (vp->vibrato_sweep_position >= (1<vibrato_sweep=0; else { /* Adjust depth */ depth *= vp->vibrato_sweep_position; depth >>= SWEEP_SHIFT; } } a = FSCALE(((double)(vp->sample->sample_rate) * vp->frequency) / ((double)(vp->sample->root_freq) * output_rate), FRACTION_BITS); pb = (sine(vp->vibrato_phase * (1.0/(2*VIBRATO_SAMPLE_INCREMENTS))) * (double)(depth) * VIBRATO_AMPLITUDE_TUNING); a *= pow(2.0, pb / (8192 * 12.f)); /* If the sweep's over, we can store the newly computed sample_increment */ if (!vp->vibrato_sweep) vp->vibrato_sample_increment[phase] = (int) a; if (sign) a = -a; /* need to preserve the loop direction */ return (int) a; } static sample_t *rs_vib_plain(sample_t *resample_buffer, float rate, Voice *vp, int *countptr) { /* Play sample until end, then free the voice. */ sample_t *dest = resample_buffer; const sample_t *src = vp->sample->data; int 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(rate, vp, 0); } RESAMPLATION; ofs += incr; if (ofs >= le) { FINALINTERP; vp->status = 0; *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(sample_t *resample_buffer, float rate, Voice *vp, int count) { /* Play sample until end-of-loop, skip back and continue. */ int ofs = vp->sample_offset, incr = vp->sample_increment, le = vp->sample->loop_end, ll = le - vp->sample->loop_start; sample_t *dest = resample_buffer; const sample_t *src = vp->sample->data; int cc = vp->vibrato_control_counter; int 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--) { RESAMPLATION; ofs += incr; } if (vibflag) { cc = vp->vibrato_control_ratio; incr = update_vibrato(rate, vp, 0); vibflag = 0; } } vp->vibrato_control_counter = cc; vp->sample_increment = incr; vp->sample_offset = ofs; /* Update offset */ return resample_buffer; } static sample_t *rs_vib_bidir(sample_t *resample_buffer, float rate, Voice *vp, int count) { int ofs = vp->sample_offset, incr = vp->sample_increment, le = vp->sample->loop_end, ls = vp->sample->loop_start; sample_t *dest = resample_buffer; const sample_t *src = vp->sample->data; int cc = vp->vibrato_control_counter; int 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--) { RESAMPLATION; ofs += incr; } if (vibflag) { cc = vp->vibrato_control_ratio; incr = update_vibrato(rate, 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--) { RESAMPLATION; ofs += incr; } if (vibflag) { cc = vp->vibrato_control_ratio; incr = update_vibrato(rate, 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 resample_buffer; } sample_t *resample_voice(Renderer *song, Voice *vp, int *countptr) { int ofs; WORD modes; if (vp->sample->sample_rate == 0) { /* 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 = 0; /* 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->status & VOICE_LPE) { if (vp->sample->loop_end - vp->sample->loop_start < 2) { // Loop is too short; turn it off. vp->status &= ~VOICE_LPE; } } if (vp->vibrato_control_ratio) { if (vp->status & VOICE_LPE && !(midi_timiditylike && vp->sample->modes & PATCH_T_NO_LOOP)) { if (modes & PATCH_BIDIR) return rs_vib_bidir(song->resample_buffer, song->rate, vp, *countptr); else return rs_vib_loop(song->resample_buffer, song->rate, vp, *countptr); } else { return rs_vib_plain(song->resample_buffer, song->rate, vp, countptr); } } else { if (vp->status & VOICE_LPE && !(midi_timiditylike && vp->sample->modes & PATCH_T_NO_LOOP)) { if (modes & PATCH_BIDIR) return rs_bidir(song->resample_buffer, vp, *countptr); else return rs_loop(song->resample_buffer, vp, *countptr); } else { return rs_plain(song->resample_buffer, vp, countptr); } } } void pre_resample(Renderer *song, Sample *sp) { double a, xdiff; int incr, ofs, newlen, count; sample_t *newdata, *dest, *src = sp->data; sample_t v1, v2, v3, v4, *vptr; static const char note_name[12][3] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; if (sp->scale_factor != 0) return; cmsg(CMSG_INFO, VERB_NOISY, " * pre-resampling for note %d (%s%d)\n", sp->scale_note, note_name[sp->scale_note % 12], (sp->scale_note & 0x7F) / 12); a = (sp->sample_rate * note_to_freq(sp->scale_note)) / (sp->root_freq * song->rate); if (a <= 0) return; newlen = (int)(sp->data_length / a); if (newlen < 0 || (newlen >> FRACTION_BITS) > MAX_SAMPLE_SIZE) return; count = newlen >> FRACTION_BITS; dest = newdata = (sample_t *)safe_malloc(count * sizeof(float)); 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 == src) ? *vptr : *(vptr - 1); v2 = *vptr; v3 = *(vptr + 1); v4 = *(vptr + 2); xdiff = FSCALENEG(ofs & FRACTION_MASK, FRACTION_BITS); *dest++ = sample_t(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) { RESAMPLATION } else { *dest++ = src[ofs >> FRACTION_BITS]; } sp->data_length = newlen; sp->loop_start = int(sp->loop_start / a); sp->loop_end = int(sp->loop_end / a); free(sp->data); sp->data = newdata; sp->sample_rate = 0; } }