2 * Copyright (C) <2011> Stefan Kost <ensonic@users.sf.net>
4 * gstwavescope.c: simple oscilloscope
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * SECTION:element-wavescope
24 * Wavescope is a simple audio visualisation element. It renders the waveforms
25 * like on an oscilloscope.
28 * <title>Example launch line</title>
30 * gst-launch audiotestsrc ! audioconvert ! wavescope ! ximagesink
39 #include "gstwavescope.h"
41 static GstStaticPadTemplate gst_wave_scope_src_template =
42 GST_STATIC_PAD_TEMPLATE ("src",
45 GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN)
48 static GstStaticPadTemplate gst_wave_scope_sink_template =
49 GST_STATIC_PAD_TEMPLATE ("sink",
52 GST_STATIC_CAPS (GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS)
56 GST_DEBUG_CATEGORY_STATIC (wave_scope_debug);
57 #define GST_CAT_DEFAULT wave_scope_debug
74 #define GST_TYPE_WAVE_SCOPE_STYLE (gst_wave_scope_style_get_type ())
76 gst_wave_scope_style_get_type (void)
78 static GType gtype = 0;
81 static const GEnumValue values[] = {
82 {STYLE_DOTS, "draw dots (default)", "dots"},
83 {STYLE_LINES, "draw lines", "lines"},
84 {STYLE_COLOR_DOTS, "draw color dots", "color-dots"},
85 {STYLE_COLOR_LINES, "draw color lines", "color-lines"},
89 gtype = g_enum_register_static ("GstWaveScopeStyle", values);
94 static void gst_wave_scope_set_property (GObject * object, guint prop_id,
95 const GValue * value, GParamSpec * pspec);
96 static void gst_wave_scope_get_property (GObject * object, guint prop_id,
97 GValue * value, GParamSpec * pspec);
98 static void gst_wave_scope_finalize (GObject * object);
100 static void render_dots (GstBaseAudioVisualizer * scope, guint32 * vdata,
101 gint16 * adata, guint num_samples);
102 static void render_lines (GstBaseAudioVisualizer * scope, guint32 * vdata,
103 gint16 * adata, guint num_samples);
104 static void render_color_dots (GstBaseAudioVisualizer * base, guint32 * vdata,
105 gint16 * adata, guint num_samples);
106 static void render_color_lines (GstBaseAudioVisualizer * base, guint32 * vdata,
107 gint16 * adata, guint num_samples);
109 static gboolean gst_wave_scope_setup (GstBaseAudioVisualizer * scope);
110 static gboolean gst_wave_scope_render (GstBaseAudioVisualizer * base,
111 GstBuffer * audio, GstBuffer * video);
114 GST_BOILERPLATE (GstWaveScope, gst_wave_scope, GstBaseAudioVisualizer,
115 GST_TYPE_BASE_AUDIO_VISUALIZER);
118 gst_wave_scope_base_init (gpointer g_class)
120 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
122 gst_element_class_set_details_simple (element_class, "Waveform oscilloscope",
124 "Simple waveform oscilloscope", "Stefan Kost <ensonic@users.sf.net>");
126 gst_element_class_add_static_pad_template (element_class,
127 &gst_wave_scope_src_template);
128 gst_element_class_add_static_pad_template (element_class,
129 &gst_wave_scope_sink_template);
133 gst_wave_scope_class_init (GstWaveScopeClass * g_class)
135 GObjectClass *gobject_class = (GObjectClass *) g_class;
136 GstBaseAudioVisualizerClass *scope_class =
137 (GstBaseAudioVisualizerClass *) g_class;
139 gobject_class->set_property = gst_wave_scope_set_property;
140 gobject_class->get_property = gst_wave_scope_get_property;
141 gobject_class->finalize = gst_wave_scope_finalize;
143 scope_class->setup = GST_DEBUG_FUNCPTR (gst_wave_scope_setup);
144 scope_class->render = GST_DEBUG_FUNCPTR (gst_wave_scope_render);
146 g_object_class_install_property (gobject_class, PROP_STYLE,
147 g_param_spec_enum ("style", "drawing style",
148 "Drawing styles for the wave form display.",
149 GST_TYPE_WAVE_SCOPE_STYLE, STYLE_DOTS,
150 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
154 gst_wave_scope_init (GstWaveScope * scope, GstWaveScopeClass * g_class)
160 gst_wave_scope_finalize (GObject * object)
162 GstWaveScope *scope = GST_WAVE_SCOPE (object);
169 G_OBJECT_CLASS (parent_class)->finalize (object);
173 gst_wave_scope_setup (GstBaseAudioVisualizer * bscope)
175 GstWaveScope *scope = GST_WAVE_SCOPE (bscope);
180 scope->flt = g_new0 (gdouble, 6 * bscope->channels);
186 gst_wave_scope_set_property (GObject * object, guint prop_id,
187 const GValue * value, GParamSpec * pspec)
189 GstWaveScope *scope = GST_WAVE_SCOPE (object);
193 scope->style = g_value_get_enum (value);
194 switch (scope->style) {
196 scope->process = render_dots;
199 scope->process = render_lines;
201 case STYLE_COLOR_DOTS:
202 scope->process = render_color_dots;
204 case STYLE_COLOR_LINES:
205 scope->process = render_color_lines;
210 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
216 gst_wave_scope_get_property (GObject * object, guint prop_id,
217 GValue * value, GParamSpec * pspec)
219 GstWaveScope *scope = GST_WAVE_SCOPE (object);
223 g_value_set_enum (value, scope->style);
226 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
231 #include "gstdrawhelpers.h"
234 render_dots (GstBaseAudioVisualizer * base, guint32 * vdata, gint16 * adata,
237 gint channels = base->channels;
238 guint i, c, s, x, y, oy;
240 guint w = base->width;
241 guint h = base->height;
244 dx = (gfloat) w / (gfloat) num_samples;
247 for (c = 0; c < channels; c++) {
249 for (i = 0; i < num_samples; i++) {
250 x = (guint) ((gfloat) i * dx);
251 y = (guint) (oy + (gfloat) adata[s] * dy);
253 draw_dot (vdata, x, y, w, 0x00FFFFFF);
259 render_lines (GstBaseAudioVisualizer * base, guint32 * vdata, gint16 * adata,
262 gint channels = base->channels;
263 guint i, c, s, x, y, oy;
265 guint w = base->width;
266 guint h = base->height;
270 dx = (gfloat) (w - 1) / (gfloat) num_samples;
271 dy = (h - 1) / 65536.0;
273 for (c = 0; c < channels; c++) {
276 y2 = (guint) (oy + (gfloat) adata[s] * dy);
277 for (i = 1; i < num_samples; i++) {
278 x = (guint) ((gfloat) i * dx);
279 y = (guint) (oy + (gfloat) adata[s] * dy);
281 draw_line_aa (vdata, x2, x, y2, y, w, 0x00FFFFFF);
288 #define CUTOFF_1 0.15
289 #define CUTOFF_2 0.45
290 #define RESONANCE (1.0/0.5)
292 #define filter(in) G_STMT_START { \
293 flt[2] = in - (flt[1] * RESONANCE) - flt[0]; \
294 flt[1] += (flt[2] * CUTOFF_1); \
295 flt[0] += (flt[1] * CUTOFF_1); \
297 flt[5] = (flt[1] + flt[2]) - (flt[4] * RESONANCE) - flt[3]; \
298 flt[4] += (flt[5] * CUTOFF_2); \
299 flt[3] += (flt[4] * CUTOFF_2); \
303 render_color_dots (GstBaseAudioVisualizer * base, guint32 * vdata,
304 gint16 * adata, guint num_samples)
306 GstWaveScope *scope = (GstWaveScope *) base;
307 gint channels = base->channels;
308 guint i, c, s, x, y, oy;
310 guint w = base->width;
311 guint h = base->height, h1 = h - 2;
312 gdouble *flt = scope->flt;
315 dx = (gfloat) w / (gfloat) num_samples;
318 for (c = 0; c < channels; c++) {
320 for (i = 0; i < num_samples; i++) {
321 x = (guint) ((gfloat) i * dx);
322 filter ((gfloat) adata[s]);
324 y = (guint) (oy + flt[0] * dy);
325 y = CLAMP (y, 0, h1);
326 draw_dot_c (vdata, x, y, w, 0x00FF0000);
328 y = (guint) (oy + flt[3] * dy);
329 y = CLAMP (y, 0, h1);
330 draw_dot_c (vdata, x, y, w, 0x0000FF00);
332 y = (guint) (oy + (flt[4] + flt[5]) * dy);
333 y = CLAMP (y, 0, h1);
334 draw_dot_c (vdata, x, y, w, 0x000000FF);
343 render_color_lines (GstBaseAudioVisualizer * base, guint32 * vdata,
344 gint16 * adata, guint num_samples)
346 GstWaveScope *scope = (GstWaveScope *) base;
347 gint channels = base->channels;
348 guint i, c, s, x, y, oy;
350 guint w = base->width;
351 guint h = base->height, h1 = h - 2;
352 gdouble *flt = scope->flt;
356 dx = (gfloat) (w - 1) / (gfloat) num_samples;
357 dy = (h - 1) / 65536.0;
359 for (c = 0; c < channels; c++) {
362 /* do first pixels */
364 filter ((gfloat) adata[s]);
366 y = (guint) (oy + flt[0] * dy);
367 y2 = CLAMP (y, 0, h1);
369 y = (guint) (oy + flt[3] * dy);
370 y3 = CLAMP (y, 0, h1);
372 y = (guint) (oy + (flt[4] + flt[5]) * dy);
373 y4 = CLAMP (y, 0, h1);
375 for (i = 1; i < num_samples; i++) {
376 x = (guint) ((gfloat) i * dx);
377 filter ((gfloat) adata[s]);
379 y = (guint) (oy + flt[0] * dy);
380 y = CLAMP (y, 0, h1);
381 draw_line_aa (vdata, x2, x, y2, y, w, 0x00FF0000);
384 y = (guint) (oy + flt[3] * dy);
385 y = CLAMP (y, 0, h1);
386 draw_line_aa (vdata, x2, x, y3, y, w, 0x0000FF00);
389 y = (guint) (oy + (flt[4] + flt[5]) * dy);
390 y = CLAMP (y, 0, h1);
391 draw_line_aa (vdata, x2, x, y4, y, w, 0x000000FF);
402 gst_wave_scope_render (GstBaseAudioVisualizer * base, GstBuffer * audio,
405 GstWaveScope *scope = GST_WAVE_SCOPE (base);
406 guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video);
407 gint16 *adata = (gint16 *) GST_BUFFER_DATA (audio);
410 num_samples = GST_BUFFER_SIZE (audio) / (base->channels * sizeof (gint16));
411 scope->process (base, vdata, adata, num_samples);
416 gst_wave_scope_plugin_init (GstPlugin * plugin)
418 GST_DEBUG_CATEGORY_INIT (wave_scope_debug, "wavescope", 0, "wavescope");
420 return gst_element_register (plugin, "wavescope", GST_RANK_NONE,
421 GST_TYPE_WAVE_SCOPE);