From 67b2dbcccacd2a131de91e9e636456f6063868c7 Mon Sep 17 00:00:00 2001 From: Paul Brossier Date: Tue, 9 May 2017 16:03:17 +0200 Subject: [PATCH] src/pitch/pitchyinfast.h: fast version of original yin --- src/pitch/pitchyinfast.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++ src/pitch/pitchyinfast.h | 102 +++++++++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 src/pitch/pitchyinfast.c create mode 100644 src/pitch/pitchyinfast.h diff --git a/src/pitch/pitchyinfast.c b/src/pitch/pitchyinfast.c new file mode 100644 index 00000000..45d312fa --- /dev/null +++ b/src/pitch/pitchyinfast.c @@ -0,0 +1,188 @@ +/* + Copyright (C) 2003-2017 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 . + +*/ + +/* This algorithm was developed by A. de Cheveigné and H. Kawahara and + * published in: + * + * de Cheveigné, A., Kawahara, H. (2002) "YIN, a fundamental frequency + * estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930. + * + * see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html + */ + +#include "aubio_priv.h" +#include "fvec.h" +#include "mathutils.h" +#include "cvec.h" +#include "spectral/fft.h" +#include "pitch/pitchyinfast.h" + +struct _aubio_pitchyinfast_t +{ + fvec_t *yin; + smpl_t tol; + smpl_t confidence; + fvec_t *tmpdata; + fvec_t *sqdiff; + fvec_t *kernel; + fvec_t *samples_fft; + fvec_t *kernel_fft; + aubio_fft_t *fft; +}; + +aubio_pitchyinfast_t * +new_aubio_pitchyinfast (uint_t bufsize) +{ + aubio_pitchyinfast_t *o = AUBIO_NEW (aubio_pitchyinfast_t); + o->yin = new_fvec (bufsize / 2); + o->tmpdata = new_fvec (bufsize); + o->sqdiff = new_fvec (bufsize / 2); + o->kernel = new_fvec (bufsize); + o->samples_fft = new_fvec (bufsize); + o->kernel_fft = new_fvec (bufsize); + o->fft = new_aubio_fft (bufsize); + o->tol = 0.15; + return o; +} + +void +del_aubio_pitchyinfast (aubio_pitchyinfast_t * o) +{ + del_fvec (o->yin); + del_fvec (o->tmpdata); + del_fvec (o->sqdiff); + del_fvec (o->kernel); + del_fvec (o->samples_fft); + del_fvec (o->kernel_fft); + del_aubio_fft (o->fft); + AUBIO_FREE (o); +} + +/* all the above in one */ +void +aubio_pitchyinfast_do (aubio_pitchyinfast_t * o, const fvec_t * input, fvec_t * out) +{ + const smpl_t tol = o->tol; + fvec_t* yin = o->yin; + const uint_t length = yin->length; + uint_t B = o->tmpdata->length; + uint_t W = o->yin->length; // B / 2 + fvec_t tmp_slice, kernel_ptr; + smpl_t *yin_data = yin->data; + uint_t tau; + sint_t period; + smpl_t tmp2 = 0.; + + // compute r_t(0) + r_t+tau(0) + { + fvec_t *squares = o->tmpdata; + fvec_weighted_copy(input, input, squares); +#if 0 + for (tau = 0; tau < W; tau++) { + tmp_slice.data = squares->data + tau; + tmp_slice.length = W; + o->sqdiff->data[tau] = fvec_sum(&tmp_slice); + } +#else + tmp_slice.data = squares->data; + tmp_slice.length = W; + o->sqdiff->data[0] = fvec_sum(&tmp_slice); + for (tau = 1; tau < W; tau++) { + o->sqdiff->data[tau] = o->sqdiff->data[tau-1]; + o->sqdiff->data[tau] -= squares->data[tau-1]; + o->sqdiff->data[tau] += squares->data[W+tau-1]; + } +#endif + fvec_add(o->sqdiff, o->sqdiff->data[0]); + } + // compute r_t(tau) = -2.*ifft(fft(samples)*fft(samples[W-1::-1])) + { + fvec_t *compmul = o->tmpdata; + fvec_t *rt_of_tau = o->samples_fft; + aubio_fft_do_complex(o->fft, input, o->samples_fft); + // build kernel, take a copy of first half of samples + tmp_slice.data = input->data; + tmp_slice.length = W; + kernel_ptr.data = o->kernel->data + 1; + kernel_ptr.length = W; + fvec_copy(&tmp_slice, &kernel_ptr); + // reverse them + fvec_rev(&kernel_ptr); + // compute fft(kernel) + aubio_fft_do_complex(o->fft, o->kernel, o->kernel_fft); + // compute complex product + compmul->data[0] = o->kernel_fft->data[0] * o->samples_fft->data[0]; + for (tau = 1; tau < W; tau++) { + compmul->data[tau] = o->kernel_fft->data[tau] * o->samples_fft->data[tau]; + compmul->data[tau] -= o->kernel_fft->data[B-tau] * o->samples_fft->data[B-tau]; + } + compmul->data[W] = o->kernel_fft->data[W] * o->samples_fft->data[W]; + for (tau = 1; tau < W; tau++) { + compmul->data[B-tau] = o->kernel_fft->data[B-tau] * o->samples_fft->data[tau]; + compmul->data[B-tau] += o->kernel_fft->data[tau] * o->samples_fft->data[B-tau]; + } + // compute inverse fft + aubio_fft_rdo_complex(o->fft, compmul, rt_of_tau); + // compute square difference r_t(tau) = sqdiff - 2 * r_t_tau[W-1:-1] + for (tau = 0; tau < W; tau++) { + yin_data[tau] = o->sqdiff->data[tau] - 2. * rt_of_tau->data[tau+W]; + } + } + + // now build yin and look for first minimum + fvec_set_all(out, 0.); + yin_data[0] = 1.; + for (tau = 1; tau < length; tau++) { + tmp2 += yin_data[tau]; + if (tmp2 != 0) { + yin->data[tau] *= tau / tmp2; + } else { + yin->data[tau] = 1.; + } + period = tau - 3; + if (tau > 4 && (yin_data[period] < tol) && + (yin_data[period] < yin_data[period + 1])) { + out->data[0] = fvec_quadratic_peak_pos (yin, period); + goto beach; + } + } + out->data[0] = fvec_quadratic_peak_pos (yin, fvec_min_elem (yin) ); +beach: + return; +} + +smpl_t +aubio_pitchyinfast_get_confidence (aubio_pitchyinfast_t * o) { + o->confidence = 1. - fvec_min (o->yin); + return o->confidence; +} + +uint_t +aubio_pitchyinfast_set_tolerance (aubio_pitchyinfast_t * o, smpl_t tol) +{ + o->tol = tol; + return 0; +} + +smpl_t +aubio_pitchyinfast_get_tolerance (aubio_pitchyinfast_t * o) +{ + return o->tol; +} diff --git a/src/pitch/pitchyinfast.h b/src/pitch/pitchyinfast.h new file mode 100644 index 00000000..abb81393 --- /dev/null +++ b/src/pitch/pitchyinfast.h @@ -0,0 +1,102 @@ +/* + Copyright (C) 2003-2017 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 + + Pitch detection using YIN algorithm (fast implementation) + + This algorithm was developed by A. de Cheveigne and H. Kawahara and + published in: + + De Cheveigné, A., Kawahara, H. (2002) "YIN, a fundamental frequency + estimator for speech and music", J. Acoust. Soc. Am. 111, 1917-1930. + + This implementation compute the autocorrelation function using time domain + convolution computed in the spectral domain. + + see http://recherche.ircam.fr/equipes/pcm/pub/people/cheveign.html + http://recherche.ircam.fr/equipes/pcm/cheveign/ps/2002_JASA_YIN_proof.pdf + +*/ + +#ifndef AUBIO_PITCHYINFAST_H +#define AUBIO_PITCHYINFAST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** pitch detection object */ +typedef struct _aubio_pitchyinfast_t aubio_pitchyinfast_t; + +/** creation of the pitch detection object + + \param buf_size size of the input buffer to analyse + +*/ +aubio_pitchyinfast_t *new_aubio_pitchyinfast (uint_t buf_size); + +/** deletion of the pitch detection object + + \param o pitch detection object as returned by new_aubio_pitchyin() + +*/ +void del_aubio_pitchyinfast (aubio_pitchyinfast_t * o); + +/** execute pitch detection an input buffer + + \param o pitch detection object as returned by new_aubio_pitchyin() + \param samples_in input signal vector (length as specified at creation time) + \param cands_out pitch period candidates, in samples + +*/ +void aubio_pitchyinfast_do (aubio_pitchyinfast_t * o, const fvec_t * samples_in, fvec_t * cands_out); + + +/** set tolerance parameter for YIN algorithm + + \param o YIN pitch detection object + \param tol tolerance parameter for minima selection [default 0.15] + +*/ +uint_t aubio_pitchyinfast_set_tolerance (aubio_pitchyinfast_t * o, smpl_t tol); + +/** get tolerance parameter for YIN algorithm + + \param o YIN pitch detection object + \return tolerance parameter for minima selection [default 0.15] + +*/ +smpl_t aubio_pitchyinfast_get_tolerance (aubio_pitchyinfast_t * o); + +/** get current confidence of YIN algorithm + + \param o YIN pitch detection object + \return confidence parameter + +*/ +smpl_t aubio_pitchyinfast_get_confidence (aubio_pitchyinfast_t * o); + +#ifdef __cplusplus +} +#endif + +#endif /* AUBIO_PITCHYINFAST_H */ + -- 2.11.0