"Fossies" - the Fresh Open Source Software Archive

Member "gst-plugins-good-1.20.3/gst/audiofx/audiokaraoke.c" (15 Jun 2022, 10770 Bytes) of package /linux/misc/gst-plugins-good-1.20.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "audiokaraoke.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.18.6_vs_1.20.0.

    1 /* 
    2  * GStreamer
    3  * Copyright (C) 2008 Wim Taymans <wim.taymans@gmail.com>
    4  *
    5  * This library is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU Library General Public
    7  * License as published by the Free Software Foundation; either
    8  * version 2 of the License, or (at your option) any later version.
    9  *
   10  * This library is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13  * Library General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU Library General Public
   16  * License along with this library; if not, write to the
   17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
   18  * Boston, MA 02110-1301, USA.
   19  */
   20 
   21 /**
   22  * SECTION:element-audiokaraoke
   23  * @title: audiokaraoke
   24  *
   25  * Remove the voice from audio by filtering the center channel.
   26  * This plugin is useful for karaoke applications.
   27  *
   28  * ## Example launch line
   29  * |[
   30  * gst-launch-1.0 filesrc location=song.ogg ! oggdemux ! vorbisdec ! audiokaraoke ! audioconvert ! alsasink
   31  * ]|
   32  *
   33  */
   34 
   35 #ifdef HAVE_CONFIG_H
   36 #include "config.h"
   37 #endif
   38 
   39 #include <math.h>
   40 
   41 #include <gst/gst.h>
   42 #include <gst/base/gstbasetransform.h>
   43 #include <gst/audio/audio.h>
   44 #include <gst/audio/gstaudiofilter.h>
   45 
   46 #include "audiokaraoke.h"
   47 
   48 #define GST_CAT_DEFAULT gst_audio_karaoke_debug
   49 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
   50 
   51 /* Filter signals and args */
   52 enum
   53 {
   54   /* FILL ME */
   55   LAST_SIGNAL
   56 };
   57 
   58 #define DEFAULT_LEVEL       1.0
   59 #define DEFAULT_MONO_LEVEL  1.0
   60 #define DEFAULT_FILTER_BAND 220.0
   61 #define DEFAULT_FILTER_WIDTH    100.0
   62 
   63 enum
   64 {
   65   PROP_0,
   66   PROP_LEVEL,
   67   PROP_MONO_LEVEL,
   68   PROP_FILTER_BAND,
   69   PROP_FILTER_WIDTH
   70 };
   71 
   72 #define ALLOWED_CAPS \
   73     "audio/x-raw,"                                                \
   74     " format=(string){"GST_AUDIO_NE(S16)","GST_AUDIO_NE(F32)"},"  \
   75     " rate=(int)[1,MAX],"                                         \
   76     " channels=(int)2,"                                           \
   77     " channel-mask=(bitmask)0x3,"                                 \
   78     " layout=(string) interleaved"
   79 
   80 G_DEFINE_TYPE (GstAudioKaraoke, gst_audio_karaoke, GST_TYPE_AUDIO_FILTER);
   81 GST_ELEMENT_REGISTER_DEFINE (audiokaraoke, "audiokaraoke",
   82     GST_RANK_NONE, GST_TYPE_AUDIO_KARAOKE);
   83 
   84 static void gst_audio_karaoke_set_property (GObject * object, guint prop_id,
   85     const GValue * value, GParamSpec * pspec);
   86 static void gst_audio_karaoke_get_property (GObject * object, guint prop_id,
   87     GValue * value, GParamSpec * pspec);
   88 
   89 static gboolean gst_audio_karaoke_setup (GstAudioFilter * filter,
   90     const GstAudioInfo * info);
   91 static GstFlowReturn gst_audio_karaoke_transform_ip (GstBaseTransform * base,
   92     GstBuffer * buf);
   93 
   94 static void gst_audio_karaoke_transform_int (GstAudioKaraoke * filter,
   95     gint16 * data, guint num_samples);
   96 static void gst_audio_karaoke_transform_float (GstAudioKaraoke * filter,
   97     gfloat * data, guint num_samples);
   98 
   99 /* GObject vmethod implementations */
  100 
  101 static void
  102 gst_audio_karaoke_class_init (GstAudioKaraokeClass * klass)
  103 {
  104   GObjectClass *gobject_class;
  105   GstElementClass *gstelement_class;
  106   GstCaps *caps;
  107 
  108   GST_DEBUG_CATEGORY_INIT (gst_audio_karaoke_debug, "audiokaraoke", 0,
  109       "audiokaraoke element");
  110 
  111   gobject_class = (GObjectClass *) klass;
  112   gstelement_class = (GstElementClass *) klass;
  113 
  114   gobject_class->set_property = gst_audio_karaoke_set_property;
  115   gobject_class->get_property = gst_audio_karaoke_get_property;
  116 
  117   g_object_class_install_property (gobject_class, PROP_LEVEL,
  118       g_param_spec_float ("level", "Level",
  119           "Level of the effect (1.0 = full)", 0.0, 1.0, DEFAULT_LEVEL,
  120           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
  121 
  122   g_object_class_install_property (gobject_class, PROP_MONO_LEVEL,
  123       g_param_spec_float ("mono-level", "Mono Level",
  124           "Level of the mono channel (1.0 = full)", 0.0, 1.0, DEFAULT_LEVEL,
  125           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
  126 
  127   g_object_class_install_property (gobject_class, PROP_FILTER_BAND,
  128       g_param_spec_float ("filter-band", "Filter Band",
  129           "The Frequency band of the filter", 0.0, 441.0, DEFAULT_FILTER_BAND,
  130           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
  131 
  132   g_object_class_install_property (gobject_class, PROP_FILTER_WIDTH,
  133       g_param_spec_float ("filter-width", "Filter Width",
  134           "The Frequency width of the filter", 0.0, 100.0, DEFAULT_FILTER_WIDTH,
  135           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
  136 
  137   gst_element_class_set_static_metadata (gstelement_class, "AudioKaraoke",
  138       "Filter/Effect/Audio",
  139       "Removes voice from sound", "Wim Taymans <wim.taymans@gmail.com>");
  140 
  141   caps = gst_caps_from_string (ALLOWED_CAPS);
  142   gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
  143       caps);
  144   gst_caps_unref (caps);
  145 
  146   GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
  147       GST_DEBUG_FUNCPTR (gst_audio_karaoke_transform_ip);
  148   GST_BASE_TRANSFORM_CLASS (klass)->transform_ip_on_passthrough = FALSE;
  149 
  150   GST_AUDIO_FILTER_CLASS (klass)->setup =
  151       GST_DEBUG_FUNCPTR (gst_audio_karaoke_setup);
  152 }
  153 
  154 static void
  155 gst_audio_karaoke_init (GstAudioKaraoke * filter)
  156 {
  157   gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
  158   gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE);
  159 
  160   filter->level = DEFAULT_LEVEL;
  161   filter->mono_level = DEFAULT_MONO_LEVEL;
  162   filter->filter_band = DEFAULT_FILTER_BAND;
  163   filter->filter_width = DEFAULT_FILTER_WIDTH;
  164 }
  165 
  166 static void
  167 update_filter (GstAudioKaraoke * filter, const GstAudioInfo * info)
  168 {
  169   gfloat A, B, C;
  170   gint rate;
  171 
  172   if (info) {
  173     rate = GST_AUDIO_INFO_RATE (info);
  174   } else {
  175     rate = GST_AUDIO_FILTER_RATE (filter);
  176   }
  177 
  178   if (rate == 0)
  179     return;
  180 
  181   C = exp (-2 * G_PI * filter->filter_width / rate);
  182   B = -4 * C / (1 + C) * cos (2 * G_PI * filter->filter_band / rate);
  183   A = sqrt (1 - B * B / (4 * C)) * (1 - C);
  184 
  185   filter->A = A;
  186   filter->B = B;
  187   filter->C = C;
  188   filter->y1 = 0.0;
  189   filter->y2 = 0.0;
  190 }
  191 
  192 static void
  193 gst_audio_karaoke_set_property (GObject * object, guint prop_id,
  194     const GValue * value, GParamSpec * pspec)
  195 {
  196   GstAudioKaraoke *filter;
  197 
  198   filter = GST_AUDIO_KARAOKE (object);
  199 
  200   switch (prop_id) {
  201     case PROP_LEVEL:
  202       filter->level = g_value_get_float (value);
  203       break;
  204     case PROP_MONO_LEVEL:
  205       filter->mono_level = g_value_get_float (value);
  206       break;
  207     case PROP_FILTER_BAND:
  208       filter->filter_band = g_value_get_float (value);
  209       update_filter (filter, NULL);
  210       break;
  211     case PROP_FILTER_WIDTH:
  212       filter->filter_width = g_value_get_float (value);
  213       update_filter (filter, NULL);
  214       break;
  215     default:
  216       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  217       break;
  218   }
  219 }
  220 
  221 static void
  222 gst_audio_karaoke_get_property (GObject * object, guint prop_id,
  223     GValue * value, GParamSpec * pspec)
  224 {
  225   GstAudioKaraoke *filter;
  226 
  227   filter = GST_AUDIO_KARAOKE (object);
  228 
  229   switch (prop_id) {
  230     case PROP_LEVEL:
  231       g_value_set_float (value, filter->level);
  232       break;
  233     case PROP_MONO_LEVEL:
  234       g_value_set_float (value, filter->mono_level);
  235       break;
  236     case PROP_FILTER_BAND:
  237       g_value_set_float (value, filter->filter_band);
  238       break;
  239     case PROP_FILTER_WIDTH:
  240       g_value_set_float (value, filter->filter_width);
  241       break;
  242     default:
  243       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  244       break;
  245   }
  246 }
  247 
  248 /* GstAudioFilter vmethod implementations */
  249 
  250 static gboolean
  251 gst_audio_karaoke_setup (GstAudioFilter * base, const GstAudioInfo * info)
  252 {
  253   GstAudioKaraoke *filter = GST_AUDIO_KARAOKE (base);
  254   gboolean ret = TRUE;
  255 
  256   switch (GST_AUDIO_INFO_FORMAT (info)) {
  257     case GST_AUDIO_FORMAT_S16:
  258       filter->process = (GstAudioKaraokeProcessFunc)
  259           gst_audio_karaoke_transform_int;
  260       break;
  261     case GST_AUDIO_FORMAT_F32:
  262       filter->process = (GstAudioKaraokeProcessFunc)
  263           gst_audio_karaoke_transform_float;
  264       break;
  265     default:
  266       ret = FALSE;
  267       break;
  268   }
  269   update_filter (filter, info);
  270 
  271   return ret;
  272 }
  273 
  274 static void
  275 gst_audio_karaoke_transform_int (GstAudioKaraoke * filter,
  276     gint16 * data, guint num_samples)
  277 {
  278   gint i, l, r, o, x;
  279   gint channels;
  280   gdouble y;
  281   gint level;
  282 
  283   channels = GST_AUDIO_FILTER_CHANNELS (filter);
  284   level = filter->level * 256;
  285 
  286   for (i = 0; i < num_samples; i += channels) {
  287     /* get left and right inputs */
  288     l = data[i];
  289     r = data[i + 1];
  290     /* do filtering */
  291     x = (l + r) / 2;
  292     y = (filter->A * x - filter->B * filter->y1) - filter->C * filter->y2;
  293     filter->y2 = filter->y1;
  294     filter->y1 = y;
  295     /* filter mono signal */
  296     o = (int) (y * filter->mono_level);
  297     o = CLAMP (o, G_MININT16, G_MAXINT16);
  298     o = (o * level) >> 8;
  299     /* now cut the center */
  300     x = l - ((r * level) >> 8) + o;
  301     r = r - ((l * level) >> 8) + o;
  302     data[i] = CLAMP (x, G_MININT16, G_MAXINT16);
  303     data[i + 1] = CLAMP (r, G_MININT16, G_MAXINT16);
  304   }
  305 }
  306 
  307 static void
  308 gst_audio_karaoke_transform_float (GstAudioKaraoke * filter,
  309     gfloat * data, guint num_samples)
  310 {
  311   gint i;
  312   gint channels;
  313   gdouble l, r, o;
  314   gdouble y;
  315 
  316   channels = GST_AUDIO_FILTER_CHANNELS (filter);
  317 
  318   for (i = 0; i < num_samples; i += channels) {
  319     /* get left and right inputs */
  320     l = data[i];
  321     r = data[i + 1];
  322     /* do filtering */
  323     y = (filter->A * ((l + r) / 2.0) - filter->B * filter->y1) -
  324         filter->C * filter->y2;
  325     filter->y2 = filter->y1;
  326     filter->y1 = y;
  327     /* filter mono signal */
  328     o = y * filter->mono_level * filter->level;
  329     /* now cut the center */
  330     data[i] = l - (r * filter->level) + o;
  331     data[i + 1] = r - (l * filter->level) + o;
  332   }
  333 }
  334 
  335 /* GstBaseTransform vmethod implementations */
  336 static GstFlowReturn
  337 gst_audio_karaoke_transform_ip (GstBaseTransform * base, GstBuffer * buf)
  338 {
  339   GstAudioKaraoke *filter = GST_AUDIO_KARAOKE (base);
  340   guint num_samples;
  341   GstClockTime timestamp, stream_time;
  342   GstMapInfo map;
  343 
  344   timestamp = GST_BUFFER_TIMESTAMP (buf);
  345   stream_time =
  346       gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
  347 
  348   GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
  349       GST_TIME_ARGS (timestamp));
  350 
  351   if (GST_CLOCK_TIME_IS_VALID (stream_time))
  352     gst_object_sync_values (GST_OBJECT (filter), stream_time);
  353 
  354   if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)))
  355     return GST_FLOW_OK;
  356 
  357   gst_buffer_map (buf, &map, GST_MAP_READWRITE);
  358   num_samples = map.size / GST_AUDIO_FILTER_BPS (filter);
  359 
  360   filter->process (filter, map.data, num_samples);
  361 
  362   gst_buffer_unmap (buf, &map);
  363 
  364   return GST_FLOW_OK;
  365 }