gst_plugins_good/gst/audiofx/audiodynamic.c
author hgs
Wed, 24 Mar 2010 18:04:17 -0500
changeset 16 8e837d1bf446
permissions -rw-r--r--
201009
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
16
hgs
parents:
diff changeset
     1
/* 
hgs
parents:
diff changeset
     2
 * GStreamer
hgs
parents:
diff changeset
     3
 * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
hgs
parents:
diff changeset
     4
 *
hgs
parents:
diff changeset
     5
 * This library is free software; you can redistribute it and/or
hgs
parents:
diff changeset
     6
 * modify it under the terms of the GNU Library General Public
hgs
parents:
diff changeset
     7
 * License as published by the Free Software Foundation; either
hgs
parents:
diff changeset
     8
 * version 2 of the License, or (at your option) any later version.
hgs
parents:
diff changeset
     9
 *
hgs
parents:
diff changeset
    10
 * This library is distributed in the hope that it will be useful,
hgs
parents:
diff changeset
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
hgs
parents:
diff changeset
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
hgs
parents:
diff changeset
    13
 * Library General Public License for more details.
hgs
parents:
diff changeset
    14
 *
hgs
parents:
diff changeset
    15
 * You should have received a copy of the GNU Library General Public
hgs
parents:
diff changeset
    16
 * License along with this library; if not, write to the
hgs
parents:
diff changeset
    17
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
hgs
parents:
diff changeset
    18
 * Boston, MA 02111-1307, USA.
hgs
parents:
diff changeset
    19
 */
hgs
parents:
diff changeset
    20
hgs
parents:
diff changeset
    21
/**
hgs
parents:
diff changeset
    22
 * SECTION:element-audiodynamic
hgs
parents:
diff changeset
    23
 *
hgs
parents:
diff changeset
    24
 * This element can act as a compressor or expander. A compressor changes the
hgs
parents:
diff changeset
    25
 * amplitude of all samples above a specific threshold with a specific ratio,
hgs
parents:
diff changeset
    26
 * a expander does the same for all samples below a specific threshold. If
hgs
parents:
diff changeset
    27
 * soft-knee mode is selected the ratio is applied smoothly.
hgs
parents:
diff changeset
    28
 *
hgs
parents:
diff changeset
    29
 * <refsect2>
hgs
parents:
diff changeset
    30
 * <title>Example launch line</title>
hgs
parents:
diff changeset
    31
 * |[
hgs
parents:
diff changeset
    32
 * gst-launch audiotestsrc wave=saw ! audiodynamic characteristics=soft-knee mode=compressor threshold=0.5 rate=0.5 ! alsasink
hgs
parents:
diff changeset
    33
 * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiodynamic characteristics=hard-knee mode=expander threshold=0.2 rate=4.0 ! alsasink
hgs
parents:
diff changeset
    34
 * gst-launch audiotestsrc wave=saw ! audioconvert ! audiodynamic ! audioconvert ! alsasink
hgs
parents:
diff changeset
    35
 * ]|
hgs
parents:
diff changeset
    36
 * </refsect2>
hgs
parents:
diff changeset
    37
 */
hgs
parents:
diff changeset
    38
hgs
parents:
diff changeset
    39
/* TODO: Implement attack and release parameters */
hgs
parents:
diff changeset
    40
hgs
parents:
diff changeset
    41
#ifdef HAVE_CONFIG_H
hgs
parents:
diff changeset
    42
#include "config.h"
hgs
parents:
diff changeset
    43
#endif
hgs
parents:
diff changeset
    44
hgs
parents:
diff changeset
    45
#include <gst/gst.h>
hgs
parents:
diff changeset
    46
#include <gst/base/gstbasetransform.h>
hgs
parents:
diff changeset
    47
#include <gst/audio/audio.h>
hgs
parents:
diff changeset
    48
#include <gst/audio/gstaudiofilter.h>
hgs
parents:
diff changeset
    49
#include <gst/controller/gstcontroller.h>
hgs
parents:
diff changeset
    50
hgs
parents:
diff changeset
    51
#include "audiodynamic.h"
hgs
parents:
diff changeset
    52
hgs
parents:
diff changeset
    53
#define GST_CAT_DEFAULT gst_audio_dynamic_debug
hgs
parents:
diff changeset
    54
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
hgs
parents:
diff changeset
    55
hgs
parents:
diff changeset
    56
static const GstElementDetails element_details =
hgs
parents:
diff changeset
    57
GST_ELEMENT_DETAILS ("Dynamic range controller",
hgs
parents:
diff changeset
    58
    "Filter/Effect/Audio",
hgs
parents:
diff changeset
    59
    "Compressor and Expander",
hgs
parents:
diff changeset
    60
    "Sebastian Dröge <slomo@circular-chaos.org>");
hgs
parents:
diff changeset
    61
hgs
parents:
diff changeset
    62
/* Filter signals and args */
hgs
parents:
diff changeset
    63
enum
hgs
parents:
diff changeset
    64
{
hgs
parents:
diff changeset
    65
  /* FILL ME */
hgs
parents:
diff changeset
    66
  LAST_SIGNAL
hgs
parents:
diff changeset
    67
};
hgs
parents:
diff changeset
    68
hgs
parents:
diff changeset
    69
enum
hgs
parents:
diff changeset
    70
{
hgs
parents:
diff changeset
    71
  PROP_0,
hgs
parents:
diff changeset
    72
  PROP_CHARACTERISTICS,
hgs
parents:
diff changeset
    73
  PROP_MODE,
hgs
parents:
diff changeset
    74
  PROP_THRESHOLD,
hgs
parents:
diff changeset
    75
  PROP_RATIO
hgs
parents:
diff changeset
    76
};
hgs
parents:
diff changeset
    77
hgs
parents:
diff changeset
    78
#define ALLOWED_CAPS \
hgs
parents:
diff changeset
    79
    "audio/x-raw-int,"                                                \
hgs
parents:
diff changeset
    80
    " depth=(int)16,"                                                 \
hgs
parents:
diff changeset
    81
    " width=(int)16,"                                                 \
hgs
parents:
diff changeset
    82
    " endianness=(int)BYTE_ORDER,"                                    \
hgs
parents:
diff changeset
    83
    " signed=(bool)TRUE,"                                             \
hgs
parents:
diff changeset
    84
    " rate=(int)[1,MAX],"                                             \
hgs
parents:
diff changeset
    85
    " channels=(int)[1,MAX]; "                                        \
hgs
parents:
diff changeset
    86
    "audio/x-raw-float,"                                              \
hgs
parents:
diff changeset
    87
    " width=(int)32,"                                                 \
hgs
parents:
diff changeset
    88
    " endianness=(int)BYTE_ORDER,"                                    \
hgs
parents:
diff changeset
    89
    " rate=(int)[1,MAX],"                                             \
hgs
parents:
diff changeset
    90
    " channels=(int)[1,MAX]"
hgs
parents:
diff changeset
    91
hgs
parents:
diff changeset
    92
#define DEBUG_INIT(bla) \
hgs
parents:
diff changeset
    93
  GST_DEBUG_CATEGORY_INIT (gst_audio_dynamic_debug, "audiodynamic", 0, "audiodynamic element");
hgs
parents:
diff changeset
    94
hgs
parents:
diff changeset
    95
GST_BOILERPLATE_FULL (GstAudioDynamic, gst_audio_dynamic, GstAudioFilter,
hgs
parents:
diff changeset
    96
    GST_TYPE_AUDIO_FILTER, DEBUG_INIT);
hgs
parents:
diff changeset
    97
hgs
parents:
diff changeset
    98
static void gst_audio_dynamic_set_property (GObject * object, guint prop_id,
hgs
parents:
diff changeset
    99
    const GValue * value, GParamSpec * pspec);
hgs
parents:
diff changeset
   100
static void gst_audio_dynamic_get_property (GObject * object, guint prop_id,
hgs
parents:
diff changeset
   101
    GValue * value, GParamSpec * pspec);
hgs
parents:
diff changeset
   102
hgs
parents:
diff changeset
   103
static gboolean gst_audio_dynamic_setup (GstAudioFilter * filter,
hgs
parents:
diff changeset
   104
    GstRingBufferSpec * format);
hgs
parents:
diff changeset
   105
static GstFlowReturn gst_audio_dynamic_transform_ip (GstBaseTransform * base,
hgs
parents:
diff changeset
   106
    GstBuffer * buf);
hgs
parents:
diff changeset
   107
hgs
parents:
diff changeset
   108
static void
hgs
parents:
diff changeset
   109
gst_audio_dynamic_transform_hard_knee_compressor_int (GstAudioDynamic * filter,
hgs
parents:
diff changeset
   110
    gint16 * data, guint num_samples);
hgs
parents:
diff changeset
   111
static void
hgs
parents:
diff changeset
   112
gst_audio_dynamic_transform_hard_knee_compressor_float (GstAudioDynamic *
hgs
parents:
diff changeset
   113
    filter, gfloat * data, guint num_samples);
hgs
parents:
diff changeset
   114
static void
hgs
parents:
diff changeset
   115
gst_audio_dynamic_transform_soft_knee_compressor_int (GstAudioDynamic * filter,
hgs
parents:
diff changeset
   116
    gint16 * data, guint num_samples);
hgs
parents:
diff changeset
   117
static void
hgs
parents:
diff changeset
   118
gst_audio_dynamic_transform_soft_knee_compressor_float (GstAudioDynamic *
hgs
parents:
diff changeset
   119
    filter, gfloat * data, guint num_samples);
hgs
parents:
diff changeset
   120
static void gst_audio_dynamic_transform_hard_knee_expander_int (GstAudioDynamic
hgs
parents:
diff changeset
   121
    * filter, gint16 * data, guint num_samples);
hgs
parents:
diff changeset
   122
static void
hgs
parents:
diff changeset
   123
gst_audio_dynamic_transform_hard_knee_expander_float (GstAudioDynamic * filter,
hgs
parents:
diff changeset
   124
    gfloat * data, guint num_samples);
hgs
parents:
diff changeset
   125
static void gst_audio_dynamic_transform_soft_knee_expander_int (GstAudioDynamic
hgs
parents:
diff changeset
   126
    * filter, gint16 * data, guint num_samples);
hgs
parents:
diff changeset
   127
static void
hgs
parents:
diff changeset
   128
gst_audio_dynamic_transform_soft_knee_expander_float (GstAudioDynamic * filter,
hgs
parents:
diff changeset
   129
    gfloat * data, guint num_samples);
hgs
parents:
diff changeset
   130
hgs
parents:
diff changeset
   131
static GstAudioDynamicProcessFunc process_functions[] = {
hgs
parents:
diff changeset
   132
  (GstAudioDynamicProcessFunc)
hgs
parents:
diff changeset
   133
      gst_audio_dynamic_transform_hard_knee_compressor_int,
hgs
parents:
diff changeset
   134
  (GstAudioDynamicProcessFunc)
hgs
parents:
diff changeset
   135
      gst_audio_dynamic_transform_hard_knee_compressor_float,
hgs
parents:
diff changeset
   136
  (GstAudioDynamicProcessFunc)
hgs
parents:
diff changeset
   137
      gst_audio_dynamic_transform_soft_knee_compressor_int,
hgs
parents:
diff changeset
   138
  (GstAudioDynamicProcessFunc)
hgs
parents:
diff changeset
   139
      gst_audio_dynamic_transform_soft_knee_compressor_float,
hgs
parents:
diff changeset
   140
  (GstAudioDynamicProcessFunc)
hgs
parents:
diff changeset
   141
      gst_audio_dynamic_transform_hard_knee_expander_int,
hgs
parents:
diff changeset
   142
  (GstAudioDynamicProcessFunc)
hgs
parents:
diff changeset
   143
      gst_audio_dynamic_transform_hard_knee_expander_float,
hgs
parents:
diff changeset
   144
  (GstAudioDynamicProcessFunc)
hgs
parents:
diff changeset
   145
      gst_audio_dynamic_transform_soft_knee_expander_int,
hgs
parents:
diff changeset
   146
  (GstAudioDynamicProcessFunc)
hgs
parents:
diff changeset
   147
  gst_audio_dynamic_transform_soft_knee_expander_float
hgs
parents:
diff changeset
   148
};
hgs
parents:
diff changeset
   149
hgs
parents:
diff changeset
   150
enum
hgs
parents:
diff changeset
   151
{
hgs
parents:
diff changeset
   152
  CHARACTERISTICS_HARD_KNEE = 0,
hgs
parents:
diff changeset
   153
  CHARACTERISTICS_SOFT_KNEE
hgs
parents:
diff changeset
   154
};
hgs
parents:
diff changeset
   155
hgs
parents:
diff changeset
   156
#define GST_TYPE_AUDIO_DYNAMIC_CHARACTERISTICS (gst_audio_dynamic_characteristics_get_type ())
hgs
parents:
diff changeset
   157
static GType
hgs
parents:
diff changeset
   158
gst_audio_dynamic_characteristics_get_type (void)
hgs
parents:
diff changeset
   159
{
hgs
parents:
diff changeset
   160
  static GType gtype = 0;
hgs
parents:
diff changeset
   161
hgs
parents:
diff changeset
   162
  if (gtype == 0) {
hgs
parents:
diff changeset
   163
    static const GEnumValue values[] = {
hgs
parents:
diff changeset
   164
      {CHARACTERISTICS_HARD_KNEE, "Hard Knee (default)",
hgs
parents:
diff changeset
   165
          "hard-knee"},
hgs
parents:
diff changeset
   166
      {CHARACTERISTICS_SOFT_KNEE, "Soft Knee (smooth)",
hgs
parents:
diff changeset
   167
          "soft-knee"},
hgs
parents:
diff changeset
   168
      {0, NULL, NULL}
hgs
parents:
diff changeset
   169
    };
hgs
parents:
diff changeset
   170
hgs
parents:
diff changeset
   171
    gtype = g_enum_register_static ("GstAudioDynamicCharacteristics", values);
hgs
parents:
diff changeset
   172
  }
hgs
parents:
diff changeset
   173
  return gtype;
hgs
parents:
diff changeset
   174
}
hgs
parents:
diff changeset
   175
hgs
parents:
diff changeset
   176
enum
hgs
parents:
diff changeset
   177
{
hgs
parents:
diff changeset
   178
  MODE_COMPRESSOR = 0,
hgs
parents:
diff changeset
   179
  MODE_EXPANDER
hgs
parents:
diff changeset
   180
};
hgs
parents:
diff changeset
   181
hgs
parents:
diff changeset
   182
#define GST_TYPE_AUDIO_DYNAMIC_MODE (gst_audio_dynamic_mode_get_type ())
hgs
parents:
diff changeset
   183
static GType
hgs
parents:
diff changeset
   184
gst_audio_dynamic_mode_get_type (void)
hgs
parents:
diff changeset
   185
{
hgs
parents:
diff changeset
   186
  static GType gtype = 0;
hgs
parents:
diff changeset
   187
hgs
parents:
diff changeset
   188
  if (gtype == 0) {
hgs
parents:
diff changeset
   189
    static const GEnumValue values[] = {
hgs
parents:
diff changeset
   190
      {MODE_COMPRESSOR, "Compressor (default)",
hgs
parents:
diff changeset
   191
          "compressor"},
hgs
parents:
diff changeset
   192
      {MODE_EXPANDER, "Expander", "expander"},
hgs
parents:
diff changeset
   193
      {0, NULL, NULL}
hgs
parents:
diff changeset
   194
    };
hgs
parents:
diff changeset
   195
hgs
parents:
diff changeset
   196
    gtype = g_enum_register_static ("GstAudioDynamicMode", values);
hgs
parents:
diff changeset
   197
  }
hgs
parents:
diff changeset
   198
  return gtype;
hgs
parents:
diff changeset
   199
}
hgs
parents:
diff changeset
   200
hgs
parents:
diff changeset
   201
static gboolean
hgs
parents:
diff changeset
   202
gst_audio_dynamic_set_process_function (GstAudioDynamic * filter)
hgs
parents:
diff changeset
   203
{
hgs
parents:
diff changeset
   204
  gint func_index;
hgs
parents:
diff changeset
   205
hgs
parents:
diff changeset
   206
  func_index = (filter->mode == MODE_COMPRESSOR) ? 0 : 4;
hgs
parents:
diff changeset
   207
  func_index += (filter->characteristics == CHARACTERISTICS_HARD_KNEE) ? 0 : 2;
hgs
parents:
diff changeset
   208
  func_index +=
hgs
parents:
diff changeset
   209
      (GST_AUDIO_FILTER (filter)->format.type == GST_BUFTYPE_FLOAT) ? 1 : 0;
hgs
parents:
diff changeset
   210
hgs
parents:
diff changeset
   211
  if (func_index >= 0 && func_index < 8) {
hgs
parents:
diff changeset
   212
    filter->process = process_functions[func_index];
hgs
parents:
diff changeset
   213
    return TRUE;
hgs
parents:
diff changeset
   214
  }
hgs
parents:
diff changeset
   215
hgs
parents:
diff changeset
   216
  return FALSE;
hgs
parents:
diff changeset
   217
}
hgs
parents:
diff changeset
   218
hgs
parents:
diff changeset
   219
/* GObject vmethod implementations */
hgs
parents:
diff changeset
   220
hgs
parents:
diff changeset
   221
static void
hgs
parents:
diff changeset
   222
gst_audio_dynamic_base_init (gpointer klass)
hgs
parents:
diff changeset
   223
{
hgs
parents:
diff changeset
   224
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
hgs
parents:
diff changeset
   225
  GstCaps *caps;
hgs
parents:
diff changeset
   226
hgs
parents:
diff changeset
   227
  gst_element_class_set_details (element_class, &element_details);
hgs
parents:
diff changeset
   228
hgs
parents:
diff changeset
   229
  caps = gst_caps_from_string (ALLOWED_CAPS);
hgs
parents:
diff changeset
   230
  gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
hgs
parents:
diff changeset
   231
      caps);
hgs
parents:
diff changeset
   232
  gst_caps_unref (caps);
hgs
parents:
diff changeset
   233
}
hgs
parents:
diff changeset
   234
hgs
parents:
diff changeset
   235
static void
hgs
parents:
diff changeset
   236
gst_audio_dynamic_class_init (GstAudioDynamicClass * klass)
hgs
parents:
diff changeset
   237
{
hgs
parents:
diff changeset
   238
  GObjectClass *gobject_class;
hgs
parents:
diff changeset
   239
hgs
parents:
diff changeset
   240
  gobject_class = (GObjectClass *) klass;
hgs
parents:
diff changeset
   241
  gobject_class->set_property = gst_audio_dynamic_set_property;
hgs
parents:
diff changeset
   242
  gobject_class->get_property = gst_audio_dynamic_get_property;
hgs
parents:
diff changeset
   243
hgs
parents:
diff changeset
   244
  g_object_class_install_property (gobject_class, PROP_CHARACTERISTICS,
hgs
parents:
diff changeset
   245
      g_param_spec_enum ("characteristics", "Characteristics",
hgs
parents:
diff changeset
   246
          "Selects whether the ratio should be applied smooth (soft-knee) "
hgs
parents:
diff changeset
   247
          "or hard (hard-knee).",
hgs
parents:
diff changeset
   248
          GST_TYPE_AUDIO_DYNAMIC_CHARACTERISTICS, CHARACTERISTICS_HARD_KNEE,
hgs
parents:
diff changeset
   249
          G_PARAM_READWRITE));
hgs
parents:
diff changeset
   250
hgs
parents:
diff changeset
   251
  g_object_class_install_property (gobject_class, PROP_MODE,
hgs
parents:
diff changeset
   252
      g_param_spec_enum ("mode", "Mode",
hgs
parents:
diff changeset
   253
          "Selects whether the filter should work on loud samples (compressor) or"
hgs
parents:
diff changeset
   254
          "quiet samples (expander).",
hgs
parents:
diff changeset
   255
          GST_TYPE_AUDIO_DYNAMIC_MODE, MODE_COMPRESSOR, G_PARAM_READWRITE));
hgs
parents:
diff changeset
   256
hgs
parents:
diff changeset
   257
  g_object_class_install_property (gobject_class, PROP_THRESHOLD,
hgs
parents:
diff changeset
   258
      g_param_spec_float ("threshold", "Threshold",
hgs
parents:
diff changeset
   259
          "Threshold until the filter is activated", 0.0, 1.0,
hgs
parents:
diff changeset
   260
          0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
hgs
parents:
diff changeset
   261
hgs
parents:
diff changeset
   262
  g_object_class_install_property (gobject_class, PROP_RATIO,
hgs
parents:
diff changeset
   263
      g_param_spec_float ("ratio", "Ratio",
hgs
parents:
diff changeset
   264
          "Ratio that should be applied", 0.0, G_MAXFLOAT,
hgs
parents:
diff changeset
   265
          1.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
hgs
parents:
diff changeset
   266
hgs
parents:
diff changeset
   267
  GST_AUDIO_FILTER_CLASS (klass)->setup =
hgs
parents:
diff changeset
   268
      GST_DEBUG_FUNCPTR (gst_audio_dynamic_setup);
hgs
parents:
diff changeset
   269
  GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
hgs
parents:
diff changeset
   270
      GST_DEBUG_FUNCPTR (gst_audio_dynamic_transform_ip);
hgs
parents:
diff changeset
   271
}
hgs
parents:
diff changeset
   272
hgs
parents:
diff changeset
   273
static void
hgs
parents:
diff changeset
   274
gst_audio_dynamic_init (GstAudioDynamic * filter, GstAudioDynamicClass * klass)
hgs
parents:
diff changeset
   275
{
hgs
parents:
diff changeset
   276
  filter->ratio = 1.0;
hgs
parents:
diff changeset
   277
  filter->threshold = 0.0;
hgs
parents:
diff changeset
   278
  filter->characteristics = CHARACTERISTICS_HARD_KNEE;
hgs
parents:
diff changeset
   279
  filter->mode = MODE_COMPRESSOR;
hgs
parents:
diff changeset
   280
  gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
hgs
parents:
diff changeset
   281
  gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE);
hgs
parents:
diff changeset
   282
}
hgs
parents:
diff changeset
   283
hgs
parents:
diff changeset
   284
static void
hgs
parents:
diff changeset
   285
gst_audio_dynamic_set_property (GObject * object, guint prop_id,
hgs
parents:
diff changeset
   286
    const GValue * value, GParamSpec * pspec)
hgs
parents:
diff changeset
   287
{
hgs
parents:
diff changeset
   288
  GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (object);
hgs
parents:
diff changeset
   289
hgs
parents:
diff changeset
   290
  switch (prop_id) {
hgs
parents:
diff changeset
   291
    case PROP_CHARACTERISTICS:
hgs
parents:
diff changeset
   292
      filter->characteristics = g_value_get_enum (value);
hgs
parents:
diff changeset
   293
      gst_audio_dynamic_set_process_function (filter);
hgs
parents:
diff changeset
   294
      break;
hgs
parents:
diff changeset
   295
    case PROP_MODE:
hgs
parents:
diff changeset
   296
      filter->mode = g_value_get_enum (value);
hgs
parents:
diff changeset
   297
      gst_audio_dynamic_set_process_function (filter);
hgs
parents:
diff changeset
   298
      break;
hgs
parents:
diff changeset
   299
    case PROP_THRESHOLD:
hgs
parents:
diff changeset
   300
      filter->threshold = g_value_get_float (value);
hgs
parents:
diff changeset
   301
      break;
hgs
parents:
diff changeset
   302
    case PROP_RATIO:
hgs
parents:
diff changeset
   303
      filter->ratio = g_value_get_float (value);
hgs
parents:
diff changeset
   304
      break;
hgs
parents:
diff changeset
   305
    default:
hgs
parents:
diff changeset
   306
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
hgs
parents:
diff changeset
   307
      break;
hgs
parents:
diff changeset
   308
  }
hgs
parents:
diff changeset
   309
}
hgs
parents:
diff changeset
   310
hgs
parents:
diff changeset
   311
static void
hgs
parents:
diff changeset
   312
gst_audio_dynamic_get_property (GObject * object, guint prop_id,
hgs
parents:
diff changeset
   313
    GValue * value, GParamSpec * pspec)
hgs
parents:
diff changeset
   314
{
hgs
parents:
diff changeset
   315
  GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (object);
hgs
parents:
diff changeset
   316
hgs
parents:
diff changeset
   317
  switch (prop_id) {
hgs
parents:
diff changeset
   318
    case PROP_CHARACTERISTICS:
hgs
parents:
diff changeset
   319
      g_value_set_enum (value, filter->characteristics);
hgs
parents:
diff changeset
   320
      break;
hgs
parents:
diff changeset
   321
    case PROP_MODE:
hgs
parents:
diff changeset
   322
      g_value_set_enum (value, filter->mode);
hgs
parents:
diff changeset
   323
      break;
hgs
parents:
diff changeset
   324
    case PROP_THRESHOLD:
hgs
parents:
diff changeset
   325
      g_value_set_float (value, filter->threshold);
hgs
parents:
diff changeset
   326
      break;
hgs
parents:
diff changeset
   327
    case PROP_RATIO:
hgs
parents:
diff changeset
   328
      g_value_set_float (value, filter->ratio);
hgs
parents:
diff changeset
   329
      break;
hgs
parents:
diff changeset
   330
    default:
hgs
parents:
diff changeset
   331
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
hgs
parents:
diff changeset
   332
      break;
hgs
parents:
diff changeset
   333
  }
hgs
parents:
diff changeset
   334
}
hgs
parents:
diff changeset
   335
hgs
parents:
diff changeset
   336
/* GstAudioFilter vmethod implementations */
hgs
parents:
diff changeset
   337
hgs
parents:
diff changeset
   338
static gboolean
hgs
parents:
diff changeset
   339
gst_audio_dynamic_setup (GstAudioFilter * base, GstRingBufferSpec * format)
hgs
parents:
diff changeset
   340
{
hgs
parents:
diff changeset
   341
  GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (base);
hgs
parents:
diff changeset
   342
  gboolean ret = TRUE;
hgs
parents:
diff changeset
   343
hgs
parents:
diff changeset
   344
  ret = gst_audio_dynamic_set_process_function (filter);
hgs
parents:
diff changeset
   345
hgs
parents:
diff changeset
   346
  return ret;
hgs
parents:
diff changeset
   347
}
hgs
parents:
diff changeset
   348
hgs
parents:
diff changeset
   349
static void
hgs
parents:
diff changeset
   350
gst_audio_dynamic_transform_hard_knee_compressor_int (GstAudioDynamic * filter,
hgs
parents:
diff changeset
   351
    gint16 * data, guint num_samples)
hgs
parents:
diff changeset
   352
{
hgs
parents:
diff changeset
   353
  glong val;
hgs
parents:
diff changeset
   354
  glong thr_p = filter->threshold * G_MAXINT16;
hgs
parents:
diff changeset
   355
  glong thr_n = filter->threshold * G_MININT16;
hgs
parents:
diff changeset
   356
hgs
parents:
diff changeset
   357
  /* Nothing to do for us if ratio is 1.0 or if the threshold
hgs
parents:
diff changeset
   358
   * equals 1.0. */
hgs
parents:
diff changeset
   359
  if (filter->threshold == 1.0 || filter->ratio == 1.0)
hgs
parents:
diff changeset
   360
    return;
hgs
parents:
diff changeset
   361
hgs
parents:
diff changeset
   362
  for (; num_samples; num_samples--) {
hgs
parents:
diff changeset
   363
    val = *data;
hgs
parents:
diff changeset
   364
hgs
parents:
diff changeset
   365
    if (val > thr_p) {
hgs
parents:
diff changeset
   366
      val = thr_p + (val - thr_p) * filter->ratio;
hgs
parents:
diff changeset
   367
    } else if (val < thr_n) {
hgs
parents:
diff changeset
   368
      val = thr_n + (val - thr_n) * filter->ratio;
hgs
parents:
diff changeset
   369
    }
hgs
parents:
diff changeset
   370
    *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16);
hgs
parents:
diff changeset
   371
  }
hgs
parents:
diff changeset
   372
}
hgs
parents:
diff changeset
   373
hgs
parents:
diff changeset
   374
static void
hgs
parents:
diff changeset
   375
gst_audio_dynamic_transform_hard_knee_compressor_float (GstAudioDynamic *
hgs
parents:
diff changeset
   376
    filter, gfloat * data, guint num_samples)
hgs
parents:
diff changeset
   377
{
hgs
parents:
diff changeset
   378
  gdouble val, threshold = filter->threshold;
hgs
parents:
diff changeset
   379
hgs
parents:
diff changeset
   380
  /* Nothing to do for us if ratio == 1.0.
hgs
parents:
diff changeset
   381
   * As float values can be above 1.0 we have to do something
hgs
parents:
diff changeset
   382
   * if threshold is greater than 1.0. */
hgs
parents:
diff changeset
   383
  if (filter->ratio == 1.0)
hgs
parents:
diff changeset
   384
    return;
hgs
parents:
diff changeset
   385
hgs
parents:
diff changeset
   386
  for (; num_samples; num_samples--) {
hgs
parents:
diff changeset
   387
    val = *data;
hgs
parents:
diff changeset
   388
hgs
parents:
diff changeset
   389
    if (val > threshold) {
hgs
parents:
diff changeset
   390
      val = threshold + (val - threshold) * filter->ratio;
hgs
parents:
diff changeset
   391
    } else if (val < -threshold) {
hgs
parents:
diff changeset
   392
      val = -threshold + (val + threshold) * filter->ratio;
hgs
parents:
diff changeset
   393
    }
hgs
parents:
diff changeset
   394
    *data++ = (gfloat) val;
hgs
parents:
diff changeset
   395
  }
hgs
parents:
diff changeset
   396
}
hgs
parents:
diff changeset
   397
hgs
parents:
diff changeset
   398
static void
hgs
parents:
diff changeset
   399
gst_audio_dynamic_transform_soft_knee_compressor_int (GstAudioDynamic * filter,
hgs
parents:
diff changeset
   400
    gint16 * data, guint num_samples)
hgs
parents:
diff changeset
   401
{
hgs
parents:
diff changeset
   402
  glong val;
hgs
parents:
diff changeset
   403
  glong thr_p = filter->threshold * G_MAXINT16;
hgs
parents:
diff changeset
   404
  glong thr_n = filter->threshold * G_MININT16;
hgs
parents:
diff changeset
   405
  gdouble a_p, b_p, c_p;
hgs
parents:
diff changeset
   406
  gdouble a_n, b_n, c_n;
hgs
parents:
diff changeset
   407
hgs
parents:
diff changeset
   408
  /* Nothing to do for us if ratio is 1.0 or if the threshold
hgs
parents:
diff changeset
   409
   * equals 1.0. */
hgs
parents:
diff changeset
   410
  if (filter->threshold == 1.0 || filter->ratio == 1.0)
hgs
parents:
diff changeset
   411
    return;
hgs
parents:
diff changeset
   412
hgs
parents:
diff changeset
   413
  /* We build a 2nd degree polynomial here for
hgs
parents:
diff changeset
   414
   * values greater than threshold or small than
hgs
parents:
diff changeset
   415
   * -threshold with:
hgs
parents:
diff changeset
   416
   * f(t) = t, f'(t) = 1, f'(m) = r
hgs
parents:
diff changeset
   417
   * =>
hgs
parents:
diff changeset
   418
   * a = (1-r)/(2*(t-m))
hgs
parents:
diff changeset
   419
   * b = (r*t - m)/(t-m)
hgs
parents:
diff changeset
   420
   * c = t * (1 - b - a*t)
hgs
parents:
diff changeset
   421
   * f(x) = ax^2 + bx + c
hgs
parents:
diff changeset
   422
   */
hgs
parents:
diff changeset
   423
hgs
parents:
diff changeset
   424
  /* shouldn't happen because this would only be the case
hgs
parents:
diff changeset
   425
   * for threshold == 1.0 which we catch above */
hgs
parents:
diff changeset
   426
  g_assert (thr_p - G_MAXINT16 != 0);
hgs
parents:
diff changeset
   427
  g_assert (thr_n - G_MININT != 0);
hgs
parents:
diff changeset
   428
hgs
parents:
diff changeset
   429
  a_p = (1 - filter->ratio) / (2 * (thr_p - G_MAXINT16));
hgs
parents:
diff changeset
   430
  b_p = (filter->ratio * thr_p - G_MAXINT16) / (thr_p - G_MAXINT16);
hgs
parents:
diff changeset
   431
  c_p = thr_p * (1 - b_p - a_p * thr_p);
hgs
parents:
diff changeset
   432
  a_n = (1 - filter->ratio) / (2 * (thr_n - G_MININT16));
hgs
parents:
diff changeset
   433
  b_n = (filter->ratio * thr_n - G_MININT16) / (thr_n - G_MININT16);
hgs
parents:
diff changeset
   434
  c_n = thr_n * (1 - b_n - a_n * thr_n);
hgs
parents:
diff changeset
   435
hgs
parents:
diff changeset
   436
  for (; num_samples; num_samples--) {
hgs
parents:
diff changeset
   437
    val = *data;
hgs
parents:
diff changeset
   438
hgs
parents:
diff changeset
   439
    if (val > thr_p) {
hgs
parents:
diff changeset
   440
      val = a_p * val * val + b_p * val + c_p;
hgs
parents:
diff changeset
   441
    } else if (val < thr_n) {
hgs
parents:
diff changeset
   442
      val = a_n * val * val + b_n * val + c_n;
hgs
parents:
diff changeset
   443
    }
hgs
parents:
diff changeset
   444
    *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16);
hgs
parents:
diff changeset
   445
  }
hgs
parents:
diff changeset
   446
}
hgs
parents:
diff changeset
   447
hgs
parents:
diff changeset
   448
static void
hgs
parents:
diff changeset
   449
gst_audio_dynamic_transform_soft_knee_compressor_float (GstAudioDynamic *
hgs
parents:
diff changeset
   450
    filter, gfloat * data, guint num_samples)
hgs
parents:
diff changeset
   451
{
hgs
parents:
diff changeset
   452
  gdouble val;
hgs
parents:
diff changeset
   453
  gdouble threshold = filter->threshold;
hgs
parents:
diff changeset
   454
  gdouble a_p, b_p, c_p;
hgs
parents:
diff changeset
   455
  gdouble a_n, b_n, c_n;
hgs
parents:
diff changeset
   456
hgs
parents:
diff changeset
   457
  /* Nothing to do for us if ratio == 1.0.
hgs
parents:
diff changeset
   458
   * As float values can be above 1.0 we have to do something
hgs
parents:
diff changeset
   459
   * if threshold is greater than 1.0. */
hgs
parents:
diff changeset
   460
  if (filter->ratio == 1.0)
hgs
parents:
diff changeset
   461
    return;
hgs
parents:
diff changeset
   462
hgs
parents:
diff changeset
   463
  /* We build a 2nd degree polynomial here for
hgs
parents:
diff changeset
   464
   * values greater than threshold or small than
hgs
parents:
diff changeset
   465
   * -threshold with:
hgs
parents:
diff changeset
   466
   * f(t) = t, f'(t) = 1, f'(m) = r
hgs
parents:
diff changeset
   467
   * =>
hgs
parents:
diff changeset
   468
   * a = (1-r)/(2*(t-m))
hgs
parents:
diff changeset
   469
   * b = (r*t - m)/(t-m)
hgs
parents:
diff changeset
   470
   * c = t * (1 - b - a*t)
hgs
parents:
diff changeset
   471
   * f(x) = ax^2 + bx + c
hgs
parents:
diff changeset
   472
   */
hgs
parents:
diff changeset
   473
hgs
parents:
diff changeset
   474
  /* FIXME: If treshold is the same as the maximum
hgs
parents:
diff changeset
   475
   * we need to raise it a bit to prevent
hgs
parents:
diff changeset
   476
   * division by zero. */
hgs
parents:
diff changeset
   477
  if (threshold == 1.0)
hgs
parents:
diff changeset
   478
    threshold = 1.0 + 0.00001;
hgs
parents:
diff changeset
   479
hgs
parents:
diff changeset
   480
  a_p = (1.0 - filter->ratio) / (2.0 * (threshold - 1.0));
hgs
parents:
diff changeset
   481
  b_p = (filter->ratio * threshold - 1.0) / (threshold - 1.0);
hgs
parents:
diff changeset
   482
  c_p = threshold * (1.0 - b_p - a_p * threshold);
hgs
parents:
diff changeset
   483
  a_n = (1.0 - filter->ratio) / (2.0 * (-threshold + 1.0));
hgs
parents:
diff changeset
   484
  b_n = (-filter->ratio * threshold + 1.0) / (-threshold + 1.0);
hgs
parents:
diff changeset
   485
  c_n = -threshold * (1.0 - b_n + a_n * threshold);
hgs
parents:
diff changeset
   486
hgs
parents:
diff changeset
   487
  for (; num_samples; num_samples--) {
hgs
parents:
diff changeset
   488
    val = *data;
hgs
parents:
diff changeset
   489
hgs
parents:
diff changeset
   490
    if (val > 1.0) {
hgs
parents:
diff changeset
   491
      val = 1.0 + (val - 1.0) * filter->ratio;
hgs
parents:
diff changeset
   492
    } else if (val > threshold) {
hgs
parents:
diff changeset
   493
      val = a_p * val * val + b_p * val + c_p;
hgs
parents:
diff changeset
   494
    } else if (val < -1.0) {
hgs
parents:
diff changeset
   495
      val = -1.0 + (val + 1.0) * filter->ratio;
hgs
parents:
diff changeset
   496
    } else if (val < -threshold) {
hgs
parents:
diff changeset
   497
      val = a_n * val * val + b_n * val + c_n;
hgs
parents:
diff changeset
   498
    }
hgs
parents:
diff changeset
   499
    *data++ = (gfloat) val;
hgs
parents:
diff changeset
   500
  }
hgs
parents:
diff changeset
   501
}
hgs
parents:
diff changeset
   502
hgs
parents:
diff changeset
   503
static void
hgs
parents:
diff changeset
   504
gst_audio_dynamic_transform_hard_knee_expander_int (GstAudioDynamic * filter,
hgs
parents:
diff changeset
   505
    gint16 * data, guint num_samples)
hgs
parents:
diff changeset
   506
{
hgs
parents:
diff changeset
   507
  glong val;
hgs
parents:
diff changeset
   508
  glong thr_p = filter->threshold * G_MAXINT16;
hgs
parents:
diff changeset
   509
  glong thr_n = filter->threshold * G_MININT16;
hgs
parents:
diff changeset
   510
  gdouble zero_p, zero_n;
hgs
parents:
diff changeset
   511
hgs
parents:
diff changeset
   512
  /* Nothing to do for us here if threshold equals 0.0
hgs
parents:
diff changeset
   513
   * or ratio equals 1.0 */
hgs
parents:
diff changeset
   514
  if (filter->threshold == 0.0 || filter->ratio == 1.0)
hgs
parents:
diff changeset
   515
    return;
hgs
parents:
diff changeset
   516
hgs
parents:
diff changeset
   517
  /* zero crossing of our function */
hgs
parents:
diff changeset
   518
  if (filter->ratio != 0.0) {
hgs
parents:
diff changeset
   519
    zero_p = thr_p - thr_p / filter->ratio;
hgs
parents:
diff changeset
   520
    zero_n = thr_n - thr_n / filter->ratio;
hgs
parents:
diff changeset
   521
  } else {
hgs
parents:
diff changeset
   522
    zero_p = zero_n = 0.0;
hgs
parents:
diff changeset
   523
  }
hgs
parents:
diff changeset
   524
hgs
parents:
diff changeset
   525
  if (zero_p < 0.0)
hgs
parents:
diff changeset
   526
    zero_p = 0.0;
hgs
parents:
diff changeset
   527
  if (zero_n > 0.0)
hgs
parents:
diff changeset
   528
    zero_n = 0.0;
hgs
parents:
diff changeset
   529
hgs
parents:
diff changeset
   530
  for (; num_samples; num_samples--) {
hgs
parents:
diff changeset
   531
    val = *data;
hgs
parents:
diff changeset
   532
hgs
parents:
diff changeset
   533
    if (val < thr_p && val > zero_p) {
hgs
parents:
diff changeset
   534
      val = filter->ratio * val + thr_p * (1 - filter->ratio);
hgs
parents:
diff changeset
   535
    } else if ((val <= zero_p && val > 0) || (val >= zero_n && val < 0)) {
hgs
parents:
diff changeset
   536
      val = 0;
hgs
parents:
diff changeset
   537
    } else if (val > thr_n && val < zero_n) {
hgs
parents:
diff changeset
   538
      val = filter->ratio * val + thr_n * (1 - filter->ratio);
hgs
parents:
diff changeset
   539
    }
hgs
parents:
diff changeset
   540
    *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16);
hgs
parents:
diff changeset
   541
  }
hgs
parents:
diff changeset
   542
}
hgs
parents:
diff changeset
   543
hgs
parents:
diff changeset
   544
static void
hgs
parents:
diff changeset
   545
gst_audio_dynamic_transform_hard_knee_expander_float (GstAudioDynamic * filter,
hgs
parents:
diff changeset
   546
    gfloat * data, guint num_samples)
hgs
parents:
diff changeset
   547
{
hgs
parents:
diff changeset
   548
  gdouble val, threshold = filter->threshold, zero;
hgs
parents:
diff changeset
   549
hgs
parents:
diff changeset
   550
  /* Nothing to do for us here if threshold equals 0.0
hgs
parents:
diff changeset
   551
   * or ratio equals 1.0 */
hgs
parents:
diff changeset
   552
  if (filter->threshold == 0.0 || filter->ratio == 1.0)
hgs
parents:
diff changeset
   553
    return;
hgs
parents:
diff changeset
   554
hgs
parents:
diff changeset
   555
  /* zero crossing of our function */
hgs
parents:
diff changeset
   556
  if (filter->ratio != 0.0)
hgs
parents:
diff changeset
   557
    zero = threshold - threshold / filter->ratio;
hgs
parents:
diff changeset
   558
  else
hgs
parents:
diff changeset
   559
    zero = 0.0;
hgs
parents:
diff changeset
   560
hgs
parents:
diff changeset
   561
  if (zero < 0.0)
hgs
parents:
diff changeset
   562
    zero = 0.0;
hgs
parents:
diff changeset
   563
hgs
parents:
diff changeset
   564
  for (; num_samples; num_samples--) {
hgs
parents:
diff changeset
   565
    val = *data;
hgs
parents:
diff changeset
   566
hgs
parents:
diff changeset
   567
    if (val < threshold && val > zero) {
hgs
parents:
diff changeset
   568
      val = filter->ratio * val + threshold * (1.0 - filter->ratio);
hgs
parents:
diff changeset
   569
    } else if ((val <= zero && val > 0.0) || (val >= -zero && val < 0.0)) {
hgs
parents:
diff changeset
   570
      val = 0.0;
hgs
parents:
diff changeset
   571
    } else if (val > -threshold && val < -zero) {
hgs
parents:
diff changeset
   572
      val = filter->ratio * val - threshold * (1.0 - filter->ratio);
hgs
parents:
diff changeset
   573
    }
hgs
parents:
diff changeset
   574
    *data++ = (gfloat) val;
hgs
parents:
diff changeset
   575
  }
hgs
parents:
diff changeset
   576
}
hgs
parents:
diff changeset
   577
hgs
parents:
diff changeset
   578
static void
hgs
parents:
diff changeset
   579
gst_audio_dynamic_transform_soft_knee_expander_int (GstAudioDynamic * filter,
hgs
parents:
diff changeset
   580
    gint16 * data, guint num_samples)
hgs
parents:
diff changeset
   581
{
hgs
parents:
diff changeset
   582
  glong val;
hgs
parents:
diff changeset
   583
  glong thr_p = filter->threshold * G_MAXINT16;
hgs
parents:
diff changeset
   584
  glong thr_n = filter->threshold * G_MININT16;
hgs
parents:
diff changeset
   585
  gdouble zero_p, zero_n;
hgs
parents:
diff changeset
   586
  gdouble a_p, b_p, c_p;
hgs
parents:
diff changeset
   587
  gdouble a_n, b_n, c_n;
hgs
parents:
diff changeset
   588
hgs
parents:
diff changeset
   589
  /* Nothing to do for us here if threshold equals 0.0
hgs
parents:
diff changeset
   590
   * or ratio equals 1.0 */
hgs
parents:
diff changeset
   591
  if (filter->threshold == 0.0 || filter->ratio == 1.0)
hgs
parents:
diff changeset
   592
    return;
hgs
parents:
diff changeset
   593
hgs
parents:
diff changeset
   594
  /* zero crossing of our function */
hgs
parents:
diff changeset
   595
  zero_p = (thr_p * (filter->ratio - 1.0)) / (1.0 + filter->ratio);
hgs
parents:
diff changeset
   596
  zero_n = (thr_n * (filter->ratio - 1.0)) / (1.0 + filter->ratio);
hgs
parents:
diff changeset
   597
hgs
parents:
diff changeset
   598
  if (zero_p < 0.0)
hgs
parents:
diff changeset
   599
    zero_p = 0.0;
hgs
parents:
diff changeset
   600
  if (zero_n > 0.0)
hgs
parents:
diff changeset
   601
    zero_n = 0.0;
hgs
parents:
diff changeset
   602
hgs
parents:
diff changeset
   603
  /* shouldn't happen as this would only happen
hgs
parents:
diff changeset
   604
   * with threshold == 0.0 */
hgs
parents:
diff changeset
   605
  g_assert (thr_p != 0);
hgs
parents:
diff changeset
   606
  g_assert (thr_n != 0);
hgs
parents:
diff changeset
   607
hgs
parents:
diff changeset
   608
  /* We build a 2n degree polynomial here for values between
hgs
parents:
diff changeset
   609
   * 0 and threshold or 0 and -threshold with:
hgs
parents:
diff changeset
   610
   * f(t) = t, f'(t) = 1, f(z) = 0, f'(z) = r
hgs
parents:
diff changeset
   611
   * z between 0 and t
hgs
parents:
diff changeset
   612
   * =>
hgs
parents:
diff changeset
   613
   * a = (1 - r^2) / (4 * t)
hgs
parents:
diff changeset
   614
   * b = (1 + r^2) / 2
hgs
parents:
diff changeset
   615
   * c = t * (1.0 - b - a*t)
hgs
parents:
diff changeset
   616
   * f(x) = ax^2 + bx + c */
hgs
parents:
diff changeset
   617
  a_p = (1.0 - filter->ratio * filter->ratio) / (4.0 * thr_p);
hgs
parents:
diff changeset
   618
  b_p = (1.0 + filter->ratio * filter->ratio) / 2.0;
hgs
parents:
diff changeset
   619
  c_p = thr_p * (1.0 - b_p - a_p * thr_p);
hgs
parents:
diff changeset
   620
  a_n = (1.0 - filter->ratio * filter->ratio) / (4.0 * thr_n);
hgs
parents:
diff changeset
   621
  b_n = (1.0 + filter->ratio * filter->ratio) / 2.0;
hgs
parents:
diff changeset
   622
  c_n = thr_n * (1.0 - b_n - a_n * thr_n);
hgs
parents:
diff changeset
   623
hgs
parents:
diff changeset
   624
  for (; num_samples; num_samples--) {
hgs
parents:
diff changeset
   625
    val = *data;
hgs
parents:
diff changeset
   626
hgs
parents:
diff changeset
   627
    if (val < thr_p && val > zero_p) {
hgs
parents:
diff changeset
   628
      val = a_p * val * val + b_p * val + c_p;
hgs
parents:
diff changeset
   629
    } else if ((val <= zero_p && val > 0) || (val >= zero_n && val < 0)) {
hgs
parents:
diff changeset
   630
      val = 0;
hgs
parents:
diff changeset
   631
    } else if (val > thr_n && val < zero_n) {
hgs
parents:
diff changeset
   632
      val = a_n * val * val + b_n * val + c_n;
hgs
parents:
diff changeset
   633
    }
hgs
parents:
diff changeset
   634
    *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16);
hgs
parents:
diff changeset
   635
  }
hgs
parents:
diff changeset
   636
}
hgs
parents:
diff changeset
   637
hgs
parents:
diff changeset
   638
static void
hgs
parents:
diff changeset
   639
gst_audio_dynamic_transform_soft_knee_expander_float (GstAudioDynamic * filter,
hgs
parents:
diff changeset
   640
    gfloat * data, guint num_samples)
hgs
parents:
diff changeset
   641
{
hgs
parents:
diff changeset
   642
  gdouble val;
hgs
parents:
diff changeset
   643
  gdouble threshold = filter->threshold;
hgs
parents:
diff changeset
   644
  gdouble zero;
hgs
parents:
diff changeset
   645
  gdouble a_p, b_p, c_p;
hgs
parents:
diff changeset
   646
  gdouble a_n, b_n, c_n;
hgs
parents:
diff changeset
   647
hgs
parents:
diff changeset
   648
  /* Nothing to do for us here if threshold equals 0.0
hgs
parents:
diff changeset
   649
   * or ratio equals 1.0 */
hgs
parents:
diff changeset
   650
  if (filter->threshold == 0.0 || filter->ratio == 1.0)
hgs
parents:
diff changeset
   651
    return;
hgs
parents:
diff changeset
   652
hgs
parents:
diff changeset
   653
  /* zero crossing of our function */
hgs
parents:
diff changeset
   654
  zero = (threshold * (filter->ratio - 1.0)) / (1.0 + filter->ratio);
hgs
parents:
diff changeset
   655
hgs
parents:
diff changeset
   656
  if (zero < 0.0)
hgs
parents:
diff changeset
   657
    zero = 0.0;
hgs
parents:
diff changeset
   658
hgs
parents:
diff changeset
   659
  /* shouldn't happen as this only happens with
hgs
parents:
diff changeset
   660
   * threshold == 0.0 */
hgs
parents:
diff changeset
   661
  g_assert (threshold != 0.0);
hgs
parents:
diff changeset
   662
hgs
parents:
diff changeset
   663
  /* We build a 2n degree polynomial here for values between
hgs
parents:
diff changeset
   664
   * 0 and threshold or 0 and -threshold with:
hgs
parents:
diff changeset
   665
   * f(t) = t, f'(t) = 1, f(z) = 0, f'(z) = r
hgs
parents:
diff changeset
   666
   * z between 0 and t
hgs
parents:
diff changeset
   667
   * =>
hgs
parents:
diff changeset
   668
   * a = (1 - r^2) / (4 * t)
hgs
parents:
diff changeset
   669
   * b = (1 + r^2) / 2
hgs
parents:
diff changeset
   670
   * c = t * (1.0 - b - a*t)
hgs
parents:
diff changeset
   671
   * f(x) = ax^2 + bx + c */
hgs
parents:
diff changeset
   672
  a_p = (1.0 - filter->ratio * filter->ratio) / (4.0 * threshold);
hgs
parents:
diff changeset
   673
  b_p = (1.0 + filter->ratio * filter->ratio) / 2.0;
hgs
parents:
diff changeset
   674
  c_p = threshold * (1.0 - b_p - a_p * threshold);
hgs
parents:
diff changeset
   675
  a_n = (1.0 - filter->ratio * filter->ratio) / (-4.0 * threshold);
hgs
parents:
diff changeset
   676
  b_n = (1.0 + filter->ratio * filter->ratio) / 2.0;
hgs
parents:
diff changeset
   677
  c_n = -threshold * (1.0 - b_n + a_n * threshold);
hgs
parents:
diff changeset
   678
hgs
parents:
diff changeset
   679
  for (; num_samples; num_samples--) {
hgs
parents:
diff changeset
   680
    val = *data;
hgs
parents:
diff changeset
   681
hgs
parents:
diff changeset
   682
    if (val < threshold && val > zero) {
hgs
parents:
diff changeset
   683
      val = a_p * val * val + b_p * val + c_p;
hgs
parents:
diff changeset
   684
    } else if ((val <= zero && val > 0.0) || (val >= -zero && val < 0.0)) {
hgs
parents:
diff changeset
   685
      val = 0.0;
hgs
parents:
diff changeset
   686
    } else if (val > -threshold && val < -zero) {
hgs
parents:
diff changeset
   687
      val = a_n * val * val + b_n * val + c_n;
hgs
parents:
diff changeset
   688
    }
hgs
parents:
diff changeset
   689
    *data++ = (gfloat) val;
hgs
parents:
diff changeset
   690
  }
hgs
parents:
diff changeset
   691
}
hgs
parents:
diff changeset
   692
hgs
parents:
diff changeset
   693
/* GstBaseTransform vmethod implementations */
hgs
parents:
diff changeset
   694
static GstFlowReturn
hgs
parents:
diff changeset
   695
gst_audio_dynamic_transform_ip (GstBaseTransform * base, GstBuffer * buf)
hgs
parents:
diff changeset
   696
{
hgs
parents:
diff changeset
   697
  GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (base);
hgs
parents:
diff changeset
   698
  guint num_samples =
hgs
parents:
diff changeset
   699
      GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8);
hgs
parents:
diff changeset
   700
hgs
parents:
diff changeset
   701
  if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf)))
hgs
parents:
diff changeset
   702
    gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf));
hgs
parents:
diff changeset
   703
hgs
parents:
diff changeset
   704
  if (gst_base_transform_is_passthrough (base) ||
hgs
parents:
diff changeset
   705
      G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)))
hgs
parents:
diff changeset
   706
    return GST_FLOW_OK;
hgs
parents:
diff changeset
   707
hgs
parents:
diff changeset
   708
  filter->process (filter, GST_BUFFER_DATA (buf), num_samples);
hgs
parents:
diff changeset
   709
hgs
parents:
diff changeset
   710
  return GST_FLOW_OK;
hgs
parents:
diff changeset
   711
}