Revision 35:2f5b169e4a3b CepstralPitchTracker.cpp

View differences:

CepstralPitchTracker.cpp
37 37
using std::vector;
38 38
using Vamp::RealTime;
39 39

  
40
CepstralPitchTracker::Hypothesis::Hypothesis()
41
{
42
    m_state = New;
43
}
44

  
45
CepstralPitchTracker::Hypothesis::~Hypothesis()
46
{
47
}
48

  
49
bool
50
CepstralPitchTracker::Hypothesis::isWithinTolerance(Estimate s) const
51
{
52
    if (m_pending.empty()) {
53
        return true;
54
    }
55

  
56
    // check we are within a relatively close tolerance of the last
57
    // candidate
58
    Estimate last = m_pending[m_pending.size()-1];
59
    double r = s.freq / last.freq;
60
    int cents = lrint(1200.0 * (log(r) / log(2.0)));
61
    if (cents < -60 || cents > 60) return false;
62

  
63
    // and within a slightly bigger tolerance of the current mean
64
    double meanFreq = getMeanFrequency();
65
    r = s.freq / meanFreq;
66
    cents = lrint(1200.0 * (log(r) / log(2.0)));
67
    if (cents < -80 || cents > 80) return false;
68
    
69
    return true;
70
}
71

  
72
bool
73
CepstralPitchTracker::Hypothesis::isOutOfDateFor(Estimate s) const
74
{
75
    if (m_pending.empty()) return false;
76

  
77
    return ((s.time - m_pending[m_pending.size()-1].time) > 
78
            RealTime::fromMilliseconds(40));
79
}
80

  
81
bool 
82
CepstralPitchTracker::Hypothesis::isSatisfied() const
83
{
84
    if (m_pending.empty()) return false;
85
    
86
    double meanConfidence = 0.0;
87
    for (int i = 0; i < m_pending.size(); ++i) {
88
        meanConfidence += m_pending[i].confidence;
89
    }
90
    meanConfidence /= m_pending.size();
91

  
92
    int lengthRequired = 10000;
93
    if (meanConfidence > 0.0) {
94
        lengthRequired = int(2.0 / meanConfidence + 0.5);
95
    }
96

  
97
    return (m_pending.size() > lengthRequired);
98
}
99

  
100
bool
101
CepstralPitchTracker::Hypothesis::accept(Estimate s)
102
{
103
    bool accept = false;
104

  
105
    switch (m_state) {
106

  
107
    case New:
108
        m_state = Provisional;
109
        accept = true;
110
        break;
111

  
112
    case Provisional:
113
        if (isOutOfDateFor(s)) {
114
            m_state = Rejected;
115
        } else if (isWithinTolerance(s)) {
116
            accept = true;
117
        }
118
        break;
119
        
120
    case Satisfied:
121
        if (isOutOfDateFor(s)) {
122
            m_state = Expired;
123
        } else if (isWithinTolerance(s)) {
124
            accept = true;
125
        }
126
        break;
127

  
128
    case Rejected:
129
        break;
130

  
131
    case Expired:
132
        break;
133
    }
134

  
135
    if (accept) {
136
        m_pending.push_back(s);
137
        if (m_state == Provisional && isSatisfied()) {
138
            m_state = Satisfied;
139
        }
140
    }
141

  
142
    return accept;
143
}        
144

  
145
CepstralPitchTracker::Hypothesis::State
146
CepstralPitchTracker::Hypothesis::getState() const
147
{
148
    return m_state;
149
}
150

  
151
CepstralPitchTracker::Hypothesis::Estimates
152
CepstralPitchTracker::Hypothesis::getAcceptedEstimates() const
153
{
154
    if (m_state == Satisfied || m_state == Expired) {
155
        return m_pending;
156
    } else {
157
        return Estimates();
158
    }
159
}
160

  
161
double
162
CepstralPitchTracker::Hypothesis::getMeanFrequency() const
163
{
164
    double acc = 0.0;
165
    for (int i = 0; i < m_pending.size(); ++i) {
166
        acc += m_pending[i].freq;
167
    }
168
    acc /= m_pending.size();
169
    return acc;
170
}
171

  
172
CepstralPitchTracker::Hypothesis::Note
173
CepstralPitchTracker::Hypothesis::getAveragedNote() const
174
{
175
    Note n;
176

  
177
    if (!(m_state == Satisfied || m_state == Expired)) {
178
        n.freq = 0.0;
179
        n.time = RealTime::zeroTime;
180
        n.duration = RealTime::zeroTime;
181
        return n;
182
    }
183

  
184
    n.time = m_pending.begin()->time;
185

  
186
    Estimates::const_iterator i = m_pending.end();
187
    --i;
188
    n.duration = i->time - n.time;
189

  
190
    // just mean frequency for now, but this isn't at all right perceptually
191
    n.freq = getMeanFrequency();
192
    
193
    return n;
194
}
195 40

  
196 41
CepstralPitchTracker::CepstralPitchTracker(float inputSampleRate) :
197 42
    Plugin(inputSampleRate),
......
320 165
{
321 166
    OutputList outputs;
322 167

  
323
    int n = 0;
324

  
325 168
    OutputDescriptor d;
326 169

  
327 170
    d.identifier = "f0";
......
391 234
}
392 235

  
393 236
void
394
CepstralPitchTracker::addFeaturesFrom(Hypothesis h, FeatureSet &fs)
237
CepstralPitchTracker::addFeaturesFrom(NoteHypothesis h, FeatureSet &fs)
395 238
{
396
    Hypothesis::Estimates es = h.getAcceptedEstimates();
239
    NoteHypothesis::Estimates es = h.getAcceptedEstimates();
397 240

  
398
    for (int i = 0; i < es.size(); ++i) {
241
    for (int i = 0; i < (int)es.size(); ++i) {
399 242
	Feature f;
400 243
	f.hasTimestamp = true;
401 244
	f.timestamp = es[i].time;
......
406 249
    Feature nf;
407 250
    nf.hasTimestamp = true;
408 251
    nf.hasDuration = true;
409
    Hypothesis::Note n = h.getAveragedNote();
252
    NoteHypothesis::Note n = h.getAveragedNote();
410 253
    nf.timestamp = n.time;
411 254
    nf.duration = n.duration;
412 255
    nf.values.push_back(n.freq);
......
422 265
        // average according to the vertical filter length
423 266
        for (int j = -m_vflen/2; j <= m_vflen/2; ++j) {
424 267
            int ix = i + m_binFrom + j;
425
            if (ix >= 0 && ix < m_blockSize) {
268
            if (ix >= 0 && ix < (int)m_blockSize) {
426 269
                v += cep[ix];
427 270
                ++n;
428 271
            }
......
575 418
        std::cerr << "magmean = " << magmean << ", confidence = " << confidence << std::endl;
576 419
    }
577 420

  
578
    Hypothesis::Estimate e;
421
    NoteHypothesis::Estimate e;
579 422
    e.freq = peakfreq;
580 423
    e.time = timestamp;
581 424
    e.confidence = confidence;
582 425

  
583
//    m_good.advanceTime();
584
    for (int i = 0; i < m_possible.size(); ++i) {
585
//        m_possible[i].advanceTime();
586
    }
587

  
588 426
    if (!m_good.accept(e)) {
589 427

  
590 428
        int candidate = -1;
591 429
        bool accepted = false;
592 430

  
593
        for (int i = 0; i < m_possible.size(); ++i) {
431
        for (int i = 0; i < (int)m_possible.size(); ++i) {
594 432
            if (m_possible[i].accept(e)) {
595
                if (m_possible[i].getState() == Hypothesis::Satisfied) {
433
                if (m_possible[i].getState() == NoteHypothesis::Satisfied) {
596 434
                    accepted = true;
597 435
                    candidate = i;
598 436
                }
......
601 439
        }
602 440

  
603 441
        if (!accepted) {
604
            Hypothesis h;
442
            NoteHypothesis h;
605 443
            h.accept(e); //!!! must succeed as h is new, so perhaps there should be a ctor for this
606 444
            m_possible.push_back(h);
607 445
        }
608 446

  
609
        if (m_good.getState() == Hypothesis::Expired) {
447
        if (m_good.getState() == NoteHypothesis::Expired) {
610 448
            addFeaturesFrom(m_good, fs);
611 449
        }
612 450
        
613
        if (m_good.getState() == Hypothesis::Expired ||
614
            m_good.getState() == Hypothesis::Rejected) {
451
        if (m_good.getState() == NoteHypothesis::Expired ||
452
            m_good.getState() == NoteHypothesis::Rejected) {
615 453
            if (candidate >= 0) {
616 454
                m_good = m_possible[candidate];
617 455
            } else {
618
                m_good = Hypothesis();
456
                m_good = NoteHypothesis();
619 457
            }
620 458
        }
621 459

  
622 460
        // reap rejected/expired hypotheses from possible list
623 461
        Hypotheses toReap = m_possible;
624 462
        m_possible.clear();
625
        for (int i = 0; i < toReap.size(); ++i) {
626
            Hypothesis h = toReap[i];
627
            if (h.getState() != Hypothesis::Rejected && 
628
                h.getState() != Hypothesis::Expired) {
463
        for (int i = 0; i < (int)toReap.size(); ++i) {
464
            NoteHypothesis h = toReap[i];
465
            if (h.getState() != NoteHypothesis::Rejected && 
466
                h.getState() != NoteHypothesis::Expired) {
629 467
                m_possible.push_back(h);
630 468
            }
631 469
        }
......
639 477
CepstralPitchTracker::getRemainingFeatures()
640 478
{
641 479
    FeatureSet fs;
642
    if (m_good.getState() == Hypothesis::Satisfied) {
480
    if (m_good.getState() == NoteHypothesis::Satisfied) {
643 481
        addFeaturesFrom(m_good, fs);
644 482
    }
645 483
    return fs;

Also available in: Unified diff