#include <samplerate.h>
#endif
+#ifdef HAVE_SPEEX
#include <speex/speex_resampler.h>
+#endif
#include <pulse/xmalloc.h>
#include <pulsecore/sconv.h>
} src;
#endif
+#ifdef HAVE_SPEEX
struct { /* data specific to speex */
SpeexResamplerState* state;
} speex;
+#endif
struct { /* data specific to ffmpeg */
struct AVResampleContext *state;
static int copy_init(pa_resampler *r);
static int trivial_init(pa_resampler*r);
+#ifdef HAVE_SPEEX
static int speex_init(pa_resampler*r);
+#endif
static int ffmpeg_init(pa_resampler*r);
static int peaks_init(pa_resampler*r);
#ifdef HAVE_LIBSAMPLERATE
[PA_RESAMPLER_SRC_LINEAR] = NULL,
#endif
[PA_RESAMPLER_TRIVIAL] = trivial_init,
+#ifdef HAVE_SPEEX
[PA_RESAMPLER_SPEEX_FLOAT_BASE+0] = speex_init,
[PA_RESAMPLER_SPEEX_FLOAT_BASE+1] = speex_init,
[PA_RESAMPLER_SPEEX_FLOAT_BASE+2] = speex_init,
[PA_RESAMPLER_SPEEX_FIXED_BASE+8] = speex_init,
[PA_RESAMPLER_SPEEX_FIXED_BASE+9] = speex_init,
[PA_RESAMPLER_SPEEX_FIXED_BASE+10] = speex_init,
+#else
+ [PA_RESAMPLER_SPEEX_FLOAT_BASE+0] = NULL,
+ [PA_RESAMPLER_SPEEX_FLOAT_BASE+1] = NULL,
+ [PA_RESAMPLER_SPEEX_FLOAT_BASE+2] = NULL,
+ [PA_RESAMPLER_SPEEX_FLOAT_BASE+3] = NULL,
+ [PA_RESAMPLER_SPEEX_FLOAT_BASE+4] = NULL,
+ [PA_RESAMPLER_SPEEX_FLOAT_BASE+5] = NULL,
+ [PA_RESAMPLER_SPEEX_FLOAT_BASE+6] = NULL,
+ [PA_RESAMPLER_SPEEX_FLOAT_BASE+7] = NULL,
+ [PA_RESAMPLER_SPEEX_FLOAT_BASE+8] = NULL,
+ [PA_RESAMPLER_SPEEX_FLOAT_BASE+9] = NULL,
+ [PA_RESAMPLER_SPEEX_FLOAT_BASE+10] = NULL,
+ [PA_RESAMPLER_SPEEX_FIXED_BASE+0] = NULL,
+ [PA_RESAMPLER_SPEEX_FIXED_BASE+1] = NULL,
+ [PA_RESAMPLER_SPEEX_FIXED_BASE+2] = NULL,
+ [PA_RESAMPLER_SPEEX_FIXED_BASE+3] = NULL,
+ [PA_RESAMPLER_SPEEX_FIXED_BASE+4] = NULL,
+ [PA_RESAMPLER_SPEEX_FIXED_BASE+5] = NULL,
+ [PA_RESAMPLER_SPEEX_FIXED_BASE+6] = NULL,
+ [PA_RESAMPLER_SPEEX_FIXED_BASE+7] = NULL,
+ [PA_RESAMPLER_SPEEX_FIXED_BASE+8] = NULL,
+ [PA_RESAMPLER_SPEEX_FIXED_BASE+9] = NULL,
+ [PA_RESAMPLER_SPEEX_FIXED_BASE+10] = NULL,
+#endif
[PA_RESAMPLER_FFMPEG] = ffmpeg_init,
[PA_RESAMPLER_AUTO] = NULL,
[PA_RESAMPLER_COPY] = copy_init,
method = PA_RESAMPLER_AUTO;
}
- if (method == PA_RESAMPLER_AUTO)
+ if (method == PA_RESAMPLER_AUTO) {
+#ifdef HAVE_SPEEX
method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3;
+#else
+ method = PA_RESAMPLER_FFMPEG;
+#endif
+ }
r = pa_xnew(pa_resampler, 1);
r->mempool = pool;
return 0;
#endif
+#ifndef HAVE_SPEEX
+ if (m >= PA_RESAMPLER_SPEEX_FLOAT_BASE && m <= PA_RESAMPLER_SPEEX_FLOAT_MAX)
+ return 0;
+ if (m >= PA_RESAMPLER_SPEEX_FIXED_BASE && m <= PA_RESAMPLER_SPEEX_FIXED_MAX)
+ return 0;
+#endif
+
return 1;
}
}
#endif
+#ifdef HAVE_SPEEX
/*** speex based implementation ***/
static void speex_resample_float(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
return 0;
}
+#endif
/* Trivial implementation */
static void trivial_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
size_t fz;
- unsigned o_index;
+ unsigned i_index, o_index;
void *src, *dst;
pa_assert(r);
pa_assert(input);
pa_assert(output);
pa_assert(out_n_frames);
+ pa_assert(r->i_ss.channels == r->o_ss.channels);
fz = r->w_sz * r->o_ss.channels;
dst = (uint8_t*) pa_memblock_acquire(output->memblock) + output->index;
for (o_index = 0;; o_index++, r->trivial.o_counter++) {
- unsigned j;
-
- j = ((r->trivial.o_counter * r->i_ss.rate) / r->o_ss.rate);
- j = j > r->trivial.i_counter ? j - r->trivial.i_counter : 0;
+ i_index = (r->trivial.o_counter * r->i_ss.rate) / r->o_ss.rate;
+ i_index = i_index > r->trivial.i_counter ? i_index - r->trivial.i_counter : 0;
- if (j >= in_n_frames)
+ if (i_index >= in_n_frames)
break;
pa_assert_fp(o_index * fz < pa_memblock_get_length(output->memblock));
- memcpy((uint8_t*) dst + fz * o_index,
- (uint8_t*) src + fz * j, (int) fz);
+ /* Directly assign some common sample sizes, use memcpy as fallback */
+ if (r->w_sz == 2) {
+ for (unsigned c = 0; c < r->o_ss.channels; c++)
+ ((uint16_t *) dst)[o_index+c] = ((uint16_t *) src)[i_index+c];
+ } else if (r->w_sz == 4) {
+ for (unsigned c = 0; c < r->o_ss.channels; c++)
+ ((uint32_t *) dst)[o_index+c] = ((uint32_t *) src)[i_index+c];
+ } else {
+ memcpy((uint8_t *) dst + fz * o_index, (uint8_t *) src + fz * i_index, (int) fz);
+ }
}
pa_memblock_release(input->memblock);
/* Peak finder implementation */
static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
- size_t fz;
- unsigned o_index;
+ unsigned c, o_index = 0;
+ unsigned i, i_end = 0;
void *src, *dst;
- unsigned start = 0;
pa_assert(r);
pa_assert(input);
pa_assert(output);
pa_assert(out_n_frames);
-
- fz = r->w_sz * r->o_ss.channels;
+ pa_assert(r->i_ss.rate >= r->o_ss.rate);
+ pa_assert(r->i_ss.channels == r->o_ss.channels);
+ pa_assert(r->work_format == PA_SAMPLE_S16NE || r->work_format == PA_SAMPLE_FLOAT32NE);
src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
dst = (uint8_t*) pa_memblock_acquire(output->memblock) + output->index;
- for (o_index = 0;; o_index++, r->peaks.o_counter++) {
- unsigned j;
+ i = (r->peaks.o_counter * r->i_ss.rate) / r->o_ss.rate;
+ i = i > r->peaks.i_counter ? i - r->peaks.i_counter : 0;
- j = ((r->peaks.o_counter * r->i_ss.rate) / r->o_ss.rate);
+ while (i_end < in_n_frames) {
+ i_end = ((r->peaks.o_counter+1) * r->i_ss.rate) / r->o_ss.rate;
+ i_end = i_end > r->peaks.i_counter ? i_end - r->peaks.i_counter : 0;
- if (j > r->peaks.i_counter)
- j -= r->peaks.i_counter;
- else
- j = 0;
+ pa_assert_fp(o_index * r->w_sz * r->o_ss.channels < pa_memblock_get_length(output->memblock));
- pa_assert(o_index * fz < pa_memblock_get_length(output->memblock));
+ /* 1ch float is treated separately, because that is the common case */
+ if (r->o_ss.channels == 1 && r->work_format == PA_SAMPLE_FLOAT32NE) {
+ float *s = (float*) src + i;
+ float *d = (float*) dst + o_index;
- if (r->work_format == PA_SAMPLE_S16NE) {
- unsigned i, c;
- int16_t *s = (int16_t*) ((uint8_t*) src + fz * start);
- int16_t *d = (int16_t*) ((uint8_t*) dst + fz * o_index);
+ for (; i < i_end && i < in_n_frames; i++) {
+ float n = fabsf(*s++);
- for (i = start; i <= j && i < in_n_frames; i++)
+ if (n > r->peaks.max_f[0])
+ r->peaks.max_f[0] = n;
+ }
- for (c = 0; c < r->o_ss.channels; c++, s++) {
- int16_t n;
+ if (i == i_end) {
+ *d = r->peaks.max_f[0];
+ r->peaks.max_f[0] = 0;
+ o_index++, r->peaks.o_counter++;
+ }
+ } else if (r->work_format == PA_SAMPLE_S16NE) {
+ int16_t *s = (int16_t*) src + r->i_ss.channels * i;
+ int16_t *d = (int16_t*) dst + r->o_ss.channels * o_index;
- n = (int16_t) (*s < 0 ? -*s : *s);
+ for (; i < i_end && i < in_n_frames; i++)
+ for (c = 0; c < r->o_ss.channels; c++) {
+ int16_t n = abs(*s++);
- if (PA_UNLIKELY(n > r->peaks.max_i[c]))
+ if (n > r->peaks.max_i[c])
r->peaks.max_i[c] = n;
}
- if (i >= in_n_frames)
- break;
-
- for (c = 0; c < r->o_ss.channels; c++, d++) {
- *d = r->peaks.max_i[c];
- r->peaks.max_i[c] = 0;
+ if (i == i_end) {
+ for (c = 0; c < r->o_ss.channels; c++, d++) {
+ *d = r->peaks.max_i[c];
+ r->peaks.max_i[c] = 0;
+ }
+ o_index++, r->peaks.o_counter++;
}
-
} else {
- unsigned i, c;
- float *s = (float*) ((uint8_t*) src + fz * start);
- float *d = (float*) ((uint8_t*) dst + fz * o_index);
-
- pa_assert(r->work_format == PA_SAMPLE_FLOAT32NE);
+ float *s = (float*) src + r->i_ss.channels * i;
+ float *d = (float*) dst + r->o_ss.channels * o_index;
- for (i = start; i <= j && i < in_n_frames; i++)
- for (c = 0; c < r->o_ss.channels; c++, s++) {
- float n = fabsf(*s);
+ for (; i < i_end && i < in_n_frames; i++)
+ for (c = 0; c < r->o_ss.channels; c++) {
+ float n = fabsf(*s++);
if (n > r->peaks.max_f[c])
r->peaks.max_f[c] = n;
}
- if (i >= in_n_frames)
- break;
-
- for (c = 0; c < r->o_ss.channels; c++, d++) {
- *d = r->peaks.max_f[c];
- r->peaks.max_f[c] = 0;
+ if (i == i_end) {
+ for (c = 0; c < r->o_ss.channels; c++, d++) {
+ *d = r->peaks.max_f[c];
+ r->peaks.max_f[c] = 0;
+ }
+ o_index++, r->peaks.o_counter++;
}
}
-
- start = j;
}
pa_memblock_release(input->memblock);