scaletempo: Add support for F64

This commit is contained in:
Sebastian Dröge 2015-10-23 20:16:17 +03:00
parent cdd7091c1c
commit 1e0b9b9853
2 changed files with 86 additions and 57 deletions

View file

@ -94,6 +94,7 @@ enum
#define SUPPORTED_CAPS \ #define SUPPORTED_CAPS \
GST_STATIC_CAPS ( \ GST_STATIC_CAPS ( \
GST_AUDIO_CAPS_MAKE (GST_AUDIO_NE (F32)) "; " \ GST_AUDIO_CAPS_MAKE (GST_AUDIO_NE (F32)) "; " \
GST_AUDIO_CAPS_MAKE (GST_AUDIO_NE (F64)) "; " \
GST_AUDIO_CAPS_MAKE (GST_AUDIO_NE (S16)) \ GST_AUDIO_CAPS_MAKE (GST_AUDIO_NE (S16)) \
) )
@ -113,40 +114,44 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
G_DEFINE_TYPE_WITH_CODE (GstScaletempo, gst_scaletempo, G_DEFINE_TYPE_WITH_CODE (GstScaletempo, gst_scaletempo,
GST_TYPE_BASE_TRANSFORM, DEBUG_INIT (0)); GST_TYPE_BASE_TRANSFORM, DEBUG_INIT (0));
static guint #define CREATE_BEST_OVERLAP_OFFSET_FLOAT_FUNC(type) \
best_overlap_offset_float (GstScaletempo * st) static guint \
{ best_overlap_offset_##type (GstScaletempo * st) \
gfloat *pw, *po, *ppc, *search_start; { \
gfloat best_corr = G_MININT; g##type *pw, *po, *ppc, *search_start; \
guint best_off = 0; g##type best_corr = G_MININT; \
gint i, off; guint best_off = 0; \
gint i, off; \
pw = st->table_window; \
po = st->buf_overlap; pw = st->table_window; \
po += st->samples_per_frame; po = st->buf_overlap; \
ppc = st->buf_pre_corr; po += st->samples_per_frame; \
for (i = st->samples_per_frame; i < st->samples_overlap; i++) { ppc = st->buf_pre_corr; \
*ppc++ = *pw++ * *po++; for (i = st->samples_per_frame; i < st->samples_overlap; i++) { \
} *ppc++ = *pw++ * *po++; \
} \
search_start = (gfloat *) st->buf_queue + st->samples_per_frame; \
for (off = 0; off < st->frames_search; off++) { search_start = (g##type *) st->buf_queue + st->samples_per_frame; \
gfloat corr = 0; for (off = 0; off < st->frames_search; off++) { \
gfloat *ps = search_start; g##type corr = 0; \
ppc = st->buf_pre_corr; g##type *ps = search_start; \
for (i = st->samples_per_frame; i < st->samples_overlap; i++) { ppc = st->buf_pre_corr; \
corr += *ppc++ * *ps++; for (i = st->samples_per_frame; i < st->samples_overlap; i++) { \
} corr += *ppc++ * *ps++; \
if (corr > best_corr) { } \
best_corr = corr; if (corr > best_corr) { \
best_off = off; best_corr = corr; \
} best_off = off; \
search_start += st->samples_per_frame; } \
} search_start += st->samples_per_frame; \
} \
return best_off * st->bytes_per_frame; \
return best_off * st->bytes_per_frame; \
} }
CREATE_BEST_OVERLAP_OFFSET_FLOAT_FUNC (float);
CREATE_BEST_OVERLAP_OFFSET_FLOAT_FUNC (double);
/* buffer padding for loop optimization: sizeof(gint32) * (loop_size - 1) */ /* buffer padding for loop optimization: sizeof(gint32) * (loop_size - 1) */
#define UNROLL_PADDING (4*3) #define UNROLL_PADDING (4*3)
static guint static guint
@ -192,20 +197,24 @@ best_overlap_offset_s16 (GstScaletempo * st)
return best_off * st->bytes_per_frame; return best_off * st->bytes_per_frame;
} }
static void #define CREATE_OUTPUT_OVERLAP_FLOAT_FUNC(type) \
output_overlap_float (GstScaletempo * st, gpointer buf_out, guint bytes_off) static void \
{ output_overlap_##type (GstScaletempo * st, gpointer buf_out, guint bytes_off) \
gfloat *pout = buf_out; { \
gfloat *pb = st->table_blend; g##type *pout = buf_out; \
gfloat *po = st->buf_overlap; g##type *pb = st->table_blend; \
gfloat *pin = (gfloat *) (st->buf_queue + bytes_off); g##type *po = st->buf_overlap; \
gint i; g##type *pin = (g##type *) (st->buf_queue + bytes_off); \
for (i = 0; i < st->samples_overlap; i++) { gint i; \
*pout++ = *po - *pb++ * (*po - *pin++); for (i = 0; i < st->samples_overlap; i++) { \
po++; *pout++ = *po - *pb++ * (*po - *pin++); \
} po++; \
} \
} }
CREATE_OUTPUT_OVERLAP_FLOAT_FUNC (float);
CREATE_OUTPUT_OVERLAP_FLOAT_FUNC (double);
static void static void
output_overlap_s16 (GstScaletempo * st, gpointer buf_out, guint bytes_off) output_overlap_s16 (GstScaletempo * st, gpointer buf_out, guint bytes_off)
{ {
@ -283,12 +292,13 @@ reinit_buffers (GstScaletempo * st)
st->bytes_standing = st->bytes_stride - st->bytes_overlap; st->bytes_standing = st->bytes_stride - st->bytes_overlap;
st->samples_standing = st->bytes_standing / st->bytes_per_sample; st->samples_standing = st->bytes_standing / st->bytes_per_sample;
st->buf_overlap = g_realloc (st->buf_overlap, st->bytes_overlap); st->buf_overlap = g_realloc (st->buf_overlap, st->bytes_overlap);
st->table_blend = g_realloc (st->table_blend, st->samples_overlap * 4); /* sizeof (gint32|gfloat) */ st->table_blend =
g_realloc (st->table_blend, st->samples_overlap * st->bytes_per_sample);
if (st->bytes_overlap > prev_overlap) { if (st->bytes_overlap > prev_overlap) {
memset ((guint8 *) st->buf_overlap + prev_overlap, 0, memset ((guint8 *) st->buf_overlap + prev_overlap, 0,
st->bytes_overlap - prev_overlap); st->bytes_overlap - prev_overlap);
} }
if (st->use_int) { if (st->format == GST_AUDIO_FORMAT_S16) {
gint32 *pb = st->table_blend; gint32 *pb = st->table_blend;
gint64 blend = 0; gint64 blend = 0;
for (i = 0; i < frames_overlap; i++) { for (i = 0; i < frames_overlap; i++) {
@ -299,7 +309,7 @@ reinit_buffers (GstScaletempo * st)
blend += 65535; /* 2^16 */ blend += 65535; /* 2^16 */
} }
st->output_overlap = output_overlap_s16; st->output_overlap = output_overlap_s16;
} else { } else if (st->format == GST_AUDIO_FORMAT_F32) {
gfloat *pb = st->table_blend; gfloat *pb = st->table_blend;
gfloat t = (gfloat) frames_overlap; gfloat t = (gfloat) frames_overlap;
for (i = 0; i < frames_overlap; i++) { for (i = 0; i < frames_overlap; i++) {
@ -309,6 +319,16 @@ reinit_buffers (GstScaletempo * st)
} }
} }
st->output_overlap = output_overlap_float; st->output_overlap = output_overlap_float;
} else {
gdouble *pb = st->table_blend;
gdouble t = (gdouble) frames_overlap;
for (i = 0; i < frames_overlap; i++) {
gdouble v = i / t;
for (j = 0; j < st->samples_per_frame; j++) {
*pb++ = v;
}
}
st->output_overlap = output_overlap_double;
} }
} }
@ -318,11 +338,12 @@ reinit_buffers (GstScaletempo * st)
if (st->frames_search < 1) { /* if no search */ if (st->frames_search < 1) { /* if no search */
st->best_overlap_offset = NULL; st->best_overlap_offset = NULL;
} else { } else {
guint bytes_pre_corr = (st->samples_overlap - st->samples_per_frame) * 4; /* sizeof (gint32|gfloat) */ guint bytes_pre_corr =
(st->samples_overlap - st->samples_per_frame) * st->bytes_per_sample;
st->buf_pre_corr = st->buf_pre_corr =
g_realloc (st->buf_pre_corr, bytes_pre_corr + UNROLL_PADDING); g_realloc (st->buf_pre_corr, bytes_pre_corr + UNROLL_PADDING);
st->table_window = g_realloc (st->table_window, bytes_pre_corr); st->table_window = g_realloc (st->table_window, bytes_pre_corr);
if (st->use_int) { if (st->format == GST_AUDIO_FORMAT_S16) {
gint64 t = frames_overlap; gint64 t = frames_overlap;
gint32 n = 8589934588LL / (t * t); /* 4 * (2^31 - 1) / t^2 */ gint32 n = 8589934588LL / (t * t); /* 4 * (2^31 - 1) / t^2 */
gint32 *pw; gint32 *pw;
@ -336,7 +357,7 @@ reinit_buffers (GstScaletempo * st)
} }
} }
st->best_overlap_offset = best_overlap_offset_s16; st->best_overlap_offset = best_overlap_offset_s16;
} else { } else if (st->format == GST_AUDIO_FORMAT_F32) {
gfloat *pw = st->table_window; gfloat *pw = st->table_window;
for (i = 1; i < frames_overlap; i++) { for (i = 1; i < frames_overlap; i++) {
gfloat v = i * (frames_overlap - i); gfloat v = i * (frames_overlap - i);
@ -345,6 +366,15 @@ reinit_buffers (GstScaletempo * st)
} }
} }
st->best_overlap_offset = best_overlap_offset_float; st->best_overlap_offset = best_overlap_offset_float;
} else {
gdouble *pw = st->table_window;
for (i = 1; i < frames_overlap; i++) {
gdouble v = i * (frames_overlap - i);
for (j = 0; j < st->samples_per_frame; j++) {
*pw++ = v;
}
}
st->best_overlap_offset = best_overlap_offset_double;
} }
} }
@ -386,7 +416,7 @@ reinit_buffers (GstScaletempo * st)
(gint) (st->bytes_standing / st->bytes_per_frame), (gint) (st->bytes_standing / st->bytes_per_frame),
(gint) (st->bytes_overlap / st->bytes_per_frame), st->frames_search, (gint) (st->bytes_overlap / st->bytes_per_frame), st->frames_search,
(gint) (st->bytes_queue_max / st->bytes_per_frame), (gint) (st->bytes_queue_max / st->bytes_per_frame),
(st->use_int ? "s16" : "float")); gst_audio_format_to_string (st->format));
st->reinit_buffers = FALSE; st->reinit_buffers = FALSE;
} }
@ -535,8 +565,8 @@ gst_scaletempo_set_caps (GstBaseTransform * trans,
GstScaletempo *scaletempo = GST_SCALETEMPO (trans); GstScaletempo *scaletempo = GST_SCALETEMPO (trans);
gint width, bps, nch, rate; gint width, bps, nch, rate;
gboolean use_int;
GstAudioInfo info; GstAudioInfo info;
GstAudioFormat format;
if (!gst_audio_info_from_caps (&info, incaps)) if (!gst_audio_info_from_caps (&info, incaps))
return FALSE; return FALSE;
@ -544,7 +574,7 @@ gst_scaletempo_set_caps (GstBaseTransform * trans,
nch = GST_AUDIO_INFO_CHANNELS (&info); nch = GST_AUDIO_INFO_CHANNELS (&info);
rate = GST_AUDIO_INFO_RATE (&info); rate = GST_AUDIO_INFO_RATE (&info);
width = GST_AUDIO_INFO_WIDTH (&info); width = GST_AUDIO_INFO_WIDTH (&info);
use_int = GST_AUDIO_INFO_IS_INTEGER (&info); format = GST_AUDIO_INFO_FORMAT (&info);
bps = width / 8; bps = width / 8;
@ -552,13 +582,12 @@ gst_scaletempo_set_caps (GstBaseTransform * trans,
if (rate != scaletempo->sample_rate if (rate != scaletempo->sample_rate
|| nch != scaletempo->samples_per_frame || nch != scaletempo->samples_per_frame
|| bps != scaletempo->bytes_per_sample || bps != scaletempo->bytes_per_sample || format != scaletempo->format) {
|| use_int != scaletempo->use_int) {
scaletempo->sample_rate = rate; scaletempo->sample_rate = rate;
scaletempo->samples_per_frame = nch; scaletempo->samples_per_frame = nch;
scaletempo->bytes_per_sample = bps; scaletempo->bytes_per_sample = bps;
scaletempo->bytes_per_frame = nch * bps; scaletempo->bytes_per_frame = nch * bps;
scaletempo->use_int = use_int; scaletempo->format = format;
scaletempo->reinit_buffers = TRUE; scaletempo->reinit_buffers = TRUE;
} }

View file

@ -48,7 +48,7 @@ struct _GstScaletempo
guint ms_search; guint ms_search;
/* caps */ /* caps */
gboolean use_int; GstAudioFormat format;
guint samples_per_frame; /* AKA number of channels */ guint samples_per_frame; /* AKA number of channels */
guint bytes_per_sample; guint bytes_per_sample;
guint bytes_per_frame; guint bytes_per_frame;