gst_plugins_good/gst/audiofx/audiopanorama.c
changeset 27 d43ce56a1534
parent 23 29ecd5cb86b3
child 31 aec498aab1d3
equal deleted inserted replaced
23:29ecd5cb86b3 27:d43ce56a1534
     1 /*
       
     2  * GStreamer
       
     3  * Copyright (C) 2006 Stefan Kost <ensonic@users.sf.net>
       
     4  * Copyright (C) 2006 Sebastian Dröge <slomo@circular-chaos.org>
       
     5  *
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Library General Public
       
     8  * License as published by the Free Software Foundation; either
       
     9  * version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This library is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Library General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Library General Public
       
    17  * License along with this library; if not, write to the
       
    18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    19  * Boston, MA 02111-1307, USA.
       
    20  */
       
    21 
       
    22 /**
       
    23  * SECTION:element-audiopanorama
       
    24  *
       
    25  * Stereo panorama effect with controllable pan position. One can choose between the default psychoacoustic panning method,
       
    26  * which keeps the same perceived loudness, and a simple panning method that just controls the volume on one channel.
       
    27  *
       
    28  * <refsect2>
       
    29  * <title>Example launch line</title>
       
    30  * |[
       
    31  * gst-launch audiotestsrc wave=saw ! audiopanorama panorama=-1.00 ! alsasink
       
    32  * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiopanorama panorama=-1.00 ! alsasink
       
    33  * gst-launch audiotestsrc wave=saw ! audioconvert ! audiopanorama panorama=-1.00 ! audioconvert ! alsasink
       
    34  * gst-launch audiotestsrc wave=saw ! audioconvert ! audiopanorama method=simple panorama=-0.50 ! audioconvert ! alsasink
       
    35  * ]|
       
    36  * </refsect2>
       
    37  */
       
    38 
       
    39 #ifdef HAVE_CONFIG_H
       
    40 #include "config.h"
       
    41 #endif
       
    42 
       
    43 #include <gst/gst.h>
       
    44 #include <gst/base/gstbasetransform.h>
       
    45 #include <gst/controller/gstcontroller.h>
       
    46 
       
    47 #include "audiopanorama.h"
       
    48 
       
    49 #define GST_CAT_DEFAULT gst_audio_panorama_debug
       
    50 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
       
    51 
       
    52 static const GstElementDetails element_details =
       
    53 GST_ELEMENT_DETAILS ("Stereo positioning",
       
    54     "Filter/Effect/Audio",
       
    55     "Positions audio streams in the stereo panorama",
       
    56     "Stefan Kost <ensonic@users.sf.net>");
       
    57 
       
    58 /* Filter signals and args */
       
    59 enum
       
    60 {
       
    61   /* FILL ME */
       
    62   LAST_SIGNAL
       
    63 };
       
    64 
       
    65 enum
       
    66 {
       
    67   PROP_0,
       
    68   PROP_PANORAMA,
       
    69   PROP_METHOD
       
    70 };
       
    71 
       
    72 enum
       
    73 {
       
    74   METHOD_PSYCHOACOUSTIC = 0,
       
    75   METHOD_SIMPLE,
       
    76   NUM_METHODS
       
    77 };
       
    78 
       
    79 #define GST_TYPE_AUDIO_PANORAMA_METHOD (gst_audio_panorama_method_get_type ())
       
    80 static GType
       
    81 gst_audio_panorama_method_get_type (void)
       
    82 {
       
    83   static GType gtype = 0;
       
    84 
       
    85   if (gtype == 0) {
       
    86     static const GEnumValue values[] = {
       
    87       {METHOD_PSYCHOACOUSTIC, "Psychoacoustic Panning (default)",
       
    88           "psychoacoustic"},
       
    89       {METHOD_SIMPLE, "Simple Panning", "simple"},
       
    90       {0, NULL, NULL}
       
    91     };
       
    92 
       
    93     gtype = g_enum_register_static ("GstAudioPanoramaMethod", values);
       
    94   }
       
    95   return gtype;
       
    96 }
       
    97 
       
    98 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
       
    99     GST_PAD_SINK,
       
   100     GST_PAD_ALWAYS,
       
   101     GST_STATIC_CAPS ("audio/x-raw-float, "
       
   102         "rate = (int) [ 1, MAX ], "
       
   103         "channels = (int) [ 1, 2 ], "
       
   104         "endianness = (int) BYTE_ORDER, " "width = (int) 32; "
       
   105         "audio/x-raw-int, "
       
   106         "rate = (int) [ 1, MAX ], "
       
   107         "channels = (int) [ 1, 2 ], "
       
   108         "endianness = (int) BYTE_ORDER, "
       
   109         "width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true")
       
   110     );
       
   111 
       
   112 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
       
   113     GST_PAD_SRC,
       
   114     GST_PAD_ALWAYS,
       
   115     GST_STATIC_CAPS ("audio/x-raw-float, "
       
   116         "rate = (int) [ 1, MAX ], "
       
   117         "channels = (int) 2, "
       
   118         "endianness = (int) BYTE_ORDER, " "width = (int) 32; "
       
   119         "audio/x-raw-int, "
       
   120         "rate = (int) [ 1, MAX ], "
       
   121         "channels = (int) 2, "
       
   122         "endianness = (int) BYTE_ORDER, "
       
   123         "width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true")
       
   124     );
       
   125 
       
   126 #define DEBUG_INIT(bla) \
       
   127   GST_DEBUG_CATEGORY_INIT (gst_audio_panorama_debug, "audiopanorama", 0, "audiopanorama element");
       
   128 
       
   129 GST_BOILERPLATE_FULL (GstAudioPanorama, gst_audio_panorama, GstBaseTransform,
       
   130     GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
       
   131 
       
   132 static void gst_audio_panorama_set_property (GObject * object, guint prop_id,
       
   133     const GValue * value, GParamSpec * pspec);
       
   134 static void gst_audio_panorama_get_property (GObject * object, guint prop_id,
       
   135     GValue * value, GParamSpec * pspec);
       
   136 
       
   137 static gboolean gst_audio_panorama_get_unit_size (GstBaseTransform * base,
       
   138     GstCaps * caps, guint * size);
       
   139 static GstCaps *gst_audio_panorama_transform_caps (GstBaseTransform * base,
       
   140     GstPadDirection direction, GstCaps * caps);
       
   141 static gboolean gst_audio_panorama_set_caps (GstBaseTransform * base,
       
   142     GstCaps * incaps, GstCaps * outcaps);
       
   143 
       
   144 static void gst_audio_panorama_transform_m2s_int (GstAudioPanorama * filter,
       
   145     gint16 * idata, gint16 * odata, guint num_samples);
       
   146 static void gst_audio_panorama_transform_s2s_int (GstAudioPanorama * filter,
       
   147     gint16 * idata, gint16 * odata, guint num_samples);
       
   148 static void gst_audio_panorama_transform_m2s_float (GstAudioPanorama * filter,
       
   149     gfloat * idata, gfloat * odata, guint num_samples);
       
   150 static void gst_audio_panorama_transform_s2s_float (GstAudioPanorama * filter,
       
   151     gfloat * idata, gfloat * odata, guint num_samples);
       
   152 
       
   153 static void gst_audio_panorama_transform_m2s_int_simple (GstAudioPanorama *
       
   154     filter, gint16 * idata, gint16 * odata, guint num_samples);
       
   155 static void gst_audio_panorama_transform_s2s_int_simple (GstAudioPanorama *
       
   156     filter, gint16 * idata, gint16 * odata, guint num_samples);
       
   157 static void gst_audio_panorama_transform_m2s_float_simple (GstAudioPanorama *
       
   158     filter, gfloat * idata, gfloat * odata, guint num_samples);
       
   159 static void gst_audio_panorama_transform_s2s_float_simple (GstAudioPanorama *
       
   160     filter, gfloat * idata, gfloat * odata, guint num_samples);
       
   161 
       
   162 static GstFlowReturn gst_audio_panorama_transform (GstBaseTransform * base,
       
   163     GstBuffer * inbuf, GstBuffer * outbuf);
       
   164 
       
   165 
       
   166 /* Table with processing functions: [channels][format][method] */
       
   167 static GstAudioPanoramaProcessFunc panorama_process_functions[2][2][2] = {
       
   168   {
       
   169         {(GstAudioPanoramaProcessFunc) gst_audio_panorama_transform_m2s_int,
       
   170               (GstAudioPanoramaProcessFunc)
       
   171             gst_audio_panorama_transform_m2s_int_simple},
       
   172         {(GstAudioPanoramaProcessFunc) gst_audio_panorama_transform_m2s_float,
       
   173               (GstAudioPanoramaProcessFunc)
       
   174             gst_audio_panorama_transform_m2s_float_simple}
       
   175       },
       
   176   {
       
   177         {(GstAudioPanoramaProcessFunc) gst_audio_panorama_transform_s2s_int,
       
   178               (GstAudioPanoramaProcessFunc)
       
   179             gst_audio_panorama_transform_s2s_int_simple},
       
   180         {(GstAudioPanoramaProcessFunc) gst_audio_panorama_transform_s2s_float,
       
   181               (GstAudioPanoramaProcessFunc)
       
   182             gst_audio_panorama_transform_s2s_float_simple}
       
   183       }
       
   184 };
       
   185 
       
   186 /* GObject vmethod implementations */
       
   187 
       
   188 static void
       
   189 gst_audio_panorama_base_init (gpointer klass)
       
   190 {
       
   191   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
       
   192 
       
   193   gst_element_class_add_pad_template (element_class,
       
   194       gst_static_pad_template_get (&src_template));
       
   195   gst_element_class_add_pad_template (element_class,
       
   196       gst_static_pad_template_get (&sink_template));
       
   197   gst_element_class_set_details (element_class, &element_details);
       
   198 }
       
   199 
       
   200 static void
       
   201 gst_audio_panorama_class_init (GstAudioPanoramaClass * klass)
       
   202 {
       
   203   GObjectClass *gobject_class;
       
   204 
       
   205   gobject_class = (GObjectClass *) klass;
       
   206   gobject_class->set_property = gst_audio_panorama_set_property;
       
   207   gobject_class->get_property = gst_audio_panorama_get_property;
       
   208 
       
   209   g_object_class_install_property (gobject_class, PROP_PANORAMA,
       
   210       g_param_spec_float ("panorama", "Panorama",
       
   211           "Position in stereo panorama (-1.0 left -> 1.0 right)", -1.0, 1.0,
       
   212           0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
       
   213   /**
       
   214    * GstAudioPanorama:method
       
   215    *
       
   216    * Panning method: psychoacoustic mode keeps the same perceived loudness,
       
   217    * while simple mode just controls the volume of one channel. It's merely
       
   218    * a matter of taste which method should be chosen. 
       
   219    *
       
   220    * Since: 0.10.6
       
   221    **/
       
   222   g_object_class_install_property (gobject_class, PROP_METHOD,
       
   223       g_param_spec_enum ("method", "Panning method",
       
   224           "Psychoacoustic mode keeps same perceived loudness, "
       
   225           "simple mode just controls volume of one channel.",
       
   226           GST_TYPE_AUDIO_PANORAMA_METHOD, METHOD_PSYCHOACOUSTIC,
       
   227           G_PARAM_READWRITE));
       
   228 
       
   229   GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
       
   230       GST_DEBUG_FUNCPTR (gst_audio_panorama_get_unit_size);
       
   231   GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
       
   232       GST_DEBUG_FUNCPTR (gst_audio_panorama_transform_caps);
       
   233   GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
       
   234       GST_DEBUG_FUNCPTR (gst_audio_panorama_set_caps);
       
   235   GST_BASE_TRANSFORM_CLASS (klass)->transform =
       
   236       GST_DEBUG_FUNCPTR (gst_audio_panorama_transform);
       
   237 }
       
   238 
       
   239 static void
       
   240 gst_audio_panorama_init (GstAudioPanorama * filter,
       
   241     GstAudioPanoramaClass * klass)
       
   242 {
       
   243 
       
   244   filter->panorama = 0;
       
   245   filter->method = METHOD_PSYCHOACOUSTIC;
       
   246   filter->width = 0;
       
   247   filter->channels = 0;
       
   248   filter->format_float = FALSE;
       
   249   filter->process = NULL;
       
   250 
       
   251   gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE);
       
   252 }
       
   253 
       
   254 static gboolean
       
   255 gst_audio_panorama_set_process_function (GstAudioPanorama * filter)
       
   256 {
       
   257   gint channel_index, format_index, method_index;
       
   258 
       
   259   /* set processing function */
       
   260   channel_index = filter->channels - 1;
       
   261   if (channel_index > 1 || channel_index < 0) {
       
   262     filter->process = NULL;
       
   263     return FALSE;
       
   264   }
       
   265 
       
   266   format_index = (filter->format_float) ? 1 : 0;
       
   267 
       
   268   method_index = filter->method;
       
   269   if (method_index >= NUM_METHODS || method_index < 0)
       
   270     method_index = METHOD_PSYCHOACOUSTIC;
       
   271 
       
   272   filter->process =
       
   273       panorama_process_functions[channel_index][format_index][method_index];
       
   274   return TRUE;
       
   275 }
       
   276 
       
   277 static void
       
   278 gst_audio_panorama_set_property (GObject * object, guint prop_id,
       
   279     const GValue * value, GParamSpec * pspec)
       
   280 {
       
   281   GstAudioPanorama *filter = GST_AUDIO_PANORAMA (object);
       
   282 
       
   283   switch (prop_id) {
       
   284     case PROP_PANORAMA:
       
   285       filter->panorama = g_value_get_float (value);
       
   286       break;
       
   287     case PROP_METHOD:
       
   288       filter->method = g_value_get_enum (value);
       
   289       gst_audio_panorama_set_process_function (filter);
       
   290       break;
       
   291     default:
       
   292       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   293       break;
       
   294   }
       
   295 }
       
   296 
       
   297 static void
       
   298 gst_audio_panorama_get_property (GObject * object, guint prop_id,
       
   299     GValue * value, GParamSpec * pspec)
       
   300 {
       
   301   GstAudioPanorama *filter = GST_AUDIO_PANORAMA (object);
       
   302 
       
   303   switch (prop_id) {
       
   304     case PROP_PANORAMA:
       
   305       g_value_set_float (value, filter->panorama);
       
   306       break;
       
   307     case PROP_METHOD:
       
   308       g_value_set_enum (value, filter->method);
       
   309       break;
       
   310     default:
       
   311       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   312       break;
       
   313   }
       
   314 }
       
   315 
       
   316 /* GstBaseTransform vmethod implementations */
       
   317 
       
   318 static gboolean
       
   319 gst_audio_panorama_get_unit_size (GstBaseTransform * base, GstCaps * caps,
       
   320     guint * size)
       
   321 {
       
   322   gint width, channels;
       
   323   GstStructure *structure;
       
   324   gboolean ret;
       
   325 
       
   326   g_assert (size);
       
   327 
       
   328   /* this works for both float and int */
       
   329   structure = gst_caps_get_structure (caps, 0);
       
   330   ret = gst_structure_get_int (structure, "width", &width);
       
   331   ret &= gst_structure_get_int (structure, "channels", &channels);
       
   332 
       
   333   *size = width * channels / 8;
       
   334 
       
   335   return ret;
       
   336 }
       
   337 
       
   338 static GstCaps *
       
   339 gst_audio_panorama_transform_caps (GstBaseTransform * base,
       
   340     GstPadDirection direction, GstCaps * caps)
       
   341 {
       
   342   GstCaps *res;
       
   343   GstStructure *structure;
       
   344 
       
   345   /* transform caps gives one single caps so we can just replace
       
   346    * the channel property with our range. */
       
   347   res = gst_caps_copy (caps);
       
   348   structure = gst_caps_get_structure (res, 0);
       
   349   if (direction == GST_PAD_SRC) {
       
   350     GST_INFO ("allow 1-2 channels");
       
   351     gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
       
   352   } else {
       
   353     GST_INFO ("allow 2 channels");
       
   354     gst_structure_set (structure, "channels", G_TYPE_INT, 2, NULL);
       
   355   }
       
   356 
       
   357   return res;
       
   358 }
       
   359 
       
   360 static gboolean
       
   361 gst_audio_panorama_set_caps (GstBaseTransform * base, GstCaps * incaps,
       
   362     GstCaps * outcaps)
       
   363 {
       
   364   GstAudioPanorama *filter = GST_AUDIO_PANORAMA (base);
       
   365   const GstStructure *structure;
       
   366   gboolean ret;
       
   367   gint width;
       
   368   const gchar *fmt;
       
   369 
       
   370   /*GST_INFO ("incaps are %" GST_PTR_FORMAT, incaps); */
       
   371 
       
   372   structure = gst_caps_get_structure (incaps, 0);
       
   373   ret = gst_structure_get_int (structure, "channels", &filter->channels);
       
   374   if (!ret)
       
   375     goto no_channels;
       
   376 
       
   377   ret = gst_structure_get_int (structure, "width", &width);
       
   378   if (!ret)
       
   379     goto no_width;
       
   380   filter->width = width / 8;
       
   381 
       
   382   fmt = gst_structure_get_name (structure);
       
   383   if (!strcmp (fmt, "audio/x-raw-int"))
       
   384     filter->format_float = FALSE;
       
   385   else
       
   386     filter->format_float = TRUE;
       
   387 
       
   388   GST_DEBUG ("try to process %s input with %d channels", fmt, filter->channels);
       
   389 
       
   390   ret = gst_audio_panorama_set_process_function (filter);
       
   391 
       
   392   if (!ret)
       
   393     GST_WARNING ("can't process input with %d channels", filter->channels);
       
   394 
       
   395   return ret;
       
   396 
       
   397 no_channels:
       
   398   GST_DEBUG ("no channels in caps");
       
   399   return ret;
       
   400 no_width:
       
   401   GST_DEBUG ("no width in caps");
       
   402   return ret;
       
   403 }
       
   404 
       
   405 /* psychoacoustic processing functions */
       
   406 static void
       
   407 gst_audio_panorama_transform_m2s_int (GstAudioPanorama * filter, gint16 * idata,
       
   408     gint16 * odata, guint num_samples)
       
   409 {
       
   410   guint i;
       
   411   gdouble val;
       
   412   glong lval, rval;
       
   413   gdouble rpan, lpan;
       
   414 
       
   415   /* pan:  -1.0  0.0  1.0
       
   416    * lpan:  1.0  0.5  0.0  
       
   417    * rpan:  0.0  0.5  1.0
       
   418    *
       
   419    * FIXME: we should use -3db (1/sqtr(2)) for 50:50
       
   420    */
       
   421   rpan = (gdouble) (filter->panorama + 1.0) / 2.0;
       
   422   lpan = 1.0 - rpan;
       
   423 
       
   424   for (i = 0; i < num_samples; i++) {
       
   425     val = (gdouble) * idata++;
       
   426 
       
   427     lval = (glong) (val * lpan);
       
   428     rval = (glong) (val * rpan);
       
   429 
       
   430     *odata++ = (gint16) CLAMP (lval, G_MININT16, G_MAXINT16);
       
   431     *odata++ = (gint16) CLAMP (rval, G_MININT16, G_MAXINT16);
       
   432   }
       
   433 }
       
   434 
       
   435 static void
       
   436 gst_audio_panorama_transform_s2s_int (GstAudioPanorama * filter, gint16 * idata,
       
   437     gint16 * odata, guint num_samples)
       
   438 {
       
   439   guint i;
       
   440   glong lval, rval;
       
   441   gdouble lival, rival;
       
   442   gdouble lrpan, llpan, rrpan, rlpan;
       
   443 
       
   444   /* pan:  -1.0  0.0  1.0
       
   445    * llpan: 1.0  1.0  0.0
       
   446    * lrpan: 1.0  0.0  0.0
       
   447    * rrpan: 0.0  1.0  1.0
       
   448    * rlpan: 0.0  0.0  1.0
       
   449    */
       
   450   if (filter->panorama > 0) {
       
   451     rlpan = (gdouble) filter->panorama;
       
   452     llpan = 1.0 - rlpan;
       
   453     lrpan = 0.0;
       
   454     rrpan = 1.0;
       
   455   } else {
       
   456     rrpan = (gdouble) (1.0 + filter->panorama);
       
   457     lrpan = 1.0 - rrpan;
       
   458     rlpan = 0.0;
       
   459     llpan = 1.0;
       
   460   }
       
   461 
       
   462   for (i = 0; i < num_samples; i++) {
       
   463     lival = (gdouble) * idata++;
       
   464     rival = (gdouble) * idata++;
       
   465 
       
   466     lval = lival * llpan + rival * lrpan;
       
   467     rval = lival * rlpan + rival * rrpan;
       
   468 
       
   469     *odata++ = (gint16) CLAMP (lval, G_MININT16, G_MAXINT16);
       
   470     *odata++ = (gint16) CLAMP (rval, G_MININT16, G_MAXINT16);
       
   471   }
       
   472 }
       
   473 
       
   474 static void
       
   475 gst_audio_panorama_transform_m2s_float (GstAudioPanorama * filter,
       
   476     gfloat * idata, gfloat * odata, guint num_samples)
       
   477 {
       
   478   guint i;
       
   479   gfloat val;
       
   480   gdouble rpan, lpan;
       
   481 
       
   482   /* pan:  -1.0  0.0  1.0
       
   483    * lpan:  1.0  0.5  0.0  
       
   484    * rpan:  0.0  0.5  1.0
       
   485    *
       
   486    * FIXME: we should use -3db (1/sqtr(2)) for 50:50
       
   487    */
       
   488   rpan = (gdouble) (filter->panorama + 1.0) / 2.0;
       
   489   lpan = 1.0 - rpan;
       
   490 
       
   491   for (i = 0; i < num_samples; i++) {
       
   492     val = *idata++;
       
   493 
       
   494     *odata++ = val * lpan;
       
   495     *odata++ = val * rpan;
       
   496   }
       
   497 }
       
   498 
       
   499 static void
       
   500 gst_audio_panorama_transform_s2s_float (GstAudioPanorama * filter,
       
   501     gfloat * idata, gfloat * odata, guint num_samples)
       
   502 {
       
   503   guint i;
       
   504   gfloat lival, rival;
       
   505   gdouble lrpan, llpan, rrpan, rlpan;
       
   506 
       
   507   /* pan:  -1.0  0.0  1.0
       
   508    * llpan: 1.0  1.0  0.0
       
   509    * lrpan: 1.0  0.0  0.0
       
   510    * rrpan: 0.0  1.0  1.0
       
   511    * rlpan: 0.0  0.0  1.0
       
   512    */
       
   513   if (filter->panorama > 0) {
       
   514     rlpan = (gdouble) filter->panorama;
       
   515     llpan = 1.0 - rlpan;
       
   516     lrpan = 0.0;
       
   517     rrpan = 1.0;
       
   518   } else {
       
   519     rrpan = (gdouble) (1.0 + filter->panorama);
       
   520     lrpan = 1.0 - rrpan;
       
   521     rlpan = 0.0;
       
   522     llpan = 1.0;
       
   523   }
       
   524 
       
   525   for (i = 0; i < num_samples; i++) {
       
   526     lival = *idata++;
       
   527     rival = *idata++;
       
   528 
       
   529     *odata++ = lival * llpan + rival * lrpan;
       
   530     *odata++ = lival * rlpan + rival * rrpan;
       
   531   }
       
   532 }
       
   533 
       
   534 /* simple processing functions */
       
   535 static void
       
   536 gst_audio_panorama_transform_m2s_int_simple (GstAudioPanorama * filter,
       
   537     gint16 * idata, gint16 * odata, guint num_samples)
       
   538 {
       
   539   guint i;
       
   540   gdouble val;
       
   541   glong lval, rval;
       
   542 
       
   543   for (i = 0; i < num_samples; i++) {
       
   544     val = (gdouble) * idata++;
       
   545 
       
   546     if (filter->panorama > 0.0) {
       
   547       lval = (glong) (val * (1.0 - filter->panorama));
       
   548       rval = (glong) val;
       
   549     } else {
       
   550       lval = (glong) val;
       
   551       rval = (glong) (val * (1.0 + filter->panorama));
       
   552     }
       
   553 
       
   554     *odata++ = (gint16) CLAMP (lval, G_MININT16, G_MAXINT16);
       
   555     *odata++ = (gint16) CLAMP (rval, G_MININT16, G_MAXINT16);
       
   556   }
       
   557 }
       
   558 
       
   559 static void
       
   560 gst_audio_panorama_transform_s2s_int_simple (GstAudioPanorama * filter,
       
   561     gint16 * idata, gint16 * odata, guint num_samples)
       
   562 {
       
   563   guint i;
       
   564   glong lval, rval;
       
   565   gdouble lival, rival;
       
   566 
       
   567   for (i = 0; i < num_samples; i++) {
       
   568     lival = (gdouble) * idata++;
       
   569     rival = (gdouble) * idata++;
       
   570 
       
   571     if (filter->panorama > 0.0) {
       
   572       lval = (glong) (lival * (1.0 - filter->panorama));
       
   573       rval = (glong) rival;
       
   574     } else {
       
   575       lval = (glong) lival;
       
   576       rval = (glong) (rival * (1.0 + filter->panorama));
       
   577     }
       
   578 
       
   579     *odata++ = (gint16) CLAMP (lval, G_MININT16, G_MAXINT16);
       
   580     *odata++ = (gint16) CLAMP (rval, G_MININT16, G_MAXINT16);
       
   581   }
       
   582 }
       
   583 
       
   584 static void
       
   585 gst_audio_panorama_transform_m2s_float_simple (GstAudioPanorama * filter,
       
   586     gfloat * idata, gfloat * odata, guint num_samples)
       
   587 {
       
   588   guint i;
       
   589   gfloat val;
       
   590 
       
   591 
       
   592   for (i = 0; i < num_samples; i++) {
       
   593     val = *idata++;
       
   594 
       
   595     if (filter->panorama > 0.0) {
       
   596       *odata++ = val * (1.0 - filter->panorama);
       
   597       *odata++ = val;
       
   598     } else {
       
   599       *odata++ = val;
       
   600       *odata++ = val * (1.0 + filter->panorama);
       
   601     }
       
   602   }
       
   603 }
       
   604 
       
   605 static void
       
   606 gst_audio_panorama_transform_s2s_float_simple (GstAudioPanorama * filter,
       
   607     gfloat * idata, gfloat * odata, guint num_samples)
       
   608 {
       
   609   guint i;
       
   610   gfloat lival, rival;
       
   611 
       
   612   for (i = 0; i < num_samples; i++) {
       
   613     lival = *idata++;
       
   614     rival = *idata++;
       
   615 
       
   616     if (filter->panorama > 0.0) {
       
   617       *odata++ = lival * (1.0 - filter->panorama);
       
   618       *odata++ = rival;
       
   619     } else {
       
   620       *odata++ = lival;
       
   621       *odata++ = rival * (1.0 + filter->panorama);
       
   622     }
       
   623   }
       
   624 }
       
   625 
       
   626 /* this function does the actual processing
       
   627  */
       
   628 static GstFlowReturn
       
   629 gst_audio_panorama_transform (GstBaseTransform * base, GstBuffer * inbuf,
       
   630     GstBuffer * outbuf)
       
   631 {
       
   632   GstAudioPanorama *filter = GST_AUDIO_PANORAMA (base);
       
   633   guint num_samples = GST_BUFFER_SIZE (outbuf) / (2 * filter->width);
       
   634 
       
   635   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (outbuf)))
       
   636     gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (outbuf));
       
   637 
       
   638   if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP))) {
       
   639     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
       
   640     memset (GST_BUFFER_DATA (outbuf), 0, GST_BUFFER_SIZE (outbuf));
       
   641     return GST_FLOW_OK;
       
   642   }
       
   643 
       
   644   filter->process (filter, GST_BUFFER_DATA (inbuf),
       
   645       GST_BUFFER_DATA (outbuf), num_samples);
       
   646 
       
   647   return GST_FLOW_OK;
       
   648 }