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 #if G_BYTE_ORDER == G_BIG_ENDIAN
46 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("xRGB"))
48 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRx"))
52 static GstStaticPadTemplate gst_wave_scope_sink_template =
53 GST_STATIC_PAD_TEMPLATE ("sink",
56 GST_STATIC_CAPS ("audio/x-raw, "
57 "format = (string) " GST_AUDIO_NE (S16) ", "
58 "layout = (string) interleaved, "
59 "rate = (int) [ 8000, 96000 ], "
60 "channels = (int) 2, " "channel-mask = (bitmask) 0x3")
64 GST_DEBUG_CATEGORY_STATIC (wave_scope_debug);
65 #define GST_CAT_DEFAULT wave_scope_debug
82 #define GST_TYPE_WAVE_SCOPE_STYLE (gst_wave_scope_style_get_type ())
84 gst_wave_scope_style_get_type (void)
86 static GType gtype = 0;
89 static const GEnumValue values[] = {
90 {STYLE_DOTS, "draw dots (default)", "dots"},
91 {STYLE_LINES, "draw lines", "lines"},
92 {STYLE_COLOR_DOTS, "draw color dots", "color-dots"},
93 {STYLE_COLOR_LINES, "draw color lines", "color-lines"},
97 gtype = g_enum_register_static ("GstWaveScopeStyle", values);
102 static void gst_wave_scope_set_property (GObject * object, guint prop_id,
103 const GValue * value, GParamSpec * pspec);
104 static void gst_wave_scope_get_property (GObject * object, guint prop_id,
105 GValue * value, GParamSpec * pspec);
106 static void gst_wave_scope_finalize (GObject * object);
108 static void render_dots (GstAudioVisualizer * scope, guint32 * vdata,
109 gint16 * adata, guint num_samples);
110 static void render_lines (GstAudioVisualizer * scope, guint32 * vdata,
111 gint16 * adata, guint num_samples);
112 static void render_color_dots (GstAudioVisualizer * base, guint32 * vdata,
113 gint16 * adata, guint num_samples);
114 static void render_color_lines (GstAudioVisualizer * base, guint32 * vdata,
115 gint16 * adata, guint num_samples);
117 static gboolean gst_wave_scope_setup (GstAudioVisualizer * scope);
118 static gboolean gst_wave_scope_render (GstAudioVisualizer * base,
119 GstBuffer * audio, GstBuffer * video);
121 #define gst_wave_scope_parent_class parent_class
122 G_DEFINE_TYPE (GstWaveScope, gst_wave_scope, GST_TYPE_AUDIO_VISUALIZER);
125 gst_wave_scope_class_init (GstWaveScopeClass * g_class)
127 GObjectClass *gobject_class = (GObjectClass *) g_class;
128 GstElementClass *gstelement_class = (GstElementClass *) g_class;
129 GstAudioVisualizerClass *scope_class = (GstAudioVisualizerClass *) g_class;
131 gobject_class->set_property = gst_wave_scope_set_property;
132 gobject_class->get_property = gst_wave_scope_get_property;
133 gobject_class->finalize = gst_wave_scope_finalize;
135 scope_class->setup = GST_DEBUG_FUNCPTR (gst_wave_scope_setup);
136 scope_class->render = GST_DEBUG_FUNCPTR (gst_wave_scope_render);
138 g_object_class_install_property (gobject_class, PROP_STYLE,
139 g_param_spec_enum ("style", "drawing style",
140 "Drawing styles for the wave form display.",
141 GST_TYPE_WAVE_SCOPE_STYLE, STYLE_DOTS,
142 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
144 gst_element_class_set_details_simple (gstelement_class,
145 "Waveform oscilloscope", "Visualization", "Simple waveform oscilloscope",
146 "Stefan Kost <ensonic@users.sf.net>");
148 gst_element_class_add_pad_template (gstelement_class,
149 gst_static_pad_template_get (&gst_wave_scope_src_template));
150 gst_element_class_add_pad_template (gstelement_class,
151 gst_static_pad_template_get (&gst_wave_scope_sink_template));
153 scope_class->render = GST_DEBUG_FUNCPTR (gst_wave_scope_render);
157 gst_wave_scope_init (GstWaveScope * scope)
163 gst_wave_scope_finalize (GObject * object)
165 GstWaveScope *scope = GST_WAVE_SCOPE (object);
172 G_OBJECT_CLASS (parent_class)->finalize (object);
176 gst_wave_scope_setup (GstAudioVisualizer * bscope)
178 GstWaveScope *scope = GST_WAVE_SCOPE (bscope);
183 scope->flt = g_new0 (gdouble, 6 * GST_AUDIO_INFO_CHANNELS (&bscope->ainfo));
189 gst_wave_scope_set_property (GObject * object, guint prop_id,
190 const GValue * value, GParamSpec * pspec)
192 GstWaveScope *scope = GST_WAVE_SCOPE (object);
196 scope->style = g_value_get_enum (value);
197 switch (scope->style) {
199 scope->process = render_dots;
202 scope->process = render_lines;
204 case STYLE_COLOR_DOTS:
205 scope->process = render_color_dots;
207 case STYLE_COLOR_LINES:
208 scope->process = render_color_lines;
213 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
219 gst_wave_scope_get_property (GObject * object, guint prop_id,
220 GValue * value, GParamSpec * pspec)
222 GstWaveScope *scope = GST_WAVE_SCOPE (object);
226 g_value_set_enum (value, scope->style);
229 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
234 #include "gstdrawhelpers.h"
237 render_dots (GstAudioVisualizer * base, guint32 * vdata, gint16 * adata,
240 gint channels = GST_AUDIO_INFO_CHANNELS (&base->ainfo);
241 guint i, c, s, x, y, oy;
243 guint w = base->width;
244 guint h = base->height;
247 dx = (gfloat) w / (gfloat) num_samples;
250 for (c = 0; c < channels; c++) {
252 for (i = 0; i < num_samples; i++) {
253 x = (guint) ((gfloat) i * dx);
254 y = (guint) (oy + (gfloat) adata[s] * dy);
256 draw_dot (vdata, x, y, w, 0x00FFFFFF);
262 render_lines (GstAudioVisualizer * base, guint32 * vdata, gint16 * adata,
265 gint channels = GST_AUDIO_INFO_CHANNELS (&base->ainfo);
266 guint i, c, s, x, y, oy;
268 guint w = base->width;
269 guint h = base->height;
273 dx = (gfloat) (w - 1) / (gfloat) num_samples;
274 dy = (h - 1) / 65536.0;
276 for (c = 0; c < channels; c++) {
279 y2 = (guint) (oy + (gfloat) adata[s] * dy);
280 for (i = 1; i < num_samples; i++) {
281 x = (guint) ((gfloat) i * dx);
282 y = (guint) (oy + (gfloat) adata[s] * dy);
284 draw_line_aa (vdata, x2, x, y2, y, w, 0x00FFFFFF);
291 #define CUTOFF_1 0.15
292 #define CUTOFF_2 0.45
293 #define RESONANCE (1.0/0.5)
295 #define filter(in) G_STMT_START { \
296 flt[2] = in - (flt[1] * RESONANCE) - flt[0]; \
297 flt[1] += (flt[2] * CUTOFF_1); \
298 flt[0] += (flt[1] * CUTOFF_1); \
300 flt[5] = (flt[1] + flt[2]) - (flt[4] * RESONANCE) - flt[3]; \
301 flt[4] += (flt[5] * CUTOFF_2); \
302 flt[3] += (flt[4] * CUTOFF_2); \
306 render_color_dots (GstAudioVisualizer * base, guint32 * vdata,
307 gint16 * adata, guint num_samples)
309 GstWaveScope *scope = (GstWaveScope *) base;
310 gint channels = GST_AUDIO_INFO_CHANNELS (&base->ainfo);
311 guint i, c, s, x, y, oy;
313 guint w = base->width;
314 guint h = base->height, h1 = h - 2;
315 gdouble *flt = scope->flt;
318 dx = (gfloat) w / (gfloat) num_samples;
321 for (c = 0; c < channels; c++) {
323 for (i = 0; i < num_samples; i++) {
324 x = (guint) ((gfloat) i * dx);
325 filter ((gfloat) adata[s]);
327 y = (guint) (oy + flt[0] * dy);
328 y = CLAMP (y, 0, h1);
329 draw_dot_c (vdata, x, y, w, 0x00FF0000);
331 y = (guint) (oy + flt[3] * dy);
332 y = CLAMP (y, 0, h1);
333 draw_dot_c (vdata, x, y, w, 0x0000FF00);
335 y = (guint) (oy + (flt[4] + flt[5]) * dy);
336 y = CLAMP (y, 0, h1);
337 draw_dot_c (vdata, x, y, w, 0x000000FF);
346 render_color_lines (GstAudioVisualizer * base, guint32 * vdata,
347 gint16 * adata, guint num_samples)
349 GstWaveScope *scope = (GstWaveScope *) base;
350 gint channels = GST_AUDIO_INFO_CHANNELS (&base->ainfo);
351 guint i, c, s, x, y, oy;
353 guint w = base->width;
354 guint h = base->height, h1 = h - 2;
355 gdouble *flt = scope->flt;
359 dx = (gfloat) (w - 1) / (gfloat) num_samples;
360 dy = (h - 1) / 65536.0;
362 for (c = 0; c < channels; c++) {
365 /* do first pixels */
367 filter ((gfloat) adata[s]);
369 y = (guint) (oy + flt[0] * dy);
370 y2 = CLAMP (y, 0, h1);
372 y = (guint) (oy + flt[3] * dy);
373 y3 = CLAMP (y, 0, h1);
375 y = (guint) (oy + (flt[4] + flt[5]) * dy);
376 y4 = CLAMP (y, 0, h1);
378 for (i = 1; i < num_samples; i++) {
379 x = (guint) ((gfloat) i * dx);
380 filter ((gfloat) adata[s]);
382 y = (guint) (oy + flt[0] * dy);
383 y = CLAMP (y, 0, h1);
384 draw_line_aa (vdata, x2, x, y2, y, w, 0x00FF0000);
387 y = (guint) (oy + flt[3] * dy);
388 y = CLAMP (y, 0, h1);
389 draw_line_aa (vdata, x2, x, y3, y, w, 0x0000FF00);
392 y = (guint) (oy + (flt[4] + flt[5]) * dy);
393 y = CLAMP (y, 0, h1);
394 draw_line_aa (vdata, x2, x, y4, y, w, 0x000000FF);
405 gst_wave_scope_render (GstAudioVisualizer * base, GstBuffer * audio,
408 GstWaveScope *scope = GST_WAVE_SCOPE (base);
409 GstMapInfo amap, vmap;
411 gint channels = GST_AUDIO_INFO_CHANNELS (&base->ainfo);
413 gst_buffer_map (audio, &amap, GST_MAP_READ);
414 gst_buffer_map (video, &vmap, GST_MAP_WRITE);
416 num_samples = amap.size / (channels * sizeof (gint16));
417 scope->process (base, (guint32 *) vmap.data, (gint16 *) amap.data,
420 gst_buffer_unmap (video, &vmap);
421 gst_buffer_unmap (audio, &amap);
427 gst_wave_scope_plugin_init (GstPlugin * plugin)
429 GST_DEBUG_CATEGORY_INIT (wave_scope_debug, "wavescope", 0, "wavescope");
431 return gst_element_register (plugin, "wavescope", GST_RANK_NONE,
432 GST_TYPE_WAVE_SCOPE);