/* * NAME: fixed->div() * DESCRIPTION: perform division using fixed-point math */ mad_fixed_t mad_f_div(mad_fixed_t x, mad_fixed_t y) { mad_fixed_t q, r; unsigned int bits; q = mad_f_abs(x / y); if (x < 0) { x = -x; y = -y; } r = x % y; if (y < 0) { x = -x; y = -y; } if (q > mad_f_intpart(MAD_F_MAX) && !(q == -mad_f_intpart(MAD_F_MIN) && r == 0 && (x < 0) != (y < 0))) return 0; for (bits = MAD_F_FRACBITS; bits && r; --bits) { q <<= 1, r <<= 1; if (r >= y) r -= y, ++q; } /* round */ if (2 * r >= y) ++q; /* fix sign */ if ((x < 0) != (y < 0)) q = -q; return q << bits; }
/* * NAME: resample_block() * DESCRIPTION: algorithmically change the sampling rate of a PCM sample block */ unsigned int mad_resample_block(struct resample_state *state, unsigned int nsamples, mad_fixed_t const *old, mad_fixed_t *newdata) { mad_fixed_t const *end, *begin; /* * This resampling algorithm is based on a linear interpolation, which is * not at all the best sounding but is relatively fast and efficient. * * A better algorithm would be one that implements a bandlimited * interpolation. */ if (state->ratio == MAD_F_ONE) { memcpy(newdata, old, nsamples * sizeof(mad_fixed_t)); return nsamples; } end = old + nsamples; begin = newdata; if (state->step < 0) { state->step = mad_f_fracpart(-state->step); while (state->step < MAD_F_ONE) { *newdata++ = state->step ? state->last + mad_f_mul(*old - state->last, state->step) : state->last; state->step += state->ratio; if (((state->step + 0x00000080L) & 0x0fffff00L) == 0) state->step = (state->step + 0x00000080L) & ~0x0fffffffL; } state->step -= MAD_F_ONE; } while (end - old > 1 + mad_f_intpart(state->step)) { old += mad_f_intpart(state->step); state->step = mad_f_fracpart(state->step); *newdata++ = state->step ? *old + mad_f_mul(old[1] - old[0], state->step) : *old; state->step += state->ratio; if (((state->step + 0x00000080L) & 0x0fffff00L) == 0) state->step = (state->step + 0x00000080L) & ~0x0fffffffL; } if (end - old == 1 + mad_f_intpart(state->step)) { state->last = end[-1]; state->step = -state->step; } else state->step -= mad_f_fromint(end - old); return newdata - begin; }