2 * Copyright (C) <2011> Stefan Kost <ensonic@users.sf.net>
4 * gstspacescope.c: simple stereo visualizer
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-spacescope
24 * Spacescope is a simple audio visualisation element. It maps the left and
25 * right channel to x and y coordinates.
28 * <title>Example launch line</title>
30 * gst-launch audiotestsrc ! audioconvert ! spacescope ! ximagesink
39 #include "gstspacescope.h"
41 static GstStaticPadTemplate gst_space_scope_src_template =
42 GST_STATIC_PAD_TEMPLATE ("src",
45 GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN)
48 static GstStaticPadTemplate gst_space_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 (space_scope_debug);
57 #define GST_CAT_DEFAULT space_scope_debug
74 #define GST_TYPE_SPACE_SCOPE_STYLE (gst_space_scope_style_get_type ())
76 gst_space_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 ("GstSpaceScopeStyle", values);
94 static void gst_space_scope_set_property (GObject * object, guint prop_id,
95 const GValue * value, GParamSpec * pspec);
96 static void gst_space_scope_get_property (GObject * object, guint prop_id,
97 GValue * value, GParamSpec * pspec);
99 static void render_dots (GstBaseAudioVisualizer * base, guint32 * vdata,
100 gint16 * adata, guint num_samples);
101 static void render_lines (GstBaseAudioVisualizer * base, guint32 * vdata,
102 gint16 * adata, guint num_samples);
103 static void render_color_dots (GstBaseAudioVisualizer * base, guint32 * vdata,
104 gint16 * adata, guint num_samples);
105 static void render_color_lines (GstBaseAudioVisualizer * base, guint32 * vdata,
106 gint16 * adata, guint num_samples);
108 static gboolean gst_space_scope_render (GstBaseAudioVisualizer * scope,
109 GstBuffer * audio, GstBuffer * video);
112 GST_BOILERPLATE (GstSpaceScope, gst_space_scope, GstBaseAudioVisualizer,
113 GST_TYPE_BASE_AUDIO_VISUALIZER);
116 gst_space_scope_base_init (gpointer g_class)
118 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
120 gst_element_class_set_details_simple (element_class, "Stereo visualizer",
122 "Simple stereo visualizer", "Stefan Kost <ensonic@users.sf.net>");
124 gst_element_class_add_static_pad_template (element_class,
125 &gst_space_scope_src_template);
126 gst_element_class_add_static_pad_template (element_class,
127 &gst_space_scope_sink_template);
131 gst_space_scope_class_init (GstSpaceScopeClass * g_class)
133 GObjectClass *gobject_class = (GObjectClass *) g_class;
134 GstBaseAudioVisualizerClass *scope_class =
135 (GstBaseAudioVisualizerClass *) g_class;
137 gobject_class->set_property = gst_space_scope_set_property;
138 gobject_class->get_property = gst_space_scope_get_property;
140 scope_class->render = GST_DEBUG_FUNCPTR (gst_space_scope_render);
142 g_object_class_install_property (gobject_class, PROP_STYLE,
143 g_param_spec_enum ("style", "drawing style",
144 "Drawing styles for the space scope display.",
145 GST_TYPE_SPACE_SCOPE_STYLE, STYLE_DOTS,
146 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
150 gst_space_scope_init (GstSpaceScope * scope, GstSpaceScopeClass * g_class)
156 gst_space_scope_set_property (GObject * object, guint prop_id,
157 const GValue * value, GParamSpec * pspec)
159 GstSpaceScope *scope = GST_SPACE_SCOPE (object);
163 scope->style = g_value_get_enum (value);
164 switch (scope->style) {
166 scope->process = render_dots;
169 scope->process = render_lines;
171 case STYLE_COLOR_DOTS:
172 scope->process = render_color_dots;
174 case STYLE_COLOR_LINES:
175 scope->process = render_color_lines;
180 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
186 gst_space_scope_get_property (GObject * object, guint prop_id,
187 GValue * value, GParamSpec * pspec)
189 GstSpaceScope *scope = GST_SPACE_SCOPE (object);
193 g_value_set_enum (value, scope->style);
196 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
201 #include "gstdrawhelpers.h"
204 render_dots (GstBaseAudioVisualizer * base, guint32 * vdata, gint16 * adata,
207 guint i, s, x, y, ox, oy;
209 guint w = base->width;
210 guint h = base->height;
212 /* draw dots 1st channel x, 2nd channel y */
218 for (i = 0; i < num_samples; i++) {
219 x = (guint) (ox + (gfloat) adata[s++] * dx);
220 y = (guint) (oy + (gfloat) adata[s++] * dy);
221 draw_dot (vdata, x, y, w, 0x00FFFFFF);
226 render_lines (GstBaseAudioVisualizer * base, guint32 * vdata, gint16 * adata,
229 guint i, s, x, y, ox, oy;
231 guint w = base->width;
232 guint h = base->height;
235 /* draw lines 1st channel x, 2nd channel y */
236 dx = (w - 1) / 65536.0;
238 dy = (h - 1) / 65536.0;
241 x2 = (guint) (ox + (gfloat) adata[s++] * dx);
242 y2 = (guint) (oy + (gfloat) adata[s++] * dy);
243 for (i = 1; i < num_samples; i++) {
244 x = (guint) (ox + (gfloat) adata[s++] * dx);
245 y = (guint) (oy + (gfloat) adata[s++] * dy);
246 draw_line_aa (vdata, x2, x, y2, y, w, 0x00FFFFFF);
252 #define CUTOFF_1 0.15
253 #define CUTOFF_2 0.45
254 #define RESONANCE (1.0/0.5)
256 #define filter(il, ir) G_STMT_START { \
257 f1l_h = il - (f1l_m * RESONANCE) - f1l_l; \
258 f1l_m += (f1l_h * CUTOFF_1); \
259 f1l_l += (f1l_m * CUTOFF_1); \
261 f2l_h = (f1l_m + f1l_h) - (f2l_m * RESONANCE) - f2l_l; \
262 f2l_m += (f2l_h * CUTOFF_2); \
263 f2l_l += (f2l_m * CUTOFF_2); \
265 f1r_h = ir - (f1r_m * RESONANCE) - f1r_l; \
266 f1r_m += (f1r_h * CUTOFF_1); \
267 f1r_l += (f1r_m * CUTOFF_1); \
269 f2r_h = (f1r_m + f1r_h) - (f2r_m * RESONANCE) - f2r_l; \
270 f2r_m += (f2r_h * CUTOFF_2); \
271 f2r_l += (f2r_m * CUTOFF_2); \
275 render_color_dots (GstBaseAudioVisualizer * base, guint32 * vdata,
276 gint16 * adata, guint num_samples)
278 GstSpaceScope *scope = (GstSpaceScope *) base;
282 gint w = base->width, w1 = w - 2;
283 gint h = base->height, h1 = h - 2;
285 gdouble f1l_l = scope->f1l_l, f1l_m = scope->f1l_m, f1l_h = scope->f1l_h;
286 gdouble f1r_l = scope->f1r_l, f1r_m = scope->f1r_m, f1r_h = scope->f1r_h;
287 gdouble f2l_l = scope->f2l_l, f2l_m = scope->f2l_m, f2l_h = scope->f2l_h;
288 gdouble f2r_l = scope->f2r_l, f2r_m = scope->f2r_m, f2r_h = scope->f2r_h;
290 /* draw dots 1st channel x, 2nd channel y */
296 for (i = 0; i < num_samples; i++) {
297 il = (gdouble) adata[s++];
298 ir = (gdouble) adata[s++];
302 x = (gint) (ox + f1l_l * dx);
303 y = (gint) (oy + f1r_l * dy);
304 x = CLAMP (x, 0, w1);
305 y = CLAMP (y, 0, h1);
306 draw_dot_c (vdata, x, y, w, 0x00FF0000);
308 x = (gint) (ox + f2l_l * dx);
309 y = (gint) (oy + f2r_l * dy);
310 x = CLAMP (x, 0, w1);
311 y = CLAMP (y, 0, h1);
312 draw_dot_c (vdata, x, y, w, 0x0000FF00);
314 x = (gint) (ox + (f2l_m + f2l_h) * dx);
315 y = (gint) (oy + (f2r_m + f2r_h) * dy);
316 x = CLAMP (x, 0, w1);
317 y = CLAMP (y, 0, h1);
318 draw_dot_c (vdata, x, y, w, 0x000000FF);
321 scope->f1l_l = f1l_l;
322 scope->f1l_m = f1l_m;
323 scope->f1l_h = f1l_h;
324 scope->f1r_l = f1r_l;
325 scope->f1r_m = f1r_m;
326 scope->f1r_h = f1r_h;
327 scope->f2l_l = f2l_l;
328 scope->f2l_m = f2l_m;
329 scope->f2l_h = f2l_h;
330 scope->f2r_l = f2r_l;
331 scope->f2r_m = f2r_m;
332 scope->f2r_h = f2r_h;
336 render_color_lines (GstBaseAudioVisualizer * base, guint32 * vdata,
337 gint16 * adata, guint num_samples)
339 GstSpaceScope *scope = (GstSpaceScope *) base;
343 gint w = base->width, w1 = w - 2;
344 gint h = base->height, h1 = h - 2;
346 gdouble f1l_l = scope->f1l_l, f1l_m = scope->f1l_m, f1l_h = scope->f1l_h;
347 gdouble f1r_l = scope->f1r_l, f1r_m = scope->f1r_m, f1r_h = scope->f1r_h;
348 gdouble f2l_l = scope->f2l_l, f2l_m = scope->f2l_m, f2l_h = scope->f2l_h;
349 gdouble f2r_l = scope->f2r_l, f2r_m = scope->f2r_m, f2r_h = scope->f2r_h;
350 gint x2, y2, x3, y3, x4, y4;
352 /* draw lines 1st channel x, 2nd channel y */
359 /* do first pixels */
360 il = (gdouble) adata[s++];
361 ir = (gdouble) adata[s++];
365 x = (gint) (ox + f1l_l * dx);
366 y = (gint) (oy + f1r_l * dy);
367 x2 = CLAMP (x, 0, w1);
368 y2 = CLAMP (y, 0, h1);
370 x = (gint) (ox + f2l_l * dx);
371 y = (gint) (oy + f2r_l * dy);
372 x3 = CLAMP (x, 0, w1);
373 y3 = CLAMP (y, 0, h1);
375 x = (gint) (ox + (f2l_m + f2l_h) * dx);
376 y = (gint) (oy + (f2r_m + f2r_h) * dy);
377 x4 = CLAMP (x, 0, w1);
378 y4 = CLAMP (y, 0, h1);
380 for (i = 1; i < num_samples; i++) {
381 il = (gdouble) adata[s++];
382 ir = (gdouble) adata[s++];
386 x = (gint) (ox + f1l_l * dx);
387 y = (gint) (oy + f1r_l * dy);
388 x = CLAMP (x, 0, w1);
389 y = CLAMP (y, 0, h1);
390 draw_line_aa (vdata, x2, x, y2, y, w, 0x00FF0000);
394 x = (gint) (ox + f2l_l * dx);
395 y = (gint) (oy + f2r_l * dy);
396 x = CLAMP (x, 0, w1);
397 y = CLAMP (y, 0, h1);
398 draw_line_aa (vdata, x3, x, y3, y, w, 0x0000FF00);
402 x = (gint) (ox + (f2l_m + f2l_h) * dx);
403 y = (gint) (oy + (f2r_m + f2r_h) * dy);
404 x = CLAMP (x, 0, w1);
405 y = CLAMP (y, 0, h1);
406 draw_line_aa (vdata, x4, x, y4, y, w, 0x000000FF);
411 scope->f1l_l = f1l_l;
412 scope->f1l_m = f1l_m;
413 scope->f1l_h = f1l_h;
414 scope->f1r_l = f1r_l;
415 scope->f1r_m = f1r_m;
416 scope->f1r_h = f1r_h;
417 scope->f2l_l = f2l_l;
418 scope->f2l_m = f2l_m;
419 scope->f2l_h = f2l_h;
420 scope->f2r_l = f2r_l;
421 scope->f2r_m = f2r_m;
422 scope->f2r_h = f2r_h;
426 gst_space_scope_render (GstBaseAudioVisualizer * base, GstBuffer * audio,
429 GstSpaceScope *scope = GST_SPACE_SCOPE (base);
430 guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video);
431 gint16 *adata = (gint16 *) GST_BUFFER_DATA (audio);
434 num_samples = GST_BUFFER_SIZE (audio) / (base->channels * sizeof (gint16));
435 scope->process (base, vdata, adata, num_samples);
440 gst_space_scope_plugin_init (GstPlugin * plugin)
442 GST_DEBUG_CATEGORY_INIT (space_scope_debug, "spacescope", 0, "spacescope");
444 return gst_element_register (plugin, "spacescope", GST_RANK_NONE,
445 GST_TYPE_SPACE_SCOPE);