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 "MonoNote.h" matthiasm@0: #include matthiasm@0: matthiasm@0: #include matthiasm@0: #include matthiasm@0: #include matthiasm@0: matthiasm@0: using std::vector; matthiasm@0: using std::pair; matthiasm@0: Chris@150: MonoNote::MonoNote(bool fixedLag) : Chris@150: m_fixedLag(fixedLag), Chris@150: hmm(m_fixedLag ? 1000 : 0) matthiasm@0: { matthiasm@0: } matthiasm@0: matthiasm@0: MonoNote::~MonoNote() matthiasm@0: { matthiasm@0: } matthiasm@0: matthiasm@0: const vector matthiasm@0: MonoNote::process(const vector > > pitchProb) matthiasm@0: { Chris@146: // Previously, this built up a single matrix of probabilities, by Chris@146: // calling calculateObsProb to get a column for each frame in Chris@146: // pitchProb. Chris@146: // Chris@146: // The number of distinct states depends on MonoNoteParameters, Chris@146: // but the defaults have 3 states per pitch, 3 pitches per MIDI Chris@146: // note, and 69 MIDI notes, giving 681 states per frame. With a Chris@146: // frame step size of 256 at 44100Hz sample rate, a 3-minute song Chris@146: // has about 30K frames leading to a 20 million element Chris@146: // probability matrix. Chris@146: // Chris@146: // Since the matrix is very sparse, we can avoid some of this by Chris@146: // feeding the (sparse implementation of) HMM one column at a Chris@146: // time. Chris@146: Chris@146: vector path; Chris@150: path.reserve(pitchProb.size()); Chris@146: Chris@146: if (!pitchProb.empty()) { Chris@146: Chris@146: hmm.initialise(hmm.calculateObsProb(pitchProb[0])); Chris@146: Chris@146: for (size_t iFrame = 1; iFrame < pitchProb.size(); ++iFrame) Chris@146: { Chris@150: if (m_fixedLag && (int(iFrame) >= hmm.m_fixedLag)) Chris@150: { Chris@150: vector rawPath = hmm.track(); Chris@150: path.push_back(rawPath[0]); Chris@150: } Chris@150: Chris@146: hmm.process(hmm.calculateObsProb(pitchProb[iFrame])); Chris@146: } Chris@146: Chris@150: vector rawPath = hmm.track(); Chris@150: path.insert(path.end(), rawPath.begin(), rawPath.end()); matthiasm@0: } matthiasm@0: Chris@150: vector out; Chris@150: out.reserve(path.size()); Chris@146: matthiasm@0: for (size_t iFrame = 0; iFrame < path.size(); ++iFrame) matthiasm@0: { matthiasm@0: double currPitch = -1; matthiasm@0: int stateKind = 0; matthiasm@0: matthiasm@0: currPitch = hmm.par.minPitch + (path[iFrame]/hmm.par.nSPP) * 1.0/hmm.par.nPPS; matthiasm@0: stateKind = (path[iFrame]) % hmm.par.nSPP + 1; matthiasm@0: matthiasm@0: out.push_back(FrameOutput(iFrame, currPitch, stateKind)); matthiasm@0: } Chris@146: matthiasm@0: return(out); Chris@9: }