d@10
|
1 /*
|
d@10
|
2 ==============================================================================
|
d@10
|
3
|
d@10
|
4 SpectralContrast.cpp
|
d@10
|
5 Created: 14 Aug 2015 12:21:29pm
|
d@10
|
6 Author: David
|
d@10
|
7
|
d@10
|
8 ==============================================================================
|
d@10
|
9 */
|
d@10
|
10
|
d@10
|
11 #include "SpectralContrast.h"
|
d@10
|
12 #include <algorithm>
|
d@12
|
13 #include <iostream>
|
d@10
|
14
|
d@10
|
15 void SpectralContrast::initSpectralContrastVariables(int frameSize, float sampleRate)
|
d@10
|
16 {
|
d@10
|
17
|
d@10
|
18 int numberBands = 6; //the number of bands in the filter
|
d@10
|
19 float lowFrequencyBound = 20; //the lower bound of the lowest band
|
d@10
|
20 float highFrequencyBound = sampleRate / 2.0f;
|
d@10
|
21 float staticDistribution = 0.15f; //the ratio of the bins to distribute equally [0, 1]
|
d@10
|
22 m_neighbourRatio = 0.4f; //the ratio of the bins in the sub band used to calculate the peak and valley", "(0,1]"
|
d@10
|
23
|
d@10
|
24 // get staticDistribution
|
d@10
|
25 float partToScale = 1.0f - staticDistribution;
|
d@10
|
26
|
d@10
|
27 float binWidth = sampleRate / frameSize;
|
d@10
|
28
|
d@10
|
29 int lastBins = 0;
|
d@10
|
30 m_startAtBin = 0;
|
d@10
|
31
|
d@10
|
32 m_numberOfBinsInBands.clear();
|
d@10
|
33 m_numberOfBinsInBands.resize(numberBands);
|
d@10
|
34 lastBins = int(lowFrequencyBound / binWidth);
|
d@10
|
35 m_startAtBin = lastBins;
|
d@10
|
36
|
d@10
|
37 // Determine how many bins are in each band to start with.
|
d@10
|
38 // The rest of the bands will be distributed logarithmically.
|
d@10
|
39 int totalNumberOfBins = int(highFrequencyBound / binWidth);
|
d@10
|
40 highFrequencyBound = int(partToScale * totalNumberOfBins) * binWidth;
|
d@10
|
41 int staticBinsPerBand = int((1 - partToScale) * totalNumberOfBins) / numberBands;
|
d@10
|
42 float ratio = highFrequencyBound / lowFrequencyBound;
|
d@10
|
43 float ratioPerBand = pow(ratio, float(1.0 / numberBands));
|
d@10
|
44 float currFreq = lowFrequencyBound;
|
d@10
|
45
|
d@10
|
46 for (int i = 0; i < numberBands; ++i)
|
d@10
|
47 {
|
d@10
|
48 currFreq = currFreq * ratioPerBand;
|
d@10
|
49 m_numberOfBinsInBands[i] = int(currFreq / binWidth - lastBins + staticBinsPerBand);
|
d@10
|
50 lastBins = int(currFreq / binWidth);
|
d@10
|
51 }
|
d@10
|
52
|
d@10
|
53 }
|
d@10
|
54
|
d@10
|
55 void SpectralContrast::computeSpectralContrast(std::vector<float> spectrum, std::vector<float>& spectralContrast, std::vector<float>& valleys)
|
d@10
|
56 {
|
d@10
|
57 std::vector<float> spectrumCopy = spectrum; // I want a copy because I'll be transforming it
|
d@10
|
58
|
d@10
|
59 //substitute minReal for a static value that is the same in all architectures. i.e.: 1e-30
|
d@12
|
60 float minFloat = std::numeric_limits<float>::min(); //numeric_limits<Real>::min();
|
d@10
|
61
|
d@10
|
62 spectralContrast.clear();
|
d@10
|
63 valleys.clear();
|
d@10
|
64
|
d@10
|
65 int specIdx = m_startAtBin;
|
d@10
|
66
|
d@12
|
67 for (int bandIdx = 0; bandIdx < int(m_numberOfBinsInBands.size()) && specIdx < int(spectrumCopy.size()); ++bandIdx)
|
d@10
|
68 {
|
d@10
|
69 // get the mean of the band
|
d@10
|
70 float bandMean = 0;
|
d@10
|
71 for (int i = 0; i < m_numberOfBinsInBands[bandIdx] && specIdx + i < int(spectrumCopy.size()); ++i)
|
d@10
|
72 {
|
d@10
|
73 bandMean += spectrumCopy[specIdx + i];
|
d@10
|
74 }
|
d@10
|
75
|
d@12
|
76 if (m_numberOfBinsInBands[bandIdx] != 0)
|
d@10
|
77 {
|
d@12
|
78 bandMean /= m_numberOfBinsInBands[bandIdx];
|
d@10
|
79 }
|
d@10
|
80
|
d@12
|
81 bandMean += minFloat;
|
d@12
|
82
|
d@10
|
83 // sort the subband (ascending order)
|
d@10
|
84 std::sort(spectrumCopy.begin() + specIdx, spectrumCopy.begin() + std::min(specIdx + m_numberOfBinsInBands[bandIdx], int(spectrum.size())));
|
d@10
|
85
|
d@10
|
86 // number of bins to take the mean of
|
d@10
|
87 int neighbourBins = int(m_neighbourRatio * m_numberOfBinsInBands[bandIdx]);
|
d@12
|
88 if (neighbourBins < 1)
|
d@12
|
89 {
|
d@12
|
90 neighbourBins = 1;
|
d@12
|
91 }
|
d@10
|
92
|
d@10
|
93 // valley (FLT_MIN prevents log(0))
|
d@10
|
94 float sum = 0;
|
d@12
|
95 for (int i = 0; i < neighbourBins && specIdx + i < int(spectrumCopy.size()); ++i)
|
d@10
|
96 {
|
d@12
|
97 sum += spectrumCopy[specIdx + i];
|
d@10
|
98 }
|
d@10
|
99
|
d@12
|
100 float valley = (sum / neighbourBins) + minFloat;
|
d@10
|
101
|
d@10
|
102 // peak
|
d@10
|
103 sum = 0;
|
d@12
|
104 for (int i = m_numberOfBinsInBands[bandIdx]; i > m_numberOfBinsInBands[bandIdx] - neighbourBins && specIdx + i - 1 < int(spectrumCopy.size()) && i > 0; --i)
|
d@10
|
105 {
|
d@12
|
106 sum += spectrumCopy[specIdx + i - 1];
|
d@10
|
107 }
|
d@12
|
108
|
d@10
|
109
|
d@12
|
110 float peak = (sum / neighbourBins) + minFloat;
|
d@10
|
111
|
d@12
|
112 float ans = (log10(peak / valley)) / (log10(bandMean) + minFloat) ;
|
d@12
|
113
|
d@12
|
114 spectralContrast.push_back(ans);
|
d@12
|
115 valleys.push_back(log10(valley));
|
d@10
|
116
|
d@10
|
117 specIdx += m_numberOfBinsInBands[bandIdx];
|
d@10
|
118 }
|
d@12
|
119
|
d@10
|
120 } |