diff options
Diffstat (limited to 'gst/spectrum')
-rw-r--r-- | gst/spectrum/.gitignore | 7 | ||||
-rw-r--r-- | gst/spectrum/Makefile.am | 10 | ||||
-rw-r--r-- | gst/spectrum/README | 5 | ||||
-rw-r--r-- | gst/spectrum/fix_fft.c | 452 | ||||
-rw-r--r-- | gst/spectrum/gstspectrum.c | 242 | ||||
-rw-r--r-- | gst/spectrum/gstspectrum.h | 67 |
6 files changed, 783 insertions, 0 deletions
diff --git a/gst/spectrum/.gitignore b/gst/spectrum/.gitignore new file mode 100644 index 00000000..08f5ed37 --- /dev/null +++ b/gst/spectrum/.gitignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +*.o +*.lo +*.la +.deps +.libs diff --git a/gst/spectrum/Makefile.am b/gst/spectrum/Makefile.am new file mode 100644 index 00000000..476c3fd1 --- /dev/null +++ b/gst/spectrum/Makefile.am @@ -0,0 +1,10 @@ +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgstspectrum.la + +libgstspectrum_la_SOURCES = gstspectrum.c fix_fft.c +libgstspectrum_la_CFLAGS = $(GST_CFLAGS) + +noinst_HEADERS = gstspectrum.h + +EXTRA_DIST = README diff --git a/gst/spectrum/README b/gst/spectrum/README new file mode 100644 index 00000000..87555712 --- /dev/null +++ b/gst/spectrum/README @@ -0,0 +1,5 @@ +This is a simple, rather lame spectrum analyzer made from the fix_fft.c +code, as found I think in xmms-0.9.1 (the 75-wide output sounds like xmms +to me), which is actually written by other people (see fix_fft.c for +credits). It worked last time I had GiST working, which was a while ago. +Yes, GiST is not included here yet, it will be in 0.1.0. diff --git a/gst/spectrum/fix_fft.c b/gst/spectrum/fix_fft.c new file mode 100644 index 00000000..ecd70303 --- /dev/null +++ b/gst/spectrum/fix_fft.c @@ -0,0 +1,452 @@ +/* fix_fft.c - Fixed-point Fast Fourier Transform */ +/* + fix_fft() perform FFT or inverse FFT + window() applies a Hanning window to the (time) input + fix_loud() calculates the loudness of the signal, for + each freq point. Result is an integer array, + units are dB (values will be negative). + iscale() scale an integer value by (numer/denom). + fix_mpy() perform fixed-point multiplication. + Sinewave[1024] sinewave normalized to 32767 (= 1.0). + Loudampl[100] Amplitudes for lopudnesses from 0 to -99 dB. + Low_pass Low-pass filter, cutoff at sample_freq / 4. + + All data are fixed-point short integers, in which + -32768 to +32768 represent -1.0 to +1.0. Integer arithmetic + is used for speed, instead of the more natural floating-point. + + For the forward FFT (time -> freq), fixed scaling is + performed to prevent arithmetic overflow, and to map a 0dB + sine/cosine wave (i.e. amplitude = 32767) to two -6dB freq + coefficients; the one in the lower half is reported as 0dB + by fix_loud(). The return value is always 0. + + For the inverse FFT (freq -> time), fixed scaling cannot be + done, as two 0dB coefficients would sum to a peak amplitude of + 64K, overflowing the 32k range of the fixed-point integers. + Thus, the fix_fft() routine performs variable scaling, and + returns a value which is the number of bits LEFT by which + the output must be shifted to get the actual amplitude + (i.e. if fix_fft() returns 3, each value of fr[] and fi[] + must be multiplied by 8 (2**3) for proper scaling. + Clearly, this cannot be done within the fixed-point short + integers. In practice, if the result is to be used as a + filter, the scale_shift can usually be ignored, as the + result will be approximately correctly normalized as is. + + TURBO C, any memory model; uses inline assembly for speed + and for carefully-scaled arithmetic. + + Written by: Tom Roberts 11/8/89 + Made portable: Malcolm Slaney 12/15/94 malcolm@interval.com + + Timing on a Macintosh PowerBook 180.... (using Symantec C6.0) + fix_fft (1024 points) 8 ticks + fft (1024 points - Using SANE) 112 Ticks + fft (1024 points - Using FPU) 11 + + */ + +#define fixed short + +/* FIX_MPY() - fixed-point multiplication macro. + This macro is a statement, not an expression (uses asm). + BEWARE: make sure _DX is not clobbered by evaluating (A) or DEST. + args are all of type fixed. + Scaling ensures that 32767*32767 = 32767. */ + +#define FIX_MPY(DEST,A,B) DEST = ((long)(A) * (long)(B))>>15 + +#define N_WAVE 1024 /* dimension of Sinewave[] */ +#define LOG2_N_WAVE 10 /* log2(N_WAVE) */ +#define N_LOUD 100 /* dimension of Loudampl[] */ + +extern fixed gst_spectrum_Sinewave[N_WAVE]; /* placed at end of this file for clarity */ +extern fixed gst_spectrum_Loudampl[N_LOUD]; +static int gst_spectrum_db_from_ampl(fixed re, fixed im); +static fixed gst_spectrum_fix_mpy(fixed a, fixed b); + +/* + fix_fft() - perform fast Fourier transform. + + if n>0 FFT is done, if n<0 inverse FFT is done + fr[n],fi[n] are real,imaginary arrays, INPUT AND RESULT. + size of data = 2**m + set inverse to 0=dft, 1=idft + */ +int gst_spectrum_fix_fft(fixed fr[], fixed fi[], int m, int inverse) { + int mr, nn, i, j, l, k, istep, n, scale, shift; + fixed qr, qi, tr, ti, wr, wi, t; + + n = 1 << m; + + if (n > N_WAVE) + return -1; + + mr = 0; + nn = n - 1; + scale = 0; + + /* decimation in time - re-order data */ + for (m = 1; m <= nn; ++m) + { + l = n; + do + { + l >>= 1; + } + while (mr + l > nn); + mr = (mr & (l - 1)) + l; + + if (mr <= m) + continue; + tr = fr[m]; + fr[m] = fr[mr]; + fr[mr] = tr; + ti = fi[m]; + fi[m] = fi[mr]; + fi[mr] = ti; + } + + l = 1; + k = LOG2_N_WAVE - 1; + while (l < n) + { + if (inverse) + { + /* variable scaling, depending upon data */ + shift = 0; + for (i = 0; i < n; ++i) + { + j = fr[i]; + if (j < 0) + j = -j; + m = fi[i]; + if (m < 0) + m = -m; + if (j > 16383 || m > 16383) + { + shift = 1; + break; + } + } + if (shift) + ++scale; + } + else + { + /* fixed scaling, for proper normalization - + there will be log2(n) passes, so this + results in an overall factor of 1/n, + distributed to maximize arithmetic accuracy. */ + shift = 1; + } + /* it may not be obvious, but the shift will be performed + on each data point exactly once, during this pass. */ + istep = l << 1; + for (m = 0; m < l; ++m) + { + j = m << k; + /* 0 <= j < N_WAVE/2 */ + wr = gst_spectrum_Sinewave[j + N_WAVE / 4]; + wi = -gst_spectrum_Sinewave[j]; + if (inverse) + wi = -wi; + if (shift) + { + wr >>= 1; + wi >>= 1; + } + for (i = m; i < n; i += istep) + { + j = i + l; + tr = gst_spectrum_fix_mpy(wr, fr[j]) - + gst_spectrum_fix_mpy(wi, fi[j]); + ti = gst_spectrum_fix_mpy(wr, fi[j]) + + gst_spectrum_fix_mpy(wi, fr[j]); + qr = fr[i]; + qi = fi[i]; + if (shift) + { + qr >>= 1; + qi >>= 1; + } + fr[j] = qr - tr; + fi[j] = qi - ti; + fr[i] = qr + tr; + fi[i] = qi + ti; + } + } + --k; + l = istep; + } + + return scale; +} + +/* window() - apply a Hanning window */ +void gst_spectrum_window(fixed fr[], int n) { + int i, j, k; + + j = N_WAVE / n; + n >>= 1; + for (i = 0, k = N_WAVE / 4; i < n; ++i, k += j) + FIX_MPY(fr[i], fr[i], 16384 - (gst_spectrum_Sinewave[k] >> 1)); + n <<= 1; + for (k -= j; i < n; ++i, k -= j) + FIX_MPY(fr[i], fr[i], 16384 - (gst_spectrum_Sinewave[k] >> 1)); +} + +/* fix_loud() - compute loudness of freq-vis components. + n should be ntot/2, where ntot was passed to fix_fft(); + 6 dB is added to account for the omitted alias components. + scale_shift should be the result of fix_fft(), if the time-series + was obtained from an inverse FFT, 0 otherwise. + loud[] is the loudness, in dB wrt 32767; will be +10 to -N_LOUD. + */ +void gst_spectrum_fix_loud(fixed loud[], fixed fr[], fixed fi[], int n, int scale_shift) { + int i, max; + + max = 0; + if (scale_shift > 0) + max = 10; + scale_shift = (scale_shift + 1) * 6; + + for (i = 0; i < n; ++i) + { + loud[i] = gst_spectrum_db_from_ampl(fr[i], fi[i]) + scale_shift; + if (loud[i] > max) + loud[i] = max; + } +} + +/* db_from_ampl() - find loudness (in dB) from + the complex amplitude. + */ +int gst_spectrum_db_from_ampl(fixed re, fixed im) { + static long loud2[N_LOUD] = + {0}; + long v; + int i; + + if (loud2[0] == 0) + { + loud2[0] = (long) gst_spectrum_Loudampl[0] * (long) gst_spectrum_Loudampl[0]; + for (i = 1; i < N_LOUD; ++i) + { + v = (long) gst_spectrum_Loudampl[i] * (long) gst_spectrum_Loudampl[i]; + loud2[i] = v; + loud2[i - 1] = (loud2[i - 1] + v) / 2; + } + } + + v = (long) re *(long) re + (long) im *(long) im; + + for (i = 0; i < N_LOUD; ++i) + if (loud2[i] <= v) + break; + + return (-i); +} + +/* + fix_mpy() - fixed-point multiplication + */ +fixed gst_spectrum_fix_mpy(fixed a, fixed b) { + FIX_MPY(a, a, b); + return a; +} + +/* + iscale() - scale an integer value by (numer/denom) + */ +int gst_spectrum_iscale(int value, int numer, int denom) { + return (long) value *(long) numer / (long) denom; +} + +/* + fix_dot() - dot product of two fixed arrays + */ +fixed gst_spectrum_fix_dot(fixed * hpa, fixed * pb, int n) { + fixed *pa; + long sum; + register fixed a, b; + unsigned int seg, off; + +/* seg = FP_SEG(hpa); + off = FP_OFF(hpa); + seg += off>>4; + off &= 0x000F; + pa = MK_FP(seg,off); + */ + sum = 0L; + while (n--) + { + a = *pa++; + b = *pb++; + FIX_MPY(a, a, b); + sum += a; + } + + if (sum > 0x7FFF) + sum = 0x7FFF; + else if (sum < -0x7FFF) + sum = -0x7FFF; + + return (fixed) sum; + +} + +#if N_WAVE != 1024 +ERROR:N_WAVE != 1024 +#endif +fixed gst_spectrum_Sinewave[1024] = { + 0, 201, 402, 603, 804, 1005, 1206, 1406, + 1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011, + 3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608, + 4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195, + 6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766, + 7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319, + 9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849, + 11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353, + 12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827, + 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268, + 15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672, + 16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036, + 18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357, + 19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631, + 20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855, + 22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027, + 23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143, + 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201, + 25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198, + 26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132, + 27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001, + 28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802, + 28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534, + 29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195, + 30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783, + 30851, 30918, 30984, 31049, + 31113, 31175, 31236, 31297, + 31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735, + 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097, + 32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382, + 32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588, + 32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717, + 32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766, + 32767, 32766, 32764, 32761, 32757, 32751, 32744, 32736, + 32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628, + 32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441, + 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176, + 32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833, + 31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413, + 31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918, + 30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349, + 30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706, + 29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992, + 28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208, + 28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355, + 27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437, + 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456, + 25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413, + 24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311, + 23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153, + 22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942, + 20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680, + 19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371, + 18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017, + 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623, + 15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191, + 14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724, + 12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227, + 11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703, + 9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156, + 7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589, + 6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006, + 4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411, + 3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808, + 1607, 1406, 1206, 1005, 804, 603, 402, 201, + 0, -201, -402, -603, -804, -1005, -1206, -1406, + -1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011, + -3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608, + -4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195, + -6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766, + -7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319, + -9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849, + -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353, + -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827, + -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268, + -15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672, + -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036, + -18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357, + -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631, + -20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855, + -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027, + -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143, + -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201, + -25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198, + -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132, + -27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001, + -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802, + -28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534, + -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195, + -30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783, + -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297, + -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735, + -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097, + -32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382, + -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588, + -32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717, + -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766, + -32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736, + -32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628, + -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441, + -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176, + -32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833, + -31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413, + -31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918, + -30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349, + -30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706, + -29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992, + -28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208, + -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355, + -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437, + -26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456, + -25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413, + -24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311, + -23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153, + -22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942, + -20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680, + -19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371, + -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017, + -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623, + -15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191, + -14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724, + -12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227, + -11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703, + -9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156, + -7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589, + -6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006, + -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411, + -3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808, + -1607, -1406, -1206, -1005, -804, -603, -402, -201, +}; + +#if N_LOUD != 100 +ERROR:N_LOUD != 100 +#endif +fixed gst_spectrum_Loudampl[100] = { + 32767, 29203, 26027, 23197, 20674, 18426, 16422, 14636, + 13044, 11626, 10361, 9234, 8230, 7335, 6537, 5826, + 5193, 4628, 4125, 3676, 3276, 2920, 2602, 2319, + 2067, 1842, 1642, 1463, 1304, 1162, 1036, 923, + 823, 733, 653, 582, 519, 462, 412, 367, + 327, 292, 260, 231, 206, 184, 164, 146, + 130, 116, 103, 92, 82, 73, 65, 58, + 51, 46, 41, 36, 32, 29, 26, 23, + 20, 18, 16, 14, 13, 11, 10, 9, + 8, 7, 6, 5, 5, 4, 4, 3, + 3, 2, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +}; diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c new file mode 100644 index 00000000..0821545c --- /dev/null +++ b/gst/spectrum/gstspectrum.c @@ -0,0 +1,242 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <string.h> + +#include "gstspectrum.h" + +static GstElementDetails gst_spectrum_details = { + "Spectrum analyzer", + "Filter/Analysis", + "Run an FFT on the audio signal, output spectrum data", + VERSION, + "Erik Walthinsen <omega@cse.ogi.edu>", + "(C) 1999", +}; + + +static GstTypeDefinition spectrumdefinition = { + "spectrum_spectrum_raw", + "spectrum/raw", + NULL, + NULL, +}; + + +/* Spectrum signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_WIDTH, +}; + + +static void gst_spectrum_class_init (GstSpectrumClass *klass); +static void gst_spectrum_init (GstSpectrum *spectrum); + +static void gst_spectrum_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); + +static void gst_spectrum_chain (GstPad *pad, GstBuffer *buf); + +#define fixed short +int gst_spectrum_fix_fft(fixed fr[], fixed fi[], int m, int inverse); +void gst_spectrum_fix_loud(fixed loud[], fixed fr[], fixed fi[], int n, int scale_shift); +void gst_spectrum_window(fixed fr[], int n); + + +static GstElementClass *parent_class = NULL; +//static guint gst_spectrum_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_spectrum_get_type (void) +{ + static GType spectrum_type = 0; + + if (!spectrum_type) { + static const GTypeInfo spectrum_info = { + sizeof(GstSpectrumClass), NULL, + NULL, + (GClassInitFunc)gst_spectrum_class_init, + NULL, + NULL, + sizeof(GstSpectrum), + 0, + (GInstanceInitFunc)gst_spectrum_init, + }; + spectrum_type = g_type_register_static(GST_TYPE_ELEMENT, "GstSpectrum", &spectrum_info, 0); + } + return spectrum_type; +} + +static void +gst_spectrum_class_init (GstSpectrumClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WIDTH, + g_param_spec_int("width","width","width", + G_MININT,G_MAXINT,0,G_PARAM_WRITABLE)); // CHECKME + + gobject_class->set_property = gst_spectrum_set_property; +} + +static void +gst_spectrum_init (GstSpectrum *spectrum) +{ + spectrum->sinkpad = gst_pad_new("sink",GST_PAD_SINK); + gst_element_add_pad(GST_ELEMENT(spectrum),spectrum->sinkpad); + gst_pad_set_chain_function(spectrum->sinkpad,gst_spectrum_chain); + spectrum->srcpad = gst_pad_new("src",GST_PAD_SRC); + gst_element_add_pad(GST_ELEMENT(spectrum),spectrum->srcpad); + + spectrum->width = 75; +} + +static void +gst_spectrum_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstSpectrum *spectrum; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_SPECTRUM(object)); + spectrum = GST_SPECTRUM(object); + + switch (prop_id) { + case ARG_WIDTH: + spectrum->width = g_value_get_int (value); + break; + default: + break; + } +} + +static void +gst_spectrum_chain (GstPad *pad, GstBuffer *buf) +{ + GstSpectrum *spectrum; + gint spec_base, spec_len; + gint16 *re, *im, *loud; + gint16 *samples; + gint samplecount,step,pos,i; + guchar *spect; + GstBuffer *newbuf; + + g_return_if_fail(pad != NULL); + g_return_if_fail(GST_IS_PAD(pad)); + g_return_if_fail(buf != NULL); + + spectrum = GST_SPECTRUM (GST_OBJECT_PARENT (pad)); + + /* first deal with audio metadata */ +// FIXME +// if (buf->meta) { +// if (spectrum->meta != NULL) { +// /* FIXME: need to unref the old metadata so it goes away */ +// } +// /* we just make a copy of the pointer */ +// spectrum->meta = (MetaAudioRaw *)(buf->data); +// /* FIXME: now we have to ref the metadata so it does go away */ +// } + + //g_return_if_fail(spectrum->meta != NULL); + + //samplecount = GST_BUFFER_SIZE(buf) / + // (spectrum->meta->channels * sizeof(gint16)); +// samples = (gint16 *)g_malloc(buf->datasize); +// g_return_if_fail(samples != NULL); +// memcpy(samples,(gint16 +//*)GST_BUFFER_DATA(buf),GST_BUFFER_DATASIZE(buf)); +// gst_buffer_unref(buf); + samples = (gint16 *)GST_BUFFER_DATA(buf); + +// return; +// spec_base = (gint) (log(samplecount) / log(2)); +// if (spec_base > 10) spec_base = 10; +// spec_len = (gint) pow(2, spec_base); + spec_base = 8; + spec_len = 1024; + + im = g_malloc(spec_len * sizeof(gint16)); + g_return_if_fail(im != NULL); + loud = g_malloc(spec_len * sizeof(gint16)); + g_return_if_fail(loud != NULL); + + memset(im,0,spec_len * sizeof(gint16)); + //if (spectrum->meta->channels == 2) { + re = g_malloc(spec_len * sizeof(gint16)); + for (i=0;i<spec_len;i++) + re[i] = (samples[(i*2)] + samples[(i*2)+1]) >> 1; + //} else + // re = samples; + gst_spectrum_window(re,spec_len); + gst_spectrum_fix_fft(re,im,spec_base,FALSE); + gst_spectrum_fix_loud(loud,re,im,spec_len,0); + if (re != samples) g_free(re); + g_free(im); + step = spec_len / (spectrum->width*2); + spect = (guchar *)g_malloc(spectrum->width); + for (i=0,pos=0;i<spectrum->width;i++,pos += step) { + if (loud[pos] > -60) + spect[i] = (loud[pos] + 60) / 2; + else + spect[i] = 0; +// if (spect[i] > 15); +// spect[i] = 15; + } + g_free(loud); + gst_buffer_unref(buf); +// g_free(samples); + + newbuf = gst_buffer_new(); + g_return_if_fail(newbuf != NULL); + GST_BUFFER_DATA(newbuf) = spect; + GST_BUFFER_SIZE(newbuf) = spectrum->width; + + gst_pad_push(spectrum->srcpad,newbuf); +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + /* create an elementfactory for the spectrum element */ + factory = gst_elementfactory_new ("spectrum",GST_TYPE_SPECTRUM, + &gst_spectrum_details); + g_return_val_if_fail (factory != NULL, FALSE); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "spectrum", + plugin_init +}; diff --git a/gst/spectrum/gstspectrum.h b/gst/spectrum/gstspectrum.h new file mode 100644 index 00000000..f7a395ec --- /dev/null +++ b/gst/spectrum/gstspectrum.h @@ -0,0 +1,67 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_SPECTRUM_H__ +#define __GST_SPECTRUM_H__ + + +#include <gst/gst.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_SPECTRUM \ + (gst_spectrum_get_type()) +#define GST_SPECTRUM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPECTRUM,GstSpectrum)) +#define GST_SPECTRUM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPECTRUM,GstSpectrum)) +#define GST_IS_SPECTRUM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPECTRUM)) +#define GST_IS_SPECTRUM_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPECTRUM)) + +typedef struct _GstSpectrum GstSpectrum; +typedef struct _GstSpectrumClass GstSpectrumClass; + +struct _GstSpectrum { + GstElement element; + + GstPad *sinkpad,*srcpad; + + gint width; +}; + +struct _GstSpectrumClass { + GstElementClass parent_class; +}; + +GType gst_spectrum_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_SPECTRUM_H__ */ |