mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 01:45:33 +00:00
audio-resampler: add linear interpolation method
Make more functions into macros. Add linear interpolation of filter coefficients.
This commit is contained in:
parent
c0f22132aa
commit
e02af5c534
3 changed files with 546 additions and 215 deletions
|
@ -21,7 +21,7 @@
|
|||
#include <xmmintrin.h>
|
||||
|
||||
static inline void
|
||||
inner_product_gfloat_1_sse (gfloat * o, const gfloat * a, const gfloat * b, gint len)
|
||||
inner_product_gfloat_none_1_sse (gfloat * o, const gfloat * a, const gfloat * b, gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i = 0;
|
||||
__m128 sum = _mm_setzero_ps ();
|
||||
|
@ -40,7 +40,35 @@ inner_product_gfloat_1_sse (gfloat * o, const gfloat * a, const gfloat * b, gint
|
|||
}
|
||||
|
||||
static inline void
|
||||
inner_product_gfloat_2_sse (gfloat * o, const gfloat * a, const gfloat * b, gint len)
|
||||
inner_product_gfloat_linear_1_sse (gfloat * o, const gfloat * a, const gfloat * b, gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i = 0;
|
||||
__m128 sum = _mm_setzero_ps (), t, b0;
|
||||
__m128 f = _mm_loadu_ps(icoeff);
|
||||
|
||||
for (; i < len; i += 4) {
|
||||
t = _mm_loadu_ps (a + i);
|
||||
|
||||
b0 = _mm_loadh_pi (b0, (__m64 *) (b + (i+0)*oversample));
|
||||
b0 = _mm_loadl_pi (b0, (__m64 *) (b + (i+1)*oversample));
|
||||
|
||||
sum =
|
||||
_mm_add_ps (sum, _mm_mul_ps (_mm_unpacklo_ps (t, t), b0));
|
||||
|
||||
b0 = _mm_loadh_pi (b0, (__m64 *) (b + (i+2)*oversample));
|
||||
b0 = _mm_loadl_pi (b0, (__m64 *) (b + (i+3)*oversample));
|
||||
|
||||
sum =
|
||||
_mm_add_ps (sum, _mm_mul_ps (_mm_unpackhi_ps (t, t), b0));
|
||||
}
|
||||
sum = _mm_mul_ps (sum, f);
|
||||
sum = _mm_add_ps (sum, _mm_movehl_ps (sum, sum));
|
||||
sum = _mm_add_ss (sum, _mm_shuffle_ps (sum, sum, 0x55));
|
||||
_mm_store_ss (o, sum);
|
||||
}
|
||||
|
||||
static inline void
|
||||
inner_product_gfloat_none_2_sse (gfloat * o, const gfloat * a, const gfloat * b, gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i = 0;
|
||||
__m128 sum = _mm_setzero_ps (), t;
|
||||
|
@ -66,15 +94,16 @@ inner_product_gfloat_2_sse (gfloat * o, const gfloat * a, const gfloat * b, gint
|
|||
*(gint64*)o = _mm_cvtsi128_si64 ((__m128i)sum);
|
||||
}
|
||||
|
||||
MAKE_RESAMPLE_FUNC (gfloat, 1, sse);
|
||||
MAKE_RESAMPLE_FUNC (gfloat, 2, sse);
|
||||
MAKE_RESAMPLE_FUNC (gfloat, none, 1, sse);
|
||||
MAKE_RESAMPLE_FUNC (gfloat, none, 2, sse);
|
||||
MAKE_RESAMPLE_FUNC (gfloat, linear, 1, sse);
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_EMMINTRIN_H) && defined(__SSE2__)
|
||||
#include <emmintrin.h>
|
||||
|
||||
static inline void
|
||||
inner_product_gint16_1_sse2 (gint16 * o, const gint16 * a, const gint16 * b, gint len)
|
||||
inner_product_gint16_none_1_sse2 (gint16 * o, const gint16 * a, const gint16 * b, gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i = 0;
|
||||
__m128i sum, ta, tb;
|
||||
|
@ -101,8 +130,8 @@ inner_product_gint16_1_sse2 (gint16 * o, const gint16 * a, const gint16 * b, gin
|
|||
}
|
||||
|
||||
static inline void
|
||||
inner_product_gdouble_1_sse2 (gdouble * o, const gdouble * a, const gdouble * b,
|
||||
gint len)
|
||||
inner_product_gdouble_none_1_sse2 (gdouble * o, const gdouble * a, const gdouble * b,
|
||||
gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i = 0;
|
||||
__m128d sum = _mm_setzero_pd ();
|
||||
|
@ -126,7 +155,7 @@ inner_product_gdouble_1_sse2 (gdouble * o, const gdouble * a, const gdouble * b,
|
|||
}
|
||||
|
||||
static inline void
|
||||
inner_product_gint16_2_sse2 (gint16 * o, const gint16 * a, const gint16 * b, gint len)
|
||||
inner_product_gint16_none_2_sse2 (gint16 * o, const gint16 * a, const gint16 * b, gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i = 0;
|
||||
__m128i sum, ta, tb, t1;
|
||||
|
@ -157,8 +186,8 @@ inner_product_gint16_2_sse2 (gint16 * o, const gint16 * a, const gint16 * b, gin
|
|||
}
|
||||
|
||||
static inline void
|
||||
inner_product_gdouble_2_sse2 (gdouble * o, const gdouble * a, const gdouble * b,
|
||||
gint len)
|
||||
inner_product_gdouble_none_2_sse2 (gdouble * o, const gdouble * a, const gdouble * b,
|
||||
gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i = 0;
|
||||
__m128d sum = _mm_setzero_pd (), t;
|
||||
|
@ -183,18 +212,18 @@ inner_product_gdouble_2_sse2 (gdouble * o, const gdouble * a, const gdouble * b,
|
|||
_mm_store_pd (o, sum);
|
||||
}
|
||||
|
||||
MAKE_RESAMPLE_FUNC (gint16, 1, sse2);
|
||||
MAKE_RESAMPLE_FUNC (gdouble, 1, sse2);
|
||||
MAKE_RESAMPLE_FUNC (gint16, 2, sse2);
|
||||
MAKE_RESAMPLE_FUNC (gdouble, 2, sse2);
|
||||
MAKE_RESAMPLE_FUNC (gint16, none, 1, sse2);
|
||||
MAKE_RESAMPLE_FUNC (gdouble, none, 1, sse2);
|
||||
MAKE_RESAMPLE_FUNC (gint16, none, 2, sse2);
|
||||
MAKE_RESAMPLE_FUNC (gdouble, none, 2, sse2);
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_SMMINTRIN_H) && defined(__SSE4_1__)
|
||||
#include <smmintrin.h>
|
||||
|
||||
static inline void
|
||||
inner_product_gint32_1_sse41 (gint32 * o, const gint32 * a, const gint32 * b,
|
||||
gint len)
|
||||
inner_product_gint32_none_1_sse41 (gint32 * o, const gint32 * a, const gint32 * b,
|
||||
gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i = 0;
|
||||
__m128i sum, ta, tb;
|
||||
|
@ -230,7 +259,7 @@ inner_product_gint32_1_sse41 (gint32 * o, const gint32 * a, const gint32 * b,
|
|||
*o = CLAMP (res, -(1L << 31), (1L << 31) - 1);
|
||||
}
|
||||
|
||||
MAKE_RESAMPLE_FUNC (gint32, 1, sse41);
|
||||
MAKE_RESAMPLE_FUNC (gint32, none, 1, sse41);
|
||||
#endif
|
||||
|
||||
static void
|
||||
|
@ -239,23 +268,25 @@ audio_resampler_check_x86 (const gchar *option)
|
|||
if (!strcmp (option, "sse")) {
|
||||
#if defined (HAVE_XMMINTRIN_H) && defined(__SSE__)
|
||||
GST_DEBUG ("enable SSE optimisations");
|
||||
resample_gfloat_1 = resample_gfloat_1_sse;
|
||||
resample_gfloat_2 = resample_gfloat_2_sse;
|
||||
resample_gfloat_none_1 = resample_gfloat_none_1_sse;
|
||||
resample_gfloat_none_2 = resample_gfloat_none_2_sse;
|
||||
resample_gfloat_linear_1 = resample_gfloat_linear_1_sse;
|
||||
#endif
|
||||
} else if (!strcmp (option, "sse2")) {
|
||||
#if defined (HAVE_EMMINTRIN_H) && defined(__SSE2__)
|
||||
GST_DEBUG ("enable SSE2 optimisations");
|
||||
resample_gint16_1 = resample_gint16_1_sse2;
|
||||
resample_gfloat_1 = resample_gfloat_1_sse;
|
||||
resample_gfloat_2 = resample_gfloat_2_sse;
|
||||
resample_gdouble_1 = resample_gdouble_1_sse2;
|
||||
resample_gint16_2 = resample_gint16_2_sse2;
|
||||
resample_gdouble_2 = resample_gdouble_2_sse2;
|
||||
resample_gint16_none_1 = resample_gint16_none_1_sse2;
|
||||
resample_gfloat_none_1 = resample_gfloat_none_1_sse;
|
||||
resample_gfloat_linear_1 = resample_gfloat_linear_1_sse;
|
||||
resample_gfloat_none_2 = resample_gfloat_none_2_sse;
|
||||
resample_gdouble_none_1 = resample_gdouble_none_1_sse2;
|
||||
resample_gint16_none_2 = resample_gint16_none_2_sse2;
|
||||
resample_gdouble_none_2 = resample_gdouble_none_2_sse2;
|
||||
#endif
|
||||
} else if (!strcmp (option, "sse41")) {
|
||||
#if defined (HAVE_SMMINTRIN_H) && defined(__SSE4_1__)
|
||||
GST_DEBUG ("enable SSE41 optimisations");
|
||||
resample_gint32_1 = resample_gint32_1_sse41;
|
||||
resample_gint32_none_1 = resample_gint32_none_1_sse41;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,10 +34,6 @@
|
|||
typedef struct _Tap
|
||||
{
|
||||
gpointer taps;
|
||||
|
||||
gint sample_inc;
|
||||
gint next_phase;
|
||||
gint size;
|
||||
} Tap;
|
||||
|
||||
typedef void (*MakeTapsFunc) (GstAudioResampler * resampler, Tap * t, gint j);
|
||||
|
@ -67,10 +63,17 @@ struct _GstAudioResampler
|
|||
/* for cubic */
|
||||
gdouble b, c;
|
||||
|
||||
GstAudioResamplerFilterMode filter_mode;
|
||||
guint filter_threshold;
|
||||
GstAudioResamplerFilterInterpolation filter_interpolation;
|
||||
gint oversample;
|
||||
|
||||
guint n_taps;
|
||||
Tap *taps;
|
||||
gpointer coeff;
|
||||
gpointer coeffmem;
|
||||
guint alloc_taps;
|
||||
guint alloc_phases;
|
||||
gsize cstride;
|
||||
gpointer tmpcoeff;
|
||||
|
||||
|
@ -103,6 +106,10 @@ GST_DEBUG_CATEGORY_STATIC (audio_resampler_debug);
|
|||
*
|
||||
*/
|
||||
|
||||
static const gint oversample_qualities[] = {
|
||||
4, 4, 4, 8, 8, 16, 16, 16, 16, 32, 32
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gdouble cutoff;
|
||||
|
@ -148,7 +155,11 @@ static const BlackmanQualityMap blackman_qualities[] = {
|
|||
#define DEFAULT_QUALITY GST_AUDIO_RESAMPLER_QUALITY_DEFAULT
|
||||
#define DEFAULT_OPT_CUBIC_B 1.0
|
||||
#define DEFAULT_OPT_CUBIC_C 0.0
|
||||
#define DEFAULT_OPT_MAX_PHASE_ERROR 0.05
|
||||
#define DEFAULT_OPT_FILTER_MODE GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO
|
||||
#define DEFAULT_OPT_FILTER_MODE_THRESHOLD 1048576
|
||||
#define DEFAULT_OPT_FILTER_INTERPOLATION GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR
|
||||
#define DEFAULT_OPT_FILTER_OVERSAMPLE 8
|
||||
#define DEFAULT_OPT_MAX_PHASE_ERROR 0.1
|
||||
|
||||
static gdouble
|
||||
get_opt_double (GstStructure * options, const gchar * name, gdouble def)
|
||||
|
@ -168,6 +179,16 @@ get_opt_int (GstStructure * options, const gchar * name, gint def)
|
|||
return res;
|
||||
}
|
||||
|
||||
static gint
|
||||
get_opt_enum (GstStructure * options, const gchar * name, GType type, gint def)
|
||||
{
|
||||
gint res;
|
||||
if (!options || !gst_structure_get_enum (options, name, type, &res))
|
||||
res = def;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#define GET_OPT_CUTOFF(options,def) get_opt_double(options, \
|
||||
GST_AUDIO_RESAMPLER_OPT_CUTOFF,def)
|
||||
#define GET_OPT_DOWN_CUTOFF_FACTOR(options,def) get_opt_double(options, \
|
||||
|
@ -182,6 +203,16 @@ get_opt_int (GstStructure * options, const gchar * name, gint def)
|
|||
GST_AUDIO_RESAMPLER_OPT_CUBIC_C, DEFAULT_OPT_CUBIC_C)
|
||||
#define GET_OPT_N_TAPS(options,def) get_opt_int(options, \
|
||||
GST_AUDIO_RESAMPLER_OPT_N_TAPS, def)
|
||||
#define GET_OPT_FILTER_MODE(options) get_opt_enum(options, \
|
||||
GST_AUDIO_RESAMPLER_OPT_FILTER_MODE, GST_TYPE_AUDIO_RESAMPLER_FILTER_MODE, \
|
||||
DEFAULT_OPT_FILTER_MODE)
|
||||
#define GET_OPT_FILTER_MODE_THRESHOLD(options) get_opt_int(options, \
|
||||
GST_AUDIO_RESAMPLER_OPT_FILTER_MODE_THRESHOLD, DEFAULT_OPT_FILTER_MODE_THRESHOLD)
|
||||
#define GET_OPT_FILTER_INTERPOLATION(options) get_opt_enum(options, \
|
||||
GST_AUDIO_RESAMPLER_OPT_FILTER_INTERPOLATION, GST_TYPE_AUDIO_RESAMPLER_FILTER_INTERPOLATION, \
|
||||
DEFAULT_OPT_FILTER_INTERPOLATION)
|
||||
#define GET_OPT_FILTER_OVERSAMPLE(options) get_opt_int(options, \
|
||||
GST_AUDIO_RESAMPLER_OPT_FILTER_OVERSAMPLE, DEFAULT_OPT_FILTER_OVERSAMPLE)
|
||||
#define GET_OPT_MAX_PHASE_ERROR(options) get_opt_double(options, \
|
||||
GST_AUDIO_RESAMPLER_OPT_MAX_PHASE_ERROR, DEFAULT_OPT_MAX_PHASE_ERROR)
|
||||
|
||||
|
@ -189,7 +220,7 @@ get_opt_int (GstStructure * options, const gchar * name, gint def)
|
|||
#define bessel dbesi0
|
||||
|
||||
static inline gdouble
|
||||
get_nearest_tap (GstAudioResampler * resampler, gdouble x)
|
||||
get_nearest_tap (gdouble x)
|
||||
{
|
||||
gdouble a = fabs (x);
|
||||
|
||||
|
@ -200,11 +231,11 @@ get_nearest_tap (GstAudioResampler * resampler, gdouble x)
|
|||
}
|
||||
|
||||
static inline gdouble
|
||||
get_linear_tap (GstAudioResampler * resampler, gdouble x)
|
||||
get_linear_tap (gdouble x, gint n_taps)
|
||||
{
|
||||
gdouble a;
|
||||
|
||||
a = fabs (x) / resampler->n_taps;
|
||||
a = fabs (x) / n_taps;
|
||||
|
||||
if (a < 1.0)
|
||||
return 1.0 - a;
|
||||
|
@ -213,17 +244,14 @@ get_linear_tap (GstAudioResampler * resampler, gdouble x)
|
|||
}
|
||||
|
||||
static inline gdouble
|
||||
get_cubic_tap (GstAudioResampler * resampler, gdouble x)
|
||||
get_cubic_tap (gdouble x, gint n_taps, gdouble b, gdouble c)
|
||||
{
|
||||
gdouble a, a2, a3, b, c;
|
||||
gdouble a, a2, a3;
|
||||
|
||||
a = fabs (x * 4.0) / resampler->n_taps;
|
||||
a = fabs (x * 4.0) / n_taps;
|
||||
a2 = a * a;
|
||||
a3 = a2 * a;
|
||||
|
||||
b = resampler->b;
|
||||
c = resampler->c;
|
||||
|
||||
if (a <= 1.0)
|
||||
return ((12.0 - 9.0 * b - 6.0 * c) * a3 +
|
||||
(-18.0 + 12.0 * b + 6.0 * c) * a2 + (6.0 - 2.0 * b)) / 6.0;
|
||||
|
@ -236,33 +264,84 @@ get_cubic_tap (GstAudioResampler * resampler, gdouble x)
|
|||
}
|
||||
|
||||
static inline gdouble
|
||||
get_blackman_nuttall_tap (GstAudioResampler * resampler, gdouble x)
|
||||
get_blackman_nuttall_tap (gdouble x, gint n_taps, gdouble Fc)
|
||||
{
|
||||
gdouble s, y, w, Fc = resampler->cutoff;
|
||||
gdouble s, y, w;
|
||||
|
||||
y = G_PI * x;
|
||||
s = (y == 0.0 ? Fc : sin (y * Fc) / y);
|
||||
|
||||
w = 2.0 * y / resampler->n_taps + G_PI;
|
||||
w = 2.0 * y / n_taps + G_PI;
|
||||
return s * (0.3635819 - 0.4891775 * cos (w) + 0.1365995 * cos (2 * w) -
|
||||
0.0106411 * cos (3 * w));
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
get_kaiser_tap (GstAudioResampler * resampler, gdouble x)
|
||||
get_kaiser_tap (gdouble x, gint n_taps, gdouble Fc, gdouble beta)
|
||||
{
|
||||
gdouble s, y, w, Fc = resampler->cutoff;
|
||||
gdouble s, y, w;
|
||||
|
||||
y = G_PI * x;
|
||||
s = (y == 0.0 ? Fc : sin (y * Fc) / y);
|
||||
|
||||
w = 2.0 * x / resampler->n_taps;
|
||||
return s * bessel (resampler->kaiser_beta * sqrt (MAX (1 - w * w, 0)));
|
||||
w = 2.0 * x / n_taps;
|
||||
return s * bessel (beta * sqrt (MAX (1 - w * w, 0)));
|
||||
}
|
||||
|
||||
#define CONVERT_TAPS(type, precision) \
|
||||
G_STMT_START { \
|
||||
type *taps = res = (type *) ((gint8*)resampler->coeff + j * resampler->cstride); \
|
||||
#define PRECISION_S16 14
|
||||
#define PRECISION_S32 30
|
||||
|
||||
static inline gdouble
|
||||
fill_taps (GstAudioResampler * resampler,
|
||||
gdouble * tmpcoeff, gdouble x, gint n_taps, gint oversample)
|
||||
{
|
||||
gdouble weight = 0.0;
|
||||
gint i;
|
||||
|
||||
switch (resampler->method) {
|
||||
case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
|
||||
for (i = 0; i < n_taps; i++)
|
||||
weight += tmpcoeff[i] = get_nearest_tap (x + i / (double) oversample);
|
||||
break;
|
||||
|
||||
case GST_AUDIO_RESAMPLER_METHOD_LINEAR:
|
||||
for (i = 0; i < n_taps; i++)
|
||||
weight += tmpcoeff[i] =
|
||||
get_linear_tap (x + i / (double) oversample, resampler->n_taps);
|
||||
break;
|
||||
|
||||
case GST_AUDIO_RESAMPLER_METHOD_CUBIC:
|
||||
for (i = 0; i < n_taps; i++)
|
||||
weight += tmpcoeff[i] =
|
||||
get_cubic_tap (x + i / (double) oversample, resampler->n_taps,
|
||||
resampler->b, resampler->c);
|
||||
break;
|
||||
|
||||
case GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL:
|
||||
for (i = 0; i < n_taps; i++)
|
||||
weight += tmpcoeff[i] =
|
||||
get_blackman_nuttall_tap (x + i / (double) oversample,
|
||||
resampler->n_taps, resampler->cutoff);
|
||||
break;
|
||||
|
||||
case GST_AUDIO_RESAMPLER_METHOD_KAISER:
|
||||
for (i = 0; i < n_taps; i++)
|
||||
weight += tmpcoeff[i] =
|
||||
get_kaiser_tap (x + i / (double) oversample, resampler->n_taps,
|
||||
resampler->cutoff, resampler->kaiser_beta);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
#define MAKE_CONVERT_TAPS_INT_FUNC(type, precision) \
|
||||
static inline void \
|
||||
convert_taps_##type (gdouble *tmpcoeff, type *taps, \
|
||||
gdouble weight, gint n_taps) \
|
||||
{ \
|
||||
gdouble multiplier = (1 << precision); \
|
||||
gint i, j; \
|
||||
gdouble offset, l_offset, h_offset; \
|
||||
|
@ -294,93 +373,115 @@ G_STMT_START { \
|
|||
} \
|
||||
if (!exact) \
|
||||
GST_WARNING ("can't find exact taps"); \
|
||||
} G_STMT_END
|
||||
|
||||
#define PRECISION_S16 15
|
||||
#define PRECISION_S32 30
|
||||
|
||||
static gpointer
|
||||
make_taps (GstAudioResampler * resampler, Tap * t, gint j)
|
||||
{
|
||||
gpointer res;
|
||||
gint n_taps = resampler->n_taps;
|
||||
gdouble x, weight = 0.0;
|
||||
gdouble *tmpcoeff = resampler->tmpcoeff;
|
||||
gint tap_offs = n_taps / 2;
|
||||
gint in_rate = resampler->in_rate;
|
||||
gint out_rate = resampler->out_rate;
|
||||
gint l;
|
||||
|
||||
x = ((double) (1.0 - tap_offs) - (double) j / out_rate);
|
||||
|
||||
switch (resampler->method) {
|
||||
case GST_AUDIO_RESAMPLER_METHOD_NEAREST:
|
||||
for (l = 0; l < n_taps; l++, x += 1.0)
|
||||
weight += tmpcoeff[l] = get_nearest_tap (resampler, x);
|
||||
break;
|
||||
|
||||
case GST_AUDIO_RESAMPLER_METHOD_LINEAR:
|
||||
for (l = 0; l < n_taps; l++, x += 1.0)
|
||||
weight += tmpcoeff[l] = get_linear_tap (resampler, x);
|
||||
break;
|
||||
|
||||
case GST_AUDIO_RESAMPLER_METHOD_CUBIC:
|
||||
for (l = 0; l < n_taps; l++, x += 1.0)
|
||||
weight += tmpcoeff[l] = get_cubic_tap (resampler, x);
|
||||
break;
|
||||
|
||||
case GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL:
|
||||
for (l = 0; l < n_taps; l++, x += 1.0)
|
||||
weight += tmpcoeff[l] = get_blackman_nuttall_tap (resampler, x);
|
||||
break;
|
||||
|
||||
case GST_AUDIO_RESAMPLER_METHOD_KAISER:
|
||||
for (l = 0; l < n_taps; l++, x += 1.0)
|
||||
weight += tmpcoeff[l] = get_kaiser_tap (resampler, x);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (resampler->format) {
|
||||
case GST_AUDIO_FORMAT_F64:
|
||||
{
|
||||
gdouble *taps = res =
|
||||
(gdouble *) ((gint8 *) resampler->coeff + j * resampler->cstride);
|
||||
for (l = 0; l < n_taps; l++)
|
||||
taps[l] = tmpcoeff[l] / weight;
|
||||
break;
|
||||
}
|
||||
case GST_AUDIO_FORMAT_F32:
|
||||
{
|
||||
gfloat *taps = res =
|
||||
(gfloat *) ((gint8 *) resampler->coeff + j * resampler->cstride);
|
||||
for (l = 0; l < n_taps; l++)
|
||||
taps[l] = tmpcoeff[l] / weight;
|
||||
break;
|
||||
}
|
||||
case GST_AUDIO_FORMAT_S32:
|
||||
CONVERT_TAPS (gint32, PRECISION_S32);
|
||||
break;
|
||||
case GST_AUDIO_FORMAT_S16:
|
||||
CONVERT_TAPS (gint16, PRECISION_S16);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
if (t) {
|
||||
t->taps = res;
|
||||
t->sample_inc = (j + in_rate) / out_rate;
|
||||
t->next_phase = (j + in_rate) % out_rate;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#define MAKE_CONVERT_TAPS_FLOAT_FUNC(type) \
|
||||
static inline void \
|
||||
convert_taps_##type (gdouble *tmpcoeff, type *taps, \
|
||||
gdouble weight, gint n_taps) \
|
||||
{ \
|
||||
gint i; \
|
||||
for (i = 0; i < n_taps; i++) \
|
||||
taps[i] = tmpcoeff[i] / weight; \
|
||||
}
|
||||
|
||||
MAKE_CONVERT_TAPS_INT_FUNC (gint16, PRECISION_S16);
|
||||
MAKE_CONVERT_TAPS_INT_FUNC (gint32, PRECISION_S32);
|
||||
MAKE_CONVERT_TAPS_FLOAT_FUNC (gfloat);
|
||||
MAKE_CONVERT_TAPS_FLOAT_FUNC (gdouble);
|
||||
|
||||
#define GET_TAPS_NONE_FUNC(type) \
|
||||
static inline gpointer \
|
||||
get_taps_##type##_none (GstAudioResampler * resampler, \
|
||||
gint *samp_index, gint *samp_phase, type icoeff[4]) \
|
||||
{ \
|
||||
Tap *t = &resampler->taps[*samp_phase]; \
|
||||
gpointer res; \
|
||||
gdouble x, weight; \
|
||||
gint out_rate = resampler->out_rate; \
|
||||
gdouble *tmpcoeff = resampler->tmpcoeff; \
|
||||
gint n_taps = resampler->n_taps; \
|
||||
\
|
||||
if (G_LIKELY (t->taps)) { \
|
||||
res = t->taps; \
|
||||
} else { \
|
||||
res = (gint8 *) resampler->coeff + *samp_phase * resampler->cstride; \
|
||||
\
|
||||
x = 1.0 - n_taps / 2 - (double) *samp_phase / out_rate; \
|
||||
weight = fill_taps (resampler, tmpcoeff, x, n_taps, 1); \
|
||||
convert_taps_##type (tmpcoeff, res, weight, n_taps); \
|
||||
\
|
||||
t->taps = res; \
|
||||
} \
|
||||
*samp_index += resampler->samp_inc; \
|
||||
*samp_phase += resampler->samp_frac; \
|
||||
if (*samp_phase >= out_rate) { \
|
||||
*samp_phase -= out_rate; \
|
||||
(*samp_index)++; \
|
||||
} \
|
||||
return res; \
|
||||
}
|
||||
|
||||
GET_TAPS_NONE_FUNC (gint16);
|
||||
GET_TAPS_NONE_FUNC (gint32);
|
||||
GET_TAPS_NONE_FUNC (gfloat);
|
||||
GET_TAPS_NONE_FUNC (gdouble);
|
||||
|
||||
#define MAKE_COEFF_LINEAR_FLOAT_FUNC(type) \
|
||||
static inline void \
|
||||
make_coeff_##type##_linear (gint frac, gint out_rate, type *icoeff) \
|
||||
{ \
|
||||
type x = (type)frac / out_rate; \
|
||||
icoeff[0] = icoeff[2] = 1.0 - x; \
|
||||
icoeff[1] = icoeff[3] = x; \
|
||||
}
|
||||
#define MAKE_COEFF_LINEAR_INT_FUNC(type,type2,prec) \
|
||||
static inline void \
|
||||
make_coeff_##type##_linear (gint frac, gint out_rate, type *icoeff) \
|
||||
{ \
|
||||
type x = ((type2)frac << prec) / out_rate; \
|
||||
icoeff[0] = icoeff[2] = (1 << prec) - x; \
|
||||
icoeff[1] = icoeff[3] = x; \
|
||||
}
|
||||
|
||||
MAKE_COEFF_LINEAR_INT_FUNC (gint16, gint32, PRECISION_S16);
|
||||
MAKE_COEFF_LINEAR_INT_FUNC (gint32, gint64, PRECISION_S32);
|
||||
MAKE_COEFF_LINEAR_FLOAT_FUNC (gfloat);
|
||||
MAKE_COEFF_LINEAR_FLOAT_FUNC (gdouble);
|
||||
|
||||
#define GET_TAPS_LINEAR_FUNC(type) \
|
||||
static inline gpointer \
|
||||
get_taps_##type##_linear (GstAudioResampler * resampler, \
|
||||
gint *samp_index, gint *samp_phase, type icoeff[4]) \
|
||||
{ \
|
||||
gpointer res; \
|
||||
gint out_rate = resampler->out_rate; \
|
||||
gint offset, frac, pos; \
|
||||
\
|
||||
pos = ((out_rate - 1) - *samp_phase) * resampler->oversample; \
|
||||
offset = pos / out_rate; \
|
||||
frac = pos % out_rate; \
|
||||
\
|
||||
res = (type *)resampler->coeff + offset; \
|
||||
make_coeff_##type##_linear (frac, out_rate, icoeff); \
|
||||
\
|
||||
*samp_index += resampler->samp_inc; \
|
||||
*samp_phase += resampler->samp_frac; \
|
||||
if (*samp_phase >= out_rate) { \
|
||||
*samp_phase -= out_rate; \
|
||||
(*samp_index)++; \
|
||||
} \
|
||||
return res; \
|
||||
}
|
||||
|
||||
GET_TAPS_LINEAR_FUNC (gint16);
|
||||
GET_TAPS_LINEAR_FUNC (gint32);
|
||||
GET_TAPS_LINEAR_FUNC (gfloat);
|
||||
GET_TAPS_LINEAR_FUNC (gdouble);
|
||||
|
||||
static inline void
|
||||
inner_product_gint16_1_c (gint16 * o, const gint16 * a, const gint16 * b,
|
||||
gint len)
|
||||
inner_product_gint16_none_1_c (gint16 * o, const gint16 * a,
|
||||
const gint16 * b, gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i;
|
||||
gint32 res = 0;
|
||||
|
@ -393,8 +494,25 @@ inner_product_gint16_1_c (gint16 * o, const gint16 * a, const gint16 * b,
|
|||
}
|
||||
|
||||
static inline void
|
||||
inner_product_gint32_1_c (gint32 * o, const gint32 * a, const gint32 * b,
|
||||
gint len)
|
||||
inner_product_gint16_linear_1_c (gint16 * o, const gint16 * a, const gint16 * b,
|
||||
gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i;
|
||||
gint32 res, res1 = 0, res2 = 0;
|
||||
gint16 *ic = icoeff;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
res1 += (gint32) a[i] * (gint32) b[i * oversample];
|
||||
res2 += (gint32) a[i] * (gint32) b[i * oversample + 1];
|
||||
}
|
||||
res = (res1 >> PRECISION_S16) * ic[0] + (res2 >> PRECISION_S16) * ic[1];
|
||||
res = (res + (1 << (PRECISION_S16 - 1))) >> PRECISION_S16;
|
||||
*o = CLAMP (res, -(1L << 15), (1L << 15) - 1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
inner_product_gint32_none_1_c (gint32 * o, const gint32 * a, const gint32 * b,
|
||||
gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i;
|
||||
gint64 res = 0;
|
||||
|
@ -407,8 +525,8 @@ inner_product_gint32_1_c (gint32 * o, const gint32 * a, const gint32 * b,
|
|||
}
|
||||
|
||||
static inline void
|
||||
inner_product_gfloat_1_c (gfloat * o, const gfloat * a, const gfloat * b,
|
||||
gint len)
|
||||
inner_product_gfloat_none_1_c (gfloat * o, const gfloat * a, const gfloat * b,
|
||||
gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i;
|
||||
gfloat res = 0.0;
|
||||
|
@ -420,8 +538,24 @@ inner_product_gfloat_1_c (gfloat * o, const gfloat * a, const gfloat * b,
|
|||
}
|
||||
|
||||
static inline void
|
||||
inner_product_gdouble_1_c (gdouble * o, const gdouble * a, const gdouble * b,
|
||||
gint len)
|
||||
inner_product_gfloat_linear_1_c (gfloat * o, const gfloat * a, const gfloat * b,
|
||||
gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i;
|
||||
gfloat res, res1 = 0.0, res2 = 0.0, *ic = icoeff;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
res1 += a[i] * b[i * oversample];
|
||||
res2 += a[i] * b[i * oversample + 1];
|
||||
}
|
||||
res = res1 * ic[0] + res2 * ic[1];
|
||||
|
||||
*o = res;
|
||||
}
|
||||
|
||||
static inline void
|
||||
inner_product_gdouble_none_1_c (gdouble * o, const gdouble * a,
|
||||
const gdouble * b, gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i;
|
||||
gdouble res = 0.0;
|
||||
|
@ -432,9 +566,26 @@ inner_product_gdouble_1_c (gdouble * o, const gdouble * a, const gdouble * b,
|
|||
*o = res;
|
||||
}
|
||||
|
||||
#define MAKE_RESAMPLE_FUNC(type,channels,arch) \
|
||||
static inline void
|
||||
inner_product_gdouble_linear_1_c (gdouble * o, const gdouble * a,
|
||||
const gdouble * b, gint len, gpointer icoeff, gint oversample)
|
||||
{
|
||||
gint i;
|
||||
gdouble res, res1 = 0.0, res2 = 0.0, *ic = icoeff;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
res1 += a[i] * b[i * oversample];
|
||||
res2 += a[i] * b[i * oversample + 1];
|
||||
}
|
||||
res = res1 * ic[0] + res2 * ic[1];
|
||||
|
||||
*o = res;
|
||||
}
|
||||
|
||||
|
||||
#define MAKE_RESAMPLE_FUNC(type,inter,channels,arch) \
|
||||
static void \
|
||||
resample_ ##type## _ ##channels## _ ##arch (GstAudioResampler * resampler, \
|
||||
resample_ ##type## _ ##inter## _ ##channels## _ ##arch (GstAudioResampler * resampler, \
|
||||
gpointer in[], gsize in_len, gpointer out[], gsize out_len, \
|
||||
gsize * consumed) \
|
||||
{ \
|
||||
|
@ -442,6 +593,7 @@ resample_ ##type## _ ##channels## _ ##arch (GstAudioResampler * resampler,
|
|||
gint n_taps = resampler->n_taps; \
|
||||
gint blocks = resampler->blocks; \
|
||||
gint ostride = resampler->ostride; \
|
||||
gint oversample = resampler->oversample; \
|
||||
gint samp_index = 0; \
|
||||
gint samp_phase = 0; \
|
||||
\
|
||||
|
@ -453,18 +605,14 @@ resample_ ##type## _ ##channels## _ ##arch (GstAudioResampler * resampler,
|
|||
samp_phase = resampler->samp_phase; \
|
||||
\
|
||||
for (di = 0; di < out_len; di++) { \
|
||||
Tap *t = &resampler->taps[samp_phase]; \
|
||||
type *ipp = &ip[samp_index * channels]; \
|
||||
gpointer taps; \
|
||||
type *ipp, icoeff[4], *taps; \
|
||||
\
|
||||
if (G_UNLIKELY ((taps = t->taps) == NULL)) \
|
||||
taps = make_taps (resampler, t, samp_phase); \
|
||||
ipp = &ip[samp_index * channels]; \
|
||||
\
|
||||
inner_product_ ##type## _##channels##_##arch (op, ipp, taps, n_taps); \
|
||||
taps = get_taps_ ##type##_##inter (resampler, &samp_index, &samp_phase, icoeff); \
|
||||
\
|
||||
inner_product_ ##type##_##inter##_##channels##_##arch (op, ipp, taps, n_taps, &icoeff,oversample); \
|
||||
op += ostride; \
|
||||
\
|
||||
samp_phase = t->next_phase; \
|
||||
samp_index += t->sample_inc; \
|
||||
} \
|
||||
memmove (ip, &ip[samp_index * channels], \
|
||||
(in_len - samp_index) * sizeof(type) * channels); \
|
||||
|
@ -475,30 +623,47 @@ resample_ ##type## _ ##channels## _ ##arch (GstAudioResampler * resampler,
|
|||
resampler->samp_phase = samp_phase; \
|
||||
}
|
||||
|
||||
MAKE_RESAMPLE_FUNC (gint16, 1, c);
|
||||
MAKE_RESAMPLE_FUNC (gint32, 1, c);
|
||||
MAKE_RESAMPLE_FUNC (gfloat, 1, c);
|
||||
MAKE_RESAMPLE_FUNC (gdouble, 1, c);
|
||||
MAKE_RESAMPLE_FUNC (gint16, none, 1, c);
|
||||
MAKE_RESAMPLE_FUNC (gint32, none, 1, c);
|
||||
MAKE_RESAMPLE_FUNC (gfloat, none, 1, c);
|
||||
MAKE_RESAMPLE_FUNC (gdouble, none, 1, c);
|
||||
|
||||
MAKE_RESAMPLE_FUNC (gint16, linear, 1, c);
|
||||
MAKE_RESAMPLE_FUNC (gfloat, linear, 1, c);
|
||||
|
||||
static ResampleFunc resample_funcs[] = {
|
||||
resample_gint16_1_c,
|
||||
resample_gint32_1_c,
|
||||
resample_gfloat_1_c,
|
||||
resample_gdouble_1_c,
|
||||
resample_gint16_none_1_c,
|
||||
resample_gint32_none_1_c,
|
||||
resample_gfloat_none_1_c,
|
||||
resample_gdouble_none_1_c,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
resample_gint16_linear_1_c,
|
||||
NULL,
|
||||
resample_gfloat_linear_1_c,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#define resample_gint16_1 resample_funcs[0]
|
||||
#define resample_gint32_1 resample_funcs[1]
|
||||
#define resample_gfloat_1 resample_funcs[2]
|
||||
#define resample_gdouble_1 resample_funcs[3]
|
||||
#define resample_gint16_2 resample_funcs[4]
|
||||
#define resample_gint32_2 resample_funcs[5]
|
||||
#define resample_gfloat_2 resample_funcs[6]
|
||||
#define resample_gdouble_2 resample_funcs[7]
|
||||
#define resample_gint16_none_1 resample_funcs[0]
|
||||
#define resample_gint32_none_1 resample_funcs[1]
|
||||
#define resample_gfloat_none_1 resample_funcs[2]
|
||||
#define resample_gdouble_none_1 resample_funcs[3]
|
||||
#define resample_gint16_none_2 resample_funcs[4]
|
||||
#define resample_gint32_none_2 resample_funcs[5]
|
||||
#define resample_gfloat_none_2 resample_funcs[6]
|
||||
#define resample_gdouble_none_2 resample_funcs[7]
|
||||
|
||||
#define resample_gint16_linear_1 resample_funcs[8]
|
||||
#define resample_gint32_linear_1 resample_funcs[9]
|
||||
#define resample_gfloat_linear_1 resample_funcs[10]
|
||||
#define resample_gdouble_linear_1 resample_funcs[11]
|
||||
|
||||
#if defined HAVE_ORC && !defined DISABLE_ORC
|
||||
# if defined (__i386__) || defined (__x86_64__)
|
||||
|
@ -571,6 +736,13 @@ MAKE_DEINTERLEAVE_FUNC (gfloat);
|
|||
MAKE_DEINTERLEAVE_FUNC (gint32);
|
||||
MAKE_DEINTERLEAVE_FUNC (gint16);
|
||||
|
||||
static DeinterleaveFunc deinterleave_funcs[] = {
|
||||
deinterleave_gint16,
|
||||
deinterleave_gint32,
|
||||
deinterleave_gfloat,
|
||||
deinterleave_gdouble
|
||||
};
|
||||
|
||||
static void
|
||||
deinterleave_copy (GstAudioResampler * resampler, gpointer sbuf[],
|
||||
gpointer in[], gsize in_frames)
|
||||
|
@ -630,15 +802,34 @@ calculate_kaiser_params (GstAudioResampler * resampler)
|
|||
resampler->n_taps, resampler->cutoff);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
alloc_coeff_mem (GstAudioResampler * resampler, gint bps, gint n_taps,
|
||||
gint n_phases)
|
||||
{
|
||||
if (resampler->alloc_taps >= n_taps && resampler->alloc_phases >= n_phases)
|
||||
return FALSE;
|
||||
|
||||
resampler->tmpcoeff =
|
||||
g_realloc_n (resampler->tmpcoeff, n_taps, sizeof (gdouble));
|
||||
|
||||
resampler->cstride = GST_ROUND_UP_32 (bps * (n_taps + TAPS_OVERREAD));
|
||||
g_free (resampler->coeffmem);
|
||||
resampler->coeffmem = g_malloc0 (n_phases * resampler->cstride + ALIGN - 1);
|
||||
resampler->coeff = MEM_ALIGN (resampler->coeffmem, ALIGN);
|
||||
resampler->alloc_taps = n_taps;
|
||||
resampler->alloc_phases = n_phases;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
resampler_calculate_taps (GstAudioResampler * resampler)
|
||||
{
|
||||
gint bps;
|
||||
gint j;
|
||||
gint n_taps;
|
||||
gint out_rate;
|
||||
gint in_rate;
|
||||
gboolean non_interleaved;
|
||||
gint in_rate, index, oversample;
|
||||
gboolean non_interleaved, interpolate;
|
||||
DeinterleaveFunc deinterleave;
|
||||
ResampleFunc resample, resample_2;
|
||||
|
||||
|
@ -669,11 +860,25 @@ resampler_calculate_taps (GstAudioResampler * resampler)
|
|||
in_rate = resampler->in_rate;
|
||||
out_rate = resampler->out_rate;
|
||||
|
||||
oversample = GET_OPT_FILTER_OVERSAMPLE (resampler->options);
|
||||
|
||||
if (out_rate < in_rate) {
|
||||
gint mult = 2;
|
||||
|
||||
resampler->cutoff = resampler->cutoff * out_rate / in_rate;
|
||||
resampler->n_taps =
|
||||
gst_util_uint64_scale_int (resampler->n_taps, in_rate, out_rate);
|
||||
|
||||
while (oversample > 1) {
|
||||
if (mult * out_rate >= in_rate)
|
||||
break;
|
||||
|
||||
mult *= 2;
|
||||
oversample >>= 1;
|
||||
}
|
||||
}
|
||||
resampler->oversample = oversample;
|
||||
|
||||
/* only round up for bigger taps, the small taps are used for nearest,
|
||||
* linear and cubic and we want to use less taps for those. */
|
||||
if (resampler->n_taps > 4)
|
||||
|
@ -682,84 +887,146 @@ resampler_calculate_taps (GstAudioResampler * resampler)
|
|||
n_taps = resampler->n_taps;
|
||||
bps = resampler->bps;
|
||||
|
||||
GST_LOG ("using n_taps %d cutoff %f", n_taps, resampler->cutoff);
|
||||
GST_LOG ("using n_taps %d cutoff %f, oversample %d", n_taps,
|
||||
resampler->cutoff, oversample);
|
||||
|
||||
resampler->taps = g_realloc_n (resampler->taps, out_rate, sizeof (Tap));
|
||||
resampler->filter_mode = GET_OPT_FILTER_MODE (resampler->options);
|
||||
resampler->filter_threshold =
|
||||
GET_OPT_FILTER_MODE_THRESHOLD (resampler->options);
|
||||
|
||||
resampler->cstride = GST_ROUND_UP_32 (bps * (n_taps + TAPS_OVERREAD));
|
||||
g_free (resampler->coeffmem);
|
||||
resampler->coeffmem = g_malloc0 (out_rate * resampler->cstride + ALIGN - 1);
|
||||
resampler->coeff = MEM_ALIGN (resampler->coeffmem, ALIGN);
|
||||
switch (resampler->filter_mode) {
|
||||
case GST_AUDIO_RESAMPLER_FILTER_MODE_INTERPOLATED:
|
||||
interpolate = TRUE;
|
||||
break;
|
||||
case GST_AUDIO_RESAMPLER_FILTER_MODE_FULL:
|
||||
interpolate = FALSE;
|
||||
break;
|
||||
default:
|
||||
case GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO:
|
||||
if (out_rate <= oversample) {
|
||||
/* don't interpolate if we need to calculate at least the same amount
|
||||
* of filter coefficients than the full table case */
|
||||
interpolate = FALSE;
|
||||
} else {
|
||||
interpolate = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
resampler->tmpcoeff =
|
||||
g_realloc_n (resampler->tmpcoeff, n_taps, sizeof (gdouble));
|
||||
if (interpolate) {
|
||||
gint otaps = oversample * n_taps + 1;
|
||||
GstAudioResamplerFilterInterpolation filter_interpolation =
|
||||
GET_OPT_FILTER_INTERPOLATION (resampler->options);
|
||||
|
||||
/* if we're asked to intepolate but no interpolation was given, */
|
||||
if (filter_interpolation == GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE)
|
||||
resampler->filter_interpolation = DEFAULT_OPT_FILTER_INTERPOLATION;
|
||||
else
|
||||
resampler->filter_interpolation = filter_interpolation;
|
||||
|
||||
if (alloc_coeff_mem (resampler, bps, otaps, 1)) {
|
||||
gpointer coeff = (gint8 *) resampler->coeff;
|
||||
gdouble *tmpcoeff = resampler->tmpcoeff;
|
||||
gdouble x, weight;
|
||||
|
||||
x = 1.0 - n_taps / 2;
|
||||
weight = fill_taps (resampler, tmpcoeff, x, otaps, oversample);
|
||||
|
||||
switch (resampler->format) {
|
||||
case GST_AUDIO_FORMAT_S16:
|
||||
convert_taps_gint16 (tmpcoeff, coeff, weight / oversample, otaps);
|
||||
break;
|
||||
case GST_AUDIO_FORMAT_S32:
|
||||
convert_taps_gint32 (tmpcoeff, coeff, weight / oversample, otaps);
|
||||
break;
|
||||
case GST_AUDIO_FORMAT_F32:
|
||||
convert_taps_gfloat (tmpcoeff, coeff, weight / oversample, otaps);
|
||||
break;
|
||||
default:
|
||||
case GST_AUDIO_FORMAT_F64:
|
||||
convert_taps_gdouble (tmpcoeff, coeff, weight / oversample, otaps);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resampler->filter_interpolation =
|
||||
GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE;
|
||||
resampler->taps = g_realloc_n (resampler->taps, out_rate, sizeof (Tap));
|
||||
memset (resampler->taps, 0, sizeof (Tap) * out_rate);
|
||||
alloc_coeff_mem (resampler, bps, n_taps, out_rate);
|
||||
}
|
||||
|
||||
resampler->samp_inc = in_rate / out_rate;
|
||||
resampler->samp_frac = in_rate % out_rate;
|
||||
|
||||
for (j = 0; j < out_rate; j++) {
|
||||
Tap *t = &resampler->taps[j];
|
||||
t->taps = NULL;
|
||||
}
|
||||
|
||||
non_interleaved =
|
||||
(resampler->flags & GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED);
|
||||
|
||||
resampler->ostride = non_interleaved ? 1 : resampler->channels;
|
||||
|
||||
/* we resample each channel separately */
|
||||
resampler->blocks = resampler->channels;
|
||||
resampler->inc = 1;
|
||||
|
||||
switch (resampler->format) {
|
||||
case GST_AUDIO_FORMAT_S16:
|
||||
resample = resample_gint16_1;
|
||||
resample_2 = resample_gint16_2;
|
||||
deinterleave = deinterleave_gint16;
|
||||
index = 0;
|
||||
break;
|
||||
case GST_AUDIO_FORMAT_S32:
|
||||
resample = resample_gint32_1;
|
||||
resample_2 = resample_gint32_2;
|
||||
deinterleave = deinterleave_gint32;
|
||||
index = 1;
|
||||
break;
|
||||
case GST_AUDIO_FORMAT_F32:
|
||||
resample = resample_gfloat_1;
|
||||
resample_2 = resample_gfloat_2;
|
||||
deinterleave = deinterleave_gfloat;
|
||||
index = 2;
|
||||
break;
|
||||
case GST_AUDIO_FORMAT_F64:
|
||||
resample = resample_gdouble_1;
|
||||
resample_2 = resample_gdouble_2;
|
||||
deinterleave = deinterleave_gdouble;
|
||||
index = 3;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
deinterleave = deinterleave_funcs[index];
|
||||
|
||||
switch (resampler->filter_interpolation) {
|
||||
default:
|
||||
case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE:
|
||||
break;
|
||||
case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR:
|
||||
index += 8;
|
||||
break;
|
||||
case GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC:
|
||||
index += 16;
|
||||
break;
|
||||
}
|
||||
resample = resample_funcs[index];
|
||||
resample_2 = resample_funcs[index + 4];
|
||||
|
||||
if (!non_interleaved && resampler->channels == 2 && n_taps >= 4 && resample_2) {
|
||||
/* we resample 2 channels in parallel */
|
||||
resampler->resample = resample_2;
|
||||
resampler->deinterleave = deinterleave_copy;
|
||||
resampler->blocks = 1;
|
||||
resampler->inc = resampler->channels;;
|
||||
} else {
|
||||
/* we resample each channel separately */
|
||||
resampler->resample = resample;
|
||||
resampler->deinterleave = deinterleave;
|
||||
resampler->blocks = resampler->channels;
|
||||
resampler->inc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define PRINT_TAPS(type,print) \
|
||||
G_STMT_START { \
|
||||
type sum = 0.0, *taps; \
|
||||
\
|
||||
if ((taps = t->taps) == NULL) \
|
||||
taps = make_taps (resampler, t, i); \
|
||||
\
|
||||
for (j = 0; j < n_taps; j++) { \
|
||||
type tap = taps[j]; \
|
||||
fprintf (stderr, "\t%" print " ", tap); \
|
||||
sum += tap; \
|
||||
} \
|
||||
fprintf (stderr, "\t: sum %" print "\n", sum);\
|
||||
#define PRINT_TAPS(type,print) \
|
||||
G_STMT_START { \
|
||||
type sum = 0.0, *taps; \
|
||||
type icoeff[4]; \
|
||||
gint samp_index = 0, samp_phase = i; \
|
||||
\
|
||||
taps = get_taps_##type##_none (resampler, &samp_index,\
|
||||
&samp_phase, icoeff); \
|
||||
\
|
||||
for (j = 0; j < n_taps; j++) { \
|
||||
type tap = taps[j]; \
|
||||
fprintf (stderr, "\t%" print " ", tap); \
|
||||
sum += tap; \
|
||||
} \
|
||||
fprintf (stderr, "\t: sum %" print "\n", sum); \
|
||||
} G_STMT_END
|
||||
|
||||
static void
|
||||
|
@ -778,9 +1045,8 @@ resampler_dump (GstAudioResampler * resampler)
|
|||
|
||||
for (i = 0; i < out_rate; i++) {
|
||||
gint j;
|
||||
Tap *t = &resampler->taps[i];
|
||||
|
||||
fprintf (stderr, "%u: %d %d\t ", i, t->sample_inc, t->next_phase);
|
||||
//fprintf (stderr, "%u: %d %d\t ", i, t->sample_inc, t->next_phase);
|
||||
switch (resampler->format) {
|
||||
case GST_AUDIO_FORMAT_F64:
|
||||
PRINT_TAPS (gdouble, "f");
|
||||
|
@ -861,6 +1127,9 @@ gst_audio_resampler_options_set_quality (GstAudioResamplerMethod method,
|
|||
break;
|
||||
}
|
||||
}
|
||||
gst_structure_set (options,
|
||||
GST_AUDIO_RESAMPLER_OPT_FILTER_OVERSAMPLE, G_TYPE_INT,
|
||||
oversample_qualities[quality], NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -112,12 +112,43 @@ typedef enum {
|
|||
*/
|
||||
#define GST_AUDIO_RESAMPLER_OPT_FILTER_MODE_THRESHOLD "GstAudioResampler.filter-mode-threshold"
|
||||
|
||||
/**
|
||||
* GstAudioResamplerFilterInterpolation:
|
||||
* @GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE: no interpolation
|
||||
* @GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR: linear interpolation of the
|
||||
* filter coeficients.
|
||||
* @GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC: cubic interpolation of the
|
||||
* filter coeficients.
|
||||
*
|
||||
* The different filter interpolation methods.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE = (0),
|
||||
GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR,
|
||||
GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC,
|
||||
} GstAudioResamplerFilterInterpolation;
|
||||
/**
|
||||
* GST_AUDIO_RESAMPLER_OPT_FILTER_INTERPOLATION:
|
||||
*
|
||||
* GST_TYPE_AUDIO_RESAMPLER_INTERPOLATION: how the filter coeficients should be
|
||||
* interpolated.
|
||||
* GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR is default.
|
||||
*/
|
||||
#define GST_AUDIO_RESAMPLER_OPT_FILTER_INTERPOLATION "GstAudioResampler.filter-interpolation"
|
||||
/**
|
||||
* GST_AUDIO_RESAMPLER_OPT_FILTER_OVERSAMPLE
|
||||
*
|
||||
* G_TYPE_UINT, oversampling to use when interpolating filters
|
||||
* 8 is the default.
|
||||
*/
|
||||
#define GST_AUDIO_RESAMPLER_OPT_FILTER_OVERSAMPLE "GstAudioResampler.filter-oversample"
|
||||
|
||||
/**
|
||||
* GST_AUDIO_RESAMPLER_OPT_MAX_PHASE_ERROR:
|
||||
*
|
||||
* G_TYPE_DOUBLE: The maximum allowed phase error when switching sample
|
||||
* rates.
|
||||
* 0.02 is the default.
|
||||
* 0.05 is the default.
|
||||
*/
|
||||
#define GST_AUDIO_RESAMPLER_OPT_MAX_PHASE_ERROR "GstAudioResampler.max-phase-error"
|
||||
|
||||
|
|
Loading…
Reference in a new issue