Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / gst / audiovisualizers / gstspacescope.c
1 /* GStreamer
2  * Copyright (C) <2011> Stefan Kost <ensonic@users.sf.net>
3  *
4  * gstspacescope.c: simple stereo visualizer
5  *
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.
10  *
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.
15  *
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.
19  */
20 /**
21  * SECTION:element-spacescope
22  * @see_also: goom
23  *
24  * Spacescope is a simple audio visualisation element. It maps the left and
25  * right channel to x and y coordinates.
26  *
27  * <refsect2>
28  * <title>Example launch line</title>
29  * |[
30  * gst-launch audiotestsrc ! audioconvert ! spacescope ! ximagesink
31  * ]|
32  * </refsect2>
33  */
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <stdlib.h>
39 #include "gstspacescope.h"
40
41 static GstStaticPadTemplate gst_space_scope_src_template =
42 GST_STATIC_PAD_TEMPLATE ("src",
43     GST_PAD_SRC,
44     GST_PAD_ALWAYS,
45     GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN)
46     );
47
48 static GstStaticPadTemplate gst_space_scope_sink_template =
49 GST_STATIC_PAD_TEMPLATE ("sink",
50     GST_PAD_SINK,
51     GST_PAD_ALWAYS,
52     GST_STATIC_CAPS (GST_AUDIO_INT_STANDARD_PAD_TEMPLATE_CAPS)
53     );
54
55
56 GST_DEBUG_CATEGORY_STATIC (space_scope_debug);
57 #define GST_CAT_DEFAULT space_scope_debug
58
59 enum
60 {
61   PROP_0,
62   PROP_STYLE
63 };
64
65 enum
66 {
67   STYLE_DOTS = 0,
68   STYLE_LINES,
69   STYLE_COLOR_DOTS,
70   STYLE_COLOR_LINES,
71   NUM_STYLES
72 };
73
74 #define GST_TYPE_SPACE_SCOPE_STYLE (gst_space_scope_style_get_type ())
75 static GType
76 gst_space_scope_style_get_type (void)
77 {
78   static GType gtype = 0;
79
80   if (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"},
86       {0, NULL, NULL}
87     };
88
89     gtype = g_enum_register_static ("GstSpaceScopeStyle", values);
90   }
91   return gtype;
92 }
93
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);
98
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);
107
108 static gboolean gst_space_scope_render (GstBaseAudioVisualizer * scope,
109     GstBuffer * audio, GstBuffer * video);
110
111
112 GST_BOILERPLATE (GstSpaceScope, gst_space_scope, GstBaseAudioVisualizer,
113     GST_TYPE_BASE_AUDIO_VISUALIZER);
114
115 static void
116 gst_space_scope_base_init (gpointer g_class)
117 {
118   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
119
120   gst_element_class_set_details_simple (element_class, "Stereo visualizer",
121       "Visualization",
122       "Simple stereo visualizer", "Stefan Kost <ensonic@users.sf.net>");
123
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);
128 }
129
130 static void
131 gst_space_scope_class_init (GstSpaceScopeClass * g_class)
132 {
133   GObjectClass *gobject_class = (GObjectClass *) g_class;
134   GstBaseAudioVisualizerClass *scope_class =
135       (GstBaseAudioVisualizerClass *) g_class;
136
137   gobject_class->set_property = gst_space_scope_set_property;
138   gobject_class->get_property = gst_space_scope_get_property;
139
140   scope_class->render = GST_DEBUG_FUNCPTR (gst_space_scope_render);
141
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));
147 }
148
149 static void
150 gst_space_scope_init (GstSpaceScope * scope, GstSpaceScopeClass * g_class)
151 {
152   /* do nothing */
153 }
154
155 static void
156 gst_space_scope_set_property (GObject * object, guint prop_id,
157     const GValue * value, GParamSpec * pspec)
158 {
159   GstSpaceScope *scope = GST_SPACE_SCOPE (object);
160
161   switch (prop_id) {
162     case PROP_STYLE:
163       scope->style = g_value_get_enum (value);
164       switch (scope->style) {
165         case STYLE_DOTS:
166           scope->process = render_dots;
167           break;
168         case STYLE_LINES:
169           scope->process = render_lines;
170           break;
171         case STYLE_COLOR_DOTS:
172           scope->process = render_color_dots;
173           break;
174         case STYLE_COLOR_LINES:
175           scope->process = render_color_lines;
176           break;
177       }
178       break;
179     default:
180       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
181       break;
182   }
183 }
184
185 static void
186 gst_space_scope_get_property (GObject * object, guint prop_id,
187     GValue * value, GParamSpec * pspec)
188 {
189   GstSpaceScope *scope = GST_SPACE_SCOPE (object);
190
191   switch (prop_id) {
192     case PROP_STYLE:
193       g_value_set_enum (value, scope->style);
194       break;
195     default:
196       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
197       break;
198   }
199 }
200
201 #include "gstdrawhelpers.h"
202
203 static void
204 render_dots (GstBaseAudioVisualizer * base, guint32 * vdata, gint16 * adata,
205     guint num_samples)
206 {
207   guint i, s, x, y, ox, oy;
208   gfloat dx, dy;
209   guint w = base->width;
210   guint h = base->height;
211
212   /* draw dots 1st channel x, 2nd channel y */
213   dx = w / 65536.0;
214   ox = w / 2;
215   dy = h / 65536.0;
216   oy = h / 2;
217   s = 0;
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);
222   }
223 }
224
225 static void
226 render_lines (GstBaseAudioVisualizer * base, guint32 * vdata, gint16 * adata,
227     guint num_samples)
228 {
229   guint i, s, x, y, ox, oy;
230   gfloat dx, dy;
231   guint w = base->width;
232   guint h = base->height;
233   gint x2, y2;
234
235   /* draw lines 1st channel x, 2nd channel y */
236   dx = (w - 1) / 65536.0;
237   ox = (w - 1) / 2;
238   dy = (h - 1) / 65536.0;
239   oy = (h - 1) / 2;
240   s = 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);
247     x2 = x;
248     y2 = y;
249   }
250 }
251
252 #define CUTOFF_1 0.15
253 #define CUTOFF_2 0.45
254 #define RESONANCE (1.0/0.5)
255
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);                                                 \
260                                                                                \
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);                                                 \
264                                                                                \
265   f1r_h = ir - (f1r_m * RESONANCE) - f1r_l;                                    \
266   f1r_m += (f1r_h * CUTOFF_1);                                                 \
267   f1r_l += (f1r_m * CUTOFF_1);                                                 \
268                                                                                \
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);                                                 \
272 } G_STMT_END
273
274 static void
275 render_color_dots (GstBaseAudioVisualizer * base, guint32 * vdata,
276     gint16 * adata, guint num_samples)
277 {
278   GstSpaceScope *scope = (GstSpaceScope *) base;
279   guint i, s;
280   gint x, y, ox, oy;
281   gfloat dx, dy;
282   gint w = base->width, w1 = w - 2;
283   gint h = base->height, h1 = h - 2;
284   gdouble il, ir;
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;
289
290   /* draw dots 1st channel x, 2nd channel y */
291   ox = w / 2;
292   oy = h / 2;
293   dx = w / 65536.0;
294   dy = h / 65536.0;
295   s = 0;
296   for (i = 0; i < num_samples; i++) {
297     il = (gdouble) adata[s++];
298     ir = (gdouble) adata[s++];
299
300     filter (il, ir);
301
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);
307
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);
313
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);
319   }
320
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;
333 }
334
335 static void
336 render_color_lines (GstBaseAudioVisualizer * base, guint32 * vdata,
337     gint16 * adata, guint num_samples)
338 {
339   GstSpaceScope *scope = (GstSpaceScope *) base;
340   guint i, s;
341   gint x, y, ox, oy;
342   gfloat dx, dy;
343   gint w = base->width, w1 = w - 2;
344   gint h = base->height, h1 = h - 2;
345   gdouble il, ir;
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;
351
352   /* draw lines 1st channel x, 2nd channel y */
353   ox = w / 2;
354   oy = h / 2;
355   dx = w / 65536.0;
356   dy = h / 65536.0;
357   s = 0;
358
359   /* do first pixels */
360   il = (gdouble) adata[s++];
361   ir = (gdouble) adata[s++];
362
363   filter (il, ir);
364
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);
369
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);
374
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);
379
380   for (i = 1; i < num_samples; i++) {
381     il = (gdouble) adata[s++];
382     ir = (gdouble) adata[s++];
383
384     filter (il, ir);
385
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);
391     x2 = x;
392     y2 = y;
393
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);
399     x3 = x;
400     y3 = y;
401
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);
407     x4 = x;
408     y4 = y;
409   }
410
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;
423 }
424
425 static gboolean
426 gst_space_scope_render (GstBaseAudioVisualizer * base, GstBuffer * audio,
427     GstBuffer * video)
428 {
429   GstSpaceScope *scope = GST_SPACE_SCOPE (base);
430   guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video);
431   gint16 *adata = (gint16 *) GST_BUFFER_DATA (audio);
432   guint num_samples;
433
434   num_samples = GST_BUFFER_SIZE (audio) / (base->channels * sizeof (gint16));
435   scope->process (base, vdata, adata, num_samples);
436   return TRUE;
437 }
438
439 gboolean
440 gst_space_scope_plugin_init (GstPlugin * plugin)
441 {
442   GST_DEBUG_CATEGORY_INIT (space_scope_debug, "spacescope", 0, "spacescope");
443
444   return gst_element_register (plugin, "spacescope", GST_RANK_NONE,
445       GST_TYPE_SPACE_SCOPE);
446 }