Commit c32bf052 authored by Jan Schmidt's avatar Jan Schmidt

audiofx/echo: added surround-delay and surround-mask

Add a new boolean surround-delay property that makes
audioecho just apply a delay to certain channels to create
a surround effect, rather than an echo on all
channels. This is useful when upmixing from stereo - for example.

Add a surround-mask property to control which channels
are considered surround sound channels when adding a
delay with surround-delay = true

Original patch from Jochen Henneberg <jh@henneberg-systemdesign.com>
parent 71c76e67
......@@ -32,11 +32,18 @@
* 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.
*
* audioecho can also be used to apply a configurable delay to audio channels
* by setting surround-delay=true. In that mode, it just delays "surround
* channels" by the delay amount instead of performing an echo. The
* channels that are configured surround channels for the delay are
* selected using the surround-channels mask property.
*
* <refsect2>
* <title>Example launch line</title>
* <title>Example launch lines</title>
* |[
* gst-launch-1.0 autoaudiosrc ! audioconvert ! audioecho delay=500000000 intensity=0.6 feedback=0.4 ! audioconvert ! autoaudiosink
* gst-launch-1.0 filesrc location="melo1.ogg" ! decodebin ! audioconvert ! audioecho delay=50000000 intensity=0.6 feedback=0.4 ! audioconvert ! autoaudiosink
* gst-launch-1.0 audiotestsrc ! audioconvert ! audio/x-raw,channels=4 ! audioecho surround-delay=true delay=500000000 ! audioconvert ! autoaudiosink
* ]|
* </refsect2>
*/
......@@ -55,13 +62,18 @@
#define GST_CAT_DEFAULT gst_audio_echo_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
/* Everything except the first 2 channels are considered surround */
#define DEFAULT_SURROUND_MASK ~((guint64)(0x3))
enum
{
PROP_0,
PROP_DELAY,
PROP_MAX_DELAY,
PROP_INTENSITY,
PROP_FEEDBACK
PROP_FEEDBACK,
PROP_SUR_DELAY,
PROP_SUR_MASK
};
#define ALLOWED_CAPS \
......@@ -135,6 +147,19 @@ gst_audio_echo_class_init (GstAudioEchoClass * klass)
0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
| GST_PARAM_CONTROLLABLE));
g_object_class_install_property (gobject_class, PROP_SUR_DELAY,
g_param_spec_boolean ("surround-delay", "Enable Surround Delay",
"Delay Surround Channels when TRUE instead of applying an echo effect",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
g_object_class_install_property (gobject_class, PROP_SUR_MASK,
g_param_spec_uint64 ("surround-mask", "Surround Mask",
"A bitmask of channels that are considered surround and delayed when surround-delay = TRUE",
1, G_MAXUINT64, DEFAULT_SURROUND_MASK,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
gst_element_class_set_static_metadata (gstelement_class, "Audio echo",
"Filter/Effect/Audio",
"Adds an echo or reverb effect to an audio stream",
......@@ -158,6 +183,8 @@ gst_audio_echo_init (GstAudioEcho * self)
self->max_delay = 1;
self->intensity = 0.0;
self->feedback = 0.0;
self->surdelay = FALSE;
self->surround_mask = DEFAULT_SURROUND_MASK;
g_mutex_init (&self->lock);
......@@ -242,6 +269,18 @@ gst_audio_echo_set_property (GObject * object, guint prop_id,
g_mutex_unlock (&self->lock);
break;
}
case PROP_SUR_DELAY:{
g_mutex_lock (&self->lock);
self->surdelay = g_value_get_boolean (value);
g_mutex_unlock (&self->lock);
break;
}
case PROP_SUR_MASK:{
g_mutex_lock (&self->lock);
self->surround_mask = g_value_get_uint64 (value);
g_mutex_unlock (&self->lock);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -275,6 +314,17 @@ gst_audio_echo_get_property (GObject * object, guint prop_id,
g_value_set_float (value, self->feedback);
g_mutex_unlock (&self->lock);
break;
case PROP_SUR_DELAY:
g_mutex_lock (&self->lock);
g_value_set_boolean (value, self->surdelay);
g_mutex_unlock (&self->lock);
break;
case PROP_SUR_MASK:{
g_mutex_lock (&self->lock);
g_value_set_uint64 (value, self->surround_mask);
g_mutex_unlock (&self->lock);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -347,16 +397,30 @@ gst_audio_echo_transform_##name (GstAudioEcho * self, \
guint echo0_index = ((echo_index + self->buffer_pos) % self->buffer_size_frames) * channels; \
guint echo1_index = ((echo_index + self->buffer_pos +1) % self->buffer_size_frames) * channels; \
guint rbout_index = (self->buffer_pos % self->buffer_size_frames) * channels; \
guint64 channel_mask = 1; \
for (j = 0; j < channels; j++) { \
gdouble in = data[i*channels + j]; \
gdouble echo0 = buffer[echo0_index + j]; \
gdouble echo1 = buffer[echo1_index + j]; \
gdouble echo = echo0 + (echo1-echo0)*echo_off; \
type out = in + self->intensity * echo; \
\
data[i*channels + j] = out; \
\
buffer[rbout_index + j] = in + self->feedback * echo; \
if (self->surdelay == FALSE) { \
gdouble in = data[i*channels + j]; \
gdouble echo0 = buffer[echo0_index + j]; \
gdouble echo1 = buffer[echo1_index + j]; \
gdouble echo = echo0 + (echo1-echo0)*echo_off; \
type out = in + self->intensity * echo; \
\
GST_DEBUG ( "not adding delay on Surround Channel %d", j); \
data[i*channels + j] = out; \
\
buffer[rbout_index + j] = in + self->feedback * echo; \
} else if (channel_mask & self->surround_mask) { \
gdouble in = data[i*channels + j]; \
gdouble echo0 = buffer[echo0_index + j]; \
type out = echo0; \
GST_DEBUG ( "Adding delay on Surround Channel %d", j); \
\
data[i*channels + j] = out; \
\
buffer[rbout_index + j] = in; \
} \
channel_mask <<= 1; \
} \
self->buffer_pos = (self->buffer_pos + 1) % self->buffer_size_frames; \
} \
......
......@@ -47,6 +47,8 @@ struct _GstAudioEcho
guint64 max_delay;
gfloat intensity;
gfloat feedback;
gboolean surdelay;
guint64 surround_mask;
/* < private > */
GstAudioEchoProcessFunc process;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment