gst_plugins_base/gst/audiotestsrc/gstaudiotestsrc.c
changeset 0 0e761a78d257
child 8 4a7fac7dd34a
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     1 /* GStreamer
       
     2  * Copyright (C) 2005 Stefan Kost <ensonic@users.sf.net>
       
     3  *
       
     4  * This library is free software; you can redistribute it and/or
       
     5  * modify it under the terms of the GNU Library General Public
       
     6  * License as published by the Free Software Foundation; either
       
     7  * version 2 of the License, or (at your option) any later version.
       
     8  *
       
     9  * This library is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    12  * Library General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU Library General Public
       
    15  * License along with this library; if not, write to the
       
    16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    17  * Boston, MA 02111-1307, USA.
       
    18  */
       
    19 /**
       
    20  * SECTION:element-audiotestsrc
       
    21  *
       
    22  * <refsect2>
       
    23  * <para>
       
    24  * AudioTestSrc can be used to generate basic audio signals. It support several
       
    25  * different waveforms and allows you to set the base frequency and volume.
       
    26  * </para>
       
    27  * <title>Example launch line</title>
       
    28  * <para>
       
    29  * <programlisting>
       
    30  * gst-launch audiotestsrc ! audioconvert ! alsasink
       
    31  * </programlisting>
       
    32  * This pipeline produces a sine with default frequency (mid-C) and volume.
       
    33  * </para>
       
    34  * <para>
       
    35  * <programlisting>
       
    36  * gst-launch audiotestsrc wave=2 freq=200 ! audioconvert ! tee name=t ! queue ! alsasink t. ! queue ! libvisual_lv_scope ! ffmpegcolorspace ! xvimagesink
       
    37  * </programlisting>
       
    38  * In this example a saw wave is generated. The wave is shown using a
       
    39  * scope visualizer from libvisual, allowing you to visually verify that
       
    40  * the saw wave is correct.
       
    41  * </para>
       
    42  * </refsect2>
       
    43  */
       
    44 
       
    45 #ifdef HAVE_CONFIG_H
       
    46 #include "config.h"
       
    47 #endif
       
    48 
       
    49 #include <math.h>
       
    50 #include <stdlib.h>
       
    51 #include <string.h>
       
    52 #include <gst/controller/gstcontroller.h>
       
    53 #include <glib_global.h>
       
    54 #include "gstaudiotestsrc.h"
       
    55 
       
    56 
       
    57 #ifndef M_PI
       
    58 #define M_PI  3.14159265358979323846
       
    59 #endif
       
    60 
       
    61 #ifndef M_PI_2
       
    62 #define M_PI_2  1.57079632679489661923
       
    63 #endif
       
    64 
       
    65 #define M_PI_M2 ( M_PI + M_PI )
       
    66 
       
    67 GST_DEBUG_CATEGORY_STATIC (audio_test_src_debug);
       
    68 #define GST_CAT_DEFAULT audio_test_src_debug
       
    69 
       
    70 static const GstElementDetails gst_audio_test_src_details =
       
    71 GST_ELEMENT_DETAILS ("Audio test source",
       
    72     "Source/Audio",
       
    73     "Creates audio test signals of given frequency and volume",
       
    74     "Stefan Kost <ensonic@users.sf.net>");
       
    75 
       
    76 
       
    77 enum
       
    78 {
       
    79   PROP_0,
       
    80   PROP_SAMPLES_PER_BUFFER,
       
    81   PROP_WAVE,
       
    82   PROP_FREQ,
       
    83   PROP_VOLUME,
       
    84   PROP_IS_LIVE,
       
    85   PROP_TIMESTAMP_OFFSET,
       
    86 };
       
    87 
       
    88 
       
    89 static GstStaticPadTemplate gst_audio_test_src_src_template =
       
    90     GST_STATIC_PAD_TEMPLATE ("src",
       
    91     GST_PAD_SRC,
       
    92     GST_PAD_ALWAYS,
       
    93     GST_STATIC_CAPS ("audio/x-raw-int, "
       
    94         "endianness = (int) BYTE_ORDER, "
       
    95         "signed = (boolean) true, "
       
    96         "width = (int) 16, "
       
    97         "depth = (int) 16, "
       
    98         "rate = (int) [ 1, MAX ], "
       
    99         "channels = (int) 1; "
       
   100         "audio/x-raw-int, "
       
   101         "endianness = (int) BYTE_ORDER, "
       
   102         "signed = (boolean) true, "
       
   103         "width = (int) 32, "
       
   104         "depth = (int) 32,"
       
   105         "rate = (int) [ 1, MAX ], "
       
   106         "channels = (int) 1; "
       
   107         "audio/x-raw-float, "
       
   108         "endianness = (int) BYTE_ORDER, "
       
   109         "width = (int) { 32, 64 }, "
       
   110         "rate = (int) [ 1, MAX ], " "channels = (int) 1")
       
   111     );
       
   112 
       
   113 
       
   114 GST_BOILERPLATE (GstAudioTestSrc, gst_audio_test_src, GstBaseSrc,
       
   115     GST_TYPE_BASE_SRC);
       
   116 
       
   117 #define GST_TYPE_AUDIO_TEST_SRC_WAVE (gst_audiostestsrc_wave_get_type())
       
   118 static GType
       
   119 gst_audiostestsrc_wave_get_type (void)
       
   120 {
       
   121   static GType audiostestsrc_wave_type = 0;
       
   122   static const GEnumValue audiostestsrc_waves[] = {
       
   123     {GST_AUDIO_TEST_SRC_WAVE_SINE, "Sine", "sine"},
       
   124     {GST_AUDIO_TEST_SRC_WAVE_SQUARE, "Square", "square"},
       
   125     {GST_AUDIO_TEST_SRC_WAVE_SAW, "Saw", "saw"},
       
   126     {GST_AUDIO_TEST_SRC_WAVE_TRIANGLE, "Triangle", "triangle"},
       
   127     {GST_AUDIO_TEST_SRC_WAVE_SILENCE, "Silence", "silence"},
       
   128     {GST_AUDIO_TEST_SRC_WAVE_WHITE_NOISE, "White noise", "white-noise"},
       
   129     {GST_AUDIO_TEST_SRC_WAVE_PINK_NOISE, "Pink noise", "pink-noise"},
       
   130     {GST_AUDIO_TEST_SRC_WAVE_SINE_TAB, "Sine table", "sine table"},
       
   131     {0, NULL, NULL},
       
   132   };
       
   133 
       
   134   if (G_UNLIKELY (audiostestsrc_wave_type == 0)) {
       
   135     audiostestsrc_wave_type = g_enum_register_static ("GstAudioTestSrcWave",
       
   136         audiostestsrc_waves);
       
   137   }
       
   138   return audiostestsrc_wave_type;
       
   139 }
       
   140 
       
   141 static void gst_audio_test_src_set_property (GObject * object,
       
   142     guint prop_id, const GValue * value, GParamSpec * pspec);
       
   143 static void gst_audio_test_src_get_property (GObject * object,
       
   144     guint prop_id, GValue * value, GParamSpec * pspec);
       
   145 
       
   146 static gboolean gst_audio_test_src_setcaps (GstBaseSrc * basesrc,
       
   147     GstCaps * caps);
       
   148 static void gst_audio_test_src_src_fixate (GstPad * pad, GstCaps * caps);
       
   149 
       
   150 static gboolean gst_audio_test_src_is_seekable (GstBaseSrc * basesrc);
       
   151 static gboolean gst_audio_test_src_do_seek (GstBaseSrc * basesrc,
       
   152     GstSegment * segment);
       
   153 static gboolean gst_audio_test_src_query (GstBaseSrc * basesrc,
       
   154     GstQuery * query);
       
   155 
       
   156 static void gst_audio_test_src_change_wave (GstAudioTestSrc * src);
       
   157 
       
   158 static void gst_audio_test_src_get_times (GstBaseSrc * basesrc,
       
   159     GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
       
   160 static GstFlowReturn gst_audio_test_src_create (GstBaseSrc * basesrc,
       
   161     guint64 offset, guint length, GstBuffer ** buffer);
       
   162 
       
   163 
       
   164 static void
       
   165 gst_audio_test_src_base_init (gpointer g_class)
       
   166 {
       
   167   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
       
   168 
       
   169   gst_element_class_add_pad_template (element_class,
       
   170       gst_static_pad_template_get (&gst_audio_test_src_src_template));
       
   171   gst_element_class_set_details (element_class, &gst_audio_test_src_details);
       
   172 }
       
   173 
       
   174 static void
       
   175 gst_audio_test_src_class_init (GstAudioTestSrcClass * klass)
       
   176 {
       
   177   GObjectClass *gobject_class;
       
   178   GstBaseSrcClass *gstbasesrc_class;
       
   179 
       
   180   gobject_class = (GObjectClass *) klass;
       
   181   gstbasesrc_class = (GstBaseSrcClass *) klass;
       
   182 
       
   183   gobject_class->set_property = gst_audio_test_src_set_property;
       
   184   gobject_class->get_property = gst_audio_test_src_get_property;
       
   185 
       
   186   g_object_class_install_property (gobject_class, PROP_SAMPLES_PER_BUFFER,
       
   187       g_param_spec_int ("samplesperbuffer", "Samples per buffer",
       
   188           "Number of samples in each outgoing buffer",
       
   189           1, G_MAXINT, 1024, G_PARAM_READWRITE));
       
   190   g_object_class_install_property (gobject_class, PROP_WAVE, g_param_spec_enum ("wave", "Waveform", "Oscillator waveform", GST_TYPE_AUDIO_TEST_SRC_WAVE,        /* enum type */
       
   191           GST_AUDIO_TEST_SRC_WAVE_SINE, /* default value */
       
   192           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
       
   193   g_object_class_install_property (gobject_class, PROP_FREQ,
       
   194       g_param_spec_double ("freq", "Frequency", "Frequency of test signal",
       
   195           0.0, 20000.0, 440.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
       
   196   g_object_class_install_property (gobject_class, PROP_VOLUME,
       
   197       g_param_spec_double ("volume", "Volume", "Volume of test signal",
       
   198           0.0, 1.0, 0.8, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
       
   199   g_object_class_install_property (gobject_class, PROP_IS_LIVE,
       
   200       g_param_spec_boolean ("is-live", "Is Live",
       
   201           "Whether to act as a live source", FALSE, G_PARAM_READWRITE));
       
   202   g_object_class_install_property (G_OBJECT_CLASS (klass),
       
   203       PROP_TIMESTAMP_OFFSET,
       
   204       g_param_spec_int64 ("timestamp-offset", "Timestamp offset",
       
   205           "An offset added to timestamps set on buffers (in ns)", G_MININT64,
       
   206           G_MAXINT64, 0, G_PARAM_READWRITE));
       
   207 
       
   208   gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_audio_test_src_setcaps);
       
   209   gstbasesrc_class->is_seekable =
       
   210       GST_DEBUG_FUNCPTR (gst_audio_test_src_is_seekable);
       
   211   gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_audio_test_src_do_seek);
       
   212   gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_audio_test_src_query);
       
   213   gstbasesrc_class->get_times =
       
   214       GST_DEBUG_FUNCPTR (gst_audio_test_src_get_times);
       
   215   gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_audio_test_src_create);
       
   216 }
       
   217 
       
   218 static void
       
   219 gst_audio_test_src_init (GstAudioTestSrc * src, GstAudioTestSrcClass * g_class)
       
   220 {
       
   221   GstPad *pad = GST_BASE_SRC_PAD (src);
       
   222 
       
   223   gst_pad_set_fixatecaps_function (pad, gst_audio_test_src_src_fixate);
       
   224 
       
   225   src->samplerate = 44100;
       
   226   src->format = GST_AUDIO_TEST_SRC_FORMAT_NONE;
       
   227   src->volume = 0.8;
       
   228   src->freq = 440.0;
       
   229 
       
   230   /* we operate in time */
       
   231   gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
       
   232   gst_base_src_set_live (GST_BASE_SRC (src), FALSE);
       
   233 
       
   234   src->samples_per_buffer = 1024;
       
   235   src->generate_samples_per_buffer = src->samples_per_buffer;
       
   236   src->timestamp_offset = G_GINT64_CONSTANT (0);
       
   237 
       
   238   src->wave = GST_AUDIO_TEST_SRC_WAVE_SINE;
       
   239 }
       
   240 
       
   241 static void
       
   242 gst_audio_test_src_src_fixate (GstPad * pad, GstCaps * caps)
       
   243 {
       
   244   GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (GST_PAD_PARENT (pad));
       
   245   const gchar *name;
       
   246   GstStructure *structure;
       
   247 
       
   248   structure = gst_caps_get_structure (caps, 0);
       
   249 
       
   250   gst_structure_fixate_field_nearest_int (structure, "rate", src->samplerate);
       
   251 
       
   252   name = gst_structure_get_name (structure);
       
   253   if (strcmp (name, "audio/x-raw-int") == 0)
       
   254     gst_structure_fixate_field_nearest_int (structure, "width", 32);
       
   255   else if (strcmp (name, "audio/x-raw-float") == 0)
       
   256     gst_structure_fixate_field_nearest_int (structure, "width", 64);
       
   257 }
       
   258 
       
   259 static gboolean
       
   260 gst_audio_test_src_setcaps (GstBaseSrc * basesrc, GstCaps * caps)
       
   261 {
       
   262   GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc);
       
   263   const GstStructure *structure;
       
   264   const gchar *name;
       
   265   gint width;
       
   266   gboolean ret;
       
   267 
       
   268   structure = gst_caps_get_structure (caps, 0);
       
   269   ret = gst_structure_get_int (structure, "rate", &src->samplerate);
       
   270 
       
   271   name = gst_structure_get_name (structure);
       
   272   if (strcmp (name, "audio/x-raw-int") == 0) {
       
   273     ret &= gst_structure_get_int (structure, "width", &width);
       
   274     src->format = (width == 32) ? GST_AUDIO_TEST_SRC_FORMAT_S32 :
       
   275         GST_AUDIO_TEST_SRC_FORMAT_S16;
       
   276   } else {
       
   277     ret &= gst_structure_get_int (structure, "width", &width);
       
   278     src->format = (width == 32) ? GST_AUDIO_TEST_SRC_FORMAT_F32 :
       
   279         GST_AUDIO_TEST_SRC_FORMAT_F64;
       
   280   }
       
   281 
       
   282   gst_audio_test_src_change_wave (src);
       
   283 
       
   284   return ret;
       
   285 }
       
   286 
       
   287 static gboolean
       
   288 gst_audio_test_src_query (GstBaseSrc * basesrc, GstQuery * query)
       
   289 {
       
   290   GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc);
       
   291   gboolean res = FALSE;
       
   292 
       
   293   switch (GST_QUERY_TYPE (query)) {
       
   294     case GST_QUERY_CONVERT:
       
   295     {
       
   296       GstFormat src_fmt, dest_fmt;
       
   297       gint64 src_val, dest_val;
       
   298 
       
   299       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
       
   300       if (src_fmt == dest_fmt) {
       
   301         dest_val = src_val;
       
   302         goto done;
       
   303       }
       
   304 
       
   305       switch (src_fmt) {
       
   306         case GST_FORMAT_DEFAULT:
       
   307           switch (dest_fmt) {
       
   308             case GST_FORMAT_TIME:
       
   309               /* samples to time */
       
   310               dest_val =
       
   311                   gst_util_uint64_scale_int (src_val, GST_SECOND,
       
   312                   src->samplerate);
       
   313               break;
       
   314             default:
       
   315               goto error;
       
   316           }
       
   317           break;
       
   318         case GST_FORMAT_TIME:
       
   319           switch (dest_fmt) {
       
   320             case GST_FORMAT_DEFAULT:
       
   321               /* time to samples */
       
   322               dest_val =
       
   323                   gst_util_uint64_scale_int (src_val, src->samplerate,
       
   324                   GST_SECOND);
       
   325               break;
       
   326             default:
       
   327               goto error;
       
   328           }
       
   329           break;
       
   330         default:
       
   331           goto error;
       
   332       }
       
   333     done:
       
   334       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
       
   335       res = TRUE;
       
   336       break;
       
   337     }
       
   338     default:
       
   339       res = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
       
   340       break;
       
   341   }
       
   342 
       
   343   return res;
       
   344   /* ERROR */
       
   345 error:
       
   346   {
       
   347     GST_DEBUG_OBJECT (src, "query failed");
       
   348     return FALSE;
       
   349   }
       
   350 }
       
   351 
       
   352 #define DEFINE_SINE(type,scale) \
       
   353 static void \
       
   354 gst_audio_test_src_create_sine_##type (GstAudioTestSrc * src, g##type * samples) \
       
   355 { \
       
   356   gint i; \
       
   357   gdouble step, amp; \
       
   358   \
       
   359   step = M_PI_M2 * src->freq / src->samplerate; \
       
   360   amp = src->volume * scale; \
       
   361   \
       
   362   for (i = 0; i < src->generate_samples_per_buffer; i++) { \
       
   363     src->accumulator += step; \
       
   364     if (src->accumulator >= M_PI_M2) \
       
   365       src->accumulator -= M_PI_M2; \
       
   366     \
       
   367     samples[i] = (g##type) (sin (src->accumulator) * amp); \
       
   368   } \
       
   369 }
       
   370 
       
   371 DEFINE_SINE (int16, 32767.0);
       
   372 DEFINE_SINE (int32, 2147483647.0);
       
   373 DEFINE_SINE (float, 1.0);
       
   374 DEFINE_SINE (double, 1.0);
       
   375 
       
   376 static ProcessFunc sine_funcs[] = {
       
   377   (ProcessFunc) gst_audio_test_src_create_sine_int16,
       
   378   (ProcessFunc) gst_audio_test_src_create_sine_int32,
       
   379   (ProcessFunc) gst_audio_test_src_create_sine_float,
       
   380   (ProcessFunc) gst_audio_test_src_create_sine_double
       
   381 };
       
   382 
       
   383 #define DEFINE_SQUARE(type,scale) \
       
   384 static void \
       
   385 gst_audio_test_src_create_square_##type (GstAudioTestSrc * src, g##type * samples) \
       
   386 { \
       
   387   gint i; \
       
   388   gdouble step, amp; \
       
   389   \
       
   390   step = M_PI_M2 * src->freq / src->samplerate; \
       
   391   amp = src->volume * scale; \
       
   392   \
       
   393   for (i = 0; i < src->generate_samples_per_buffer; i++) { \
       
   394     src->accumulator += step; \
       
   395     if (src->accumulator >= M_PI_M2) \
       
   396       src->accumulator -= M_PI_M2; \
       
   397     \
       
   398     samples[i] = (g##type) ((src->accumulator < M_PI) ? amp : -amp); \
       
   399   } \
       
   400 }
       
   401 
       
   402 DEFINE_SQUARE (int16, 32767.0);
       
   403 DEFINE_SQUARE (int32, 2147483647.0);
       
   404 DEFINE_SQUARE (float, 1.0);
       
   405 DEFINE_SQUARE (double, 1.0);
       
   406 
       
   407 static ProcessFunc square_funcs[] = {
       
   408   (ProcessFunc) gst_audio_test_src_create_square_int16,
       
   409   (ProcessFunc) gst_audio_test_src_create_square_int32,
       
   410   (ProcessFunc) gst_audio_test_src_create_square_float,
       
   411   (ProcessFunc) gst_audio_test_src_create_square_double
       
   412 };
       
   413 
       
   414 #define DEFINE_SAW(type,scale) \
       
   415 static void \
       
   416 gst_audio_test_src_create_saw_##type (GstAudioTestSrc * src, g##type * samples) \
       
   417 { \
       
   418   gint i; \
       
   419   gdouble step, amp; \
       
   420   \
       
   421   step = M_PI_M2 * src->freq / src->samplerate; \
       
   422   amp = (src->volume * scale) / M_PI; \
       
   423   \
       
   424   for (i = 0; i < src->generate_samples_per_buffer; i++) { \
       
   425     src->accumulator += step; \
       
   426     if (src->accumulator >= M_PI_M2) \
       
   427       src->accumulator -= M_PI_M2; \
       
   428     \
       
   429     if (src->accumulator < M_PI) { \
       
   430       samples[i] = (g##type) (src->accumulator * amp); \
       
   431     } else { \
       
   432       samples[i] = (g##type) ((M_PI_M2 - src->accumulator) * -amp); \
       
   433     } \
       
   434   } \
       
   435 }
       
   436 
       
   437 DEFINE_SAW (int16, 32767.0);
       
   438 DEFINE_SAW (int32, 2147483647.0);
       
   439 DEFINE_SAW (float, 1.0);
       
   440 DEFINE_SAW (double, 1.0);
       
   441 
       
   442 static ProcessFunc saw_funcs[] = {
       
   443   (ProcessFunc) gst_audio_test_src_create_saw_int16,
       
   444   (ProcessFunc) gst_audio_test_src_create_saw_int32,
       
   445   (ProcessFunc) gst_audio_test_src_create_saw_float,
       
   446   (ProcessFunc) gst_audio_test_src_create_saw_double
       
   447 };
       
   448 
       
   449 #define DEFINE_TRIANGLE(type,scale) \
       
   450 static void \
       
   451 gst_audio_test_src_create_triangle_##type (GstAudioTestSrc * src, g##type * samples) \
       
   452 { \
       
   453   gint i; \
       
   454   gdouble step, amp; \
       
   455   \
       
   456   step = M_PI_M2 * src->freq / src->samplerate; \
       
   457   amp = (src->volume * scale) / M_PI_2; \
       
   458   \
       
   459   for (i = 0; i < src->generate_samples_per_buffer; i++) { \
       
   460     src->accumulator += step; \
       
   461     if (src->accumulator >= M_PI_M2) \
       
   462       src->accumulator -= M_PI_M2; \
       
   463     \
       
   464     if (src->accumulator < (M_PI * 0.5)) { \
       
   465       samples[i] = (g##type) (src->accumulator * amp); \
       
   466     } else if (src->accumulator < (M_PI * 1.5)) { \
       
   467       samples[i] = (g##type) ((src->accumulator - M_PI) * -amp); \
       
   468     } else { \
       
   469       samples[i] = (g##type) ((M_PI_M2 - src->accumulator) * -amp); \
       
   470     } \
       
   471   } \
       
   472 }
       
   473 
       
   474 DEFINE_TRIANGLE (int16, 32767.0);
       
   475 DEFINE_TRIANGLE (int32, 2147483647.0);
       
   476 DEFINE_TRIANGLE (float, 1.0);
       
   477 DEFINE_TRIANGLE (double, 1.0);
       
   478 
       
   479 static ProcessFunc triangle_funcs[] = {
       
   480   (ProcessFunc) gst_audio_test_src_create_triangle_int16,
       
   481   (ProcessFunc) gst_audio_test_src_create_triangle_int32,
       
   482   (ProcessFunc) gst_audio_test_src_create_triangle_float,
       
   483   (ProcessFunc) gst_audio_test_src_create_triangle_double
       
   484 };
       
   485 
       
   486 #define DEFINE_SILENCE(type) \
       
   487 static void \
       
   488 gst_audio_test_src_create_silence_##type (GstAudioTestSrc * src, g##type * samples) \
       
   489 { \
       
   490   memset (samples, 0, src->generate_samples_per_buffer * sizeof (g##type)); \
       
   491 }
       
   492 
       
   493 DEFINE_SILENCE (int16);
       
   494 DEFINE_SILENCE (int32);
       
   495 DEFINE_SILENCE (float);
       
   496 DEFINE_SILENCE (double);
       
   497 
       
   498 static ProcessFunc silence_funcs[] = {
       
   499   (ProcessFunc) gst_audio_test_src_create_silence_int16,
       
   500   (ProcessFunc) gst_audio_test_src_create_silence_int32,
       
   501   (ProcessFunc) gst_audio_test_src_create_silence_float,
       
   502   (ProcessFunc) gst_audio_test_src_create_silence_double
       
   503 };
       
   504 
       
   505 #define DEFINE_WHITE_NOISE(type,scale) \
       
   506 static void \
       
   507 gst_audio_test_src_create_white_noise_##type (GstAudioTestSrc * src, g##type * samples) \
       
   508 { \
       
   509   gint i; \
       
   510   gdouble amp = (src->volume * scale); \
       
   511   \
       
   512   for (i = 0; i < src->generate_samples_per_buffer; i++) { \
       
   513     samples[i] = (g##type) (amp * g_random_double_range (-1.0, 1.0)); \
       
   514   } \
       
   515 }
       
   516 
       
   517 DEFINE_WHITE_NOISE (int16, 32767.0);
       
   518 DEFINE_WHITE_NOISE (int32, 2147483647.0);
       
   519 DEFINE_WHITE_NOISE (float, 1.0);
       
   520 DEFINE_WHITE_NOISE (double, 1.0);
       
   521 
       
   522 static ProcessFunc white_noise_funcs[] = {
       
   523   (ProcessFunc) gst_audio_test_src_create_white_noise_int16,
       
   524   (ProcessFunc) gst_audio_test_src_create_white_noise_int32,
       
   525   (ProcessFunc) gst_audio_test_src_create_white_noise_float,
       
   526   (ProcessFunc) gst_audio_test_src_create_white_noise_double
       
   527 };
       
   528 
       
   529 /* pink noise calculation is based on
       
   530  * http://www.firstpr.com.au/dsp/pink-noise/phil_burk_19990905_patest_pink.c
       
   531  * which has been released under public domain
       
   532  * Many thanks Phil!
       
   533  */
       
   534 static void
       
   535 gst_audio_test_src_init_pink_noise (GstAudioTestSrc * src)
       
   536 {
       
   537   gint i;
       
   538   gint num_rows = 12;           /* arbitrary: 1 .. PINK_MAX_RANDOM_ROWS */
       
   539   glong pmax;
       
   540 
       
   541   src->pink.index = 0;
       
   542   src->pink.index_mask = (1 << num_rows) - 1;
       
   543   /* calculate maximum possible signed random value.
       
   544    * Extra 1 for white noise always added. */
       
   545   pmax = (num_rows + 1) * (1 << (PINK_RANDOM_BITS - 1));
       
   546   src->pink.scalar = 1.0f / pmax;
       
   547   /* Initialize rows. */
       
   548   for (i = 0; i < num_rows; i++)
       
   549     src->pink.rows[i] = 0;
       
   550   src->pink.running_sum = 0;
       
   551 }
       
   552 
       
   553 /* Generate Pink noise values between -1.0 and +1.0 */
       
   554 static gdouble
       
   555 gst_audio_test_src_generate_pink_noise_value (GstPinkNoise * pink)
       
   556 {
       
   557   glong new_random;
       
   558   glong sum;
       
   559 
       
   560   /* Increment and mask index. */
       
   561   pink->index = (pink->index + 1) & pink->index_mask;
       
   562 
       
   563   /* If index is zero, don't update any random values. */
       
   564   if (pink->index != 0) {
       
   565     /* Determine how many trailing zeros in PinkIndex. */
       
   566     /* This algorithm will hang if n==0 so test first. */
       
   567     gint num_zeros = 0;
       
   568     gint n = pink->index;
       
   569 
       
   570     while ((n & 1) == 0) {
       
   571       n = n >> 1;
       
   572       num_zeros++;
       
   573     }
       
   574 
       
   575     /* Replace the indexed ROWS random value.
       
   576      * Subtract and add back to RunningSum instead of adding all the random
       
   577      * values together. Only one changes each time.
       
   578      */
       
   579     pink->running_sum -= pink->rows[num_zeros];
       
   580     //new_random = ((glong)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT;
       
   581     new_random = 32768.0 - (65536.0 * (gulong) rand () / (RAND_MAX + 1.0));
       
   582     pink->running_sum += new_random;
       
   583     pink->rows[num_zeros] = new_random;
       
   584   }
       
   585 
       
   586   /* Add extra white noise value. */
       
   587   new_random = 32768.0 - (65536.0 * (gulong) rand () / (RAND_MAX + 1.0));
       
   588   sum = pink->running_sum + new_random;
       
   589 
       
   590   /* Scale to range of -1.0 to 0.9999. */
       
   591   return (pink->scalar * sum);
       
   592 }
       
   593 
       
   594 #define DEFINE_PINK(type, scale) \
       
   595 static void \
       
   596 gst_audio_test_src_create_pink_noise_##type (GstAudioTestSrc * src, g##type * samples) \
       
   597 { \
       
   598   gint i; \
       
   599   gdouble amp; \
       
   600   \
       
   601   amp = src->volume * scale; \
       
   602   \
       
   603   for (i = 0; i < src->generate_samples_per_buffer; i++) { \
       
   604     samples[i] = \
       
   605         (g##type) (gst_audio_test_src_generate_pink_noise_value (&src->pink) * \
       
   606         amp); \
       
   607   } \
       
   608 }
       
   609 
       
   610 DEFINE_PINK (int16, 32767.0);
       
   611 DEFINE_PINK (int32, 2147483647.0);
       
   612 DEFINE_PINK (float, 1.0);
       
   613 DEFINE_PINK (double, 1.0);
       
   614 
       
   615 static ProcessFunc pink_noise_funcs[] = {
       
   616   (ProcessFunc) gst_audio_test_src_create_pink_noise_int16,
       
   617   (ProcessFunc) gst_audio_test_src_create_pink_noise_int32,
       
   618   (ProcessFunc) gst_audio_test_src_create_pink_noise_float,
       
   619   (ProcessFunc) gst_audio_test_src_create_pink_noise_double
       
   620 };
       
   621 
       
   622 static void
       
   623 gst_audio_test_src_init_sine_table (GstAudioTestSrc * src)
       
   624 {
       
   625   gint i;
       
   626   gdouble ang = 0.0;
       
   627   gdouble step = M_PI_M2 / 1024.0;
       
   628   gdouble amp = src->volume;
       
   629 
       
   630   for (i = 0; i < 1024; i++) {
       
   631     src->wave_table[i] = sin (ang) * amp;
       
   632     ang += step;
       
   633   }
       
   634 }
       
   635 
       
   636 #define DEFINE_SINE_TABLE(type,scale) \
       
   637 static void \
       
   638 gst_audio_test_src_create_sine_table_##type (GstAudioTestSrc * src, g##type * samples) \
       
   639 { \
       
   640   gint i; \
       
   641   gdouble step, scl; \
       
   642   \
       
   643   step = M_PI_M2 * src->freq / src->samplerate; \
       
   644   scl = 1024.0 / M_PI_M2; \
       
   645   \
       
   646   for (i = 0; i < src->generate_samples_per_buffer; i++) { \
       
   647     src->accumulator += step; \
       
   648     if (src->accumulator >= M_PI_M2) \
       
   649       src->accumulator -= M_PI_M2; \
       
   650     \
       
   651     samples[i] = (g##type) scale * src->wave_table[(gint) (src->accumulator * scl)]; \
       
   652   } \
       
   653 }
       
   654 
       
   655 DEFINE_SINE_TABLE (int16, 32767.0);
       
   656 DEFINE_SINE_TABLE (int32, 2147483647.0);
       
   657 DEFINE_SINE_TABLE (float, 1.0);
       
   658 DEFINE_SINE_TABLE (double, 1.0);
       
   659 
       
   660 static ProcessFunc sine_table_funcs[] = {
       
   661   (ProcessFunc) gst_audio_test_src_create_sine_table_int16,
       
   662   (ProcessFunc) gst_audio_test_src_create_sine_table_int32,
       
   663   (ProcessFunc) gst_audio_test_src_create_sine_table_float,
       
   664   (ProcessFunc) gst_audio_test_src_create_sine_table_double
       
   665 };
       
   666 
       
   667 /*
       
   668  * gst_audio_test_src_change_wave:
       
   669  * Assign function pointer of wave genrator.
       
   670  */
       
   671 static void
       
   672 gst_audio_test_src_change_wave (GstAudioTestSrc * src)
       
   673 {
       
   674   if (src->format == -1) {
       
   675     src->process = NULL;
       
   676     return;
       
   677   }
       
   678 
       
   679   switch (src->wave) {
       
   680     case GST_AUDIO_TEST_SRC_WAVE_SINE:
       
   681       src->process = sine_funcs[src->format];
       
   682       break;
       
   683     case GST_AUDIO_TEST_SRC_WAVE_SQUARE:
       
   684       src->process = square_funcs[src->format];
       
   685       break;
       
   686     case GST_AUDIO_TEST_SRC_WAVE_SAW:
       
   687       src->process = saw_funcs[src->format];
       
   688       break;
       
   689     case GST_AUDIO_TEST_SRC_WAVE_TRIANGLE:
       
   690       src->process = triangle_funcs[src->format];
       
   691       break;
       
   692     case GST_AUDIO_TEST_SRC_WAVE_SILENCE:
       
   693       src->process = silence_funcs[src->format];
       
   694       break;
       
   695     case GST_AUDIO_TEST_SRC_WAVE_WHITE_NOISE:
       
   696       src->process = white_noise_funcs[src->format];
       
   697       break;
       
   698     case GST_AUDIO_TEST_SRC_WAVE_PINK_NOISE:
       
   699       gst_audio_test_src_init_pink_noise (src);
       
   700       src->process = pink_noise_funcs[src->format];
       
   701       break;
       
   702     case GST_AUDIO_TEST_SRC_WAVE_SINE_TAB:
       
   703       gst_audio_test_src_init_sine_table (src);
       
   704       src->process = sine_table_funcs[src->format];
       
   705       break;
       
   706     default:
       
   707       GST_ERROR ("invalid wave-form");
       
   708       break;
       
   709   }
       
   710 }
       
   711 
       
   712 /*
       
   713  * gst_audio_test_src_change_volume:
       
   714  * Recalc wave tables for precalculated waves.
       
   715  */
       
   716 static void
       
   717 gst_audio_test_src_change_volume (GstAudioTestSrc * src)
       
   718 {
       
   719   switch (src->wave) {
       
   720     case GST_AUDIO_TEST_SRC_WAVE_SINE_TAB:
       
   721       gst_audio_test_src_init_sine_table (src);
       
   722       break;
       
   723     default:
       
   724       break;
       
   725   }
       
   726 }
       
   727 
       
   728 static void
       
   729 gst_audio_test_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
       
   730     GstClockTime * start, GstClockTime * end)
       
   731 {
       
   732   /* for live sources, sync on the timestamp of the buffer */
       
   733   if (gst_base_src_is_live (basesrc)) {
       
   734     GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
       
   735 
       
   736     if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
       
   737       /* get duration to calculate end time */
       
   738       GstClockTime duration = GST_BUFFER_DURATION (buffer);
       
   739 
       
   740       if (GST_CLOCK_TIME_IS_VALID (duration)) {
       
   741         *end = timestamp + duration;
       
   742       }
       
   743       *start = timestamp;
       
   744     }
       
   745   } else {
       
   746     *start = -1;
       
   747     *end = -1;
       
   748   }
       
   749 }
       
   750 
       
   751 static gboolean
       
   752 gst_audio_test_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment)
       
   753 {
       
   754   GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (basesrc);
       
   755   GstClockTime time;
       
   756 
       
   757   segment->time = segment->start;
       
   758   time = segment->last_stop;
       
   759 
       
   760   /* now move to the time indicated */
       
   761   src->n_samples =
       
   762       gst_util_uint64_scale_int (time, src->samplerate, GST_SECOND);
       
   763   src->running_time =
       
   764       gst_util_uint64_scale_int (src->n_samples, GST_SECOND, src->samplerate);
       
   765 
       
   766   g_assert (src->running_time <= time);
       
   767 
       
   768   if (GST_CLOCK_TIME_IS_VALID (segment->stop)) {
       
   769     time = segment->stop;
       
   770     src->n_samples_stop = gst_util_uint64_scale_int (time, src->samplerate,
       
   771         GST_SECOND);
       
   772     src->check_seek_stop = TRUE;
       
   773   } else {
       
   774     src->check_seek_stop = FALSE;
       
   775   }
       
   776   src->eos_reached = FALSE;
       
   777 
       
   778   return TRUE;
       
   779 }
       
   780 
       
   781 static gboolean
       
   782 gst_audio_test_src_is_seekable (GstBaseSrc * basesrc)
       
   783 {
       
   784   /* we're seekable... */
       
   785   return TRUE;
       
   786 }
       
   787 
       
   788 static GstFlowReturn
       
   789 gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset,
       
   790     guint length, GstBuffer ** buffer)
       
   791 {
       
   792   GstFlowReturn res;
       
   793   GstAudioTestSrc *src;
       
   794   GstBuffer *buf;
       
   795   GstClockTime next_time;
       
   796   gint64 n_samples;
       
   797   gint sample_size;
       
   798 
       
   799   src = GST_AUDIO_TEST_SRC (basesrc);
       
   800 
       
   801   if (src->eos_reached)
       
   802     return GST_FLOW_UNEXPECTED;
       
   803 
       
   804   /* example for tagging generated data */
       
   805   if (!src->tags_pushed) {
       
   806     GstTagList *taglist;
       
   807     GstEvent *event;
       
   808 
       
   809     taglist = gst_tag_list_new ();
       
   810 
       
   811     gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
       
   812         GST_TAG_DESCRIPTION, "audiotest wave", NULL);
       
   813 
       
   814     event = gst_event_new_tag (taglist);
       
   815     gst_pad_push_event (basesrc->srcpad, event);
       
   816     src->tags_pushed = TRUE;
       
   817   }
       
   818 
       
   819   /* check for eos */
       
   820   if (src->check_seek_stop &&
       
   821       (src->n_samples_stop > src->n_samples) &&
       
   822       (src->n_samples_stop < src->n_samples + src->samples_per_buffer)
       
   823       ) {
       
   824     /* calculate only partial buffer */
       
   825     src->generate_samples_per_buffer = src->n_samples_stop - src->n_samples;
       
   826     n_samples = src->n_samples_stop;
       
   827     src->eos_reached = TRUE;
       
   828   } else {
       
   829     /* calculate full buffer */
       
   830     src->generate_samples_per_buffer = src->samples_per_buffer;
       
   831     n_samples = src->n_samples + src->samples_per_buffer;
       
   832   }
       
   833   next_time = gst_util_uint64_scale (n_samples, GST_SECOND,
       
   834       (guint64) src->samplerate);
       
   835 
       
   836   /* allocate a new buffer suitable for this pad */
       
   837   switch (src->format) {
       
   838     case GST_AUDIO_TEST_SRC_FORMAT_S16:
       
   839       sample_size = sizeof (gint16);
       
   840       break;
       
   841     case GST_AUDIO_TEST_SRC_FORMAT_S32:
       
   842       sample_size = sizeof (gint32);
       
   843       break;
       
   844     case GST_AUDIO_TEST_SRC_FORMAT_F32:
       
   845       sample_size = sizeof (gfloat);
       
   846       break;
       
   847     case GST_AUDIO_TEST_SRC_FORMAT_F64:
       
   848       sample_size = sizeof (gdouble);
       
   849       break;
       
   850     default:
       
   851       sample_size = -1;
       
   852       GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL),
       
   853           ("format wasn't negotiated before get function"));
       
   854       return GST_FLOW_NOT_NEGOTIATED;
       
   855       break;
       
   856   }
       
   857 
       
   858   if ((res = gst_pad_alloc_buffer (basesrc->srcpad, src->n_samples,
       
   859               src->generate_samples_per_buffer * sample_size,
       
   860               GST_PAD_CAPS (basesrc->srcpad), &buf)) != GST_FLOW_OK) {
       
   861     return res;
       
   862   }
       
   863 
       
   864   GST_BUFFER_TIMESTAMP (buf) = src->timestamp_offset + src->running_time;
       
   865   GST_BUFFER_OFFSET_END (buf) = n_samples;
       
   866   GST_BUFFER_DURATION (buf) = next_time - src->running_time;
       
   867 
       
   868   gst_object_sync_values (G_OBJECT (src), src->running_time);
       
   869 
       
   870   src->running_time = next_time;
       
   871   src->n_samples = n_samples;
       
   872 
       
   873   GST_LOG_OBJECT (src, "generating %u samples at ts %" GST_TIME_FORMAT,
       
   874       length, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
       
   875 
       
   876   src->process (src, GST_BUFFER_DATA (buf));
       
   877 
       
   878   if (G_UNLIKELY ((src->wave == GST_AUDIO_TEST_SRC_WAVE_SILENCE)
       
   879           || (src->volume == 0.0))) {
       
   880     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_GAP);
       
   881   }
       
   882 
       
   883   *buffer = buf;
       
   884 
       
   885   return GST_FLOW_OK;
       
   886 }
       
   887 
       
   888 static void
       
   889 gst_audio_test_src_set_property (GObject * object, guint prop_id,
       
   890     const GValue * value, GParamSpec * pspec)
       
   891 {
       
   892   GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (object);
       
   893 
       
   894   switch (prop_id) {
       
   895     case PROP_SAMPLES_PER_BUFFER:
       
   896       src->samples_per_buffer = g_value_get_int (value);
       
   897       break;
       
   898     case PROP_WAVE:
       
   899       src->wave = g_value_get_enum (value);
       
   900       gst_audio_test_src_change_wave (src);
       
   901       break;
       
   902     case PROP_FREQ:
       
   903       src->freq = g_value_get_double (value);
       
   904       break;
       
   905     case PROP_VOLUME:
       
   906       src->volume = g_value_get_double (value);
       
   907       gst_audio_test_src_change_volume (src);
       
   908       break;
       
   909     case PROP_IS_LIVE:
       
   910       gst_base_src_set_live (GST_BASE_SRC (src), g_value_get_boolean (value));
       
   911       break;
       
   912     case PROP_TIMESTAMP_OFFSET:
       
   913       src->timestamp_offset = g_value_get_int64 (value);
       
   914       break;
       
   915     default:
       
   916       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   917       break;
       
   918   }
       
   919 }
       
   920 
       
   921 static void
       
   922 gst_audio_test_src_get_property (GObject * object, guint prop_id,
       
   923     GValue * value, GParamSpec * pspec)
       
   924 {
       
   925   GstAudioTestSrc *src = GST_AUDIO_TEST_SRC (object);
       
   926 
       
   927   switch (prop_id) {
       
   928     case PROP_SAMPLES_PER_BUFFER:
       
   929       g_value_set_int (value, src->samples_per_buffer);
       
   930       break;
       
   931     case PROP_WAVE:
       
   932       g_value_set_enum (value, src->wave);
       
   933       break;
       
   934     case PROP_FREQ:
       
   935       g_value_set_double (value, src->freq);
       
   936       break;
       
   937     case PROP_VOLUME:
       
   938       g_value_set_double (value, src->volume);
       
   939       break;
       
   940     case PROP_IS_LIVE:
       
   941       g_value_set_boolean (value, gst_base_src_is_live (GST_BASE_SRC (src)));
       
   942       break;
       
   943     case PROP_TIMESTAMP_OFFSET:
       
   944       g_value_set_int64 (value, src->timestamp_offset);
       
   945       break;
       
   946     default:
       
   947       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   948       break;
       
   949   }
       
   950 }
       
   951 
       
   952 static gboolean
       
   953 plugin_init (GstPlugin * plugin)
       
   954 {
       
   955   /* initialize gst controller library */
       
   956   gst_controller_init (NULL, NULL);
       
   957 
       
   958   GST_DEBUG_CATEGORY_INIT (audio_test_src_debug, "audiotestsrc", 0,
       
   959       "Audio Test Source");
       
   960 
       
   961   return gst_element_register (plugin, "audiotestsrc",
       
   962       GST_RANK_NONE, GST_TYPE_AUDIO_TEST_SRC);
       
   963 }
       
   964 
       
   965 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
       
   966     GST_VERSION_MINOR,
       
   967     "audiotestsrc",
       
   968     "Creates audio test signals of given frequency and volume",
       
   969     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
       
   970 
       
   971 #ifdef __SYMBIAN32__
       
   972 EXPORT_C 
       
   973 #endif
       
   974 GstPluginDesc* _GST_PLUGIN_DESC()
       
   975 {
       
   976 	return &gst_plugin_desc;
       
   977 }
       
   978