Limit the delay by a new max-delay property

Introduce a new max-delay property that can only
be set before going to PLAYING or PAUSED. This
is used to limit the maximum delay and is set
to the current delay by default.

Using this will make sure that we have enough data
in our internal ringbuffer for the echo. With dynamic
reallocation of the ringbuffer as used before silence
could've been used as the echo directly after setting
a new delay.
This commit is contained in:
Sebastian Dröge 2009-01-28 15:57:20 +01:00
parent 4be55825c3
commit 1f32369451
2 changed files with 55 additions and 40 deletions

View file

@ -27,7 +27,11 @@
* *
* For getting an echo effect you have to set the delay to a larger value, * For getting an echo effect you have to set the delay to a larger value,
* for example 200ms and more. Everything below will result in a simple * for example 200ms and more. Everything below will result in a simple
* reverb effect, which results in a slightly metallic sounding. * reverb effect, which results in a slightly metallic sound.
*
* Use the max-delay property to set the maximum amount of delay that
* will be used. This can only be set before going to the PAUSED or PLAYING
* state and will be set to the current delay by default.
* *
* <refsect2> * <refsect2>
* <title>Example launch line</title> * <title>Example launch line</title>
@ -57,6 +61,7 @@ enum
{ {
PROP_0, PROP_0,
PROP_DELAY, PROP_DELAY,
PROP_MAX_DELAY,
PROP_INTENSITY, PROP_INTENSITY,
PROP_FEEDBACK PROP_FEEDBACK
}; };
@ -123,10 +128,17 @@ gst_audio_echo_class_init (GstAudioEchoClass * klass)
g_object_class_install_property (gobject_class, PROP_DELAY, g_object_class_install_property (gobject_class, PROP_DELAY,
g_param_spec_uint64 ("delay", "Delay", g_param_spec_uint64 ("delay", "Delay",
"Delay of the echo in nanosecondsecho", 1, G_MAXUINT64, "Delay of the echo in nanoseconds", 1, G_MAXUINT64,
1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
| GST_PARAM_CONTROLLABLE)); | GST_PARAM_CONTROLLABLE));
g_object_class_install_property (gobject_class, PROP_MAX_DELAY,
g_param_spec_uint64 ("max-delay", "Maximum Delay",
"Maximum delay of the echo in nanoseconds"
" (can't be changed in PLAYING or PAUSED state)",
1, G_MAXUINT64, 1,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
g_object_class_install_property (gobject_class, PROP_INTENSITY, g_object_class_install_property (gobject_class, PROP_INTENSITY,
g_param_spec_float ("intensity", "Intensity", g_param_spec_float ("intensity", "Intensity",
"Intensity of the echo", 0.0, 1.0, "Intensity of the echo", 0.0, 1.0,
@ -149,6 +161,7 @@ static void
gst_audio_echo_init (GstAudioEcho * self, GstAudioEchoClass * klass) gst_audio_echo_init (GstAudioEcho * self, GstAudioEchoClass * klass)
{ {
self->delay = 1; self->delay = 1;
self->max_delay = 1;
self->intensity = 0.0; self->intensity = 0.0;
self->feedback = 0.0; self->feedback = 0.0;
@ -174,45 +187,38 @@ gst_audio_echo_set_property (GObject * object, guint prop_id,
switch (prop_id) { switch (prop_id) {
case PROP_DELAY:{ case PROP_DELAY:{
guint rate, width, channels; guint max_delay, delay;
GST_BASE_TRANSFORM_LOCK (self); GST_BASE_TRANSFORM_LOCK (self);
self->delay = g_value_get_uint64 (value); delay = g_value_get_uint64 (value);
max_delay = self->max_delay;
rate = GST_AUDIO_FILTER (self)->format.rate; if (delay > max_delay && GST_STATE (self) > GST_STATE_READY) {
width = GST_AUDIO_FILTER (self)->format.width / 8; GST_WARNING_OBJECT (self, "New delay (%" GST_TIME_FORMAT ") "
channels = GST_AUDIO_FILTER (self)->format.channels; "is larger than maximum delay (%" GST_TIME_FORMAT ")",
GST_TIME_ARGS (delay), GST_TIME_ARGS (max_delay));
if (self->buffer && rate > 0) { self->delay = max_delay;
guint new_echo = } else {
MAX (gst_util_uint64_scale (self->delay, rate, GST_SECOND), 1); self->delay = delay;
guint new_size_frames = MAX (new_echo, self->max_delay = MAX (delay, max_delay);
gst_util_uint64_scale (self->delay + (GST_SECOND -
self->delay % GST_SECOND), rate, GST_SECOND));
guint new_size = new_size_frames * width * channels;
if (new_size > self->buffer_size) {
guint i;
guint8 *old_buffer = self->buffer;
self->buffer_size = new_size;
self->buffer = g_malloc0 (new_size);
for (i = 0; i < self->buffer_size_frames; i++) {
memcpy (&self->buffer[i * width * channels],
&old_buffer[((i +
self->buffer_pos) % self->buffer_size_frames) *
width * channels], channels * width);
} }
self->buffer_size_frames = new_size_frames; GST_BASE_TRANSFORM_UNLOCK (self);
self->delay_frames = new_echo;
self->buffer_pos = 0;
}
} else if (self->buffer) {
g_free (self->buffer);
self->buffer = NULL;
} }
break;
case PROP_MAX_DELAY:{
guint max_delay, delay;
GST_BASE_TRANSFORM_LOCK (self);
max_delay = g_value_get_uint64 (value);
delay = self->delay;
if (GST_STATE (self) > GST_STATE_READY) {
GST_ERROR_OBJECT (self, "Can't change maximum delay in"
" PLAYING or PAUSED state");
} else {
self->delay = delay;
self->max_delay = max_delay;
}
GST_BASE_TRANSFORM_UNLOCK (self); GST_BASE_TRANSFORM_UNLOCK (self);
} }
break; break;
@ -246,6 +252,11 @@ gst_audio_echo_get_property (GObject * object, guint prop_id,
g_value_set_uint64 (value, self->delay); g_value_set_uint64 (value, self->delay);
GST_BASE_TRANSFORM_UNLOCK (self); GST_BASE_TRANSFORM_UNLOCK (self);
break; break;
case PROP_MAX_DELAY:
GST_BASE_TRANSFORM_LOCK (self);
g_value_set_uint64 (value, self->max_delay);
GST_BASE_TRANSFORM_UNLOCK (self);
break;
case PROP_INTENSITY: case PROP_INTENSITY:
GST_BASE_TRANSFORM_LOCK (self); GST_BASE_TRANSFORM_LOCK (self);
g_value_set_float (value, self->intensity); g_value_set_float (value, self->intensity);
@ -363,13 +374,16 @@ gst_audio_echo_transform_ip (GstBaseTransform * base, GstBuffer * buf)
self->delay_frames = self->delay_frames =
MAX (gst_util_uint64_scale (self->delay, rate, GST_SECOND), 1); MAX (gst_util_uint64_scale (self->delay, rate, GST_SECOND), 1);
self->buffer_size_frames = self->buffer_size_frames =
MAX (self->delay_frames, MAX (gst_util_uint64_scale (self->max_delay, rate, GST_SECOND), 1);
gst_util_uint64_scale (self->delay + (GST_SECOND -
self->delay % GST_SECOND), rate, GST_SECOND));
self->buffer_size = self->buffer_size_frames * width * channels; self->buffer_size = self->buffer_size_frames * width * channels;
self->buffer = g_malloc0 (self->buffer_size); self->buffer = g_try_malloc0 (self->buffer_size);
self->buffer_pos = 0; self->buffer_pos = 0;
if (self->buffer == NULL) {
GST_ERROR_OBJECT (self, "Failed to allocate %u bytes", self->buffer_size);
return GST_FLOW_ERROR;
}
} }
self->process (self, GST_BUFFER_DATA (buf), num_samples); self->process (self, GST_BUFFER_DATA (buf), num_samples);

View file

@ -44,6 +44,7 @@ struct _GstAudioEcho
GstAudioFilter audiofilter; GstAudioFilter audiofilter;
guint64 delay; guint64 delay;
guint64 max_delay;
gfloat intensity; gfloat intensity;
gfloat feedback; gfloat feedback;