gst/filter/gstlpwsinc.*: Allow choosing between hamming and blackman window. The blackman window provides a better st...

Original commit message from CVS:
* gst/filter/gstlpwsinc.c: (gst_lpwsinc_window_get_type),
(gst_lpwsinc_class_init), (gst_lpwsinc_init),
(lpwsinc_build_kernel), (lpwsinc_set_property),
(lpwsinc_get_property):
* gst/filter/gstlpwsinc.h:
Allow choosing between hamming and blackman window. The blackman
window provides a better stopband attenuation but a bit slower
rolloff.
This commit is contained in:
Sebastian Dröge 2007-08-10 04:32:47 +00:00
parent 882fd5c387
commit 982bf23b35
3 changed files with 62 additions and 3 deletions

View file

@ -1,3 +1,14 @@
2007-08-10 Sebastian Dröge <slomo@circular-chaos.org>
* gst/filter/gstlpwsinc.c: (gst_lpwsinc_window_get_type),
(gst_lpwsinc_class_init), (gst_lpwsinc_init),
(lpwsinc_build_kernel), (lpwsinc_set_property),
(lpwsinc_get_property):
* gst/filter/gstlpwsinc.h:
Allow choosing between hamming and blackman window. The blackman
window provides a better stopband attenuation but a bit slower
rolloff.
2007-08-10 Sebastian Dröge <slomo@circular-chaos.org> 2007-08-10 Sebastian Dröge <slomo@circular-chaos.org>
* gst/filter/gstlpwsinc.c: (gst_lpwsinc_mode_get_type), * gst/filter/gstlpwsinc.c: (gst_lpwsinc_mode_get_type),

View file

@ -29,7 +29,6 @@
* TODO: - Implement the convolution in place, probably only makes sense * TODO: - Implement the convolution in place, probably only makes sense
* when using FFT convolution as currently the convolution itself * when using FFT convolution as currently the convolution itself
* is probably the bottleneck. * is probably the bottleneck.
* - Allow choosing between different windows (blackman, hanning, ...)
* - Maybe allow cascading the filter to get a better stopband attenuation. * - Maybe allow cascading the filter to get a better stopband attenuation.
* Can be done by convolving a filter kernel with itself. * Can be done by convolving a filter kernel with itself.
*/ */
@ -69,7 +68,8 @@ enum
PROP_0, PROP_0,
PROP_LENGTH, PROP_LENGTH,
PROP_FREQUENCY, PROP_FREQUENCY,
PROP_MODE PROP_MODE,
PROP_WINDOW
}; };
enum enum
@ -98,6 +98,33 @@ gst_lpwsinc_mode_get_type (void)
return gtype; return gtype;
} }
enum
{
WINDOW_HAMMING = 0,
WINDOW_BLACKMAN
};
#define GST_TYPE_LPWSINC_WINDOW (gst_lpwsinc_window_get_type ())
static GType
gst_lpwsinc_window_get_type (void)
{
static GType gtype = 0;
if (gtype == 0) {
static const GEnumValue values[] = {
{WINDOW_HAMMING, "Hamming window (default)",
"hamming"},
{WINDOW_BLACKMAN, "Blackman window",
"blackman"},
{0, NULL, NULL}
};
gtype = g_enum_register_static ("GstLPWSincWindow", values);
}
return gtype;
}
#define ALLOWED_CAPS \ #define ALLOWED_CAPS \
"audio/x-raw-float," \ "audio/x-raw-float," \
" width = (int) { 32, 64 }, " \ " width = (int) { 32, 64 }, " \
@ -185,6 +212,11 @@ gst_lpwsinc_class_init (GstLPWSincClass * klass)
"Low pass or high pass mode", GST_TYPE_LPWSINC_MODE, "Low pass or high pass mode", GST_TYPE_LPWSINC_MODE,
MODE_LOW_PASS, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); MODE_LOW_PASS, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
g_object_class_install_property (gobject_class, PROP_WINDOW,
g_param_spec_enum ("window", "Window",
"Window function to use", GST_TYPE_LPWSINC_WINDOW,
WINDOW_HAMMING, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
trans_class->transform = GST_DEBUG_FUNCPTR (lpwsinc_transform); trans_class->transform = GST_DEBUG_FUNCPTR (lpwsinc_transform);
trans_class->get_unit_size = GST_DEBUG_FUNCPTR (lpwsinc_get_unit_size); trans_class->get_unit_size = GST_DEBUG_FUNCPTR (lpwsinc_get_unit_size);
GST_AUDIO_FILTER_CLASS (klass)->setup = GST_DEBUG_FUNCPTR (lpwsinc_setup); GST_AUDIO_FILTER_CLASS (klass)->setup = GST_DEBUG_FUNCPTR (lpwsinc_setup);
@ -193,6 +225,8 @@ gst_lpwsinc_class_init (GstLPWSincClass * klass)
static void static void
gst_lpwsinc_init (GstLPWSinc * self, GstLPWSincClass * g_class) gst_lpwsinc_init (GstLPWSinc * self, GstLPWSincClass * g_class)
{ {
self->mode = MODE_LOW_PASS;
self->window = WINDOW_HAMMING;
self->wing_size = 50; self->wing_size = 50;
self->frequency = 0.0; self->frequency = 0.0;
self->kernel = NULL; self->kernel = NULL;
@ -292,7 +326,11 @@ lpwsinc_build_kernel (GstLPWSinc * self)
else else
self->kernel[i] = sin (w * (i - len)) / (i - len); self->kernel[i] = sin (w * (i - len)) / (i - len);
/* windowing */ /* windowing */
if (self->window == WINDOW_HAMMING)
self->kernel[i] *= (0.54 - 0.46 * cos (M_PI * i / len)); self->kernel[i] *= (0.54 - 0.46 * cos (M_PI * i / len));
else
self->kernel[i] *=
(0.42 - 0.5 * cos (M_PI * i / len) + 0.08 * cos (2 * M_PI * i / len));
} }
/* normalize for unity gain at DC */ /* normalize for unity gain at DC */
@ -414,6 +452,12 @@ lpwsinc_set_property (GObject * object, guint prop_id, const GValue * value,
lpwsinc_build_kernel (self); lpwsinc_build_kernel (self);
GST_BASE_TRANSFORM_UNLOCK (self); GST_BASE_TRANSFORM_UNLOCK (self);
break; break;
case PROP_WINDOW:
GST_BASE_TRANSFORM_LOCK (self);
self->window = g_value_get_enum (value);
lpwsinc_build_kernel (self);
GST_BASE_TRANSFORM_UNLOCK (self);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -436,6 +480,9 @@ lpwsinc_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_MODE: case PROP_MODE:
g_value_set_enum (value, self->mode); g_value_set_enum (value, self->mode);
break; break;
case PROP_WINDOW:
g_value_set_enum (value, self->window);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;

View file

@ -67,6 +67,7 @@ struct _GstLPWSinc {
GstLPWSincProcessFunc process; GstLPWSincProcessFunc process;
gint mode; gint mode;
gint window;
gdouble frequency; gdouble frequency;
gint wing_size; /* length of a "wing" of the filter; gint wing_size; /* length of a "wing" of the filter;
actual length is 2 * wing_size + 1 */ actual length is 2 * wing_size + 1 */