Chris@9: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@9: Chris@9: /* Chris@9: pYIN - A fundamental frequency estimator for monophonic audio Chris@9: Centre for Digital Music, Queen Mary, University of London. Chris@9: Chris@9: This program is free software; you can redistribute it and/or Chris@9: modify it under the terms of the GNU General Public License as Chris@9: published by the Free Software Foundation; either version 2 of the Chris@9: License, or (at your option) any later version. See the file Chris@9: COPYING included with this distribution for more information. Chris@9: */ Chris@9: matthiasm@0: #include "MonoPitchHMM.h" matthiasm@0: matthiasm@0: #include matthiasm@0: matthiasm@0: #include matthiasm@0: #include matthiasm@0: matthiasm@0: using std::vector; matthiasm@0: using std::pair; matthiasm@0: matthiasm@0: MonoPitchHMM::MonoPitchHMM() : matthiasm@65: m_minFreq(61.735), // b 1 matthiasm@58: // m_minFreq(110), matthiasm@24: m_nBPS(5), matthiasm@0: m_nPitch(0), matthiasm@0: m_transitionWidth(0), matthiasm@0: m_selfTrans(0.99), matthiasm@0: m_yinTrust(.5), matthiasm@0: m_freqs(0) matthiasm@0: { matthiasm@50: m_transitionWidth = 9*(m_nBPS/2) + 1; matthiasm@65: m_nPitch = 69 * m_nBPS; matthiasm@25: m_freqs = vector(2*m_nPitch); matthiasm@0: for (size_t iPitch = 0; iPitch < m_nPitch; ++iPitch) matthiasm@0: { matthiasm@0: m_freqs[iPitch] = m_minFreq * std::pow(2, iPitch * 1.0 / (12 * m_nBPS)); matthiasm@0: m_freqs[iPitch+m_nPitch] = -m_freqs[iPitch]; matthiasm@0: } matthiasm@0: build(); matthiasm@0: } matthiasm@0: matthiasm@0: const vector matthiasm@0: MonoPitchHMM::calculateObsProb(const vector > pitchProb) matthiasm@0: { matthiasm@0: vector out = vector(2*m_nPitch+1); matthiasm@0: double probYinPitched = 0; matthiasm@0: // BIN THE PITCHES matthiasm@0: for (size_t iPair = 0; iPair < pitchProb.size(); ++iPair) matthiasm@0: { matthiasm@0: double freq = 440. * std::pow(2, (pitchProb[iPair].first - 69)/12); matthiasm@0: if (freq <= m_minFreq) continue; matthiasm@0: double d = 0; matthiasm@0: double oldd = 1000; matthiasm@0: for (size_t iPitch = 0; iPitch < m_nPitch; ++iPitch) matthiasm@0: { matthiasm@0: d = std::abs(freq-m_freqs[iPitch]); matthiasm@0: if (oldd < d && iPitch > 0) matthiasm@0: { matthiasm@0: // previous bin must have been the closest matthiasm@0: out[iPitch-1] = pitchProb[iPair].second; matthiasm@0: probYinPitched += out[iPitch-1]; matthiasm@0: break; matthiasm@0: } matthiasm@0: oldd = d; matthiasm@0: } matthiasm@0: } matthiasm@0: matthiasm@0: double probReallyPitched = m_yinTrust * probYinPitched; matthiasm@58: // std::cerr << probReallyPitched << " " << probYinPitched << std::endl; matthiasm@58: // damn, I forget what this is all about... matthiasm@0: for (size_t iPitch = 0; iPitch < m_nPitch; ++iPitch) matthiasm@0: { matthiasm@0: if (probYinPitched > 0) out[iPitch] *= (probReallyPitched/probYinPitched) ; matthiasm@0: out[iPitch+m_nPitch] = (1 - probReallyPitched) / m_nPitch; matthiasm@0: } matthiasm@0: // out[2*m_nPitch] = m_yinTrust * (1 - probYinPitched); matthiasm@0: return(out); matthiasm@0: } matthiasm@0: matthiasm@0: void matthiasm@0: MonoPitchHMM::build() matthiasm@0: { matthiasm@0: // INITIAL VECTOR matthiasm@25: init = vector(2*m_nPitch, 1.0 / 2*m_nPitch); matthiasm@0: matthiasm@0: // TRANSITIONS matthiasm@0: for (size_t iPitch = 0; iPitch < m_nPitch; ++iPitch) matthiasm@0: { matthiasm@0: int theoreticalMinNextPitch = static_cast(iPitch)-static_cast(m_transitionWidth/2); matthiasm@0: int minNextPitch = iPitch>m_transitionWidth/2 ? iPitch-m_transitionWidth/2 : 0; matthiasm@0: int maxNextPitch = iPitch weights; matthiasm@0: for (size_t i = minNextPitch; i <= maxNextPitch; ++i) matthiasm@0: { matthiasm@0: if (i <= iPitch) matthiasm@0: { matthiasm@0: weights.push_back(i-theoreticalMinNextPitch+1); matthiasm@0: // weights.push_back(i-theoreticalMinNextPitch+1+m_transitionWidth/2); matthiasm@0: } else { matthiasm@0: weights.push_back(iPitch-theoreticalMinNextPitch+1-(i-iPitch)); matthiasm@0: // weights.push_back(iPitch-theoreticalMinNextPitch+1-(i-iPitch)+m_transitionWidth/2); matthiasm@0: } matthiasm@0: weightSum += weights[weights.size()-1]; matthiasm@0: } matthiasm@0: matthiasm@0: // std::cerr << minNextPitch << " " << maxNextPitch << std::endl; matthiasm@0: // TRANSITIONS TO CLOSE PITCH matthiasm@0: for (size_t i = minNextPitch; i <= maxNextPitch; ++i) matthiasm@0: { matthiasm@0: from.push_back(iPitch); matthiasm@0: to.push_back(i); matthiasm@0: transProb.push_back(weights[i-minNextPitch] / weightSum * m_selfTrans); matthiasm@0: matthiasm@0: from.push_back(iPitch); matthiasm@0: to.push_back(i+m_nPitch); matthiasm@0: transProb.push_back(weights[i-minNextPitch] / weightSum * (1-m_selfTrans)); matthiasm@0: matthiasm@0: from.push_back(iPitch+m_nPitch); matthiasm@0: to.push_back(i+m_nPitch); matthiasm@0: transProb.push_back(weights[i-minNextPitch] / weightSum * m_selfTrans); matthiasm@0: // transProb.push_back(weights[i-minNextPitch] / weightSum * 0.5); matthiasm@0: matthiasm@0: from.push_back(iPitch+m_nPitch); matthiasm@0: to.push_back(i); matthiasm@0: transProb.push_back(weights[i-minNextPitch] / weightSum * (1-m_selfTrans)); matthiasm@0: // transProb.push_back(weights[i-minNextPitch] / weightSum * 0.5); matthiasm@0: } matthiasm@0: matthiasm@0: // TRANSITION TO UNVOICED matthiasm@0: // from.push_back(iPitch+m_nPitch); matthiasm@0: // to.push_back(2*m_nPitch); matthiasm@0: // transProb.push_back(1-m_selfTrans); matthiasm@0: matthiasm@0: // TRANSITION FROM UNVOICED TO PITCH matthiasm@25: // from.push_back(2*m_nPitch); matthiasm@25: // to.push_back(iPitch+m_nPitch); matthiasm@25: // transProb.push_back(1.0/m_nPitch); matthiasm@0: } matthiasm@0: // UNVOICED SELFTRANSITION matthiasm@0: // from.push_back(2*m_nPitch); matthiasm@0: // to.push_back(2*m_nPitch); matthiasm@0: // transProb.push_back(m_selfTrans); matthiasm@0: matthiasm@0: // for (size_t i = 0; i < from.size(); ++i) { matthiasm@0: // std::cerr << "P(["<< from[i] << " --> " << to[i] << "]) = " << transProb[i] << std::endl; matthiasm@0: // } matthiasm@0: Chris@9: }