~ubuntu-branches/ubuntu/gutsy/audacity/gutsy-backports

« back to all changes in this revision

Viewing changes to lib-src/soundtouch/source/example/bpm/PeakFinder.cpp

  • Committer: Bazaar Package Importer
  • Author(s): John Dong
  • Date: 2008-02-18 21:58:19 UTC
  • mfrom: (13.1.2 hardy)
  • Revision ID: james.westby@ubuntu.com-20080218215819-tmbcf1rx238r8gdv
Tags: 1.3.4-1.1ubuntu1~gutsy1
Automated backport upload; no source changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
////////////////////////////////////////////////////////////////////////////////
2
 
///
3
 
/// Peak detection routine. 
4
 
///
5
 
/// The routine detects highest value on an array of values and calculates the 
6
 
/// precise peak location as a mass-center of the 'hump' around the peak value.
7
 
///
8
 
/// Author        : Copyright (c) Olli Parviainen
9
 
/// Author e-mail : oparviai 'at' iki.fi
10
 
/// SoundTouch WWW: http://www.surina.net/soundtouch
11
 
///
12
 
////////////////////////////////////////////////////////////////////////////////
13
 
//
14
 
// Last changed  : $Date: 2006/09/18 07:31:48 $
15
 
// File revision : $Revision: 1.2 $
16
 
//
17
 
// $Id: PeakFinder.cpp,v 1.2 2006/09/18 07:31:48 richardash1981 Exp $
18
 
//
19
 
////////////////////////////////////////////////////////////////////////////////
20
 
//
21
 
// License :
22
 
//
23
 
//  SoundTouch audio processing library
24
 
//  Copyright (c) Olli Parviainen
25
 
//
26
 
//  This library is free software; you can redistribute it and/or
27
 
//  modify it under the terms of the GNU Lesser General Public
28
 
//  License as published by the Free Software Foundation; either
29
 
//  version 2.1 of the License, or (at your option) any later version.
30
 
//
31
 
//  This library is distributed in the hope that it will be useful,
32
 
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
33
 
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
34
 
//  Lesser General Public License for more details.
35
 
//
36
 
//  You should have received a copy of the GNU Lesser General Public
37
 
//  License along with this library; if not, write to the Free Software
38
 
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
39
 
//
40
 
////////////////////////////////////////////////////////////////////////////////
41
 
 
42
 
#include <math.h>
43
 
#include <assert.h>
44
 
 
45
 
#include "PeakFinder.h"
46
 
 
47
 
 
48
 
PeakFinder::PeakFinder()
49
 
{
50
 
}
51
 
 
52
 
 
53
 
// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding
54
 
// to direction defined by 'direction' until next 'hump' after minimum value will 
55
 
// begin
56
 
int PeakFinder::findGround(const float *data, int peakpos, int direction) const
57
 
{
58
 
    float refvalue;
59
 
    int lowpos;
60
 
    int pos;
61
 
    int climb_count;
62
 
    float delta;
63
 
 
64
 
    climb_count = 0;
65
 
    refvalue = data[peakpos];
66
 
    lowpos = peakpos;
67
 
 
68
 
    pos = peakpos;
69
 
 
70
 
    while ((pos > minPos) && (pos < maxPos))
71
 
    {
72
 
        int prevpos;
73
 
 
74
 
        prevpos = pos;
75
 
        pos += direction;
76
 
 
77
 
        // calculate derivate
78
 
        delta = data[pos] - data[prevpos];
79
 
        if (delta <= 0)
80
 
        {
81
 
            // going downhill, ok
82
 
            if (climb_count)
83
 
            {
84
 
                climb_count --;  // decrease climb count
85
 
            }
86
 
 
87
 
            // check if new minimum found
88
 
            if (data[pos] < refvalue)
89
 
            {
90
 
                // new minimum found
91
 
                lowpos = pos;
92
 
                refvalue = data[pos];
93
 
            }
94
 
        }
95
 
        else
96
 
        {
97
 
            // going uphill, increase climbing counter
98
 
            climb_count ++;
99
 
            if (climb_count > 5) break;    // we've been climbing too long => it's next uphill => quit
100
 
        }
101
 
    }
102
 
    return lowpos;
103
 
}
104
 
 
105
 
 
106
 
// Find offset where the value crosses the given level, when starting from 'peakpos' and
107
 
// proceeds to direction defined in 'direction'
108
 
int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const
109
 
{
110
 
    float peaklevel;
111
 
    int pos;
112
 
 
113
 
    peaklevel = data[peakpos];
114
 
    assert(peaklevel >= level);
115
 
    pos = peakpos;
116
 
    while ((pos >= minPos) && (pos < maxPos))
117
 
    {
118
 
        if (data[pos + direction] < level) return pos;   // crossing found
119
 
        pos += direction;
120
 
    }
121
 
    return -1;  // not found
122
 
}
123
 
 
124
 
 
125
 
// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos'
126
 
float PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const
127
 
{
128
 
    int i;
129
 
    float sum;
130
 
    float wsum;
131
 
 
132
 
    sum = 0;
133
 
    wsum = 0;
134
 
    for (i = firstPos; i <= lastPos; i ++)
135
 
    {
136
 
        sum += (float)i * data[i];
137
 
        wsum += data[i];
138
 
    }
139
 
    return sum / wsum;
140
 
}
141
 
 
142
 
 
143
 
float PeakFinder::detectPeak(const float *data, int minPos, int maxPos) 
144
 
{
145
 
    #define max(x, y) (((x) > (y)) ? (x) : (y))
146
 
 
147
 
    int i;
148
 
    int peakpos;                // position of peak level
149
 
    float peakLevel;            // peak level
150
 
    int crosspos1, crosspos2;   // position where the peak 'hump' crosses cutting level
151
 
    float cutLevel;             // cutting value
152
 
    float groundLevel;          // ground level of the peak
153
 
    int gp1, gp2;               // bottom positions of the peak 'hump'
154
 
 
155
 
    this->minPos = minPos;
156
 
    this->maxPos = maxPos;
157
 
 
158
 
    // find absolute peak
159
 
    peakpos = minPos;
160
 
    peakLevel = data[minPos];
161
 
    for (i = minPos + 1; i < maxPos; i ++)
162
 
    {
163
 
        if (data[i] > peakLevel) 
164
 
        {
165
 
            peakLevel = data[i];
166
 
            peakpos = i;
167
 
        }
168
 
    }
169
 
    
170
 
    // find ground positions.
171
 
    gp1 = findGround(data, peakpos, -1);
172
 
    gp2 = findGround(data, peakpos, 1);
173
 
 
174
 
    groundLevel = max(data[gp1], data[gp2]);
175
 
 
176
 
    if (groundLevel < 1e-6) return 0;                // ground level too small => detection failed
177
 
    if ((peakLevel / groundLevel) < 1.3) return 0;   // peak less than 30% of the ground level => no good peak detected
178
 
 
179
 
    // calculate 70%-level of the peak
180
 
    cutLevel = 0.70f * peakLevel + 0.30f * groundLevel;
181
 
    // find mid-level crossings
182
 
    crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1);
183
 
    crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1);
184
 
 
185
 
    if ((crosspos1 < 0) || (crosspos2 < 0)) return 0;   // no crossing, no peak..
186
 
 
187
 
    // calculate mass center of the peak surroundings
188
 
    return calcMassCenter(data, crosspos1, crosspos2);
189
 
}
190
 
 
191