diff options
-rw-r--r-- | examples/puredata/xtract~.c | 180 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/descriptors.c | 317 | ||||
-rw-r--r-- | src/libxtract.c | 5 | ||||
-rw-r--r-- | xtract/libxtract.h | 90 | ||||
-rw-r--r-- | xtract/xtract_macros.h | 6 |
6 files changed, 455 insertions, 145 deletions
diff --git a/examples/puredata/xtract~.c b/examples/puredata/xtract~.c index 69c3e0d..c5febd5 100644 --- a/examples/puredata/xtract~.c +++ b/examples/puredata/xtract~.c @@ -102,157 +102,70 @@ static void *xtract_new(t_symbol *me, t_int argc, t_atom *argv) { t_symbol *tmp; t_xtract_tilde *x = (t_xtract_tilde *)pd_new(xtract_class); - xtract_mel_filter *f; - t_int n, N, floatargs = 0; + xtract_mel_filter *mf; + t_int n, N, f, F, n_args, type; + t_function_descriptor *fd; + n_args = type = 0; + + f = F = XTRACT_FEATURES; + N = BLOCKSIZE; x->argv = NULL; tmp = atom_getsymbol(argv); - /* map creation args to features */ - if(tmp == gensym("mean")) x->feature = MEAN; - else if(tmp == gensym("variance")) x->feature = VARIANCE; - else if(tmp == gensym("standard_deviation"))x->feature = STANDARD_DEVIATION; - else if(tmp == gensym("average_deviation")) x->feature = AVERAGE_DEVIATION; - else if(tmp == gensym("skewness")) x->feature = SKEWNESS; - else if(tmp == gensym("kurtosis")) x->feature = KURTOSIS; - else if(tmp == gensym("centroid")) x->feature = CENTROID; - else if(tmp == gensym("irregularity_k")) x->feature = IRREGULARITY_K; - else if(tmp == gensym("irregularity_j")) x->feature = IRREGULARITY_J; - else if(tmp == gensym("tristimulus_1")) x->feature = TRISTIMULUS_1; - else if(tmp == gensym("tristimulus_2")) x->feature = TRISTIMULUS_2; - else if(tmp == gensym("tristimulus_3")) x->feature = TRISTIMULUS_3; - else if(tmp == gensym("smoothness")) x->feature = SMOOTHNESS; - else if(tmp == gensym("spread")) x->feature = SPREAD; - else if(tmp == gensym("zcr")) x->feature = ZCR; - else if(tmp == gensym("rolloff")) x->feature = ROLLOFF; - else if(tmp == gensym("loudness")) x->feature = LOUDNESS; - else if(tmp == gensym("flatness")) x->feature = FLATNESS; - else if(tmp == gensym("tonality")) x->feature = TONALITY; - else if(tmp == gensym("crest")) x->feature = CREST; - else if(tmp == gensym("noisiness")) x->feature = NOISINESS; - else if(tmp == gensym("rms_amplitude")) x->feature = RMS_AMPLITUDE; - else if(tmp == gensym("inharmonicity")) x->feature = INHARMONICITY; - else if(tmp == gensym("power")) x->feature = POWER; - else if(tmp == gensym("odd_even_ratio")) x->feature = ODD_EVEN_RATIO; - else if(tmp == gensym("sharpness")) x->feature = SHARPNESS; - else if(tmp == gensym("slope")) x->feature = SLOPE; - else if(tmp == gensym("f0")) x->feature = F0; - else if(tmp == gensym("failsafe_f0")) x->feature = FAILSAFE_F0; - else if(tmp == gensym("hps"))x->feature = HPS; - else if(tmp == gensym("lowest_value"))x->feature = LOWEST_VALUE; - else if(tmp == gensym("highest_value"))x->feature = HIGHEST_VALUE; - else if(tmp == gensym("sum"))x->feature = SUM; - else if(tmp == gensym("dct")) x->feature = DCT; - else if(tmp == gensym("magnitude_spectrum")) - x->feature = MAGNITUDE_SPECTRUM; - else if(tmp == gensym("autocorrelation")) x->feature = AUTOCORRELATION; - else if(tmp == gensym("autocorrelation_fft")) - x->feature = AUTOCORRELATION_FFT; - else if(tmp == gensym("amdf")) x->feature = AMDF; - else if(tmp == gensym("asdf")) x->feature = ASDF; - else if(tmp == gensym("peaks")) x->feature = PEAKS; - else if(tmp == gensym("flux")) x->feature = FLUX; - else if(tmp == gensym("attack_time")) x->feature = ATTACK_TIME; - else if(tmp == gensym("decay_time")) x->feature = DECAY_TIME; - else if(tmp == gensym("delta")) x->feature = DELTA_FEATURE; - else if(tmp == gensym("mfcc")) x->feature = MFCC; - else if(tmp == gensym("harmonics")) x->feature = HARMONICS; - else if(tmp == gensym("bark_coefficients")) x->feature = BARK_COEFFICIENTS; - else post("xtract~: No feature selected"); + /* get function descriptors */ + fd = (t_function_descriptor *)xtract_make_descriptors(); - /* allocate memory for feature arguments */ - switch(x->feature){ - case MEAN: - case VARIANCE: - case STANDARD_DEVIATION: - case AVERAGE_DEVIATION: - case ROLLOFF: - case INHARMONICITY: - case MAGNITUDE_SPECTRUM: - case ODD_EVEN_RATIO: - case LOWEST_VALUE: - case F0: - case FAILSAFE_F0: - case TONALITY: - floatargs = 1; - break; - case SKEWNESS: - case KURTOSIS: - case PEAKS: - case HARMONICS: - case NOISINESS: - case CREST: - floatargs = 2; - break; - case CENTROID: - case IRREGULARITY_K: - case IRREGULARITY_J: - case TRISTIMULUS_1: - case TRISTIMULUS_2: - case TRISTIMULUS_3: - case SMOOTHNESS: - case FLATNESS: - case SPREAD: - case ZCR: - case LOUDNESS: - case HIGHEST_VALUE: - case SUM: - case RMS_AMPLITUDE: - case POWER: - case SHARPNESS: - case SLOPE: - case HPS: - case FLUX: /*not implemented */ - case ATTACK_TIME: /*not implemented */ - case DECAY_TIME: /*not implemented */ - case DELTA_FEATURE: /*not implemented */ - case AUTOCORRELATION_FFT: - case MFCC: - case DCT: - case AUTOCORRELATION: - case AMDF: - case ASDF: - case BARK_COEFFICIENTS: - floatargs = 0; - break; - default: - floatargs = 0; + /* iterate over descriptors */ + while(f--){ + /* map creation arg to feature */ + if(tmp == gensym(fd[f].algo.name)){ + x->feature = f; break; + } } - if(x->feature == MFCC){ - x->memory.argv = (size_t)(sizeof(xtract_mel_filter)); - x->argv = (xtract_mel_filter *)getbytes(x->memory.argv); - } - else if(x->feature == BARK_COEFFICIENTS){ - x->memory.argv = (size_t)(BARK_BANDS * sizeof(t_int)); - x->argv = (t_int *)getbytes(x->memory.argv); - } - else if (floatargs){ - x->memory.argv = (size_t)(floatargs * sizeof(t_float)); - x->argv = (t_float *)getbytes(x->memory.argv); + /* allocate memory for feature arguments */ + n_args = fd[f].n_args; + type = fd[f].argv.type; + + if(n_args){ + if(type == MEL_FILTER){ + x->memory.argv = (size_t)(n_args * sizeof(xtract_mel_filter)); + x->argv = (xtract_mel_filter *)getbytes(x->memory.argv); + } + else if(type == INT){ + x->memory.argv = (size_t)(n_args * sizeof(t_int)); + x->argv = (t_int *)getbytes(x->memory.argv); + } + else if (type == FLOAT){ + x->memory.argv = (size_t)(n_args * sizeof(t_float)); + x->argv = (t_float *)getbytes(x->memory.argv); + } + else + x->memory.argv = 0; } - else - x->memory.argv = 0; + post("xtract~: %s", fd[f].algo.pretty_name); + /* do init if needed */ if(x->feature == MFCC){ - f = x->argv; + mf = x->argv; - f->n_filters = 20; + mf->n_filters = 20; post("xtract~: mfcc: filters = %d", ((xtract_mel_filter *)x->argv)->n_filters); - f->filters = - (t_float **)getbytes(f->n_filters * sizeof(t_float *)); - for(n = 0; n < f->n_filters; n++) - f->filters[n] = (float *)getbytes(N * sizeof(float)); + mf->filters = + (t_float **)getbytes(mf->n_filters * sizeof(t_float *)); + for(n = 0; n < mf->n_filters; n++) + mf->filters[n] = (float *)getbytes(N * sizeof(float)); xtract_init_mfcc(N, NYQUIST, EQUAL_GAIN, 18000.0f, - 80.0f, f->n_filters, f->filters); + 80.0f, mf->n_filters, mf->filters); } else if(x->feature == BARK_COEFFICIENTS) xtract_init_bark(N, NYQUIST, x->argv); @@ -279,6 +192,9 @@ static void *xtract_new(t_symbol *me, t_int argc, t_atom *argv) { /* otherwise: float */ else outlet_new(&x->x_obj, &s_float); + /* free the function descriptors */ + xtract_free_descriptors(fd); + return (void *)x; } @@ -304,10 +220,10 @@ static void xtract_tilde_show_help(t_xtract_tilde *x, t_symbol *s){ i = XTRACT_FEATURES; post("\n\txtract~: Feature List\n"); - + /* while(i--){ post("\t%s", xtract_help_strings[i]+7); - } + }*/ } static void xtract_tilde_free(t_xtract_tilde *x) { diff --git a/src/Makefile.am b/src/Makefile.am index 3cb9e77..66f4198 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ -SOURCES = libxtract.c scalar.c vector.c delta.c init.c +SOURCES = libxtract.c descriptors.c scalar.c vector.c delta.c init.c if BUILD_FFT FFT_DEFINE = -DXTRACT_FFT diff --git a/src/descriptors.c b/src/descriptors.c new file mode 100644 index 0000000..0d35fd6 --- /dev/null +++ b/src/descriptors.c @@ -0,0 +1,317 @@ +/* libxtract feature extraction library + * + * Copyright (C) 2006 Jamie Bullock + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include "xtract/libxtract.h" +#include <stdlib.h> +#include <string.h> +#define XTRACT + +void *xtract_make_descriptors(){ + + t_function_descriptor *fd, *d; + int f , F; + char *name, *pretty_name; + int *n_args; + + f = F = XTRACT_FEATURES; + + fd = malloc(XTRACT_FEATURES * sizeof(t_function_descriptor)); + + while(f--){ + d = &fd[f]; + switch(f){ + case MEAN: + case VARIANCE: + case STANDARD_DEVIATION: + case AVERAGE_DEVIATION: + case ROLLOFF: + case INHARMONICITY: + case MAGNITUDE_SPECTRUM: + case ODD_EVEN_RATIO: + case LOWEST_VALUE: + case F0: + case FAILSAFE_F0: + case TONALITY: + d->n_args = 1; + d->argv.type = FLOAT; + break; + case SKEWNESS: + case KURTOSIS: + case PEAKS: + case HARMONICS: + case NOISINESS: + case CREST: + d->n_args = 2; + d->argv.type = FLOAT; + break; + case MFCC: + d->n_args = 1; + d->argv.type = MEL_FILTER; + break; + case BARK_COEFFICIENTS: + d->n_args = BARK_BANDS; + d->argv.type = INT; + break; + case CENTROID: + case IRREGULARITY_K: + case IRREGULARITY_J: + case TRISTIMULUS_1: + case TRISTIMULUS_2: + case TRISTIMULUS_3: + case SMOOTHNESS: + case FLATNESS: + case SPREAD: + case ZCR: + case LOUDNESS: + case HIGHEST_VALUE: + case SUM: + case RMS_AMPLITUDE: + case POWER: + case SHARPNESS: + case SLOPE: + case HPS: + case FLUX: + case ATTACK_TIME: + case DECAY_TIME: + case DELTA_FEATURE: + case AUTOCORRELATION_FFT: + case DCT: + case AUTOCORRELATION: + case AMDF: + case ASDF: + d->n_args = 0; + break; + default: + d->n_args = 0; + break; + } + name = d->algo.name; + pretty_name = d->algo.pretty_name; + n_args = d->n_args; + switch(f){ + case MEAN: + strcpy(name, "mean"); + strcpy(pretty_name, "Mean"); + break; + case VARIANCE: + strcpy(name, "variance"); + strcpy(pretty_name, "Variance"); + break; + case STANDARD_DEVIATION: + strcpy(name, "standard_deviation"); + strcpy(pretty_name, "Standard Deviation"); + break; + case AVERAGE_DEVIATION: + strcpy(name, "average_deviation"); + strcpy(pretty_name, "Average Deviation"); + break; + case ROLLOFF: + strcpy(name, "rolloff"); + strcpy(pretty_name, "Spectral Rolloff"); + break; + case INHARMONICITY: + strcpy(name, "inharmonicity"); + strcpy(pretty_name, "Inharmonicity"); + break; + case MAGNITUDE_SPECTRUM: + strcpy(name, "magnitude_spectrum"); + strcpy(pretty_name, "Magnitude Spectrum"); + break; + case ODD_EVEN_RATIO: + strcpy(name, "odd_even_ratio"); + strcpy(pretty_name, "Odd/Even Harmonic Ratio"); + break; + case LOWEST_VALUE: + strcpy(name, "lowest_value"); + strcpy(pretty_name, "Lowest Value"); + break; + case F0: + strcpy(name, "f0"); + strcpy(pretty_name, "Fundamental Frequency"); + break; + case FAILSAFE_F0: + strcpy(name, "failsafe_f0"); + strcpy(pretty_name, "Fundamental Frequency (failsafe)"); + break; + case TONALITY: + strcpy(name, "tonality"); + strcpy(pretty_name, "Tonality"); + break; + case SKEWNESS: + strcpy(name, "skewness"); + strcpy(pretty_name, "Spectral Skewness"); + break; + case KURTOSIS: + strcpy(name, "kurtosis"); + strcpy(pretty_name, "Spectral Kurtosis"); + break; + case PEAKS: + strcpy(name, "peaks"); + strcpy(pretty_name, "Spectral Peaks"); + break; + case HARMONICS: + strcpy(name, "harmonics"); + strcpy(pretty_name, "Spectral Harmonics"); + break; + case NOISINESS: + strcpy(name, "noisiness"); + strcpy(pretty_name, "Noisiness"); + break; + case CREST: + strcpy(name, "crest"); + strcpy(pretty_name, "Spectral Crest Measure"); + break; + case MFCC: + strcpy(name, "mfcc"); + strcpy(pretty_name, "Mel Frequency Cepstral Coefficients"); + break; + case BARK_COEFFICIENTS: + strcpy(name, "bark_coefficients"); + strcpy(pretty_name, "Bark Coefficients"); + break; + case CENTROID: + strcpy(name, "centroid"); + strcpy(pretty_name, "Spectral Centroid"); + break; + case IRREGULARITY_K: + strcpy(name, "irregularity_k"); + strcpy(pretty_name, "Irregularity I"); + break; + case IRREGULARITY_J: + strcpy(name, "irregularity_j"); + strcpy(pretty_name, "Irregularity II"); + break; + case TRISTIMULUS_1: + strcpy(name, "tristimulus_1"); + strcpy(pretty_name, "Tristimulus I"); + break; + case TRISTIMULUS_2: + strcpy(name, "tristimulus_2"); + strcpy(pretty_name, "Tristimulus II"); + break; + case TRISTIMULUS_3: + strcpy(name, "tristimulus_3"); + strcpy(pretty_name, "Tristimulus III"); + break; + case SMOOTHNESS: + strcpy(name, "smoothness"); + strcpy(pretty_name, "Spectral Smoothness"); + break; + case FLATNESS: + strcpy(name, "flatness"); + strcpy(pretty_name, "Spectral Flatness"); + break; + case SPREAD: + strcpy(name, "spread"); + strcpy(pretty_name, "Spectral Spread"); + break; + case ZCR: + strcpy(name, "zcr"); + strcpy(pretty_name, "Zero Crossing Rate"); + break; + case LOUDNESS: + strcpy(name, "loudness"); + strcpy(pretty_name, "Loudness"); + break; + case HIGHEST_VALUE: + strcpy(name, "highest_value"); + strcpy(pretty_name, "Highest Value"); + break; + case SUM: + strcpy(name, "sum"); + strcpy(pretty_name, "Sum of Values"); + break; + case RMS_AMPLITUDE: + strcpy(name, "rms_amplitude"); + strcpy(pretty_name, "RMS Amplitude"); + break; + case POWER: + strcpy(name, "power"); + strcpy(pretty_name, "Spectral Power"); + break; + case SHARPNESS: + strcpy(name, "sharpness"); + strcpy(pretty_name, "Spectral Sharpness"); + break; + case SLOPE: + strcpy(name, "slope"); + strcpy(pretty_name, "Spectral Slope"); + break; + case HPS: + strcpy(name, "hps"); + strcpy(pretty_name, "Harmonic Product Spectrum"); + break; + case FLUX: + strcpy(name, "flux"); + strcpy(pretty_name, "Spectral Flux"); + break; + case ATTACK_TIME: + strcpy(name, "attack_time"); + strcpy(pretty_name, "Attack Time"); + break; + case DECAY_TIME: + strcpy(name, "decay_time"); + strcpy(pretty_name, "Decay Time"); + break; + case DELTA_FEATURE: + strcpy(name, "delta_feature"); + strcpy(pretty_name, "Delta Feature"); + break; + case AUTOCORRELATION_FFT: + strcpy(name, "autocorrelation_fft"); + strcpy(pretty_name, "Autocorrelation (FFT method)"); + break; + case DCT: + strcpy(name, "dct"); + strcpy(pretty_name, "Discrete Cosine Transform"); + break; + case AUTOCORRELATION: + strcpy(name, "autocorrelation"); + strcpy(pretty_name, "Autocorrelation"); + break; + case AMDF: + strcpy(name, "amdf"); + strcpy(pretty_name, "Average Magnitude Difference Function"); + break; + case ASDF: + strcpy(name, "asdf"); + strcpy(pretty_name, "Average Squared Difference Function"); + break; + default: + break; + } + } + + return fd; +} + +int xtract_free_descriptors(void *fd){ + + if (fd != NULL) { + free(fd); + } + + return SUCCESS; +} + + + + + diff --git a/src/libxtract.c b/src/libxtract.c index f729ccf..c8865d5 100644 --- a/src/libxtract.c +++ b/src/libxtract.c @@ -75,7 +75,8 @@ int(*xtract[])(const float *, const int, const void *, float *) = { xtract_harmonics }; -char *xtract_help_strings[] = { + +/*char *xtract_help_strings[] = { "xtract_mean", "xtract_variance", "xtract_standard_deviation", @@ -123,4 +124,4 @@ char *xtract_help_strings[] = { "xtract_mfcc", "xtract_dct", "xtract_harmonics" - }; + }; */ diff --git a/xtract/libxtract.h b/xtract/libxtract.h index 8c0dc40..6f1c08f 100644 --- a/xtract/libxtract.h +++ b/xtract/libxtract.h @@ -129,6 +129,80 @@ enum return_codes_ { FEATURE_NOT_IMPLEMENTED }; +/** \brief Enumeration of data types*/ +typedef enum type_ { + FLOAT, + INT, + MEL_FILTER, +} t_type; + +/** \brief Enumeration of units*/ +typedef enum unit_ { + HERTZ, + DBFS +} t_unit; + +/** \brief Boolean */ +typedef enum { + FALSE, + TRUE +} t_bool; + +/** \brief Enumeration of vector format types*/ +typedef enum vector_ { + MAGNITUDES, + FREQUENCIES, + FREQUENCIES_AND_MAGNITUDES, + BARK_COEFFS, + MEL_COEFFS, + SAMPLES, +} t_vector; + +/** \brief Data structure containing useful information about functions provided by LibXtract. */ +typedef struct _function_descriptor { + + struct { + char name[MAX_NAME_LENGTH]; + char pretty_name[MAX_NAME_LENGTH]; + char description[MAX_DESC_LENGTH]; + char author[MAX_AUTHOR_LENGTH]; + int year; + } algo; + + struct { + t_vector format; + t_unit unit; + } data; + + int n_args; + + struct { + t_type type; + float min[MAXARGS]; + float max[MAXARGS]; + float def[MAXARGS]; + t_unit unit[MAXARGS]; + } argv; + + t_bool is_scalar; + + union { + + struct { + float min; + float max; + t_unit unit; + } scalar; + + struct { + t_vector format; + t_unit unit; + } vector; + + } result; + +} t_function_descriptor; + /** * * \brief An array of pointers to functions that perform the extraction @@ -178,17 +252,11 @@ printf("Mean = %.2f\n", mean); #ifdef XTRACT extern int(*xtract[XTRACT_FEATURES])(const float *data, const int N, const 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 +/** \brief An array of pointers to function descriptors * - * 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. + * Defined in libxtract.c. This is an array of pointers to function descriptors designed to be queried for useful information such as the expected input and output units of a function, or the number of arguments it takes. */ -extern char *xtract_units[XTRACT_FEATURES]; +//extern t_function_descriptor *xtract_help[XTRACT_FEATURES]; #endif @@ -210,7 +278,11 @@ int xtract_init_mfcc(int N, float nyquist, int style, float freq_max, float freq */ int xtract_init_bark(int N, float nyquist, int *band_limits); +/* \brief A function to build an array of function descriptors */ +void *xtract_make_descriptors(); +/* \brief A function to free an array of function descriptors */ +int xtract_free_descriptors(void *fd); /* Free functions */ /** @} */ diff --git a/xtract/xtract_macros.h b/xtract/xtract_macros.h index 8b55d48..ca8d924 100644 --- a/xtract/xtract_macros.h +++ b/xtract/xtract_macros.h @@ -42,7 +42,11 @@ extern "C" { #define VERY_BIG_NUMBER 1e20 #define SR_LIMIT 192000 #define BARK_BANDS 26 - +#define NONE 0 +#define MAXARGS 4 +#define MAX_NAME_LENGTH 64 +#define MAX_AUTHOR_LENGTH 128 +#define MAX_DESC_LENGTH 256 #ifdef __cplusplus } |