diff options
Diffstat (limited to 'src/lingot-yin.c')
| -rw-r--r-- | src/lingot-yin.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/lingot-yin.c b/src/lingot-yin.c new file mode 100644 index 0000000..617f625 --- /dev/null +++ b/src/lingot-yin.c @@ -0,0 +1,74 @@ +//-*- C++ -*- +/* + * YIN pitch estimator + * Copyright (C) 2008 Piotr Pawlow <pp@siedziba.pl> + * + * This file is part of lingot. + * + * lingot 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. + * + * lingot 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 lingot; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Implementation of YIN algorithm, published in: + * + * A. de Cheveigne and H. Kawahara: YIN, an F0 estimator + * J. Acoust. Soc. Am., Vol. 111, No. 4, April 2002 + * http://www.ircam.fr/pcm/cheveign/pss/2002_JASA_YIN.pdf + */ + +#include "lingot-yin.h" + +inline FLT yin_sqr(FLT x) +{ + return x*x; +} + +inline FLT yin_interpolate_tau(FLT y1, FLT y2, FLT y3) +{ + return ((y1 - y3)/(2.0*(y3 + y1 - (2.0*y2)))); +} + +FLT yin(LingotCore* core) { + FLT dt_tau; + FLT dt_tau_sum = 0; + FLT dpt_right = 1.0/0.0, dpt_center, dpt_left; + FLT thr = core->conf->yin_threshold; + FLT dpt_min = 1.0/0.0; + FLT dpt_min_left, dpt_min_right; + int j, tau, tau_min; + int len = core->conf->temporal_buffer_size / 2; + + for (tau = 1; (tau < len) && ((dpt_center > thr) || (dpt_right < dpt_center) || (tau <= 2)); tau++) + { + dt_tau = 0; + for (j = 0; j < len ; j++) + { + dt_tau += yin_sqr(core->temporal_buffer[j] - core->temporal_buffer[j+tau]); + } + dt_tau_sum += dt_tau; + + dpt_left = dpt_center; + dpt_center = dpt_right; + dpt_right = dt_tau / ( 1.0 / tau * dt_tau_sum ); + + if (dpt_center < dpt_min) + { + dpt_min_left = dpt_left; + dpt_min = dpt_center; + dpt_min_right = dpt_right; + tau_min = tau - 1; + } + } + return (FLT)tau_min + yin_interpolate_tau(dpt_left, dpt_center, dpt_right); +} |
