gstaudiotestsrc.c 41.5 KB
Newer Older
Stefan Kost's avatar
Stefan Kost committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/* GStreamer
 * Copyright (C) 2005 Stefan Kost <ensonic@users.sf.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
/**
 * SECTION:element-audiotestsrc
 *
 * AudioTestSrc can be used to generate basic audio signals. It support several
23 24 25
 * different waveforms and allows to set the base frequency and volume.
 *
 * <refsect2>
Stefan Kost's avatar
Stefan Kost committed
26
 * <title>Example launch line</title>
27
 * |[
Stefan Kost's avatar
Stefan Kost committed
28
 * gst-launch audiotestsrc ! audioconvert ! alsasink
29 30
 * ]| This pipeline produces a sine with default frequency, 440 Hz, and the
 * default volume, 0.8 (relative to a maximum 1.0).
31
 * |[
32
 * gst-launch audiotestsrc wave=2 freq=200 ! audioconvert ! tee name=t ! queue ! alsasink t. ! queue ! libvisual_lv_scope ! ffmpegcolorspace ! xvimagesink
33
 * ]| In this example a saw wave is generated. The wave is shown using a
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
34 35
 * scope visualizer from libvisual, allowing you to visually verify that
 * the saw wave is correct.
Stefan Kost's avatar
Stefan Kost committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49
 * </refsect2>
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <gst/controller/gstcontroller.h>

#include "gstaudiotestsrc.h"

50

David Schleef's avatar
David Schleef committed
51
#define M_PI_M2 ( G_PI + G_PI )
Stefan Kost's avatar
Stefan Kost committed
52

53 54 55
GST_DEBUG_CATEGORY_STATIC (audio_test_src_debug);
#define GST_CAT_DEFAULT audio_test_src_debug

56 57 58 59 60 61
#define DEFAULT_SAMPLES_PER_BUFFER   1024
#define DEFAULT_WAVE                 GST_AUDIO_TEST_SRC_WAVE_SINE
#define DEFAULT_FREQ                 440.0
#define DEFAULT_VOLUME               0.8
#define DEFAULT_IS_LIVE              FALSE
#define DEFAULT_TIMESTAMP_OFFSET     G_GINT64_CONSTANT (0)
62
#define DEFAULT_CAN_ACTIVATE_PUSH    TRUE
63
#define DEFAULT_CAN_ACTIVATE_PULL    FALSE
Stefan Kost's avatar
Stefan Kost committed
64 65 66 67 68 69 70 71 72 73

enum
{
  PROP_0,
  PROP_SAMPLES_PER_BUFFER,
  PROP_WAVE,
  PROP_FREQ,
  PROP_VOLUME,
  PROP_IS_LIVE,
  PROP_TIMESTAMP_OFFSET,
74 75
  PROP_CAN_ACTIVATE_PUSH,
  PROP_CAN_ACTIVATE_PULL,
76
  PROP_LAST
Stefan Kost's avatar
Stefan Kost committed
77 78 79
};


80
static GstStaticPadTemplate gst_audio_test_src_src_template =
81
    GST_STATIC_PAD_TEMPLATE ("src",
Stefan Kost's avatar
Stefan Kost committed
82 83 84 85 86 87
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("audio/x-raw-int, "
        "endianness = (int) BYTE_ORDER, "
        "signed = (boolean) true, "
        "width = (int) 16, "
88 89
        "depth = (int) 16, "
        "rate = (int) [ 1, MAX ], "
90
        "channels = (int) [ 1, 2 ]; "
91 92 93 94 95 96
        "audio/x-raw-int, "
        "endianness = (int) BYTE_ORDER, "
        "signed = (boolean) true, "
        "width = (int) 32, "
        "depth = (int) 32,"
        "rate = (int) [ 1, MAX ], "
97
        "channels = (int) [ 1, 2 ]; "
98 99 100
        "audio/x-raw-float, "
        "endianness = (int) BYTE_ORDER, "
        "width = (int) { 32, 64 }, "
101
        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
Stefan Kost's avatar
Stefan Kost committed
102 103
    );

104 105
#define gst_audio_test_src_parent_class parent_class
G_DEFINE_TYPE (GstAudioTestSrc, gst_audio_test_src, GST_TYPE_BASE_SRC);
Stefan Kost's avatar
Stefan Kost committed
106

107
#define GST_TYPE_AUDIO_TEST_SRC_WAVE (gst_audiostestsrc_wave_get_type())
Stefan Kost's avatar
Stefan Kost committed
108 109 110 111
static GType
gst_audiostestsrc_wave_get_type (void)
{
  static GType audiostestsrc_wave_type = 0;
112
  static const GEnumValue audiostestsrc_waves[] = {
113 114 115 116 117
    {GST_AUDIO_TEST_SRC_WAVE_SINE, "Sine", "sine"},
    {GST_AUDIO_TEST_SRC_WAVE_SQUARE, "Square", "square"},
    {GST_AUDIO_TEST_SRC_WAVE_SAW, "Saw", "saw"},
    {GST_AUDIO_TEST_SRC_WAVE_TRIANGLE, "Triangle", "triangle"},
    {GST_AUDIO_TEST_SRC_WAVE_SILENCE, "Silence", "silence"},
118
    {GST_AUDIO_TEST_SRC_WAVE_WHITE_NOISE, "White uniform noise", "white-noise"},
119
    {GST_AUDIO_TEST_SRC_WAVE_PINK_NOISE, "Pink noise", "pink-noise"},
120
    {GST_AUDIO_TEST_SRC_WAVE_SINE_TAB, "Sine table", "sine-table"},
121
    {GST_AUDIO_TEST_SRC_WAVE_TICKS, "Periodic Ticks", "ticks"},
122
    {GST_AUDIO_TEST_SRC_WAVE_GAUSSIAN_WHITE_NOISE, "White Gaussian noise",
123
        "gaussian-noise"},
124
    {GST_AUDIO_TEST_SRC_WAVE_RED_NOISE, "Red (brownian) noise", "red-noise"},
125 126
    {GST_AUDIO_TEST_SRC_WAVE_BLUE_NOISE, "Blue noise", "blue-noise"},
    {GST_AUDIO_TEST_SRC_WAVE_VIOLET_NOISE, "Violet noise", "violet-noise"},
Stefan Kost's avatar
Stefan Kost committed
127 128 129
    {0, NULL, NULL},
  };

130
  if (G_UNLIKELY (audiostestsrc_wave_type == 0)) {
Stefan Kost's avatar
Stefan Kost committed
131 132 133 134 135 136
    audiostestsrc_wave_type = g_enum_register_static ("GstAudioTestSrcWave",
        audiostestsrc_waves);
  }
  return audiostestsrc_wave_type;
}

137 138
static void gst_audio_test_src_finalize (GObject * object);

139
static void gst_audio_test_src_set_property (GObject * object,
Stefan Kost's avatar
Stefan Kost committed
140
    guint prop_id, const GValue * value, GParamSpec * pspec);
141
static void gst_audio_test_src_get_property (GObject * object,
Stefan Kost's avatar
Stefan Kost committed
142 143
    guint prop_id, GValue * value, GParamSpec * pspec);

144 145 146
static gboolean gst_audio_test_src_setcaps (GstBaseSrc * basesrc,
    GstCaps * caps);
static void gst_audio_test_src_src_fixate (GstPad * pad, GstCaps * caps);
Stefan Kost's avatar
Stefan Kost committed
147

148 149 150
static gboolean gst_audio_test_src_is_seekable (GstBaseSrc * basesrc);
static gboolean gst_audio_test_src_do_seek (GstBaseSrc * basesrc,
    GstSegment * segment);
151
static gboolean gst_audio_test_src_query (GstBaseSrc * basesrc,
152
    GstQuery * query);
Stefan Kost's avatar
Stefan Kost committed
153

154
static void gst_audio_test_src_change_wave (GstAudioTestSrc * src);
Stefan Kost's avatar
Stefan Kost committed
155

156
static void gst_audio_test_src_get_times (GstBaseSrc * basesrc,
157
    GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
158 159
static gboolean gst_audio_test_src_start (GstBaseSrc * basesrc);
static gboolean gst_audio_test_src_stop (GstBaseSrc * basesrc);
160
static GstFlowReturn gst_audio_test_src_create (GstBaseSrc * basesrc,
Stefan Kost's avatar
Stefan Kost committed
161 162 163
    guint64 offset, guint length, GstBuffer ** buffer);

static void
164
gst_audio_test_src_class_init (GstAudioTestSrcClass * klass)
Stefan Kost's avatar
Stefan Kost committed
165 166
{
  GObjectClass *gobject_class;
167
  GstElementClass *gstelement_class;
Stefan Kost's avatar
Stefan Kost committed
168 169 170
  GstBaseSrcClass *gstbasesrc_class;

  gobject_class = (GObjectClass *) klass;
171
  gstelement_class = (GstElementClass *) klass;
Stefan Kost's avatar
Stefan Kost committed
172 173
  gstbasesrc_class = (GstBaseSrcClass *) klass;

174 175
  gobject_class->set_property = gst_audio_test_src_set_property;
  gobject_class->get_property = gst_audio_test_src_get_property;
176
  gobject_class->finalize = gst_audio_test_src_finalize;
Stefan Kost's avatar
Stefan Kost committed
177 178 179 180

  g_object_class_install_property (gobject_class, PROP_SAMPLES_PER_BUFFER,
      g_param_spec_int ("samplesperbuffer", "Samples per buffer",
          "Number of samples in each outgoing buffer",
181 182 183 184 185
          1, G_MAXINT, DEFAULT_SAMPLES_PER_BUFFER,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (gobject_class, PROP_WAVE,
      g_param_spec_enum ("wave", "Waveform", "Oscillator waveform",
          GST_TYPE_AUDIO_TEST_SRC_WAVE, GST_AUDIO_TEST_SRC_WAVE_SINE,
186
          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
Stefan Kost's avatar
Stefan Kost committed
187 188
  g_object_class_install_property (gobject_class, PROP_FREQ,
      g_param_spec_double ("freq", "Frequency", "Frequency of test signal",
189
          0.0, 20000.0, DEFAULT_FREQ,
190
          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
Stefan Kost's avatar
Stefan Kost committed
191
  g_object_class_install_property (gobject_class, PROP_VOLUME,
192
      g_param_spec_double ("volume", "Volume", "Volume of test signal", 0.0,
193
          1.0, DEFAULT_VOLUME,
194
          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
Stefan Kost's avatar
Stefan Kost committed
195 196
  g_object_class_install_property (gobject_class, PROP_IS_LIVE,
      g_param_spec_boolean ("is-live", "Is Live",
197
          "Whether to act as a live source", DEFAULT_IS_LIVE,
198
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Stefan Kost's avatar
Stefan Kost committed
199
  g_object_class_install_property (G_OBJECT_CLASS (klass),
200 201
      PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset",
          "Timestamp offset",
Stefan Kost's avatar
Stefan Kost committed
202
          "An offset added to timestamps set on buffers (in ns)", G_MININT64,
203 204
          G_MAXINT64, DEFAULT_TIMESTAMP_OFFSET,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
205 206 207 208 209 210 211 212
  g_object_class_install_property (gobject_class, PROP_CAN_ACTIVATE_PUSH,
      g_param_spec_boolean ("can-activate-push", "Can activate push",
          "Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (gobject_class, PROP_CAN_ACTIVATE_PULL,
      g_param_spec_boolean ("can-activate-pull", "Can activate pull",
          "Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Stefan Kost's avatar
Stefan Kost committed
213

214 215 216 217 218 219 220
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&gst_audio_test_src_src_template));
  gst_element_class_set_details_simple (gstelement_class,
      "Audio test source", "Source/Audio",
      "Creates audio test signals of given frequency and volume",
      "Stefan Kost <ensonic@users.sf.net>");

221
  gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_audio_test_src_setcaps);
222 223 224
  gstbasesrc_class->is_seekable =
      GST_DEBUG_FUNCPTR (gst_audio_test_src_is_seekable);
  gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_audio_test_src_do_seek);
225
  gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_audio_test_src_query);
226 227
  gstbasesrc_class->get_times =
      GST_DEBUG_FUNCPTR (gst_audio_test_src_get_times);
228 229
  gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_audio_test_src_start);
  gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_audio_test_src_stop);
230
  gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_audio_test_src_create);
Stefan Kost's avatar
Stefan Kost committed
231 232 233
}

static void
234
gst_audio_test_src_init (GstAudioTestSrc * src)
Stefan Kost's avatar
Stefan Kost committed
235 236 237
{
  GstPad *pad = GST_BASE_SRC_PAD (src);

238
  gst_pad_set_fixatecaps_function (pad, gst_audio_test_src_src_fixate);
Stefan Kost's avatar
Stefan Kost committed
239 240

  src->samplerate = 44100;
241
  src->format = GST_AUDIO_TEST_SRC_FORMAT_NONE;
242 243 244

  src->volume = DEFAULT_VOLUME;
  src->freq = DEFAULT_FREQ;
245

246 247
  /* we operate in time */
  gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
248
  gst_base_src_set_live (GST_BASE_SRC (src), DEFAULT_IS_LIVE);
Stefan Kost's avatar
Stefan Kost committed
249

250
  src->samples_per_buffer = DEFAULT_SAMPLES_PER_BUFFER;
251
  src->generate_samples_per_buffer = src->samples_per_buffer;
252
  src->timestamp_offset = DEFAULT_TIMESTAMP_OFFSET;
253
  src->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
Stefan Kost's avatar
Stefan Kost committed
254

255 256
  src->gen = NULL;

257
  src->wave = DEFAULT_WAVE;
258
  gst_base_src_set_blocksize (GST_BASE_SRC (src), -1);
Stefan Kost's avatar
Stefan Kost committed
259 260
}

261 262 263 264 265 266 267 268 269 270 271 272
static void
gst_audio_test_src_finalize (GObject * object)
{
  GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (object);

  if (src->gen)
    g_rand_free (src->gen);
  src->gen = NULL;

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

Stefan Kost's avatar
Stefan Kost committed
273
static void
274
gst_audio_test_src_src_fixate (GstPad * pad, GstCaps * caps)
Stefan Kost's avatar
Stefan Kost committed
275
{
276
  GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (GST_PAD_PARENT (pad));
277
  const gchar *name;
Stefan Kost's avatar
Stefan Kost committed
278 279 280 281
  GstStructure *structure;

  structure = gst_caps_get_structure (caps, 0);

282 283
  GST_DEBUG_OBJECT (src, "fixating samplerate to %d", src->samplerate);

284
  gst_structure_fixate_field_nearest_int (structure, "rate", src->samplerate);
285 286 287 288 289 290

  name = gst_structure_get_name (structure);
  if (strcmp (name, "audio/x-raw-int") == 0)
    gst_structure_fixate_field_nearest_int (structure, "width", 32);
  else if (strcmp (name, "audio/x-raw-float") == 0)
    gst_structure_fixate_field_nearest_int (structure, "width", 64);
291 292 293

  /* fixate to mono unless downstream requires stereo, for backwards compat */
  gst_structure_fixate_field_nearest_int (structure, "channels", 1);
Stefan Kost's avatar
Stefan Kost committed
294 295 296
}

static gboolean
297
gst_audio_test_src_setcaps (GstBaseSrc * basesrc, GstCaps * caps)
Stefan Kost's avatar
Stefan Kost committed
298
{
299
  GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc);
Stefan Kost's avatar
Stefan Kost committed
300
  const GstStructure *structure;
301 302
  const gchar *name;
  gint width;
Stefan Kost's avatar
Stefan Kost committed
303 304 305
  gboolean ret;

  structure = gst_caps_get_structure (caps, 0);
306
  ret = gst_structure_get_int (structure, "rate", &src->samplerate);
Stefan Kost's avatar
Stefan Kost committed
307

308 309
  GST_DEBUG_OBJECT (src, "negotiated to samplerate %d", src->samplerate);

310 311 312 313 314 315 316 317 318 319 320
  name = gst_structure_get_name (structure);
  if (strcmp (name, "audio/x-raw-int") == 0) {
    ret &= gst_structure_get_int (structure, "width", &width);
    src->format = (width == 32) ? GST_AUDIO_TEST_SRC_FORMAT_S32 :
        GST_AUDIO_TEST_SRC_FORMAT_S16;
  } else {
    ret &= gst_structure_get_int (structure, "width", &width);
    src->format = (width == 32) ? GST_AUDIO_TEST_SRC_FORMAT_F32 :
        GST_AUDIO_TEST_SRC_FORMAT_F64;
  }

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
  /* allocate a new buffer suitable for this pad */
  switch (src->format) {
    case GST_AUDIO_TEST_SRC_FORMAT_S16:
      src->sample_size = sizeof (gint16);
      break;
    case GST_AUDIO_TEST_SRC_FORMAT_S32:
      src->sample_size = sizeof (gint32);
      break;
    case GST_AUDIO_TEST_SRC_FORMAT_F32:
      src->sample_size = sizeof (gfloat);
      break;
    case GST_AUDIO_TEST_SRC_FORMAT_F64:
      src->sample_size = sizeof (gdouble);
      break;
    default:
      /* can't really happen */
      ret = FALSE;
      break;
  }

341 342 343
  ret &= gst_structure_get_int (structure, "channels", &src->channels);
  GST_DEBUG_OBJECT (src, "negotiated to %d channels", src->channels);

344 345
  gst_audio_test_src_change_wave (src);

Stefan Kost's avatar
Stefan Kost committed
346 347 348 349
  return ret;
}

static gboolean
350
gst_audio_test_src_query (GstBaseSrc * basesrc, GstQuery * query)
Stefan Kost's avatar
Stefan Kost committed
351
{
352
  GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc);
Stefan Kost's avatar
Stefan Kost committed
353 354
  gboolean res = FALSE;

355
  switch (GST_QUERY_TYPE (query)) {
356
    case GST_QUERY_CONVERT:
Stefan Kost's avatar
Stefan Kost committed
357
    {
358 359
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;
Stefan Kost's avatar
Stefan Kost committed
360

361
      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
362 363 364 365
      if (src_fmt == dest_fmt) {
        dest_val = src_val;
        goto done;
      }
Stefan Kost's avatar
Stefan Kost committed
366

367 368 369 370 371
      switch (src_fmt) {
        case GST_FORMAT_DEFAULT:
          switch (dest_fmt) {
            case GST_FORMAT_TIME:
              /* samples to time */
372 373 374
              dest_val =
                  gst_util_uint64_scale_int (src_val, GST_SECOND,
                  src->samplerate);
375 376 377 378
              break;
            default:
              goto error;
          }
Stefan Kost's avatar
Stefan Kost committed
379
          break;
380 381 382 383
        case GST_FORMAT_TIME:
          switch (dest_fmt) {
            case GST_FORMAT_DEFAULT:
              /* time to samples */
384 385 386
              dest_val =
                  gst_util_uint64_scale_int (src_val, src->samplerate,
                  GST_SECOND);
387 388 389 390
              break;
            default:
              goto error;
          }
Stefan Kost's avatar
Stefan Kost committed
391 392
          break;
        default:
393
          goto error;
Stefan Kost's avatar
Stefan Kost committed
394
      }
395
    done:
396
      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
397
      res = TRUE;
Wim Taymans's avatar
Wim Taymans committed
398 399
      break;
    }
400 401 402 403 404 405 406 407
    case GST_QUERY_SCHEDULING:
    {
      /* if we can operate in pull mode */
      gst_query_set_scheduling (query, src->can_activate_pull, TRUE, FALSE, 1,
          -1, 1);
      res = TRUE;
      break;
    }
Stefan Kost's avatar
Stefan Kost committed
408
    default:
409
      res = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
Stefan Kost's avatar
Stefan Kost committed
410 411 412 413
      break;
  }

  return res;
414 415 416 417 418 419
  /* ERROR */
error:
  {
    GST_DEBUG_OBJECT (src, "query failed");
    return FALSE;
  }
Stefan Kost's avatar
Stefan Kost committed
420 421
}

422 423 424 425
#define DEFINE_SINE(type,scale) \
static void \
gst_audio_test_src_create_sine_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
426
  gint i, c; \
427 428 429 430 431
  gdouble step, amp; \
  \
  step = M_PI_M2 * src->freq / src->samplerate; \
  amp = src->volume * scale; \
  \
432 433
  i = 0; \
  while (i < (src->generate_samples_per_buffer * src->channels)) { \
434 435 436 437
    src->accumulator += step; \
    if (src->accumulator >= M_PI_M2) \
      src->accumulator -= M_PI_M2; \
    \
438 439 440
    for (c = 0; c < src->channels; ++c) { \
      samples[i++] = (g##type) (sin (src->accumulator) * amp); \
    } \
441 442
  } \
}
Stefan Kost's avatar
Stefan Kost committed
443

444 445 446 447
DEFINE_SINE (int16, 32767.0);
DEFINE_SINE (int32, 2147483647.0);
DEFINE_SINE (float, 1.0);
DEFINE_SINE (double, 1.0);
Stefan Kost's avatar
Stefan Kost committed
448

449
static const ProcessFunc sine_funcs[] = {
450 451 452 453 454
  (ProcessFunc) gst_audio_test_src_create_sine_int16,
  (ProcessFunc) gst_audio_test_src_create_sine_int32,
  (ProcessFunc) gst_audio_test_src_create_sine_float,
  (ProcessFunc) gst_audio_test_src_create_sine_double
};
Stefan Kost's avatar
Stefan Kost committed
455

456 457 458 459
#define DEFINE_SQUARE(type,scale) \
static void \
gst_audio_test_src_create_square_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
460
  gint i, c; \
461 462 463 464 465
  gdouble step, amp; \
  \
  step = M_PI_M2 * src->freq / src->samplerate; \
  amp = src->volume * scale; \
  \
466 467
  i = 0; \
  while (i < (src->generate_samples_per_buffer * src->channels)) { \
468 469 470 471
    src->accumulator += step; \
    if (src->accumulator >= M_PI_M2) \
      src->accumulator -= M_PI_M2; \
    \
472
    for (c = 0; c < src->channels; ++c) { \
David Schleef's avatar
David Schleef committed
473
      samples[i++] = (g##type) ((src->accumulator < G_PI) ? amp : -amp); \
474
    } \
475
  } \
Stefan Kost's avatar
Stefan Kost committed
476 477
}

478 479 480 481
DEFINE_SQUARE (int16, 32767.0);
DEFINE_SQUARE (int32, 2147483647.0);
DEFINE_SQUARE (float, 1.0);
DEFINE_SQUARE (double, 1.0);
Stefan Kost's avatar
Stefan Kost committed
482

483
static const ProcessFunc square_funcs[] = {
484 485 486 487 488
  (ProcessFunc) gst_audio_test_src_create_square_int16,
  (ProcessFunc) gst_audio_test_src_create_square_int32,
  (ProcessFunc) gst_audio_test_src_create_square_float,
  (ProcessFunc) gst_audio_test_src_create_square_double
};
Stefan Kost's avatar
Stefan Kost committed
489

490 491 492 493
#define DEFINE_SAW(type,scale) \
static void \
gst_audio_test_src_create_saw_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
494
  gint i, c; \
495 496 497
  gdouble step, amp; \
  \
  step = M_PI_M2 * src->freq / src->samplerate; \
David Schleef's avatar
David Schleef committed
498
  amp = (src->volume * scale) / G_PI; \
499
  \
500 501
  i = 0; \
  while (i < (src->generate_samples_per_buffer * src->channels)) { \
502 503 504 505
    src->accumulator += step; \
    if (src->accumulator >= M_PI_M2) \
      src->accumulator -= M_PI_M2; \
    \
David Schleef's avatar
David Schleef committed
506
    if (src->accumulator < G_PI) { \
507 508
      for (c = 0; c < src->channels; ++c) \
        samples[i++] = (g##type) (src->accumulator * amp); \
509
    } else { \
510 511
      for (c = 0; c < src->channels; ++c) \
        samples[i++] = (g##type) ((M_PI_M2 - src->accumulator) * -amp); \
512 513
    } \
  } \
Stefan Kost's avatar
Stefan Kost committed
514 515
}

516 517 518 519
DEFINE_SAW (int16, 32767.0);
DEFINE_SAW (int32, 2147483647.0);
DEFINE_SAW (float, 1.0);
DEFINE_SAW (double, 1.0);
Stefan Kost's avatar
Stefan Kost committed
520

521
static const ProcessFunc saw_funcs[] = {
522 523 524 525 526
  (ProcessFunc) gst_audio_test_src_create_saw_int16,
  (ProcessFunc) gst_audio_test_src_create_saw_int32,
  (ProcessFunc) gst_audio_test_src_create_saw_float,
  (ProcessFunc) gst_audio_test_src_create_saw_double
};
Stefan Kost's avatar
Stefan Kost committed
527

528 529 530 531
#define DEFINE_TRIANGLE(type,scale) \
static void \
gst_audio_test_src_create_triangle_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
532
  gint i, c; \
533 534 535
  gdouble step, amp; \
  \
  step = M_PI_M2 * src->freq / src->samplerate; \
David Schleef's avatar
David Schleef committed
536
  amp = (src->volume * scale) / G_PI_2; \
537
  \
538 539
  i = 0; \
  while (i < (src->generate_samples_per_buffer * src->channels)) { \
540 541 542 543
    src->accumulator += step; \
    if (src->accumulator >= M_PI_M2) \
      src->accumulator -= M_PI_M2; \
    \
David Schleef's avatar
David Schleef committed
544
    if (src->accumulator < (G_PI_2)) { \
545 546
      for (c = 0; c < src->channels; ++c) \
        samples[i++] = (g##type) (src->accumulator * amp); \
David Schleef's avatar
David Schleef committed
547
    } else if (src->accumulator < (G_PI * 1.5)) { \
548
      for (c = 0; c < src->channels; ++c) \
David Schleef's avatar
David Schleef committed
549
        samples[i++] = (g##type) ((src->accumulator - G_PI) * -amp); \
550
    } else { \
551 552
      for (c = 0; c < src->channels; ++c) \
        samples[i++] = (g##type) ((M_PI_M2 - src->accumulator) * -amp); \
553 554
    } \
  } \
Stefan Kost's avatar
Stefan Kost committed
555 556
}

557 558 559 560
DEFINE_TRIANGLE (int16, 32767.0);
DEFINE_TRIANGLE (int32, 2147483647.0);
DEFINE_TRIANGLE (float, 1.0);
DEFINE_TRIANGLE (double, 1.0);
Stefan Kost's avatar
Stefan Kost committed
561

562
static const ProcessFunc triangle_funcs[] = {
563 564 565 566 567 568 569 570 571 572
  (ProcessFunc) gst_audio_test_src_create_triangle_int16,
  (ProcessFunc) gst_audio_test_src_create_triangle_int32,
  (ProcessFunc) gst_audio_test_src_create_triangle_float,
  (ProcessFunc) gst_audio_test_src_create_triangle_double
};

#define DEFINE_SILENCE(type) \
static void \
gst_audio_test_src_create_silence_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
573
  memset (samples, 0, src->generate_samples_per_buffer * sizeof (g##type) * src->channels); \
Stefan Kost's avatar
Stefan Kost committed
574 575
}

576 577 578 579
DEFINE_SILENCE (int16);
DEFINE_SILENCE (int32);
DEFINE_SILENCE (float);
DEFINE_SILENCE (double);
Stefan Kost's avatar
Stefan Kost committed
580

581
static const ProcessFunc silence_funcs[] = {
582 583 584 585 586
  (ProcessFunc) gst_audio_test_src_create_silence_int16,
  (ProcessFunc) gst_audio_test_src_create_silence_int32,
  (ProcessFunc) gst_audio_test_src_create_silence_float,
  (ProcessFunc) gst_audio_test_src_create_silence_double
};
Stefan Kost's avatar
Stefan Kost committed
587

588 589 590 591
#define DEFINE_WHITE_NOISE(type,scale) \
static void \
gst_audio_test_src_create_white_noise_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
592
  gint i, c; \
593 594
  gdouble amp = (src->volume * scale); \
  \
595 596 597
  i = 0; \
  while (i < (src->generate_samples_per_buffer * src->channels)) { \
    for (c = 0; c < src->channels; ++c) \
598
      samples[i++] = (g##type) (amp * g_rand_double_range (src->gen, -1.0, 1.0)); \
599
  } \
Stefan Kost's avatar
Stefan Kost committed
600 601
}

602 603 604 605 606
DEFINE_WHITE_NOISE (int16, 32767.0);
DEFINE_WHITE_NOISE (int32, 2147483647.0);
DEFINE_WHITE_NOISE (float, 1.0);
DEFINE_WHITE_NOISE (double, 1.0);

607
static const ProcessFunc white_noise_funcs[] = {
608 609 610 611 612 613
  (ProcessFunc) gst_audio_test_src_create_white_noise_int16,
  (ProcessFunc) gst_audio_test_src_create_white_noise_int32,
  (ProcessFunc) gst_audio_test_src_create_white_noise_float,
  (ProcessFunc) gst_audio_test_src_create_white_noise_double
};

614
/* pink noise calculation is based on
615 616 617 618 619
 * http://www.firstpr.com.au/dsp/pink-noise/phil_burk_19990905_patest_pink.c
 * which has been released under public domain
 * Many thanks Phil!
 */
static void
620
gst_audio_test_src_init_pink_noise (GstAudioTestSrc * src)
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
{
  gint i;
  gint num_rows = 12;           /* arbitrary: 1 .. PINK_MAX_RANDOM_ROWS */
  glong pmax;

  src->pink.index = 0;
  src->pink.index_mask = (1 << num_rows) - 1;
  /* calculate maximum possible signed random value.
   * Extra 1 for white noise always added. */
  pmax = (num_rows + 1) * (1 << (PINK_RANDOM_BITS - 1));
  src->pink.scalar = 1.0f / pmax;
  /* Initialize rows. */
  for (i = 0; i < num_rows; i++)
    src->pink.rows[i] = 0;
  src->pink.running_sum = 0;
}

/* Generate Pink noise values between -1.0 and +1.0 */
639
static gdouble
640
gst_audio_test_src_generate_pink_noise_value (GstAudioTestSrc * src)
641
{
642
  GstPinkNoise *pink = &src->pink;
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
  glong new_random;
  glong sum;

  /* Increment and mask index. */
  pink->index = (pink->index + 1) & pink->index_mask;

  /* If index is zero, don't update any random values. */
  if (pink->index != 0) {
    /* Determine how many trailing zeros in PinkIndex. */
    /* This algorithm will hang if n==0 so test first. */
    gint num_zeros = 0;
    gint n = pink->index;

    while ((n & 1) == 0) {
      n = n >> 1;
      num_zeros++;
    }

    /* Replace the indexed ROWS random value.
     * Subtract and add back to RunningSum instead of adding all the random
     * values together. Only one changes each time.
     */
    pink->running_sum -= pink->rows[num_zeros];
666 667
    new_random = 32768.0 - (65536.0 * (gulong) g_rand_int (src->gen)
        / (G_MAXUINT32 + 1.0));
668 669 670 671 672
    pink->running_sum += new_random;
    pink->rows[num_zeros] = new_random;
  }

  /* Add extra white noise value. */
673 674
  new_random = 32768.0 - (65536.0 * (gulong) g_rand_int (src->gen)
      / (G_MAXUINT32 + 1.0));
675 676 677 678 679 680
  sum = pink->running_sum + new_random;

  /* Scale to range of -1.0 to 0.9999. */
  return (pink->scalar * sum);
}

681 682 683 684
#define DEFINE_PINK(type, scale) \
static void \
gst_audio_test_src_create_pink_noise_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
685
  gint i, c; \
686 687 688 689
  gdouble amp; \
  \
  amp = src->volume * scale; \
  \
690 691 692 693
  i = 0; \
  while (i < (src->generate_samples_per_buffer * src->channels)) { \
    for (c = 0; c < src->channels; ++c) { \
      samples[i++] = \
694
        (g##type) (gst_audio_test_src_generate_pink_noise_value (src) * \
695
        amp); \
696
    } \
697 698
  } \
}
699

700 701 702 703
DEFINE_PINK (int16, 32767.0);
DEFINE_PINK (int32, 2147483647.0);
DEFINE_PINK (float, 1.0);
DEFINE_PINK (double, 1.0);
704

705
static const ProcessFunc pink_noise_funcs[] = {
706 707 708 709 710
  (ProcessFunc) gst_audio_test_src_create_pink_noise_int16,
  (ProcessFunc) gst_audio_test_src_create_pink_noise_int32,
  (ProcessFunc) gst_audio_test_src_create_pink_noise_float,
  (ProcessFunc) gst_audio_test_src_create_pink_noise_double
};
711

712 713 714 715 716 717
static void
gst_audio_test_src_init_sine_table (GstAudioTestSrc * src)
{
  gint i;
  gdouble ang = 0.0;
  gdouble step = M_PI_M2 / 1024.0;
718
  gdouble amp = src->volume;
719 720

  for (i = 0; i < 1024; i++) {
721
    src->wave_table[i] = sin (ang) * amp;
722 723 724 725
    ang += step;
  }
}

726 727 728 729
#define DEFINE_SINE_TABLE(type,scale) \
static void \
gst_audio_test_src_create_sine_table_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
730
  gint i, c; \
731 732 733 734 735
  gdouble step, scl; \
  \
  step = M_PI_M2 * src->freq / src->samplerate; \
  scl = 1024.0 / M_PI_M2; \
  \
736 737
  i = 0; \
  while (i < (src->generate_samples_per_buffer * src->channels)) { \
738 739 740 741
    src->accumulator += step; \
    if (src->accumulator >= M_PI_M2) \
      src->accumulator -= M_PI_M2; \
    \
742 743
    for (c = 0; c < src->channels; ++c) \
      samples[i++] = (g##type) scale * src->wave_table[(gint) (src->accumulator * scl)]; \
744 745
  } \
}
746

747 748 749 750
DEFINE_SINE_TABLE (int16, 32767.0);
DEFINE_SINE_TABLE (int32, 2147483647.0);
DEFINE_SINE_TABLE (float, 1.0);
DEFINE_SINE_TABLE (double, 1.0);
751

752
static const ProcessFunc sine_table_funcs[] = {
753 754 755 756 757
  (ProcessFunc) gst_audio_test_src_create_sine_table_int16,
  (ProcessFunc) gst_audio_test_src_create_sine_table_int32,
  (ProcessFunc) gst_audio_test_src_create_sine_table_float,
  (ProcessFunc) gst_audio_test_src_create_sine_table_double
};
758

759 760 761 762
#define DEFINE_TICKS(type,scale) \
static void \
gst_audio_test_src_create_tick_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
763
  gint i, c; \
764 765 766 767 768 769 770 771 772 773
  gdouble step, scl; \
  \
  step = M_PI_M2 * src->freq / src->samplerate; \
  scl = 1024.0 / M_PI_M2; \
  \
  for (i = 0; i < src->generate_samples_per_buffer; i++) { \
    src->accumulator += step; \
    if (src->accumulator >= M_PI_M2) \
      src->accumulator -= M_PI_M2; \
    \
774
    if ((src->next_sample + i)%src->samplerate < 1600) { \
775 776
      for (c = 0; c < src->channels; ++c) \
        samples[(i * src->channels) + c] = (g##type) scale * src->wave_table[(gint) (src->accumulator * scl)]; \
777
    } else { \
778 779
      for (c = 0; c < src->channels; ++c) \
        samples[(i * src->channels) + c] = 0; \
780 781 782 783 784 785 786 787 788
    } \
  } \
}

DEFINE_TICKS (int16, 32767.0);
DEFINE_TICKS (int32, 2147483647.0);
DEFINE_TICKS (float, 1.0);
DEFINE_TICKS (double, 1.0);

789
static const ProcessFunc tick_funcs[] = {
790 791 792 793 794 795
  (ProcessFunc) gst_audio_test_src_create_tick_int16,
  (ProcessFunc) gst_audio_test_src_create_tick_int32,
  (ProcessFunc) gst_audio_test_src_create_tick_float,
  (ProcessFunc) gst_audio_test_src_create_tick_double
};

796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
/* Gaussian white noise using Box-Muller algorithm.  unit variance
 * normally-distributed random numbers are generated in pairs as the real
 * and imaginary parts of a compex random variable with
 * uniformly-distributed argument and \chi^{2}-distributed modulus.
 */

#define DEFINE_GAUSSIAN_WHITE_NOISE(type,scale) \
static void \
gst_audio_test_src_create_gaussian_white_noise_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
  gint i, c; \
  gdouble amp = (src->volume * scale); \
  \
  for (i = 0; i < src->generate_samples_per_buffer * src->channels; ) { \
    for (c = 0; c < src->channels; ++c) { \
811 812
      gdouble mag = sqrt (-2 * log (1.0 - g_rand_double (src->gen))); \
      gdouble phs = g_rand_double_range (src->gen, 0.0, M_PI_M2); \
813 814 815 816 817 818 819 820 821 822 823 824 825 826
      \
      samples[i++] = (g##type) (amp * mag * cos (phs)); \
      if (++c >= src->channels) \
        break; \
      samples[i++] = (g##type) (amp * mag * sin (phs)); \
    } \
  } \
}

DEFINE_GAUSSIAN_WHITE_NOISE (int16, 32767.0);
DEFINE_GAUSSIAN_WHITE_NOISE (int32, 2147483647.0);
DEFINE_GAUSSIAN_WHITE_NOISE (float, 1.0);
DEFINE_GAUSSIAN_WHITE_NOISE (double, 1.0);

827
static const ProcessFunc gaussian_white_noise_funcs[] = {
828 829 830 831 832 833
  (ProcessFunc) gst_audio_test_src_create_gaussian_white_noise_int16,
  (ProcessFunc) gst_audio_test_src_create_gaussian_white_noise_int32,
  (ProcessFunc) gst_audio_test_src_create_gaussian_white_noise_float,
  (ProcessFunc) gst_audio_test_src_create_gaussian_white_noise_double
};

834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
/* Brownian (Red) Noise: noise where the power density decreases by 6 dB per
 * octave with increasing frequency
 *
 * taken from http://vellocet.com/dsp/noise/VRand.html
 * by Andrew Simper of Vellocet (andy@vellocet.com)
 */

#define DEFINE_RED_NOISE(type,scale) \
static void \
gst_audio_test_src_create_red_noise_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
  gint i, c; \
  gdouble amp = (src->volume * scale); \
  gdouble state = src->red.state; \
  \
  for (i = 0; i < src->generate_samples_per_buffer * src->channels; ) { \
    for (c = 0; c < src->channels; ++c) { \
      while (TRUE) { \
        gdouble  r = g_rand_double_range (src->gen, -1.0, 1.0); \
        state += r; \
        if (state<-8.0f || state>8.0f) state -= r; \
        else break; \
      } \
      samples[i++] = (g##type) (amp * state * 0.0625f); /* /16.0 */ \
    } \
  } \
  src->red.state = state; \
}

DEFINE_RED_NOISE (int16, 32767.0);
DEFINE_RED_NOISE (int32, 2147483647.0);
DEFINE_RED_NOISE (float, 1.0);
DEFINE_RED_NOISE (double, 1.0);

static const ProcessFunc red_noise_funcs[] = {
  (ProcessFunc) gst_audio_test_src_create_red_noise_int16,
  (ProcessFunc) gst_audio_test_src_create_red_noise_int32,
  (ProcessFunc) gst_audio_test_src_create_red_noise_float,
  (ProcessFunc) gst_audio_test_src_create_red_noise_double
};

875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
/* Blue Noise: apply spectral inversion to pink noise */

#define DEFINE_BLUE_NOISE(type) \
static void \
gst_audio_test_src_create_blue_noise_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
  gint i, c; \
  static gdouble flip=1.0; \
  \
  gst_audio_test_src_create_pink_noise_##type (src, samples); \
  for (i = 0; i < src->generate_samples_per_buffer * src->channels; ) { \
    for (c = 0; c < src->channels; ++c) { \
      samples[i++] *= flip; \
    } \
    flip *= -1.0; \
  } \
}

DEFINE_BLUE_NOISE (int16);
DEFINE_BLUE_NOISE (int32);
DEFINE_BLUE_NOISE (float);
DEFINE_BLUE_NOISE (double);

static const ProcessFunc blue_noise_funcs[] = {
  (ProcessFunc) gst_audio_test_src_create_blue_noise_int16,
  (ProcessFunc) gst_audio_test_src_create_blue_noise_int32,
  (ProcessFunc) gst_audio_test_src_create_blue_noise_float,
  (ProcessFunc) gst_audio_test_src_create_blue_noise_double
};


/* Violet Noise: apply spectral inversion to red noise */

#define DEFINE_VIOLET_NOISE(type) \
static void \
gst_audio_test_src_create_violet_noise_##type (GstAudioTestSrc * src, g##type * samples) \
{ \
  gint i, c; \
  static gdouble flip=1.0; \
  \
  gst_audio_test_src_create_red_noise_##type (src, samples); \
  for (i = 0; i < src->generate_samples_per_buffer * src->channels; ) { \
    for (c = 0; c < src->channels; ++c) { \
      samples[i++] *= flip; \
    } \
    flip *= -1.0; \
  } \
}

DEFINE_VIOLET_NOISE (int16);
DEFINE_VIOLET_NOISE (int32);
DEFINE_VIOLET_NOISE (float);
DEFINE_VIOLET_NOISE (double);

static const ProcessFunc violet_noise_funcs[] = {
  (ProcessFunc) gst_audio_test_src_create_violet_noise_int16,
  (ProcessFunc) gst_audio_test_src_create_violet_noise_int32,
  (ProcessFunc) gst_audio_test_src_create_violet_noise_float,
  (ProcessFunc) gst_audio_test_src_create_violet_noise_double
};
935 936


937 938 939 940
/*
 * gst_audio_test_src_change_wave:
 * Assign function pointer of wave genrator.
 */
Stefan Kost's avatar
Stefan Kost committed
941
static void
942
gst_audio_test_src_change_wave (GstAudioTestSrc * src)
Stefan Kost's avatar
Stefan Kost committed
943
{
944 945 946 947 948
  if (src->format == -1) {
    src->process = NULL;
    return;
  }

Stefan Kost's avatar
Stefan Kost committed
949
  switch (src->wave) {
950
    case GST_AUDIO_TEST_SRC_WAVE_SINE:
951
      src->process = sine_funcs[src->format];
Stefan Kost's avatar
Stefan Kost committed
952
      break;
953
    case GST_AUDIO_TEST_SRC_WAVE_SQUARE:
954
      src->process = square_funcs[src->format];
Stefan Kost's avatar
Stefan Kost committed
955
      break;
956
    case GST_AUDIO_TEST_SRC_WAVE_SAW:
957
      src->process = saw_funcs[src->format];
Stefan Kost's avatar
Stefan Kost committed
958
      break;
959
    case GST_AUDIO_TEST_SRC_WAVE_TRIANGLE:
960
      src->process = triangle_funcs[src->format];
Stefan Kost's avatar
Stefan Kost committed
961
      break;
962
    case GST_AUDIO_TEST_SRC_WAVE_SILENCE:
963
      src->process = silence_funcs[src->format];
Stefan Kost's avatar
Stefan Kost committed
964
      break;
965
    case GST_AUDIO_TEST_SRC_WAVE_WHITE_NOISE:
966 967
      if (!(src->gen))
        src->gen = g_rand_new ();
968
      src->process = white_noise_funcs[src->format];
Stefan Kost's avatar
Stefan Kost committed
969
      break;