XMMS2
src/xmms/visualization/format.c
Go to the documentation of this file.
00001 #include <math.h>
00002 #include "common.h"
00003 
00004 #define FFT_LEN XMMSC_VISUALIZATION_WINDOW_SIZE
00005 /* TODO: better way, check this! */
00006 #define FFT_BITS 9
00007 
00008 /* Log scale settings */
00009 #define AMP_LOG_SCALE_THRESHOLD0    0.001f
00010 #define AMP_LOG_SCALE_DIVISOR       6.908f  /* divisor = -log threshold */
00011 #define FREQ_LOG_SCALE_BASE     2.0f
00012 
00013 static gfloat window[FFT_LEN];
00014 static gfloat spec[FFT_LEN/2];
00015 static gboolean fft_ready = FALSE;
00016 static gboolean fft_done;
00017 
00018 void fft_init ()
00019 {
00020     if (!fft_ready) {
00021         int i;
00022         /* calculate Hann window used to reduce spectral leakage */
00023         for (i = 0; i < FFT_LEN; i++) {
00024             window[i] = 0.5 - 0.5 * cos (2.0 * M_PI * i / FFT_LEN);
00025         }
00026         fft_done = TRUE;
00027     }
00028     fft_done = FALSE;
00029 }
00030 
00031 /* interesting: data->value.uint32 = xmms_sample_samples_to_ms (vis->format, pos); */
00032 
00033 static void
00034 fft (short *samples, gfloat *spec)
00035 {
00036     gint nv2, k, l, j = 0, i;
00037     gfloat t_r, t_i;
00038     gfloat buf[FFT_LEN][2];
00039 
00040     for (i = 0; i < FFT_LEN; i++){
00041         buf[i][0]  = (float) samples[j++];
00042         buf[i][0] += (float) samples[j++];
00043         buf[i][0] /= (float) (1 << 17);
00044         buf[i][0] *= window[i];
00045         buf[i][1] = 0.0f;
00046     }
00047 
00048     /* reorder... */  /* this is crappy! Go rewrite it using real bitreversing */
00049     nv2 = FFT_LEN / 2;
00050     j = 1;
00051 
00052     for (i = 1; i < FFT_LEN; i++) {
00053         if (i < j) {
00054             t_r = buf[i - 1][0];
00055             t_i = buf[i - 1][1];
00056             buf[i - 1][0] = buf[j - 1][0];
00057             buf[i - 1][1] = buf[j - 1][1];
00058             buf[j - 1][0] = t_r;
00059             buf[j - 1][1] = t_i;
00060         }
00061 
00062         k = nv2;
00063 
00064         while (k < j) {
00065             j -= k;
00066             k >>= 1;
00067         }
00068 
00069         j += k;
00070     }
00071 
00072     /* do fft */
00073     for (l = 1; l <= FFT_BITS; l++) {
00074         gint le = 1 << l;
00075         gint le1 = le / 2;
00076         gfloat u_r = 1.0;
00077         gfloat u_i = 0.0;
00078         gfloat w_r =  cosf (M_PI / (float) le1);
00079         gfloat w_i = -sinf (M_PI / (float) le1);
00080 
00081         for (j = 1; j <= le1; j++) {
00082             for (i = j; i <= FFT_LEN; i += le) {
00083                 gint ip = i + le1;
00084 
00085                 t_r = buf[ip - 1][0] * u_r - u_i * buf[ip - 1][1];
00086                 t_i = buf[ip - 1][1] * u_r + u_i * buf[ip - 1][0];
00087 
00088                 buf[ip - 1][0] = buf[i - 1][0] - t_r;
00089                 buf[ip - 1][1] = buf[i - 1][1] - t_i;
00090 
00091                 buf[i - 1][0] =  buf[i - 1][0] + t_r;
00092                 buf[i - 1][1] =  buf[i - 1][1] + t_i;
00093             }
00094 
00095             t_r = u_r * w_r - w_i * u_i;
00096             u_i = w_r * u_i + w_i * u_r;
00097             u_r = t_r;
00098         }
00099     }
00100 
00101     /* output abs-value instead */
00102     for (i = 0; i < nv2; i++) {
00103         spec[i] = hypot (buf[i][0], buf[i][1]);
00104     }
00105 
00106     /* correct the scale */
00107     spec[0] /= 2;
00108     spec[nv2 - 1] /= 2;
00109 }
00110 
00111 /**
00112  * Calcualte the FFT on the decoded data buffer.
00113  */
00114 static short
00115 fill_buffer_fft (int16_t* dest, int size, short *src)
00116 {
00117     int i;
00118     float tmp;
00119 
00120     if (size != FFT_LEN * 2) {
00121         return 0;
00122     }
00123 
00124     if (!fft_done) {
00125         fft (src, spec);
00126         fft_done = TRUE;
00127     }
00128 
00129     /* TODO: more sophisticated! */
00130     for (i = 0; i < FFT_LEN / 2; ++i) {
00131         if (spec[i] >= 1.0) {
00132             dest[i] = htons (SHRT_MAX);
00133         } else if (spec[i] < 0.0) {
00134             dest[i] = 0;
00135         } else {
00136             tmp = spec[i];
00137             if (tmp > AMP_LOG_SCALE_THRESHOLD0) {
00138 //              tmp = 1.0f + (logf (tmp) /  AMP_LOG_SCALE_DIVISOR);
00139             } else {
00140                 tmp = 0.0f;
00141             }
00142             dest[i] = htons ((int16_t)(tmp * SHRT_MAX));
00143         }
00144     }
00145     return FFT_LEN / 2;
00146 }
00147 
00148 short
00149 fill_buffer (int16_t *dest, xmmsc_vis_properties_t* prop, int channels, int size, short *src)
00150 {
00151     int i, j;
00152     if (prop->type == VIS_PEAK) {
00153         short l = 0, r = 0;
00154         for (i = 0; i < size; i += channels) {
00155             if (src[i] > 0 && src[i] > l) {
00156                 l = src[i];
00157             }
00158             if (src[i] < 0 && -src[i] > l) {
00159                 l = -src[i];
00160             }
00161             if (channels > 1) {
00162                 if (src[i+1] > 0 && src[i+1] > r) {
00163                     r = src[i+1];
00164                 }
00165                 if (src[i+1] < 0 && -src[i+1] > r) {
00166                     r = -src[i+1];
00167                 }
00168             }
00169         }
00170         if (channels == 1) {
00171             r = l;
00172         }
00173         if (prop->stereo) {
00174             dest[0] = htons (l);
00175             dest[1] = htons (r);
00176             size = 2;
00177         } else {
00178             dest[0] = htons ((l + r) / 2);
00179             size = 1;
00180         }
00181     }
00182     if (prop->type == VIS_PCM) {
00183         for (i = 0, j = 0; i < size; i += channels, j++) {
00184             short *l, *r;
00185             if (prop->pcm_hardwire) {
00186                 l = &dest[j*2];
00187                 r = &dest[j*2 + 1];
00188             } else {
00189                 l = &dest[j];
00190                 r = &dest[size/channels + j];
00191             }
00192             *l = htons (src[i]);
00193             if (prop->stereo) {
00194                 if (channels > 1) {
00195                     *r = htons (src[i+1]);
00196                 } else {
00197                     *r = htons (src[i]);
00198                 }
00199             }
00200         }
00201         size /= channels;
00202         if (prop->stereo) {
00203             size *= 2;
00204         }
00205     }
00206     if (prop->type == VIS_SPECTRUM) {
00207         size = fill_buffer_fft (dest, size, src);
00208     }
00209     return size;
00210 }