audioamplify: Add noclip method and support for more formats

Fixes bug #585828 and #585831.
This commit is contained in:
Kipp Cannon 2009-06-19 22:20:45 +02:00 committed by Sebastian Dröge
parent 8ecd5f1a06
commit afccf53ace
2 changed files with 233 additions and 165 deletions

View file

@ -74,6 +74,7 @@ enum
METHOD_CLIP = 0,
METHOD_WRAP_NEGATIVE,
METHOD_WRAP_POSITIVE,
METHOD_NOCLIP,
NUM_METHODS
};
@ -85,12 +86,13 @@ gst_audio_amplify_clipping_method_get_type (void)
if (gtype == 0) {
static const GEnumValue values[] = {
{METHOD_CLIP, "Normal Clipping (default)", "clip"},
{METHOD_CLIP, "Normal clipping (default)", "clip"},
{METHOD_WRAP_NEGATIVE,
"Push overdriven values back from the opposite side",
"wrap-negative"},
{METHOD_WRAP_POSITIVE, "Push overdriven values back from the same side",
"wrap-positive"},
{METHOD_NOCLIP, "No clipping", "none"},
{0, NULL, NULL}
};
@ -100,7 +102,14 @@ gst_audio_amplify_clipping_method_get_type (void)
return gtype;
}
#define ALLOWED_CAPS \
#define ALLOWED_CAPS \
"audio/x-raw-int," \
" depth=(int)8," \
" width=(int)8," \
" endianness=(int)BYTE_ORDER," \
" signed=(bool)TRUE," \
" rate=(int)[1,MAX]," \
" channels=(int)[1,MAX]; " \
"audio/x-raw-int," \
" depth=(int)16," \
" width=(int)16," \
@ -108,9 +117,16 @@ gst_audio_amplify_clipping_method_get_type (void)
" signed=(bool)TRUE," \
" rate=(int)[1,MAX]," \
" channels=(int)[1,MAX]; " \
"audio/x-raw-float," \
"audio/x-raw-int," \
" depth=(int)32," \
" width=(int)32," \
" endianness=(int)BYTE_ORDER," \
" signed=(bool)TRUE," \
" rate=(int)[1,MAX]," \
" channels=(int)[1,MAX]; " \
"audio/x-raw-float," \
" width=(int){32,64}," \
" endianness=(int)BYTE_ORDER," \
" rate=(int)[1,MAX]," \
" channels=(int)[1,MAX]"
@ -120,6 +136,8 @@ gst_audio_amplify_clipping_method_get_type (void)
GST_BOILERPLATE_FULL (GstAudioAmplify, gst_audio_amplify, GstAudioFilter,
GST_TYPE_AUDIO_FILTER, DEBUG_INIT);
static gboolean gst_audio_amplify_set_process_function (GstAudioAmplify *
filter, gint clipping, gint format, gint width);
static void gst_audio_amplify_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_audio_amplify_get_property (GObject * object, guint prop_id,
@ -130,34 +148,137 @@ static gboolean gst_audio_amplify_setup (GstAudioFilter * filter,
static GstFlowReturn gst_audio_amplify_transform_ip (GstBaseTransform * base,
GstBuffer * buf);
static void gst_audio_amplify_transform_int_clip (GstAudioAmplify * filter,
gint16 * data, guint num_samples);
static void gst_audio_amplify_transform_int_wrap_negative (GstAudioAmplify *
filter, gint16 * data, guint num_samples);
static void gst_audio_amplify_transform_int_wrap_positive (GstAudioAmplify *
filter, gint16 * data, guint num_samples);
static void gst_audio_amplify_transform_float_clip (GstAudioAmplify * filter,
gfloat * data, guint num_samples);
static void gst_audio_amplify_transform_float_wrap_negative (GstAudioAmplify *
filter, gfloat * data, guint num_samples);
static void gst_audio_amplify_transform_float_wrap_positive (GstAudioAmplify *
filter, gfloat * data, guint num_samples);
#define MIN_gint8 G_MININT8
#define MAX_gint8 G_MAXINT8
#define MIN_gint16 G_MININT16
#define MAX_gint16 G_MAXINT16
#define MIN_gint32 G_MININT32
#define MAX_gint32 G_MAXINT32
/* table of processing functions: [format][clipping_method] */
static GstAudioAmplifyProcessFunc processing_functions[2][3] = {
{
(GstAudioAmplifyProcessFunc) gst_audio_amplify_transform_int_clip,
(GstAudioAmplifyProcessFunc)
gst_audio_amplify_transform_int_wrap_negative,
(GstAudioAmplifyProcessFunc)
gst_audio_amplify_transform_int_wrap_positive},
{
(GstAudioAmplifyProcessFunc) gst_audio_amplify_transform_float_clip,
(GstAudioAmplifyProcessFunc)
gst_audio_amplify_transform_float_wrap_negative,
(GstAudioAmplifyProcessFunc)
gst_audio_amplify_transform_float_wrap_positive}
};
#define MAKE_INT_FUNCS(type) \
static void \
gst_audio_amplify_transform_##type##_clip (GstAudioAmplify * filter, \
void * data, guint num_samples) \
{ \
type *d = data; \
\
while (num_samples--) { \
glong val = *d * filter->amplification; \
*d++ = CLAMP (val, MIN_##type, MAX_##type); \
} \
} \
static void \
gst_audio_amplify_transform_##type##_wrap_negative (GstAudioAmplify * filter, \
void * data, guint num_samples) \
{ \
type *d = data; \
\
while (num_samples--) { \
glong val = *d * filter->amplification; \
if (val > MAX_##type) \
val = MIN_##type + (val - MIN_##type) % ((glong) MAX_##type - \
MIN_##type); \
else if (val < MIN_##type) \
val = MAX_##type - (MAX_##type - val) % ((glong) MAX_##type - \
MIN_##type); \
*d++ = val; \
} \
} \
static void \
gst_audio_amplify_transform_##type##_wrap_positive (GstAudioAmplify * filter, \
void * data, guint num_samples) \
{ \
type *d = data; \
\
while (num_samples--) { \
glong val = *d * filter->amplification; \
do { \
if (val > MAX_##type) \
val = MAX_##type - (val - MAX_##type); \
else if (val < MIN_##type) \
val = MIN_##type + (MIN_##type - val); \
else \
break; \
} while (1); \
*d++ = val; \
} \
} \
static void \
gst_audio_amplify_transform_##type##_noclip (GstAudioAmplify * filter, \
void * data, guint num_samples) \
{ \
type *d = data; \
\
while (num_samples--) \
*d++ *= filter->amplification; \
}
#define MAKE_FLOAT_FUNCS(type) \
static void \
gst_audio_amplify_transform_##type##_clip (GstAudioAmplify * filter, \
void * data, guint num_samples) \
{ \
type *d = data; \
\
while (num_samples--) { \
type val = *d* filter->amplification; \
*d++ = CLAMP (val, -1.0, +1.0); \
} \
} \
static void \
gst_audio_amplify_transform_##type##_wrap_negative (GstAudioAmplify * \
filter, void * data, guint num_samples) \
{ \
type *d = data; \
\
while (num_samples--) { \
type val = *d * filter->amplification; \
do { \
if (val > 1.0) \
val = -1.0 + (val - 1.0); \
else if (val < -1.0) \
val = 1.0 - (1.0 - val); \
else \
break; \
} while (1); \
*d++ = val; \
} \
} \
static void \
gst_audio_amplify_transform_##type##_wrap_positive (GstAudioAmplify * filter, \
void * data, guint num_samples) \
{ \
type *d = data; \
\
while (num_samples--) { \
type val = *d* filter->amplification; \
do { \
if (val > 1.0) \
val = 1.0 - (val - 1.0); \
else if (val < -1.0) \
val = -1.0 + (-1.0 - val); \
else \
break; \
} while (1); \
*d++ = val; \
} \
} \
static void \
gst_audio_amplify_transform_##type##_noclip (GstAudioAmplify * filter, \
void * data, guint num_samples) \
{ \
type *d = data; \
\
while (num_samples--) \
*d++ *= filter->amplification; \
}
/* *INDENT-OFF* */
MAKE_INT_FUNCS (gint8)
MAKE_INT_FUNCS (gint16)
MAKE_INT_FUNCS (gint32)
MAKE_FLOAT_FUNCS (gfloat)
MAKE_FLOAT_FUNCS (gdouble)
/* GObject vmethod implementations */
@ -213,24 +334,90 @@ static void
gst_audio_amplify_init (GstAudioAmplify * filter, GstAudioAmplifyClass * klass)
{
filter->amplification = 1.0;
filter->clipping_method = METHOD_CLIP;
filter->format_index = 0;
gst_audio_amplify_set_process_function (filter, METHOD_CLIP,
GST_BUFTYPE_LINEAR, 16);
gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE);
}
static gboolean
gst_audio_amplify_set_process_function (GstAudioAmplify * filter)
static GstAudioAmplifyProcessFunc
gst_audio_amplify_process_function (gint clipping, gint format, gint width)
{
gint method_index;
static const struct {
gint format;
gint width;
gint clipping;
GstAudioAmplifyProcessFunc func;
} *p, process[] = {
{GST_BUFTYPE_FLOAT, 32, METHOD_CLIP,
gst_audio_amplify_transform_gfloat_clip},
{GST_BUFTYPE_FLOAT, 32, METHOD_WRAP_NEGATIVE,
gst_audio_amplify_transform_gfloat_wrap_negative},
{GST_BUFTYPE_FLOAT, 32, METHOD_WRAP_POSITIVE,
gst_audio_amplify_transform_gfloat_wrap_positive},
{GST_BUFTYPE_FLOAT, 32, METHOD_NOCLIP,
gst_audio_amplify_transform_gfloat_noclip},
{GST_BUFTYPE_FLOAT, 64, METHOD_CLIP,
gst_audio_amplify_transform_gdouble_clip},
{GST_BUFTYPE_FLOAT, 64, METHOD_WRAP_NEGATIVE,
gst_audio_amplify_transform_gdouble_wrap_negative},
{GST_BUFTYPE_FLOAT, 64, METHOD_WRAP_POSITIVE,
gst_audio_amplify_transform_gdouble_wrap_positive},
{GST_BUFTYPE_FLOAT, 64, METHOD_NOCLIP,
gst_audio_amplify_transform_gdouble_noclip},
{GST_BUFTYPE_LINEAR, 8, METHOD_CLIP,
gst_audio_amplify_transform_gint8_clip},
{GST_BUFTYPE_LINEAR, 8, METHOD_WRAP_NEGATIVE,
gst_audio_amplify_transform_gint8_wrap_negative},
{GST_BUFTYPE_LINEAR, 8, METHOD_WRAP_POSITIVE,
gst_audio_amplify_transform_gint8_wrap_positive},
{GST_BUFTYPE_LINEAR, 8, METHOD_NOCLIP,
gst_audio_amplify_transform_gint8_noclip},
{GST_BUFTYPE_LINEAR, 16, METHOD_CLIP,
gst_audio_amplify_transform_gint16_clip},
{GST_BUFTYPE_LINEAR, 16, METHOD_WRAP_NEGATIVE,
gst_audio_amplify_transform_gint16_wrap_negative},
{GST_BUFTYPE_LINEAR, 16, METHOD_WRAP_POSITIVE,
gst_audio_amplify_transform_gint16_wrap_positive},
{GST_BUFTYPE_LINEAR, 16, METHOD_NOCLIP,
gst_audio_amplify_transform_gint16_noclip},
{GST_BUFTYPE_LINEAR, 32, METHOD_CLIP,
gst_audio_amplify_transform_gint32_clip},
{GST_BUFTYPE_LINEAR, 32, METHOD_WRAP_NEGATIVE,
gst_audio_amplify_transform_gint32_wrap_negative},
{GST_BUFTYPE_LINEAR, 32, METHOD_WRAP_POSITIVE,
gst_audio_amplify_transform_gint32_wrap_positive},
{GST_BUFTYPE_LINEAR, 32, METHOD_NOCLIP,
gst_audio_amplify_transform_gint32_noclip},
{0, 0, 0, NULL}
};
for (p = process; p->func; p++)
if (p->format == format && p->width == width && p->clipping == clipping)
return p->func;
return NULL;
}
static gboolean
gst_audio_amplify_set_process_function (GstAudioAmplify * filter, gint
clipping_method, gint format, gint width)
{
GstAudioAmplifyProcessFunc process;
/* set processing function */
method_index = filter->clipping_method;
if (method_index >= NUM_METHODS || method_index < 0)
method_index = METHOD_CLIP;
process = gst_audio_amplify_process_function (clipping_method, format,
width);
if (!process) {
GST_DEBUG ("wrong format");
return FALSE;
}
filter->process = process;
filter->clipping_method = clipping_method;
filter->format = format;
filter->width = width;
filter->process = processing_functions[filter->format_index][method_index];
return TRUE;
}
@ -247,8 +434,8 @@ gst_audio_amplify_set_property (GObject * object, guint prop_id,
filter->amplification == 1.0);
break;
case PROP_CLIPPING_METHOD:
filter->clipping_method = g_value_get_enum (value);
gst_audio_amplify_set_process_function (filter);
gst_audio_amplify_set_process_function (filter, g_value_get_enum (value),
filter->format, filter->width);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -280,129 +467,9 @@ static gboolean
gst_audio_amplify_setup (GstAudioFilter * base, GstRingBufferSpec * format)
{
GstAudioAmplify *filter = GST_AUDIO_AMPLIFY (base);
gboolean ret;
if (format->type == GST_BUFTYPE_LINEAR && format->width == 16)
filter->format_index = 0;
else if (format->type == GST_BUFTYPE_FLOAT && format->width == 32)
filter->format_index = 1;
else
goto wrong_format;
ret = gst_audio_amplify_set_process_function (filter);
if (!ret)
GST_WARNING ("can't process input");
return ret;
wrong_format:
GST_DEBUG ("wrong format");
return FALSE;
}
static void
gst_audio_amplify_transform_int_clip (GstAudioAmplify * filter,
gint16 * data, guint num_samples)
{
gint i;
glong val;
for (i = 0; i < num_samples; i++) {
val = (*data) * filter->amplification;
*data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16);
}
}
static void
gst_audio_amplify_transform_int_wrap_negative (GstAudioAmplify * filter,
gint16 * data, guint num_samples)
{
gint i;
glong val;
for (i = 0; i < num_samples; i++) {
val = (*data) * filter->amplification;
if (val > G_MAXINT16)
val = ((val - G_MININT16) & 0xffff) + G_MININT16;
else if (val < G_MININT16)
val = ((val - G_MAXINT16) & 0xffff) + G_MAXINT16;
*data++ = val;
}
}
static void
gst_audio_amplify_transform_int_wrap_positive (GstAudioAmplify * filter,
gint16 * data, guint num_samples)
{
gint i;
glong val;
for (i = 0; i < num_samples; i++) {
val = (*data) * filter->amplification;
while (val > G_MAXINT16 || val < G_MININT16) {
if (val > G_MAXINT16)
val = G_MAXINT16 - (val - G_MAXINT16);
else if (val < G_MININT16)
val = G_MININT16 - (val - G_MININT16);
}
*data++ = val;
}
}
static void
gst_audio_amplify_transform_float_clip (GstAudioAmplify * filter,
gfloat * data, guint num_samples)
{
gint i;
gfloat val;
for (i = 0; i < num_samples; i++) {
val = (*data) * filter->amplification;
if (val > 1.0)
val = 1.0;
else if (val < -1.0)
val = -1.0;
*data++ = val;
}
}
static void
gst_audio_amplify_transform_float_wrap_negative (GstAudioAmplify * filter,
gfloat * data, guint num_samples)
{
gint i;
gfloat val;
for (i = 0; i < num_samples; i++) {
val = (*data) * filter->amplification;
while (val > 1.0 || val < -1.0) {
if (val > 1.0)
val = -1.0 + (val - 1.0);
else if (val < -1.0)
val = 1.0 + (val + 1.0);
}
*data++ = val;
}
}
static void
gst_audio_amplify_transform_float_wrap_positive (GstAudioAmplify * filter,
gfloat * data, guint num_samples)
{
gint i;
gfloat val;
for (i = 0; i < num_samples; i++) {
val = (*data) * filter->amplification;
while (val > 1.0 || val < -1.0) {
if (val > 1.0)
val = 1.0 - (val - 1.0);
else if (val < -1.0)
val = -1.0 - (val + 1.0);
}
*data++ = val;
}
return gst_audio_amplify_set_process_function (filter,
filter->clipping_method, format->type, format->width);
}
/* GstBaseTransform vmethod implementations */

View file

@ -37,7 +37,7 @@ G_BEGIN_DECLS
typedef struct _GstAudioAmplify GstAudioAmplify;
typedef struct _GstAudioAmplifyClass GstAudioAmplifyClass;
typedef void (*GstAudioAmplifyProcessFunc) (GstAudioAmplify *, guint8 *, guint);
typedef void (*GstAudioAmplifyProcessFunc) (GstAudioAmplify *, void *, guint);
struct _GstAudioAmplify
{
@ -48,7 +48,8 @@ struct _GstAudioAmplify
/* < private > */
GstAudioAmplifyProcessFunc process;
gint clipping_method;
gint format_index;
gint format;
gint width;
};
struct _GstAudioAmplifyClass