Merge branch 'master' into 0.11
[platform/upstream/gst-plugins-good.git] / tests / examples / audiofx / firfilter-example.c
1 /* GStreamer
2  * Copyright (C) 2009 Sebastian Droege <sebastian.droege@collabora.co.uk>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /* This small sample application creates a bandpass FIR filter
21  * by transforming the frequency response to the filter kernel.
22  */
23
24 #include <string.h>
25 #include <math.h>
26
27 #include <gst/gst.h>
28 #include <gst/fft/gstfftf64.h>
29
30 static gboolean
31 on_message (GstBus * bus, GstMessage * message, gpointer user_data)
32 {
33   GMainLoop *loop = (GMainLoop *) user_data;
34
35   switch (GST_MESSAGE_TYPE (message)) {
36     case GST_MESSAGE_ERROR:
37       g_error ("Got ERROR");
38       g_main_loop_quit (loop);
39       break;
40     case GST_MESSAGE_WARNING:
41       g_warning ("Got WARNING");
42       g_main_loop_quit (loop);
43       break;
44     case GST_MESSAGE_EOS:
45       g_main_loop_quit (loop);
46       break;
47     default:
48       break;
49   }
50
51   return TRUE;
52 }
53
54 static void
55 on_rate_changed (GstElement * element, gint rate, gpointer user_data)
56 {
57   GValueArray *va;
58   GValue v = { 0, };
59   GstFFTF64 *fft;
60   GstFFTF64Complex frequency_response[17];
61   gdouble tmp[32];
62   gdouble filter_kernel[32];
63   guint i;
64
65   /* Create the frequency response: zero outside
66    * a small frequency band */
67   for (i = 0; i < 17; i++) {
68     if (i < 5 || i > 11)
69       frequency_response[i].r = 0.0;
70     else
71       frequency_response[i].r = 1.0;
72
73     frequency_response[i].i = 0.0;
74   }
75
76   /* Calculate the inverse FT of the frequency response */
77   fft = gst_fft_f64_new (32, TRUE);
78   gst_fft_f64_inverse_fft (fft, frequency_response, tmp);
79   gst_fft_f64_free (fft);
80
81   /* Shift the inverse FT of the frequency response by 16,
82    * i.e. the half of the kernel length to get the
83    * impulse response. See http://www.dspguide.com/ch17/1.htm
84    * for more information.
85    */
86   for (i = 0; i < 32; i++)
87     filter_kernel[i] = tmp[(i + 16) % 32];
88
89   /* Apply the hamming window to the impulse response to get
90    * a better result than given from the rectangular window
91    */
92   for (i = 0; i < 32; i++)
93     filter_kernel[i] *= (0.54 - 0.46 * cos (2 * G_PI * i / 32));
94
95   va = g_value_array_new (1);
96
97   g_value_init (&v, G_TYPE_DOUBLE);
98   for (i = 0; i < 32; i++) {
99     g_value_set_double (&v, filter_kernel[i]);
100     g_value_array_append (va, &v);
101     g_value_reset (&v);
102   }
103   g_object_set (G_OBJECT (element), "kernel", va, NULL);
104   /* Latency is 1/2 of the kernel length for this method of
105    * calculating a filter kernel from the frequency response
106    */
107   g_object_set (G_OBJECT (element), "latency", (gint64) (32 / 2), NULL);
108   g_value_array_free (va);
109 }
110
111 gint
112 main (gint argc, gchar * argv[])
113 {
114   GstElement *pipeline, *src, *filter, *conv, *sink;
115   GstBus *bus;
116   GMainLoop *loop;
117
118   gst_init (NULL, NULL);
119
120   pipeline = gst_element_factory_make ("pipeline", NULL);
121
122   src = gst_element_factory_make ("audiotestsrc", NULL);
123   g_object_set (G_OBJECT (src), "wave", 5, NULL);
124
125   filter = gst_element_factory_make ("audiofirfilter", NULL);
126   g_signal_connect (G_OBJECT (filter), "rate-changed",
127       G_CALLBACK (on_rate_changed), NULL);
128
129   conv = gst_element_factory_make ("audioconvert", NULL);
130
131   sink = gst_element_factory_make ("autoaudiosink", NULL);
132   g_return_val_if_fail (sink != NULL, -1);
133
134   gst_bin_add_many (GST_BIN (pipeline), src, filter, conv, sink, NULL);
135   if (!gst_element_link_many (src, filter, conv, sink, NULL)) {
136     g_error ("Failed to link elements");
137     return -2;
138   }
139
140   loop = g_main_loop_new (NULL, FALSE);
141
142   bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
143   gst_bus_add_signal_watch (bus);
144   g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop);
145   gst_object_unref (GST_OBJECT (bus));
146
147   if (gst_element_set_state (pipeline,
148           GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
149     g_error ("Failed to go into PLAYING state");
150     return -3;
151   }
152
153   g_main_loop_run (loop);
154
155   gst_element_set_state (pipeline, GST_STATE_NULL);
156
157   g_main_loop_unref (loop);
158   gst_object_unref (pipeline);
159
160   return 0;
161 }