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_s16.h"
28 #include "kiss_fftr_s16.h"
29 #include "gstfft.h"
30 #include "gstffts16.h"
31
32 /**
33 * SECTION:gstffts16
34 * @title: GstFFTS16
35 * @short_description: FFT functions for signed 16 bit integer samples
36 *
37 * #GstFFTS16 provides a FFT implementation and related functions for
38 * signed 16 bit integer samples. To use this call gst_fft_s16_new() for
39 * allocating a #GstFFTS16 instance with the appropriate parameters and
40 * then call gst_fft_s16_fft() or gst_fft_s16_inverse_fft() to perform the
41 * FFT or inverse FFT on a buffer of samples.
42 *
43 * After use free the #GstFFTS16 instance with gst_fft_s16_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_s16_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_s16_window() can comfortably
55 * be used.
56 *
57 * Be aware, that you can't simply run gst_fft_s16_inverse_fft() on the
58 * resulting frequency data of gst_fft_s16_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 _GstFFTS16
66 {
67 void *cfg;
68 gboolean inverse;
69 gint len;
70 };
71
72 /**
73 * gst_fft_s16_new: (skip)
74 * @len: Length of the FFT in the time domain
75 * @inverse: %TRUE if the #GstFFTS16 instance should be used for the inverse FFT
76 *
77 * This returns a new #GstFFTS16 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 #GstFFTS16 instance.
85 */
86 GstFFTS16 *
gst_fft_s16_new(gint len,gboolean inverse)87 gst_fft_s16_new (gint len, gboolean inverse)
88 {
89 GstFFTS16 *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_s16_alloc (len, (inverse) ? 1 : 0, NULL, &subsize);
96 memneeded = ALIGN_STRUCT (sizeof (GstFFTS16)) + subsize;
97
98 self = (GstFFTS16 *) g_malloc0 (memneeded);
99
100 self->cfg = (((guint8 *) self) + ALIGN_STRUCT (sizeof (GstFFTS16)));
101 self->cfg = kiss_fftr_s16_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_s16_fft:
112 * @self: #GstFFTS16 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 #GstFFTS16 instance with gst_fft_s16_new().
120 *
121 * @freqdata must be large enough to hold @len/2 + 1 #GstFFTS16Complex frequency
122 * domain samples.
123 *
124 */
125 void
gst_fft_s16_fft(GstFFTS16 * self,const gint16 * timedata,GstFFTS16Complex * freqdata)126 gst_fft_s16_fft (GstFFTS16 * self, const gint16 * timedata,
127 GstFFTS16Complex * 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_s16 (self->cfg, timedata, (kiss_fft_s16_cpx *) freqdata);
135 }
136
137 /**
138 * gst_fft_s16_inverse_fft:
139 * @self: #GstFFTS16 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 #GstFFTS16 instance with gst_fft_s16_new().
147 *
148 * @timedata must be large enough to hold @len time domain samples.
149 *
150 */
151 void
gst_fft_s16_inverse_fft(GstFFTS16 * self,const GstFFTS16Complex * freqdata,gint16 * timedata)152 gst_fft_s16_inverse_fft (GstFFTS16 * self, const GstFFTS16Complex * freqdata,
153 gint16 * 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_s16 (self->cfg, (kiss_fft_s16_cpx *) freqdata, timedata);
161 }
162
163 /**
164 * gst_fft_s16_free:
165 * @self: #GstFFTS16 instance for this call
166 *
167 * This frees the memory allocated for @self.
168 *
169 */
170 void
gst_fft_s16_free(GstFFTS16 * self)171 gst_fft_s16_free (GstFFTS16 * self)
172 {
173 g_free (self);
174 }
175
176 /**
177 * gst_fft_s16_window:
178 * @self: #GstFFTS16 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_s16_window(GstFFTS16 * self,gint16 * timedata,GstFFTWindow window)186 gst_fft_s16_window (GstFFTS16 * self, gint16 * 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