Chris@9
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@9
|
2
|
Chris@9
|
3 /*
|
Chris@9
|
4 pYIN - A fundamental frequency estimator for monophonic audio
|
Chris@9
|
5 Centre for Digital Music, Queen Mary, University of London.
|
Chris@9
|
6
|
Chris@9
|
7 This program is free software; you can redistribute it and/or
|
Chris@9
|
8 modify it under the terms of the GNU General Public License as
|
Chris@9
|
9 published by the Free Software Foundation; either version 2 of the
|
Chris@9
|
10 License, or (at your option) any later version. See the file
|
Chris@9
|
11 COPYING included with this distribution for more information.
|
Chris@9
|
12 */
|
Chris@9
|
13
|
matthiasm@0
|
14 #include "SparseHMM.h"
|
matthiasm@0
|
15 #include <vector>
|
matthiasm@0
|
16 #include <cstdio>
|
matthiasm@0
|
17 #include <iostream>
|
matthiasm@0
|
18
|
matthiasm@0
|
19 using std::vector;
|
matthiasm@0
|
20 using std::pair;
|
matthiasm@0
|
21
|
matthiasm@0
|
22 const vector<double>
|
matthiasm@0
|
23 SparseHMM::calculateObsProb(const vector<pair<double, double> > data)
|
matthiasm@0
|
24 {
|
matthiasm@0
|
25 // dummy (virtual?) implementation to be overloaded
|
matthiasm@0
|
26 return(vector<double>());
|
matthiasm@0
|
27 }
|
matthiasm@0
|
28
|
matthiasm@0
|
29 const std::vector<int>
|
matthiasm@0
|
30 SparseHMM::decodeViterbi(std::vector<vector<double> > obsProb,
|
matthiasm@0
|
31 vector<double> *scale)
|
matthiasm@0
|
32 {
|
matthiasm@0
|
33 size_t nState = init.size();
|
matthiasm@0
|
34 size_t nFrame = obsProb.size();
|
matthiasm@0
|
35
|
matthiasm@0
|
36 // check for consistency
|
matthiasm@0
|
37 size_t nTrans = transProb.size();
|
matthiasm@0
|
38
|
matthiasm@0
|
39 // declaring variables
|
matthiasm@0
|
40 std::vector<double> delta = std::vector<double>(nState);
|
matthiasm@0
|
41 std::vector<double> oldDelta = std::vector<double>(nState);
|
matthiasm@0
|
42 vector<vector<int> > psi; // "matrix" of remembered indices of the best transitions
|
matthiasm@0
|
43 vector<int> path = vector<int>(nFrame, nState-1); // the final output path (current assignment arbitrary, makes sense only for Chordino, where nChord-1 is the "no chord" label)
|
matthiasm@0
|
44
|
matthiasm@0
|
45 double deltasum = 0;
|
matthiasm@0
|
46
|
matthiasm@0
|
47 // initialise first frame
|
matthiasm@0
|
48 for (size_t iState = 0; iState < nState; ++iState)
|
matthiasm@0
|
49 {
|
matthiasm@0
|
50 oldDelta[iState] = init[iState] * obsProb[0][iState];
|
matthiasm@0
|
51 // std::cerr << iState << " ----- " << init[iState] << std::endl;
|
matthiasm@0
|
52 deltasum += oldDelta[iState];
|
matthiasm@0
|
53 }
|
matthiasm@0
|
54
|
matthiasm@0
|
55 for (size_t iState = 0; iState < nState; ++iState)
|
matthiasm@0
|
56 {
|
matthiasm@0
|
57 oldDelta[iState] /= deltasum; // normalise (scale)
|
matthiasm@0
|
58 // std::cerr << oldDelta[iState] << std::endl;
|
matthiasm@0
|
59 }
|
matthiasm@0
|
60
|
matthiasm@0
|
61 scale->push_back(1.0/deltasum);
|
matthiasm@0
|
62 psi.push_back(vector<int>(nState,0));
|
matthiasm@0
|
63
|
matthiasm@0
|
64 // rest of forward step
|
matthiasm@0
|
65 for (size_t iFrame = 1; iFrame < nFrame; ++iFrame)
|
matthiasm@0
|
66 {
|
matthiasm@0
|
67 deltasum = 0;
|
matthiasm@0
|
68 psi.push_back(vector<int>(nState,0));
|
matthiasm@0
|
69
|
matthiasm@0
|
70 // calculate best previous state for every current state
|
matthiasm@0
|
71 size_t fromState;
|
matthiasm@0
|
72 size_t toState;
|
matthiasm@0
|
73 double currentTransProb;
|
matthiasm@0
|
74 double currentValue;
|
matthiasm@0
|
75
|
matthiasm@0
|
76 // this is the "sparse" loop
|
matthiasm@0
|
77 for (size_t iTrans = 0; iTrans < nTrans; ++iTrans)
|
matthiasm@0
|
78 {
|
matthiasm@0
|
79 fromState = from[iTrans];
|
matthiasm@0
|
80 toState = to[iTrans];
|
matthiasm@0
|
81 currentTransProb = transProb[iTrans];
|
matthiasm@0
|
82
|
matthiasm@0
|
83 currentValue = oldDelta[fromState] * currentTransProb;
|
matthiasm@0
|
84 if (currentValue > delta[toState])
|
matthiasm@0
|
85 {
|
matthiasm@0
|
86 delta[toState] = currentValue; // will be multiplied by the right obs later!
|
matthiasm@0
|
87 psi[iFrame][toState] = fromState;
|
matthiasm@0
|
88 }
|
matthiasm@0
|
89 }
|
matthiasm@0
|
90
|
matthiasm@0
|
91 for (size_t jState = 0; jState < nState; ++jState)
|
matthiasm@0
|
92 {
|
matthiasm@0
|
93 delta[jState] *= obsProb[iFrame][jState];
|
matthiasm@0
|
94 deltasum += delta[jState];
|
matthiasm@0
|
95 }
|
matthiasm@0
|
96
|
matthiasm@0
|
97 if (deltasum > 0)
|
matthiasm@0
|
98 {
|
matthiasm@0
|
99 for (size_t iState = 0; iState < nState; ++iState)
|
matthiasm@0
|
100 {
|
matthiasm@0
|
101 oldDelta[iState] = delta[iState] / deltasum; // normalise (scale)
|
matthiasm@0
|
102 delta[iState] = 0;
|
matthiasm@0
|
103 }
|
matthiasm@0
|
104 scale->push_back(1.0/deltasum);
|
matthiasm@0
|
105 } else
|
matthiasm@0
|
106 {
|
matthiasm@27
|
107 std::cerr << "WARNING: Viterbi has been fed some zero probabilities, at least they become zero at frame " << iFrame << " in combination with the model." << std::endl;
|
matthiasm@0
|
108 for (size_t iState = 0; iState < nState; ++iState)
|
matthiasm@0
|
109 {
|
matthiasm@0
|
110 oldDelta[iState] = 1.0/nState;
|
matthiasm@0
|
111 delta[iState] = 0;
|
matthiasm@0
|
112 }
|
matthiasm@0
|
113 scale->push_back(1.0);
|
matthiasm@0
|
114 }
|
matthiasm@0
|
115 }
|
matthiasm@0
|
116
|
matthiasm@0
|
117 // initialise backward step
|
matthiasm@0
|
118 double bestValue = 0;
|
matthiasm@0
|
119 for (size_t iState = 0; iState < nState; ++iState)
|
matthiasm@0
|
120 {
|
matthiasm@0
|
121 double currentValue = oldDelta[iState];
|
matthiasm@0
|
122 if (currentValue > bestValue)
|
matthiasm@0
|
123 {
|
matthiasm@0
|
124 bestValue = currentValue;
|
matthiasm@0
|
125 path[nFrame-1] = iState;
|
matthiasm@0
|
126 }
|
matthiasm@0
|
127 }
|
matthiasm@0
|
128
|
matthiasm@0
|
129 // rest of backward step
|
matthiasm@0
|
130 for (int iFrame = nFrame-2; iFrame != -1; --iFrame)
|
matthiasm@0
|
131 {
|
matthiasm@0
|
132 path[iFrame] = psi[iFrame+1][path[iFrame+1]];
|
matthiasm@0
|
133 }
|
matthiasm@0
|
134
|
matthiasm@27
|
135 // for (size_t iState = 0; iState < nState; ++iState)
|
matthiasm@27
|
136 // {
|
matthiasm@27
|
137 // // std::cerr << psi[2][iState] << std::endl;
|
matthiasm@27
|
138 // }
|
matthiasm@0
|
139
|
matthiasm@0
|
140 return path;
|
matthiasm@0
|
141 }
|