mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
gst/audiofx/: Use a custom mutex for protecting the instance fields instead of the GstObject lock. Using the latter c...
Original commit message from CVS: * gst/audiofx/audiochebband.c: (gst_audio_cheb_band_class_init), (gst_audio_cheb_band_init), (gst_audio_cheb_band_finalize), (gst_audio_cheb_band_set_property): * gst/audiofx/audiochebband.h: * gst/audiofx/audiocheblimit.c: (gst_audio_cheb_limit_class_init), (gst_audio_cheb_limit_init), (gst_audio_cheb_limit_finalize), (gst_audio_cheb_limit_set_property): * gst/audiofx/audiocheblimit.h: * gst/audiofx/audiowsincband.c: (gst_audio_wsincband_class_init), (gst_audio_wsincband_init), (gst_audio_wsincband_finalize), (gst_audio_wsincband_set_property): * gst/audiofx/audiowsincband.h: * gst/audiofx/audiowsinclimit.c: (gst_audio_wsinclimit_class_init), (gst_audio_wsinclimit_init), (gst_audio_wsinclimit_finalize), (gst_audio_wsinclimit_set_property): * gst/audiofx/audiowsinclimit.h: Use a custom mutex for protecting the instance fields instead of the GstObject lock. Using the latter can lead to deadlocks, especially with the FIR filters when updating the latency.
This commit is contained in:
parent
0016658ace
commit
4b227159cb
9 changed files with 134 additions and 54 deletions
22
ChangeLog
22
ChangeLog
|
@ -1,3 +1,25 @@
|
|||
2009-01-13 Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
|
||||
* gst/audiofx/audiochebband.c: (gst_audio_cheb_band_class_init),
|
||||
(gst_audio_cheb_band_init), (gst_audio_cheb_band_finalize),
|
||||
(gst_audio_cheb_band_set_property):
|
||||
* gst/audiofx/audiochebband.h:
|
||||
* gst/audiofx/audiocheblimit.c: (gst_audio_cheb_limit_class_init),
|
||||
(gst_audio_cheb_limit_init), (gst_audio_cheb_limit_finalize),
|
||||
(gst_audio_cheb_limit_set_property):
|
||||
* gst/audiofx/audiocheblimit.h:
|
||||
* gst/audiofx/audiowsincband.c: (gst_audio_wsincband_class_init),
|
||||
(gst_audio_wsincband_init), (gst_audio_wsincband_finalize),
|
||||
(gst_audio_wsincband_set_property):
|
||||
* gst/audiofx/audiowsincband.h:
|
||||
* gst/audiofx/audiowsinclimit.c: (gst_audio_wsinclimit_class_init),
|
||||
(gst_audio_wsinclimit_init), (gst_audio_wsinclimit_finalize),
|
||||
(gst_audio_wsinclimit_set_property):
|
||||
* gst/audiofx/audiowsinclimit.h:
|
||||
Use a custom mutex for protecting the instance fields instead of
|
||||
the GstObject lock. Using the latter can lead to deadlocks, especially
|
||||
with the FIR filters when updating the latency.
|
||||
|
||||
2009-01-11 Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
|
||||
* gst/audiofx/Makefile.am:
|
||||
|
|
|
@ -113,6 +113,7 @@ static void gst_audio_cheb_band_set_property (GObject * object,
|
|||
guint prop_id, const GValue * value, GParamSpec * pspec);
|
||||
static void gst_audio_cheb_band_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec);
|
||||
static void gst_audio_cheb_band_finalize (GObject * object);
|
||||
|
||||
static gboolean gst_audio_cheb_band_setup (GstAudioFilter * filter,
|
||||
GstRingBufferSpec * format);
|
||||
|
@ -164,6 +165,7 @@ gst_audio_cheb_band_class_init (GstAudioChebBandClass * klass)
|
|||
|
||||
gobject_class->set_property = gst_audio_cheb_band_set_property;
|
||||
gobject_class->get_property = gst_audio_cheb_band_get_property;
|
||||
gobject_class->finalize = gst_audio_cheb_band_finalize;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_MODE,
|
||||
g_param_spec_enum ("mode", "Mode",
|
||||
|
@ -210,6 +212,8 @@ gst_audio_cheb_band_init (GstAudioChebBand * filter,
|
|||
filter->type = 1;
|
||||
filter->poles = 4;
|
||||
filter->ripple = 0.25;
|
||||
|
||||
filter->lock = g_mutex_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -567,6 +571,17 @@ generate_coefficients (GstAudioChebBand * filter)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_cheb_band_finalize (GObject * object)
|
||||
{
|
||||
GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
|
||||
|
||||
g_mutex_free (filter->lock);
|
||||
filter->lock = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_cheb_band_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
|
@ -575,40 +590,40 @@ gst_audio_cheb_band_set_property (GObject * object, guint prop_id,
|
|||
|
||||
switch (prop_id) {
|
||||
case PROP_MODE:
|
||||
GST_OBJECT_LOCK (filter);
|
||||
g_mutex_lock (filter->lock);
|
||||
filter->mode = g_value_get_enum (value);
|
||||
generate_coefficients (filter);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
g_mutex_unlock (filter->lock);
|
||||
break;
|
||||
case PROP_TYPE:
|
||||
GST_OBJECT_LOCK (filter);
|
||||
g_mutex_lock (filter->lock);
|
||||
filter->type = g_value_get_int (value);
|
||||
generate_coefficients (filter);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
g_mutex_unlock (filter->lock);
|
||||
break;
|
||||
case PROP_LOWER_FREQUENCY:
|
||||
GST_OBJECT_LOCK (filter);
|
||||
g_mutex_lock (filter->lock);
|
||||
filter->lower_frequency = g_value_get_float (value);
|
||||
generate_coefficients (filter);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
g_mutex_unlock (filter->lock);
|
||||
break;
|
||||
case PROP_UPPER_FREQUENCY:
|
||||
GST_OBJECT_LOCK (filter);
|
||||
g_mutex_lock (filter->lock);
|
||||
filter->upper_frequency = g_value_get_float (value);
|
||||
generate_coefficients (filter);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
g_mutex_unlock (filter->lock);
|
||||
break;
|
||||
case PROP_RIPPLE:
|
||||
GST_OBJECT_LOCK (filter);
|
||||
g_mutex_lock (filter->lock);
|
||||
filter->ripple = g_value_get_float (value);
|
||||
generate_coefficients (filter);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
g_mutex_unlock (filter->lock);
|
||||
break;
|
||||
case PROP_POLES:
|
||||
GST_OBJECT_LOCK (filter);
|
||||
g_mutex_lock (filter->lock);
|
||||
filter->poles = GST_ROUND_UP_4 (g_value_get_int (value));
|
||||
generate_coefficients (filter);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
g_mutex_unlock (filter->lock);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
|
|
|
@ -48,6 +48,9 @@ struct _GstAudioChebBand
|
|||
gfloat lower_frequency;
|
||||
gfloat upper_frequency;
|
||||
gfloat ripple;
|
||||
|
||||
/* < private > */
|
||||
GMutex *lock;
|
||||
};
|
||||
|
||||
struct _GstAudioChebBandClass
|
||||
|
|
|
@ -109,6 +109,7 @@ static void gst_audio_cheb_limit_set_property (GObject * object,
|
|||
guint prop_id, const GValue * value, GParamSpec * pspec);
|
||||
static void gst_audio_cheb_limit_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec);
|
||||
static void gst_audio_cheb_limit_finalize (GObject * object);
|
||||
|
||||
static gboolean gst_audio_cheb_limit_setup (GstAudioFilter * filter,
|
||||
GstRingBufferSpec * format);
|
||||
|
@ -161,6 +162,7 @@ gst_audio_cheb_limit_class_init (GstAudioChebLimitClass * klass)
|
|||
|
||||
gobject_class->set_property = gst_audio_cheb_limit_set_property;
|
||||
gobject_class->get_property = gst_audio_cheb_limit_get_property;
|
||||
gobject_class->finalize = gst_audio_cheb_limit_finalize;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_MODE,
|
||||
g_param_spec_enum ("mode", "Mode",
|
||||
|
@ -203,6 +205,8 @@ gst_audio_cheb_limit_init (GstAudioChebLimit * filter,
|
|||
filter->type = 1;
|
||||
filter->poles = 4;
|
||||
filter->ripple = 0.25;
|
||||
|
||||
filter->lock = g_mutex_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -478,6 +482,17 @@ generate_coefficients (GstAudioChebLimit * filter)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_cheb_limit_finalize (GObject * object)
|
||||
{
|
||||
GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (object);
|
||||
|
||||
g_mutex_free (filter->lock);
|
||||
filter->lock = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_cheb_limit_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
|
@ -486,34 +501,34 @@ gst_audio_cheb_limit_set_property (GObject * object, guint prop_id,
|
|||
|
||||
switch (prop_id) {
|
||||
case PROP_MODE:
|
||||
GST_OBJECT_LOCK (filter);
|
||||
g_mutex_lock (filter->lock);
|
||||
filter->mode = g_value_get_enum (value);
|
||||
generate_coefficients (filter);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
g_mutex_unlock (filter->lock);
|
||||
break;
|
||||
case PROP_TYPE:
|
||||
GST_OBJECT_LOCK (filter);
|
||||
g_mutex_lock (filter->lock);
|
||||
filter->type = g_value_get_int (value);
|
||||
generate_coefficients (filter);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
g_mutex_unlock (filter->lock);
|
||||
break;
|
||||
case PROP_CUTOFF:
|
||||
GST_OBJECT_LOCK (filter);
|
||||
g_mutex_lock (filter->lock);
|
||||
filter->cutoff = g_value_get_float (value);
|
||||
generate_coefficients (filter);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
g_mutex_unlock (filter->lock);
|
||||
break;
|
||||
case PROP_RIPPLE:
|
||||
GST_OBJECT_LOCK (filter);
|
||||
g_mutex_lock (filter->lock);
|
||||
filter->ripple = g_value_get_float (value);
|
||||
generate_coefficients (filter);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
g_mutex_unlock (filter->lock);
|
||||
break;
|
||||
case PROP_POLES:
|
||||
GST_OBJECT_LOCK (filter);
|
||||
g_mutex_lock (filter->lock);
|
||||
filter->poles = GST_ROUND_UP_2 (g_value_get_int (value));
|
||||
generate_coefficients (filter);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
g_mutex_unlock (filter->lock);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
|
|
|
@ -49,6 +49,9 @@ struct _GstAudioChebLimit
|
|||
gint poles;
|
||||
gfloat cutoff;
|
||||
gfloat ripple;
|
||||
|
||||
/* < private > */
|
||||
GMutex *lock;
|
||||
};
|
||||
|
||||
struct _GstAudioChebLimitClass
|
||||
|
|
|
@ -26,13 +26,6 @@
|
|||
* chapter 16
|
||||
* available at http://www.dspguide.com/
|
||||
*
|
||||
* TODO: - Implement the convolution in place, probably only makes sense
|
||||
* when using FFT convolution as currently the convolution itself
|
||||
* is probably the bottleneck
|
||||
* - Maybe allow cascading the filter to get a better stopband attenuation.
|
||||
* Can be done by convolving a filter kernel with itself
|
||||
* - Drop the first kernel_length/2 samples and append the same number of
|
||||
* samples on EOS as the first few samples are essentialy zero.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -150,6 +143,7 @@ static void gst_audio_wsincband_set_property (GObject * object, guint prop_id,
|
|||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_audio_wsincband_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_audio_wsincband_finalize (GObject * object);
|
||||
|
||||
static gboolean gst_audio_wsincband_setup (GstAudioFilter * base,
|
||||
GstRingBufferSpec * format);
|
||||
|
@ -177,6 +171,7 @@ gst_audio_wsincband_class_init (GstAudioWSincBandClass * klass)
|
|||
|
||||
gobject_class->set_property = gst_audio_wsincband_set_property;
|
||||
gobject_class->get_property = gst_audio_wsincband_get_property;
|
||||
gobject_class->finalize = gst_audio_wsincband_finalize;
|
||||
|
||||
/* FIXME: Don't use the complete possible range but restrict the upper boundary
|
||||
* so automatically generated UIs can use a slider */
|
||||
|
@ -218,6 +213,8 @@ gst_audio_wsincband_init (GstAudioWSincBand * self,
|
|||
self->upper_frequency = 0.0;
|
||||
self->mode = MODE_BAND_PASS;
|
||||
self->window = WINDOW_HAMMING;
|
||||
|
||||
self->lock = g_mutex_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -352,6 +349,17 @@ gst_audio_wsincband_setup (GstAudioFilter * base, GstRingBufferSpec * format)
|
|||
return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, format);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_wsincband_finalize (GObject * object)
|
||||
{
|
||||
GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (object);
|
||||
|
||||
g_mutex_free (self->lock);
|
||||
self->lock = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_wsincband_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
|
@ -364,7 +372,7 @@ gst_audio_wsincband_set_property (GObject * object, guint prop_id,
|
|||
case PROP_LENGTH:{
|
||||
gint val;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
g_mutex_lock (self->lock);
|
||||
val = g_value_get_int (value);
|
||||
if (val % 2 == 0)
|
||||
val++;
|
||||
|
@ -375,32 +383,32 @@ gst_audio_wsincband_set_property (GObject * object, guint prop_id,
|
|||
self->kernel_length = val;
|
||||
gst_audio_wsincband_build_kernel (self);
|
||||
}
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
g_mutex_unlock (self->lock);
|
||||
break;
|
||||
}
|
||||
case PROP_LOWER_FREQUENCY:
|
||||
GST_OBJECT_LOCK (self);
|
||||
g_mutex_lock (self->lock);
|
||||
self->lower_frequency = g_value_get_float (value);
|
||||
gst_audio_wsincband_build_kernel (self);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
g_mutex_unlock (self->lock);
|
||||
break;
|
||||
case PROP_UPPER_FREQUENCY:
|
||||
GST_OBJECT_LOCK (self);
|
||||
g_mutex_lock (self->lock);
|
||||
self->upper_frequency = g_value_get_float (value);
|
||||
gst_audio_wsincband_build_kernel (self);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
g_mutex_unlock (self->lock);
|
||||
break;
|
||||
case PROP_MODE:
|
||||
GST_OBJECT_LOCK (self);
|
||||
g_mutex_lock (self->lock);
|
||||
self->mode = g_value_get_enum (value);
|
||||
gst_audio_wsincband_build_kernel (self);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
g_mutex_unlock (self->lock);
|
||||
break;
|
||||
case PROP_WINDOW:
|
||||
GST_OBJECT_LOCK (self);
|
||||
g_mutex_lock (self->lock);
|
||||
self->window = g_value_get_enum (value);
|
||||
gst_audio_wsincband_build_kernel (self);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
g_mutex_unlock (self->lock);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
|
|
|
@ -60,11 +60,13 @@ typedef struct _GstAudioWSincBandClass GstAudioWSincBandClass;
|
|||
struct _GstAudioWSincBand {
|
||||
GstAudioFXBaseFIRFilter parent;
|
||||
|
||||
/* < private > */
|
||||
gint mode;
|
||||
gint window;
|
||||
gfloat lower_frequency, upper_frequency;
|
||||
gint kernel_length; /* length of the filter kernel */
|
||||
|
||||
/* < private > */
|
||||
GMutex *lock;
|
||||
};
|
||||
|
||||
struct _GstAudioWSincBandClass {
|
||||
|
|
|
@ -26,11 +26,6 @@
|
|||
* chapter 16
|
||||
* available at http://www.dspguide.com/
|
||||
*
|
||||
* TODO: - Implement the convolution in place, probably only makes sense
|
||||
* when using FFT convolution as currently the convolution itself
|
||||
* is probably the bottleneck
|
||||
* - Maybe allow cascading the filter to get a better stopband attenuation.
|
||||
* Can be done by convolving a filter kernel with itself
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -147,6 +142,7 @@ static void gst_audio_wsinclimit_set_property (GObject * object, guint prop_id,
|
|||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_audio_wsinclimit_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_audio_wsinclimit_finalize (GObject * object);
|
||||
|
||||
static gboolean gst_audio_wsinclimit_setup (GstAudioFilter * base,
|
||||
GstRingBufferSpec * format);
|
||||
|
@ -175,6 +171,7 @@ gst_audio_wsinclimit_class_init (GstAudioWSincLimitClass * klass)
|
|||
|
||||
gobject_class->set_property = gst_audio_wsinclimit_set_property;
|
||||
gobject_class->get_property = gst_audio_wsinclimit_get_property;
|
||||
gobject_class->finalize = gst_audio_wsinclimit_finalize;
|
||||
|
||||
/* FIXME: Don't use the complete possible range but restrict the upper boundary
|
||||
* so automatically generated UIs can use a slider */
|
||||
|
@ -211,6 +208,8 @@ gst_audio_wsinclimit_init (GstAudioWSincLimit * self,
|
|||
self->window = WINDOW_HAMMING;
|
||||
self->kernel_length = 101;
|
||||
self->cutoff = 0.0;
|
||||
|
||||
self->lock = g_mutex_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -292,6 +291,17 @@ gst_audio_wsinclimit_setup (GstAudioFilter * base, GstRingBufferSpec * format)
|
|||
return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, format);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_wsinclimit_finalize (GObject * object)
|
||||
{
|
||||
GstAudioWSincLimit *self = GST_AUDIO_WSINC_LIMIT (object);
|
||||
|
||||
g_mutex_free (self->lock);
|
||||
self->lock = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_wsinclimit_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
|
@ -304,7 +314,7 @@ gst_audio_wsinclimit_set_property (GObject * object, guint prop_id,
|
|||
case PROP_LENGTH:{
|
||||
gint val;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
g_mutex_lock (self->lock);
|
||||
val = g_value_get_int (value);
|
||||
if (val % 2 == 0)
|
||||
val++;
|
||||
|
@ -315,26 +325,26 @@ gst_audio_wsinclimit_set_property (GObject * object, guint prop_id,
|
|||
self->kernel_length = val;
|
||||
gst_audio_wsinclimit_build_kernel (self);
|
||||
}
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
g_mutex_unlock (self->lock);
|
||||
break;
|
||||
}
|
||||
case PROP_FREQUENCY:
|
||||
GST_OBJECT_LOCK (self);
|
||||
g_mutex_lock (self->lock);
|
||||
self->cutoff = g_value_get_float (value);
|
||||
gst_audio_wsinclimit_build_kernel (self);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
g_mutex_unlock (self->lock);
|
||||
break;
|
||||
case PROP_MODE:
|
||||
GST_OBJECT_LOCK (self);
|
||||
g_mutex_lock (self->lock);
|
||||
self->mode = g_value_get_enum (value);
|
||||
gst_audio_wsinclimit_build_kernel (self);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
g_mutex_unlock (self->lock);
|
||||
break;
|
||||
case PROP_WINDOW:
|
||||
GST_OBJECT_LOCK (self);
|
||||
g_mutex_lock (self->lock);
|
||||
self->window = g_value_get_enum (value);
|
||||
gst_audio_wsinclimit_build_kernel (self);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
g_mutex_unlock (self->lock);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
|
|
|
@ -60,11 +60,13 @@ typedef struct _GstAudioWSincLimitClass GstAudioWSincLimitClass;
|
|||
struct _GstAudioWSincLimit {
|
||||
GstAudioFXBaseFIRFilter parent;
|
||||
|
||||
/* < private > */
|
||||
gint mode;
|
||||
gint window;
|
||||
gfloat cutoff;
|
||||
gint kernel_length;
|
||||
|
||||
/* < private > */
|
||||
GMutex *lock;
|
||||
};
|
||||
|
||||
struct _GstAudioWSincLimitClass {
|
||||
|
|
Loading…
Reference in a new issue