diff options
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | examples/puredata/lpcc-test.pd | 57 | ||||
-rw-r--r-- | examples/puredata/xtract~.c | 10 | ||||
-rw-r--r-- | src/descriptors.c | 64 | ||||
-rw-r--r-- | src/libxtract.c | 4 | ||||
-rw-r--r-- | src/vector.c | 87 | ||||
-rw-r--r-- | xtract/libxtract.h | 9 | ||||
-rw-r--r-- | xtract/xtract_vector.h | 29 |
8 files changed, 255 insertions, 7 deletions
@@ -13,3 +13,5 @@ Check and add return values as appropriate. Make them more sensible! ...do other stuff and eventually... ...optimise! Use the fftw guru interface to create multipurpose global plans from xtract_fft_init() +Add LPC via Schur algorithm +If argv uses an integer, then it should point to a variable of type int. At the moment floats are used to store ints. diff --git a/examples/puredata/lpcc-test.pd b/examples/puredata/lpcc-test.pd new file mode 100644 index 0000000..607e846 --- /dev/null +++ b/examples/puredata/lpcc-test.pd @@ -0,0 +1,57 @@ +#N canvas 356 233 722 300 10; +#X obj 160 170 xtract~ autocorrelation; +#N canvas 0 0 450 300 graph1 0; +#X array lpcc 16 float 5; +#A 0 0 0 -0.827113 -0.827113 -0.827113 -0.485055 0.314974 0.657032 +0.810476 0.396513 0.0440753 -0.630112 -0.9456 -0.887411 -1.12995 0.596854 +; +#X coords 0 16 15 -16 200 140 1; +#X restore 458 97 graph; +#X obj 149 34 noise~; +#N canvas 9 103 450 300 lpc 0; +#X obj 323 25 block~ 32; +#X obj 140 52 inlet~; +#X obj 140 113 xtract~ lpc; +#N canvas 237 125 450 300 lpcc 0; +#X obj 26 130 xtract~ lpcc; +#N canvas 0 0 450 300 graph1 0; +#X array lpc 16 float 5; +#A 0 -1.03207 -1.03207 -1.03207 -21.8757 -21.8757 -21.8757 -21.8757 +-0.391539 -0.391539 -0.391539 -0.391539 0.448536 0.448536 0.448536 +0.448536 0.516603; +#X coords 0 16 15 -16 200 140 1; +#X restore 219 37 graph; +#X obj 23 12 block~ 16; +#X obj 26 51 tabreceive~ lpc; +#X msg 95 107 list 16; +#X obj 24 196 tabsend~ lpcc; +#X obj 95 85 loadbang; +#X connect 0 0 5 0; +#X connect 3 0 0 0; +#X connect 4 0 0 1; +#X connect 6 0 4 0; +#X restore 298 172 pd lpcc; +#X obj 137 220 tabsend~ lpc; +#X obj 139 152 a_blockswap~ 32; +#X connect 1 0 2 0; +#X connect 2 0 5 0; +#X connect 5 0 4 0; +#X restore 160 218 pd lpc; +#X obj 31 52 a_hann 16; +#X obj 31 25 loadbang; +#X obj 98 23 bng 15 250 50 0 empty empty empty 0 -6 0 10 -262144 -1 +-1; +#X obj 156 139 *~; +#X obj 27 -41 block~ 16 4; +#X obj 265 81 *~ 0.4; +#X obj 148 87 *~ 0.1; +#X obj 266 46 osc~ 1000; +#X connect 0 0 3 0; +#X connect 2 0 10 0; +#X connect 4 0 7 0; +#X connect 5 0 4 0; +#X connect 6 0 4 0; +#X connect 7 0 0 0; +#X connect 9 0 7 1; +#X connect 10 0 7 1; +#X connect 11 0 9 0; diff --git a/examples/puredata/xtract~.c b/examples/puredata/xtract~.c index e58aea0..f82aab6 100644 --- a/examples/puredata/xtract~.c +++ b/examples/puredata/xtract~.c @@ -93,7 +93,7 @@ static t_int *xtract_perform_vector(t_int *w) { tmp_in = copybytes(in, N * sizeof(t_float)); tmp_out = getbytes(N * sizeof(t_float)); - if(x->feature == XTRACT_PEAK_SPECTRUM) + if(x->feature == XTRACT_PEAK_SPECTRUM || x->feature == XTRACT_LPC) N >>= 1; return_code = xtract[x->feature](tmp_in, N, x->argv, tmp_out); @@ -239,7 +239,9 @@ static void *xtract_new(t_symbol *me, t_int argc, t_atom *argv) { x->feature == XTRACT_BARK_COEFFICIENTS || x->feature == XTRACT_SPECTRUM || x->feature == XTRACT_PEAK_SPECTRUM || - x->feature == XTRACT_HARMONIC_SPECTRUM) + x->feature == XTRACT_HARMONIC_SPECTRUM || + x->feature == XTRACT_LPC || + x->feature == XTRACT_LPCC) x->feature_type = XTRACT_VECTOR; else if (x->feature == XTRACT_FLUX || x->feature == XTRACT_ATTACK_TIME || @@ -273,8 +275,8 @@ t_int argc, t_atom *argv) { x->argv = getbytes(argc * sizeof(float)); - while(argc--) - ((t_float *)x->argv)[argc] = atom_getfloat(&argv[argc]); + while(argc--) + ((t_float *)x->argv)[argc] = atom_getfloat(&argv[argc]); /* }*/ } diff --git a/src/descriptors.c b/src/descriptors.c index 6b6438e..3c43775 100644 --- a/src/descriptors.c +++ b/src/descriptors.c @@ -137,21 +137,26 @@ void *xtract_make_descriptors(){ case XTRACT_LOWEST_VALUE: case XTRACT_TONALITY: case XTRACT_MFCC: + case XTRACT_LPC: + case XTRACT_LPCC: *argv_min = XTRACT_ANY; *argv_max = XTRACT_ANY; *argv_def = XTRACT_ANY; *argv_unit = XTRACT_ANY; + break; case XTRACT_SPECTRAL_INHARMONICITY: *argv_min = 0.f; *argv_max = XTRACT_SR_UPPER_LIMIT / 2; *argv_def = XTRACT_FUNDAMENTAL_DEFAULT; *argv_unit = XTRACT_HERTZ; + break; case XTRACT_F0: case XTRACT_FAILSAFE_F0: *argv_min = XTRACT_SR_LOWER_LIMIT; *argv_max = XTRACT_SR_UPPER_LIMIT; *argv_def = XTRACT_SR_DEFAULT; *argv_unit = XTRACT_HERTZ; + break; /* argc = 2 */; case XTRACT_ROLLOFF: *argv_min = XTRACT_FFT_BANDS_MIN; @@ -162,6 +167,7 @@ void *xtract_make_descriptors(){ *(argv_max + 1) = 100.f; *(argv_def + 1) = 95.f; *(argv_unit + 1) = XTRACT_PERCENT; + break; case XTRACT_SPECTRUM: *argv_min = XTRACT_SR_LOWER_LIMIT / 2; *argv_max = XTRACT_SR_UPPER_LIMIT / 2; @@ -171,6 +177,7 @@ void *xtract_make_descriptors(){ *(argv_max + 1) = 3 ; *(argv_def + 1) = 0; *(argv_unit + 1) = XTRACT_NONE; + break; case XTRACT_PEAK_SPECTRUM: *argv_min = XTRACT_SR_LOWER_LIMIT / 2; *argv_max = XTRACT_SR_UPPER_LIMIT / 2; @@ -180,6 +187,7 @@ void *xtract_make_descriptors(){ *(argv_max + 1) = 100.f ; *(argv_def + 1) = 10.f ; *(argv_unit + 1) = XTRACT_PERCENT; + break; case XTRACT_HARMONIC_SPECTRUM: *argv_min = 0.f; *argv_max = XTRACT_SR_UPPER_LIMIT / 2; @@ -189,6 +197,7 @@ void *xtract_make_descriptors(){ *(argv_max + 1) = 1.f ; *(argv_def + 1) = .1f ; *(argv_unit + 1) = XTRACT_NONE; + break; case XTRACT_NOISINESS: case XTRACT_SKEWNESS: case XTRACT_KURTOSIS: @@ -203,6 +212,7 @@ void *xtract_make_descriptors(){ *(argv_max + 1) = XTRACT_NONE; *(argv_def + 1) = XTRACT_NONE; *(argv_unit + 1) = XTRACT_NONE; + break; case XTRACT_BARK_COEFFICIENTS: /* BARK_COEFFICIENTS is special because argc = BARK_BANDS */ default: @@ -210,6 +220,7 @@ void *xtract_make_descriptors(){ *argv_max = XTRACT_NONE; *argv_def = XTRACT_NONE; *argv_unit = XTRACT_NONE; + break; } argv_donor = &d->argv.donor[0]; @@ -326,6 +337,12 @@ void *xtract_make_descriptors(){ case XTRACT_MFCC: *data_format = XTRACT_SPECTRAL_MAGNITUDES; break; + case XTRACT_LPC: + *data_format = XTRACT_AUTOCORRELATION_COEFFS; + break; + case XTRACT_LPCC: + *data_format = XTRACT_LPC_COEFFS; + break; case XTRACT_SPECTRAL_INHARMONICITY: case XTRACT_HARMONIC_SPECTRUM: *data_format = XTRACT_SPECTRAL_PEAKS; @@ -414,6 +431,8 @@ void *xtract_make_descriptors(){ case XTRACT_TONALITY: case XTRACT_LOUDNESS: case XTRACT_NONZERO_COUNT: + case XTRACT_LPC: + case XTRACT_LPCC: *data_unit = XTRACT_ANY; break; case XTRACT_SPECTRAL_MEAN: @@ -646,6 +665,25 @@ void *xtract_make_descriptors(){ strcpy(desc, "Extract MFCC from a spectrum"); strcpy(p_desc, "Extract MFCC from an audio spectrum"); strcpy(author, "Rabiner"); + break; + case XTRACT_LPC: + strcpy(name, "lpc"); + strcpy(p_name, "Linear predictive coding coefficients"); + strcpy(desc, "Extract LPC from autocorrelation coefficients"); + strcpy(p_desc, + "Extract LPC from autocorrelation coefficients"); + strcpy(author, + "Rabiner and Juang as implemented by Jutta Degener"); + *year = 1994; + break; + case XTRACT_LPCC: + strcpy(name, "lpcc"); + strcpy(p_name, "Linear predictive coding cepstral coefficients"); + strcpy(desc, "Extract LPC cepstrum from LPC coefficients"); + strcpy(p_desc, + "Extract LPC cepstrum from LPC coefficients"); + strcpy(author, "Rabiner and Juang"); + *year = 1993; break; case XTRACT_BARK_COEFFICIENTS: strcpy(name, "bark_coefficients"); @@ -926,6 +964,10 @@ void *xtract_make_descriptors(){ *argc = 1; *argv_type = XTRACT_MEL_FILTER; break; + case XTRACT_LPCC: + *argc = 1; + *argv_type = XTRACT_INT; + break; case XTRACT_BARK_COEFFICIENTS: *argc = XTRACT_BARK_BANDS; *argv_type = XTRACT_INT; @@ -961,6 +1003,7 @@ void *xtract_make_descriptors(){ case XTRACT_ASDF: case XTRACT_NONZERO_COUNT: case XTRACT_ODD_EVEN_RATIO: + case XTRACT_LPC: default: *argc = 0; break; @@ -1019,6 +1062,8 @@ void *xtract_make_descriptors(){ case XTRACT_SPECTRUM: case XTRACT_AUTOCORRELATION_FFT: case XTRACT_MFCC: + case XTRACT_LPC: + case XTRACT_LPCC: case XTRACT_DCT: case XTRACT_HARMONIC_SPECTRUM: *is_scalar = XTRACT_FALSE; @@ -1077,14 +1122,17 @@ void *xtract_make_descriptors(){ *result_unit = XTRACT_HERTZ; *result_min = 0.f; *result_max = XTRACT_SR_UPPER_LIMIT / 2; + break; case XTRACT_ZCR: *result_unit = XTRACT_HERTZ; *result_min = 0.f; *result_max = XTRACT_ANY; + break; case XTRACT_ODD_EVEN_RATIO: *result_unit = XTRACT_NONE; *result_min = 0.f; *result_max = 1.f; + break; case XTRACT_LOUDNESS: case XTRACT_FLATNESS: case XTRACT_TONALITY: @@ -1093,10 +1141,13 @@ void *xtract_make_descriptors(){ case XTRACT_POWER: case XTRACT_SHARPNESS: case XTRACT_SPECTRAL_SLOPE: + case XTRACT_LPC: + case XTRACT_LPCC: default: *result_unit = XTRACT_UNKNOWN; *result_min = XTRACT_UNKNOWN; *result_max = XTRACT_UNKNOWN; + break; } } else { @@ -1113,18 +1164,31 @@ void *xtract_make_descriptors(){ case XTRACT_DCT: *result_format = XTRACT_ARBITRARY_SERIES; *result_unit = XTRACT_ANY; + break; case XTRACT_BARK_COEFFICIENTS: *result_format = XTRACT_BARK_COEFFS; *result_unit = XTRACT_UNKNOWN; /* FIX: check */ + break; case XTRACT_PEAK_SPECTRUM: case XTRACT_SPECTRUM: case XTRACT_HARMONIC_SPECTRUM: *result_format = XTRACT_SPECTRAL; *result_unit = XTRACT_ANY_AMPLITUDE_HERTZ; + break; case XTRACT_AUTOCORRELATION_FFT: + break; case XTRACT_MFCC: *result_format = XTRACT_MEL_COEFFS; *result_unit = XTRACT_UNKNOWN; /* FIX: check */ + break; + case XTRACT_LPC: + *result_format = XTRACT_LPC_COEFFS; + *result_unit = XTRACT_UNKNOWN; + break; + case XTRACT_LPCC: + *result_format = XTRACT_LPCC_COEFFS; + *result_unit = XTRACT_UNKNOWN; + break; default: break; } diff --git a/src/libxtract.c b/src/libxtract.c index ce946a7..a3ed984 100644 --- a/src/libxtract.c +++ b/src/libxtract.c @@ -79,6 +79,8 @@ int(*xtract[])(const float *, const int, const void *, float *) = { xtract_autocorrelation_fft, xtract_mfcc, xtract_dct, - xtract_harmonic_spectrum + xtract_harmonic_spectrum, + xtract_lpc, + xtract_lpcc }; diff --git a/src/vector.c b/src/vector.c index 0305751..06fc281 100644 --- a/src/vector.c +++ b/src/vector.c @@ -449,3 +449,90 @@ int xtract_harmonic_spectrum(const float *data, const int N, const void *argv, f return XTRACT_SUCCESS; } +int xtract_lpc(const float *data, const int N, const void *argv, float *result){ + + int i, j, k, M, L; + float r = 0.f, + error = 0.f; + + float *ref = NULL, + *lpc = NULL ; + + error = data[0]; + k = N; /* The length of *data */ + L = N - 1; /* The number of LPC coefficients */ + M = L * 2; /* The length of *result */ + ref = result; + lpc = result+L; + + if(error == 0.0){ + for(i = 0; i < M; i++) + result[i] = 0.f; + return XTRACT_NO_RESULT; + } + + memset(result, 0, M * sizeof(float)); + + for (i = 0; i < L; i++) { + + /* Sum up this iteration's reflection coefficient. */ + r = -data[i + 1]; + for (j = 0; j < i; j++) + r -= lpc[j] * data[i - j]; + ref[i] = r /= error; + + /* Update LPC coefficients and total error. */ + lpc[i] = r; + for (j = 0; j < i / 2; j++) { + float tmp = lpc[j]; + lpc[j] = r * lpc[i - 1 - j]; + lpc[i - 1 - j] += r * tmp; + } + if (i % 2) lpc[j] += lpc[j] * r; + + error *= 1 - r * r; + } + + return XTRACT_SUCCESS; +} + +int xtract_lpcc(const float *data, const int N, const void *argv, float *result){ + + /* Given N lpc coefficients extract an LPC cepstrum of size argv[0] */ + /* Based on an an algorithm by rabiner and Juang */ + + int n, k; + float sum; + int order = N - 1; /* Eventually change this to Q = 3/2 p as suggested in Rabiner */ + int cep_length; + + if(argv == NULL) + cep_length = N - 1; + else + cep_length = (int)((float *)argv)[0]; + + memset(result, 0, cep_length * sizeof(float)); + + for (n = 1; n <= order && n <= cep_length; n++){ + sum = 0.f; + for (k = 1; k < n; k++) + sum += k * result[k-1] * data[n - k]; + result[n-1] = data[n] + sum / n; + } + + /* be wary of these interpolated values */ + for(n = order + 1; n <= cep_length; n++){ + sum = 0.f; + for (k = n - (order - 1); k < n; k++) + sum += k * result[k-1] * data[n - k]; + result[n-1] = sum / n; + } + + return XTRACT_SUCCESS; + +} +//int xtract_lpcc_s(const float *data, const int N, const void *argv, float *result){ +// return XTRACT_SUCCESS; +//} + + diff --git a/xtract/libxtract.h b/xtract/libxtract.h index e967372..40512b0 100644 --- a/xtract/libxtract.h +++ b/xtract/libxtract.h @@ -56,7 +56,7 @@ extern "C" { * @{ */ -#define XTRACT_FEATURES 54 +#define XTRACT_FEATURES 56 /** \brief Enumeration of features, elements are used as indixes to an array of pointers to feature extracton functions */ enum xtract_features_ { @@ -113,7 +113,9 @@ enum xtract_features_ { XTRACT_AUTOCORRELATION_FFT, XTRACT_MFCC, XTRACT_DCT, - XTRACT_HARMONIC_SPECTRUM + XTRACT_HARMONIC_SPECTRUM, + XTRACT_LPC, + XTRACT_LPCC }; /** \brief Enumeration of feature initialisation functions */ @@ -198,9 +200,12 @@ typedef enum xtract_vector_ { XTRACT_SPECTRAL_HARMONICS_MAGNITUDES, /* N spectral harmonic frequencies */ XTRACT_SPECTRAL_HARMONICS_FREQUENCIES, + XTRACT_AUTOCORRELATION_COEFFS, XTRACT_ARBITRARY_SERIES, XTRACT_AUDIO_SAMPLES, XTRACT_MEL_COEFFS, + XTRACT_LPC_COEFFS, + XTRACT_LPCC_COEFFS, XTRACT_BARK_COEFFS, XTRACT_NO_DATA } xtract_vector_t; diff --git a/xtract/xtract_vector.h b/xtract/xtract_vector.h index e67ae6d..7effac0 100644 --- a/xtract/xtract_vector.h +++ b/xtract/xtract_vector.h @@ -126,6 +126,35 @@ int xtract_peak_spectrum(const float *data, const int N, const void *argv, float */ int xtract_harmonic_spectrum(const float *data, const int N, const void *argv, float *result); +/** \brief Extract Linear Predictive Coding Coefficients + * + * Based on algorithm in Rabiner and Juang as implemented by Jutta Degener in Dr. Dobb's Journal December, 1994. + * + * Returns N-1 reflection (PARCOR) coefficients and N-1 LPC coefficients via *result + * + * \param *data: N autocorrelation values e.g the data pointed to by *result from xtract_autocorrelation() + * \param N: the number of autocorrelation values to be considered + * \param *argv: a pointer to NULL + * \param *result: a pointer to an array containing N-1 reflection coefficients and N-1 LPC coefficients. + * + * An array of size 2 * (N - 1) must be allocated, and *result must point to its first element. + */ +int xtract_lpc(const float *data, const int N, const void *argv, float *result); + +/** \brief Extract Linear Predictive Coding Cepstral Coefficients + * + * \param *data: a pointer to the first element in an array of LPC coeffiecients e.g. a pointer to the second half of the array pointed to by *result from xtract_lpc() + * \param N: the number of LPC coefficients to be considered + * \param *argv: a pointer to a float representing the order of the result vector. This must be a whole number. According to Rabiner and Juang the ratio between the number (p) of LPC coefficients and the order (Q) of the LPC cepstrum is given by Q ~ (3/2)p where Q > p. + * \param *result: a pointer to an array containing the resultant LPCC. + * + * An array of size Q, where Q is given by argv[0] must be allocated, and *result must point to its first element. + * + */ +int xtract_lpcc(const float *data, const int N, const void *argv, float *result); + + + /** @} */ #ifdef __cplusplus |