Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* The design goals of this code are: - Very fast algorithm - SIMD-friendly algorithm - Low memory requirement - Good *perceptual* quality (and not best SNR)
Warning: This resampler is relatively new. Although I think I got rid of all the major bugs and I don't expect the API to change anymore, there may be something I've missed. So use with caution.
This algorithm is based on this original resampling algorithm: Smith, Julius O. Digital Audio Resampling Home Page Center for Computer Research in Music and Acoustics (CCRMA), Stanford University, 2007. Web published at https://ccrma.stanford.edu/~jos/resample/.
There is one main difference, though. This resampler uses cubic interpolation instead of linear interpolation in the above paper. This makes the table much smaller and makes it possible to compute that table on a per-stream basis. In turn, being able to tweak the table for each stream makes it possible to both reduce complexity on simple ratios (e.g. 2/3), and get rid of the rounding operations in the inner loop. The latter both reduces CPU time and makes the algorithm more SIMD-friendly.
*/
int quality;
spx_uint32_t nb_channels;
spx_uint32_t filt_len;
spx_uint32_t mem_alloc_size;
spx_uint32_t buffer_size; int int_advance; int frac_advance; float cutoff;
spx_uint32_t oversample; int initialised; int started;
/* These are per-channel */
spx_int32_t *last_sample;
spx_uint32_t *samp_frac_num;
spx_uint32_t *magic_samples;
#if 0 #include <stdio.h> int main(int argc, char **argv)
{ int i; for (i=0;i<256;i++)
{
printf ("%f\n", compute_func(i/256., KAISER12));
} return 0;
} #endif
#ifdef FIXED_POINT /* The slow way of computing a sinc for the table. Should improve that some day */ static spx_word16_t sinc(float cutoff, float x, int N, conststruct FuncDef *window_func)
{ /*fprintf (stderr, "%f ", x);*/ float xx = x * cutoff; if (fabs(x)<1e-6f) return WORD2INT(32768.*cutoff); elseif (fabs(x) > .5f*N) return 0; /*FIXME: Can it really be any slower than this? */ return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func));
} #else /* The slow way of computing a sinc for the table. Should improve that some day */ static spx_word16_t sinc(float cutoff, float x, int N, conststruct FuncDef *window_func)
{ /*fprintf (stderr, "%f ", x);*/ float xx = x * cutoff; if (fabs(x)<1e-6) return cutoff; elseif (fabs(x) > .5*N) return 0; /*FIXME: Can it really be any slower than this? */ return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func);
} #endif
#ifdef FIXED_POINT staticvoid cubic_coef(spx_word16_t x, spx_word16_t interp[4])
{ /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
but I know it's MMSE-optimal on a sinc */
spx_word16_t x2, x3;
x2 = MULT16_16_P15(x, x);
x3 = MULT16_16_P15(x, x2);
interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15);
interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1));
interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15); /* Just to make sure we don't have rounding problems */
interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3]; if (interp[2]<32767)
interp[2]+=1;
} #else staticvoid cubic_coef(spx_word16_t frac, spx_word16_t interp[4])
{ /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
but I know it's MMSE-optimal on a sinc */
interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac;
interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac; /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac; /* Just to make sure we don't have rounding problems */
interp[2] = 1.-interp[0]-interp[1]-interp[3];
} #endif
#ifdef OVERRIDE_INNER_PRODUCT_SINGLE if (!moz_speex_have_single_simd()) { #endif int j;
sum = 0; for(j=0;j<N;j++) sum += MULT16_16(sinct[j], iptr[j]);
/* This code is slower on most DSPs which have only 2 accumulators. Plus this this forces truncation to 32 bits and you lose the HW guard bits. I think we can trust the compiler and let it vectorize and/or unroll itself. spx_word32_t accum[4] = {0,0,0,0}; for(j=0;j<N;j+=4) { accum[0] += MULT16_16(sinct[j], iptr[j]); accum[1] += MULT16_16(sinct[j+1], iptr[j+1]); accum[2] += MULT16_16(sinct[j+2], iptr[j+2]); accum[3] += MULT16_16(sinct[j+3], iptr[j+3]); } sum = accum[0] + accum[1] + accum[2] + accum[3];
*/
sum = SATURATE32PSHR(sum, 15, 32767); #ifdef OVERRIDE_INNER_PRODUCT_SINGLE
} else {
sum = inner_product_single(sinct, iptr, N);
} #endif
/* This resampler is used to produce zero output in situations where memory for the filter could not be allocated. The expected numbers of input and output samples are still processed so that callers failing to check error
codes are not surprised, possibly getting into infinite loops. */ staticint resampler_basic_zero(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
{ int out_sample = 0; int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; constint out_stride = st->out_stride; constint int_advance = st->int_advance; constint frac_advance = st->frac_advance; const spx_uint32_t den_rate = st->den_rate;
staticint multiply_frac(spx_uint32_t *result, spx_uint32_t value, spx_uint32_t num, spx_uint32_t den)
{
spx_uint32_t major = value / den;
spx_uint32_t remain = value % den; /* TODO: Could use 64 bits operation to check for overflow. But only guaranteed in C99+ */ if (remain > UINT32_MAX / num || major > UINT32_MAX / num
|| major * num > UINT32_MAX - remain * num / den) return RESAMPLER_ERR_OVERFLOW;
*result = remain * num / den + major * num; return RESAMPLER_ERR_SUCCESS;
}
if (st->num_rate > st->den_rate)
{ /* down-sampling */
st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate; if (multiply_frac(&st->filt_len,st->filt_len,st->num_rate,st->den_rate) != RESAMPLER_ERR_SUCCESS) goto fail; /* Round up to make sure we have a multiple of 8 for SSE */
st->filt_len = ((st->filt_len-1)&(~0x7))+8; if (2*st->den_rate < st->num_rate)
st->oversample >>= 1; if (4*st->den_rate < st->num_rate)
st->oversample >>= 1; if (8*st->den_rate < st->num_rate)
st->oversample >>= 1; if (16*st->den_rate < st->num_rate)
st->oversample >>= 1; if (st->oversample < 1)
st->oversample = 1;
} else { /* up-sampling */
st->cutoff = quality_map[st->quality].upsample_bandwidth;
}
use_direct = #ifdef RESAMPLE_HUGEMEM /* Choose the direct resampler, even with higher initialization costs,
when resampling any multiple of 100 to 44100. */
st->den_rate <= 441 #else /* Choose the resampling type that requires the least amount of memory */
st->filt_len*st->den_rate <= st->filt_len*st->oversample+8 #endif
&& INT_MAX/sizeof(spx_word16_t)/st->den_rate >= st->filt_len; if (use_direct)
{
min_sinc_table_length = st->filt_len*st->den_rate;
} else { if ((INT_MAX/sizeof(spx_word16_t)-8)/st->oversample < st->filt_len) goto fail;
min_sinc_table_length = st->filt_len*st->oversample+8;
} if (st->sinc_table_length < min_sinc_table_length)
{
spx_word16_t *sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,min_sinc_table_length*sizeof(spx_word16_t)); if (!sinc_table) goto fail;
/* Here's the place where we update the filter memory to take into account the change in filter length. It's probably the messiest part of the code
due to handling of lots of corner cases. */
/* Adding buffer_size to filt_len won't overflow here because filt_len
could be multiplied by sizeof(spx_word16_t) above. */
min_alloc_size = st->filt_len-1 + st->buffer_size; if (min_alloc_size > st->mem_alloc_size)
{
spx_word16_t *mem; if (INT_MAX/sizeof(spx_word16_t)/st->nb_channels < min_alloc_size) goto fail; elseif (!(mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*min_alloc_size * sizeof(*mem)))) goto fail;
st->mem = mem;
st->mem_alloc_size = min_alloc_size;
} if (!st->started)
{
spx_uint32_t i; for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
st->mem[i] = 0; /*speex_warning("reinit filter");*/
} elseif (st->filt_len > old_length)
{
spx_uint32_t i; /* Increase the filter length */ /*speex_warning("increase filter size");*/ for (i=st->nb_channels;i--;)
{
spx_uint32_t j;
spx_uint32_t olen = old_length;
spx_uint32_t start = i*st->mem_alloc_size;
spx_uint32_t magic_samples = st->magic_samples[i]; /*if (st->magic_samples[i])*/
{ /* Try and remove the magic samples as if nothing had happened */
/* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
olen = old_length + 2*magic_samples; for (j=old_length-1+magic_samples;j--;)
st->mem[start+j+magic_samples] = st->mem[i*old_alloc_size+j]; for (j=0;j<magic_samples;j++)
st->mem[start+j] = 0;
st->magic_samples[i] = 0;
} if (st->filt_len > olen)
{ /* If the new filter length is still bigger than the "augmented" length */ /* Copy data going backward */ for (j=0;j<olen-1;j++)
st->mem[start+(st->filt_len-2-j)] = st->mem[start+(olen-2-j)]; /* Then put zeros for lack of anything better */ for (;j<st->filt_len-1;j++)
st->mem[start+(st->filt_len-2-j)] = 0; /* Adjust last_sample */
st->last_sample[i] += (st->filt_len - olen)/2;
} else { /* Put back some of the magic! */
magic_samples = (olen - st->filt_len)/2; for (j=0;j<st->filt_len-1+magic_samples;j++)
st->mem[start+j] = st->mem[start+j+magic_samples];
st->magic_samples[i] = magic_samples;
}
}
} elseif (st->filt_len < old_length)
{
spx_uint32_t i; /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"
samples so they can be used directly as input the next time(s) */ for (i=0;i<st->nb_channels;i++)
{
spx_uint32_t j;
spx_uint32_t old_magic = st->magic_samples[i];
st->magic_samples[i] = (old_length - st->filt_len)/2; /* We must copy some of the memory that's no longer used */ /* Copy data going backward */ for (j=0;j<st->filt_len-1+st->magic_samples[i]+old_magic;j++)
st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
st->magic_samples[i] += old_magic;
}
} return RESAMPLER_ERR_SUCCESS;
fail:
st->resampler_ptr = resampler_basic_zero; /* st->mem may still contain consumed input samples for the filter. Restore filt_len so that filt_len - 1 still points to the position after
the last of these samples. */
st->filt_len = old_length; return RESAMPLER_ERR_ALLOC_FAILED;
}
/* Per channel data */ if (!(st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(spx_int32_t)))) goto fail; if (!(st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t)))) goto fail; if (!(st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t)))) goto fail;
/* If we couldn't process all "magic" input samples, save the rest for next time */ if (st->magic_samples[channel_index])
{
spx_uint32_t i; for (i=0;i<st->magic_samples[channel_index];i++)
mem[N-1+i]=mem[N-1+i+tmp_in_len];
}
*out += out_len*st->out_stride; return out_len;
}
EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
{
spx_uint32_t i; for (i=0;i<st->nb_channels;i++)
{
st->last_sample[i] = 0;
st->magic_samples[i] = 0;
st->samp_frac_num[i] = 0;
} for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
st->mem[i] = 0; return RESAMPLER_ERR_SUCCESS;
}
EXPORT constchar *speex_resampler_strerror(int err)
{ switch (err)
{ case RESAMPLER_ERR_SUCCESS: return"Success."; case RESAMPLER_ERR_ALLOC_FAILED: return"Memory allocation failed."; case RESAMPLER_ERR_BAD_STATE: return"Bad resampler state."; case RESAMPLER_ERR_INVALID_ARG: return"Invalid argument."; case RESAMPLER_ERR_PTR_OVERLAP: return"Input and output buffers overlap."; default: return"Unknown error. Bad error code or strange version mismatch.";
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.