1 /* GStreamer
2  *
3  * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
4  *
5  * equalizer.c: Unit test for the equalizer element
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  */
22 
23 #include <gst/gst.h>
24 #include <gst/audio/audio.h>
25 #include <gst/base/gstbasetransform.h>
26 #include <gst/check/gstcheck.h>
27 
28 #include <math.h>
29 
30 /* For ease of programming we use globals to keep refs for our floating
31  * src and sink pads we create; otherwise we always have to do get_pad,
32  * get_peer, and then remove references in every test function */
33 GstPad *mysrcpad, *mysinkpad;
34 
35 #define EQUALIZER_CAPS_STRING                     \
36     "audio/x-raw, "                               \
37     "format = (string) "GST_AUDIO_NE (F64) ", "   \
38     "layout = (string) interleaved, "             \
39     "channels = (int) 1, "                        \
40     "rate = (int) 48000"
41 
42 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
43     GST_PAD_SINK,
44     GST_PAD_ALWAYS,
45     GST_STATIC_CAPS ("audio/x-raw, "
46         "format = (string) " GST_AUDIO_NE (F64) ", "
47         "layout = (string) interleaved, "
48         "channels = (int) 1, " "rate = (int) 48000")
49     );
50 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
51     GST_PAD_SRC,
52     GST_PAD_ALWAYS,
53     GST_STATIC_CAPS ("audio/x-raw, "
54         "format = (string) " GST_AUDIO_NE (F64) ", "
55         "layout = (string) interleaved, "
56         "channels = (int) 1, " "rate = (int) 48000")
57     );
58 
59 static GstElement *
setup_equalizer(void)60 setup_equalizer (void)
61 {
62   GstElement *equalizer;
63 
64   GST_DEBUG ("setup_equalizer");
65   equalizer = gst_check_setup_element ("equalizer-nbands");
66   mysrcpad = gst_check_setup_src_pad (equalizer, &srctemplate);
67   mysinkpad = gst_check_setup_sink_pad (equalizer, &sinktemplate);
68   gst_pad_set_active (mysrcpad, TRUE);
69   gst_pad_set_active (mysinkpad, TRUE);
70 
71   return equalizer;
72 }
73 
74 static void
cleanup_equalizer(GstElement * equalizer)75 cleanup_equalizer (GstElement * equalizer)
76 {
77   GST_DEBUG ("cleanup_equalizer");
78 
79   g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
80   g_list_free (buffers);
81   buffers = NULL;
82 
83   gst_pad_set_active (mysrcpad, FALSE);
84   gst_pad_set_active (mysinkpad, FALSE);
85   gst_check_teardown_src_pad (equalizer);
86   gst_check_teardown_sink_pad (equalizer);
87   gst_check_teardown_element (equalizer);
88 }
89 
GST_START_TEST(test_equalizer_5bands_passthrough)90 GST_START_TEST (test_equalizer_5bands_passthrough)
91 {
92   GstElement *equalizer;
93   GstBuffer *inbuffer;
94   GstCaps *caps;
95   gdouble *in, *res;
96   gint i;
97   GstMapInfo map;
98 
99   equalizer = setup_equalizer ();
100   g_object_set (G_OBJECT (equalizer), "num-bands", 5, NULL);
101 
102   fail_unless_equals_int (gst_child_proxy_get_children_count (GST_CHILD_PROXY
103           (equalizer)), 5);
104 
105   fail_unless (gst_element_set_state (equalizer,
106           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
107       "could not set to playing");
108 
109   inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
110   gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
111   in = (gdouble *) map.data;
112   for (i = 0; i < 1024; i++)
113     in[i] = g_random_double_range (-1.0, 1.0);
114   gst_buffer_unmap (inbuffer, &map);
115 
116   caps = gst_caps_from_string (EQUALIZER_CAPS_STRING);
117   gst_check_setup_events (mysrcpad, equalizer, caps, GST_FORMAT_TIME);
118   gst_caps_unref (caps);
119   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
120 
121   /* pushing gives away my reference ... */
122   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
123   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
124   /* ... and puts a new buffer on the global list */
125   fail_unless (g_list_length (buffers) == 1);
126 
127   gst_buffer_map (GST_BUFFER (buffers->data), &map, GST_MAP_READ);
128   res = (gdouble *) map.data;
129 
130   for (i = 0; i < 1024; i++)
131     fail_unless_equals_float (in[i], res[i]);
132   gst_buffer_unmap (GST_BUFFER (buffers->data), &map);
133 
134   /* cleanup */
135   cleanup_equalizer (equalizer);
136 }
137 
138 GST_END_TEST;
139 
GST_START_TEST(test_equalizer_5bands_minus_24)140 GST_START_TEST (test_equalizer_5bands_minus_24)
141 {
142   GstElement *equalizer;
143   GstBuffer *inbuffer;
144   GstCaps *caps;
145   gdouble *in, *res, rms_in, rms_out;
146   gint i;
147   GstMapInfo map;
148 
149   equalizer = setup_equalizer ();
150   g_object_set (G_OBJECT (equalizer), "num-bands", 5, NULL);
151 
152   fail_unless_equals_int (gst_child_proxy_get_children_count (GST_CHILD_PROXY
153           (equalizer)), 5);
154 
155   for (i = 0; i < 5; i++) {
156     GObject *band =
157         gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (equalizer), i);
158     fail_unless (band != NULL);
159 
160     g_object_set (band, "gain", -24.0, NULL);
161     g_object_unref (band);
162   }
163 
164   fail_unless (gst_element_set_state (equalizer,
165           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
166       "could not set to playing");
167 
168   inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
169   gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
170   in = (gdouble *) map.data;
171   for (i = 0; i < 1024; i++)
172     in[i] = g_random_double_range (-1.0, 1.0);
173   gst_buffer_unmap (inbuffer, &map);
174 
175   rms_in = 0.0;
176   for (i = 0; i < 1024; i++)
177     rms_in += in[i] * in[i];
178   rms_in = sqrt (rms_in / 1024);
179 
180   caps = gst_caps_from_string (EQUALIZER_CAPS_STRING);
181   gst_check_setup_events (mysrcpad, equalizer, caps, GST_FORMAT_TIME);
182   gst_caps_unref (caps);
183   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
184 
185   /* pushing gives away my reference ... */
186   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
187   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
188   /* ... and puts a new buffer on the global list */
189   fail_unless (g_list_length (buffers) == 1);
190 
191   gst_buffer_map (GST_BUFFER (buffers->data), &map, GST_MAP_READ);
192   res = (gdouble *) map.data;
193 
194   rms_out = 0.0;
195   for (i = 0; i < 1024; i++)
196     rms_out += res[i] * res[i];
197   rms_out = sqrt (rms_out / 1024);
198   gst_buffer_unmap (GST_BUFFER (buffers->data), &map);
199 
200   fail_unless (rms_in > rms_out);
201 
202   /* cleanup */
203   cleanup_equalizer (equalizer);
204 }
205 
206 GST_END_TEST;
207 
GST_START_TEST(test_equalizer_5bands_plus_12)208 GST_START_TEST (test_equalizer_5bands_plus_12)
209 {
210   GstElement *equalizer;
211   GstBuffer *inbuffer;
212   GstCaps *caps;
213   gdouble *in, *res, rms_in, rms_out;
214   gint i;
215   GstMapInfo map;
216 
217   equalizer = setup_equalizer ();
218   g_object_set (G_OBJECT (equalizer), "num-bands", 5, NULL);
219 
220   fail_unless_equals_int (gst_child_proxy_get_children_count (GST_CHILD_PROXY
221           (equalizer)), 5);
222 
223   for (i = 0; i < 5; i++) {
224     GObject *band =
225         gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (equalizer), i);
226     fail_unless (band != NULL);
227 
228     g_object_set (band, "gain", 12.0, NULL);
229     g_object_unref (band);
230   }
231 
232   fail_unless (gst_element_set_state (equalizer,
233           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
234       "could not set to playing");
235 
236   inbuffer = gst_buffer_new_and_alloc (1024 * sizeof (gdouble));
237   gst_buffer_map (inbuffer, &map, GST_MAP_WRITE);
238   in = (gdouble *) map.data;
239   for (i = 0; i < 1024; i++)
240     in[i] = g_random_double_range (-1.0, 1.0);
241   gst_buffer_unmap (inbuffer, &map);
242 
243   rms_in = 0.0;
244   for (i = 0; i < 1024; i++)
245     rms_in += in[i] * in[i];
246   rms_in = sqrt (rms_in / 1024);
247 
248   caps = gst_caps_from_string (EQUALIZER_CAPS_STRING);
249   gst_check_setup_events (mysrcpad, equalizer, caps, GST_FORMAT_TIME);
250   gst_caps_unref (caps);
251   ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
252 
253   /* pushing gives away my reference ... */
254   fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
255   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
256   /* ... and puts a new buffer on the global list */
257   fail_unless (g_list_length (buffers) == 1);
258 
259   gst_buffer_map (GST_BUFFER (buffers->data), &map, GST_MAP_READ);
260   res = (gdouble *) map.data;
261 
262   rms_out = 0.0;
263   for (i = 0; i < 1024; i++)
264     rms_out += res[i] * res[i];
265   rms_out = sqrt (rms_out / 1024);
266   gst_buffer_unmap (GST_BUFFER (buffers->data), &map);
267 
268   fail_unless (rms_in < rms_out);
269 
270   /* cleanup */
271   cleanup_equalizer (equalizer);
272 }
273 
274 GST_END_TEST;
275 
GST_START_TEST(test_equalizer_band_number_changing)276 GST_START_TEST (test_equalizer_band_number_changing)
277 {
278   GstElement *equalizer;
279   gint i;
280 
281   equalizer = setup_equalizer ();
282 
283   g_object_set (G_OBJECT (equalizer), "num-bands", 5, NULL);
284   fail_unless_equals_int (gst_child_proxy_get_children_count (GST_CHILD_PROXY
285           (equalizer)), 5);
286 
287   for (i = 0; i < 5; i++) {
288     GObject *band;
289 
290     band = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (equalizer), i);
291     fail_unless (band != NULL);
292     g_object_unref (band);
293   }
294 
295   g_object_set (G_OBJECT (equalizer), "num-bands", 10, NULL);
296   fail_unless_equals_int (gst_child_proxy_get_children_count (GST_CHILD_PROXY
297           (equalizer)), 10);
298 
299   for (i = 0; i < 10; i++) {
300     GObject *band;
301 
302     band = gst_child_proxy_get_child_by_index (GST_CHILD_PROXY (equalizer), i);
303     fail_unless (band != NULL);
304     g_object_unref (band);
305   }
306 
307   /* cleanup */
308   cleanup_equalizer (equalizer);
309 }
310 
311 GST_END_TEST;
312 
GST_START_TEST(test_equalizer_presets)313 GST_START_TEST (test_equalizer_presets)
314 {
315   GstElement *eq1, *eq2;
316   gint type;
317   gdouble gain, freq;
318 
319   eq1 = gst_check_setup_element ("equalizer-nbands");
320   g_object_set (G_OBJECT (eq1), "num-bands", 3, NULL);
321 
322   /* set properties to non-defaults */
323   gst_child_proxy_set ((GstChildProxy *) eq1,
324       "band0::type", 0, "band0::gain", -3.0, "band0::freq", 100.0,
325       "band1::type", 1, "band1::gain", +3.0, "band1::freq", 1000.0,
326       "band2::type", 2, "band2::gain", +9.0, "band2::freq", 10000.0, NULL);
327 
328   /* save preset */
329   gst_preset_save_preset ((GstPreset *) eq1, "_testpreset_");
330   GST_INFO_OBJECT (eq1, "Preset saved");
331 
332   eq2 = gst_check_setup_element ("equalizer-nbands");
333   g_object_set (G_OBJECT (eq2), "num-bands", 3, NULL);
334 
335   /* load preset */
336   gst_preset_load_preset ((GstPreset *) eq2, "_testpreset_");
337   GST_INFO_OBJECT (eq1, "Preset loaded");
338 
339   /* compare properties */
340   gst_child_proxy_get ((GstChildProxy *) eq2,
341       "band0::type", &type, "band0::gain", &gain, "band0::freq", &freq, NULL);
342   ck_assert_int_eq (type, 0);
343   fail_unless (gain == -3.0, NULL);
344   fail_unless (freq == 100.0, NULL);
345   gst_child_proxy_get ((GstChildProxy *) eq2,
346       "band1::type", &type, "band1::gain", &gain, "band1::freq", &freq, NULL);
347   ck_assert_int_eq (type, 1);
348   fail_unless (gain == +3.0, NULL);
349   fail_unless (freq == 1000.0, NULL);
350   gst_child_proxy_get ((GstChildProxy *) eq2,
351       "band2::type", &type, "band2::gain", &gain, "band2::freq", &freq, NULL);
352   ck_assert_int_eq (type, 2);
353   fail_unless (gain == +9.0, NULL);
354   fail_unless (freq == 10000.0, NULL);
355 
356   gst_preset_delete_preset ((GstPreset *) eq1, "_testpreset_");
357   gst_check_teardown_element (eq1);
358   gst_check_teardown_element (eq2);
359 }
360 
361 GST_END_TEST;
362 
363 
364 static Suite *
equalizer_suite(void)365 equalizer_suite (void)
366 {
367   Suite *s = suite_create ("equalizer");
368   TCase *tc_chain = tcase_create ("general");
369 
370   suite_add_tcase (s, tc_chain);
371   tcase_add_test (tc_chain, test_equalizer_5bands_passthrough);
372   tcase_add_test (tc_chain, test_equalizer_5bands_minus_24);
373   tcase_add_test (tc_chain, test_equalizer_5bands_plus_12);
374   tcase_add_test (tc_chain, test_equalizer_band_number_changing);
375   tcase_add_test (tc_chain, test_equalizer_presets);
376 
377   return s;
378 }
379 
380 GST_CHECK_MAIN (equalizer);
381