changeset 38:0ea4d6430cfc

Implemented xtract_harmonics
author Jamie Bullock <jamie@postlude.co.uk>
date Sat, 09 Dec 2006 15:21:35 +0000
parents b699a37d27c4
children 39c76f4db5b7
files ChangeLog configure.in examples/puredata/xtract~.c src/delta.c src/init.c src/libxtract.c src/scalar.c src/vector.c xtract/libxtract.h xtract/xtract_macros.h xtract/xtract_scalar.h xtract/xtract_vector.h
diffstat 12 files changed, 139 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Dec 09 11:42:13 2006 +0000
+++ b/ChangeLog	Sat Dec 09 15:21:35 2006 +0000
@@ -1,3 +1,8 @@
+2006-11-10 Jamie Bullock <jamie@postlude.co.uk>
+    * version 0.3.0
+	* Corrected typos in scalar.c
+	* Added -Wall to CFLAGS and corrected problems relating to warnings
+	* Added xtract_harmonics and corresponding documentation
 2006-11-10 Jamie Bullock <jamie@postlude.co.uk>
     * version 0.2.2
 	* Fixed 'bus error' crash on Mac OS X by adding 'extern' declarations
--- a/configure.in	Sat Dec 09 11:42:13 2006 +0000
+++ b/configure.in	Sat Dec 09 15:21:35 2006 +0000
@@ -2,9 +2,9 @@
 # Increment for major API changes, release status changes
 m4_define(libxtract_major_version, 0)
 # Increment for feature additions and enhancements
-m4_define(libxtract_minor_version, 2)
+m4_define(libxtract_minor_version, 3)
 # Increment for fixes 
-m4_define(libxtract_fix_version, 2)
+m4_define(libxtract_fix_version, 0)
 
 m4_define(libxtract_version, libxtract_major_version.libxtract_minor_version.libxtract_fix_version)
 		
@@ -64,7 +64,7 @@
 # age to 0.
 XTRACT_SO_VERSION=0:0:0
 
-CFLAGS="$CFLAGS -pedantic -ansi -Wall"
+CFLAGS="$CFLAGS -pedantic -ansi -Wall -std=c99"
 LDFLAGS="$LDFLAGS -lm"
 
 AC_ARG_WITH(pd_dir,
--- a/examples/puredata/xtract~.c	Sat Dec 09 11:42:13 2006 +0000
+++ b/examples/puredata/xtract~.c	Sat Dec 09 15:21:35 2006 +0000
@@ -39,10 +39,14 @@
     t_sample *in = (t_sample *)(w[1]);
     t_xtract_tilde *x = (t_xtract_tilde *)(w[2]);
     t_int N = (t_int)(w[3]);
+    t_int return_code = 0;
     float result = 0;
 
-    xtract[x->feature]((float *)in, N, x->argv, &result);
+    return_code = xtract[x->feature]((float *)in, N, x->argv, &result);
 
+    if(return_code == FEATURE_NOT_IMPLEMENTED)
+	pd_error(x, "Feature not implemented");
+    
     outlet_float(x->x_obj.ob_outlet, result);
     return (w+4);
 }
@@ -53,11 +57,15 @@
     t_float *tmp_in, *tmp_out;
     t_xtract_tilde *x = (t_xtract_tilde *)(w[3]);
     t_int N = (t_int)(w[4]), n;
+    t_int return_code = 0;
 
     tmp_in = copybytes(in, N * sizeof(t_float));
     tmp_out = getbytes(N * sizeof(t_float));
     
-    xtract[x->feature](tmp_in, N, x->argv, tmp_out);
+    return_code = xtract[x->feature](tmp_in, N, x->argv, tmp_out);
+    
+    if(return_code == FEATURE_NOT_IMPLEMENTED)
+	pd_error(x, "Feature not implemented");
     
     n = N;
 
@@ -158,6 +166,10 @@
         80.0f, f->n_filters, f->filters);
     }
     else if(tmp == gensym("dct")) x->feature = DCT;
+    else if(tmp == gensym("harmonics")){ 
+	x->feature = HARMONICS;
+	x->argv = getbytes(3 * sizeof(t_float));
+    }
     else if(tmp == gensym("bark_coefficients")){
         x->feature = BARK_COEFFICIENTS;
         x->argv = (t_int *)getbytes(BARK_BANDS * sizeof(t_int));
@@ -173,7 +185,8 @@
     if(x->feature == AUTOCORRELATION || x->feature == AUTOCORRELATION_FFT ||
     x->feature == MFCC || x->feature == AMDF || x->feature == ASDF|| 
     x->feature == DCT || x->feature == BARK_COEFFICIENTS || 
-    x->feature == MAGNITUDE_SPECTRUM || x->feature == PEAKS) 
+    x->feature == MAGNITUDE_SPECTRUM || x->feature == PEAKS || 
+    x->feature == HARMONICS) 
         x->feature_type = VECTOR;
                 
     else if (x->feature == FLUX || x->feature == ATTACK_TIME || 
--- a/src/delta.c	Sat Dec 09 11:42:13 2006 +0000
+++ b/src/delta.c	Sat Dec 09 15:21:35 2006 +0000
@@ -20,30 +20,29 @@
 
 /* xtract_delta.c: defines functions that extract a feature as a single value from more than one input vector */
 
-#include "xtract/xtract_delta.h"
-#include "xtract/xtract_macros.h"
+#include "xtract/libxtract.h"
 
 int xtract_flux(float *data, int N, void *argv , float *result){
 
-    NOT_IMPLEMENTED;
+    return FEATURE_NOT_IMPLEMENTED;
 
 }
 
 int xtract_attack_time(float *data, int N, void *argv , float *result){
 
-    NOT_IMPLEMENTED;
+    return FEATURE_NOT_IMPLEMENTED;
 
 }
 
 int xtract_decay_time(float *data, int N, void *argv, float *result){
 
-    NOT_IMPLEMENTED;
+    return FEATURE_NOT_IMPLEMENTED;
 
 }
 
 int xtract_delta_feature(float *data, int N, void *argv, float *result){
 
-    NOT_IMPLEMENTED;
+    return FEATURE_NOT_IMPLEMENTED;
 
 }
 
--- a/src/init.c	Sat Dec 09 11:42:13 2006 +0000
+++ b/src/init.c	Sat Dec 09 15:21:35 2006 +0000
@@ -112,7 +112,7 @@
 
 int xtract_init_bark(int N, float nyquist, int *band_limits){
 
-    float  bark_freq_max, bark_freq_min, freq_bw_bark, temp, edges[] = {0, 100, 200, 300, 400, 510, 630, 770, 920, 1080, 1270, 1480, 1720, 2000, 2320, 2700, 3150, 3700, 4400, 5300, 6400, 7700, 9500, 12000, 15500, 20500, 27000}; /* Takes us up to sr = 54kHz (CCRMA: JOS)*/
+    float  edges[] = {0, 100, 200, 300, 400, 510, 630, 770, 920, 1080, 1270, 1480, 1720, 2000, 2320, 2700, 3150, 3700, 4400, 5300, 6400, 7700, 9500, 12000, 15500, 20500, 27000}; /* Takes us up to sr = 54kHz (CCRMA: JOS)*/
 
     int M, bands = BARK_BANDS;
     
@@ -121,4 +121,6 @@
     while(bands--)
         band_limits[bands] = edges[bands] / nyquist * M;
         /*FIX shohuld use rounding, but couldn't get it to work */
+
+    return SUCCESS;
 }
--- a/src/libxtract.c	Sat Dec 09 11:42:13 2006 +0000
+++ b/src/libxtract.c	Sat Dec 09 15:21:35 2006 +0000
@@ -68,7 +68,8 @@
     xtract_magnitude_spectrum,
     xtract_autocorrelation_fft,
     xtract_mfcc,
-    xtract_dct
+    xtract_dct,
+    xtract_harmonics
 };
 
 char *xtract_help_strings[] = {
@@ -114,5 +115,6 @@
    "xtract_magnitude_spectrum",
    "xtract_autocorrelation_fft",
    "xtract_mfcc",
-   "xtract_dct"
+   "xtract_dct",
+   "xtract_harmonics"
    };
--- a/src/scalar.c	Sat Dec 09 11:42:13 2006 +0000
+++ b/src/scalar.c	Sat Dec 09 15:21:35 2006 +0000
@@ -33,6 +33,8 @@
 	*result += *data++;
 
     *result /= N;
+
+    return SUCCESS;
 }
 
 int xtract_variance(float *data, int N, void *argv, float *result){
@@ -43,12 +45,15 @@
 	*result += *data++ - *(float *)argv;
 
     *result = SQ(*result) / (N - 1);
+    
+    return SUCCESS;
 }
 
 int xtract_standard_deviation(float *data, int N, void *argv, float *result){
 
     *result = sqrt(*(float *)argv);
 
+    return SUCCESS;
 }
 
 int xtract_average_deviation(float *data, int N, void *argv, float *result){
@@ -60,6 +65,7 @@
 
     *result /= N;
 
+    return SUCCESS;
 }
 
 int xtract_skewness(float *data, int N, void *argv,  float *result){
@@ -71,6 +77,7 @@
 
     *result = pow(*result, 3) / N;
 
+    return SUCCESS;
 }
 
 int xtract_kurtosis(float *data, int N, void *argv,  float *result){
@@ -82,6 +89,7 @@
 
     *result = pow(*result, 4) / N - 3;
 
+    return SUCCESS;
 }
 
 
@@ -92,7 +100,7 @@
     float *freqs, *amps, FA = 0.f, A = 0.f;
 
     freqs = data;
-    amps = data + (N  >>  1);
+    amps = data + n;
 
     while(n--){
 	FA += freqs[n] * amps[n];
@@ -101,6 +109,7 @@
 
     *result = FA / A;
 
+    return SUCCESS;
 }
 
 int xtract_irregularity_k(float *data, int N, void *argv, float *result){
@@ -111,6 +120,7 @@
     for(n = 1; n < M; n++)
 	*result += abs(data[n] - (data[n-1] + data[n] + data[n+1]) / 3);
 
+    return SUCCESS;
 }
 
 int xtract_irregularity_j(float *data, int N, void *argv, float *result){
@@ -126,6 +136,7 @@
 
     *result = num / den;
 
+    return SUCCESS;
 }
 
 int xtract_tristimulus_1(float *data, int N, void *argv, float *result){
@@ -139,6 +150,7 @@
 
     *result = data[0] / den;
 
+    return SUCCESS;
 }
 
 int xtract_tristimulus_2(float *data, int N, void *argv, float *result){
@@ -152,6 +164,7 @@
 
     *result = (data[1] + data[2] + data[3])  / den;
 
+    return SUCCESS;
 }
 
 int xtract_tristimulus_3(float *data, int N, void *argv, float *result){
@@ -167,6 +180,7 @@
 
     *result = num / den;
 
+    return SUCCESS;
 }
 
 int xtract_smoothness(float *data, int N, void *argv, float *result){
@@ -181,6 +195,8 @@
 	*result += abs(20 * log(data[n-1]) - (20 * log(data[n-2]) + 
 		    20 * log(data[n-1]) + 20 * log(data[n])) / 3);
     }
+    
+    return SUCCESS;
 }
 
 int xtract_spread(float *data, int N, void *argv, float *result){
@@ -197,6 +213,7 @@
 
     *result = sqrt(num / den);
 
+    return SUCCESS;
 }
 
 int xtract_zcr(float *data, int N, void *argv, float *result){
@@ -208,6 +225,7 @@
 
     *result /= N;
 
+    return SUCCESS;
 }
 
 int xtract_rolloff(float *data, int N, void *argv, float *result){
@@ -223,6 +241,7 @@
 
     *result = n;
 
+    return SUCCESS;
 }
 
 int xtract_loudness(float *data, int N, void *argv, float *result){
@@ -233,6 +252,8 @@
 
     while(n--)
 	*result += pow(data[n], 0.23);
+
+    return SUCCESS;
 }
 
 
@@ -254,6 +275,7 @@
 
     *result = 10 * log10(num / den);
 
+    return SUCCESS;
 }
 
 int xtract_tonality(float *data, int N, void *argv, float *result){
@@ -266,17 +288,18 @@
 
     *result = MIN(sfmdb, 1);
 
+    return SUCCESS;
 }
 
 int xtract_crest(float *data, int N, void *argv, float *result){
 
-    NOT_IMPLEMENTED;
+    return FEATURE_NOT_IMPLEMENTED;
 
 }
 
 int xtract_noisiness(float *data, int N, void *argv, float *result){
 
-    NOT_IMPLEMENTED;
+    return FEATURE_NOT_IMPLEMENTED;
 
 }
 
@@ -288,6 +311,7 @@
 
     *result = sqrt(*result / N);
 
+    return SUCCESS;
 }
 
 int xtract_inharmonicity(float *data, int N, void *argv, float *result){
@@ -306,18 +330,19 @@
 
     *result = (2 * num) / (*fund * den); 
 
+    return SUCCESS;
 }
 
 
 int xtract_power(float *data, int N, void *argv, float *result){
 
-    NOT_IMPLEMENTED;
+    return FEATURE_NOT_IMPLEMENTED;
 
 }
 
 int xtract_odd_even_ratio(float *data, int N, void *argv, float *result){
 
-    int n = N >> 1, j, k;
+    int n = N, j, k;
 
     float num = 0.f, den = 0.f;
 
@@ -330,17 +355,18 @@
 
     *result = num / den;
 
+    return SUCCESS;
 }
 
 int xtract_sharpness(float *data, int N, void *argv, float *result){
 
-    NOT_IMPLEMENTED;
+    return FEATURE_NOT_IMPLEMENTED;
 
 }
 
 int xtract_slope(float *data, int N, void *argv, float *result){
 
-    NOT_IMPLEMENTED;
+    return FEATURE_NOT_IMPLEMENTED;
 
 }
 
@@ -356,6 +382,7 @@
 
     *result = (lowest_match == SR_LIMIT ? 0 : lowest_match);
 
+    return SUCCESS;
 }
 
 int xtract_hps(float *data, int N, void *argv, float *result){
@@ -416,6 +443,7 @@
     free(coeffs3);
     free(product);
 
+    return SUCCESS;
 }
 
 
--- a/src/vector.c	Sat Dec 09 11:42:13 2006 +0000
+++ b/src/vector.c	Sat Dec 09 15:21:35 2006 +0000
@@ -51,6 +51,7 @@
     fftwf_destroy_plan(plan);
     fftwf_free(temp);
     
+    return SUCCESS;
 }
 
 int xtract_autocorrelation_fft(float *data, int N, void *argv, float *result){
@@ -69,13 +70,14 @@
     
     fftwf_destroy_plan(plan);
     fftwf_free(temp);
+
+    return SUCCESS;
 }
 
 int xtract_mfcc(float *data, int N, void *argv, float *result){
 
     xtract_mel_filter *f;
     int n, filter;
-    fftwf_plan plan;
 
     f = (xtract_mel_filter *)argv;
 
@@ -91,6 +93,7 @@
     
     xtract_dct(result, f->n_filters, NULL, result);
 
+    return SUCCESS;
 }
 
 int xtract_dct(float *data, int N, void *argv, float *result){
@@ -102,6 +105,8 @@
     
     fftwf_execute(plan);
     fftwf_destroy_plan(plan);
+
+    return SUCCESS;
 }
 
 #else
@@ -147,6 +152,8 @@
         }
         result[n] = corr / N;
     }
+
+    return SUCCESS;
 }
 
 int xtract_amdf(float *data, int N, void *argv, float *result){
@@ -164,6 +171,8 @@
         }
         result[n] = md / N;
     }
+
+    return SUCCESS;
 }
 
 int xtract_asdf(float *data, int N, void *argv, float *result){
@@ -180,6 +189,8 @@
         }
         result[n] = sd / N;
     }
+
+    return SUCCESS;
 }
 
 int xtract_bark_coefficients(float *data, int N, void *argv, float *result){
@@ -192,12 +203,14 @@
         for(n = limits[band]; n < limits[band + 1]; n++)
             result[band] += data[n];
     }
+
+    return SUCCESS;
 }
 
 int xtract_peaks(float *data, int N, void *argv, float *result){
 
     float thresh, max, y, y2, y3, p, width, sr; 
-    int n = N, M, return_code;
+    int n = N, M, return_code = SUCCESS;
     
     if(argv != NULL){
         thresh = ((float *)argv)[0];
@@ -259,3 +272,32 @@
     return (return_code ? return_code : SUCCESS);
 }
 
+int xtract_harmonics(float *data, int N, void *argv, float *result){
+    
+    int n = (N >> 1), M = n; 
+
+    float *freqs, *amps, f0, thresh, ratio, nearest, distance;
+
+    freqs = data;
+    amps = data + n;
+    f0 = *((float *)argv);
+    thresh = *((float *)argv+1);
+
+    ratio = nearest = distance = 0.f;
+
+    while(n--){
+	if(freqs[n]){
+	    ratio = freqs[n] / f0;
+	    nearest = round(ratio);
+	    distance = fabs(nearest - ratio);
+	    if(distance > thresh)
+		result[n] = result[M + n] = 0.f;
+	    else
+		result[n] = result[M + n] = freqs[n];
+	}
+	else
+	    result[n] = result[M + n] = 0.f;
+    }
+    return SUCCESS;
+}
+	    
--- a/xtract/libxtract.h	Sat Dec 09 11:42:13 2006 +0000
+++ b/xtract/libxtract.h	Sat Dec 09 15:21:35 2006 +0000
@@ -53,7 +53,7 @@
   * @{
   */
 
-#define XTRACT_FEATURES 43
+#define XTRACT_FEATURES 44
     
 #define LOG_LIMIT 10e-10
 #define VERY_BIG_NUMBER 2e10
@@ -104,7 +104,8 @@
     MAGNITUDE_SPECTRUM,
     AUTOCORRELATION_FFT,
     MFCC,
-    DCT
+    DCT,
+    HARMONICS
 };
 
 /** \brief Enumeration of feature types */
@@ -126,7 +127,8 @@
     MALLOC_FAILED,
     BAD_ARGV,
     BAD_VECTOR_SIZE,
-    NO_RESULT
+    NO_RESULT,
+    FEATURE_NOT_IMPLEMENTED
 };
 
 /**
@@ -178,12 +180,18 @@
 #ifdef XTRACT
 extern int(*xtract[XTRACT_FEATURES])(float *data, int N, void *argv, float *result);
 
-
 /** \brief An array of pointers to function help strings
  *
  * Defined in libxtract.c. As a minimum this will contain pointers to the names of all of the feature extraction functions in the library. This is intended as a 'quick reference' to be queried as necessary.
  */
 extern char *xtract_help_strings[XTRACT_FEATURES];
+
+/** \brief An array of pointers to strings giving function output units
+ *
+ * Defined in libxtract.c. This contains pointers to strings giving the output units of all of the feature extraction functions in the library. This is intended as a 'quick reference' to be queried as necessary.
+ */
+extern char *xtract_units[XTRACT_FEATURES];
+
 #endif
 
 /** \brief A structure to store a set of n_filters Mel filters */
--- a/xtract/xtract_macros.h	Sat Dec 09 11:42:13 2006 +0000
+++ b/xtract/xtract_macros.h	Sat Dec 09 15:21:35 2006 +0000
@@ -34,7 +34,6 @@
 #define SQ(a) ((a) * (a))
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
-#define NOT_IMPLEMENTED printf("Feature not implemented yet.\n")
 #define NEEDS_FFTW printf("LibXtract must be compiled with fftw support to use this function.\n")
 
 #ifdef __cplusplus
--- a/xtract/xtract_scalar.h	Sat Dec 09 11:42:13 2006 +0000
+++ b/xtract/xtract_scalar.h	Sat Dec 09 15:21:35 2006 +0000
@@ -117,7 +117,7 @@
 
 /** \brief Calculate the Tristimulus of an input vector using a method described by Pollard and Jansson (1982)
  * 
- * \param *data: a pointer to the first element in an array of floats representing the amplitudes of the harmonic spectrum of an audio vector
+ * \param *data: a pointer to the first element in an array of floats representing the amplitudes of the harmonic spectrum of an audio vector e.g. a pointer to the second half of the array pointed to by *result from xtract_harmonics()
  * \param N: the number of elements to be considered
  * \param *argv: a pointer to NULL
  * \param *result: the tristimulus of N values from the array pointed to by *data
@@ -246,8 +246,8 @@
 /* Odd to even harmonic ratio */
 /** \brief Extract the Odd to even harmonic ratio of an input vector 
  * 
- * \param *data: a pointer to the first element in an array of floats representing the harmonic spectrum of an audio vector
- * \param N: the number of elements to be considered
+ * \param *data: a pointer to the first element in an array of floats representing the frequencies of the harmonic spectrum of an audio vector. It is sufficient to pass in a pointer to the array pointed to by *result from xtract_harmonics.
+ * \param N: the number of elements to be considered. If using the array pointed to by *result from xtract_harmonics, N should equal half the total array size i.e., just the frequencies of the peaks.
  * \param *argv: a pointer to NULL
  * \param *result: the odd/even harmonic ratio of N values from the array pointed to by *data
  */
--- a/xtract/xtract_vector.h	Sat Dec 09 11:42:13 2006 +0000
+++ b/xtract/xtract_vector.h	Sat Dec 09 15:21:35 2006 +0000
@@ -109,7 +109,7 @@
  */
 int xtract_bark_coefficients(float *data, int N, void *argv, float *result);
 
-/** \brief Extract the frequency and amplitude of spectral peaks from a of a magnitude spectrum
+/** \brief Extract the frequency and amplitude of spectral peaks from a magnitude spectrum
  * \param *data: a pointer to the first element in an array of floats representing the magnitude spectrum of an audio vector
  * \param N: the number of array elements to be considered
  * \param *argv: a pointer to an array containing peak threshold as percentage below max peak, and sample rate 
@@ -117,6 +117,14 @@
  */
 int xtract_peaks(float *data, int N, void *argv, float *result);
 
+/** \brief Extract the harmonic spectrum of from a of a peak spectrum 
+ * \param *data: a pointer to the first element in an array of floats representing the peak spectrum of an audio vector (e.g. *result from  xtract_peaks). It is expected that the first half of the array pointed to by *data will contain frequencies for each peak considered, and the the second half will contain the respective amplitudes
+ * \param N: the size of the array pointed to by *data
+ * \param *argv: a pointer to an array containing the fundamental (f0) of the spectrum, and a threshold (t) where 0<=t<=1.0, and t determines the distance from the nearest harmonic number within which a partial can be considered harmonic.
+ * \param *result: a pointer to an array of size N containing N/2 freqs and N/2 amplitudes, amplitudes are on a decibel scale with dbFS = 0
+ */
+int xtract_harmonics(float *data, int N, void *argv, float *result);
+
 /** @} */
 
 #ifdef __cplusplus