XMMS2
format.c
Go to the documentation of this file.
1#include <math.h>
2#include "common.h"
3
4#define FFT_LEN XMMSC_VISUALIZATION_WINDOW_SIZE
5/* TODO: better way, check this! */
6#define FFT_BITS 9
7
8/* Log scale settings */
9#define AMP_LOG_SCALE_THRESHOLD0 0.001f
10#define AMP_LOG_SCALE_DIVISOR 6.908f /* divisor = -log threshold */
11#define FREQ_LOG_SCALE_BASE 2.0f
12
13static gfloat window[FFT_LEN];
14static gfloat spec[FFT_LEN/2];
15static gboolean fft_ready = FALSE;
16static gboolean fft_done;
17
18void fft_init ()
19{
20 if (!fft_ready) {
21 int i;
22 /* calculate Hann window used to reduce spectral leakage */
23 for (i = 0; i < FFT_LEN; i++) {
24 window[i] = 0.5 - 0.5 * cos (2.0 * M_PI * i / FFT_LEN);
25 }
26 fft_done = TRUE;
27 }
28 fft_done = FALSE;
29}
30
31/* interesting: data->value.uint32 = xmms_sample_samples_to_ms (vis->format, pos); */
32
33static void
34fft (short *samples, gfloat *spec)
35{
36 gint nv2, k, l, j = 0, i;
37 gfloat t_r, t_i;
38 gfloat buf[FFT_LEN][2];
39
40 for (i = 0; i < FFT_LEN; i++){
41 buf[i][0] = (float) samples[j++];
42 buf[i][0] += (float) samples[j++];
43 buf[i][0] /= (float) (1 << 17);
44 buf[i][0] *= window[i];
45 buf[i][1] = 0.0f;
46 }
47
48 /* reorder... */ /* this is crappy! Go rewrite it using real bitreversing */
49 nv2 = FFT_LEN / 2;
50 j = 1;
51
52 for (i = 1; i < FFT_LEN; i++) {
53 if (i < j) {
54 t_r = buf[i - 1][0];
55 t_i = buf[i - 1][1];
56 buf[i - 1][0] = buf[j - 1][0];
57 buf[i - 1][1] = buf[j - 1][1];
58 buf[j - 1][0] = t_r;
59 buf[j - 1][1] = t_i;
60 }
61
62 k = nv2;
63
64 while (k < j) {
65 j -= k;
66 k >>= 1;
67 }
68
69 j += k;
70 }
71
72 /* do fft */
73 for (l = 1; l <= FFT_BITS; l++) {
74 gint le = 1 << l;
75 gint le1 = le / 2;
76 gfloat u_r = 1.0;
77 gfloat u_i = 0.0;
78 gfloat w_r = cosf (M_PI / (float) le1);
79 gfloat w_i = -sinf (M_PI / (float) le1);
80
81 for (j = 1; j <= le1; j++) {
82 for (i = j; i <= FFT_LEN; i += le) {
83 gint ip = i + le1;
84
85 t_r = buf[ip - 1][0] * u_r - u_i * buf[ip - 1][1];
86 t_i = buf[ip - 1][1] * u_r + u_i * buf[ip - 1][0];
87
88 buf[ip - 1][0] = buf[i - 1][0] - t_r;
89 buf[ip - 1][1] = buf[i - 1][1] - t_i;
90
91 buf[i - 1][0] = buf[i - 1][0] + t_r;
92 buf[i - 1][1] = buf[i - 1][1] + t_i;
93 }
94
95 t_r = u_r * w_r - w_i * u_i;
96 u_i = w_r * u_i + w_i * u_r;
97 u_r = t_r;
98 }
99 }
100
101 /* output abs-value instead */
102 for (i = 0; i < nv2; i++) {
103 spec[i] = hypot (buf[i][0], buf[i][1]);
104 }
105
106 /* correct the scale */
107 spec[0] /= 2;
108 spec[nv2 - 1] /= 2;
109}
110
111/**
112 * Calcualte the FFT on the decoded data buffer.
113 */
114static short
115fill_buffer_fft (int16_t* dest, int size, short *src)
116{
117 int i;
118 float tmp;
119
120 if (size != FFT_LEN * 2) {
121 return 0;
122 }
123
124 if (!fft_done) {
125 fft (src, spec);
126 fft_done = TRUE;
127 }
128
129 /* TODO: more sophisticated! */
130 for (i = 0; i < FFT_LEN / 2; ++i) {
131 if (spec[i] >= 1.0) {
132 dest[i] = htons (SHRT_MAX);
133 } else if (spec[i] < 0.0) {
134 dest[i] = 0;
135 } else {
136 tmp = spec[i];
137 if (tmp > AMP_LOG_SCALE_THRESHOLD0) {
138// tmp = 1.0f + (logf (tmp) / AMP_LOG_SCALE_DIVISOR);
139 } else {
140 tmp = 0.0f;
141 }
142 dest[i] = htons ((int16_t)(tmp * SHRT_MAX));
143 }
144 }
145 return FFT_LEN / 2;
146}
147
148short
149fill_buffer (int16_t *dest, xmmsc_vis_properties_t* prop, int channels, int size, short *src)
150{
151 int i, j;
152 if (prop->type == VIS_PEAK) {
153 short l = 0, r = 0;
154 for (i = 0; i < size; i += channels) {
155 if (src[i] > 0 && src[i] > l) {
156 l = src[i];
157 }
158 if (src[i] < 0 && -src[i] > l) {
159 l = -src[i];
160 }
161 if (channels > 1) {
162 if (src[i+1] > 0 && src[i+1] > r) {
163 r = src[i+1];
164 }
165 if (src[i+1] < 0 && -src[i+1] > r) {
166 r = -src[i+1];
167 }
168 }
169 }
170 if (channels == 1) {
171 r = l;
172 }
173 if (prop->stereo) {
174 dest[0] = htons (l);
175 dest[1] = htons (r);
176 size = 2;
177 } else {
178 dest[0] = htons ((l + r) / 2);
179 size = 1;
180 }
181 }
182 if (prop->type == VIS_PCM) {
183 for (i = 0, j = 0; i < size; i += channels, j++) {
184 short *l, *r;
185 if (prop->pcm_hardwire) {
186 l = &dest[j*2];
187 r = &dest[j*2 + 1];
188 } else {
189 l = &dest[j];
190 r = &dest[size/channels + j];
191 }
192 *l = htons (src[i]);
193 if (prop->stereo) {
194 if (channels > 1) {
195 *r = htons (src[i+1]);
196 } else {
197 *r = htons (src[i]);
198 }
199 }
200 }
201 size /= channels;
202 if (prop->stereo) {
203 size *= 2;
204 }
205 }
206 if (prop->type == VIS_SPECTRUM) {
207 size = fill_buffer_fft (dest, size, src);
208 }
209 return size;
210}
short fill_buffer(int16_t *dest, xmmsc_vis_properties_t *prop, int channels, int size, short *src)
Definition format.c:149
#define AMP_LOG_SCALE_THRESHOLD0
Definition format.c:9
#define FFT_LEN
Definition format.c:4
#define FFT_BITS
Definition format.c:6
void fft_init()
Definition format.c:18
@ VIS_SPECTRUM
Properties of the delivered vis data.