1 /* GStreamer
2  * Copyright (C) <2007> Sebastian Dröge <slomo@circular-chaos.org>
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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 
24 #include <glib.h>
25 #include <math.h>
26 
27 #include "_kiss_fft_guts_f32.h"
28 #include "kiss_fftr_f32.h"
29 #include "gstfft.h"
30 #include "gstfftf32.h"
31 
32 /**
33  * SECTION:gstfftf32
34  * @title: GstFFTF32
35  * @short_description: FFT functions for 32 bit float samples
36  *
37  * #GstFFTF32 provides a FFT implementation and related functions for
38  * 32 bit float samples. To use this call gst_fft_f32_new() for
39  * allocating a #GstFFTF32 instance with the appropriate parameters and
40  * then call gst_fft_f32_fft() or gst_fft_f32_inverse_fft() to perform the
41  * FFT or inverse FFT on a buffer of samples.
42  *
43  * After use free the #GstFFTF32 instance with gst_fft_f32_free().
44  *
45  * For the best performance use gst_fft_next_fast_length() to get a
46  * number that is entirely a product of 2, 3 and 5 and use this as the
47  * @len parameter for gst_fft_f32_new().
48  *
49  * The @len parameter specifies the number of samples in the time domain that
50  * will be processed or generated. The number of samples in the frequency domain
51  * is @len/2 + 1. To get n samples in the frequency domain use 2*n - 2 as @len.
52  *
53  * Before performing the FFT on time domain data it usually makes sense
54  * to apply a window function to it. For this gst_fft_f32_window() can comfortably
55  * be used.
56  *
57  * Be aware, that you can't simply run gst_fft_f32_inverse_fft() on the
58  * resulting frequency data of gst_fft_f32_fft() to get the original data back.
59  * The relation between them is iFFT (FFT (x)) = x * nfft where nfft is the
60  * length of the FFT. This also has to be taken into account when calculation
61  * the magnitude of the frequency data.
62  *
63  */
64 
65 struct _GstFFTF32
66 {
67   void *cfg;
68   gboolean inverse;
69   gint len;
70 };
71 
72 /**
73  * gst_fft_f32_new: (skip)
74  * @len: Length of the FFT in the time domain
75  * @inverse: %TRUE if the #GstFFTF32 instance should be used for the inverse FFT
76  *
77  * This returns a new #GstFFTF32 instance with the given parameters. It makes
78  * sense to keep one instance for several calls for speed reasons.
79  *
80  * @len must be even and to get the best performance a product of
81  * 2, 3 and 5. To get the next number with this characteristics use
82  * gst_fft_next_fast_length().
83  *
84  * Returns: a new #GstFFTF32 instance.
85  */
86 GstFFTF32 *
gst_fft_f32_new(gint len,gboolean inverse)87 gst_fft_f32_new (gint len, gboolean inverse)
88 {
89   GstFFTF32 *self;
90   gsize subsize = 0, memneeded;
91 
92   g_return_val_if_fail (len > 0, NULL);
93   g_return_val_if_fail (len % 2 == 0, NULL);
94 
95   kiss_fftr_f32_alloc (len, (inverse) ? 1 : 0, NULL, &subsize);
96   memneeded = ALIGN_STRUCT (sizeof (GstFFTF32)) + subsize;
97 
98   self = (GstFFTF32 *) g_malloc0 (memneeded);
99 
100   self->cfg = (((guint8 *) self) + ALIGN_STRUCT (sizeof (GstFFTF32)));
101   self->cfg = kiss_fftr_f32_alloc (len, (inverse) ? 1 : 0, self->cfg, &subsize);
102   g_assert (self->cfg);
103 
104   self->inverse = inverse;
105   self->len = len;
106 
107   return self;
108 }
109 
110 /**
111  * gst_fft_f32_fft:
112  * @self: #GstFFTF32 instance for this call
113  * @timedata: Buffer of the samples in the time domain
114  * @freqdata: Target buffer for the samples in the frequency domain
115  *
116  * This performs the FFT on @timedata and puts the result in @freqdata.
117  *
118  * @timedata must have as many samples as specified with the @len parameter while
119  * allocating the #GstFFTF32 instance with gst_fft_f32_new().
120  *
121  * @freqdata must be large enough to hold @len/2 + 1 #GstFFTF32Complex frequency
122  * domain samples.
123  *
124  */
125 void
gst_fft_f32_fft(GstFFTF32 * self,const gfloat * timedata,GstFFTF32Complex * freqdata)126 gst_fft_f32_fft (GstFFTF32 * self, const gfloat * timedata,
127     GstFFTF32Complex * freqdata)
128 {
129   g_return_if_fail (self);
130   g_return_if_fail (!self->inverse);
131   g_return_if_fail (timedata);
132   g_return_if_fail (freqdata);
133 
134   kiss_fftr_f32 (self->cfg, timedata, (kiss_fft_f32_cpx *) freqdata);
135 }
136 
137 /**
138  * gst_fft_f32_inverse_fft:
139  * @self: #GstFFTF32 instance for this call
140  * @freqdata: Buffer of the samples in the frequency domain
141  * @timedata: Target buffer for the samples in the time domain
142  *
143  * This performs the inverse FFT on @freqdata and puts the result in @timedata.
144  *
145  * @freqdata must have @len/2 + 1 samples, where @len is the parameter specified
146  * while allocating the #GstFFTF32 instance with gst_fft_f32_new().
147  *
148  * @timedata must be large enough to hold @len time domain samples.
149  *
150  */
151 void
gst_fft_f32_inverse_fft(GstFFTF32 * self,const GstFFTF32Complex * freqdata,gfloat * timedata)152 gst_fft_f32_inverse_fft (GstFFTF32 * self, const GstFFTF32Complex * freqdata,
153     gfloat * timedata)
154 {
155   g_return_if_fail (self);
156   g_return_if_fail (self->inverse);
157   g_return_if_fail (timedata);
158   g_return_if_fail (freqdata);
159 
160   kiss_fftri_f32 (self->cfg, (kiss_fft_f32_cpx *) freqdata, timedata);
161 }
162 
163 /**
164  * gst_fft_f32_free:
165  * @self: #GstFFTF32 instance for this call
166  *
167  * This frees the memory allocated for @self.
168  *
169  */
170 void
gst_fft_f32_free(GstFFTF32 * self)171 gst_fft_f32_free (GstFFTF32 * self)
172 {
173   g_free (self);
174 }
175 
176 /**
177  * gst_fft_f32_window:
178  * @self: #GstFFTF32 instance for this call
179  * @timedata: Time domain samples
180  * @window: Window function to apply
181  *
182  * This calls the window function @window on the @timedata sample buffer.
183  *
184  */
185 void
gst_fft_f32_window(GstFFTF32 * self,gfloat * timedata,GstFFTWindow window)186 gst_fft_f32_window (GstFFTF32 * self, gfloat * timedata, GstFFTWindow window)
187 {
188   gint i, len;
189 
190   g_return_if_fail (self);
191   g_return_if_fail (timedata);
192 
193   len = self->len;
194 
195   switch (window) {
196     case GST_FFT_WINDOW_RECTANGULAR:
197       /* do nothing */
198       break;
199     case GST_FFT_WINDOW_HAMMING:
200       for (i = 0; i < len; i++)
201         timedata[i] *= (0.53836 - 0.46164 * cos (2.0 * G_PI * i / len));
202       break;
203     case GST_FFT_WINDOW_HANN:
204       for (i = 0; i < len; i++)
205         timedata[i] *= (0.5 - 0.5 * cos (2.0 * G_PI * i / len));
206       break;
207     case GST_FFT_WINDOW_BARTLETT:
208       for (i = 0; i < len; i++)
209         timedata[i] *= (1.0 - fabs ((2.0 * i - len) / len));
210       break;
211     case GST_FFT_WINDOW_BLACKMAN:
212       for (i = 0; i < len; i++)
213         timedata[i] *= (0.42 - 0.5 * cos ((2.0 * i) / len) +
214             0.08 * cos ((4.0 * i) / len));
215       break;
216     default:
217       g_assert_not_reached ();
218       break;
219   }
220 }
221