From 1651b58b304306342c74fbf5e60e994f5b17f27b Mon Sep 17 00:00:00 2001 From: Paul Brossier Date: Wed, 4 Nov 2009 22:24:06 +0100 Subject: [PATCH] src/spectral/: added statistics.c, containing some cuidado spectral shape descriptors --- src/Makefile.am | 5 +- src/aubio.h | 1 - src/spectral/specdesc.c | 149 +++++++++-------------- src/spectral/spectral_centroid.c | 38 ------ src/spectral/spectral_centroid.h | 41 ------- src/spectral/statistics.c | 198 +++++++++++++++++++++++++++++++ 6 files changed, 259 insertions(+), 173 deletions(-) delete mode 100644 src/spectral/spectral_centroid.c delete mode 100644 src/spectral/spectral_centroid.h create mode 100644 src/spectral/statistics.c diff --git a/src/Makefile.am b/src/Makefile.am index 931557e5..7baa35dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,6 @@ nobase_pkginclude_HEADERS = \ spectral/fft.h \ spectral/tss.h \ spectral/specdesc.h \ - spectral/spectral_centroid.h \ pitch/pitch.h \ pitch/pitchmcomb.h \ pitch/pitchyin.h \ @@ -57,7 +56,8 @@ libaubio_la_SOURCES = \ spectral/phasevoc.c \ spectral/fft.c \ spectral/tss.c \ - spectral/spectral_centroid.c \ + spectral/specdesc.c \ + spectral/statistics.c \ pitch/pitch.c \ pitch/pitchmcomb.c \ pitch/pitchyin.c \ @@ -65,7 +65,6 @@ libaubio_la_SOURCES = \ pitch/pitchfcomb.c \ pitch/pitchyinfft.c \ onset/onset.c \ - onset/onsetdetection.c \ onset/peakpick.c \ tempo/tempo.c \ tempo/beattracking.c diff --git a/src/aubio.h b/src/aubio.h index 6008ad4e..15c2ad36 100644 --- a/src/aubio.h +++ b/src/aubio.h @@ -183,7 +183,6 @@ extern "C" #include "pitch/pitchyinfft.h" #include "pitch/pitchschmitt.h" #include "pitch/pitchfcomb.h" -#include "spectral/spectral_centroid.h" #include "onset/peakpick.h" #include "tempo/beattracking.h" #endif diff --git a/src/spectral/specdesc.c b/src/spectral/specdesc.c index 684a16cd..838188e4 100644 --- a/src/spectral/specdesc.c +++ b/src/spectral/specdesc.c @@ -26,104 +26,30 @@ #include "mathutils.h" #include "utils/hist.h" -/** Energy based onset detection function - - This function calculates the local energy of the input spectral frame. - - \param o onset detection object as returned by new_aubio_specdesc() - \param fftgrain input spectral frame - \param onset output onset detection function - -*/ void aubio_specdesc_energy(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset); -/** High Frequency Content onset detection function - - This method computes the High Frequency Content (HFC) of the input spectral - frame. The resulting function is efficient at detecting percussive onsets. - - Paul Masri. Computer modeling of Sound for Transformation and Synthesis of - Musical Signal. PhD dissertation, University of Bristol, UK, 1996. - - \param o onset detection object as returned by new_aubio_specdesc() - \param fftgrain input spectral frame - \param onset output onset detection function - -*/ void aubio_specdesc_hfc(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset); -/** Complex Domain Method onset detection function - - Christopher Duxbury, Mike E. Davies, and Mark B. Sandler. Complex domain - onset detection for musical signals. In Proceedings of the Digital Audio - Effects Conference, DAFx-03, pages 90-93, London, UK, 2003. - - \param o onset detection object as returned by new_aubio_specdesc() - \param fftgrain input spectral frame - \param onset output onset detection function - -*/ void aubio_specdesc_complex(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset); -/** Phase Based Method onset detection function - - Juan-Pablo Bello, Mike P. Davies, and Mark B. Sandler. Phase-based note onset - detection for music signals. In Proceedings of the IEEE International - Conference on Acoustics Speech and Signal Processing, pages 441­444, - Hong-Kong, 2003. - - \param o onset detection object as returned by new_aubio_specdesc() - \param fftgrain input spectral frame - \param onset output onset detection function - -*/ void aubio_specdesc_phase(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset); -/** Spectral difference method onset detection function - - Jonhatan Foote and Shingo Uchihashi. The beat spectrum: a new approach to - rhythm analysis. In IEEE International Conference on Multimedia and Expo - (ICME 2001), pages 881­884, Tokyo, Japan, August 2001. - - \param o onset detection object as returned by new_aubio_specdesc() - \param fftgrain input spectral frame - \param onset output onset detection function - -*/ void aubio_specdesc_specdiff(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset); -/** Kullback-Liebler onset detection function - - Stephen Hainsworth and Malcom Macleod. Onset detection in music audio - signals. In Proceedings of the International Computer Music Conference - (ICMC), Singapore, 2003. - - \param o onset detection object as returned by new_aubio_specdesc() - \param fftgrain input spectral frame - \param onset output onset detection function - -*/ void aubio_specdesc_kl(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset); -/** Modified Kullback-Liebler onset detection function - - Paul Brossier, ``Automatic annotation of musical audio for interactive - systems'', Chapter 2, Temporal segmentation, PhD thesis, Centre for Digital - music, Queen Mary University of London, London, UK, 2006. - - \param o onset detection object as returned by new_aubio_specdesc() - \param fftgrain input spectral frame - \param onset output onset detection function - -*/ void aubio_specdesc_mkl(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset); -/** Spectral Flux - - Simon Dixon, Onset Detection Revisited, in ``Proceedings of the 9th - International Conference on Digital Audio Effects'' (DAFx-06), Montreal, - Canada, 2006. - - \param o onset detection object as returned by new_aubio_specdesc() - \param fftgrain input spectral frame - \param onset output onset detection function - -*/ void aubio_specdesc_specflux(aubio_specdesc_t *o, cvec_t * fftgrain, fvec_t * onset); +extern void aubio_specdesc_centroid (aubio_specdesc_t * o, cvec_t * spec, + fvec_t * desc); +extern void aubio_specdesc_spread (aubio_specdesc_t * o, cvec_t * spec, + fvec_t * desc); +extern void aubio_specdesc_skewness (aubio_specdesc_t * o, cvec_t * spec, + fvec_t * desc); +extern void aubio_specdesc_kurtosis (aubio_specdesc_t * o, cvec_t * spec, + fvec_t * desc); +extern void aubio_specdesc_slope (aubio_specdesc_t * o, cvec_t * spec, + fvec_t * desc); +extern void aubio_specdesc_decrease (aubio_specdesc_t * o, cvec_t * spec, + fvec_t * desc); +extern void aubio_specdesc_rolloff (aubio_specdesc_t * o, cvec_t * spec, + fvec_t * desc); + /** onsetdetection types */ typedef enum { aubio_onset_energy, /**< energy based */ @@ -134,6 +60,13 @@ typedef enum { aubio_onset_kl, /**< Kullback Liebler */ aubio_onset_mkl, /**< modified Kullback Liebler */ aubio_onset_specflux, /**< spectral flux */ + aubio_specmethod_centroid, /**< spectral centroid */ + aubio_specmethod_spread, /**< spectral spread */ + aubio_specmethod_skewness, /**< spectral skewness */ + aubio_specmethod_kurtosis, /**< spectral kurtosis */ + aubio_specmethod_slope, /**< spectral kurtosis */ + aubio_specmethod_decrease, /**< spectral decrease */ + aubio_specmethod_rolloff, /**< spectral rolloff */ aubio_onset_default = aubio_onset_hfc, /**< default mode, set to hfc */ } aubio_specdesc_type; @@ -341,10 +274,24 @@ new_aubio_specdesc (char_t * onset_mode, onset_type = aubio_onset_kl; else if (strcmp (onset_mode, "specflux") == 0) onset_type = aubio_onset_specflux; + else if (strcmp (onset_mode, "centroid") == 0) + onset_type = aubio_specmethod_centroid; + else if (strcmp (onset_mode, "spread") == 0) + onset_type = aubio_specmethod_spread; + else if (strcmp (onset_mode, "skewness") == 0) + onset_type = aubio_specmethod_skewness; + else if (strcmp (onset_mode, "kurtosis") == 0) + onset_type = aubio_specmethod_kurtosis; + else if (strcmp (onset_mode, "slope") == 0) + onset_type = aubio_specmethod_slope; + else if (strcmp (onset_mode, "decrease") == 0) + onset_type = aubio_specmethod_decrease; + else if (strcmp (onset_mode, "rolloff") == 0) + onset_type = aubio_specmethod_rolloff; else if (strcmp (onset_mode, "default") == 0) onset_type = aubio_onset_default; else { - AUBIO_ERR("unknown onset type.\n"); + AUBIO_ERR("unknown spectral descriptor type %s.\n", onset_mode); onset_type = aubio_onset_default; } switch(onset_type) { @@ -411,6 +358,28 @@ new_aubio_specdesc (char_t * onset_mode, case aubio_onset_specflux: o->funcpointer = aubio_specdesc_specflux; break; + // for for the additional descriptors. these don't need additional memory + case aubio_specmethod_centroid: + o->funcpointer = aubio_specdesc_centroid; + break; + case aubio_specmethod_spread: + o->funcpointer = aubio_specdesc_spread; + break; + case aubio_specmethod_skewness: + o->funcpointer = aubio_specdesc_skewness; + break; + case aubio_specmethod_kurtosis: + o->funcpointer = aubio_specdesc_kurtosis; + break; + case aubio_specmethod_slope: + o->funcpointer = aubio_specdesc_slope; + break; + case aubio_specmethod_decrease: + o->funcpointer = aubio_specdesc_decrease; + break; + case aubio_specmethod_rolloff: + o->funcpointer = aubio_specdesc_rolloff; + break; default: break; } diff --git a/src/spectral/spectral_centroid.c b/src/spectral/spectral_centroid.c deleted file mode 100644 index a9227c94..00000000 --- a/src/spectral/spectral_centroid.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (C) 2007-2009 Paul Brossier - - This file is part of aubio. - - aubio 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 3 of the License, or - (at your option) any later version. - - aubio 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 aubio. If not, see . - -*/ - -#include "aubio_priv.h" -#include "cvec.h" -#include "spectral/spectral_centroid.h" - -smpl_t aubio_spectral_centroid(cvec_t * spectrum, smpl_t samplerate) { - uint_t i=0, j; - smpl_t sum = 0., sc = 0.; - for ( j = 0; j < spectrum->length; j++ ) { - sum += spectrum->norm[i][j]; - } - if (sum == 0.) return 0.; - for ( j = 0; j < spectrum->length; j++ ) { - sc += (smpl_t)j * spectrum->norm[i][j]; - } - return sc / sum * samplerate / (smpl_t)(spectrum->length); -} - - diff --git a/src/spectral/spectral_centroid.h b/src/spectral/spectral_centroid.h deleted file mode 100644 index a841c1fc..00000000 --- a/src/spectral/spectral_centroid.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - Copyright (C) 2007-2009 Paul Brossier - - This file is part of aubio. - - aubio 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 3 of the License, or - (at your option) any later version. - - aubio 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 aubio. If not, see . - -*/ - -/** @file - * compute spectrum centroid of a cvec object - */ - -#ifndef _SPECTRAL_CENTROID_H -#define _SPECTRAL_CENTROID_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * spectrum centroid computed on a cvec - */ -smpl_t aubio_spectral_centroid(cvec_t * input, smpl_t samplerate); - -#ifdef __cplusplus -} -#endif - -#endif /* _SPECTRAL_CENTROID_H */ diff --git a/src/spectral/statistics.c b/src/spectral/statistics.c new file mode 100644 index 00000000..93150509 --- /dev/null +++ b/src/spectral/statistics.c @@ -0,0 +1,198 @@ +/* + Copyright (C) 2007-2009 Paul Brossier + + This file is part of aubio. + + aubio 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 3 of the License, or + (at your option) any later version. + + aubio 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 aubio. If not, see . + +*/ + +#include "aubio_priv.h" +#include "cvec.h" +#include "spectral/specdesc.h" + +smpl_t +cvec_sum_channel (cvec_t * s, uint_t i) +{ + uint_t j; + smpl_t tmp = 0.0; + for (j = 0; j < s->length; j++) + tmp += s->norm[i][j]; + return tmp; +} + +smpl_t +cvec_mean_channel (cvec_t * s, uint_t i) +{ + return cvec_sum_channel(s, i) / (smpl_t) (s->length); +} + +smpl_t +cvec_centroid_channel (cvec_t * spec, uint_t i) +{ + smpl_t sum = 0., sc = 0.; + uint_t j; + sum = cvec_sum_channel (spec, i); + if (sum == 0.) { + return 0.; + } else { + for (j = 0; j < spec->length; j++) { + sc += (smpl_t) j *spec->norm[i][j]; + } + return sc / sum; + } +} + +smpl_t +cvec_moment_channel (cvec_t * spec, uint_t i, uint_t order) +{ + smpl_t sum = 0., centroid = 0., sc = 0.; + uint_t j; + sum = cvec_sum_channel (spec, i); + if (sum == 0.) { + return 0.; + } else { + centroid = cvec_centroid_channel (spec, i); + for (j = 0; j < spec->length; j++) { + sc += (smpl_t) POW(j - centroid, order) * spec->norm[i][j]; + } + return sc / sum; + } +} + +void +aubio_specdesc_centroid (aubio_specdesc_t * o UNUSED, cvec_t * spec, + fvec_t * desc) +{ + uint_t i; + for (i = 0; i < spec->channels; i++) { + desc->data[i][0] = cvec_centroid_channel (spec, i); + } +} + +void +aubio_specdesc_spread (aubio_specdesc_t * o UNUSED, cvec_t * spec, + fvec_t * desc) +{ + uint_t i; + for (i = 0; i < spec->channels; i++) { + desc->data[i][0] = cvec_moment_channel (spec, i, 2); + } +} + +void +aubio_specdesc_skewness (aubio_specdesc_t * o UNUSED, cvec_t * spec, + fvec_t * desc) +{ + uint_t i; smpl_t spread; + for (i = 0; i < spec->channels; i++) { + spread = cvec_moment_channel (spec, i, 2); + if (spread == 0) { + desc->data[i][0] = 0.; + } else { + desc->data[i][0] = cvec_moment_channel (spec, i, 3); + desc->data[i][0] /= POW ( SQRT (spread), 3); + } + } +} + +void +aubio_specdesc_kurtosis (aubio_specdesc_t * o UNUSED, cvec_t * spec, + fvec_t * desc) +{ + uint_t i; smpl_t spread; + for (i = 0; i < spec->channels; i++) { + spread = cvec_moment_channel (spec, i, 2); + if (spread == 0) { + desc->data[i][0] = 0.; + } else { + desc->data[i][0] = cvec_moment_channel (spec, i, 4); + desc->data[i][0] /= SQR (spread); + } + } +} + +void +aubio_specdesc_slope (aubio_specdesc_t * o UNUSED, cvec_t * spec, + fvec_t * desc) +{ + uint_t i, j; + smpl_t norm = 0, sum = 0.; + // compute N * sum(j**2) - sum(j)**2 + for (j = 0; j < spec->length; j++) { + norm += j*j; + } + norm *= spec->length; + // sum_0^N(j) = length * (length + 1) / 2 + norm -= SQR( (spec->length) * (spec->length - 1.) / 2. ); + for (i = 0; i < spec->channels; i++) { + sum = cvec_sum_channel (spec, i); + desc->data[i][0] = 0.; + if (sum == 0.) { + break; + } else { + for (j = 0; j < spec->length; j++) { + desc->data[i][0] += j * spec->norm[i][j]; + } + desc->data[i][0] *= spec->length; + desc->data[i][0] -= sum * spec->length * (spec->length - 1) / 2.; + desc->data[i][0] /= norm; + desc->data[i][0] /= sum; + } + } +} + +void +aubio_specdesc_decrease (aubio_specdesc_t *o UNUSED, cvec_t * spec, + fvec_t * desc) +{ + uint_t i, j; smpl_t sum; + for (i = 0; i < spec->channels; i++) { + sum = cvec_sum_channel (spec, i); + desc->data[i][0] = 0; + if (sum == 0.) { + break; + } else { + sum -= spec->norm[i][0]; + for (j = 1; j < spec->length; j++) { + desc->data[i][0] += (spec->norm[i][j] - spec->norm[i][0]) / j; + } + desc->data[i][0] /= sum; + } + } +} + +void +aubio_specdesc_rolloff (aubio_specdesc_t *o UNUSED, cvec_t * spec, + fvec_t *desc) +{ + uint_t i, j; smpl_t cumsum, rollsum; + for (i = 0; i < spec->channels; i++) { + cumsum = 0.; rollsum = 0.; + for (j = 0; j < spec->length; j++) { + cumsum += SQR (spec->norm[i][j]); + } + if (cumsum == 0) { + desc->data[i][0] = 0.; + } else { + cumsum *= 0.95; + j = 0; + while (rollsum < cumsum) { + rollsum += SQR (spec->norm[i][j]); + j++; + } + desc->data[i][0] = j; + } + } +} -- 2.26.2